package.xml0000644000175100001660000136000214760300421010113 0ustar mongodb pecl.php.net MongoDB driver for PHP The purpose of this driver is to provide exceptionally thin glue between MongoDB and PHP, implementing only fundamental and performance-critical components necessary to build a fully-functional MongoDB driver. Andreas Braun alcaeus alcaeus@php.net yes Jeremy Mikola jmikola jmikola@php.net yes Derick Rethans derick derick@php.net no Hannes Magnusson bjori bjori@php.net no Katherine Walker kvwalker kvwalker@php.net no 2025-02-28 1.21.0 1.21.0 stable stable Apache License ## What's Changed * PHPC-2343: Require PHP 8.1 by @alcaeus in https://github.com/mongodb/mongo-php-driver/pull/1631 * Update branch names for GHA workflows by @alcaeus in https://github.com/mongodb/mongo-php-driver/pull/1646 * Bump version to 1.21-dev by @alcaeus in https://github.com/mongodb/mongo-php-driver/pull/1661 * Document how to run part of the test suite by @GromNaN in https://github.com/mongodb/mongo-php-driver/pull/1690 * PHPC-2458: Deprecate float arg for UTCDateTime constructor by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1695 * PHPC-2464: Emit deprecation notice for negative "limit" Query option by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1710 * PHPC-2460: Use zend_zval_type_name instead of internal macros by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1714 * PHPC-1247: Update links to PHP.net docs by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1735 * Test PPC and Zseries on RHEL 9 by @alcaeus in https://github.com/mongodb/mongo-php-driver/pull/1740 * PHPC-2472: Update to libmongocrypt 1.12.0 by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1743 * PHPC-2473: Bump to libmongoc 1.29.0 by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1748 * PHPC-2471: Sync BSON corpus tests for Y10K date parsing by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1742 * Use correct arch name in Windows artifacts. by @mickverm in https://github.com/mongodb/mongo-php-driver/pull/1762 * PHPC-2499: Update to libmongoc 1.29.2 by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1766 * PHPC-2496: WriteException stub should inherit ServerException by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1769 * PHPC-2477: Remove unused libmongoc and libbson constants by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1768 * PHPC-2502: Remove XFAIL in server-executeQuery-012.phpt by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1772 * PHPC-2489: Deprecate passing WriteConcern and ReadPreference objects to execute methods by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1770 * PHPC-2501: Conditionally define MONGOC_CYRUS_PLUGIN_PATH_PREFIX on Windows by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1777 * PHPC-2503: Conditionally allow more concise output for libbson 1.30 by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1779 * PHPC:2498: Accept integer types for Document array access by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1781 * PHPC-2508 and PHPC-2506: Bump libmongoc to 1.30 by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1785 * PHPC-2513: Check for returned _id before appending insert by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1788 * PHPC-2519: Bump libmongoc to 1.30.1 by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1792 * PHPC-2518: Support sort option for updateOne and replaceOne by @jmikola in https://github.com/mongodb/mongo-php-driver/pull/1794 * Use pre-packaged-source for pie downloads by @asgrim in https://github.com/mongodb/mongo-php-driver/pull/1782 ## New Contributors * @asgrim made their first contribution in https://github.com/mongodb/mongo-php-driver/pull/1782 **Full Changelog**: https://github.com/mongodb/mongo-php-driver/compare/1.20.1...1.21.0 8.1.0 8.99.99 1.4.8 mongodb mongodb-1.21.0/scripts/autotools/libbson/CheckHeaders.m40000644000175100001660000000042114760300420020055 0ustar AC_HEADER_STDBOOL AC_SUBST(BSON_HAVE_STDBOOL_H, 0) if test "$ac_cv_header_stdbool_h" = "yes"; then AC_SUBST(BSON_HAVE_STDBOOL_H, 1) fi AC_CHECK_HEADER([strings.h], [AC_SUBST(BSON_HAVE_STRINGS_H, 1)], [AC_SUBST(BSON_HAVE_STRINGS_H, 0)]) mongodb-1.21.0/scripts/autotools/libbson/Endian.m40000644000175100001660000000027614760300420016752 0ustar AC_C_BIGENDIAN( [AC_SUBST(BSON_BYTE_ORDER, 4321)], [AC_SUBST(BSON_BYTE_ORDER, 1234)], [AC_MSG_ERROR([unknown endianness])], [AC_MSG_ERROR([universal endianness is not supported])] ) mongodb-1.21.0/scripts/autotools/libbson/FindDependencies.m40000644000175100001660000000373214760300420020743 0ustar # Check for strnlen() dnl AC_CHECK_FUNC isn't properly respecting _XOPEN_SOURCE for strnlen for unknown reason AC_SUBST(BSON_HAVE_STRNLEN, 0) AC_CACHE_CHECK([for strnlen], bson_cv_have_strnlen, [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include int strnlen () { return 0; } ]])], [bson_cv_have_strnlen=no], [bson_cv_have_strnlen=yes])]) if test "$bson_cv_have_strnlen" = yes; then AC_SUBST(BSON_HAVE_STRNLEN, 1) fi # Check for snprintf() AC_SUBST(BSON_HAVE_SNPRINTF, 0) AC_CHECK_FUNC(snprintf, [AC_SUBST(BSON_HAVE_SNPRINTF, 1)]) # Check for strlcpy() AC_SUBST(BSON_HAVE_STRLCPY, 0) AC_CHECK_FUNC(strlcpy, [AC_SUBST(BSON_HAVE_STRLCPY, 1)]) # Check for struct timespec AC_SUBST(BSON_HAVE_TIMESPEC, 0) AC_CHECK_TYPE([struct timespec], [AC_SUBST(BSON_HAVE_TIMESPEC, 1)], [], [#include ]) # Check for clock_gettime and if it needs -lrt AC_SUBST(BSON_HAVE_CLOCK_GETTIME, 0) AC_SEARCH_LIBS([clock_gettime], [rt], [AC_SUBST(BSON_HAVE_CLOCK_GETTIME, 1)]) # Check if math functions need -lm AC_SEARCH_LIBS([floor], [m]) # Check for gmtime_r() AC_SUBST(BSON_HAVE_GMTIME_R, 0) AC_CHECK_FUNC(gmtime_r, [AC_SUBST(BSON_HAVE_GMTIME_R, 1)]) # Check for rand_r() AC_SUBST(BSON_HAVE_RAND_R, 0) AC_CHECK_FUNC(rand_r, [AC_SUBST(BSON_HAVE_RAND_R, 1)]) # Check for pthreads. We might need to make this better to handle mingw, # but I actually think it is okay to just check for it even though we will # use win32 primatives. AX_PTHREAD([ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PTHREAD_CFLAGS" PHP_EVAL_LIBLINE([$PTHREAD_LIBS],[MONGODB_SHARED_LIBADD]) # PTHREAD_CFLAGS may come back as "-pthread", which should also be used when # linking. We can trust PHP_EVAL_LIBLINE to ignore other values. PHP_EVAL_LIBLINE([$PTHREAD_CFLAGS],[MONGODB_SHARED_LIBADD]) ],[ AC_MSG_ERROR([libbson requires pthreads on non-Windows platforms.]) ]) # Check for aligned_alloc() AC_SUBST(BSON_HAVE_ALIGNED_ALLOC, 0) AC_CHECK_FUNC(aligned_alloc, [AC_SUBST(BSON_HAVE_ALIGNED_ALLOC, 1)]) mongodb-1.21.0/scripts/autotools/libbson/Versions.m40000644000175100001660000000125214760300420017357 0ustar BSON_CURRENT_FILE=[]PHP_EXT_SRCDIR(mongodb)[/src/LIBMONGOC_VERSION_CURRENT] libbson_VERSION_FULL=$(cat $BSON_CURRENT_FILE) dnl Ensure newline for "cut" implementations that need it, e.g. HP-UX. libbson_VERSION_MAJOR=$( (cat $BSON_CURRENT_FILE; echo) | cut -d- -f1 | cut -d. -f1 ) libbson_VERSION_MINOR=$( (cat $BSON_CURRENT_FILE; echo) | cut -d- -f1 | cut -d. -f2 ) libbson_VERSION_PATCH=$( (cat $BSON_CURRENT_FILE; echo) | cut -d- -f1 | cut -d. -f3 ) libbson_VERSION_PRERELEASE=$(cut -s -d- -f2 $BSON_CURRENT_FILE) AC_SUBST(libbson_VERSION_FULL) AC_SUBST(libbson_VERSION_MAJOR) AC_SUBST(libbson_VERSION_MINOR) AC_SUBST(libbson_VERSION_PATCH) AC_SUBST(libbson_VERSION_PRERELEASE) mongodb-1.21.0/scripts/autotools/libmongoc/CheckCompression.m40000644000175100001660000001227414760300420021335 0ustar PHP_ARG_WITH([mongodb-snappy], [whether to enable Snappy for compression], [AS_HELP_STRING([--with-mongodb-snappy=@<:@auto/yes/no@:>@], [MongoDB: Enable Snappy for compression [default=auto]])], [auto], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_SNAPPY], [auto yes no]) PHP_ARG_WITH([mongodb-zlib], [whether to enable zlib for compression], [AS_HELP_STRING([--with-mongodb-zlib=@<:@auto/system/bundled/no@:>@], [MongoDB: Enable zlib for compression [default=auto]])], [auto], [no]) dnl PHP_ARG_WITH without a value assigns "yes". Treat it like "auto" since we dnl fall back to bundled zlib if the system library isn't found if test "$PHP_MONGODB_ZLIB" = "yes"; then PHP_MONGODB_ZLIB="auto" fi PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_ZLIB], [auto system bundled no]) PHP_ARG_WITH([mongodb-zstd], [whether to enable zstd for compression], [AS_HELP_STRING([--with-mongodb-zstd=@<:@auto/yes/no@:>@], [MongoDB: Enable zstd for compression [default=auto]])], [auto], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_ZSTD], [auto yes no]) found_snappy="no" found_zlib="no" bundled_zlib="no" found_zstd="no" AS_IF([test "$PHP_MONGODB_SNAPPY" = "auto" -o "$PHP_MONGODB_SNAPPY" = "yes"],[ PKG_CHECK_MODULES([PHP_MONGODB_SNAPPY],[snappy],[ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_SNAPPY_CFLAGS" PHP_EVAL_LIBLINE([$PHP_MONGODB_SNAPPY_LIBS],[MONGODB_SHARED_LIBADD]) found_snappy="yes" ],[ PHP_CHECK_LIBRARY([snappy], [snappy_uncompress], [have_snappy_lib="yes"], [have_snappy_lib="no"]) AC_CHECK_HEADER([snappy-c.h], [have_snappy_headers=yes], [have_snappy_headers=no]) if test "$have_snappy_lib" = "yes" -a "$have_snappy_headers" = "yes"; then PHP_ADD_LIBRARY([snappy],,[MONGODB_SHARED_LIBADD]) found_snappy="yes" fi ]) if test "$PHP_MONGODB_SNAPPY" = "yes" -a "$found_snappy" = "no"; then AC_MSG_ERROR([Snappy libraries and development headers could not be found]) fi ]) AS_IF([test "$PHP_MONGODB_ZLIB" = "auto" -o "$PHP_MONGODB_ZLIB" = "system"],[ PKG_CHECK_MODULES([PHP_MONGODB_ZLIB],[zlib],[ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_ZLIB_CFLAGS" PHP_EVAL_LIBLINE([$PHP_MONGODB_ZLIB_LIBS],[MONGODB_SHARED_LIBADD]) found_zlib="yes" ],[ PHP_CHECK_LIBRARY([zlib], [compress2], [have_zlib_lib="yes"], [have_zlib_lib="no"]) AC_CHECK_HEADER([zlib.h], [have_zlib_headers=yes], [have_zlib_headers=no]) if test "$have_zlib_lib" = "yes" -a "$have_zlib_headers" = "yes"; then PHP_ADD_LIBRARY([z],,[MONGODB_SHARED_LIBADD]) found_zlib="yes" fi ]) if test "$PHP_MONGODB_ZLIB" = "system" -a "$found_zlib" = "no"; then AC_MSG_ERROR([zlib libraries and development headers could not be found]) fi ]) dnl Use libmongoc's bundled zlib if necessary AS_IF([test "$found_zlib" = "no" -a \( "$PHP_MONGODB_ZLIB" = "auto" -o "$PHP_MONGODB_ZLIB" = "bundled" \)],[ AC_CHECK_HEADER([unistd.h],[PHP_MONGODB_ZLIB_CFLAGS="$PHP_MONGODB_ZLIB_CFLAGS -DHAVE_UNISTD_H"]) AC_CHECK_HEADER([stdarg.h],[PHP_MONGODB_ZLIB_CFLAGS="$PHP_MONGODB_ZLIB_CFLAGS -DHAVE_STDARG_H"]) bundled_zlib="yes" ]) AS_IF([test "$PHP_MONGODB_ZSTD" = "auto" -o "$PHP_MONGODB_ZSTD" = "yes"],[ PKG_CHECK_MODULES([PHP_MONGODB_ZSTD],[libzstd],[ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_ZSTD_CFLAGS" PHP_EVAL_LIBLINE([$PHP_MONGODB_ZSTD_LIBS],[MONGODB_SHARED_LIBADD]) found_zstd="yes" ],[ PHP_CHECK_LIBRARY([zstd], [ZSTD_compress], [have_zstd_lib="yes"], [have_zstd_lib="no"]) AC_CHECK_HEADER([zstd.h], [have_zstd_headers=yes], [have_zstd_headers=no]) if test "$have_zstd_lib" = "yes" -a "$have_zstd_headers" = "yes"; then PHP_ADD_LIBRARY([zstd],,[MONGODB_SHARED_LIBADD]) found_zstd="yes" fi ]) if test "$PHP_MONGODB_ZSTD" = "yes" -a "$found_zstd" = "no"; then AC_MSG_ERROR([zstd libraries and development headers could not be found]) fi ]) if test "$found_snappy" = "yes" -o "$found_zlib" = "yes" -o "$bundled_zlib" = "yes" -o "$found_zstd" = "yes"; then AC_SUBST(MONGOC_ENABLE_COMPRESSION, 1) if test "$found_snappy" = "yes"; then AC_SUBST(MONGOC_ENABLE_COMPRESSION_SNAPPY, 1) else AC_SUBST(MONGOC_ENABLE_COMPRESSION_SNAPPY, 0) fi if test "$found_zlib" = "yes" -o "$bundled_zlib" = "yes"; then AC_SUBST(MONGOC_ENABLE_COMPRESSION_ZLIB, 1) else AC_SUBST(MONGOC_ENABLE_COMPRESSION_ZLIB, 0) fi if test "$found_zstd" = "yes"; then AC_SUBST(MONGOC_ENABLE_COMPRESSION_ZSTD, 1) else AC_SUBST(MONGOC_ENABLE_COMPRESSION_ZSTD, 0) fi else AC_SUBST(MONGOC_ENABLE_COMPRESSION, 0) AC_SUBST(MONGOC_ENABLE_COMPRESSION_SNAPPY, 0) AC_SUBST(MONGOC_ENABLE_COMPRESSION_ZLIB, 0) AC_SUBST(MONGOC_ENABLE_COMPRESSION_ZSTD, 0) fi mongodb-1.21.0/scripts/autotools/libmongoc/CheckResolv.m40000644000175100001660000000562114760300420020304 0ustar dnl Disable SRV until we find a library AC_SUBST(MONGOC_ENABLE_SRV, 0) dnl Disable Windows DNSAPI AC_SUBST(MONGOC_HAVE_DNSAPI, 0) found_resolv="no" libc_has_resolv="no" if test "$os_aix" = "yes" -o "$os_freebsd" = "yes"; then libc_has_resolv="yes" fi dnl Temporarily link libresolv for detection if necessary if test "$libc_has_resolv" = "no"; then old_LIBS="$LIBS" LIBS="$LIBS -lresolv" fi dnl Thread-safe DNS query function for _mongoc_client_get_srv. dnl Could be a macro, not a function, so check with AC_LINK_IFELSE. AC_MSG_CHECKING([for res_nsearch]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include ]], [[ int len; unsigned char reply[1024]; res_state statep; len = res_nsearch( statep, "example.com", ns_c_in, ns_t_srv, reply, sizeof(reply)); ]])], [ AC_MSG_RESULT([yes]) AC_SUBST(MONGOC_HAVE_RES_SEARCH, 0) AC_SUBST(MONGOC_HAVE_RES_NSEARCH, 1) found_resolv="yes" dnl We have res_nsearch. Call res_ndestroy (BSD/Mac) or res_nclose (Linux)? AC_MSG_CHECKING([for res_ndestroy]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include ]], [[ res_state statep; res_ndestroy(statep); ]])], [ AC_MSG_RESULT([yes]) AC_SUBST(MONGOC_HAVE_RES_NDESTROY, 1) AC_SUBST(MONGOC_HAVE_RES_NCLOSE, 0) ], [ AC_MSG_RESULT([no]) AC_SUBST(MONGOC_HAVE_RES_NDESTROY, 0) AC_MSG_CHECKING([for res_nclose]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include ]], [[ res_state statep; res_nclose(statep); ]])], [ AC_MSG_RESULT([yes]) AC_SUBST(MONGOC_HAVE_RES_NCLOSE, 1) ], [ AC_MSG_RESULT([no]) AC_SUBST(MONGOC_HAVE_RES_NCLOSE, 0) ]) ]) ],[ AC_MSG_RESULT([no]) AC_SUBST(MONGOC_HAVE_RES_NSEARCH, 0) AC_SUBST(MONGOC_HAVE_RES_NDESTROY, 0) AC_SUBST(MONGOC_HAVE_RES_NCLOSE, 0) dnl Thread-unsafe function. AC_MSG_CHECKING([for res_search]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include #include ]], [[ int len; unsigned char reply[1024]; len = res_search("example.com", ns_c_in, ns_t_srv, reply, sizeof(reply)); ]])], [ AC_MSG_RESULT([yes]) AC_SUBST(MONGOC_HAVE_RES_SEARCH, 1) found_resolv="yes" ], [ AC_MSG_RESULT([no]) AC_SUBST(MONGOC_HAVE_RES_SEARCH, 0) ]) ]) AS_IF([test "$found_resolv" = "yes"],[ AC_SUBST(MONGOC_ENABLE_SRV, 1) ]) if test "$libc_has_resolv" = "no"; then LIBS="$old_LIBS" AS_IF([test "$found_resolv" = "yes"],[ PHP_ADD_LIBRARY([resolv],,[MONGODB_SHARED_LIBADD]) ]) fi mongodb-1.21.0/scripts/autotools/libmongoc/CheckSSL.m40000644000175100001660000002372514760300420017500 0ustar PHP_ARG_WITH([mongodb-ssl], [whether to enable crypto and TLS], [AS_HELP_STRING([--with-mongodb-ssl=@<:@auto/openssl/libressl/darwin/no@:>@], [MongoDB: Enable TLS connections and SCRAM-SHA-1 authentication [default=auto]])], [auto], [no]) if test "$PHP_MONGODB_SSL" = "auto" -o "$PHP_MONGODB_SSL" = "no"; then crypto_required="no" else crypto_required="yes" dnl PHP_ARG_WITH without a value assigns "yes". Treat it like "auto" but dnl require a crypto library. if test "$PHP_MONGODB_SSL" = "yes"; then PHP_MONGODB_SSL="auto" fi fi PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_SSL], [auto openssl libressl darwin no]) PHP_ARG_WITH([openssl-dir], [deprecated option for OpenSSL library path], [AS_HELP_STRING([--with-openssl-dir=@<:@auto/DIR@:>@], [MongoDB: OpenSSL library path (deprecated for pkg-config) [default=auto]])], [auto], [no]) if test "$PHP_OPENSSL_DIR" != "auto"; then AC_MSG_WARN([Using --with-openssl-dir is deprecated and will be removed in a future version.]) fi AS_IF([test "$PHP_MONGODB_SSL" = "openssl" -o "$PHP_MONGODB_SSL" = "auto"],[ found_openssl="no" dnl OpenSSL 1.0.1 is required for libmongoc 1.24+ (CDRIVER-3562). This can be dnl enforced through pkg-config but not the PHP_CHECK_LIBRARY fallback. PKG_CHECK_MODULES([PHP_MONGODB_SSL],[openssl >= 1.0.1],[ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_SSL_CFLAGS" PHP_EVAL_LIBLINE([$PHP_MONGODB_SSL_LIBS],[MONGODB_SHARED_LIBADD]) PHP_MONGODB_SSL="openssl" found_openssl="yes" old_CFLAGS="$CFLAGS" CFLAGS="$PHP_MONGODB_SSL_CFLAGS $CFLAGS" AC_CHECK_DECLS([ASN1_STRING_get0_data], [have_ASN1_STRING_get0_data="yes"], [have_ASN1_STRING_get0_data="no"], [[#include ]]) CFLAGS="$old_CFLAGS" ],[ unset OPENSSL_INCDIR unset OPENSSL_LIBDIR dnl Use a list of directories from PHP_SETUP_OPENSSL by default. dnl Support documented "auto" and older, undocumented "yes" options if test "$PHP_OPENSSL_DIR" = "auto" -o "$PHP_OPENSSL_DIR" = "yes"; then PHP_OPENSSL_DIR="/usr/local/ssl /usr/local /usr /usr/local/openssl" fi for i in $PHP_OPENSSL_DIR; do if test -r $i/include/openssl/evp.h; then OPENSSL_INCDIR="$i/include" fi if test -r $i/$PHP_LIBDIR/libssl.a -o -r $i/$PHP_LIBDIR/libssl.$SHLIB_SUFFIX_NAME; then OPENSSL_LIBDIR="$i/$PHP_LIBDIR" fi test -n "$OPENSSL_INCDIR" && test -n "$OPENSSL_LIBDIR" && break done if test -n "$OPENSSL_LIBDIR"; then OPENSSL_LIBDIR_LDFLAG="-L$OPENSSL_LIBDIR" fi PHP_CHECK_LIBRARY([crypto], [EVP_DigestInit_ex], [have_crypto_lib="yes"], [have_crypto_lib="no"], [$OPENSSL_LIBDIR_LDFLAG]) dnl Check whether OpenSSL >= 1.1.0 is available PHP_CHECK_LIBRARY([ssl], [OPENSSL_init_ssl], [have_ssl_lib="yes"], [have_ssl_lib="no"], [$OPENSSL_LIBDIR_LDFLAG -lcrypto]) dnl If necessary, check whether OpenSSL < 1.1.0 is available if test "$have_ssl_lib" = "no"; then PHP_CHECK_LIBRARY([ssl], [SSL_library_init], [have_ssl_lib="yes"], [have_ssl_lib="no"], [$OPENSSL_LIBDIR_LDFLAG -lcrypto]) fi if test "$have_ssl_lib" = "yes" -a "$have_crypto_lib" = "yes"; then PHP_ADD_LIBRARY([ssl],,[MONGODB_SHARED_LIBADD]) PHP_ADD_LIBRARY([crypto],,[MONGODB_SHARED_LIBADD]) if test -n "$OPENSSL_LIBDIR"; then PHP_ADD_LIBPATH([$OPENSSL_LIBDIR],[MONGODB_SHARED_LIBADD]) fi if test -n "$OPENSSL_INCDIR"; then PHP_ADD_INCLUDE($OPENSSL_INCDIR) fi old_CFLAGS="$CFLAGS" CFLAGS="-I$OPENSSL_INCDIR $CFLAGS" AC_CHECK_DECLS([ASN1_STRING_get0_data], [have_ASN1_STRING_get0_data="yes"], [have_ASN1_STRING_get0_data="no"], [[#include ]]) CFLAGS="$old_CFLAGS" PHP_MONGODB_SSL="openssl" found_openssl="yes" fi ]) if test "$PHP_MONGODB_SSL" = "openssl" -a "$found_openssl" != "yes"; then AC_MSG_ERROR([OpenSSL libraries and development headers could not be found]) fi ]) AS_IF([test "$PHP_MONGODB_SSL" = "darwin" -o \( "$PHP_MONGODB_SSL" = "auto" -a "$os_darwin" = "yes" \)],[ if test "$os_darwin" = "no"; then AC_MSG_ERROR([Darwin SSL is only supported on macOS]) fi dnl PHP_FRAMEWORKS is only used for SAPI builds, so use MONGODB_SHARED_LIBADD for shared builds if test "$ext_shared" = "yes"; then MONGODB_SHARED_LIBADD="-framework Security -framework CoreFoundation $MONGODB_SHARED_LIBADD" else PHP_ADD_FRAMEWORK([Security]) PHP_ADD_FRAMEWORK([CoreFoundation]) fi PHP_MONGODB_SSL="darwin" ]) AS_IF([test "$PHP_MONGODB_SSL" = "libressl" -o "$PHP_MONGODB_SSL" = "auto"],[ found_libressl="no" PKG_CHECK_MODULES([PHP_MONGODB_SSL],[libtls libcrypto],[ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_SSL_CFLAGS" PHP_EVAL_LIBLINE([$PHP_MONGODB_SSL_LIBS],[MONGODB_SHARED_LIBADD]) PHP_MONGODB_SSL="libressl" found_libressl="yes" ],[ PHP_CHECK_LIBRARY([crypto], [EVP_DigestInit_ex], [have_crypto_lib="yes"], [have_crypto_lib="no"]) PHP_CHECK_LIBRARY([tls], [tls_init], [have_ssl_lib="yes"], [have_ssl_lib="no"], [-lcrypto]) if test "$have_ssl_lib" = "yes" -a "$have_crypto_lib" = "yes"; then PHP_ADD_LIBRARY([tls],,[MONGODB_SHARED_LIBADD]) PHP_ADD_LIBRARY([crypto],,[MONGODB_SHARED_LIBADD]) PHP_MONGODB_SSL="libressl" found_libressl="yes" fi ]) if test "$PHP_MONGODB_SSL" = "libressl" -a "$found_libressl" != "yes"; then AC_MSG_ERROR([LibreSSL libraries and development headers could not be found]) fi ]) AS_IF([test "$PHP_MONGODB_SSL" = "auto"],[ if test "$crypto_required" = "yes"; then AC_MSG_ERROR([crypto and TLS libraries not found]) fi PHP_MONGODB_SSL="no" ]) AC_MSG_CHECKING([which TLS library to use]) AC_MSG_RESULT([$PHP_MONGODB_SSL]) dnl Disable Windows SSL and crypto AC_SUBST(MONGOC_ENABLE_SSL_SECURE_CHANNEL, 0) AC_SUBST(MONGOC_ENABLE_CRYPTO_CNG, 0) AC_SUBST(MONGOC_HAVE_BCRYPT_PBKDF2, 0) if test "$PHP_MONGODB_SSL" = "openssl" -o "$PHP_MONGODB_SSL" = "libressl" -o "$PHP_MONGODB_SSL" = "darwin"; then AC_SUBST(MONGOC_ENABLE_SSL, 1) AC_SUBST(MONGOC_ENABLE_CRYPTO, 1) if test "$PHP_MONGODB_SSL" = "darwin"; then AC_SUBST(MONGOC_ENABLE_SSL_OPENSSL, 0) AC_SUBST(MONGOC_ENABLE_SSL_LIBRESSL, 0) AC_SUBST(MONGOC_ENABLE_SSL_SECURE_TRANSPORT, 1) AC_SUBST(MONGOC_ENABLE_CRYPTO_LIBCRYPTO, 0) AC_SUBST(MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO, 1) PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -DKMS_MESSAGE_ENABLE_CRYPTO=1 -DKMS_MESSAGE_ENABLE_CRYPTO_COMMON_CRYPTO=1" elif test "$PHP_MONGODB_SSL" = "openssl"; then AC_SUBST(MONGOC_ENABLE_SSL_OPENSSL, 1) AC_SUBST(MONGOC_ENABLE_SSL_LIBRESSL, 0) AC_SUBST(MONGOC_ENABLE_SSL_SECURE_TRANSPORT, 0) AC_SUBST(MONGOC_ENABLE_CRYPTO_LIBCRYPTO, 1) AC_SUBST(MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO, 0) PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -DKMS_MESSAGE_ENABLE_CRYPTO=1 -DKMS_MESSAGE_ENABLE_CRYPTO_LIBCRYPTO=1" elif test "$PHP_MONGODB_SSL" = "libressl"; then AC_SUBST(MONGOC_ENABLE_SSL_OPENSSL, 0) AC_SUBST(MONGOC_ENABLE_SSL_LIBRESSL, 1) AC_SUBST(MONGOC_ENABLE_SSL_SECURE_TRANSPORT, 0) AC_SUBST(MONGOC_ENABLE_CRYPTO_LIBCRYPTO, 1) AC_SUBST(MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO, 0) PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -DKMS_MESSAGE_ENABLE_CRYPTO=1 -DKMS_MESSAGE_ENABLE_CRYPTO_LIBCRYPTO=1" fi else AC_SUBST(MONGOC_ENABLE_SSL, 0) AC_SUBST(MONGOC_ENABLE_SSL_LIBRESSL, 0) AC_SUBST(MONGOC_ENABLE_SSL_OPENSSL, 0) AC_SUBST(MONGOC_ENABLE_SSL_SECURE_TRANSPORT, 0) AC_SUBST(MONGOC_ENABLE_CRYPTO, 0) AC_SUBST(MONGOC_ENABLE_CRYPTO_LIBCRYPTO, 0) AC_SUBST(MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO, 0) fi if test "$have_ASN1_STRING_get0_data" = "yes"; then AC_SUBST(MONGOC_HAVE_ASN1_STRING_GET0_DATA, 1) else AC_SUBST(MONGOC_HAVE_ASN1_STRING_GET0_DATA, 0) fi PHP_ARG_ENABLE([mongodb-crypto-system-profile], [whether to use system crypto profile], [AS_HELP_STRING([--enable-mongodb-crypto-system-profile], [MongoDB: Use system crypto profile (OpenSSL only) [default=no]])], [no], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_CRYPTO_SYSTEM_PROFILE], [yes no]) PHP_ARG_WITH([system-ciphers], [deprecated option for whether to use system crypto profile], AS_HELP_STRING([--enable-system-ciphers], [MongoDB: whether to use system crypto profile (deprecated for --enable-mongodb-crypto-system-profile) [default=no]]), [no], [no]) dnl Do not validate PHP_SYSTEM_CIPHERS for static builds, since it is also used dnl by the OpenSSL extension, which checks for values other than "no". if test "$ext_shared" = "yes"; then PHP_MONGODB_VALIDATE_ARG([PHP_SYSTEM_CIPHERS], [yes no]) if test "$PHP_SYSTEM_CIPHERS" != "no"; then AC_MSG_WARN([Using --enable-system-ciphers is deprecated and will be removed in a future version. Please use --enable-mongodb-crypto-system-profile instead]) fi fi dnl Also consider the deprecated --enable-system-ciphers option if test "$PHP_MONGODB_CRYPTO_SYSTEM_PROFILE" = "yes" -o "$PHP_SYSTEM_CIPHERS" = "yes"; then if test "$PHP_MONGODB_SSL" = "openssl"; then AC_SUBST(MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE, 1) else AC_MSG_ERROR([System crypto profile is only available with OpenSSL]) fi else AC_SUBST(MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE, 0) fi mongodb-1.21.0/scripts/autotools/libmongoc/CheckSasl.m40000644000175100001660000000456614760300420017743 0ustar PHP_ARG_WITH([mongodb-sasl], [whether to enable SASL for Kerberos authentication], [AS_HELP_STRING([--with-mongodb-sasl=@<:@auto/cyrus/no@:>@], [MongoDB: Enable SASL for Kerberos authentication [default=auto]])], [auto], [no]) dnl PHP_ARG_WITH without a value assigns "yes". Treat it like "cyrus" (required) if test "$PHP_MONGODB_SASL" = "yes"; then PHP_MONGODB_SASL="cyrus" fi PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_SASL], [auto cyrus no]) AS_IF([test "$PHP_MONGODB_SASL" = "auto" -o "$PHP_MONGODB_SASL" = "cyrus"],[ found_cyrus="no" PKG_CHECK_MODULES([PHP_MONGODB_SASL],[libsasl2],[ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_SASL_CFLAGS" PHP_EVAL_LIBLINE([$PHP_MONGODB_SASL_LIBS],[MONGODB_SHARED_LIBADD]) PHP_MONGODB_SASL="cyrus" found_cyrus="yes" ],[ PHP_CHECK_LIBRARY([sasl2], [sasl_client_init], [have_sasl2_lib="yes"], [have_sasl2_lib="no"]) AC_CHECK_HEADER([sasl/sasl.h], [have_sasl_headers=yes], [have_sasl_headers=no]) if test "$have_sasl2_lib" = "yes" -a "$have_sasl_headers" = "yes"; then PHP_ADD_LIBRARY([sasl2],,[MONGODB_SHARED_LIBADD]) PHP_MONGODB_SASL="cyrus" found_cyrus="yes" fi ]) if test "$found_cyrus" = "yes"; then PHP_CHECK_LIBRARY([sasl2], [sasl_client_done], [have_sasl_client_done=yes], [have_sasl_client_done=no], $MONGODB_SHARED_LIBADD) fi if test "$PHP_MONGODB_SASL" = "cyrus" -a "$found_cyrus" != "yes"; then AC_MSG_ERROR([Cyrus SASL libraries and development headers could not be found]) fi ]) if test "$PHP_MONGODB_SASL" = "auto"; then PHP_MONGODB_SASL="no" fi AC_MSG_CHECKING([which SASL library to use]) AC_MSG_RESULT([$PHP_MONGODB_SASL]) dnl Disable Windows SSPI AC_SUBST(MONGOC_ENABLE_SASL_SSPI, 0) if test "$PHP_MONGODB_SASL" = "cyrus"; then AC_SUBST(MONGOC_ENABLE_SASL, 1) AC_SUBST(MONGOC_ENABLE_SASL_CYRUS, 1) if test "$have_sasl_client_done" = "yes"; then AC_SUBST(MONGOC_HAVE_SASL_CLIENT_DONE, 1) else AC_SUBST(MONGOC_HAVE_SASL_CLIENT_DONE, 0) fi else AC_SUBST(MONGOC_ENABLE_SASL, 0) AC_SUBST(MONGOC_ENABLE_SASL_CYRUS, 0) AC_SUBST(MONGOC_HAVE_SASL_CLIENT_DONE, 0) fi mongodb-1.21.0/scripts/autotools/libmongoc/CheckUtf8Proc.m40000644000175100001660000000306214760300420020501 0ustar PHP_ARG_WITH([mongodb-utf8proc], [whether to use bundled or system utf8proc for SCRAM-SHA-256 SASLprep], [AS_HELP_STRING([--with-mongodb-utf8proc=@<:@bundled/system@:>@], [MongoDB: Use bundled or system utf8proc for SCRAM-SHA-256 SASLprep [default=bundled]])], [bundled], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_UTF8PROC], [bundled system]) found_utf8proc="no" bundled_utf8proc="no" AS_IF([test "$PHP_MONGODB_UTF8PROC" = "system"],[ PKG_CHECK_MODULES([PHP_MONGODB_UTF8PROC],[libutf8proc],[ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_UTF8PROC_CFLAGS" PHP_EVAL_LIBLINE([$PHP_MONGODB_UTF8PROC_LIBS],[MONGODB_SHARED_LIBADD]) found_utf8proc="yes" ],[ PHP_CHECK_LIBRARY([utf8proc], [utf8proc_NFKC], [have_utf8proc_lib="yes"], [have_utf8proc_lib="no"]) AC_CHECK_HEADER([utf8proc.h], [have_utf8proc_headers=yes], [have_utf8proc_headers=no]) if test "$have_utf8proc_lib" = "yes" -a "$have_utf8proc_headers" = "yes"; then PHP_ADD_LIBRARY([utf8proc],,[MONGODB_SHARED_LIBADD]) found_utf8proc="yes" fi ]) if test "$PHP_MONGODB_UTF8PROC" = "system" -a "$found_utf8proc" = "no"; then AC_MSG_ERROR([utf8proc library and development headers could not be found]) fi ]) AS_IF([test "$PHP_MONGODB_UTF8PROC" = "bundled"],[ PHP_MONGODB_UTF8PROC_CFLAGS="$PHP_MONGODB_UTF8PROC_CFLAGS -DUTF8PROC_STATIC" bundled_utf8proc="yes" ]) mongodb-1.21.0/scripts/autotools/libmongoc/Endian.m40000644000175100001660000000045114760300420017266 0ustar AC_C_BIGENDIAN( [PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -DKMS_MESSAGE_BIG_ENDIAN=1"], [PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -DKMS_MESSAGE_LITTLE_ENDIAN=1"], [AC_MSG_ERROR([unknown endianness])], [AC_MSG_ERROR([universal endianness is not supported])] ) mongodb-1.21.0/scripts/autotools/libmongoc/FindDependencies.m40000644000175100001660000000305714760300420021264 0ustar # Check for shm functions AC_CHECK_FUNCS([shm_open],[],[ AC_CHECK_LIB([rt], [shm_open], [PHP_ADD_LIBRARY([rt],,[MONGODB_SHARED_LIBADD])], []) ]) # Check for sched_getcpu AC_CHECK_FUNC([sched_getcpu], [AC_SUBST(MONGOC_HAVE_SCHED_GETCPU, 1)], [AC_SUBST(MONGOC_HAVE_SCHED_GETCPU, 0)]) AC_CHECK_TYPE([socklen_t], [AC_SUBST(MONGOC_HAVE_SOCKLEN, 1)], [AC_SUBST(MONGOC_HAVE_SOCKLEN, 0)], [#include ]) AC_CHECK_MEMBER([struct sockaddr_storage.ss_family], [AC_SUBST(MONGOC_HAVE_SS_FAMILY, 1)], [AC_SUBST(MONGOC_HAVE_SS_FAMILY, 0)], [#include ]) AC_DEFINE([ACCEPT_ARG2], [], [Description]) AC_DEFINE([ACCEPT_ARG3], [], [Description]) AX_PROTOTYPE_ACCEPT AC_SUBST(MONGOC_SOCKET_ARG2, "$ACCEPT_ARG2") AC_SUBST(MONGOC_SOCKET_ARG3, "$ACCEPT_ARG3") # Check for pthreads. libmongoc's original FindDependencies.m4 script did not # require pthreads, but it does appear to be necessary on non-Windows platforms # based on mongoc-openssl.c and mongoc-thread-private.h. AX_PTHREAD([ PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PTHREAD_CFLAGS" PHP_EVAL_LIBLINE([$PTHREAD_LIBS],[MONGODB_SHARED_LIBADD]) # PTHREAD_CFLAGS may come back as "-pthread", which should also be used when # linking. We can trust PHP_EVAL_LIBLINE to ignore other values. PHP_EVAL_LIBLINE([$PTHREAD_CFLAGS],[MONGODB_SHARED_LIBADD]) ],[ AC_MSG_ERROR([libmongoc requires pthreads on non-Windows platforms.]) ]) mongodb-1.21.0/scripts/autotools/libmongoc/Versions.m40000644000175100001660000000131214760300420017675 0ustar MONGOC_CURRENT_FILE=[]PHP_EXT_SRCDIR(mongodb)[/src/LIBMONGOC_VERSION_CURRENT] libmongoc_VERSION_FULL=$(cat $MONGOC_CURRENT_FILE) dnl Ensure newline for "cut" implementations that need it, e.g. HP-UX. libmongoc_VERSION_MAJOR=$( (cat $MONGOC_CURRENT_FILE; echo) | cut -d- -f1 | cut -d. -f1 ) libmongoc_VERSION_MINOR=$( (cat $MONGOC_CURRENT_FILE; echo) | cut -d- -f1 | cut -d. -f2 ) libmongoc_VERSION_PATCH=$( (cat $MONGOC_CURRENT_FILE; echo) | cut -d- -f1 | cut -d. -f3 ) libmongoc_VERSION_PRERELEASE=$(cut -s -d- -f2 $MONGOC_CURRENT_FILE) AC_SUBST(libmongoc_VERSION_FULL) AC_SUBST(libmongoc_VERSION_MAJOR) AC_SUBST(libmongoc_VERSION_MINOR) AC_SUBST(libmongoc_VERSION_PATCH) AC_SUBST(libmongoc_VERSION_PRERELEASE) mongodb-1.21.0/scripts/autotools/libmongocrypt/CheckSSL.m40000644000175100001660000000216714760300420020414 0ustar if test "$PHP_MONGODB_CLIENT_SIDE_ENCRYPTION" != "no"; then AC_MSG_CHECKING([which crypto library to use for libmongocrypt]) AC_MSG_RESULT([$PHP_MONGODB_SSL]) dnl Disable Windows crypto AC_SUBST(MONGOCRYPT_ENABLE_CRYPTO_CNG, 0) if test "$PHP_MONGODB_SSL" = "darwin"; then PHP_MONGODB_CLIENT_SIDE_ENCRYPTION="yes" AC_SUBST(MONGOCRYPT_ENABLE_CRYPTO, 1) AC_SUBST(MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO, 0) AC_SUBST(MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO, 1) elif test "$PHP_MONGODB_SSL" = "openssl" -o "$PHP_MONGODB_SSL" = "libressl"; then PHP_MONGODB_CLIENT_SIDE_ENCRYPTION="yes" AC_SUBST(MONGOCRYPT_ENABLE_CRYPTO, 1) AC_SUBST(MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO, 1) AC_SUBST(MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO, 0) elif test "$PHP_MONGODB_CLIENT_SIDE_ENCRYPTION" = "auto"; then PHP_MONGODB_CLIENT_SIDE_ENCRYPTION="no" AC_MSG_RESULT(No SSL library found. Compiling without libmongocrypt. Please specify a library using the --with-mongodb-ssl option) else AC_MSG_ERROR(Need an SSL library to compile with libmongocrypt. Please specify it using the --with-mongodb-ssl option) fi fi mongodb-1.21.0/scripts/autotools/libmongocrypt/Endian.m40000644000175100001660000000057014760300420020207 0ustar AC_C_BIGENDIAN( [PHP_MONGODB_LIBMONGOCRYPT_CFLAGS="$PHP_MONGODB_LIBMONGOCRYPT_CFLAGS -DKMS_MESSAGE_BIG_ENDIAN=1 -DMONGOCRYPT_BIG_ENDIAN=1"], [PHP_MONGODB_LIBMONGOCRYPT_CFLAGS="$PHP_MONGODB_LIBMONGOCRYPT_CFLAGS -DKMS_MESSAGE_LITTLE_ENDIAN=1 -DMONGOCRYPT_LITTLE_ENDIAN=1"], [AC_MSG_ERROR([unknown endianness])], [AC_MSG_ERROR([universal endianness is not supported])] ) mongodb-1.21.0/scripts/autotools/libmongocrypt/Version.m40000644000175100001660000000037014760300420020434 0ustar if test "$PHP_MONGODB_CLIENT_SIDE_ENCRYPTION" = "yes"; then MONGOCRYPT_CURRENT_FILE=[]PHP_EXT_SRCDIR(mongodb)[/src/LIBMONGOCRYPT_VERSION_CURRENT] MONGOCRYPT_BUILD_VERSION=$(cat $MONGOCRYPT_CURRENT_FILE) AC_SUBST(MONGOCRYPT_BUILD_VERSION) fi mongodb-1.21.0/scripts/autotools/m4/ax_check_compile_flag.m40000644000175100001660000000407014760300420020706 0ustar # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS mongodb-1.21.0/scripts/autotools/m4/ax_prototype.m40000644000175100001660000002011214760300420017170 0ustar # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_prototype.html # =========================================================================== # # SYNOPSIS # # AX_PROTOTYPE(function, includes, code, TAG1, values1 [, TAG2, values2 [...]]) # # DESCRIPTION # # Try all the combinations of , ... to successfully compile # . , , ... are substituted in and with # values found in , , ... respectively. , # , ... contain a list of possible values for each corresponding # tag and all combinations are tested. When AC_TRY_COMPILE(include, code) # is successful for a given substitution, the macro stops and defines the # following macros: FUNCTION_TAG1, FUNCTION_TAG2, ... using AC_DEFINE() # with values set to the current values of , , ... If no # combination is successful the configure script is aborted with a # message. # # Intended purpose is to find which combination of argument types is # acceptable for a given function . It is recommended to list # the most specific types first. For instance ARG1, [size_t, int] instead # of ARG1, [int, size_t]. # # Generic usage pattern: # # 1) add a call in configure.ac # # AX_PROTOTYPE(...) # # 2) call autoheader to see which symbols are not covered # # 3) add the lines in config.h # # /* Type of Nth argument of function */ # #undef FUNCTION_ARGN # # 4) Within the code use FUNCTION_ARGN instead of an hardwired type # # Complete example: # # 1) configure.ac # # AX_PROTOTYPE(getpeername, # [ # #include # #include # ], # [ # int a = 0; # ARG2 * b = 0; # ARG3 * c = 0; # getpeername(a, b, c); # ], # ARG2, [struct sockaddr, void], # ARG3, [socklen_t, size_t, int, unsigned int, long unsigned int]) # # 2) call autoheader # # autoheader: Symbol `GETPEERNAME_ARG2' is not covered by ./config.h # autoheader: Symbol `GETPEERNAME_ARG3' is not covered by ./config.h # # 3) config.h # # /* Type of second argument of getpeername */ # #undef GETPEERNAME_ARG2 # # /* Type of third argument of getpeername */ # #undef GETPEERNAME_ARG3 # # 4) in the code # # ... # GETPEERNAME_ARG2 name; # GETPEERNAME_ARG3 namelen; # ... # ret = getpeername(socket, &name, &namelen); # ... # # Implementation notes: generating all possible permutations of the # arguments is not easily done with the usual mixture of shell and m4, # that is why this macro is almost 100% m4 code. It generates long but # simple to read code. # # LICENSE # # Copyright (c) 2009 Loic Dachary # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 11 AU_ALIAS([AC_PROTOTYPE], [AX_PROTOTYPE]) AC_DEFUN([AX_PROTOTYPE],[ dnl dnl Upper case function name dnl pushdef([function],translit([$1], [a-z], [A-Z])) dnl dnl Collect tags that will be substituted dnl pushdef([tags],[AX_PROTOTYPE_TAGS(builtin([shift],builtin([shift],builtin([shift],$@))))]) dnl dnl Wrap in a 1 time loop, when a combination is found break to stop the combinatory exploration dnl for i in 1 do AX_PROTOTYPE_LOOP(AX_PROTOTYPE_REVERSE($1, AX_PROTOTYPE_SUBST($2,tags),AX_PROTOTYPE_SUBST($3,tags),builtin([shift],builtin([shift],builtin([shift],$@))))) AC_MSG_ERROR($1 unable to find a working combination) done popdef([tags]) popdef([function]) ]) dnl dnl AX_PROTOTYPE_REVERSE(list) dnl dnl Reverse the order of the dnl AC_DEFUN([AX_PROTOTYPE_REVERSE],[ifelse($#,0,,$#,1,[[$1]],[AX_PROTOTYPE_REVERSE(builtin([shift],$@)),[$1]])]) dnl dnl AX_PROTOTYPE_SUBST(string, tag) dnl dnl Substitute all occurrence of in with _VAL. dnl Assumes that tag_VAL is a macro containing the value associated to tag. dnl AC_DEFUN([AX_PROTOTYPE_SUBST],[ifelse($2,,[$1],[AX_PROTOTYPE_SUBST(patsubst([$1],[$2],[$2[]_VAL]),builtin([shift],builtin([shift],$@)))])]) dnl dnl AX_PROTOTYPE_TAGS([tag, values, [tag, values ...]]) dnl dnl Generate a list of by skipping . dnl AC_DEFUN([AX_PROTOTYPE_TAGS],[ifelse($1,,[],[$1, AX_PROTOTYPE_TAGS(builtin([shift],builtin([shift],$@)))])]) dnl dnl AX_PROTOTYPE_DEFINES(tags) dnl dnl Generate a AC_DEFINE(function_tag, tag_VAL) for each tag in list dnl Assumes that function is a macro containing the name of the function in upper case dnl and that tag_VAL is a macro containing the value associated to tag. dnl AC_DEFUN([AX_PROTOTYPE_DEFINES],[ifelse($1,,[], [AC_DEFINE(function[]_$1, $1_VAL) AC_SUBST(function[]_$1, "$1_VAL") AX_PROTOTYPE_DEFINES(builtin([shift],$@))])]) dnl dnl AX_PROTOTYPE_STATUS(tags) dnl dnl Generates a message suitable for argument to AC_MSG_* macros. For each tag dnl in the list the message tag => tag_VAL is generated. dnl Assumes that tag_VAL is a macro containing the value associated to tag. dnl AC_DEFUN([AX_PROTOTYPE_STATUS],[ifelse($1,,[],[$1 => $1_VAL AX_PROTOTYPE_STATUS(builtin([shift],$@))])]) dnl dnl AX_PROTOTYPE_EACH(tag, values) dnl dnl Call AX_PROTOTYPE_LOOP for each values and define the macro tag_VAL to dnl the current value. dnl AC_DEFUN([AX_PROTOTYPE_EACH],[ ifelse($2,, [ ], [ pushdef([$1_VAL], $2) AX_PROTOTYPE_LOOP(rest) popdef([$1_VAL]) AX_PROTOTYPE_EACH($1, builtin([shift], builtin([shift], $@))) ]) ]) dnl dnl AX_PROTOTYPE_LOOP([tag, values, [tag, values ...]], code, include, function) dnl dnl If there is a tag/values pair, call AX_PROTOTYPE_EACH with it. dnl If there is no tag/values pair left, tries to compile the code and include dnl using AC_TRY_COMPILE. If it compiles, AC_DEFINE all the tags to their dnl current value and exit with success. dnl AC_DEFUN([AX_PROTOTYPE_LOOP],[ ifelse(builtin([eval], $# > 3), 1, [ pushdef([rest],[builtin([shift],builtin([shift],$@))]) AX_PROTOTYPE_EACH($2,$1) popdef([rest]) ], [ AC_MSG_CHECKING($3 AX_PROTOTYPE_STATUS(tags)) dnl dnl Activate fatal warnings if possible, gives better guess dnl ac_save_CPPFLAGS="$CPPFLAGS" dnl ifelse(AC_LANG,CPLUSPLUS,if test "$GXX" = "yes" ; then CPPFLAGS="$CPPFLAGS -Werror" ; fi) dnl ifelse(AC_LANG,C,if test "$GCC" = "yes" ; then CPPFLAGS="$CPPFLAGS -Werror" ; fi) dnl dnl Disable the 'unused-variable' warning in case e.g. -Wall was enabled, dnl otherwise the test may always fail. dnl if (test "x$GCC" = "xyes" || test "x$GXX" = "xyes" ); then CPPFLAGS="$CPPFLAGS -Werror -Wno-unused-variable" ; fi AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$2], [$1])], [ CPPFLAGS="$ac_save_CPPFLAGS" AC_MSG_RESULT(ok) AX_PROTOTYPE_DEFINES(tags) break; ], [ CPPFLAGS="$ac_save_CPPFLAGS" AC_MSG_RESULT(not ok) ]) ] ) ]) mongodb-1.21.0/scripts/autotools/m4/ax_prototype_accept.m40000644000175100001660000000467314760300420020525 0ustar # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_prototype_accept.html # =========================================================================== # # SYNOPSIS # # AX_PROTOTYPE_ACCEPT # # DESCRIPTION # # Requires the AX_PROTOTYPE macro. FIXME: Put this in the code! # # Find the type of argument two and three of accept. User must include the # following in acconfig.h: # # /* Type of second argument of accept */ # #undef ACCEPT_ARG2 # # /* Type of third argument of accept */ # #undef ACCEPT_ARG3 # # LICENSE # # Copyright (c) 2008 Loic Dachary # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 6 AU_ALIAS([AC_PROTOTYPE_ACCEPT], [AX_PROTOTYPE_ACCEPT]) AC_DEFUN([AX_PROTOTYPE_ACCEPT],[ AX_PROTOTYPE(accept, [ #include #include ], [ int a = 0; ARG2 * b = 0; ARG3 * c = 0; accept(a, b, c); ], ARG2, [struct sockaddr, void], ARG3, [socklen_t, size_t, int, unsigned int, long unsigned int]) ]) mongodb-1.21.0/scripts/autotools/m4/ax_pthread.m40000644000175100001660000005412214760300420016562 0ustar # =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is # needed for multi-threaded programs (defaults to the value of CC # respectively CXX otherwise). (This is necessary on e.g. AIX to use the # special cc_r/CC_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also to link with them as well. For example, you might link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threaded programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # CXX="$PTHREAD_CXX" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to # that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # Copyright (c) 2019 Marc Stevens # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 31 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PROG_SED]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then ax_pthread_save_CC="$CC" ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"]) CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi CC="$ax_pthread_save_CC" CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items with a "," contain both # C compiler flags (before ",") and linker flags (after ","). Other items # starting with a "-" are C compiler flags, and remaining items are # library names, except for "none" which indicates that we try without # any flags at all, and "pthread-config" which is a program returning # the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 # (Note: HP C rejects this with "bad form for `-t' option") # -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads and # -D_REENTRANT too), HP C (must be checked before -lpthread, which # is present but should not be used directly; and before -mthreads, # because the compiler interprets this as "-mt" + "-hreads") # -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case $host_os in freebsd*) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) ax_pthread_flags="-kthread lthread $ax_pthread_flags" ;; hpux*) # From the cc(1) man page: "[-mt] Sets various -D flags to enable # multi-threading and also sets -lpthread." ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" ;; openedition*) # IBM z/OS requires a feature-test macro to be defined in order to # enable POSIX threads at all, so give the user a hint if this is # not set. (We don't define these ourselves, as they can affect # other portions of the system API in unpredictable ways.) AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], [ # if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) AX_PTHREAD_ZOS_MISSING # endif ], [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) ;; solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (N.B.: The stubs are missing # pthread_cleanup_push, or rather a function called by this macro, # so we could check for that, but who knows whether they'll stub # that too in a future libc.) So we'll check first for the # standard Solaris way of linking pthreads (-mt -lpthread). ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" ;; esac # Are we compiling with Clang? AC_CACHE_CHECK([whether $CC is Clang], [ax_cv_PTHREAD_CLANG], [ax_cv_PTHREAD_CLANG=no # Note that Autoconf sets GCC=yes for Clang as well as GCC if test "x$GCC" = "xyes"; then AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ # if defined(__clang__) && defined(__llvm__) AX_PTHREAD_CC_IS_CLANG # endif ], [ax_cv_PTHREAD_CLANG=yes]) fi ]) ax_pthread_clang="$ax_cv_PTHREAD_CLANG" # GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) # Note that for GCC and Clang -pthread generally implies -lpthread, # except when -nostdlib is passed. # This is problematic using libtool to build C++ shared libraries with pthread: # [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 # [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 # [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 # To solve this, first try -pthread together with -lpthread for GCC AS_IF([test "x$GCC" = "xyes"], [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"]) # Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first AS_IF([test "x$ax_pthread_clang" = "xyes"], [ax_pthread_flags="-pthread,-lpthread -pthread"]) # The presence of a feature test macro requesting re-entrant function # definitions is, on some systems, a strong hint that pthreads support is # correctly enabled case $host_os in darwin* | hpux* | linux* | osf* | solaris*) ax_pthread_check_macro="_REENTRANT" ;; aix*) ax_pthread_check_macro="_THREAD_SAFE" ;; *) ax_pthread_check_macro="--" ;; esac AS_IF([test "x$ax_pthread_check_macro" = "x--"], [ax_pthread_check_cond=0], [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) if test "x$ax_pthread_ok" = "xno"; then for ax_pthread_try_flag in $ax_pthread_flags; do case $ax_pthread_try_flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; *,*) PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include # if $ax_pthread_check_cond # error "$ax_pthread_check_macro must be defined" # endif static void *some_global = NULL; static void routine(void *a) { /* To avoid any unused-parameter or unused-but-set-parameter warning. */ some_global = a; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" AC_MSG_RESULT([$ax_pthread_ok]) AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Clang needs special handling, because older versions handle the -pthread # option in a rather... idiosyncratic way if test "x$ax_pthread_clang" = "xyes"; then # Clang takes -pthread; it has never supported any other flag # (Note 1: This will need to be revisited if a system that Clang # supports has POSIX threads in a separate library. This tends not # to be the way of modern systems, but it's conceivable.) # (Note 2: On some systems, notably Darwin, -pthread is not needed # to get POSIX threads support; the API is always present and # active. We could reasonably leave PTHREAD_CFLAGS empty. But # -pthread does define _REENTRANT, and while the Darwin headers # ignore this macro, third-party headers might not.) # However, older versions of Clang make a point of warning the user # that, in an invocation where only linking and no compilation is # taking place, the -pthread option has no effect ("argument unused # during compilation"). They expect -pthread to be passed in only # when source code is being compiled. # # Problem is, this is at odds with the way Automake and most other # C build frameworks function, which is that the same flags used in # compilation (CFLAGS) are also used in linking. Many systems # supported by AX_PTHREAD require exactly this for POSIX threads # support, and in fact it is often not straightforward to specify a # flag that is used only in the compilation phase and not in # linking. Such a scenario is extremely rare in practice. # # Even though use of the -pthread flag in linking would only print # a warning, this can be a nuisance for well-run software projects # that build with -Werror. So if the active version of Clang has # this misfeature, we search for an option to squash it. AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown # Create an alternate version of $ac_link that compiles and # links in two steps (.c -> .o, .o -> exe) instead of one # (.c -> exe), because the warning occurs only in the second # step ax_pthread_save_ac_link="$ac_link" ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"` ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" ax_pthread_save_CFLAGS="$CFLAGS" for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" ac_link="$ax_pthread_save_ac_link" AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], [ac_link="$ax_pthread_2step_ac_link" AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], [break]) ]) done ac_link="$ax_pthread_save_ac_link" CFLAGS="$ax_pthread_save_CFLAGS" AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" ]) case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in no | unknown) ;; *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; esac fi # $ax_pthread_clang = yes # Various other checks: if test "x$ax_pthread_ok" = "xyes"; then ax_pthread_save_CFLAGS="$CFLAGS" ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_CACHE_CHECK([for joinable pthread attribute], [ax_cv_PTHREAD_JOINABLE_ATTR], [ax_cv_PTHREAD_JOINABLE_ATTR=unknown for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $ax_pthread_attr; return attr /* ; */])], [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], []) done ]) AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ test "x$ax_pthread_joinable_attr_defined" != "xyes"], [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$ax_cv_PTHREAD_JOINABLE_ATTR], [Define to necessary symbol if this constant uses a non-standard name on your system.]) ax_pthread_joinable_attr_defined=yes ]) AC_CACHE_CHECK([whether more special flags are required for pthreads], [ax_cv_PTHREAD_SPECIAL_FLAGS], [ax_cv_PTHREAD_SPECIAL_FLAGS=no case $host_os in solaris*) ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" ;; esac ]) AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ test "x$ax_pthread_special_flags_added" != "xyes"], [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" ax_pthread_special_flags_added=yes]) AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT; return i;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ test "x$ax_pthread_prio_inherit_defined" != "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) ax_pthread_prio_inherit_defined=yes ]) CFLAGS="$ax_pthread_save_CFLAGS" LIBS="$ax_pthread_save_LIBS" # More AIX lossage: compile with *_r variant if test "x$GCC" != "xyes"; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [ AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"]) AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])]) ], [ AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC]) AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])]) ] ) ]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) AC_SUBST([PTHREAD_CXX]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test "x$ax_pthread_ok" = "xyes"; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD mongodb-1.21.0/scripts/autotools/m4/php_mongodb.m40000644000175100001660000000357414760300420016744 0ustar dnl dnl PHP_MONGODB_ADD_SOURCES(source-path, sources [, special-flags]) dnl dnl Adds sources which are located relative to source-path. source-path should dnl be relative to the extension directory (i.e. PHP_EXT_DIR). special-flags dnl will be passed to the compiler. dnl dnl This macro will call PHP_ADD_SOURCES or PHP_ADD_SOURCES_X depending on dnl whether the extension is being built statically or as a shared module. dnl AC_DEFUN([PHP_MONGODB_ADD_SOURCES],[ _src_path=PHP_EXT_DIR(mongodb) dnl Join extension directory and source path case $_src_path in ""[)] _src_path="$1" ;; */[)] _src_path="$_src_path$1" ;; *[)] _src_path="$_src_path/$1" ;; esac dnl Trim trailing slash from source path case $_src_path in */[)] _src_path=${_src_path%?} esac if test "$ext_shared" = "no"; then PHP_ADD_SOURCES($_src_path, [$2], [$3]) else PHP_ADD_SOURCES_X($_src_path, [$2], [$3], shared_objects_mongodb, yes) fi ]) dnl dnl PHP_MONGODB_ADD_INCLUDE(path) dnl dnl Adds an include path relative to the extension source directory (i.e. dnl PHP_EXT_SRCDIR). dnl AC_DEFUN([PHP_MONGODB_ADD_INCLUDE],[ PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(mongodb)[/][$1]) ]) dnl dnl PHP_MONGODB_ADD_BUILD_DIR(path) dnl dnl Adds a build directory relative to the extension build directory (i.e. dnl PHP_EXT_BUILDDIR). dnl AC_DEFUN([PHP_MONGODB_ADD_BUILD_DIR],[ PHP_ADD_BUILD_DIR(PHP_EXT_BUILDDIR(mongodb)[/][$1]) ]) dnl dnl PHP_MONGODB_VALIDATE_ARG(arg-name, valid-values) dnl dnl Checks that value of arg-name is in the space-delimited list of valid-values dnl and raises an error if not. dnl AC_DEFUN([PHP_MONGODB_VALIDATE_ARG], [ ac_php_mongodb_valid_arg="no" for value in $2; do if test "$value" = "$$1"; then ac_php_mongodb_valid_arg="yes" break fi done if test "$ac_php_mongodb_valid_arg" = "no"; then AC_MSG_ERROR([Expected $1 to be one of "$2", "$$1" given]) fi ]) mongodb-1.21.0/scripts/autotools/m4/pkg.m40000644000175100001660000002425014760300420015223 0ustar # https://gitlab.freedesktop.org/pkg-config/pkg-config/-/blob/pkg-config-0.29.2/pkg.m4.in # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR mongodb-1.21.0/scripts/autotools/CheckCompiler.m40000644000175100001660000000327014760300420016631 0ustar # If CFLAGS and CXXFLAGS are unset, default to empty. # This is to tell automake not to include '-g' if C{XX,}FLAGS is not set. # For more info - http://www.gnu.org/software/automake/manual/autoconf.html#C_002b_002b-Compiler if test -z "$CXXFLAGS"; then CXXFLAGS="" fi if test -z "$CFLAGS"; then CFLAGS="" fi AC_PROG_CC AC_PROG_CXX dnl AC_PROG_CC_C99 is previously called in config.m4, but AC_PROG_CC resets CC dnl so call it once more to ensure C99 remains enabled m4_version_prereq([2.70],,[AC_PROG_CC_C99]) # Check that an appropriate C compiler is available. # Note: BEGIN_IGNORE_DEPRECATIONS macro requires GCC 4.6+. c_compiler="unknown" AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #if !(defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)) #error Not a supported GCC compiler #endif #if defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #if GCC_VERSION < 40600 #error Not a supported GCC compiler #endif #endif ])], [c_compiler="gcc"], []) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #if defined(__clang__) #define CLANG_VERSION (__clang_major__ * 10000 \ + __clang_minor__ * 100 \ + __clang_patchlevel__) #if CLANG_VERSION < 30300 #error Not a supported Clang compiler #endif #endif ])], [c_compiler="clang"], []) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #if !(defined(__SUNPRO_C)) #error Not a supported Sun compiler #endif ])], [c_compiler="sun"], []) AC_LANG_POP([C]) if test "$c_compiler" = "unknown"; then AC_MSG_ERROR([Compiler GCC >= 4.6 or Clang >= 3.3 is required for C compilation]) fi AC_C_CONST AC_C_INLINE AC_C_TYPEOF mongodb-1.21.0/scripts/autotools/CheckHost.m40000644000175100001660000000177414760300420016003 0ustar AC_CANONICAL_HOST os_win32=no os_netbsd=no os_freebsd=no os_openbsd=no os_hpux=no os_linux=no os_solaris=no os_darwin=no os_gnu=no os_aix=no case "$host" in *-mingw*|*-*-cygwin*) os_win32=yes TARGET_OS=windows ;; *-*-*netbsd*) os_netbsd=yes TARGET_OS=unix ;; *-*-*freebsd*) os_freebsd=yes TARGET_OS=unix ;; *-*-*openbsd*) os_openbsd=yes TARGET_OS=unix ;; *-*-hpux*) os_hpux=yes TARGET_OS=unix ;; *-*-linux*) os_linux=yes os_gnu=yes TARGET_OS=unix ;; *-*-solaris*) os_solaris=yes TARGET_OS=unix ;; *-*-darwin*) os_darwin=yes TARGET_OS=unix ;; *-*-aix*|*-*-os400*) os_aix=yes TARGET_OS=unix ;; gnu*|k*bsd*-gnu*) os_gnu=yes TARGET_OS=unix ;; *) AC_MSG_WARN([*** Please add $host to configure.ac checks!]) ;; esac mongodb-1.21.0/scripts/autotools/PlatformFlags.m40000644000175100001660000000231314760300420016657 0ustar dnl Enable POSIX features up to POSIX.1-2008 plus the XSI extension and BSD-derived definitions. dnl Both _BSD_SOURCE and _DEFAULT_SOURCE are defined for backwards-compatibility with glibc 2.19 and earlier. dnl _BSD_SOURCE and _DEFAULT_SOURCE are required by `getpagesize`, `h_errno`, etc. dnl _XOPEN_SOURCE=700 is required by `strnlen`, `strerror_l`, etc. dnl https://man7.org/linux/man-pages/man7/feature_test_macros.7.html dnl https://pubs.opengroup.org/onlinepubs/7908799/xsh/compilation.html CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_DEFAULT_SOURCE" PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_DEFAULT_SOURCE" dnl Enable non-standard features on FreeBSD with __BSD_VISIBLE=1 if test "$os_freebsd" = "yes"; then CPPFLAGS="$CPPFLAGS -D__BSD_VISIBLE=1" PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -D__BSD_VISIBLE=1" fi AS_IF([test "$os_darwin" = "yes"],[ dnl Non-POSIX extensions are required by `_SC_NPROCESSORS_ONLN`. dnl https://opensource.apple.com/source/Libc/Libc-1439.40.11/gen/compat.5.auto.html CPPFLAGS="$CPPFLAGS -D_DARWIN_C_SOURCE" PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS -D_DARWIN_C_SOURCE" ]) mongodb-1.21.0/scripts/clang-format.sh0000755000175100001660000000234414760300420014540 0ustar #!/bin/sh CLANG_ARGS="-Werror" if test x"$1" = xchanged; then FILES1=`git ls-files | grep -v "src/contrib" | grep -v "_arginfo.h" | grep '\.[ch]$'` FILES2=`git ls-files --others --exclude-standard | grep -v "src/contrib" | grep -v "_arginfo.h" | grep '\.[ch]$'` FILES="$FILES1 $FILES2" else FILES1=`git ls-files | grep -v "src/contrib" | grep -v "_arginfo.h" | grep '\.[ch]$'` FILES2=`git ls-files --others --exclude-standard | grep -v "src/contrib" | grep -v "_arginfo.h" | grep '\.[ch]$'` FILES="$FILES1 $FILES2" fi if test x"$1" = xcheck; then CLANG_ARGS="$CLANG_ARGS -n" fi # Find clang-format, we prefer -6.0, but also allow binaries without -suffix as # long as they're >= 6.0.0 CLANG_FORMAT=`which clang-format-6.0` if [ -z "$CLANG_FORMAT" ]; then CLANG_FORMAT=`which clang-format` fi if [ -z "$CLANG_FORMAT" ]; then echo "Couldn't find clang-format" exit fi VERSION=`$CLANG_FORMAT -version | cut -d " " -f 3` VERSION_MAJOR=`echo $VERSION | cut -d "." -f 1` if [ $VERSION_MAJOR -lt 6 ]; then echo "Found clang-format $VERSION but we need >= 6.0.0" exit fi FAILURE="" # Run formatter for i in $FILES; do $CLANG_FORMAT $CLANG_ARGS -i $i [ $? -eq 0 ] || FAILURE="yes" done if [ -z "$FAILURE" ]; then exit 0 fi exit 1 mongodb-1.21.0/scripts/convert-bson-corpus-tests.php0000644000175100001660000002771314760300420017437 0ustar 'Embedded null in code string is not supported in libbson (CDRIVER-1879)', 'Javascript Code with Scope: Unicode and embedded null in code string, empty scope' => 'Embedded null in code string is not supported in libbson (CDRIVER-1879)', 'Top-level document validity: Bad $date (number, not string or hash)' => 'Legacy extended JSON $date syntax uses numbers (CDRIVER-2223)', ]; $for64bitOnly = [ /* Note: Although 64-bit integers be represented by the Int64 class, these * tests fail on 32-bit platforms due to json_canonicalize() roundtripping * values through PHP, which converts large integers to floats. */ 'Int64 type: MinValue' => "Can't represent 64-bit ints on a 32-bit platform", 'Int64 type: MaxValue' => "Can't represent 64-bit ints on a 32-bit platform", ]; $outputPath = realpath(__DIR__ . '/../tests') . '/bson-corpus/'; if ( ! is_dir($outputPath) && ! mkdir($outputPath, 0755, true)) { printf("Error creating output path: %s\n", $outputPath); } foreach (array_slice($argv, 1) as $inputFile) { if ( ! is_readable($inputFile) || ! is_file($inputFile)) { printf("Error reading %s\n", $inputFile); continue; } $test = json_decode(file_get_contents($inputFile), true); if (json_last_error() !== JSON_ERROR_NONE) { printf("Error decoding %s: %s\n", $inputFile, json_last_error_msg()); continue; } if ( ! isset($test['description'])) { printf("Skipping test file without \"description\" field: %s\n", $inputFile); continue; } if ( ! empty($test['valid'])) { foreach ($test['valid'] as $i => $case) { $outputFile = sprintf('%s-valid-%03d.phpt', pathinfo($inputFile, PATHINFO_FILENAME), $i + 1); try { $output = renderPhpt(getParamsForValid($test, $case), $expectedFailures, $for64bitOnly); } catch (Exception $e) { printf("Error processing valid[%d] in %s: %s\n", $i, $inputFile, $e->getMessage()); continue; } if (false === file_put_contents($outputPath . '/' . $outputFile, $output)) { printf("Error writing valid[%d] in %s\n", $i, $inputFile); continue; } } } if ( ! empty($test['decodeErrors'])) { foreach ($test['decodeErrors'] as $i => $case) { $outputFile = sprintf('%s-decodeError-%03d.phpt', pathinfo($inputFile, PATHINFO_FILENAME), $i + 1); try { $output = renderPhpt(getParamsForDecodeError($test, $case), $expectedFailures, $for64bitOnly); } catch (Exception $e) { printf("Error processing decodeErrors[%d] in %s: %s\n", $i, $inputFile, $e->getMessage()); continue; } if (false === file_put_contents($outputPath . '/' . $outputFile, $output)) { printf("Error writing decodeErrors[%d] in %s\n", $i, $inputFile); continue; } } } if ( ! empty($test['parseErrors'])) { foreach ($test['parseErrors'] as $i => $case) { $outputFile = sprintf('%s-parseError-%03d.phpt', pathinfo($inputFile, PATHINFO_FILENAME), $i + 1); try { $output = renderPhpt(getParamsForParseError($test, $case), $expectedFailures, $for64bitOnly); } catch (Exception $e) { printf("Error processing parseErrors[%d] in %s: %s\n", $i, $inputFile, $e->getMessage()); continue; } if (false === file_put_contents($outputPath . '/' . $outputFile, $output)) { printf("Error writing parseErrors[%d] in %s\n", $i, $inputFile); continue; } } } } function getParamsForValid(array $test, array $case) { foreach (['description', 'canonical_bson', 'canonical_extjson'] as $field) { if (!isset($case[$field])) { throw new InvalidArgumentException(sprintf('Missing "%s" field', $field)); } } $code = ''; $expect = ''; $lossy = isset($case['lossy']) ? (boolean) $case['lossy'] : false; $canonicalBson = $case['canonical_bson']; $expectedCanonicalBson = strtolower($canonicalBson); $code .= sprintf('$canonicalBson = hex2bin(%s);', var_export($canonicalBson, true)) . "\n"; if (isset($case['degenerate_bson'])) { $degenerateBson = $case['degenerate_bson']; $expectedDegenerateBson = strtolower($degenerateBson); $code .= sprintf('$degenerateBson = hex2bin(%s);', var_export($degenerateBson, true)) . "\n"; } if (isset($case['converted_bson'])) { $convertedBson = $case['converted_bson']; $expectedConvertedBson = strtolower($convertedBson); $code .= sprintf('$convertedBson = hex2bin(%s);', var_export($convertedBson, true)) . "\n"; } $canonicalExtJson = $case['canonical_extjson']; $expectedCanonicalExtJson = json_canonicalize($canonicalExtJson); $code .= sprintf('$canonicalExtJson = %s;', var_export($canonicalExtJson, true)) . "\n"; if (isset($case['relaxed_extjson'])) { $relaxedExtJson = $case['relaxed_extjson']; $expectedRelaxedExtJson = json_canonicalize($relaxedExtJson); $code .= sprintf('$relaxedExtJson = %s;', var_export($relaxedExtJson, true)) . "\n"; } if (isset($case['degenerate_extjson'])) { $degenerateExtJson = $case['degenerate_extjson']; $expectedDegenerateExtJson = json_canonicalize($degenerateExtJson); $code .= sprintf('$degenerateExtJson = %s;', var_export($degenerateExtJson, true)) . "\n"; } if (isset($case['converted_extjson'])) { $convertedExtJson = $case['converted_extjson']; $expectedConvertedExtJson = json_canonicalize($convertedExtJson); $code .= sprintf('$convertedExtJson = %s;', var_export($convertedExtJson, true)) . "\n"; } $code .= "\n// Canonical BSON -> BSON object -> Canonical BSON\n"; $code .= 'echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n";' . "\n"; $expect .= $expectedCanonicalBson . "\n"; $code .= "\n// Canonical BSON -> BSON object -> Canonical extJSON\n"; $code .= 'echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n";' . "\n"; $expect .= $expectedCanonicalExtJson . "\n"; if (isset($relaxedExtJson)) { $code .= "\n// Canonical BSON -> BSON object -> Relaxed extJSON\n"; $code .= 'echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n";' . "\n"; $expect .= $expectedRelaxedExtJson . "\n"; } if (!$lossy) { $code .= "\n// Canonical extJSON -> BSON object -> Canonical BSON\n"; $code .= 'echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n";' . "\n"; $expect .= $expectedCanonicalBson . "\n"; } if (isset($degenerateBson)) { $code .= "\n// Degenerate BSON -> BSON object -> Canonical BSON\n"; $code .= 'echo bin2hex((string) MongoDB\BSON\Document::fromPHP(MongoDB\BSON\Document::fromBSON($degenerateBson)->toPHP())), "\n";' . "\n"; $expect .= $expectedCanonicalBson . "\n"; $code .= "\n// Degenerate BSON -> BSON object -> Canonical extJSON\n"; $code .= 'echo json_canonicalize(MongoDB\BSON\Document::fromBSON($degenerateBson)->toCanonicalExtendedJSON()), "\n";' . "\n"; $expect .= $expectedCanonicalExtJson . "\n"; if (isset($relaxedExtJson)) { $code .= "\n// Degenerate BSON -> BSON object -> Relaxed extJSON\n"; $code .= 'echo json_canonicalize(MongoDB\BSON\Document::fromBSON($degenerateBson)->toRelaxedExtendedJSON()), "\n";' . "\n"; $expect .= $expectedRelaxedExtJson . "\n"; } } if (isset($degenerateExtJson) && !$lossy) { $code .= "\n// Degenerate extJSON -> BSON object -> Canonical BSON\n"; $code .= 'echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n";' . "\n"; $expect .= $expectedCanonicalBson . "\n"; } if (isset($relaxedExtJson)) { $code .= "\n// Relaxed extJSON -> BSON object -> Relaxed extJSON\n"; $code .= 'echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n";' . "\n"; $expect .= $expectedRelaxedExtJson . "\n"; } return [ '%NAME%' => sprintf('%s: %s', trim($test['description']), trim($case['description'])), '%CODE%' => trim($code), '%EXPECT%' => trim($expect), ]; } function getParamsForDecodeError(array $test, array $case) { foreach (['description', 'bson'] as $field) { if (!isset($case[$field])) { throw new InvalidArgumentException(sprintf('Missing "%s" field', $field)); } } $code = sprintf('$bson = hex2bin(%s);', var_export($case['bson'], true)) . "\n\n"; $code .= "throws(function() use (\$bson) {\n"; $code .= " MongoDB\\BSON\\Document::fromBSON(\$bson)->toPHP();\n"; $code .= "}, 'MongoDB\Driver\Exception\UnexpectedValueException');"; /* We do not test for the exception message, since that may differ based on * the nature of the decoding error. */ $expect = "OK: Got MongoDB\Driver\Exception\UnexpectedValueException"; return [ '%NAME%' => sprintf('%s: %s', trim($test['description']), trim($case['description'])), '%CODE%' => trim($code), '%EXPECT%' => trim($expect), ]; } function getParamsForParseError(array $test, array $case) { foreach (['description', 'string'] as $field) { if (!isset($case[$field])) { throw new InvalidArgumentException(sprintf('Missing "%s" field', $field)); } } $code = ''; $expect = ''; switch ($test['bson_type']) { case '0x00': // Top-level document case '0x05': // Binary $code = "throws(function() {\n"; $code .= sprintf(" MongoDB\\BSON\\Document::fromJSON(%s);\n", var_export($case['string'], true)); $code .= "}, 'MongoDB\Driver\Exception\UnexpectedValueException');"; /* We do not test for the exception message, since that may differ * based on the nature of the parse error. */ $expect = "OK: Got MongoDB\Driver\Exception\UnexpectedValueException"; break; case '0x13': // Decimal128 $code = "throws(function() {\n"; $code .= sprintf(" new MongoDB\BSON\Decimal128(%s);\n", var_export($case['string'], true)); $code .= "}, 'MongoDB\Driver\Exception\InvalidArgumentException');"; /* We do not test for the exception message, since that may differ * based on the nature of the parse error. */ $expect = "OK: Got MongoDB\Driver\Exception\InvalidArgumentException"; break; default: throw new UnexpectedValueException(sprintf("Parse errors not supported for BSON type: %s", $test['bson_type'])); } return [ '%NAME%' => sprintf('%s: %s', trim($test['description']), trim($case['description'])), '%CODE%' => trim($code), '%EXPECT%' => trim($expect), ]; } function renderPhpt(array $params, array $expectedFailures, array $for64bitOnly) { $params['%XFAIL%'] = isset($expectedFailures[$params['%NAME%']]) ? "--XFAIL--\n" . $expectedFailures[$params['%NAME%']] . "\n" : ''; $params['%SKIPIF%'] = isset($for64bitOnly[$params['%NAME%']]) ? "--SKIPIF--\n" . "" . "\n" : ''; $template = <<< 'TEMPLATE' --TEST-- %NAME% %XFAIL%%SKIPIF%--DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- %EXPECT% ===DONE=== TEMPLATE; return str_replace(array_keys($params), array_values($params), $template); } mongodb-1.21.0/scripts/generate-functionmap.php0000644000175100001660000001054214760300420016452 0ustar createFunctionMap($filename); printf("Created call map in %s\n", $filename); class FunctionMapGenerator { public function createFunctionMap(string $filename): void { $this->writeFunctionMap($filename, $this->getFunctionMap()); } private function getFunctionMap(): array { $classes = array_filter(get_declared_classes(), $this->filterItems(...)); $interfaces = array_filter(get_declared_interfaces(), $this->filterItems(...)); $functions = array_filter(get_defined_functions()['internal'], $this->filterItems(...)); $functionMap = []; // Generate call map for functions foreach ($functions as $functionName) { $reflectionFunction = new ReflectionFunction($functionName); $functionMap[$reflectionFunction->getName()] = $this->getFunctionMapEntry($reflectionFunction); } // Generate call map for classes and interfaces $members = array_merge($classes, $interfaces); sort($members); $skippedMethods = ['__set_state', '__wakeup', '__serialize', '__unserialize']; foreach ($members as $member) { $reflectionClass = new ReflectionClass($member); foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { if ($method->getDeclaringClass() != $reflectionClass && $method->getName() != '__toString') { continue; } if (in_array($method->getName(), $skippedMethods, true)) { continue; } $methodKey = $reflectionClass->getName() . '::' . $method->getName(); $functionMap[$methodKey] = $this->getFunctionMapEntry($method); } } return $functionMap; } private function writeFunctionMap(string $filename, array $functionMap): void { $lines = []; foreach ($functionMap as $methodName => $typeInfo) { $generatedTypeInfo = implode( ', ', array_map( function (string|int $key, string $value): string { if (is_int($key)) { return $this->removeDoubleBackslash(var_export($value, true)); } return sprintf('%s => %s', var_export($key, true), $this->removeDoubleBackslash(var_export($value, true))); }, array_keys($typeInfo), array_values($typeInfo) ) ); $lines[] = sprintf( ' %s => [%s],', $this->removeDoubleBackslash(var_export($methodName, true)), $generatedTypeInfo ); } $fileTemplate = <<<'PHP' hasReturnType() => (string) $function->getReturnType(), $function->hasTentativeReturnType() => (string) $function->getTentativeReturnType(), default => 'void', }; $functionMapEntry = [$returnType]; foreach ($function->getParameters() as $parameter) { $parameterKey = $parameter->getName(); if ($parameter->isOptional()) { $parameterKey .= '='; } $functionMapEntry[$parameterKey] = (string) $parameter->getType(); } return $functionMapEntry; } private function removeDoubleBackslash(string $string): string { return str_replace('\\\\', '\\', $string); } } mongodb-1.21.0/scripts/update-sbom.sh0000755000175100001660000000146714760300420014413 0ustar #!/usr/bin/env bash SCRIPT_DIR=$(dirname ${BASH_SOURCE[0]}) ROOT_DIR=$(realpath "${SCRIPT_DIR}/../") PURLS_FILE="${ROOT_DIR}/purls.txt" LIBMONGOC_VERSION=$(cat ${ROOT_DIR}/src/LIBMONGOC_VERSION_CURRENT | tr -d '[:space:]') LIBMONGOCRYPT_VERSION=$(cat ${ROOT_DIR}/src/LIBMONGOCRYPT_VERSION_CURRENT | tr -d '[:space:]') # Generate purls file from stored versions echo "pkg:github/mongodb/mongo-c-driver@${LIBMONGOC_VERSION}" > $PURLS_FILE echo "pkg:github/mongodb/libmongocrypt@${LIBMONGOCRYPT_VERSION}" >> $PURLS_FILE # Use silkbomb to update the sbom.json file docker run --platform="linux/amd64" -it --rm -v ${ROOT_DIR}:/pwd \ artifactory.corp.mongodb.com/release-tools-container-registry-public-local/silkbomb:1.0 \ update --sbom-in /pwd/sbom.json --purls /pwd/purls.txt --sbom-out /pwd/sbom.json rm $PURLS_FILE mongodb-1.21.0/scripts/update-submodule-sources.php0000644000175100001660000000466614760300420017311 0ustar 'src/libmongoc/src/common/src', 'PHP_MONGODB_KMS_MESSAGE_SOURCES' => 'src/libmongoc/src/kms-message/src', 'PHP_MONGODB_BSON_SOURCES' => 'src/libmongoc/src/libbson/src/bson', 'PHP_MONGODB_JSONSL_SOURCES' => 'src/libmongoc/src/libbson/src/jsonsl', 'PHP_MONGODB_MONGOC_SOURCES' => 'src/libmongoc/src/libmongoc/src/mongoc', 'PHP_MONGODB_UTF8PROC_SOURCES' => 'src/libmongoc/src/utf8proc-2.8.0', 'PHP_MONGODB_ZLIB_SOURCES' => 'src/libmongoc/src/zlib-1.3.1', 'PHP_MONGODB_MONGOCRYPT_SOURCES' => 'src/libmongocrypt/src', 'PHP_MONGODB_MONGOCRYPT_CRYPTO_SOURCES' => 'src/libmongocrypt/src/crypto', 'PHP_MONGODB_MONGOCRYPT_OS_POSIX_SOURCES' => 'src/libmongocrypt/src/os_posix', 'PHP_MONGODB_MONGOCRYPT_OS_WIN_SOURCES' => 'src/libmongocrypt/src/os_win', 'PHP_MONGODB_MONGOCRYPT_KMS_MESSAGE_SOURCES' => 'src/libmongocrypt/kms-message/src', // Note: src/libmongocrypt/src/mlib does not contain source files (as of libmongocrypt 1.3.2) ]; $patterns = []; $replacements = []; // Paths are relative to the project root directory chdir(__DIR__ . '/..'); foreach ($vars as $var => $path) { $cutNth = 2 + substr_count($path, '/'); $files = trim(shell_exec(sprintf($cmd, $path, $cutNth))); // Note: utf8proc_data.c is included from utf8proc.c and should not be compiled directly if ($var === 'PHP_MONGODB_UTF8PROC_SOURCES') { $files = trim(str_replace('utf8proc_data.c', '', $files)); } $patterns[] = sprintf('/(%s=")([^"]*)(";?)/', $var); $replacements[] = '$1' . $files . '$3'; } $files = [ realpath(__DIR__ . '/../config.m4') => count($patterns), // config.w32 does not use PHP_MONGODB_ZLIB_SOURCES (PHPC-1111) realpath(__DIR__ . '/../config.w32') => count($patterns) - 1, ]; foreach ($files as $file => $expectedCount) { $replaced = preg_replace($patterns, $replacements, file_get_contents($file), 1, $count); if ($count !== $expectedCount) { fprintf(STDERR, "Skipping %s: Expected %d replacements but only matched %d\n", basename($file), $expectedCount, $count); continue; } printf("Updated %s\n", basename($file)); file_put_contents($file, $replaced); } mongodb-1.21.0/src/BSON/Binary.c0000644000175100001660000002436014760300420013062 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "Binary_arginfo.h" #define PHONGO_BINARY_UUID_SIZE 16 zend_class_entry* php_phongo_binary_ce; /* Initialize the object and return whether it was successful. An exception will * be thrown on error. */ static bool php_phongo_binary_init(php_phongo_binary_t* intern, const char* data, size_t data_len, zend_long type) { if (type < 0 || type > UINT8_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected type to be an unsigned 8-bit integer, %" PHONGO_LONG_FORMAT " given", type); return false; } if ((type == BSON_SUBTYPE_UUID_DEPRECATED || type == BSON_SUBTYPE_UUID) && data_len != PHONGO_BINARY_UUID_SIZE) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected UUID length to be %d bytes, %d given", PHONGO_BINARY_UUID_SIZE, data_len); return false; } intern->data = estrndup(data, data_len); intern->data_len = data_len; intern->type = (uint8_t) type; return true; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_binary_init_from_hash(php_phongo_binary_t* intern, HashTable* props) { zval *data, *type; if ((data = zend_hash_str_find(props, "data", sizeof("data") - 1)) && Z_TYPE_P(data) == IS_STRING && (type = zend_hash_str_find(props, "type", sizeof("type") - 1)) && Z_TYPE_P(type) == IS_LONG) { return php_phongo_binary_init(intern, Z_STRVAL_P(data), Z_STRLEN_P(data), Z_LVAL_P(type)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"data\" string and \"type\" integer fields", ZSTR_VAL(php_phongo_binary_ce->name)); return false; } static HashTable* php_phongo_binary_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_binary_t* intern; HashTable* props; intern = Z_OBJ_BINARY(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 2); if (!intern->data) { return props; } { zval data, type; ZVAL_STRINGL(&data, intern->data, intern->data_len); zend_hash_str_update(props, "data", sizeof("data") - 1, &data); ZVAL_LONG(&type, intern->type); zend_hash_str_update(props, "type", sizeof("type") - 1, &type); } return props; } /* Construct a new BSON binary type */ static PHP_METHOD(MongoDB_BSON_Binary, __construct) { php_phongo_binary_t* intern; char* data; size_t data_len; zend_long type = BSON_SUBTYPE_BINARY; intern = Z_BINARY_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STRING(data, data_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(type) PHONGO_PARSE_PARAMETERS_END(); php_phongo_binary_init(intern, data, data_len, type); } static PHP_METHOD(MongoDB_BSON_Binary, __set_state) { php_phongo_binary_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_binary_ce); intern = Z_BINARY_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_binary_init_from_hash(intern, props); } /* Return the Binary's data string. */ static PHP_METHOD(MongoDB_BSON_Binary, __toString) { php_phongo_binary_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_BINARY_OBJ_P(getThis()); RETURN_STRINGL(intern->data, intern->data_len); } static PHP_METHOD(MongoDB_BSON_Binary, getData) { php_phongo_binary_t* intern; intern = Z_BINARY_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRINGL(intern->data, intern->data_len); } static PHP_METHOD(MongoDB_BSON_Binary, getType) { php_phongo_binary_t* intern; intern = Z_BINARY_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->type); } static PHP_METHOD(MongoDB_BSON_Binary, jsonSerialize) { php_phongo_binary_t* intern; char type[3]; int type_len; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_BINARY_OBJ_P(getThis()); array_init_size(return_value, 2); { zend_string* data = php_base64_encode((unsigned char*) intern->data, intern->data_len); ADD_ASSOC_STRINGL(return_value, "$binary", ZSTR_VAL(data), ZSTR_LEN(data)); zend_string_free(data); } type_len = snprintf(type, sizeof(type), "%02x", intern->type); ADD_ASSOC_STRINGL(return_value, "$type", type, type_len); } static PHP_METHOD(MongoDB_BSON_Binary, serialize) { php_phongo_binary_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; intern = Z_BINARY_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 2); ADD_ASSOC_STRINGL(&retval, "data", intern->data, intern->data_len); ADD_ASSOC_LONG_EX(&retval, "type", intern->type); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_Binary, unserialize) { php_phongo_binary_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_BINARY_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_binary_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_binary_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_Binary, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_binary_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_Binary, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_binary_init_from_hash(Z_BINARY_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\Binary object handlers */ static zend_object_handlers php_phongo_handler_binary; static void php_phongo_binary_free_object(zend_object* object) { php_phongo_binary_t* intern = Z_OBJ_BINARY(object); zend_object_std_dtor(&intern->std); if (intern->data) { efree(intern->data); } if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_binary_create_object(zend_class_entry* class_type) { php_phongo_binary_t* intern = zend_object_alloc(sizeof(php_phongo_binary_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_binary; return &intern->std; } static zend_object* php_phongo_binary_clone_object(zend_object* object) { php_phongo_binary_t* intern; php_phongo_binary_t* new_intern; zend_object* new_object; intern = Z_OBJ_BINARY(object); new_object = php_phongo_binary_create_object(object->ce); new_intern = Z_OBJ_BINARY(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); php_phongo_binary_init(new_intern, intern->data, intern->data_len, intern->type); return new_object; } static int php_phongo_binary_compare_objects(zval* o1, zval* o2) { php_phongo_binary_t *intern1, *intern2; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_BINARY_OBJ_P(o1); intern2 = Z_BINARY_OBJ_P(o2); /* MongoDB compares binary types first by the data length, then by the type * byte, and finally by the binary data itself. */ if (intern1->data_len != intern2->data_len) { return intern1->data_len < intern2->data_len ? -1 : 1; } if (intern1->type != intern2->type) { return intern1->type < intern2->type ? -1 : 1; } return zend_binary_strcmp(intern1->data, intern1->data_len, intern2->data, intern2->data_len); } static HashTable* php_phongo_binary_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_binary_get_properties_hash(object, true); } static HashTable* php_phongo_binary_get_properties(zend_object* object) { return php_phongo_binary_get_properties_hash(object, false); } void php_phongo_binary_init_ce(INIT_FUNC_ARGS) { php_phongo_binary_ce = register_class_MongoDB_BSON_Binary(php_phongo_binary_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_binary_ce->create_object = php_phongo_binary_create_object; memcpy(&php_phongo_handler_binary, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_binary.compare = php_phongo_binary_compare_objects; php_phongo_handler_binary.clone_obj = php_phongo_binary_clone_object; php_phongo_handler_binary.get_debug_info = php_phongo_binary_get_debug_info; php_phongo_handler_binary.get_properties = php_phongo_binary_get_properties; php_phongo_handler_binary.free_obj = php_phongo_binary_free_object; php_phongo_handler_binary.offset = XtOffsetOf(php_phongo_binary_t, std); } bool phongo_binary_new(zval* object, const char* data, size_t data_len, bson_subtype_t type) { php_phongo_binary_t* intern; object_init_ex(object, php_phongo_binary_ce); intern = Z_BINARY_OBJ_P(object); intern->data = estrndup(data, data_len); intern->data_len = data_len; intern->type = (uint8_t) type; return true; } mongodb-1.21.0/src/BSON/Binary.h0000644000175100001660000000147414760300420013070 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_BSON_BINARY_H #define PHONGO_BSON_BINARY_H #define PHONGO_BINARY_UUID_SIZE 16 bool phongo_binary_new(zval* object, const char* data, size_t data_len, bson_subtype_t type); #endif /* PHONGO_BSON_BINARY_H */ mongodb-1.21.0/src/BSON/BinaryInterface.c0000644000175100001660000000155514760300420014704 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "BinaryInterface_arginfo.h" zend_class_entry* php_phongo_binary_interface_ce; void php_phongo_binary_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_binary_interface_ce = register_class_MongoDB_BSON_BinaryInterface(); } mongodb-1.21.0/src/BSON/BinaryInterface_arginfo.h0000644000175100001660000000260414760300420016412 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 9177931b152386567f53fed87887207971acceaf */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_BinaryInterface_getData, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_BinaryInterface_getType, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_BinaryInterface___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_BSON_BinaryInterface_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_BinaryInterface, getData, arginfo_class_MongoDB_BSON_BinaryInterface_getData, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_BinaryInterface, getType, arginfo_class_MongoDB_BSON_BinaryInterface_getType, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_BinaryInterface, __toString, arginfo_class_MongoDB_BSON_BinaryInterface___toString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_BinaryInterface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "BinaryInterface", class_MongoDB_BSON_BinaryInterface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/Binary_arginfo.h0000644000175100001660000001747514760300420014605 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 5b480f539df83a112ecaecc234364272d9209257 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Binary___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, type, IS_LONG, 0, "MongoDB\\BSON\\Binary::TYPE_GENERIC") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary_getData, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary_getType, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Binary___set_state, 0, 1, MongoDB\\BSON\\Binary, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Binary___toString arginfo_class_MongoDB_BSON_Binary_getData #define arginfo_class_MongoDB_BSON_Binary_serialize arginfo_class_MongoDB_BSON_Binary_getData ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Binary, __construct); static ZEND_METHOD(MongoDB_BSON_Binary, getData); static ZEND_METHOD(MongoDB_BSON_Binary, getType); static ZEND_METHOD(MongoDB_BSON_Binary, __set_state); static ZEND_METHOD(MongoDB_BSON_Binary, __toString); static ZEND_METHOD(MongoDB_BSON_Binary, serialize); static ZEND_METHOD(MongoDB_BSON_Binary, unserialize); static ZEND_METHOD(MongoDB_BSON_Binary, __unserialize); static ZEND_METHOD(MongoDB_BSON_Binary, __serialize); static ZEND_METHOD(MongoDB_BSON_Binary, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Binary_methods[] = { ZEND_ME(MongoDB_BSON_Binary, __construct, arginfo_class_MongoDB_BSON_Binary___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, getData, arginfo_class_MongoDB_BSON_Binary_getData, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, getType, arginfo_class_MongoDB_BSON_Binary_getType, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, __set_state, arginfo_class_MongoDB_BSON_Binary___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, __toString, arginfo_class_MongoDB_BSON_Binary___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, serialize, arginfo_class_MongoDB_BSON_Binary_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, unserialize, arginfo_class_MongoDB_BSON_Binary_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, __unserialize, arginfo_class_MongoDB_BSON_Binary___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, __serialize, arginfo_class_MongoDB_BSON_Binary___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, jsonSerialize, arginfo_class_MongoDB_BSON_Binary_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Binary(zend_class_entry *class_entry_MongoDB_BSON_BinaryInterface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Binary", class_MongoDB_BSON_Binary_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_MongoDB_BSON_BinaryInterface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); zval const_TYPE_GENERIC_value; ZVAL_LONG(&const_TYPE_GENERIC_value, BSON_SUBTYPE_BINARY); zend_string *const_TYPE_GENERIC_name = zend_string_init_interned("TYPE_GENERIC", sizeof("TYPE_GENERIC") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_GENERIC_name, &const_TYPE_GENERIC_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_GENERIC_name); zval const_TYPE_FUNCTION_value; ZVAL_LONG(&const_TYPE_FUNCTION_value, BSON_SUBTYPE_FUNCTION); zend_string *const_TYPE_FUNCTION_name = zend_string_init_interned("TYPE_FUNCTION", sizeof("TYPE_FUNCTION") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_FUNCTION_name, &const_TYPE_FUNCTION_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_FUNCTION_name); zval const_TYPE_OLD_BINARY_value; ZVAL_LONG(&const_TYPE_OLD_BINARY_value, BSON_SUBTYPE_BINARY_DEPRECATED); zend_string *const_TYPE_OLD_BINARY_name = zend_string_init_interned("TYPE_OLD_BINARY", sizeof("TYPE_OLD_BINARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_OLD_BINARY_name, &const_TYPE_OLD_BINARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_OLD_BINARY_name); zval const_TYPE_OLD_UUID_value; ZVAL_LONG(&const_TYPE_OLD_UUID_value, BSON_SUBTYPE_UUID_DEPRECATED); zend_string *const_TYPE_OLD_UUID_name = zend_string_init_interned("TYPE_OLD_UUID", sizeof("TYPE_OLD_UUID") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_OLD_UUID_name, &const_TYPE_OLD_UUID_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_OLD_UUID_name); zval const_TYPE_UUID_value; ZVAL_LONG(&const_TYPE_UUID_value, BSON_SUBTYPE_UUID); zend_string *const_TYPE_UUID_name = zend_string_init_interned("TYPE_UUID", sizeof("TYPE_UUID") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_UUID_name, &const_TYPE_UUID_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_UUID_name); zval const_TYPE_MD5_value; ZVAL_LONG(&const_TYPE_MD5_value, BSON_SUBTYPE_MD5); zend_string *const_TYPE_MD5_name = zend_string_init_interned("TYPE_MD5", sizeof("TYPE_MD5") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_MD5_name, &const_TYPE_MD5_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_MD5_name); zval const_TYPE_ENCRYPTED_value; ZVAL_LONG(&const_TYPE_ENCRYPTED_value, BSON_SUBTYPE_ENCRYPTED); zend_string *const_TYPE_ENCRYPTED_name = zend_string_init_interned("TYPE_ENCRYPTED", sizeof("TYPE_ENCRYPTED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_ENCRYPTED_name, &const_TYPE_ENCRYPTED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_ENCRYPTED_name); zval const_TYPE_COLUMN_value; ZVAL_LONG(&const_TYPE_COLUMN_value, BSON_SUBTYPE_COLUMN); zend_string *const_TYPE_COLUMN_name = zend_string_init_interned("TYPE_COLUMN", sizeof("TYPE_COLUMN") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_COLUMN_name, &const_TYPE_COLUMN_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_COLUMN_name); zval const_TYPE_SENSITIVE_value; ZVAL_LONG(&const_TYPE_SENSITIVE_value, BSON_SUBTYPE_SENSITIVE); zend_string *const_TYPE_SENSITIVE_name = zend_string_init_interned("TYPE_SENSITIVE", sizeof("TYPE_SENSITIVE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_SENSITIVE_name, &const_TYPE_SENSITIVE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_SENSITIVE_name); zval const_TYPE_USER_DEFINED_value; ZVAL_LONG(&const_TYPE_USER_DEFINED_value, BSON_SUBTYPE_USER); zend_string *const_TYPE_USER_DEFINED_name = zend_string_init_interned("TYPE_USER_DEFINED", sizeof("TYPE_USER_DEFINED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_USER_DEFINED_name, &const_TYPE_USER_DEFINED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_USER_DEFINED_name); return class_entry; } mongodb-1.21.0/src/BSON/DBPointer.c0000644000175100001660000002252614760300420013466 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "DBPointer_arginfo.h" zend_class_entry* php_phongo_dbpointer_ce; /* Initialize the object and return whether it was successful. An exception will * be thrown on error. */ static bool php_phongo_dbpointer_init(php_phongo_dbpointer_t* intern, const char* ref, size_t ref_len, const char* id, size_t id_len) { if (strlen(ref) != (size_t) ref_len) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Ref cannot contain null bytes"); return false; } if (!bson_oid_is_valid(id, id_len)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing ObjectId string: %s", id); return false; } intern->ref = estrndup(ref, ref_len); intern->ref_len = ref_len; memset(intern->id, 0, sizeof(intern->id)); strncpy(intern->id, id, sizeof(intern->id) - 1); return true; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_dbpointer_init_from_hash(php_phongo_dbpointer_t* intern, HashTable* props) { zval *ref, *id; if ((ref = zend_hash_str_find(props, "ref", sizeof("ref") - 1)) && Z_TYPE_P(ref) == IS_STRING && (id = zend_hash_str_find(props, "id", sizeof("id") - 1)) && Z_TYPE_P(id) == IS_STRING) { return php_phongo_dbpointer_init(intern, Z_STRVAL_P(ref), Z_STRLEN_P(ref), Z_STRVAL_P(id), Z_STRLEN_P(id)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"ref\" and \"id\" string fields", ZSTR_VAL(php_phongo_dbpointer_ce->name)); return false; } HashTable* php_phongo_dbpointer_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_dbpointer_t* intern; HashTable* props; intern = Z_OBJ_DBPOINTER(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 2); if (!intern->ref) { return props; } { zval ref, id; ZVAL_STRING(&ref, intern->ref); ZVAL_STRING(&id, intern->id); zend_hash_str_update(props, "ref", sizeof("ref") - 1, &ref); zend_hash_str_update(props, "id", sizeof("id") - 1, &id); } return props; } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_DBPointer) /* Return the DBPointer's namespace string and ObjectId. */ static PHP_METHOD(MongoDB_BSON_DBPointer, __toString) { php_phongo_dbpointer_t* intern; char* retval; int retval_len; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_DBPOINTER_OBJ_P(getThis()); retval_len = spprintf(&retval, 0, "[%s/%s]", intern->ref, intern->id); RETVAL_STRINGL(retval, retval_len); efree(retval); } static PHP_METHOD(MongoDB_BSON_DBPointer, __set_state) { php_phongo_dbpointer_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_dbpointer_ce); intern = Z_DBPOINTER_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_dbpointer_init_from_hash(intern, props); } static PHP_METHOD(MongoDB_BSON_DBPointer, jsonSerialize) { php_phongo_dbpointer_t* intern; zval zdb_pointer; zval zoid; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_DBPOINTER_OBJ_P(getThis()); array_init_size(&zdb_pointer, 2); array_init_size(&zoid, 1); ADD_ASSOC_STRINGL(&zdb_pointer, "$ref", intern->ref, intern->ref_len); ADD_ASSOC_STRING(&zoid, "$oid", intern->id); ADD_ASSOC_ZVAL(&zdb_pointer, "$id", &zoid); array_init_size(return_value, 1); ADD_ASSOC_ZVAL(return_value, "$dbPointer", &zdb_pointer); } static PHP_METHOD(MongoDB_BSON_DBPointer, serialize) { php_phongo_dbpointer_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; intern = Z_DBPOINTER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 2); ADD_ASSOC_STRINGL(&retval, "ref", intern->ref, intern->ref_len); ADD_ASSOC_STRING(&retval, "id", intern->id); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_DBPointer, unserialize) { php_phongo_dbpointer_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_DBPOINTER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_dbpointer_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_dbpointer_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_DBPointer, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_dbpointer_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_DBPointer, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_dbpointer_init_from_hash(Z_DBPOINTER_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\DBPointer object handlers */ static zend_object_handlers php_phongo_handler_dbpointer; static void php_phongo_dbpointer_free_object(zend_object* object) { php_phongo_dbpointer_t* intern = Z_OBJ_DBPOINTER(object); zend_object_std_dtor(&intern->std); if (intern->ref) { efree(intern->ref); } if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } zend_object* php_phongo_dbpointer_create_object(zend_class_entry* class_type) { php_phongo_dbpointer_t* intern = zend_object_alloc(sizeof(php_phongo_dbpointer_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_dbpointer; return &intern->std; } static zend_object* php_phongo_dbpointer_clone_object(zend_object* object) { php_phongo_dbpointer_t* intern; php_phongo_dbpointer_t* new_intern; zend_object* new_object; intern = Z_OBJ_DBPOINTER(object); new_object = php_phongo_dbpointer_create_object(object->ce); new_intern = Z_OBJ_DBPOINTER(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); php_phongo_dbpointer_init(new_intern, intern->ref, intern->ref_len, intern->id, 24); return new_object; } static int php_phongo_dbpointer_compare_objects(zval* o1, zval* o2) { php_phongo_dbpointer_t *intern1, *intern2; int retval; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_DBPOINTER_OBJ_P(o1); intern2 = Z_DBPOINTER_OBJ_P(o2); retval = strcmp(intern1->ref, intern2->ref); if (retval != 0) { return retval; } return strcmp(intern1->id, intern2->id); } static HashTable* php_phongo_dbpointer_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_dbpointer_get_properties_hash(object, true); } static HashTable* php_phongo_dbpointer_get_properties(zend_object* object) { return php_phongo_dbpointer_get_properties_hash(object, false); } void php_phongo_dbpointer_init_ce(INIT_FUNC_ARGS) { php_phongo_dbpointer_ce = register_class_MongoDB_BSON_DBPointer(php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_dbpointer_ce->create_object = php_phongo_dbpointer_create_object; memcpy(&php_phongo_handler_dbpointer, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_dbpointer.compare = php_phongo_dbpointer_compare_objects; php_phongo_handler_dbpointer.clone_obj = php_phongo_dbpointer_clone_object; php_phongo_handler_dbpointer.get_debug_info = php_phongo_dbpointer_get_debug_info; php_phongo_handler_dbpointer.get_properties = php_phongo_dbpointer_get_properties; php_phongo_handler_dbpointer.free_obj = php_phongo_dbpointer_free_object; php_phongo_handler_dbpointer.offset = XtOffsetOf(php_phongo_dbpointer_t, std); } bool phongo_dbpointer_new(zval* object, const char* ref, size_t ref_len, const bson_oid_t* oid) { php_phongo_dbpointer_t* intern; object_init_ex(object, php_phongo_dbpointer_ce); intern = Z_DBPOINTER_OBJ_P(object); intern->ref = estrndup(ref, ref_len); intern->ref_len = ref_len; bson_oid_to_string(oid, intern->id); return true; } mongodb-1.21.0/src/BSON/DBPointer.h0000644000175100001660000000144414760300420013467 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_DBPOINTER_H #define PHONGO_BSON_DBPOINTER_H bool phongo_dbpointer_new(zval* object, const char* ref, size_t ref_len, const bson_oid_t* oid); #endif /* PHONGO_BSON_DBPOINTER_H */ mongodb-1.21.0/src/BSON/DBPointer_arginfo.h0000644000175100001660000000666514760300420015206 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 0fd301b8c3e14f219023edc4d3137304f2bea022 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_DBPointer___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_DBPointer___set_state, 0, 1, MongoDB\\BSON\\DBPointer, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_DBPointer___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_DBPointer_serialize arginfo_class_MongoDB_BSON_DBPointer___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_DBPointer_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_DBPointer___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_DBPointer___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_DBPointer_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_DBPointer, __construct); static ZEND_METHOD(MongoDB_BSON_DBPointer, __set_state); static ZEND_METHOD(MongoDB_BSON_DBPointer, __toString); static ZEND_METHOD(MongoDB_BSON_DBPointer, serialize); static ZEND_METHOD(MongoDB_BSON_DBPointer, unserialize); static ZEND_METHOD(MongoDB_BSON_DBPointer, __unserialize); static ZEND_METHOD(MongoDB_BSON_DBPointer, __serialize); static ZEND_METHOD(MongoDB_BSON_DBPointer, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_DBPointer_methods[] = { ZEND_ME(MongoDB_BSON_DBPointer, __construct, arginfo_class_MongoDB_BSON_DBPointer___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_DBPointer, __set_state, arginfo_class_MongoDB_BSON_DBPointer___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_DBPointer, __toString, arginfo_class_MongoDB_BSON_DBPointer___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_DBPointer, serialize, arginfo_class_MongoDB_BSON_DBPointer_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_DBPointer, unserialize, arginfo_class_MongoDB_BSON_DBPointer_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_DBPointer, __unserialize, arginfo_class_MongoDB_BSON_DBPointer___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_DBPointer, __serialize, arginfo_class_MongoDB_BSON_DBPointer___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_DBPointer, jsonSerialize, arginfo_class_MongoDB_BSON_DBPointer_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_DBPointer(zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "DBPointer", class_MongoDB_BSON_DBPointer_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 4, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Decimal128.c0000644000175100001660000002125214760300420013424 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "Decimal128_arginfo.h" zend_class_entry* php_phongo_decimal128_ce; /* Initialize the object and return whether it was successful. An exception will * be thrown on error. */ static bool php_phongo_decimal128_init(php_phongo_decimal128_t* intern, const char* value) { if (!bson_decimal128_from_string(value, &intern->decimal)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing Decimal128 string: %s", value); return false; } intern->initialized = true; return true; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_decimal128_init_from_hash(php_phongo_decimal128_t* intern, HashTable* props) { zval* dec; if ((dec = zend_hash_str_find(props, "dec", sizeof("dec") - 1)) && Z_TYPE_P(dec) == IS_STRING) { return php_phongo_decimal128_init(intern, Z_STRVAL_P(dec)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"dec\" string field", ZSTR_VAL(php_phongo_decimal128_ce->name)); return false; } static HashTable* php_phongo_decimal128_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_decimal128_t* intern; HashTable* props; char outbuf[BSON_DECIMAL128_STRING] = ""; intern = Z_OBJ_DECIMAL128(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 1); if (!intern->initialized) { return props; } bson_decimal128_to_string(&intern->decimal, outbuf); { zval dec; ZVAL_STRING(&dec, outbuf); zend_hash_str_update(props, "dec", sizeof("dec") - 1, &dec); } return props; } /* Construct a new BSON Decimal128 type */ static PHP_METHOD(MongoDB_BSON_Decimal128, __construct) { php_phongo_decimal128_t* intern; char* value; size_t value_len; intern = Z_DECIMAL128_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(value, value_len) PHONGO_PARSE_PARAMETERS_END(); php_phongo_decimal128_init(intern, value); } static PHP_METHOD(MongoDB_BSON_Decimal128, __set_state) { php_phongo_decimal128_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_decimal128_ce); intern = Z_DECIMAL128_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_decimal128_init_from_hash(intern, props); } static PHP_METHOD(MongoDB_BSON_Decimal128, __toString) { php_phongo_decimal128_t* intern; char outbuf[BSON_DECIMAL128_STRING]; intern = Z_DECIMAL128_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); bson_decimal128_to_string(&intern->decimal, outbuf); RETURN_STRING(outbuf); } static PHP_METHOD(MongoDB_BSON_Decimal128, jsonSerialize) { php_phongo_decimal128_t* intern; char outbuf[BSON_DECIMAL128_STRING] = ""; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_DECIMAL128_OBJ_P(getThis()); array_init_size(return_value, 1); bson_decimal128_to_string(&intern->decimal, outbuf); ADD_ASSOC_STRING(return_value, "$numberDecimal", outbuf); } static PHP_METHOD(MongoDB_BSON_Decimal128, serialize) { php_phongo_decimal128_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; char outbuf[BSON_DECIMAL128_STRING]; intern = Z_DECIMAL128_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); bson_decimal128_to_string(&intern->decimal, outbuf); array_init_size(&retval, 1); ADD_ASSOC_STRING(&retval, "dec", outbuf); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_Decimal128, unserialize) { php_phongo_decimal128_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_DECIMAL128_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_decimal128_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_decimal128_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_Decimal128, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_decimal128_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_Decimal128, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_decimal128_init_from_hash(Z_DECIMAL128_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\Decimal128 object handlers */ static zend_object_handlers php_phongo_handler_decimal128; static void php_phongo_decimal128_free_object(zend_object* object) { php_phongo_decimal128_t* intern = Z_OBJ_DECIMAL128(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_decimal128_create_object(zend_class_entry* class_type) { php_phongo_decimal128_t* intern = zend_object_alloc(sizeof(php_phongo_decimal128_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_decimal128; return &intern->std; } static zend_object* php_phongo_decimal128_clone_object(zend_object* object) { php_phongo_decimal128_t* intern; php_phongo_decimal128_t* new_intern; zend_object* new_object; intern = Z_OBJ_DECIMAL128(object); new_object = php_phongo_decimal128_create_object(object->ce); new_intern = Z_OBJ_DECIMAL128(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); // Use memcpy to copy bson value to avoid converting to string and back memcpy(&new_intern->decimal, &intern->decimal, sizeof(bson_decimal128_t)); new_intern->initialized = true; return new_object; } static HashTable* php_phongo_decimal128_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_decimal128_get_properties_hash(object, true); } static HashTable* php_phongo_decimal128_get_properties(zend_object* object) { return php_phongo_decimal128_get_properties_hash(object, false); } void php_phongo_decimal128_init_ce(INIT_FUNC_ARGS) { php_phongo_decimal128_ce = register_class_MongoDB_BSON_Decimal128(php_phongo_decimal128_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_decimal128_ce->create_object = php_phongo_decimal128_create_object; memcpy(&php_phongo_handler_decimal128, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_decimal128.clone_obj = php_phongo_decimal128_clone_object; php_phongo_handler_decimal128.get_debug_info = php_phongo_decimal128_get_debug_info; php_phongo_handler_decimal128.get_properties = php_phongo_decimal128_get_properties; php_phongo_handler_decimal128.free_obj = php_phongo_decimal128_free_object; php_phongo_handler_decimal128.offset = XtOffsetOf(php_phongo_decimal128_t, std); } bool phongo_decimal128_new(zval* object, const bson_decimal128_t* decimal) { php_phongo_decimal128_t* intern; object_init_ex(object, php_phongo_decimal128_ce); intern = Z_DECIMAL128_OBJ_P(object); memcpy(&intern->decimal, decimal, sizeof(bson_decimal128_t)); intern->initialized = true; return true; } mongodb-1.21.0/src/BSON/Decimal128.h0000644000175100001660000000142214760300420013426 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_DECIMAL128_H #define PHONGO_BSON_DECIMAL128_H bool phongo_decimal128_new(zval* object, const bson_decimal128_t* decimal); #endif /* PHONGO_BSON_DECIMAL128_H */ mongodb-1.21.0/src/BSON/Decimal128Interface.c0000644000175100001660000000160114760300420015241 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "Decimal128Interface_arginfo.h" zend_class_entry* php_phongo_decimal128_interface_ce; void php_phongo_decimal128_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_decimal128_interface_ce = register_class_MongoDB_BSON_Decimal128Interface(); } mongodb-1.21.0/src/BSON/Decimal128Interface_arginfo.h0000644000175100001660000000153014760300420016754 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: d6d5d5cf0e586b9d76d208ea72b851da3cd37c34 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Decimal128Interface___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_BSON_Decimal128Interface_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_Decimal128Interface, __toString, arginfo_class_MongoDB_BSON_Decimal128Interface___toString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Decimal128Interface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Decimal128Interface", class_MongoDB_BSON_Decimal128Interface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/Decimal128_arginfo.h0000644000175100001660000000716414760300420015144 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: e2a5c43ff506b05c576242ab76ea1cb7fd9f5c30 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Decimal128___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Decimal128___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Decimal128___set_state, 0, 1, MongoDB\\BSON\\Decimal128, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Decimal128_serialize arginfo_class_MongoDB_BSON_Decimal128___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Decimal128_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Decimal128___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Decimal128___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Decimal128_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Decimal128, __construct); static ZEND_METHOD(MongoDB_BSON_Decimal128, __toString); static ZEND_METHOD(MongoDB_BSON_Decimal128, __set_state); static ZEND_METHOD(MongoDB_BSON_Decimal128, serialize); static ZEND_METHOD(MongoDB_BSON_Decimal128, unserialize); static ZEND_METHOD(MongoDB_BSON_Decimal128, __unserialize); static ZEND_METHOD(MongoDB_BSON_Decimal128, __serialize); static ZEND_METHOD(MongoDB_BSON_Decimal128, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Decimal128_methods[] = { ZEND_ME(MongoDB_BSON_Decimal128, __construct, arginfo_class_MongoDB_BSON_Decimal128___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Decimal128, __toString, arginfo_class_MongoDB_BSON_Decimal128___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Decimal128, __set_state, arginfo_class_MongoDB_BSON_Decimal128___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Decimal128, serialize, arginfo_class_MongoDB_BSON_Decimal128_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Decimal128, unserialize, arginfo_class_MongoDB_BSON_Decimal128_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Decimal128, __unserialize, arginfo_class_MongoDB_BSON_Decimal128___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Decimal128, __serialize, arginfo_class_MongoDB_BSON_Decimal128___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Decimal128, jsonSerialize, arginfo_class_MongoDB_BSON_Decimal128_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Decimal128(zend_class_entry *class_entry_MongoDB_BSON_Decimal128Interface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Decimal128", class_MongoDB_BSON_Decimal128_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_MongoDB_BSON_Decimal128Interface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Document.c0000644000175100001660000004563514760300420013424 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php_phongo.h" #include "phongo_error.h" #include "phongo_bson_encode.h" #include "BSON/Document_arginfo.h" #include "BSON/Iterator.h" zend_class_entry* php_phongo_document_ce; /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_document_init_from_hash(php_phongo_document_t* intern, HashTable* props) { zval* data; if ((data = zend_hash_str_find(props, "data", sizeof("data") - 1)) && Z_TYPE_P(data) == IS_STRING) { zend_string* decoded = php_base64_decode_str(Z_STR_P(data)); intern->bson = bson_new_from_data((const uint8_t*) ZSTR_VAL(decoded), ZSTR_LEN(decoded)); zend_string_free(decoded); if (intern->bson == NULL) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires valid BSON", ZSTR_VAL(php_phongo_document_ce->name)); return false; } return true; } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"data\" string field", ZSTR_VAL(php_phongo_document_ce->name)); return false; } static HashTable* php_phongo_document_get_properties_hash(zend_object* object, bool is_temp, int size) { php_phongo_document_t* intern; HashTable* props; intern = Z_OBJ_DOCUMENT(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, size); if (!intern->bson) { return props; } { zval data; ZVAL_STR(&data, php_base64_encode((const unsigned char*) bson_get_data(intern->bson), intern->bson->len)); zend_hash_str_update(props, "data", sizeof("data") - 1, &data); } return props; } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_Document) static PHP_METHOD(MongoDB_BSON_Document, fromBSON) { zval zv; php_phongo_document_t* intern = NULL; zend_string* bson_string; const bson_t* bson; bson_reader_t* reader; bool eof = false; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(bson_string) PHONGO_PARSE_PARAMETERS_END(); reader = bson_reader_new_from_data((const uint8_t*) ZSTR_VAL(bson_string), ZSTR_LEN(bson_string)); if (!(bson = bson_reader_read(reader, NULL))) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not read document from BSON reader"); goto cleanup; } object_init_ex(&zv, php_phongo_document_ce); intern = Z_DOCUMENT_OBJ_P(&zv); intern->bson = bson_copy(bson); if (bson_reader_read(reader, &eof) || !eof) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Reading document did not exhaust input buffer"); zval_ptr_dtor(&zv); goto cleanup; } RETVAL_ZVAL(&zv, 1, 1); cleanup: if (reader) { bson_reader_destroy(reader); } } static PHP_METHOD(MongoDB_BSON_Document, fromJSON) { zval zv; php_phongo_document_t* intern; zend_string* json; bson_t* bson; bson_error_t error; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(json) PHONGO_PARSE_PARAMETERS_END(); bson = bson_new_from_json((const uint8_t*) ZSTR_VAL(json), ZSTR_LEN(json), &error); if (!bson) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s", error.domain == BSON_ERROR_JSON ? error.message : "Error parsing JSON"); return; } object_init_ex(&zv, php_phongo_document_ce); intern = Z_DOCUMENT_OBJ_P(&zv); intern->bson = bson; RETURN_ZVAL(&zv, 1, 1); } static PHP_METHOD(MongoDB_BSON_Document, fromPHP) { zval zv; php_phongo_document_t* intern; zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY_OR_OBJECT(data) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(&zv, php_phongo_document_ce); intern = Z_DOCUMENT_OBJ_P(&zv); intern->bson = bson_new(); // Explicitly allow constructing a Document from a PackedArray php_phongo_zval_to_bson(data, PHONGO_BSON_ALLOW_ROOT_ARRAY, intern->bson, NULL); RETURN_ZVAL(&zv, 1, 1); } static bool php_phongo_document_get(php_phongo_document_t* intern, char* key, size_t key_len, zval* return_value, bool null_if_missing) { bson_iter_t iter; if (!bson_iter_init(&iter, intern->bson)) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not initialize BSON iterator"); return false; } if (!bson_iter_find_w_len(&iter, key, key_len)) { if (null_if_missing) { ZVAL_NULL(return_value); return true; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key \"%s\" in BSON document", key); return false; } phongo_bson_value_to_zval(bson_iter_value(&iter), return_value); return true; } static bool php_phongo_document_get_by_zval(php_phongo_document_t* intern, zval* key, zval* return_value, bool null_if_missing) { if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_LONG) { if (null_if_missing) { ZVAL_NULL(return_value); return true; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find key of type \"%s\" in BSON document", zend_zval_type_name(key)); return false; } zend_string* tmp_str; zend_string* str = zval_try_get_tmp_string(key, &tmp_str); if (!str) { // Exception already thrown return false; } if (!php_phongo_document_get(intern, ZSTR_VAL(str), ZSTR_LEN(str), return_value, null_if_missing)) { // Exception already thrown zend_tmp_string_release(tmp_str); return false; } zend_tmp_string_release(tmp_str); return true; } static PHP_METHOD(MongoDB_BSON_Document, get) { php_phongo_document_t* intern; char* key; size_t key_len; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(key, key_len) PHONGO_PARSE_PARAMETERS_END(); intern = Z_DOCUMENT_OBJ_P(getThis()); // May throw, in which case we do nothing php_phongo_document_get(intern, key, key_len, return_value, false); } static PHP_METHOD(MongoDB_BSON_Document, getIterator) { PHONGO_PARSE_PARAMETERS_NONE(); phongo_iterator_init(return_value, getThis()); } static bool php_phongo_document_has(php_phongo_document_t* intern, char* key, size_t key_len) { bson_iter_t iter; if (!bson_iter_init(&iter, intern->bson)) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not initialize BSON iterator"); return false; } return bson_iter_find_w_len(&iter, key, key_len); } static bool php_phongo_document_has_by_zval(php_phongo_document_t* intern, zval* key) { if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_LONG) { return false; } zend_string* tmp_str; zend_string* str = zval_try_get_tmp_string(key, &tmp_str); if (!str) { // Exception already thrown return false; } if (!php_phongo_document_has(intern, ZSTR_VAL(str), ZSTR_LEN(str))) { // Exception may be thrown if BSON iterator could not be initialized zend_tmp_string_release(tmp_str); return false; } zend_tmp_string_release(tmp_str); return true; } static PHP_METHOD(MongoDB_BSON_Document, has) { php_phongo_document_t* intern; char* key; size_t key_len; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(key, key_len) PHONGO_PARSE_PARAMETERS_END(); intern = Z_DOCUMENT_OBJ_P(getThis()); RETURN_BOOL(php_phongo_document_has(intern, key, key_len)); } static PHP_METHOD(MongoDB_BSON_Document, toCanonicalExtendedJSON) { php_phongo_document_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_DOCUMENT_OBJ_P(getThis()); php_phongo_bson_to_json(return_value, intern->bson, PHONGO_JSON_MODE_CANONICAL); } static PHP_METHOD(MongoDB_BSON_Document, toRelaxedExtendedJSON) { php_phongo_document_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_DOCUMENT_OBJ_P(getThis()); php_phongo_bson_to_json(return_value, intern->bson, PHONGO_JSON_MODE_RELAXED); } static PHP_METHOD(MongoDB_BSON_Document, toPHP) { php_phongo_document_t* intern; zval* typemap = NULL; php_phongo_bson_state state; PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_ARRAY(typemap) PHONGO_PARSE_PARAMETERS_END(); PHONGO_BSON_INIT_STATE(state); if (!php_phongo_bson_typemap_to_state(typemap, &state.map)) { return; } intern = Z_DOCUMENT_OBJ_P(getThis()); state.map.int64_as_object = true; if (!php_phongo_bson_to_zval_ex(intern->bson, &state)) { zval_ptr_dtor(&state.zchild); php_phongo_bson_typemap_dtor(&state.map); RETURN_NULL(); } php_phongo_bson_typemap_dtor(&state.map); RETURN_ZVAL(&state.zchild, 0, 1); } static PHP_METHOD(MongoDB_BSON_Document, offsetExists) { php_phongo_document_t* intern; zval* offset; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(offset) PHONGO_PARSE_PARAMETERS_END(); intern = Z_DOCUMENT_OBJ_P(getThis()); RETURN_BOOL(php_phongo_document_has_by_zval(intern, offset)); } static PHP_METHOD(MongoDB_BSON_Document, offsetGet) { php_phongo_document_t* intern; zval* offset; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(offset) PHONGO_PARSE_PARAMETERS_END(); intern = Z_DOCUMENT_OBJ_P(getThis()); // May throw, in which case we do nothing php_phongo_document_get_by_zval(intern, offset, return_value, false); } static PHP_METHOD(MongoDB_BSON_Document, offsetSet) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot write to %s property", ZSTR_VAL(php_phongo_document_ce->name)); } static PHP_METHOD(MongoDB_BSON_Document, offsetUnset) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot unset %s property", ZSTR_VAL(php_phongo_document_ce->name)); } static PHP_METHOD(MongoDB_BSON_Document, __toString) { php_phongo_document_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_DOCUMENT_OBJ_P(getThis()); RETVAL_STRINGL((const char*) bson_get_data(intern->bson), intern->bson->len); } static PHP_METHOD(MongoDB_BSON_Document, __set_state) { php_phongo_document_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_document_ce); intern = Z_DOCUMENT_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_document_init_from_hash(intern, props); } static PHP_METHOD(MongoDB_BSON_Document, serialize) { php_phongo_document_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; zend_string* str; intern = Z_DOCUMENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 1); str = php_base64_encode(bson_get_data(intern->bson), intern->bson->len); ADD_ASSOC_STR(&retval, "data", str); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); zend_string_free(str); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_Document, unserialize) { php_phongo_document_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_DOCUMENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_document_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_document_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_Document, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_document_get_properties_hash(Z_OBJ_P(getThis()), true, 1)); } static PHP_METHOD(MongoDB_BSON_Document, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_document_init_from_hash(Z_DOCUMENT_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\BSON object handlers */ static zend_object_handlers php_phongo_handler_document; static void php_phongo_document_free_object(zend_object* object) { php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); zend_object_std_dtor(&intern->std); if (intern->bson) { bson_destroy(intern->bson); } if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_document_create_object(zend_class_entry* class_type) { php_phongo_document_t* intern = zend_object_alloc(sizeof(php_phongo_document_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_document; return &intern->std; } static zend_object* php_phongo_document_clone_object(zend_object* object) { php_phongo_document_t* intern; php_phongo_document_t* new_intern; zend_object* new_object; intern = Z_OBJ_DOCUMENT(object); new_object = php_phongo_document_create_object(object->ce); new_intern = Z_OBJ_DOCUMENT(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); new_intern->bson = bson_copy(intern->bson); return new_object; } static int php_phongo_document_compare_objects(zval* o1, zval* o2) { php_phongo_document_t *intern1, *intern2; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_DOCUMENT_OBJ_P(o1); intern2 = Z_DOCUMENT_OBJ_P(o2); return bson_compare(intern1->bson, intern2->bson); } static HashTable* php_phongo_document_get_debug_info(zend_object* object, int* is_temp) { php_phongo_document_t* intern; HashTable* props; *is_temp = 1; intern = Z_OBJ_DOCUMENT(object); /* This get_debug_info handler reports an additional property. This does not * conflict with other uses of php_phongo_document_get_properties_hash since * we always allocated a new HashTable with is_temp=true. */ props = php_phongo_document_get_properties_hash(object, true, 2); { php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); state.map.array.type = PHONGO_TYPEMAP_BSON; state.map.document.type = PHONGO_TYPEMAP_BSON; if (!php_phongo_bson_to_zval_ex(intern->bson, &state)) { zval_ptr_dtor(&state.zchild); goto failure; } zend_hash_str_update(props, "value", sizeof("value") - 1, &state.zchild); } return props; failure: PHONGO_GET_PROPERTY_HASH_FREE_PROPS(is_temp, props); return NULL; } static HashTable* php_phongo_document_get_properties(zend_object* object) { return php_phongo_document_get_properties_hash(object, false, 1); } zval* php_phongo_document_read_property(zend_object* object, zend_string* member, int type, void** cache_slot, zval* rv) { php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); if (!php_phongo_document_get(intern, ZSTR_VAL(member), ZSTR_LEN(member), rv, type == BP_VAR_IS)) { // Exception already thrown return &EG(uninitialized_zval); } return rv; } zval* php_phongo_document_write_property(zend_object* object, zend_string* member, zval* value, void** cache_slot) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot write to %s property", ZSTR_VAL(php_phongo_document_ce->name)); return value; } int php_phongo_document_has_property(zend_object* object, zend_string* member, int has_set_exists, void** cache_slot) { php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); return php_phongo_document_has(intern, ZSTR_VAL(member), ZSTR_LEN(member)); } void php_phongo_document_unset_property(zend_object* object, zend_string* member, void** cache_slot) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot unset %s property", ZSTR_VAL(php_phongo_document_ce->name)); } zval* php_phongo_document_read_dimension(zend_object* object, zval* offset, int type, zval* rv) { php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); if (!php_phongo_document_get_by_zval(intern, offset, rv, type == BP_VAR_IS)) { // Exception already thrown return &EG(uninitialized_zval); } return rv; } void php_phongo_document_write_dimension(zend_object* object, zval* offset, zval* value) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot write to %s property", ZSTR_VAL(php_phongo_document_ce->name)); } int php_phongo_document_has_dimension(zend_object* object, zval* member, int check_empty) { php_phongo_document_t* intern = Z_OBJ_DOCUMENT(object); return php_phongo_document_has_by_zval(intern, member); } void php_phongo_document_unset_dimension(zend_object* object, zval* offset) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot unset %s property", ZSTR_VAL(php_phongo_document_ce->name)); } void php_phongo_document_init_ce(INIT_FUNC_ARGS) { php_phongo_document_ce = register_class_MongoDB_BSON_Document(zend_ce_aggregate, zend_ce_serializable, zend_ce_arrayaccess, php_phongo_type_ce, zend_ce_stringable); php_phongo_document_ce->create_object = php_phongo_document_create_object; memcpy(&php_phongo_handler_document, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_document.compare = php_phongo_document_compare_objects; php_phongo_handler_document.clone_obj = php_phongo_document_clone_object; php_phongo_handler_document.get_debug_info = php_phongo_document_get_debug_info; php_phongo_handler_document.get_properties = php_phongo_document_get_properties; php_phongo_handler_document.free_obj = php_phongo_document_free_object; php_phongo_handler_document.read_property = php_phongo_document_read_property; php_phongo_handler_document.write_property = php_phongo_document_write_property; php_phongo_handler_document.has_property = php_phongo_document_has_property; php_phongo_handler_document.unset_property = php_phongo_document_unset_property; php_phongo_handler_document.read_dimension = php_phongo_document_read_dimension; php_phongo_handler_document.write_dimension = php_phongo_document_write_dimension; php_phongo_handler_document.has_dimension = php_phongo_document_has_dimension; php_phongo_handler_document.unset_dimension = php_phongo_document_unset_dimension; php_phongo_handler_document.offset = XtOffsetOf(php_phongo_document_t, std); } bool phongo_document_new(zval* object, bson_t* bson, bool copy) { php_phongo_document_t* intern; object_init_ex(object, php_phongo_document_ce); intern = Z_DOCUMENT_OBJ_P(object); intern->bson = copy ? bson_copy(bson) : bson; return true; } mongodb-1.21.0/src/BSON/Document.h0000644000175100001660000000140114760300420013410 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_DOCUMENT_H #define PHONGO_BSON_DOCUMENT_H bool phongo_document_new(zval* object, bson_t* bson, bool copy); #endif /* PHONGO_BSON_DOCUMENT_H */ mongodb-1.21.0/src/BSON/Document_arginfo.h0000644000175100001660000001713114760300420015124 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 4efc86c2e070f6d6a8dd5cbfe6ea126fba9a4251 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Document___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Document_fromBSON, 0, 1, MongoDB\\BSON\\Document, 0) ZEND_ARG_TYPE_INFO(0, bson, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Document_fromJSON, 0, 1, MongoDB\\BSON\\Document, 0) ZEND_ARG_TYPE_INFO(0, json, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Document_fromPHP, 0, 1, MongoDB\\BSON\\Document, 0) ZEND_ARG_TYPE_MASK(0, value, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document_get, 0, 1, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Document_getIterator, 0, 0, MongoDB\\BSON\\Iterator, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document_has, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_MongoDB_BSON_Document_toPHP, 0, 0, MAY_BE_ARRAY|MAY_BE_OBJECT) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, typeMap, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document_toCanonicalExtendedJSON, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Document_toRelaxedExtendedJSON arginfo_class_MongoDB_BSON_Document_toCanonicalExtendedJSON ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document_offsetExists, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document_offsetGet, 0, 1, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document_offsetSet, 0, 2, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document_offsetUnset, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Document___toString arginfo_class_MongoDB_BSON_Document_toCanonicalExtendedJSON ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Document___set_state, 0, 1, MongoDB\\BSON\\Document, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Document_serialize arginfo_class_MongoDB_BSON_Document_toCanonicalExtendedJSON ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Document___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Document, __construct); static ZEND_METHOD(MongoDB_BSON_Document, fromBSON); static ZEND_METHOD(MongoDB_BSON_Document, fromJSON); static ZEND_METHOD(MongoDB_BSON_Document, fromPHP); static ZEND_METHOD(MongoDB_BSON_Document, get); static ZEND_METHOD(MongoDB_BSON_Document, getIterator); static ZEND_METHOD(MongoDB_BSON_Document, has); static ZEND_METHOD(MongoDB_BSON_Document, toPHP); static ZEND_METHOD(MongoDB_BSON_Document, toCanonicalExtendedJSON); static ZEND_METHOD(MongoDB_BSON_Document, toRelaxedExtendedJSON); static ZEND_METHOD(MongoDB_BSON_Document, offsetExists); static ZEND_METHOD(MongoDB_BSON_Document, offsetGet); static ZEND_METHOD(MongoDB_BSON_Document, offsetSet); static ZEND_METHOD(MongoDB_BSON_Document, offsetUnset); static ZEND_METHOD(MongoDB_BSON_Document, __toString); static ZEND_METHOD(MongoDB_BSON_Document, __set_state); static ZEND_METHOD(MongoDB_BSON_Document, serialize); static ZEND_METHOD(MongoDB_BSON_Document, unserialize); static ZEND_METHOD(MongoDB_BSON_Document, __unserialize); static ZEND_METHOD(MongoDB_BSON_Document, __serialize); static const zend_function_entry class_MongoDB_BSON_Document_methods[] = { ZEND_ME(MongoDB_BSON_Document, __construct, arginfo_class_MongoDB_BSON_Document___construct, ZEND_ACC_PRIVATE) ZEND_ME(MongoDB_BSON_Document, fromBSON, arginfo_class_MongoDB_BSON_Document_fromBSON, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, fromJSON, arginfo_class_MongoDB_BSON_Document_fromJSON, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, fromPHP, arginfo_class_MongoDB_BSON_Document_fromPHP, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, get, arginfo_class_MongoDB_BSON_Document_get, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, getIterator, arginfo_class_MongoDB_BSON_Document_getIterator, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, has, arginfo_class_MongoDB_BSON_Document_has, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, toPHP, arginfo_class_MongoDB_BSON_Document_toPHP, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, toCanonicalExtendedJSON, arginfo_class_MongoDB_BSON_Document_toCanonicalExtendedJSON, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, toRelaxedExtendedJSON, arginfo_class_MongoDB_BSON_Document_toRelaxedExtendedJSON, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, offsetExists, arginfo_class_MongoDB_BSON_Document_offsetExists, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_BSON_Document, offsetGet, arginfo_class_MongoDB_BSON_Document_offsetGet, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_BSON_Document, offsetSet, arginfo_class_MongoDB_BSON_Document_offsetSet, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_BSON_Document, offsetUnset, arginfo_class_MongoDB_BSON_Document_offsetUnset, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_BSON_Document, __toString, arginfo_class_MongoDB_BSON_Document___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, __set_state, arginfo_class_MongoDB_BSON_Document___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, serialize, arginfo_class_MongoDB_BSON_Document_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, unserialize, arginfo_class_MongoDB_BSON_Document_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, __unserialize, arginfo_class_MongoDB_BSON_Document___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Document, __serialize, arginfo_class_MongoDB_BSON_Document___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Document(zend_class_entry *class_entry_IteratorAggregate, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_ArrayAccess, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Document", class_MongoDB_BSON_Document_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_IteratorAggregate, class_entry_Serializable, class_entry_ArrayAccess, class_entry_MongoDB_BSON_Type, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Int64.c0000644000175100001660000004371314760300420012545 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "phongo_util.h" #include "Int64_arginfo.h" zend_class_entry* php_phongo_int64_ce; /* Initialize the object and return whether it was successful. */ static bool php_phongo_int64_init(php_phongo_int64_t* intern, int64_t integer) { intern->integer = integer; intern->initialized = true; return true; } /* Initialize the object from a numeric string and return whether it was * successful. An exception will be thrown on error. */ static bool php_phongo_int64_init_from_string(php_phongo_int64_t* intern, const char* s_integer, size_t s_integer_len) { int64_t integer; if (!php_phongo_parse_int64(&integer, s_integer, s_integer_len)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing \"%s\" as 64-bit integer for %s initialization", s_integer, ZSTR_VAL(php_phongo_int64_ce->name)); return false; } return php_phongo_int64_init(intern, integer); } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_int64_init_from_hash(php_phongo_int64_t* intern, HashTable* props) { zval* value; if ((value = zend_hash_str_find(props, "integer", sizeof("integer") - 1)) && Z_TYPE_P(value) == IS_STRING) { return php_phongo_int64_init_from_string(intern, Z_STRVAL_P(value), Z_STRLEN_P(value)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"integer\" string field", ZSTR_VAL(php_phongo_int64_ce->name)); return false; } HashTable* php_phongo_int64_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_int64_t* intern; HashTable* props; intern = Z_OBJ_INT64(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 2); if (!intern->initialized) { return props; } { zval value; ZVAL_INT64_STRING(&value, intern->integer); zend_hash_str_update(props, "integer", sizeof("integer") - 1, &value); } return props; } static PHP_METHOD(MongoDB_BSON_Int64, __construct) { php_phongo_int64_t* intern; zval* value; intern = Z_INT64_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(value); PHONGO_PARSE_PARAMETERS_END(); if (Z_TYPE_P(value) == IS_STRING) { php_phongo_int64_init_from_string(intern, Z_STRVAL_P(value), Z_STRLEN_P(value)); } else if (Z_TYPE_P(value) == IS_LONG) { php_phongo_int64_init(intern, Z_LVAL_P(value)); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected value to be integer or string, %s given", zend_zval_type_name(value)); } } /* Return the Int64's value as a string. */ static PHP_METHOD(MongoDB_BSON_Int64, __toString) { php_phongo_int64_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_INT64_OBJ_P(getThis()); ZVAL_INT64_STRING(return_value, intern->integer); } static PHP_METHOD(MongoDB_BSON_Int64, __set_state) { php_phongo_int64_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_int64_ce); intern = Z_INT64_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_int64_init_from_hash(intern, props); } static PHP_METHOD(MongoDB_BSON_Int64, jsonSerialize) { php_phongo_int64_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_INT64_OBJ_P(getThis()); array_init_size(return_value, 1); ADD_ASSOC_INT64_AS_STRING(return_value, "$numberLong", intern->integer); } static PHP_METHOD(MongoDB_BSON_Int64, serialize) { php_phongo_int64_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_INT64_OBJ_P(getThis()); array_init_size(&retval, 1); ADD_ASSOC_INT64_AS_STRING(&retval, "integer", intern->integer); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_Int64, unserialize) { php_phongo_int64_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_INT64_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_int64_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_int64_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_Int64, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_int64_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_Int64, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_int64_init_from_hash(Z_INT64_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\Int64 object handlers */ static zend_object_handlers php_phongo_handler_int64; static void php_phongo_int64_free_object(zend_object* object) { php_phongo_int64_t* intern = Z_OBJ_INT64(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } zend_object* php_phongo_int64_create_object(zend_class_entry* class_type) { php_phongo_int64_t* intern = zend_object_alloc(sizeof(php_phongo_int64_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_int64; return &intern->std; } static zend_object* php_phongo_int64_clone_object(zend_object* object) { php_phongo_int64_t* intern; php_phongo_int64_t* new_intern; zend_object* new_object; intern = Z_OBJ_INT64(object); new_object = php_phongo_int64_create_object(object->ce); new_intern = Z_OBJ_INT64(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); php_phongo_int64_init(new_intern, intern->integer); return new_object; } static bool php_phongo_int64_is_int64_object(zval* object) { if (Z_TYPE_P(object) != IS_OBJECT) { return false; } return Z_OBJ_P(object)->ce == php_phongo_int64_ce; } static bool php_phongo_int64_is_long_or_double(zval* value) { return Z_TYPE_P(value) == IS_LONG || Z_TYPE_P(value) == IS_DOUBLE; } static int php_phongo_int64_compare_int64_objects(zval* o1, zval* o2) { php_phongo_int64_t *intern1, *intern2; intern1 = Z_INT64_OBJ_P(o1); intern2 = Z_INT64_OBJ_P(o2); if (intern1->integer != intern2->integer) { return intern1->integer < intern2->integer ? -1 : 1; } return 0; } static int php_phongo_int64_compare_with_long_or_float(zval* object, zval* value) { php_phongo_int64_t* intern; int64_t long_value; double double_value; intern = Z_INT64_OBJ_P(object); assert(php_phongo_int64_is_long_or_double(value)); switch (Z_TYPE_P(value)) { case IS_LONG: long_value = Z_LVAL_P(value); if (intern->integer != long_value) { return intern->integer < long_value ? -1 : 1; } break; case IS_DOUBLE: double_value = Z_DVAL_P(value); if (intern->integer != double_value) { return intern->integer < double_value ? -1 : 1; } break; default: return 0; } return 0; } static int php_phongo_int64_compare_objects(zval* o1, zval* o2) { if (php_phongo_int64_is_int64_object(o1) && php_phongo_int64_is_int64_object(o2)) { return php_phongo_int64_compare_int64_objects(o1, o2); } if (php_phongo_int64_is_int64_object(o1) && php_phongo_int64_is_long_or_double(o2)) { return php_phongo_int64_compare_with_long_or_float(o1, o2); } if (php_phongo_int64_is_long_or_double(o1) && php_phongo_int64_is_int64_object(o2)) { // Invert the result as we're flipping the values used for comparison return -1 * php_phongo_int64_compare_with_long_or_float(o2, o1); } ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); return 0; } static zend_result php_phongo_int64_cast_object(zend_object* readobj, zval* retval, int type) { php_phongo_int64_t* intern; intern = Z_OBJ_INT64(readobj); switch (type) { case IS_DOUBLE: ZVAL_DOUBLE(retval, (double) intern->integer); return SUCCESS; case IS_LONG: case _IS_NUMBER: #if SIZEOF_ZEND_LONG == 4 if (intern->integer > INT32_MAX || intern->integer < INT32_MIN) { zend_error(E_WARNING, "Truncating 64-bit integer value %" PRId64 " to 32 bits", intern->integer); } #endif ZVAL_LONG(retval, intern->integer); return SUCCESS; case _IS_BOOL: ZVAL_BOOL(retval, intern->integer != 0); return SUCCESS; default: return zend_std_cast_object_tostring(readobj, retval, type); } } /* Computes the power of two int64_t values by using the exponentiation by * squaring algorithm. This is necessary because in case the result exceeds * the range of a int64_t, we want PHP to return a float as it would when * using 64-bit values directly. We can't use anything involving zend_long * here as this would limit us to 32 bits on a 32-bit platform. This also * prohibits us from falling back to PHP's default functions after unwrapping * the int64_t from the php_phongo_int64_t instance. */ static int64_t phongo_pow_int64(int64_t base, int64_t exp) { if (exp == 0) { return 1; } if (exp % 2) { return base * phongo_pow_int64(base * base, (exp - 1) / 2); } return phongo_pow_int64(base * base, exp / 2); } #define OPERATION_RESULT_INT64(value) phongo_int64_new(result, (value)); #define PHONGO_GET_INT64(int64, zval) \ if (Z_TYPE_P((zval)) == IS_LONG) { \ (int64) = Z_LVAL_P((zval)); \ } else if (Z_TYPE_P((zval)) == IS_OBJECT && Z_OBJCE_P((zval)) == php_phongo_int64_ce) { \ (int64) = Z_INT64_OBJ_P((zval))->integer; \ } else { \ return FAILURE; \ } #define INT64_SIGN_MASK INT64_MIN /* Overload arithmetic operators for computation on int64_t values. * This ensures that any computation involving at least one php_phongo_int64_t * results in a php_phongo_int64_t value, regardless of whether the result * would fit in an int32_t or not. Results that exceed the 64-bit integer * range are returned as float as PHP would do when using 64-bit integers. * Note that ZEND_(PRE|POST)_(INC|DEC) are not handled here: when checking for * a do_operation handler for inc/dec, PHP calls the handler with a ZEND_ADD * or ZEND_SUB opcode and the same pointer for result and op1, and a ZVAL_LONG * of 1 for op2. */ static zend_result php_phongo_int64_do_operation_ex(zend_uchar opcode, zval* result, zval* op1, zval* op2) { int64_t value1, value2, lresult; PHONGO_GET_INT64(value1, op1); switch (opcode) { case ZEND_ADD: PHONGO_GET_INT64(value2, op2); lresult = value1 + value2; /* The following is based on the logic in fast_long_add_function() in PHP. * If the result sign differs from the first operand sign, we have an overflow if: * - adding a positive to a positive yields a negative, or * - adding a negative to a negative (i.e. subtraction) yields a positive */ if ((value1 & INT64_SIGN_MASK) != (lresult & INT64_SIGN_MASK) && (value1 & INT64_SIGN_MASK) == (value2 & INT64_SIGN_MASK)) { ZVAL_DOUBLE(result, (double) value1 + (double) value2); } else { OPERATION_RESULT_INT64(lresult); } return SUCCESS; case ZEND_SUB: PHONGO_GET_INT64(value2, op2); lresult = value1 - value2; /* The following is based on the logic in fast_long_sub_function() in PHP. * If the result sign differs from the first operand sign, we have an overflow if: * - subtracting a positive from a negative yields a positive, or * - subtracting a negative from a positive (i.e. addition) yields a negative */ if ((value1 & INT64_SIGN_MASK) != (lresult & INT64_SIGN_MASK) && (value1 & INT64_SIGN_MASK) != (value2 & INT64_SIGN_MASK)) { ZVAL_DOUBLE(result, (double) value1 - (double) value2); } else { OPERATION_RESULT_INT64(lresult); } return SUCCESS; case ZEND_MUL: PHONGO_GET_INT64(value2, op2); /* The following is based on the C-native implementation of * ZEND_SIGNED_MULTIPLY_LONG() in PHP if no other methods (e.g. ASM * or _builtin_smull_overflow) can be used. */ { int64_t lres = value1 * value2; long double dres = (long double) value1 * (long double) value2; long double delta = (long double) lres - dres; if ((dres + delta) != dres) { ZVAL_DOUBLE(result, dres); } else { OPERATION_RESULT_INT64(lres); } } return SUCCESS; case ZEND_DIV: PHONGO_GET_INT64(value2, op2); if (value2 == 0) { zend_throw_exception(zend_ce_division_by_zero_error, "Division by zero", 0); return FAILURE; } /* The following is based on div_function_base() in PHP. * - INT64_MIN / 1 exceeds the int64 range -> return double * - if division has a remainder, return double as result can't be * an int */ if ((value1 == INT64_MIN && value2 == -1) || (value1 % value2 != 0)) { ZVAL_DOUBLE(result, (double) value1 / value2); } else { OPERATION_RESULT_INT64(value1 / value2); } return SUCCESS; case ZEND_MOD: PHONGO_GET_INT64(value2, op2); if (value2 == 0) { zend_throw_exception(zend_ce_division_by_zero_error, "Division by zero", 0); return FAILURE; } OPERATION_RESULT_INT64(value1 % value2); return SUCCESS; case ZEND_SL: PHONGO_GET_INT64(value2, op2); OPERATION_RESULT_INT64(value1 << value2); return SUCCESS; case ZEND_SR: PHONGO_GET_INT64(value2, op2); OPERATION_RESULT_INT64(value1 >> value2); return SUCCESS; case ZEND_POW: PHONGO_GET_INT64(value2, op2); // Negative exponents always yield floats, leave them for PHP to handle if (value2 < 0) { return FAILURE; } // Handle 0 separately to distinguish between base 0 and // phongo_pow_int64 overflowing if (value1 == 0) { OPERATION_RESULT_INT64(0); return SUCCESS; } { int64_t pow_result = phongo_pow_int64(value1, value2); // If the result would overflow an int64_t, we let PHP fall back // to its default pow() implementation which returns a float. if (pow_result == 0) { return FAILURE; } OPERATION_RESULT_INT64(pow_result); } return SUCCESS; case ZEND_BW_AND: PHONGO_GET_INT64(value2, op2); OPERATION_RESULT_INT64(value1 & value2); return SUCCESS; case ZEND_BW_OR: PHONGO_GET_INT64(value2, op2); OPERATION_RESULT_INT64(value1 | value2); return SUCCESS; case ZEND_BW_XOR: PHONGO_GET_INT64(value2, op2); OPERATION_RESULT_INT64(value1 ^ value2); return SUCCESS; case ZEND_BW_NOT: OPERATION_RESULT_INT64(~value1); return SUCCESS; default: return FAILURE; } } static zend_result php_phongo_int64_do_operation(zend_uchar opcode, zval* result, zval* op1, zval* op2) { zval op1_copy; int retval; // Copy op1 for unary operations (e.g. $int64++) to ensure correct return values if (result == op1) { ZVAL_COPY_VALUE(&op1_copy, op1); op1 = &op1_copy; } retval = php_phongo_int64_do_operation_ex(opcode, result, op1, op2); if (retval == SUCCESS && op1 == &op1_copy) { zval_ptr_dtor(op1); } return retval; } #undef OPERATION_RESULT_INT64 #undef PHONGO_GET_INT64 #undef INT64_SIGN_MASK static HashTable* php_phongo_int64_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_int64_get_properties_hash(object, true); } static HashTable* php_phongo_int64_get_properties(zend_object* object) { return php_phongo_int64_get_properties_hash(object, false); } void php_phongo_int64_init_ce(INIT_FUNC_ARGS) { php_phongo_int64_ce = register_class_MongoDB_BSON_Int64(php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_int64_ce->create_object = php_phongo_int64_create_object; memcpy(&php_phongo_handler_int64, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_int64.compare = php_phongo_int64_compare_objects; php_phongo_handler_int64.clone_obj = php_phongo_int64_clone_object; php_phongo_handler_int64.get_debug_info = php_phongo_int64_get_debug_info; php_phongo_handler_int64.get_properties = php_phongo_int64_get_properties; php_phongo_handler_int64.free_obj = php_phongo_int64_free_object; php_phongo_handler_int64.offset = XtOffsetOf(php_phongo_int64_t, std); php_phongo_handler_int64.cast_object = php_phongo_int64_cast_object; php_phongo_handler_int64.do_operation = php_phongo_int64_do_operation; } bool phongo_int64_new(zval* object, int64_t integer) { php_phongo_int64_t* intern; object_init_ex(object, php_phongo_int64_ce); intern = Z_INT64_OBJ_P(object); intern->integer = integer; intern->initialized = true; return true; } mongodb-1.21.0/src/BSON/Int64.h0000644000175100001660000000135514760300420012546 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_INT64_H #define PHONGO_BSON_INT64_H bool phongo_int64_new(zval* object, int64_t integer); #endif /* PHONGO_BSON_INT64_H */ mongodb-1.21.0/src/BSON/Int64_arginfo.h0000644000175100001660000000653314760300420014256 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 26a7fdee9a7adefd7d6877669d4d28b9c68d8153 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Int64___construct, 0, 0, 1) ZEND_ARG_TYPE_MASK(0, value, MAY_BE_LONG|MAY_BE_STRING, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Int64___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Int64___set_state, 0, 1, MongoDB\\BSON\\Int64, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Int64_serialize arginfo_class_MongoDB_BSON_Int64___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Int64_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Int64___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Int64___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Int64_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Int64, __construct); static ZEND_METHOD(MongoDB_BSON_Int64, __toString); static ZEND_METHOD(MongoDB_BSON_Int64, __set_state); static ZEND_METHOD(MongoDB_BSON_Int64, serialize); static ZEND_METHOD(MongoDB_BSON_Int64, unserialize); static ZEND_METHOD(MongoDB_BSON_Int64, __unserialize); static ZEND_METHOD(MongoDB_BSON_Int64, __serialize); static ZEND_METHOD(MongoDB_BSON_Int64, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Int64_methods[] = { ZEND_ME(MongoDB_BSON_Int64, __construct, arginfo_class_MongoDB_BSON_Int64___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Int64, __toString, arginfo_class_MongoDB_BSON_Int64___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Int64, __set_state, arginfo_class_MongoDB_BSON_Int64___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Int64, serialize, arginfo_class_MongoDB_BSON_Int64_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Int64, unserialize, arginfo_class_MongoDB_BSON_Int64_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Int64, __unserialize, arginfo_class_MongoDB_BSON_Int64___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Int64, __serialize, arginfo_class_MongoDB_BSON_Int64___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Int64, jsonSerialize, arginfo_class_MongoDB_BSON_Int64_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Int64(zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Int64", class_MongoDB_BSON_Int64_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 4, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Iterator.c0000644000175100001660000002435714760300420013435 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php_phongo.h" #include "phongo_error.h" #include "BSON/Iterator.h" #include "BSON/Iterator_arginfo.h" zend_class_entry* php_phongo_iterator_ce; static const bson_t* php_phongo_iterator_get_bson_from_zval(zval* zbson) { if (Z_TYPE_P(zbson) != IS_OBJECT) { return NULL; } if (instanceof_function(Z_OBJCE_P(zbson), php_phongo_document_ce)) { return Z_DOCUMENT_OBJ_P(zbson)->bson; } else if (instanceof_function(Z_OBJCE_P(zbson), php_phongo_packedarray_ce)) { return Z_PACKEDARRAY_OBJ_P(zbson)->bson; } else { return NULL; } } static bool php_phongo_iterator_init_with_zval(php_phongo_iterator_t* iterator, zval* zbson) { const bson_t* bson; bson = php_phongo_iterator_get_bson_from_zval(zbson); if (!bson) { /* Should never happen, but if it does: exception */ phongo_throw_exception(PHONGO_ERROR_LOGIC, "Could not create iterator for %s instance", zend_zval_type_name(zbson)); return false; } if (!bson_iter_init(&iterator->iter, bson)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not create iterator for %s instance", zend_zval_type_name(zbson)); return false; } ZVAL_COPY(&iterator->bson, zbson); if (instanceof_function(Z_OBJCE_P(zbson), php_phongo_packedarray_ce)) { iterator->is_array = true; } iterator->valid = bson_iter_next(&iterator->iter); return true; } static void php_phongo_iterator_free_current(php_phongo_iterator_t* intern) { if (Z_ISUNDEF(intern->current)) { return; } zval_ptr_dtor(&intern->current); ZVAL_UNDEF(&intern->current); } static void php_phongo_iterator_build_current(php_phongo_iterator_t* intern) { php_phongo_iterator_free_current(intern); phongo_bson_value_to_zval(bson_iter_value(&intern->iter), &intern->current); } static zval* php_phongo_iterator_get_current(php_phongo_iterator_t* intern) { if (!intern->valid) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot call current() on an exhausted iterator"); return NULL; } if (Z_ISUNDEF(intern->current)) { php_phongo_iterator_build_current(intern); } return &intern->current; } static void php_phongo_iterator_next(php_phongo_iterator_t* intern) { intern->valid = bson_iter_next(&intern->iter); intern->key++; php_phongo_iterator_free_current(intern); } static bool php_phongo_iterator_key(php_phongo_iterator_t* intern, zval* key) { const char* ckey; if (!intern->valid) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot call key() on an exhausted iterator"); return false; } if (intern->is_array) { ZVAL_LONG(key, intern->key); return true; } ckey = bson_iter_key(&intern->iter); if (!bson_utf8_validate(ckey, strlen(ckey), false)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Detected corrupt BSON data at offset %d", intern->iter.off); return false; } ZVAL_STRING(key, ckey); return true; } static void php_phongo_iterator_rewind(php_phongo_iterator_t* intern) { /* Don't re-initialise iterator if we're still on the first item */ if (intern->key == 0) { return; } php_phongo_iterator_free_current(intern); bson_iter_init(&intern->iter, php_phongo_iterator_get_bson_from_zval(&intern->bson)); intern->key = 0; intern->valid = bson_iter_next(&intern->iter); } static HashTable* php_phongo_iterator_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_iterator_t* intern; HashTable* props; intern = Z_OBJ_ITERATOR(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 1); zend_hash_str_update(props, "bson", sizeof("bson") - 1, &intern->bson); Z_TRY_ADDREF(intern->bson); return props; } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_Iterator) static PHP_METHOD(MongoDB_BSON_Iterator, current) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(getThis()); zval* data; PHONGO_PARSE_PARAMETERS_NONE(); data = php_phongo_iterator_get_current(intern); if (!data) { // Exception already thrown RETURN_NULL(); } if (Z_ISUNDEF_P(data)) { RETURN_NULL(); } else { ZVAL_COPY_DEREF(return_value, data); } } static PHP_METHOD(MongoDB_BSON_Iterator, key) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!php_phongo_iterator_key(intern, return_value)) { // Exception already thrown return; } } static PHP_METHOD(MongoDB_BSON_Iterator, next) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_iterator_next(intern); } static PHP_METHOD(MongoDB_BSON_Iterator, valid) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_BOOL(intern->valid); } static PHP_METHOD(MongoDB_BSON_Iterator, rewind) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_iterator_rewind(intern); } void phongo_iterator_init(zval* return_value, zval* document_or_packedarray) { php_phongo_iterator_t* intern; object_init_ex(return_value, php_phongo_iterator_ce); intern = Z_ITERATOR_OBJ_P(return_value); php_phongo_iterator_init_with_zval(intern, document_or_packedarray); } /* MongoDB\BSON\Iterator object handlers */ static zend_object_handlers php_phongo_handler_iterator; static void php_phongo_iterator_free_object(zend_object* object) { php_phongo_iterator_t* intern = Z_OBJ_ITERATOR(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } php_phongo_iterator_free_current(intern); zval_ptr_dtor(&intern->bson); } static zend_object* php_phongo_iterator_create_object(zend_class_entry* class_type) { php_phongo_iterator_t* intern = zend_object_alloc(sizeof(php_phongo_iterator_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_iterator; return &intern->std; } static zend_object* php_phongo_iterator_clone_object(zend_object* object) { php_phongo_iterator_t* intern; php_phongo_iterator_t* new_intern; zend_object* new_object; intern = Z_OBJ_ITERATOR(object); new_object = php_phongo_iterator_create_object(object->ce); new_intern = Z_OBJ_ITERATOR(new_object); php_phongo_iterator_init_with_zval(new_intern, &intern->bson); zend_objects_clone_members(&new_intern->std, &intern->std); return new_object; } static HashTable* php_phongo_iterator_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_iterator_get_properties_hash(object, true); } static HashTable* php_phongo_iterator_get_properties(zend_object* object) { return php_phongo_iterator_get_properties_hash(object, false); } /* Iterator handlers */ static void php_phongo_iterator_it_dtor(zend_object_iterator* iter) { zval_ptr_dtor(&iter->data); } static int php_phongo_iterator_it_valid(zend_object_iterator* iter) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(&iter->data); return intern->valid ? SUCCESS : FAILURE; } static zval* php_phongo_iterator_it_get_current_data(zend_object_iterator* iter) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(&iter->data); return php_phongo_iterator_get_current(intern); } static void php_phongo_iterator_it_get_current_key(zend_object_iterator* iter, zval* key) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(&iter->data); if (!php_phongo_iterator_key(intern, key)) { // Exception already thrown return; } } static void php_phongo_iterator_it_move_forward(zend_object_iterator* iter) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(&iter->data); php_phongo_iterator_next(intern); } static void php_phongo_iterator_it_rewind(zend_object_iterator* iter) { php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(&iter->data); php_phongo_iterator_rewind(intern); } static HashTable* php_phongo_iterator_it_get_gc(zend_object_iterator* iter, zval** table, int* n) { *n = 1; *table = &iter->data; return NULL; } static const zend_object_iterator_funcs php_phongo_iterator_it_funcs = { php_phongo_iterator_it_dtor, php_phongo_iterator_it_valid, php_phongo_iterator_it_get_current_data, php_phongo_iterator_it_get_current_key, php_phongo_iterator_it_move_forward, php_phongo_iterator_it_rewind, NULL, /* invalidate_current */ php_phongo_iterator_it_get_gc }; static zend_object_iterator* php_phongo_iterator_get_iterator(zend_class_entry* ce, zval* object, int by_ref) { zend_object_iterator* iterator; if (by_ref) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "An iterator cannot be used with foreach by reference"); return NULL; } iterator = emalloc(sizeof(zend_object_iterator)); zend_iterator_init(iterator); ZVAL_OBJ_COPY(&iterator->data, Z_OBJ_P(object)); iterator->funcs = &php_phongo_iterator_it_funcs; return iterator; } void php_phongo_iterator_init_ce(INIT_FUNC_ARGS) { php_phongo_iterator_ce = register_class_MongoDB_BSON_Iterator(zend_ce_iterator); php_phongo_iterator_ce->create_object = php_phongo_iterator_create_object; php_phongo_iterator_ce->get_iterator = php_phongo_iterator_get_iterator; memcpy(&php_phongo_handler_iterator, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_iterator.clone_obj = php_phongo_iterator_clone_object; php_phongo_handler_iterator.get_debug_info = php_phongo_iterator_get_debug_info; php_phongo_handler_iterator.get_properties = php_phongo_iterator_get_properties; php_phongo_handler_iterator.free_obj = php_phongo_iterator_free_object; php_phongo_handler_iterator.offset = XtOffsetOf(php_phongo_iterator_t, std); } mongodb-1.21.0/src/BSON/Iterator.h0000644000175100001660000000140314760300420013425 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_ITERATOR_H #define PHONGO_ITERATOR_H #include void phongo_iterator_init(zval* return_value, zval* document_or_packedarray); #endif /* PHONGO_ITERATOR_H */ mongodb-1.21.0/src/BSON/Iterator_arginfo.h0000644000175100001660000000447414760300420015145 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: b1cb9bc973c616b9ec005232e95368bf1b233480 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Iterator___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Iterator_current, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_MongoDB_BSON_Iterator_key, 0, 0, MAY_BE_STRING|MAY_BE_LONG) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Iterator_next, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Iterator_rewind arginfo_class_MongoDB_BSON_Iterator_next ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Iterator_valid, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Iterator, __construct); static ZEND_METHOD(MongoDB_BSON_Iterator, current); static ZEND_METHOD(MongoDB_BSON_Iterator, key); static ZEND_METHOD(MongoDB_BSON_Iterator, next); static ZEND_METHOD(MongoDB_BSON_Iterator, rewind); static ZEND_METHOD(MongoDB_BSON_Iterator, valid); static const zend_function_entry class_MongoDB_BSON_Iterator_methods[] = { ZEND_ME(MongoDB_BSON_Iterator, __construct, arginfo_class_MongoDB_BSON_Iterator___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Iterator, current, arginfo_class_MongoDB_BSON_Iterator_current, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Iterator, key, arginfo_class_MongoDB_BSON_Iterator_key, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Iterator, next, arginfo_class_MongoDB_BSON_Iterator_next, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Iterator, rewind, arginfo_class_MongoDB_BSON_Iterator_rewind, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Iterator, valid, arginfo_class_MongoDB_BSON_Iterator_valid, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Iterator(zend_class_entry *class_entry_Iterator) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Iterator", class_MongoDB_BSON_Iterator_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; zend_class_implements(class_entry, 1, class_entry_Iterator); return class_entry; } mongodb-1.21.0/src/BSON/Javascript.c0000644000175100001660000002747414760300420013755 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include #include #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "Javascript_arginfo.h" zend_class_entry* php_phongo_javascript_ce; /* Initialize the object and return whether it was successful. An exception will * be thrown on error. */ static bool php_phongo_javascript_init(php_phongo_javascript_t* intern, const char* code, size_t code_len, zval* scope) { if (scope && Z_TYPE_P(scope) != IS_OBJECT && Z_TYPE_P(scope) != IS_ARRAY && Z_TYPE_P(scope) != IS_NULL) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected scope to be array or object, %s given", zend_get_type_by_const(Z_TYPE_P(scope))); return false; } if (strlen(code) != (size_t) code_len) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Code cannot contain null bytes"); return false; } intern->code = estrndup(code, code_len); intern->code_len = code_len; if (scope && (Z_TYPE_P(scope) == IS_OBJECT || Z_TYPE_P(scope) == IS_ARRAY)) { intern->scope = bson_new(); php_phongo_zval_to_bson(scope, PHONGO_BSON_NONE, intern->scope, NULL); } else { intern->scope = NULL; } return true; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_javascript_init_from_hash(php_phongo_javascript_t* intern, HashTable* props) { zval *code, *scope; if ((code = zend_hash_str_find(props, "code", sizeof("code") - 1)) && Z_TYPE_P(code) == IS_STRING) { scope = zend_hash_str_find(props, "scope", sizeof("scope") - 1); return php_phongo_javascript_init(intern, Z_STRVAL_P(code), Z_STRLEN_P(code), scope); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"code\" string field", ZSTR_VAL(php_phongo_javascript_ce->name)); return false; } HashTable* php_phongo_javascript_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_javascript_t* intern; HashTable* props; intern = Z_OBJ_JAVASCRIPT(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 2); if (!intern->code) { return props; } { zval code; ZVAL_STRING(&code, intern->code); zend_hash_str_update(props, "code", sizeof("code") - 1, &code); if (intern->scope) { php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); if (!php_phongo_bson_to_zval_ex(intern->scope, &state)) { zval_ptr_dtor(&state.zchild); goto failure; } zend_hash_str_update(props, "scope", sizeof("scope") - 1, &state.zchild); } else { zval scope; ZVAL_NULL(&scope); zend_hash_str_update(props, "scope", sizeof("scope") - 1, &scope); } } return props; failure: PHONGO_GET_PROPERTY_HASH_FREE_PROPS(is_temp, props); return NULL; } /* Construct a new BSON Javascript type. The scope is a document mapping identifiers and values, representing the scope in which the code string will be evaluated. Note that this type cannot be represented as Extended JSON. */ static PHP_METHOD(MongoDB_BSON_Javascript, __construct) { php_phongo_javascript_t* intern; char* code; size_t code_len; zval* scope = NULL; intern = Z_JAVASCRIPT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STRING(code, code_len) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_OBJECT_EX(scope, 1, 0) PHONGO_PARSE_PARAMETERS_END(); php_phongo_javascript_init(intern, code, code_len, scope); } static PHP_METHOD(MongoDB_BSON_Javascript, __set_state) { php_phongo_javascript_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_javascript_ce); intern = Z_JAVASCRIPT_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_javascript_init_from_hash(intern, props); } /* Return the Javascript's code string. */ static PHP_METHOD(MongoDB_BSON_Javascript, __toString) { php_phongo_javascript_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_JAVASCRIPT_OBJ_P(getThis()); RETURN_STRINGL(intern->code, intern->code_len); } static PHP_METHOD(MongoDB_BSON_Javascript, getCode) { php_phongo_javascript_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_JAVASCRIPT_OBJ_P(getThis()); RETURN_STRINGL(intern->code, intern->code_len); } static PHP_METHOD(MongoDB_BSON_Javascript, getScope) { php_phongo_javascript_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_JAVASCRIPT_OBJ_P(getThis()); if (!intern->scope) { RETURN_NULL(); } if (intern->scope->len) { php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); if (!php_phongo_bson_to_zval_ex(intern->scope, &state)) { zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } else { RETURN_NULL(); } } static PHP_METHOD(MongoDB_BSON_Javascript, jsonSerialize) { php_phongo_javascript_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_JAVASCRIPT_OBJ_P(getThis()); array_init_size(return_value, 2); ADD_ASSOC_STRINGL(return_value, "$code", intern->code, intern->code_len); if (intern->scope && intern->scope->len) { php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); if (!php_phongo_bson_to_zval_ex(intern->scope, &state)) { zval_ptr_dtor(&state.zchild); return; } ADD_ASSOC_ZVAL_EX(return_value, "$scope", &state.zchild); } } static PHP_METHOD(MongoDB_BSON_Javascript, serialize) { php_phongo_javascript_t* intern; zval retval; php_phongo_bson_state state; php_serialize_data_t var_hash; smart_str buf = { 0 }; PHONGO_BSON_INIT_STATE(state); intern = Z_JAVASCRIPT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (intern->scope && intern->scope->len) { if (!php_phongo_bson_to_zval_ex(intern->scope, &state)) { zval_ptr_dtor(&state.zchild); return; } } else { ZVAL_NULL(&state.zchild); } array_init_size(&retval, 2); ADD_ASSOC_STRINGL(&retval, "code", intern->code, intern->code_len); ADD_ASSOC_ZVAL(&retval, "scope", &state.zchild); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_Javascript, unserialize) { php_phongo_javascript_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_JAVASCRIPT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_javascript_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_javascript_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_Javascript, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_javascript_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_Javascript, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_javascript_init_from_hash(Z_JAVASCRIPT_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\Javascript object handlers */ static zend_object_handlers php_phongo_handler_javascript; static void php_phongo_javascript_free_object(zend_object* object) { php_phongo_javascript_t* intern = Z_OBJ_JAVASCRIPT(object); zend_object_std_dtor(&intern->std); if (intern->code) { efree(intern->code); } if (intern->scope) { bson_destroy(intern->scope); intern->scope = NULL; } if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } zend_object* php_phongo_javascript_create_object(zend_class_entry* class_type) { php_phongo_javascript_t* intern = zend_object_alloc(sizeof(php_phongo_javascript_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_javascript; return &intern->std; } static zend_object* php_phongo_javascript_clone_object(zend_object* object) { php_phongo_javascript_t* intern; php_phongo_javascript_t* new_intern; zend_object* new_object; intern = Z_OBJ_JAVASCRIPT(object); new_object = php_phongo_javascript_create_object(object->ce); new_intern = Z_OBJ_JAVASCRIPT(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); php_phongo_javascript_init(new_intern, intern->code, intern->code_len, NULL); new_intern->scope = bson_copy(intern->scope); return new_object; } static int php_phongo_javascript_compare_objects(zval* o1, zval* o2) { php_phongo_javascript_t *intern1, *intern2; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_JAVASCRIPT_OBJ_P(o1); intern2 = Z_JAVASCRIPT_OBJ_P(o2); /* Do not consider the scope document for comparisons */ return strcmp(intern1->code, intern2->code); } static HashTable* php_phongo_javascript_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_javascript_get_properties_hash(object, true); } static HashTable* php_phongo_javascript_get_properties(zend_object* object) { return php_phongo_javascript_get_properties_hash(object, false); } void php_phongo_javascript_init_ce(INIT_FUNC_ARGS) { php_phongo_javascript_ce = register_class_MongoDB_BSON_Javascript(php_phongo_javascript_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_javascript_ce->create_object = php_phongo_javascript_create_object; memcpy(&php_phongo_handler_javascript, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_javascript.compare = php_phongo_javascript_compare_objects; php_phongo_handler_javascript.clone_obj = php_phongo_javascript_clone_object; php_phongo_handler_javascript.get_debug_info = php_phongo_javascript_get_debug_info; php_phongo_handler_javascript.get_properties = php_phongo_javascript_get_properties; php_phongo_handler_javascript.free_obj = php_phongo_javascript_free_object; php_phongo_handler_javascript.offset = XtOffsetOf(php_phongo_javascript_t, std); } bool phongo_javascript_new(zval* object, const char* code, size_t code_len, const bson_t* scope) { php_phongo_javascript_t* intern; if (scope) { php_phongo_bson_state state; bool valid_scope; PHONGO_BSON_INIT_STATE(state); valid_scope = php_phongo_bson_to_zval_ex(scope, &state); zval_ptr_dtor(&state.zchild); if (!valid_scope) { return false; } } object_init_ex(object, php_phongo_javascript_ce); intern = Z_JAVASCRIPT_OBJ_P(object); intern->code = estrndup(code, code_len); intern->code_len = code_len; intern->scope = scope ? bson_copy(scope) : NULL; return true; } mongodb-1.21.0/src/BSON/Javascript.h0000644000175100001660000000145014760300420013744 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_JAVASCRIPT_H #define PHONGO_BSON_JAVASCRIPT_H bool phongo_javascript_new(zval* object, const char* code, size_t code_len, const bson_t* scope); #endif /* PHONGO_BSON_JAVASCRIPT_H */ mongodb-1.21.0/src/BSON/JavascriptInterface.c0000644000175100001660000000160114760300420015556 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "JavascriptInterface_arginfo.h" zend_class_entry* php_phongo_javascript_interface_ce; void php_phongo_javascript_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_javascript_interface_ce = register_class_MongoDB_BSON_JavascriptInterface(); } mongodb-1.21.0/src/BSON/JavascriptInterface_arginfo.h0000644000175100001660000000265314760300420017300 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 82f701e4bbef2f207a3058c7875991b7a61617a9 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_JavascriptInterface_getCode, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_JavascriptInterface_getScope, 0, 0, IS_OBJECT, 1) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_JavascriptInterface___toString arginfo_class_MongoDB_BSON_JavascriptInterface_getCode static const zend_function_entry class_MongoDB_BSON_JavascriptInterface_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_JavascriptInterface, getCode, arginfo_class_MongoDB_BSON_JavascriptInterface_getCode, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_JavascriptInterface, getScope, arginfo_class_MongoDB_BSON_JavascriptInterface_getScope, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_JavascriptInterface, __toString, arginfo_class_MongoDB_BSON_JavascriptInterface___toString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_JavascriptInterface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "JavascriptInterface", class_MongoDB_BSON_JavascriptInterface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/Javascript_arginfo.h0000644000175100001660000001040714760300420015453 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: ca211f93a2f8cb801527ed7a3f4b6c434d879370 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Javascript___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, code, IS_STRING, 0) ZEND_ARG_TYPE_MASK(0, scope, MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Javascript___set_state, 0, 1, MongoDB\\BSON\\Javascript, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Javascript_getCode, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Javascript_getScope, 0, 0, IS_OBJECT, 1) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Javascript___toString arginfo_class_MongoDB_BSON_Javascript_getCode #define arginfo_class_MongoDB_BSON_Javascript_serialize arginfo_class_MongoDB_BSON_Javascript_getCode ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Javascript_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Javascript___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Javascript___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Javascript_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Javascript, __construct); static ZEND_METHOD(MongoDB_BSON_Javascript, __set_state); static ZEND_METHOD(MongoDB_BSON_Javascript, getCode); static ZEND_METHOD(MongoDB_BSON_Javascript, getScope); static ZEND_METHOD(MongoDB_BSON_Javascript, __toString); static ZEND_METHOD(MongoDB_BSON_Javascript, serialize); static ZEND_METHOD(MongoDB_BSON_Javascript, unserialize); static ZEND_METHOD(MongoDB_BSON_Javascript, __unserialize); static ZEND_METHOD(MongoDB_BSON_Javascript, __serialize); static ZEND_METHOD(MongoDB_BSON_Javascript, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Javascript_methods[] = { ZEND_ME(MongoDB_BSON_Javascript, __construct, arginfo_class_MongoDB_BSON_Javascript___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, __set_state, arginfo_class_MongoDB_BSON_Javascript___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, getCode, arginfo_class_MongoDB_BSON_Javascript_getCode, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, getScope, arginfo_class_MongoDB_BSON_Javascript_getScope, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, __toString, arginfo_class_MongoDB_BSON_Javascript___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, serialize, arginfo_class_MongoDB_BSON_Javascript_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, unserialize, arginfo_class_MongoDB_BSON_Javascript_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, __unserialize, arginfo_class_MongoDB_BSON_Javascript___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, __serialize, arginfo_class_MongoDB_BSON_Javascript___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Javascript, jsonSerialize, arginfo_class_MongoDB_BSON_Javascript_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Javascript(zend_class_entry *class_entry_MongoDB_BSON_JavascriptInterface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Javascript", class_MongoDB_BSON_Javascript_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_MongoDB_BSON_JavascriptInterface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/MaxKey.c0000644000175100001660000000610514760300420013031 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "MaxKey_arginfo.h" zend_class_entry* php_phongo_maxkey_ce; static PHP_METHOD(MongoDB_BSON_MaxKey, __set_state) { zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_maxkey_ce); } static PHP_METHOD(MongoDB_BSON_MaxKey, jsonSerialize) { PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(return_value, 1); ADD_ASSOC_LONG_EX(return_value, "$maxKey", 1); } static PHP_METHOD(MongoDB_BSON_MaxKey, serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRING(""); } static PHP_METHOD(MongoDB_BSON_MaxKey, unserialize) { char* serialized; size_t serialized_len; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); } static PHP_METHOD(MongoDB_BSON_MaxKey, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(return_value, 0); } static PHP_METHOD(MongoDB_BSON_MaxKey, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); } /* MongoDB\BSON\MaxKey object handlers */ static zend_object_handlers php_phongo_handler_maxkey; static void php_phongo_maxkey_free_object(zend_object* object) { php_phongo_maxkey_t* intern = Z_OBJ_MAXKEY(object); zend_object_std_dtor(&intern->std); } static zend_object* php_phongo_maxkey_create_object(zend_class_entry* class_type) { php_phongo_maxkey_t* intern = zend_object_alloc(sizeof(php_phongo_maxkey_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_maxkey; return &intern->std; } void php_phongo_maxkey_init_ce(INIT_FUNC_ARGS) { php_phongo_maxkey_ce = register_class_MongoDB_BSON_MaxKey(php_phongo_maxkey_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable); php_phongo_maxkey_ce->create_object = php_phongo_maxkey_create_object; memcpy(&php_phongo_handler_maxkey, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); /* Re-assign default handler previously removed in php_phongo.c */ php_phongo_handler_maxkey.clone_obj = zend_objects_clone_obj; php_phongo_handler_maxkey.free_obj = php_phongo_maxkey_free_object; php_phongo_handler_maxkey.offset = XtOffsetOf(php_phongo_maxkey_t, std); } mongodb-1.21.0/src/BSON/MaxKeyInterface.c0000644000175100001660000000155514760300420014656 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "MaxKeyInterface_arginfo.h" zend_class_entry* php_phongo_maxkey_interface_ce; void php_phongo_maxkey_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_maxkey_interface_ce = register_class_MongoDB_BSON_MaxKeyInterface(); } mongodb-1.21.0/src/BSON/MaxKeyInterface_arginfo.h0000644000175100001660000000101114760300420016353 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 6c27815fcc33b0b03365b6b24d4145d8621cf13d */ static const zend_function_entry class_MongoDB_BSON_MaxKeyInterface_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_MaxKeyInterface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "MaxKeyInterface", class_MongoDB_BSON_MaxKeyInterface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/MaxKey_arginfo.h0000644000175100001660000000550214760300420014543 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: d397817e708c2633223aa7b6a7273c0a1a4feb1d */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_MaxKey___set_state, 0, 1, MongoDB\\BSON\\MaxKey, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MaxKey_serialize, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MaxKey_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MaxKey___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MaxKey___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MaxKey_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_MaxKey, __set_state); static ZEND_METHOD(MongoDB_BSON_MaxKey, serialize); static ZEND_METHOD(MongoDB_BSON_MaxKey, unserialize); static ZEND_METHOD(MongoDB_BSON_MaxKey, __unserialize); static ZEND_METHOD(MongoDB_BSON_MaxKey, __serialize); static ZEND_METHOD(MongoDB_BSON_MaxKey, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_MaxKey_methods[] = { ZEND_ME(MongoDB_BSON_MaxKey, __set_state, arginfo_class_MongoDB_BSON_MaxKey___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MaxKey, serialize, arginfo_class_MongoDB_BSON_MaxKey_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MaxKey, unserialize, arginfo_class_MongoDB_BSON_MaxKey_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MaxKey, __unserialize, arginfo_class_MongoDB_BSON_MaxKey___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MaxKey, __serialize, arginfo_class_MongoDB_BSON_MaxKey___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MaxKey, jsonSerialize, arginfo_class_MongoDB_BSON_MaxKey_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_MaxKey(zend_class_entry *class_entry_MongoDB_BSON_MaxKeyInterface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "MaxKey", class_MongoDB_BSON_MaxKey_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 4, class_entry_MongoDB_BSON_MaxKeyInterface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable); return class_entry; } mongodb-1.21.0/src/BSON/MinKey.c0000644000175100001660000000610514760300420013027 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "MinKey_arginfo.h" zend_class_entry* php_phongo_minkey_ce; static PHP_METHOD(MongoDB_BSON_MinKey, __set_state) { zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_minkey_ce); } static PHP_METHOD(MongoDB_BSON_MinKey, jsonSerialize) { PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(return_value, 1); ADD_ASSOC_LONG_EX(return_value, "$minKey", 1); } static PHP_METHOD(MongoDB_BSON_MinKey, serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRING(""); } static PHP_METHOD(MongoDB_BSON_MinKey, unserialize) { char* serialized; size_t serialized_len; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); } static PHP_METHOD(MongoDB_BSON_MinKey, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(return_value, 0); } static PHP_METHOD(MongoDB_BSON_MinKey, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); } /* MongoDB\BSON\MinKey object handlers */ static zend_object_handlers php_phongo_handler_minkey; static void php_phongo_minkey_free_object(zend_object* object) { php_phongo_minkey_t* intern = Z_OBJ_MINKEY(object); zend_object_std_dtor(&intern->std); } static zend_object* php_phongo_minkey_create_object(zend_class_entry* class_type) { php_phongo_minkey_t* intern = zend_object_alloc(sizeof(php_phongo_minkey_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_minkey; return &intern->std; } void php_phongo_minkey_init_ce(INIT_FUNC_ARGS) { php_phongo_minkey_ce = register_class_MongoDB_BSON_MinKey(php_phongo_minkey_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable); php_phongo_minkey_ce->create_object = php_phongo_minkey_create_object; memcpy(&php_phongo_handler_minkey, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); /* Re-assign default handler previously removed in php_phongo.c */ php_phongo_handler_minkey.clone_obj = zend_objects_clone_obj; php_phongo_handler_minkey.free_obj = php_phongo_minkey_free_object; php_phongo_handler_minkey.offset = XtOffsetOf(php_phongo_minkey_t, std); } mongodb-1.21.0/src/BSON/MinKeyInterface.c0000644000175100001660000000155514760300420014654 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "MinKeyInterface_arginfo.h" zend_class_entry* php_phongo_minkey_interface_ce; void php_phongo_minkey_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_minkey_interface_ce = register_class_MongoDB_BSON_MinKeyInterface(); } mongodb-1.21.0/src/BSON/MinKeyInterface_arginfo.h0000644000175100001660000000101114760300420016351 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: c9b23e875d9dc9ebb0ed3391d88cb2458ed96407 */ static const zend_function_entry class_MongoDB_BSON_MinKeyInterface_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_MinKeyInterface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "MinKeyInterface", class_MongoDB_BSON_MinKeyInterface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/MinKey_arginfo.h0000644000175100001660000000550214760300420014541 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: faf0e180715b7673158c3230cc109a93124cf4a9 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_MinKey___set_state, 0, 1, MongoDB\\BSON\\MinKey, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MinKey_serialize, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MinKey_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MinKey___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MinKey___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_MinKey_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_MinKey, __set_state); static ZEND_METHOD(MongoDB_BSON_MinKey, serialize); static ZEND_METHOD(MongoDB_BSON_MinKey, unserialize); static ZEND_METHOD(MongoDB_BSON_MinKey, __unserialize); static ZEND_METHOD(MongoDB_BSON_MinKey, __serialize); static ZEND_METHOD(MongoDB_BSON_MinKey, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_MinKey_methods[] = { ZEND_ME(MongoDB_BSON_MinKey, __set_state, arginfo_class_MongoDB_BSON_MinKey___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MinKey, serialize, arginfo_class_MongoDB_BSON_MinKey_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MinKey, unserialize, arginfo_class_MongoDB_BSON_MinKey_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MinKey, __unserialize, arginfo_class_MongoDB_BSON_MinKey___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MinKey, __serialize, arginfo_class_MongoDB_BSON_MinKey___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_MinKey, jsonSerialize, arginfo_class_MongoDB_BSON_MinKey_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_MinKey(zend_class_entry *class_entry_MongoDB_BSON_MinKeyInterface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "MinKey", class_MongoDB_BSON_MinKey_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 4, class_entry_MongoDB_BSON_MinKeyInterface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable); return class_entry; } mongodb-1.21.0/src/BSON/ObjectId.c0000644000175100001660000002264514760300420013325 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "ObjectId_arginfo.h" #define PHONGO_OID_SIZE sizeof(((php_phongo_objectid_t*) 0)->oid) #define PHONGO_OID_LEN (PHONGO_OID_SIZE - 1) zend_class_entry* php_phongo_objectid_ce; /* Initialize the object with a generated value and return whether it was * successful. */ static bool php_phongo_objectid_init(php_phongo_objectid_t* intern) { bson_oid_t oid; intern->initialized = true; bson_oid_init(&oid, NULL); bson_oid_to_string(&oid, intern->oid); return true; } /* Initialize the object from a hex string and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_objectid_init_from_hex_string(php_phongo_objectid_t* intern, const char* hex, size_t hex_len) { if (bson_oid_is_valid(hex, hex_len)) { bson_oid_t oid; bson_oid_init_from_string(&oid, hex); bson_oid_to_string(&oid, intern->oid); intern->initialized = true; return true; } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing ObjectId string: %s", hex); return false; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_objectid_init_from_hash(php_phongo_objectid_t* intern, HashTable* props) { zval* z_oid; z_oid = zend_hash_str_find(props, "oid", sizeof("oid") - 1); if (z_oid && Z_TYPE_P(z_oid) == IS_STRING) { return php_phongo_objectid_init_from_hex_string(intern, Z_STRVAL_P(z_oid), Z_STRLEN_P(z_oid)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"oid\" string field", ZSTR_VAL(php_phongo_objectid_ce->name)); return false; } static HashTable* php_phongo_objectid_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_objectid_t* intern; HashTable* props; intern = Z_OBJ_OBJECTID(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 1); if (!intern->initialized) { return props; } { zval zv; ZVAL_STRING(&zv, intern->oid); zend_hash_str_update(props, "oid", sizeof("oid") - 1, &zv); } return props; } /* Constructs a new BSON ObjectId type, optionally from a hex string. */ static PHP_METHOD(MongoDB_BSON_ObjectId, __construct) { php_phongo_objectid_t* intern; char* id = NULL; size_t id_len; intern = Z_OBJECTID_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_STRING_OR_NULL(id, id_len) PHONGO_PARSE_PARAMETERS_END(); if (id) { php_phongo_objectid_init_from_hex_string(intern, id, id_len); } else { php_phongo_objectid_init(intern); } } static PHP_METHOD(MongoDB_BSON_ObjectId, getTimestamp) { php_phongo_objectid_t* intern; bson_oid_t tmp_oid; intern = Z_OBJECTID_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); bson_oid_init_from_string(&tmp_oid, intern->oid); RETVAL_LONG(bson_oid_get_time_t(&tmp_oid)); } static PHP_METHOD(MongoDB_BSON_ObjectId, __set_state) { php_phongo_objectid_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_objectid_ce); intern = Z_OBJECTID_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_objectid_init_from_hash(intern, props); } static PHP_METHOD(MongoDB_BSON_ObjectId, __toString) { php_phongo_objectid_t* intern; intern = Z_OBJECTID_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRINGL(intern->oid, PHONGO_OID_LEN); } static PHP_METHOD(MongoDB_BSON_ObjectId, jsonSerialize) { php_phongo_objectid_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_OBJECTID_OBJ_P(getThis()); array_init_size(return_value, 1); ADD_ASSOC_STRINGL(return_value, "$oid", intern->oid, PHONGO_OID_LEN); } static PHP_METHOD(MongoDB_BSON_ObjectId, serialize) { php_phongo_objectid_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; intern = Z_OBJECTID_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 1); ADD_ASSOC_STRINGL(&retval, "oid", intern->oid, PHONGO_OID_LEN); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_ObjectId, unserialize) { php_phongo_objectid_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_OBJECTID_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_objectid_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_objectid_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_ObjectId, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_objectid_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_ObjectId, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_objectid_init_from_hash(Z_OBJECTID_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\ObjectId object handlers */ static zend_object_handlers php_phongo_handler_objectid; static void php_phongo_objectid_free_object(zend_object* object) { php_phongo_objectid_t* intern = Z_OBJ_OBJECTID(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_objectid_create_object(zend_class_entry* class_type) { php_phongo_objectid_t* intern = zend_object_alloc(sizeof(php_phongo_objectid_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_objectid; return &intern->std; } static zend_object* php_phongo_objectid_clone_object(zend_object* object) { php_phongo_objectid_t* intern; php_phongo_objectid_t* new_intern; zend_object* new_object; intern = Z_OBJ_OBJECTID(object); new_object = php_phongo_objectid_create_object(object->ce); new_intern = Z_OBJ_OBJECTID(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); // Use memcpy to copy bson value to avoid converting to string and back memcpy(&new_intern->oid, &intern->oid, PHONGO_OID_SIZE); new_intern->initialized = true; return new_object; } static int php_phongo_objectid_compare_objects(zval* o1, zval* o2) { php_phongo_objectid_t* intern1; php_phongo_objectid_t* intern2; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_OBJECTID_OBJ_P(o1); intern2 = Z_OBJECTID_OBJ_P(o2); return strcmp(intern1->oid, intern2->oid); } static HashTable* php_phongo_objectid_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_objectid_get_properties_hash(object, true); } static HashTable* php_phongo_objectid_get_properties(zend_object* object) { return php_phongo_objectid_get_properties_hash(object, false); } void php_phongo_objectid_init_ce(INIT_FUNC_ARGS) { php_phongo_objectid_ce = register_class_MongoDB_BSON_ObjectId(php_phongo_objectid_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_objectid_ce->create_object = php_phongo_objectid_create_object; memcpy(&php_phongo_handler_objectid, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_objectid.compare = php_phongo_objectid_compare_objects; php_phongo_handler_objectid.clone_obj = php_phongo_objectid_clone_object; php_phongo_handler_objectid.get_debug_info = php_phongo_objectid_get_debug_info; php_phongo_handler_objectid.get_properties = php_phongo_objectid_get_properties; php_phongo_handler_objectid.free_obj = php_phongo_objectid_free_object; php_phongo_handler_objectid.offset = XtOffsetOf(php_phongo_objectid_t, std); } bool phongo_objectid_new(zval* return_value, const bson_oid_t* oid) { php_phongo_objectid_t* intern; object_init_ex(return_value, php_phongo_objectid_ce); intern = Z_OBJECTID_OBJ_P(return_value); bson_oid_to_string(oid, intern->oid); intern->initialized = true; return true; } mongodb-1.21.0/src/BSON/ObjectId.h0000644000175100001660000000145714760300420013330 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_BSON_OBJECTID_H #define PHONGO_BSON_OBJECTID_H #include "bson/bson.h" #include bool phongo_objectid_new(zval* return_value, const bson_oid_t* oid); #endif /* PHONGO_BSON_OBJECTID_H */ mongodb-1.21.0/src/BSON/ObjectIdInterface.c0000644000175100001660000000156714760300420015146 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "ObjectIdInterface_arginfo.h" zend_class_entry* php_phongo_objectid_interface_ce; void php_phongo_objectid_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_objectid_interface_ce = register_class_MongoDB_BSON_ObjectIdInterface(); } mongodb-1.21.0/src/BSON/ObjectIdInterface_arginfo.h0000644000175100001660000000220714760300420016650 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: b68b5dcd9eb41216be44fbcd5fc80349e6fcefd0 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_ObjectIdInterface_getTimestamp, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_ObjectIdInterface___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_BSON_ObjectIdInterface_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_ObjectIdInterface, getTimestamp, arginfo_class_MongoDB_BSON_ObjectIdInterface_getTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_ObjectIdInterface, __toString, arginfo_class_MongoDB_BSON_ObjectIdInterface___toString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_ObjectIdInterface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "ObjectIdInterface", class_MongoDB_BSON_ObjectIdInterface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/ObjectId_arginfo.h0000644000175100001660000000756614760300420015044 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 22bff62df5f5363fbb44eabf77225e1b765be73f */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_ObjectId___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, id, IS_STRING, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_ObjectId_getTimestamp, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_ObjectId___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_ObjectId___set_state, 0, 1, MongoDB\\BSON\\ObjectId, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_ObjectId_serialize arginfo_class_MongoDB_BSON_ObjectId___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_ObjectId_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_ObjectId___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_ObjectId___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_ObjectId_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_ObjectId, __construct); static ZEND_METHOD(MongoDB_BSON_ObjectId, getTimestamp); static ZEND_METHOD(MongoDB_BSON_ObjectId, __toString); static ZEND_METHOD(MongoDB_BSON_ObjectId, __set_state); static ZEND_METHOD(MongoDB_BSON_ObjectId, serialize); static ZEND_METHOD(MongoDB_BSON_ObjectId, unserialize); static ZEND_METHOD(MongoDB_BSON_ObjectId, __unserialize); static ZEND_METHOD(MongoDB_BSON_ObjectId, __serialize); static ZEND_METHOD(MongoDB_BSON_ObjectId, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_ObjectId_methods[] = { ZEND_ME(MongoDB_BSON_ObjectId, __construct, arginfo_class_MongoDB_BSON_ObjectId___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_ObjectId, getTimestamp, arginfo_class_MongoDB_BSON_ObjectId_getTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_ObjectId, __toString, arginfo_class_MongoDB_BSON_ObjectId___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_ObjectId, __set_state, arginfo_class_MongoDB_BSON_ObjectId___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_ObjectId, serialize, arginfo_class_MongoDB_BSON_ObjectId_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_ObjectId, unserialize, arginfo_class_MongoDB_BSON_ObjectId_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_ObjectId, __unserialize, arginfo_class_MongoDB_BSON_ObjectId___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_ObjectId, __serialize, arginfo_class_MongoDB_BSON_ObjectId___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_ObjectId, jsonSerialize, arginfo_class_MongoDB_BSON_ObjectId_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_ObjectId(zend_class_entry *class_entry_MongoDB_BSON_ObjectIdInterface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "ObjectId", class_MongoDB_BSON_ObjectId_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_MongoDB_BSON_ObjectIdInterface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/PackedArray.c0000644000175100001660000004353414760300420014030 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php_phongo.h" #include "phongo_error.h" #include "phongo_bson_encode.h" #include "BSON/PackedArray_arginfo.h" #include "BSON/Iterator.h" zend_class_entry* php_phongo_packedarray_ce; /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_packedarray_init_from_hash(php_phongo_packedarray_t* intern, HashTable* props) { zval* data; if ((data = zend_hash_str_find(props, "data", sizeof("data") - 1)) && Z_TYPE_P(data) == IS_STRING) { zend_string* decoded = php_base64_decode_str(Z_STR_P(data)); intern->bson = bson_new_from_data((const uint8_t*) ZSTR_VAL(decoded), ZSTR_LEN(decoded)); zend_string_free(decoded); if (intern->bson == NULL) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires valid BSON", ZSTR_VAL(php_phongo_packedarray_ce->name)); return false; } return true; } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"data\" string field", ZSTR_VAL(php_phongo_packedarray_ce->name)); return false; } static HashTable* php_phongo_packedarray_get_properties_hash(zend_object* object, bool is_temp, int size) { php_phongo_packedarray_t* intern; HashTable* props; intern = Z_OBJ_PACKEDARRAY(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, size); if (!intern->bson) { return props; } { zval data; ZVAL_STR(&data, php_base64_encode((const unsigned char*) bson_get_data(intern->bson), intern->bson->len)); zend_hash_str_update(props, "data", sizeof("data") - 1, &data); } return props; } static bool php_phongo_packedarray_to_json(zval* return_value, bson_json_mode_t mode, const bson_t* bson) { char* json = NULL; size_t json_len; bson_json_opts_t* opts = bson_json_opts_new(mode, BSON_MAX_LEN_UNLIMITED); bool ret = false; bson_json_opts_set_outermost_array(opts, true); json = bson_as_json_with_opts(bson, &json_len, opts); if (json) { ZVAL_STRINGL(return_value, json, json_len); bson_free(json); ret = true; } else { ZVAL_UNDEF(return_value); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not convert BSON array to a JSON string"); } bson_json_opts_destroy(opts); return ret; } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_PackedArray) static PHP_METHOD(MongoDB_BSON_PackedArray, fromJSON) { zval zv; php_phongo_packedarray_t* intern; zend_string* json; bson_t* bson; bson_error_t error; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(json) PHONGO_PARSE_PARAMETERS_END(); bson = bson_new_from_json((const uint8_t*) ZSTR_VAL(json), ZSTR_LEN(json), &error); if (!bson) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s", error.domain == BSON_ERROR_JSON ? error.message : "Error parsing JSON"); return; } // Check if BSON contains only numeric keys if (!bson_empty(bson)) { bson_iter_t iter; uint32_t expected_key = 0; char expected_key_str[11]; const char* key_str; if (!bson_iter_init(&iter, bson)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Received invalid JSON array"); bson_destroy(bson); return; } while (bson_iter_next(&iter)) { key_str = bson_iter_key(&iter); snprintf(expected_key_str, sizeof(expected_key_str), "%" PRIu32, expected_key); if (strcmp(key_str, expected_key_str)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Received invalid JSON array: expected key %" PRIu32 ", but found \"%s\"", expected_key, key_str); bson_destroy(bson); return; } expected_key++; } } object_init_ex(&zv, php_phongo_packedarray_ce); intern = Z_PACKEDARRAY_OBJ_P(&zv); intern->bson = bson; RETURN_ZVAL(&zv, 1, 1); } static PHP_METHOD(MongoDB_BSON_PackedArray, fromPHP) { zval zv; php_phongo_packedarray_t* intern; zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); if (!zend_array_is_list(Z_ARRVAL_P(data))) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected value to be a list, but given array is not"); return; } object_init_ex(&zv, php_phongo_packedarray_ce); intern = Z_PACKEDARRAY_OBJ_P(&zv); intern->bson = bson_new(); php_phongo_zval_to_bson(data, PHONGO_BSON_NONE, intern->bson, NULL); RETURN_ZVAL(&zv, 1, 1); } static bool seek_iter_to_index(bson_iter_t* iter, zend_long index) { for (zend_long i = 0; i <= index; i++) { if (!bson_iter_next(iter)) { return false; } } return true; } static bool php_phongo_packedarray_get(php_phongo_packedarray_t* intern, zend_long index, zval* return_value, bool null_if_missing) { bson_iter_t iter; if (!bson_iter_init(&iter, intern->bson)) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not initialize BSON iterator"); return false; } if (!seek_iter_to_index(&iter, index)) { if (null_if_missing) { ZVAL_NULL(return_value); return true; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find index \"%d\" in BSON array", index); return false; } phongo_bson_value_to_zval(bson_iter_value(&iter), return_value); return true; } static PHP_METHOD(MongoDB_BSON_PackedArray, get) { php_phongo_packedarray_t* intern; zend_long index; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(index) PHONGO_PARSE_PARAMETERS_END(); intern = Z_PACKEDARRAY_OBJ_P(getThis()); if (!php_phongo_packedarray_get(intern, index, return_value, false)) { // Exception already thrown RETURN_NULL(); } } static PHP_METHOD(MongoDB_BSON_PackedArray, getIterator) { PHONGO_PARSE_PARAMETERS_NONE(); phongo_iterator_init(return_value, getThis()); } static bool php_phongo_packedarray_has(php_phongo_packedarray_t* intern, zend_long index) { bson_iter_t iter; if (!bson_iter_init(&iter, intern->bson)) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not initialize BSON iterator"); return false; } return seek_iter_to_index(&iter, index); } static PHP_METHOD(MongoDB_BSON_PackedArray, has) { php_phongo_packedarray_t* intern; zend_long index; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(index) PHONGO_PARSE_PARAMETERS_END(); intern = Z_PACKEDARRAY_OBJ_P(getThis()); RETURN_BOOL(php_phongo_packedarray_has(intern, index)); } static PHP_METHOD(MongoDB_BSON_PackedArray, toCanonicalExtendedJSON) { php_phongo_packedarray_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_PACKEDARRAY_OBJ_P(getThis()); php_phongo_packedarray_to_json(return_value, BSON_JSON_MODE_CANONICAL, intern->bson); } static PHP_METHOD(MongoDB_BSON_PackedArray, toRelaxedExtendedJSON) { php_phongo_packedarray_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_PACKEDARRAY_OBJ_P(getThis()); php_phongo_packedarray_to_json(return_value, BSON_JSON_MODE_RELAXED, intern->bson); } static PHP_METHOD(MongoDB_BSON_PackedArray, toPHP) { php_phongo_packedarray_t* intern; zval* typemap = NULL; php_phongo_bson_state state; PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_ARRAY(typemap) PHONGO_PARSE_PARAMETERS_END(); PHONGO_BSON_INIT_STATE(state); if (!php_phongo_bson_typemap_to_state(typemap, &state.map)) { return; } intern = Z_PACKEDARRAY_OBJ_P(getThis()); state.is_visiting_array = true; state.map.int64_as_object = true; if (!php_phongo_bson_to_zval_ex(intern->bson, &state)) { zval_ptr_dtor(&state.zchild); php_phongo_bson_typemap_dtor(&state.map); RETURN_NULL(); } php_phongo_bson_typemap_dtor(&state.map); RETURN_ZVAL(&state.zchild, 0, 1); } static PHP_METHOD(MongoDB_BSON_PackedArray, offsetExists) { php_phongo_packedarray_t* intern; zval* key; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(key) PHONGO_PARSE_PARAMETERS_END(); intern = Z_PACKEDARRAY_OBJ_P(getThis()); if (Z_TYPE_P(key) != IS_LONG) { RETURN_FALSE; } RETURN_BOOL(php_phongo_packedarray_has(intern, Z_LVAL_P(key))); } static PHP_METHOD(MongoDB_BSON_PackedArray, offsetGet) { php_phongo_packedarray_t* intern; zval* key; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(key) PHONGO_PARSE_PARAMETERS_END(); intern = Z_PACKEDARRAY_OBJ_P(getThis()); if (Z_TYPE_P(key) != IS_LONG) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find index of type \"%s\" in BSON array", zend_zval_type_name(key)); return; } // May throw, in which case we do nothing php_phongo_packedarray_get(intern, Z_LVAL_P(key), return_value, false); } static PHP_METHOD(MongoDB_BSON_PackedArray, offsetSet) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot write to %s offset", ZSTR_VAL(php_phongo_packedarray_ce->name)); } static PHP_METHOD(MongoDB_BSON_PackedArray, offsetUnset) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot unset %s offset", ZSTR_VAL(php_phongo_packedarray_ce->name)); } static PHP_METHOD(MongoDB_BSON_PackedArray, __toString) { php_phongo_packedarray_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_PACKEDARRAY_OBJ_P(getThis()); RETVAL_STRINGL((const char*) bson_get_data(intern->bson), intern->bson->len); } static PHP_METHOD(MongoDB_BSON_PackedArray, __set_state) { php_phongo_packedarray_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_packedarray_ce); intern = Z_PACKEDARRAY_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_packedarray_init_from_hash(intern, props); } static PHP_METHOD(MongoDB_BSON_PackedArray, serialize) { php_phongo_packedarray_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; zend_string* str; intern = Z_PACKEDARRAY_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 1); str = php_base64_encode(bson_get_data(intern->bson), intern->bson->len); ADD_ASSOC_STR(&retval, "data", str); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); zend_string_free(str); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_PackedArray, unserialize) { php_phongo_packedarray_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_PACKEDARRAY_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_packedarray_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_packedarray_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_PackedArray, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_packedarray_get_properties_hash(Z_OBJ_P(getThis()), true, 1)); } static PHP_METHOD(MongoDB_BSON_PackedArray, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_packedarray_init_from_hash(Z_PACKEDARRAY_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\PackedArray object handlers */ static zend_object_handlers php_phongo_handler_packedarray; static void php_phongo_packedarray_free_object(zend_object* object) { php_phongo_packedarray_t* intern = Z_OBJ_PACKEDARRAY(object); zend_object_std_dtor(&intern->std); if (intern->bson) { bson_destroy(intern->bson); } if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_packedarray_create_object(zend_class_entry* class_type) { php_phongo_packedarray_t* intern = zend_object_alloc(sizeof(php_phongo_packedarray_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_packedarray; return &intern->std; } static zend_object* php_phongo_packedarray_clone_object(zend_object* object) { php_phongo_packedarray_t* intern; php_phongo_packedarray_t* new_intern; zend_object* new_object; intern = Z_OBJ_PACKEDARRAY(object); new_object = php_phongo_packedarray_create_object(object->ce); new_intern = Z_OBJ_PACKEDARRAY(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); new_intern->bson = bson_copy(intern->bson); return new_object; } static int php_phongo_packedarray_compare_objects(zval* o1, zval* o2) { php_phongo_packedarray_t *intern1, *intern2; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_PACKEDARRAY_OBJ_P(o1); intern2 = Z_PACKEDARRAY_OBJ_P(o2); return bson_compare(intern1->bson, intern2->bson); } static HashTable* php_phongo_packedarray_get_debug_info(zend_object* object, int* is_temp) { php_phongo_packedarray_t* intern; HashTable* props; *is_temp = 1; intern = Z_OBJ_PACKEDARRAY(object); /* This get_debug_info handler reports an additional property. This does not * conflict with other uses of php_phongo_document_get_properties_hash since * we always allocated a new HashTable with is_temp=true. */ props = php_phongo_packedarray_get_properties_hash(object, true, 2); { php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); state.is_visiting_array = true; state.map.array.type = PHONGO_TYPEMAP_BSON; state.map.document.type = PHONGO_TYPEMAP_BSON; if (!php_phongo_bson_to_zval_ex(intern->bson, &state)) { zval_ptr_dtor(&state.zchild); goto failure; } zend_hash_str_update(props, "value", sizeof("value") - 1, &state.zchild); } return props; failure: PHONGO_GET_PROPERTY_HASH_FREE_PROPS(is_temp, props); return NULL; } static HashTable* php_phongo_packedarray_get_properties(zend_object* object) { return php_phongo_packedarray_get_properties_hash(object, false, 1); } zval* php_phongo_packedarray_read_dimension(zend_object* object, zval* offset, int type, zval* rv) { php_phongo_packedarray_t* intern; intern = Z_OBJ_PACKEDARRAY(object); if (Z_TYPE_P(offset) != IS_LONG) { if (type == BP_VAR_IS) { ZVAL_NULL(rv); return rv; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Could not find index of type \"%s\" in BSON array", zend_zval_type_name(offset)); return &EG(uninitialized_zval); } if (!php_phongo_packedarray_get(intern, Z_LVAL_P(offset), rv, type == BP_VAR_IS)) { // Exception already thrown return &EG(uninitialized_zval); } return rv; } void php_phongo_packedarray_write_dimension(zend_object* object, zval* offset, zval* value) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot write to %s offset", ZSTR_VAL(php_phongo_packedarray_ce->name)); } int php_phongo_packedarray_has_dimension(zend_object* object, zval* member, int check_empty) { php_phongo_packedarray_t* intern; intern = Z_OBJ_PACKEDARRAY(object); if (Z_TYPE_P(member) != IS_LONG) { return false; } return php_phongo_packedarray_has(intern, Z_LVAL_P(member)); } void php_phongo_packedarray_unset_dimension(zend_object* object, zval* offset) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cannot unset %s offset", ZSTR_VAL(php_phongo_packedarray_ce->name)); } void php_phongo_packedarray_init_ce(INIT_FUNC_ARGS) { php_phongo_packedarray_ce = register_class_MongoDB_BSON_PackedArray(zend_ce_aggregate, zend_ce_serializable, zend_ce_arrayaccess, php_phongo_type_ce, zend_ce_stringable); php_phongo_packedarray_ce->create_object = php_phongo_packedarray_create_object; memcpy(&php_phongo_handler_packedarray, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_packedarray.compare = php_phongo_packedarray_compare_objects; php_phongo_handler_packedarray.clone_obj = php_phongo_packedarray_clone_object; php_phongo_handler_packedarray.get_debug_info = php_phongo_packedarray_get_debug_info; php_phongo_handler_packedarray.get_properties = php_phongo_packedarray_get_properties; php_phongo_handler_packedarray.free_obj = php_phongo_packedarray_free_object; php_phongo_handler_packedarray.read_dimension = php_phongo_packedarray_read_dimension; php_phongo_handler_packedarray.write_dimension = php_phongo_packedarray_write_dimension; php_phongo_handler_packedarray.has_dimension = php_phongo_packedarray_has_dimension; php_phongo_handler_packedarray.unset_dimension = php_phongo_packedarray_unset_dimension; php_phongo_handler_packedarray.offset = XtOffsetOf(php_phongo_packedarray_t, std); } bool phongo_packedarray_new(zval* object, bson_t* bson, bool copy) { php_phongo_packedarray_t* intern; object_init_ex(object, php_phongo_packedarray_ce); intern = Z_PACKEDARRAY_OBJ_P(object); intern->bson = copy ? bson_copy(bson) : bson; return true; } mongodb-1.21.0/src/BSON/PackedArray.h0000644000175100001660000000141514760300420014025 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_PACKEDARRAY_H #define PHONGO_BSON_PACKEDARRAY_H bool phongo_packedarray_new(zval* object, bson_t* bson, bool copy); #endif /* PHONGO_BSON_PACKEDARRAY_H */ mongodb-1.21.0/src/BSON/PackedArray_arginfo.h0000644000175100001660000001672214760300420015541 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 3e80c319dc75e220bd5f471badb7ac40888ddd87 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_fromJSON, 0, 1, MongoDB\\BSON\\PackedArray, 0) ZEND_ARG_TYPE_INFO(0, json, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_fromPHP, 0, 1, MongoDB\\BSON\\PackedArray, 0) ZEND_ARG_TYPE_INFO(0, value, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_get, 0, 1, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_getIterator, 0, 0, MongoDB\\BSON\\Iterator, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_has, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_MongoDB_BSON_PackedArray_toPHP, 0, 0, MAY_BE_ARRAY|MAY_BE_OBJECT) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, typeMap, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_PackedArray_toRelaxedExtendedJSON arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_offsetExists, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_offsetGet, 0, 1, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_offsetSet, 0, 2, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_offsetUnset, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, offset, IS_MIXED, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_PackedArray___toString arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray___set_state, 0, 1, MongoDB\\BSON\\PackedArray, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_PackedArray_serialize arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_PackedArray___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_PackedArray, __construct); static ZEND_METHOD(MongoDB_BSON_PackedArray, fromJSON); static ZEND_METHOD(MongoDB_BSON_PackedArray, fromPHP); static ZEND_METHOD(MongoDB_BSON_PackedArray, get); static ZEND_METHOD(MongoDB_BSON_PackedArray, getIterator); static ZEND_METHOD(MongoDB_BSON_PackedArray, has); static ZEND_METHOD(MongoDB_BSON_PackedArray, toPHP); static ZEND_METHOD(MongoDB_BSON_PackedArray, toCanonicalExtendedJSON); static ZEND_METHOD(MongoDB_BSON_PackedArray, toRelaxedExtendedJSON); static ZEND_METHOD(MongoDB_BSON_PackedArray, offsetExists); static ZEND_METHOD(MongoDB_BSON_PackedArray, offsetGet); static ZEND_METHOD(MongoDB_BSON_PackedArray, offsetSet); static ZEND_METHOD(MongoDB_BSON_PackedArray, offsetUnset); static ZEND_METHOD(MongoDB_BSON_PackedArray, __toString); static ZEND_METHOD(MongoDB_BSON_PackedArray, __set_state); static ZEND_METHOD(MongoDB_BSON_PackedArray, serialize); static ZEND_METHOD(MongoDB_BSON_PackedArray, unserialize); static ZEND_METHOD(MongoDB_BSON_PackedArray, __unserialize); static ZEND_METHOD(MongoDB_BSON_PackedArray, __serialize); static const zend_function_entry class_MongoDB_BSON_PackedArray_methods[] = { ZEND_ME(MongoDB_BSON_PackedArray, __construct, arginfo_class_MongoDB_BSON_PackedArray___construct, ZEND_ACC_PRIVATE) ZEND_ME(MongoDB_BSON_PackedArray, fromJSON, arginfo_class_MongoDB_BSON_PackedArray_fromJSON, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, fromPHP, arginfo_class_MongoDB_BSON_PackedArray_fromPHP, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, get, arginfo_class_MongoDB_BSON_PackedArray_get, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, getIterator, arginfo_class_MongoDB_BSON_PackedArray_getIterator, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, has, arginfo_class_MongoDB_BSON_PackedArray_has, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, toPHP, arginfo_class_MongoDB_BSON_PackedArray_toPHP, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, toCanonicalExtendedJSON, arginfo_class_MongoDB_BSON_PackedArray_toCanonicalExtendedJSON, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, toRelaxedExtendedJSON, arginfo_class_MongoDB_BSON_PackedArray_toRelaxedExtendedJSON, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, offsetExists, arginfo_class_MongoDB_BSON_PackedArray_offsetExists, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_BSON_PackedArray, offsetGet, arginfo_class_MongoDB_BSON_PackedArray_offsetGet, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_BSON_PackedArray, offsetSet, arginfo_class_MongoDB_BSON_PackedArray_offsetSet, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_BSON_PackedArray, offsetUnset, arginfo_class_MongoDB_BSON_PackedArray_offsetUnset, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_BSON_PackedArray, __toString, arginfo_class_MongoDB_BSON_PackedArray___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, __set_state, arginfo_class_MongoDB_BSON_PackedArray___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, serialize, arginfo_class_MongoDB_BSON_PackedArray_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, unserialize, arginfo_class_MongoDB_BSON_PackedArray_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, __unserialize, arginfo_class_MongoDB_BSON_PackedArray___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_PackedArray, __serialize, arginfo_class_MongoDB_BSON_PackedArray___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_PackedArray(zend_class_entry *class_entry_IteratorAggregate, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_ArrayAccess, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "PackedArray", class_MongoDB_BSON_PackedArray_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_IteratorAggregate, class_entry_Serializable, class_entry_ArrayAccess, class_entry_MongoDB_BSON_Type, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Persistable.c0000644000175100001660000000251314760300420014107 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "Persistable_arginfo.h" zend_class_entry* php_phongo_persistable_ce; static int php_phongo_implement_persistable(zend_class_entry* interface, zend_class_entry* class_type) { if (class_type->ce_flags & ZEND_ACC_ENUM) { zend_error_noreturn(E_ERROR, "Enum class %s cannot implement interface %s", ZSTR_VAL(class_type->name), ZSTR_VAL(interface->name)); return FAILURE; } return SUCCESS; } void php_phongo_persistable_init_ce(INIT_FUNC_ARGS) { php_phongo_persistable_ce = register_class_MongoDB_BSON_Persistable(php_phongo_serializable_ce, php_phongo_unserializable_ce); php_phongo_persistable_ce->interface_gets_implemented = php_phongo_implement_persistable; } mongodb-1.21.0/src/BSON/Persistable_arginfo.h0000644000175100001660000000206514760300420015623 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: ae3ff5f618e86293cdbee0ce419fee2b82c95ed6 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_MongoDB_BSON_Persistable_bsonSerialize, 0, 0, stdClass|MongoDB\\BSON\\Document, MAY_BE_ARRAY) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_BSON_Persistable_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_Persistable, bsonSerialize, arginfo_class_MongoDB_BSON_Persistable_bsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Persistable(zend_class_entry *class_entry_MongoDB_BSON_Serializable, zend_class_entry *class_entry_MongoDB_BSON_Unserializable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Persistable", class_MongoDB_BSON_Persistable_methods); class_entry = zend_register_internal_interface(&ce); zend_class_implements(class_entry, 2, class_entry_MongoDB_BSON_Serializable, class_entry_MongoDB_BSON_Unserializable); return class_entry; } mongodb-1.21.0/src/BSON/Regex.c0000644000175100001660000002520614760300420012710 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "Regex_arginfo.h" zend_class_entry* php_phongo_regex_ce; /* qsort() compare callback for alphabetizing regex flags upon initialization */ static int php_phongo_regex_compare_flags(const void* f1, const void* f2) { if (*(const char*) f1 == *(const char*) f2) { return 0; } return (*(const char*) f1 > *(const char*) f2) ? 1 : -1; } /* Initialize the object and return whether it was successful. An exception will * be thrown on error. */ static bool php_phongo_regex_init(php_phongo_regex_t* intern, const char* pattern, size_t pattern_len, const char* flags, size_t flags_len) { if (strlen(pattern) != (size_t) pattern_len) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Pattern cannot contain null bytes"); return false; } intern->pattern = estrndup(pattern, pattern_len); intern->pattern_len = pattern_len; if (flags) { if (strlen(flags) != (size_t) flags_len) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Flags cannot contain null bytes"); return false; } intern->flags = estrndup(flags, flags_len); intern->flags_len = flags_len; /* Ensure flags are alphabetized upon initialization */ qsort((void*) intern->flags, flags_len, 1, php_phongo_regex_compare_flags); } else { intern->flags = estrdup(""); intern->flags_len = 0; } return true; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_regex_init_from_hash(php_phongo_regex_t* intern, HashTable* props) { zval *pattern, *flags; if ((pattern = zend_hash_str_find(props, "pattern", sizeof("pattern") - 1)) && Z_TYPE_P(pattern) == IS_STRING && (flags = zend_hash_str_find(props, "flags", sizeof("flags") - 1)) && Z_TYPE_P(flags) == IS_STRING) { return php_phongo_regex_init(intern, Z_STRVAL_P(pattern), Z_STRLEN_P(pattern), Z_STRVAL_P(flags), Z_STRLEN_P(flags)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"pattern\" and \"flags\" string fields", ZSTR_VAL(php_phongo_regex_ce->name)); return false; } static HashTable* php_phongo_regex_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_regex_t* intern; HashTable* props; intern = Z_OBJ_REGEX(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 2); if (!intern->pattern) { return props; } { zval pattern, flags; ZVAL_STRINGL(&pattern, intern->pattern, intern->pattern_len); zend_hash_str_update(props, "pattern", sizeof("pattern") - 1, &pattern); ZVAL_STRINGL(&flags, intern->flags, intern->flags_len); zend_hash_str_update(props, "flags", sizeof("flags") - 1, &flags); } return props; } /* Constructs a new BSON regular expression type. */ static PHP_METHOD(MongoDB_BSON_Regex, __construct) { php_phongo_regex_t* intern; char* pattern; size_t pattern_len; char* flags = NULL; size_t flags_len = 0; intern = Z_REGEX_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STRING(pattern, pattern_len) Z_PARAM_OPTIONAL Z_PARAM_STRING(flags, flags_len) PHONGO_PARSE_PARAMETERS_END(); php_phongo_regex_init(intern, pattern, pattern_len, flags, flags_len); } static PHP_METHOD(MongoDB_BSON_Regex, getPattern) { php_phongo_regex_t* intern; intern = Z_REGEX_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRINGL(intern->pattern, intern->pattern_len); } static PHP_METHOD(MongoDB_BSON_Regex, getFlags) { php_phongo_regex_t* intern; intern = Z_REGEX_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRINGL(intern->flags, intern->flags_len); } static PHP_METHOD(MongoDB_BSON_Regex, __set_state) { php_phongo_regex_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_regex_ce); intern = Z_REGEX_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_regex_init_from_hash(intern, props); } /* Returns a string in the form: /pattern/flags */ static PHP_METHOD(MongoDB_BSON_Regex, __toString) { php_phongo_regex_t* intern; char* regex; int regex_len; intern = Z_REGEX_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); regex_len = spprintf(®ex, 0, "/%s/%s", intern->pattern, intern->flags); RETVAL_STRINGL(regex, regex_len); efree(regex); } static PHP_METHOD(MongoDB_BSON_Regex, jsonSerialize) { php_phongo_regex_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_REGEX_OBJ_P(getThis()); array_init_size(return_value, 2); ADD_ASSOC_STRINGL(return_value, "$regex", intern->pattern, intern->pattern_len); ADD_ASSOC_STRINGL(return_value, "$options", intern->flags, intern->flags_len); } static PHP_METHOD(MongoDB_BSON_Regex, serialize) { php_phongo_regex_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; intern = Z_REGEX_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 2); ADD_ASSOC_STRINGL(&retval, "pattern", intern->pattern, intern->pattern_len); ADD_ASSOC_STRINGL(&retval, "flags", intern->flags, intern->flags_len); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_Regex, unserialize) { php_phongo_regex_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_REGEX_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_regex_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_regex_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_Regex, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_regex_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_Regex, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_regex_init_from_hash(Z_REGEX_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\Regex object handlers */ static zend_object_handlers php_phongo_handler_regex; static void php_phongo_regex_free_object(zend_object* object) { php_phongo_regex_t* intern = Z_OBJ_REGEX(object); zend_object_std_dtor(&intern->std); if (intern->pattern) { efree(intern->pattern); } if (intern->flags) { efree(intern->flags); } if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_regex_create_object(zend_class_entry* class_type) { php_phongo_regex_t* intern = zend_object_alloc(sizeof(php_phongo_regex_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_regex; return &intern->std; } static zend_object* php_phongo_regex_clone_object(zend_object* object) { php_phongo_regex_t* intern; php_phongo_regex_t* new_intern; zend_object* new_object; intern = Z_OBJ_REGEX(object); new_object = php_phongo_regex_create_object(object->ce); new_intern = Z_OBJ_REGEX(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); php_phongo_regex_init(new_intern, intern->pattern, intern->pattern_len, intern->flags, intern->flags_len); return new_object; } static int php_phongo_regex_compare_objects(zval* o1, zval* o2) { php_phongo_regex_t *intern1, *intern2; int retval; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_REGEX_OBJ_P(o1); intern2 = Z_REGEX_OBJ_P(o2); /* MongoDB compares the pattern string before the flags. */ retval = strcmp(intern1->pattern, intern2->pattern); if (retval != 0) { return retval; } return strcmp(intern1->flags, intern2->flags); } static HashTable* php_phongo_regex_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_regex_get_properties_hash(object, true); } static HashTable* php_phongo_regex_get_properties(zend_object* object) { return php_phongo_regex_get_properties_hash(object, false); } void php_phongo_regex_init_ce(INIT_FUNC_ARGS) { php_phongo_regex_ce = register_class_MongoDB_BSON_Regex(php_phongo_regex_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_regex_ce->create_object = php_phongo_regex_create_object; memcpy(&php_phongo_handler_regex, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_regex.compare = php_phongo_regex_compare_objects; php_phongo_handler_regex.clone_obj = php_phongo_regex_clone_object; php_phongo_handler_regex.get_debug_info = php_phongo_regex_get_debug_info; php_phongo_handler_regex.get_properties = php_phongo_regex_get_properties; php_phongo_handler_regex.free_obj = php_phongo_regex_free_object; php_phongo_handler_regex.offset = XtOffsetOf(php_phongo_regex_t, std); } bool phongo_regex_new(zval* object, const char* pattern, const char* flags) { php_phongo_regex_t* intern; object_init_ex(object, php_phongo_regex_ce); intern = Z_REGEX_OBJ_P(object); intern->pattern_len = strlen(pattern); intern->pattern = estrndup(pattern, intern->pattern_len); intern->flags_len = strlen(flags); intern->flags = estrndup(flags, intern->flags_len); return true; } mongodb-1.21.0/src/BSON/Regex.h0000644000175100001660000000140414760300420012707 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_REGEX_H #define PHONGO_BSON_REGEX_H bool phongo_regex_new(zval* object, const char* pattern, const char* flags); #endif /* PHONGO_BSON_REGEX_H */ mongodb-1.21.0/src/BSON/RegexInterface.c0000644000175100001660000000155014760300420014525 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "RegexInterface_arginfo.h" zend_class_entry* php_phongo_regex_interface_ce; void php_phongo_regex_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_regex_interface_ce = register_class_MongoDB_BSON_RegexInterface(); } mongodb-1.21.0/src/BSON/RegexInterface_arginfo.h0000644000175100001660000000252314760300420016240 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 72a53fb51ca60f8ccb38a73afe74f76fb81bac71 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_RegexInterface_getPattern, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_RegexInterface_getFlags arginfo_class_MongoDB_BSON_RegexInterface_getPattern #define arginfo_class_MongoDB_BSON_RegexInterface___toString arginfo_class_MongoDB_BSON_RegexInterface_getPattern static const zend_function_entry class_MongoDB_BSON_RegexInterface_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_RegexInterface, getPattern, arginfo_class_MongoDB_BSON_RegexInterface_getPattern, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_RegexInterface, getFlags, arginfo_class_MongoDB_BSON_RegexInterface_getFlags, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_RegexInterface, __toString, arginfo_class_MongoDB_BSON_RegexInterface___toString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_RegexInterface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "RegexInterface", class_MongoDB_BSON_RegexInterface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/Regex_arginfo.h0000644000175100001660000001000314760300420014407 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: aa53c6b26b0dea96d357c59b51b4c6e9f5a21317 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Regex___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_STRING, 0, "\'\'") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Regex_getPattern, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Regex_getFlags arginfo_class_MongoDB_BSON_Regex_getPattern #define arginfo_class_MongoDB_BSON_Regex___toString arginfo_class_MongoDB_BSON_Regex_getPattern ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Regex___set_state, 0, 1, MongoDB\\BSON\\Regex, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Regex_serialize arginfo_class_MongoDB_BSON_Regex_getPattern ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Regex_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Regex___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Regex___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Regex_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Regex, __construct); static ZEND_METHOD(MongoDB_BSON_Regex, getPattern); static ZEND_METHOD(MongoDB_BSON_Regex, getFlags); static ZEND_METHOD(MongoDB_BSON_Regex, __toString); static ZEND_METHOD(MongoDB_BSON_Regex, __set_state); static ZEND_METHOD(MongoDB_BSON_Regex, serialize); static ZEND_METHOD(MongoDB_BSON_Regex, unserialize); static ZEND_METHOD(MongoDB_BSON_Regex, __unserialize); static ZEND_METHOD(MongoDB_BSON_Regex, __serialize); static ZEND_METHOD(MongoDB_BSON_Regex, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Regex_methods[] = { ZEND_ME(MongoDB_BSON_Regex, __construct, arginfo_class_MongoDB_BSON_Regex___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, getPattern, arginfo_class_MongoDB_BSON_Regex_getPattern, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, getFlags, arginfo_class_MongoDB_BSON_Regex_getFlags, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, __toString, arginfo_class_MongoDB_BSON_Regex___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, __set_state, arginfo_class_MongoDB_BSON_Regex___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, serialize, arginfo_class_MongoDB_BSON_Regex_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, unserialize, arginfo_class_MongoDB_BSON_Regex_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, __unserialize, arginfo_class_MongoDB_BSON_Regex___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, __serialize, arginfo_class_MongoDB_BSON_Regex___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Regex, jsonSerialize, arginfo_class_MongoDB_BSON_Regex_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Regex(zend_class_entry *class_entry_MongoDB_BSON_RegexInterface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Regex", class_MongoDB_BSON_Regex_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_MongoDB_BSON_RegexInterface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Serializable.c0000644000175100001660000000155514760300420014245 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "Serializable_arginfo.h" zend_class_entry* php_phongo_serializable_ce; void php_phongo_serializable_init_ce(INIT_FUNC_ARGS) { php_phongo_serializable_ce = register_class_MongoDB_BSON_Serializable(php_phongo_type_ce); } mongodb-1.21.0/src/BSON/Serializable_arginfo.h0000644000175100001660000000174314760300420015756 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: cf790c4aaa9d12777681842564139008ec73218b */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_MongoDB_BSON_Serializable_bsonSerialize, 0, 0, stdClass|MongoDB\\BSON\\Document|MongoDB\\BSON\\PackedArray, MAY_BE_ARRAY) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_BSON_Serializable_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_Serializable, bsonSerialize, arginfo_class_MongoDB_BSON_Serializable_bsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Serializable(zend_class_entry *class_entry_MongoDB_BSON_Type) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Serializable", class_MongoDB_BSON_Serializable_methods); class_entry = zend_register_internal_interface(&ce); zend_class_implements(class_entry, 1, class_entry_MongoDB_BSON_Type); return class_entry; } mongodb-1.21.0/src/BSON/Symbol.c0000644000175100001660000002001614760300420013075 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "Symbol_arginfo.h" zend_class_entry* php_phongo_symbol_ce; /* Initialize the object and return whether it was successful. An exception will * be thrown on error. */ static bool php_phongo_symbol_init(php_phongo_symbol_t* intern, const char* symbol, size_t symbol_len) { if (strlen(symbol) != (size_t) symbol_len) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Symbol cannot contain null bytes"); return false; } intern->symbol = estrndup(symbol, symbol_len); intern->symbol_len = symbol_len; return true; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_symbol_init_from_hash(php_phongo_symbol_t* intern, HashTable* props) { zval* symbol; if ((symbol = zend_hash_str_find(props, "symbol", sizeof("symbol") - 1)) && Z_TYPE_P(symbol) == IS_STRING) { return php_phongo_symbol_init(intern, Z_STRVAL_P(symbol), Z_STRLEN_P(symbol)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"symbol\" string field", ZSTR_VAL(php_phongo_symbol_ce->name)); return false; } HashTable* php_phongo_symbol_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_symbol_t* intern; HashTable* props; intern = Z_OBJ_SYMBOL(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 2); if (!intern->symbol) { return props; } { zval symbol; ZVAL_STRING(&symbol, intern->symbol); zend_hash_str_update(props, "symbol", sizeof("symbol") - 1, &symbol); } return props; } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_Symbol) /* Return the Symbol's symbol string. */ static PHP_METHOD(MongoDB_BSON_Symbol, __toString) { php_phongo_symbol_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_SYMBOL_OBJ_P(getThis()); RETURN_STRINGL(intern->symbol, intern->symbol_len); } static PHP_METHOD(MongoDB_BSON_Symbol, __set_state) { php_phongo_symbol_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_symbol_ce); intern = Z_SYMBOL_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_symbol_init_from_hash(intern, props); } static PHP_METHOD(MongoDB_BSON_Symbol, jsonSerialize) { php_phongo_symbol_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_SYMBOL_OBJ_P(getThis()); array_init_size(return_value, 1); ADD_ASSOC_STRINGL(return_value, "$symbol", intern->symbol, intern->symbol_len); } static PHP_METHOD(MongoDB_BSON_Symbol, serialize) { php_phongo_symbol_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; intern = Z_SYMBOL_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 1); ADD_ASSOC_STRINGL(&retval, "symbol", intern->symbol, intern->symbol_len); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_Symbol, unserialize) { php_phongo_symbol_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_SYMBOL_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_symbol_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_symbol_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_Symbol, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); ZVAL_ARR(return_value, php_phongo_symbol_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_Symbol, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_symbol_init_from_hash(Z_SYMBOL_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\Symbol object handlers */ static zend_object_handlers php_phongo_handler_symbol; static void php_phongo_symbol_free_object(zend_object* object) { php_phongo_symbol_t* intern = Z_OBJ_SYMBOL(object); zend_object_std_dtor(&intern->std); if (intern->symbol) { efree(intern->symbol); } if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } zend_object* php_phongo_symbol_create_object(zend_class_entry* class_type) { php_phongo_symbol_t* intern = zend_object_alloc(sizeof(php_phongo_symbol_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_symbol; return &intern->std; } static zend_object* php_phongo_symbol_clone_object(zend_object* object) { php_phongo_symbol_t* intern; php_phongo_symbol_t* new_intern; zend_object* new_object; intern = Z_OBJ_SYMBOL(object); new_object = php_phongo_symbol_create_object(object->ce); new_intern = Z_OBJ_SYMBOL(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); php_phongo_symbol_init(new_intern, intern->symbol, intern->symbol_len); return new_object; } static int php_phongo_symbol_compare_objects(zval* o1, zval* o2) { php_phongo_symbol_t *intern1, *intern2; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_SYMBOL_OBJ_P(o1); intern2 = Z_SYMBOL_OBJ_P(o2); return strcmp(intern1->symbol, intern2->symbol); } static HashTable* php_phongo_symbol_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_symbol_get_properties_hash(object, true); } static HashTable* php_phongo_symbol_get_properties(zend_object* object) { return php_phongo_symbol_get_properties_hash(object, false); } void php_phongo_symbol_init_ce(INIT_FUNC_ARGS) { php_phongo_symbol_ce = register_class_MongoDB_BSON_Symbol(php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_symbol_ce->create_object = php_phongo_symbol_create_object; memcpy(&php_phongo_handler_symbol, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_symbol.compare = php_phongo_symbol_compare_objects; php_phongo_handler_symbol.clone_obj = php_phongo_symbol_clone_object; php_phongo_handler_symbol.get_debug_info = php_phongo_symbol_get_debug_info; php_phongo_handler_symbol.get_properties = php_phongo_symbol_get_properties; php_phongo_handler_symbol.free_obj = php_phongo_symbol_free_object; php_phongo_handler_symbol.offset = XtOffsetOf(php_phongo_symbol_t, std); } bool phongo_symbol_new(zval* object, const char* symbol, size_t symbol_len) { php_phongo_symbol_t* intern; object_init_ex(object, php_phongo_symbol_ce); intern = Z_SYMBOL_OBJ_P(object); intern->symbol = estrndup(symbol, symbol_len); intern->symbol_len = symbol_len; return true; } mongodb-1.21.0/src/BSON/Symbol.h0000644000175100001660000000140714760300420013105 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_SYMBOL_H #define PHONGO_BSON_SYMBOL_H bool phongo_symbol_new(zval* object, const char* symbol, size_t symbol_len); #endif /* PHONGO_BSON_SYMBOL_H */ mongodb-1.21.0/src/BSON/Symbol_arginfo.h0000644000175100001660000000650314760300420014614 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: d13589fe0654877d462494f88d99ff20d22cde24 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Symbol___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Symbol___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Symbol___set_state, 0, 1, MongoDB\\BSON\\Symbol, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Symbol_serialize arginfo_class_MongoDB_BSON_Symbol___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Symbol_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Symbol___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Symbol___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Symbol_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Symbol, __construct); static ZEND_METHOD(MongoDB_BSON_Symbol, __toString); static ZEND_METHOD(MongoDB_BSON_Symbol, __set_state); static ZEND_METHOD(MongoDB_BSON_Symbol, serialize); static ZEND_METHOD(MongoDB_BSON_Symbol, unserialize); static ZEND_METHOD(MongoDB_BSON_Symbol, __unserialize); static ZEND_METHOD(MongoDB_BSON_Symbol, __serialize); static ZEND_METHOD(MongoDB_BSON_Symbol, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Symbol_methods[] = { ZEND_ME(MongoDB_BSON_Symbol, __construct, arginfo_class_MongoDB_BSON_Symbol___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Symbol, __toString, arginfo_class_MongoDB_BSON_Symbol___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Symbol, __set_state, arginfo_class_MongoDB_BSON_Symbol___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Symbol, serialize, arginfo_class_MongoDB_BSON_Symbol_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Symbol, unserialize, arginfo_class_MongoDB_BSON_Symbol_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Symbol, __unserialize, arginfo_class_MongoDB_BSON_Symbol___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Symbol, __serialize, arginfo_class_MongoDB_BSON_Symbol___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Symbol, jsonSerialize, arginfo_class_MongoDB_BSON_Symbol_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Symbol(zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Symbol", class_MongoDB_BSON_Symbol_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 4, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Timestamp.c0000644000175100001660000003233414760300420013601 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "phongo_util.h" #include "Timestamp_arginfo.h" zend_class_entry* php_phongo_timestamp_ce; /* Initialize the object and return whether it was successful. An exception will * be thrown on error. */ static bool php_phongo_timestamp_init(php_phongo_timestamp_t* intern, int64_t increment, int64_t timestamp) { if (increment < 0 || increment > UINT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected increment to be an unsigned 32-bit integer, %" PRId64 " given", increment); return false; } if (timestamp < 0 || timestamp > UINT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected timestamp to be an unsigned 32-bit integer, %" PRId64 " given", timestamp); return false; } intern->increment = (uint32_t) increment; intern->timestamp = (uint32_t) timestamp; intern->initialized = true; return true; } /* Initialize the object from numeric strings and return whether it was * successful. An exception will be thrown on error. */ static bool php_phongo_timestamp_init_from_string(php_phongo_timestamp_t* intern, const char* s_increment, size_t s_increment_len, const char* s_timestamp, size_t s_timestamp_len) { int64_t increment, timestamp; if (!php_phongo_parse_int64(&increment, s_increment, s_increment_len)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing \"%s\" as 64-bit integer increment for %s initialization", s_increment, ZSTR_VAL(php_phongo_timestamp_ce->name)); return false; } if (!php_phongo_parse_int64(×tamp, s_timestamp, s_timestamp_len)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing \"%s\" as 64-bit integer timestamp for %s initialization", s_timestamp, ZSTR_VAL(php_phongo_timestamp_ce->name)); return false; } return php_phongo_timestamp_init(intern, increment, timestamp); } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_timestamp_init_from_hash(php_phongo_timestamp_t* intern, HashTable* props) { zval *increment, *timestamp; if ((increment = zend_hash_str_find(props, "increment", sizeof("increment") - 1)) && Z_TYPE_P(increment) == IS_LONG && (timestamp = zend_hash_str_find(props, "timestamp", sizeof("timestamp") - 1)) && Z_TYPE_P(timestamp) == IS_LONG) { return php_phongo_timestamp_init(intern, Z_LVAL_P(increment), Z_LVAL_P(timestamp)); } if ((increment = zend_hash_str_find(props, "increment", sizeof("increment") - 1)) && Z_TYPE_P(increment) == IS_STRING && (timestamp = zend_hash_str_find(props, "timestamp", sizeof("timestamp") - 1)) && Z_TYPE_P(timestamp) == IS_STRING) { return php_phongo_timestamp_init_from_string(intern, Z_STRVAL_P(increment), Z_STRLEN_P(increment), Z_STRVAL_P(timestamp), Z_STRLEN_P(timestamp)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"increment\" and \"timestamp\" integer or numeric string fields", ZSTR_VAL(php_phongo_timestamp_ce->name)); return false; } static HashTable* php_phongo_timestamp_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_timestamp_t* intern; HashTable* props; char s_increment[24]; char s_timestamp[24]; int s_increment_len; int s_timestamp_len; intern = Z_OBJ_TIMESTAMP(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 2); if (!intern->initialized) { return props; } s_increment_len = snprintf(s_increment, sizeof(s_increment), "%" PRIu32, intern->increment); s_timestamp_len = snprintf(s_timestamp, sizeof(s_timestamp), "%" PRIu32, intern->timestamp); { zval increment, timestamp; ZVAL_STRINGL(&increment, s_increment, s_increment_len); zend_hash_str_update(props, "increment", sizeof("increment") - 1, &increment); ZVAL_STRINGL(×tamp, s_timestamp, s_timestamp_len); zend_hash_str_update(props, "timestamp", sizeof("timestamp") - 1, ×tamp); } return props; } /* Construct a new BSON timestamp type, which consists of a 4-byte increment and 4-byte timestamp. */ static PHP_METHOD(MongoDB_BSON_Timestamp, __construct) { php_phongo_timestamp_t* intern; zval * increment = NULL, *timestamp = NULL; intern = Z_TIMESTAMP_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ZVAL(increment) Z_PARAM_ZVAL(timestamp) PHONGO_PARSE_PARAMETERS_END(); if (Z_TYPE_P(increment) == IS_LONG && Z_TYPE_P(timestamp) == IS_LONG) { php_phongo_timestamp_init(intern, Z_LVAL_P(increment), Z_LVAL_P(timestamp)); return; } if (Z_TYPE_P(increment) == IS_LONG) { convert_to_string(increment); } if (Z_TYPE_P(increment) != IS_STRING) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected increment to be an unsigned 32-bit integer or string, %s given", zend_zval_type_name(increment)); return; } if (Z_TYPE_P(timestamp) == IS_LONG) { convert_to_string(timestamp); } if (Z_TYPE_P(timestamp) != IS_STRING) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected timestamp to be an unsigned 32-bit integer or string, %s given", zend_zval_type_name(timestamp)); return; } php_phongo_timestamp_init_from_string(intern, Z_STRVAL_P(increment), Z_STRLEN_P(increment), Z_STRVAL_P(timestamp), Z_STRLEN_P(timestamp)); } static PHP_METHOD(MongoDB_BSON_Timestamp, getIncrement) { php_phongo_timestamp_t* intern; intern = Z_TIMESTAMP_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->increment); } static PHP_METHOD(MongoDB_BSON_Timestamp, getTimestamp) { php_phongo_timestamp_t* intern; intern = Z_TIMESTAMP_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->timestamp); } static PHP_METHOD(MongoDB_BSON_Timestamp, __set_state) { php_phongo_timestamp_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_timestamp_ce); intern = Z_TIMESTAMP_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_timestamp_init_from_hash(intern, props); } /* Returns a string in the form: [increment:timestamp] */ static PHP_METHOD(MongoDB_BSON_Timestamp, __toString) { php_phongo_timestamp_t* intern; char* retval; int retval_len; intern = Z_TIMESTAMP_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); retval_len = spprintf(&retval, 0, "[%" PRIu32 ":%" PRIu32 "]", intern->increment, intern->timestamp); RETVAL_STRINGL(retval, retval_len); efree(retval); } static PHP_METHOD(MongoDB_BSON_Timestamp, jsonSerialize) { php_phongo_timestamp_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_TIMESTAMP_OBJ_P(getThis()); array_init_size(return_value, 1); { zval ts; array_init_size(&ts, 2); ADD_ASSOC_LONG_EX(&ts, "t", intern->timestamp); ADD_ASSOC_LONG_EX(&ts, "i", intern->increment); ADD_ASSOC_ZVAL_EX(return_value, "$timestamp", &ts); } } static PHP_METHOD(MongoDB_BSON_Timestamp, serialize) { php_phongo_timestamp_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; char s_increment[12]; char s_timestamp[12]; int s_increment_len; int s_timestamp_len; intern = Z_TIMESTAMP_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); s_increment_len = snprintf(s_increment, sizeof(s_increment), "%" PRIu32, intern->increment); s_timestamp_len = snprintf(s_timestamp, sizeof(s_timestamp), "%" PRIu32, intern->timestamp); array_init_size(&retval, 2); ADD_ASSOC_STRINGL(&retval, "increment", s_increment, s_increment_len); ADD_ASSOC_STRINGL(&retval, "timestamp", s_timestamp, s_timestamp_len); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_Timestamp, unserialize) { php_phongo_timestamp_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_TIMESTAMP_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_timestamp_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_timestamp_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_Timestamp, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_timestamp_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_Timestamp, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_timestamp_init_from_hash(Z_TIMESTAMP_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\Timestamp object handlers */ static zend_object_handlers php_phongo_handler_timestamp; static void php_phongo_timestamp_free_object(zend_object* object) { php_phongo_timestamp_t* intern = Z_OBJ_TIMESTAMP(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_timestamp_create_object(zend_class_entry* class_type) { php_phongo_timestamp_t* intern = zend_object_alloc(sizeof(php_phongo_timestamp_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_timestamp; return &intern->std; } static zend_object* php_phongo_timestamp_clone_object(zend_object* object) { php_phongo_timestamp_t* intern; php_phongo_timestamp_t* new_intern; zend_object* new_object; intern = Z_OBJ_TIMESTAMP(object); new_object = php_phongo_timestamp_create_object(object->ce); new_intern = Z_OBJ_TIMESTAMP(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); php_phongo_timestamp_init(new_intern, intern->increment, intern->timestamp); return new_object; } static int php_phongo_timestamp_compare_objects(zval* o1, zval* o2) { php_phongo_timestamp_t *intern1, *intern2; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_TIMESTAMP_OBJ_P(o1); intern2 = Z_TIMESTAMP_OBJ_P(o2); /* MongoDB compares the timestamp before the increment. */ if (intern1->timestamp != intern2->timestamp) { return intern1->timestamp < intern2->timestamp ? -1 : 1; } if (intern1->increment != intern2->increment) { return intern1->increment < intern2->increment ? -1 : 1; } return 0; } static HashTable* php_phongo_timestamp_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_timestamp_get_properties_hash(object, true); } static HashTable* php_phongo_timestamp_get_properties(zend_object* object) { return php_phongo_timestamp_get_properties_hash(object, false); } void php_phongo_timestamp_init_ce(INIT_FUNC_ARGS) { php_phongo_timestamp_ce = register_class_MongoDB_BSON_Timestamp(php_phongo_timestamp_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_timestamp_ce->create_object = php_phongo_timestamp_create_object; memcpy(&php_phongo_handler_timestamp, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_timestamp.compare = php_phongo_timestamp_compare_objects; php_phongo_handler_timestamp.clone_obj = php_phongo_timestamp_clone_object; php_phongo_handler_timestamp.get_debug_info = php_phongo_timestamp_get_debug_info; php_phongo_handler_timestamp.get_properties = php_phongo_timestamp_get_properties; php_phongo_handler_timestamp.free_obj = php_phongo_timestamp_free_object; php_phongo_handler_timestamp.offset = XtOffsetOf(php_phongo_timestamp_t, std); } bool phongo_timestamp_new(zval* object, uint32_t increment, uint32_t timestamp) { php_phongo_timestamp_t* intern; object_init_ex(object, php_phongo_timestamp_ce); intern = Z_TIMESTAMP_OBJ_P(object); intern->increment = increment; intern->timestamp = timestamp; intern->initialized = true; return true; } mongodb-1.21.0/src/BSON/Timestamp.h0000644000175100001660000000142414760300420013602 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_TIMESTAMP_H #define PHONGO_BSON_TIMESTAMP_H bool phongo_timestamp_new(zval* object, uint32_t increment, uint32_t timestamp); #endif /* PHONGO_BSON_TIMESTAMP_H */ mongodb-1.21.0/src/BSON/TimestampInterface.c0000644000175100001660000000157414760300420015424 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "TimestampInterface_arginfo.h" zend_class_entry* php_phongo_timestamp_interface_ce; void php_phongo_timestamp_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_timestamp_interface_ce = register_class_MongoDB_BSON_TimestampInterface(); } mongodb-1.21.0/src/BSON/TimestampInterface_arginfo.h0000644000175100001660000000267314760300420017137 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 2a749d00f223cb25242c2f3a303b183074f5841c */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_TimestampInterface_getTimestamp, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_TimestampInterface_getIncrement arginfo_class_MongoDB_BSON_TimestampInterface_getTimestamp ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_TimestampInterface___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_BSON_TimestampInterface_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_TimestampInterface, getTimestamp, arginfo_class_MongoDB_BSON_TimestampInterface_getTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_TimestampInterface, getIncrement, arginfo_class_MongoDB_BSON_TimestampInterface_getIncrement, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_TimestampInterface, __toString, arginfo_class_MongoDB_BSON_TimestampInterface___toString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_TimestampInterface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "TimestampInterface", class_MongoDB_BSON_TimestampInterface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/Timestamp_arginfo.h0000644000175100001660000001041514760300420015307 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 32e036d627150cc5d09cf687eb4ae0e469fbc198 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Timestamp___construct, 0, 0, 2) ZEND_ARG_TYPE_MASK(0, increment, MAY_BE_LONG|MAY_BE_STRING, NULL) ZEND_ARG_TYPE_MASK(0, timestamp, MAY_BE_LONG|MAY_BE_STRING, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Timestamp_getTimestamp, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Timestamp_getIncrement arginfo_class_MongoDB_BSON_Timestamp_getTimestamp ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Timestamp___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Timestamp___set_state, 0, 1, MongoDB\\BSON\\Timestamp, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Timestamp_serialize arginfo_class_MongoDB_BSON_Timestamp___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Timestamp_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Timestamp___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Timestamp___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Timestamp_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Timestamp, __construct); static ZEND_METHOD(MongoDB_BSON_Timestamp, getTimestamp); static ZEND_METHOD(MongoDB_BSON_Timestamp, getIncrement); static ZEND_METHOD(MongoDB_BSON_Timestamp, __toString); static ZEND_METHOD(MongoDB_BSON_Timestamp, __set_state); static ZEND_METHOD(MongoDB_BSON_Timestamp, serialize); static ZEND_METHOD(MongoDB_BSON_Timestamp, unserialize); static ZEND_METHOD(MongoDB_BSON_Timestamp, __unserialize); static ZEND_METHOD(MongoDB_BSON_Timestamp, __serialize); static ZEND_METHOD(MongoDB_BSON_Timestamp, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Timestamp_methods[] = { ZEND_ME(MongoDB_BSON_Timestamp, __construct, arginfo_class_MongoDB_BSON_Timestamp___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, getTimestamp, arginfo_class_MongoDB_BSON_Timestamp_getTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, getIncrement, arginfo_class_MongoDB_BSON_Timestamp_getIncrement, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, __toString, arginfo_class_MongoDB_BSON_Timestamp___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, __set_state, arginfo_class_MongoDB_BSON_Timestamp___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, serialize, arginfo_class_MongoDB_BSON_Timestamp_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, unserialize, arginfo_class_MongoDB_BSON_Timestamp_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, __unserialize, arginfo_class_MongoDB_BSON_Timestamp___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, __serialize, arginfo_class_MongoDB_BSON_Timestamp___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Timestamp, jsonSerialize, arginfo_class_MongoDB_BSON_Timestamp_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Timestamp(zend_class_entry *class_entry_MongoDB_BSON_TimestampInterface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Timestamp", class_MongoDB_BSON_Timestamp_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_MongoDB_BSON_TimestampInterface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Type.c0000644000175100001660000000146314760300420012556 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "Type_arginfo.h" zend_class_entry* php_phongo_type_ce; void php_phongo_type_init_ce(INIT_FUNC_ARGS) { php_phongo_type_ce = register_class_MongoDB_BSON_Type(); } mongodb-1.21.0/src/BSON/Type_arginfo.h0000644000175100001660000000073514760300420014271 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: ece602b4c841263e650ab50fa949a83ad265db69 */ static const zend_function_entry class_MongoDB_BSON_Type_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Type(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Type", class_MongoDB_BSON_Type_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/UTCDateTime.c0000644000175100001660000003456714760300420013720 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "phongo_util.h" #include "UTCDateTime_arginfo.h" zend_class_entry* php_phongo_utcdatetime_ce; /* Initialize the object and return whether it was successful. */ static bool php_phongo_utcdatetime_init(php_phongo_utcdatetime_t* intern, int64_t milliseconds) { intern->milliseconds = milliseconds; intern->initialized = true; return true; } /* Initialize the object from a numeric string and return whether it was * successful. An exception will be thrown on error. */ static bool php_phongo_utcdatetime_init_from_string(php_phongo_utcdatetime_t* intern, const char* s_milliseconds, size_t s_milliseconds_len) { int64_t milliseconds; if (!php_phongo_parse_int64(&milliseconds, s_milliseconds, s_milliseconds_len)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing \"%s\" as 64-bit integer for %s initialization", s_milliseconds, ZSTR_VAL(php_phongo_utcdatetime_ce->name)); return false; } return php_phongo_utcdatetime_init(intern, milliseconds); } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_utcdatetime_init_from_hash(php_phongo_utcdatetime_t* intern, HashTable* props) { zval* milliseconds; if ((milliseconds = zend_hash_str_find(props, "milliseconds", sizeof("milliseconds") - 1)) && Z_TYPE_P(milliseconds) == IS_LONG) { return php_phongo_utcdatetime_init(intern, Z_LVAL_P(milliseconds)); } if ((milliseconds = zend_hash_str_find(props, "milliseconds", sizeof("milliseconds") - 1)) && Z_TYPE_P(milliseconds) == IS_STRING) { return php_phongo_utcdatetime_init_from_string(intern, Z_STRVAL_P(milliseconds), Z_STRLEN_P(milliseconds)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"milliseconds\" integer or numeric string field", ZSTR_VAL(php_phongo_utcdatetime_ce->name)); return false; } /* Initialize the object from the current time and return whether it was * successful. */ static bool php_phongo_utcdatetime_init_from_current_time(php_phongo_utcdatetime_t* intern) { int64_t sec, usec; struct timeval cur_time; bson_gettimeofday(&cur_time); sec = cur_time.tv_sec; usec = cur_time.tv_usec; intern->milliseconds = (sec * 1000) + (usec / 1000); intern->initialized = true; return true; } /* Initialize the object from a DateTime object and return whether it was * successful. */ static bool php_phongo_utcdatetime_init_from_date(php_phongo_utcdatetime_t* intern, php_date_obj* datetime_obj) { int64_t sec, usec; /* The following assignments use the same logic as date_format() in php_date.c */ sec = datetime_obj->time->sse; usec = (int64_t) floor(datetime_obj->time->us); intern->milliseconds = (sec * 1000) + (usec / 1000); intern->initialized = true; return true; } static bool php_phongo_utcdatetime_init_from_object(php_phongo_utcdatetime_t* intern, zend_object* object) { if (instanceof_function(object->ce, php_date_get_interface_ce())) { php_phongo_utcdatetime_init_from_date(intern, php_date_obj_from_obj(object)); return true; } if (instanceof_function(object->ce, php_phongo_int64_ce)) { php_phongo_utcdatetime_init(intern, php_int64_fetch_object(object)->integer); return true; } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected instance of %s or %s, %s given", ZSTR_VAL(php_date_get_interface_ce()->name), ZSTR_VAL(php_phongo_int64_ce->name), ZSTR_VAL(object->ce->name)); return false; } static bool php_phongo_utcdatetime_init_from_double(php_phongo_utcdatetime_t* intern, double milliseconds) { char tmp[24]; int tmp_len; tmp_len = snprintf(tmp, sizeof(tmp), "%.0f", milliseconds > 0 ? floor(milliseconds) : ceil(milliseconds)); return php_phongo_utcdatetime_init_from_string(intern, tmp, tmp_len); } static HashTable* php_phongo_utcdatetime_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_utcdatetime_t* intern; HashTable* props; intern = Z_OBJ_UTCDATETIME(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 1); if (!intern->initialized) { return props; } { zval milliseconds; ZVAL_INT64_STRING(&milliseconds, intern->milliseconds); zend_hash_str_update(props, "milliseconds", sizeof("milliseconds") - 1, &milliseconds); } return props; } static void php_phongo_utcdatetime_to_php_date(zval* return_value, const zval* this, zend_class_entry* ce) { php_phongo_utcdatetime_t* intern; php_date_obj* datetime_obj; char* sec_str; size_t sec_len; int64_t sec, usec; intern = Z_UTCDATETIME_OBJ_P(this); object_init_ex(return_value, ce); datetime_obj = Z_PHPDATE_P(return_value); sec = intern->milliseconds / 1000; usec = (llabs(intern->milliseconds) % 1000) * 1000; if (intern->milliseconds < 0 && usec != 0) { /* For dates before the unix epoch, we need to subtract the microseconds from the timestamp. * Since we can't directly pass microseconds when calling php_date_initialize due to a bug in PHP, * we manually decrement the timestamp and subtract the number of microseconds from a full seconds * to store in the us field. */ sec--; usec = 1000000 - usec; } /* TODO PHP 8.1.7+: microseconds can be included in the format string */ sec_len = spprintf(&sec_str, 0, "@%" PRId64, sec); php_date_initialize(datetime_obj, sec_str, sec_len, NULL, NULL, 0); efree(sec_str); datetime_obj->time->us = usec; } /* Construct a new BSON UTCDateTime type from either the current time, milliseconds since the epoch, or a DateTimeInterface object. Defaults to the current time. */ static PHP_METHOD(MongoDB_BSON_UTCDateTime, __construct) { php_phongo_utcdatetime_t* intern; zval* milliseconds = NULL; intern = Z_UTCDATETIME_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_OR_NULL(milliseconds) PHONGO_PARSE_PARAMETERS_END(); if (milliseconds == NULL) { php_phongo_utcdatetime_init_from_current_time(intern); return; } switch (Z_TYPE_P(milliseconds)) { case IS_OBJECT: php_phongo_utcdatetime_init_from_object(intern, Z_OBJ_P(milliseconds)); return; case IS_LONG: php_phongo_utcdatetime_init(intern, Z_LVAL_P(milliseconds)); return; case IS_DOUBLE: php_error_docref(NULL, E_DEPRECATED, "Creating a %s instance with a float is deprecated and will be removed in ext-mongodb 2.0", ZSTR_VAL(php_phongo_utcdatetime_ce->name)); php_phongo_utcdatetime_init_from_double(intern, Z_DVAL_P(milliseconds)); return; case IS_STRING: php_error_docref(NULL, E_DEPRECATED, "Creating a %s instance with a string is deprecated and will be removed in ext-mongodb 2.0", ZSTR_VAL(php_phongo_utcdatetime_ce->name)); php_phongo_utcdatetime_init_from_string(intern, Z_STRVAL_P(milliseconds), Z_STRLEN_P(milliseconds)); return; } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected integer or string, %s given", zend_zval_type_name(milliseconds)); } static PHP_METHOD(MongoDB_BSON_UTCDateTime, __set_state) { php_phongo_utcdatetime_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_utcdatetime_ce); intern = Z_UTCDATETIME_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_utcdatetime_init_from_hash(intern, props); } /* Returns the UTCDateTime's milliseconds as a string */ static PHP_METHOD(MongoDB_BSON_UTCDateTime, __toString) { php_phongo_utcdatetime_t* intern; intern = Z_UTCDATETIME_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); ZVAL_INT64_STRING(return_value, intern->milliseconds); } /* Returns a DateTime object representing this UTCDateTime */ static PHP_METHOD(MongoDB_BSON_UTCDateTime, toDateTime) { PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_utcdatetime_to_php_date(return_value, getThis(), php_date_get_date_ce()); } /* Returns a DateTimeImmutable object representing this UTCDateTime */ static PHP_METHOD(MongoDB_BSON_UTCDateTime, toDateTimeImmutable) { PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_utcdatetime_to_php_date(return_value, getThis(), php_date_get_immutable_ce()); } static PHP_METHOD(MongoDB_BSON_UTCDateTime, jsonSerialize) { php_phongo_utcdatetime_t* intern; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_UTCDATETIME_OBJ_P(getThis()); array_init_size(return_value, 1); { zval udt; array_init_size(&udt, 1); ADD_ASSOC_INT64_AS_STRING(&udt, "$numberLong", intern->milliseconds); ADD_ASSOC_ZVAL_EX(return_value, "$date", &udt); } } static PHP_METHOD(MongoDB_BSON_UTCDateTime, serialize) { php_phongo_utcdatetime_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; intern = Z_UTCDATETIME_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 1); ADD_ASSOC_INT64_AS_STRING(&retval, "milliseconds", intern->milliseconds); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_BSON_UTCDateTime, unserialize) { php_phongo_utcdatetime_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_UTCDATETIME_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_utcdatetime_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_utcdatetime_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_BSON_UTCDateTime, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_utcdatetime_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_BSON_UTCDateTime, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_utcdatetime_init_from_hash(Z_UTCDATETIME_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\BSON\UTCDateTime object handlers */ static zend_object_handlers php_phongo_handler_utcdatetime; static void php_phongo_utcdatetime_free_object(zend_object* object) { php_phongo_utcdatetime_t* intern = Z_OBJ_UTCDATETIME(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_utcdatetime_create_object(zend_class_entry* class_type) { php_phongo_utcdatetime_t* intern = zend_object_alloc(sizeof(php_phongo_utcdatetime_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_utcdatetime; return &intern->std; } static zend_object* php_phongo_utcdatetime_clone_object(zend_object* object) { php_phongo_utcdatetime_t* intern; php_phongo_utcdatetime_t* new_intern; zend_object* new_object; intern = Z_OBJ_UTCDATETIME(object); new_object = php_phongo_utcdatetime_create_object(object->ce); new_intern = Z_OBJ_UTCDATETIME(new_object); zend_objects_clone_members(&new_intern->std, &intern->std); php_phongo_utcdatetime_init(new_intern, intern->milliseconds); return new_object; } static int php_phongo_utcdatetime_compare_objects(zval* o1, zval* o2) { php_phongo_utcdatetime_t *intern1, *intern2; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_UTCDATETIME_OBJ_P(o1); intern2 = Z_UTCDATETIME_OBJ_P(o2); if (intern1->milliseconds != intern2->milliseconds) { return intern1->milliseconds < intern2->milliseconds ? -1 : 1; } return 0; } static HashTable* php_phongo_utcdatetime_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_utcdatetime_get_properties_hash(object, true); } static HashTable* php_phongo_utcdatetime_get_properties(zend_object* object) { return php_phongo_utcdatetime_get_properties_hash(object, false); } void php_phongo_utcdatetime_init_ce(INIT_FUNC_ARGS) { php_phongo_utcdatetime_ce = register_class_MongoDB_BSON_UTCDateTime(php_phongo_utcdatetime_interface_ce, php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_utcdatetime_ce->create_object = php_phongo_utcdatetime_create_object; memcpy(&php_phongo_handler_utcdatetime, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_utcdatetime.compare = php_phongo_utcdatetime_compare_objects; php_phongo_handler_utcdatetime.clone_obj = php_phongo_utcdatetime_clone_object; php_phongo_handler_utcdatetime.get_debug_info = php_phongo_utcdatetime_get_debug_info; php_phongo_handler_utcdatetime.get_properties = php_phongo_utcdatetime_get_properties; php_phongo_handler_utcdatetime.free_obj = php_phongo_utcdatetime_free_object; php_phongo_handler_utcdatetime.offset = XtOffsetOf(php_phongo_utcdatetime_t, std); } bool phongo_utcdatetime_new(zval* object, int64_t msec_since_epoch) { php_phongo_utcdatetime_t* intern; object_init_ex(object, php_phongo_utcdatetime_ce); intern = Z_UTCDATETIME_OBJ_P(object); intern->milliseconds = msec_since_epoch; intern->initialized = true; return true; } mongodb-1.21.0/src/BSON/UTCDateTime.h0000644000175100001660000000141614760300420013710 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef PHONGO_BSON_UTCDATETIME_H #define PHONGO_BSON_UTCDATETIME_H bool phongo_utcdatetime_new(zval* object, int64_t msec_since_epoch); #endif /* PHONGO_BSON_UTCDATETIME_H */ mongodb-1.21.0/src/BSON/UTCDateTimeInterface.c0000644000175100001660000000160614760300420015525 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include #include "php_phongo.h" #include "UTCDateTimeInterface_arginfo.h" zend_class_entry* php_phongo_utcdatetime_interface_ce; void php_phongo_utcdatetime_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_utcdatetime_interface_ce = register_class_MongoDB_BSON_UTCDateTimeInterface(); } mongodb-1.21.0/src/BSON/UTCDateTimeInterface_arginfo.h0000644000175100001660000000223714760300420017240 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: d6725fe1f1e80ebc13fcc924b0a794b23b44c034 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTimeInterface_toDateTime, 0, 0, DateTime, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTimeInterface___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_BSON_UTCDateTimeInterface_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_UTCDateTimeInterface, toDateTime, arginfo_class_MongoDB_BSON_UTCDateTimeInterface_toDateTime, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_UTCDateTimeInterface, __toString, arginfo_class_MongoDB_BSON_UTCDateTimeInterface___toString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_UTCDateTimeInterface(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "UTCDateTimeInterface", class_MongoDB_BSON_UTCDateTimeInterface_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/UTCDateTime_arginfo.h0000644000175100001660000001065214760300420015417 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: ab30193571615b458a7ba01eb20da36ef1ecaf64 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime___construct, 0, 0, 0) ZEND_ARG_OBJ_TYPE_MASK(0, milliseconds, DateTimeInterface|MongoDB\\BSON\\Int64, MAY_BE_LONG|MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime_toDateTime, 0, 0, DateTime, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime_toDateTimeImmutable, 0, 0, DateTimeImmutable, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime___set_state, 0, 1, MongoDB\\BSON\\\125TCDateTime, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_UTCDateTime_serialize arginfo_class_MongoDB_BSON_UTCDateTime___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_UTCDateTime_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_UTCDateTime, __construct); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, toDateTime); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, toDateTimeImmutable); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, __toString); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, __set_state); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, serialize); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, unserialize); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, __unserialize); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, __serialize); static ZEND_METHOD(MongoDB_BSON_UTCDateTime, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_UTCDateTime_methods[] = { ZEND_ME(MongoDB_BSON_UTCDateTime, __construct, arginfo_class_MongoDB_BSON_UTCDateTime___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, toDateTime, arginfo_class_MongoDB_BSON_UTCDateTime_toDateTime, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, toDateTimeImmutable, arginfo_class_MongoDB_BSON_UTCDateTime_toDateTimeImmutable, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, __toString, arginfo_class_MongoDB_BSON_UTCDateTime___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, __set_state, arginfo_class_MongoDB_BSON_UTCDateTime___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, serialize, arginfo_class_MongoDB_BSON_UTCDateTime_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, unserialize, arginfo_class_MongoDB_BSON_UTCDateTime_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, __unserialize, arginfo_class_MongoDB_BSON_UTCDateTime___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, __serialize, arginfo_class_MongoDB_BSON_UTCDateTime___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_UTCDateTime, jsonSerialize, arginfo_class_MongoDB_BSON_UTCDateTime_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_UTCDateTime(zend_class_entry *class_entry_MongoDB_BSON_UTCDateTimeInterface, zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "UTCDateTime", class_MongoDB_BSON_UTCDateTime_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 5, class_entry_MongoDB_BSON_UTCDateTimeInterface, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Undefined.c0000644000175100001660000000653414760300420013542 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "Undefined_arginfo.h" zend_class_entry* php_phongo_undefined_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_BSON_Undefined) /* Return the empty string. */ static PHP_METHOD(MongoDB_BSON_Undefined, __toString) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRINGL("", 0); } static PHP_METHOD(MongoDB_BSON_Undefined, __set_state) { zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_undefined_ce); } static PHP_METHOD(MongoDB_BSON_Undefined, jsonSerialize) { PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(return_value, 1); ADD_ASSOC_BOOL_EX(return_value, "$undefined", 1); } static PHP_METHOD(MongoDB_BSON_Undefined, serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRING(""); } static PHP_METHOD(MongoDB_BSON_Undefined, unserialize) { char* serialized; size_t serialized_len; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); } static PHP_METHOD(MongoDB_BSON_Undefined, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(return_value, 0); } static PHP_METHOD(MongoDB_BSON_Undefined, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); } /* MongoDB\BSON\Undefined object handlers */ static zend_object_handlers php_phongo_handler_undefined; static void php_phongo_undefined_free_object(zend_object* object) { php_phongo_undefined_t* intern = Z_OBJ_UNDEFINED(object); zend_object_std_dtor(&intern->std); } static zend_object* php_phongo_undefined_create_object(zend_class_entry* class_type) { php_phongo_undefined_t* intern = zend_object_alloc(sizeof(php_phongo_undefined_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_undefined; return &intern->std; } void php_phongo_undefined_init_ce(INIT_FUNC_ARGS) { php_phongo_undefined_ce = register_class_MongoDB_BSON_Undefined(php_phongo_json_serializable_ce, php_phongo_type_ce, zend_ce_serializable, zend_ce_stringable); php_phongo_undefined_ce->create_object = php_phongo_undefined_create_object; memcpy(&php_phongo_handler_undefined, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); /* Re-assign default handler previously removed in php_phongo.c */ php_phongo_handler_undefined.clone_obj = zend_objects_clone_obj; php_phongo_handler_undefined.free_obj = php_phongo_undefined_free_object; php_phongo_handler_undefined.offset = XtOffsetOf(php_phongo_undefined_t, std); } mongodb-1.21.0/src/BSON/Undefined_arginfo.h0000644000175100001660000000667014760300420015255 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 19f544907b65caa4d9e82581531195d1dca026fd */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Undefined___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Undefined___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Undefined___set_state, 0, 1, MongoDB\\BSON\\\125ndefined, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_BSON_Undefined_serialize arginfo_class_MongoDB_BSON_Undefined___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Undefined_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Undefined___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Undefined___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Undefined_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Undefined, __construct); static ZEND_METHOD(MongoDB_BSON_Undefined, __toString); static ZEND_METHOD(MongoDB_BSON_Undefined, __set_state); static ZEND_METHOD(MongoDB_BSON_Undefined, serialize); static ZEND_METHOD(MongoDB_BSON_Undefined, unserialize); static ZEND_METHOD(MongoDB_BSON_Undefined, __unserialize); static ZEND_METHOD(MongoDB_BSON_Undefined, __serialize); static ZEND_METHOD(MongoDB_BSON_Undefined, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Undefined_methods[] = { ZEND_ME(MongoDB_BSON_Undefined, __construct, arginfo_class_MongoDB_BSON_Undefined___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Undefined, __toString, arginfo_class_MongoDB_BSON_Undefined___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Undefined, __set_state, arginfo_class_MongoDB_BSON_Undefined___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Undefined, serialize, arginfo_class_MongoDB_BSON_Undefined_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Undefined, unserialize, arginfo_class_MongoDB_BSON_Undefined_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Undefined, __unserialize, arginfo_class_MongoDB_BSON_Undefined___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Undefined, __serialize, arginfo_class_MongoDB_BSON_Undefined___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Undefined, jsonSerialize, arginfo_class_MongoDB_BSON_Undefined_jsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Undefined(zend_class_entry *class_entry_JsonSerializable, zend_class_entry *class_entry_MongoDB_BSON_Type, zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Undefined", class_MongoDB_BSON_Undefined_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 4, class_entry_JsonSerializable, class_entry_MongoDB_BSON_Type, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/BSON/Unserializable.c0000644000175100001660000000245314760300420014606 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "Unserializable_arginfo.h" zend_class_entry* php_phongo_unserializable_ce; static int php_phongo_implement_unserializable(zend_class_entry* interface, zend_class_entry* class_type) { if (class_type->ce_flags & ZEND_ACC_ENUM) { zend_error_noreturn(E_ERROR, "Enum class %s cannot implement interface %s", ZSTR_VAL(class_type->name), ZSTR_VAL(interface->name)); return FAILURE; } return SUCCESS; } void php_phongo_unserializable_init_ce(INIT_FUNC_ARGS) { php_phongo_unserializable_ce = register_class_MongoDB_BSON_Unserializable(); php_phongo_unserializable_ce->interface_gets_implemented = php_phongo_implement_unserializable; } mongodb-1.21.0/src/BSON/Unserializable_arginfo.h0000644000175100001660000000155414760300420016321 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 2954181cca6d68d40bf46d5ffad15f3ccbc73b72 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Unserializable_bsonUnserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_BSON_Unserializable_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_BSON_Unserializable, bsonUnserialize, arginfo_class_MongoDB_BSON_Unserializable_bsonUnserialize, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_BSON_Unserializable(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\BSON", "Unserializable", class_MongoDB_BSON_Unserializable_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/BSON/functions.c0000644000175100001660000001006114760300420013637 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" /* Returns the BSON representation of a PHP value */ PHP_FUNCTION(MongoDB_BSON_fromPHP) { zval* data; bson_t* bson; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY_OR_OBJECT(data) PHONGO_PARSE_PARAMETERS_END(); bson = bson_new(); php_phongo_zval_to_bson(data, PHONGO_BSON_NONE, bson, NULL); RETVAL_STRINGL((const char*) bson_get_data(bson), bson->len); bson_destroy(bson); } /* Returns the PHP representation of a BSON value, optionally converting it into a custom class */ PHP_FUNCTION(MongoDB_BSON_toPHP) { char* data; size_t data_len; zval* typemap = NULL; php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STRING(data, data_len) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(typemap) PHONGO_PARSE_PARAMETERS_END(); if (!php_phongo_bson_typemap_to_state(typemap, &state.map)) { return; } if (!php_phongo_bson_data_to_zval_ex((const unsigned char*) data, data_len, &state)) { zval_ptr_dtor(&state.zchild); php_phongo_bson_typemap_dtor(&state.map); RETURN_NULL(); } php_phongo_bson_typemap_dtor(&state.map); RETURN_ZVAL(&state.zchild, 0, 1); } /* Returns the BSON representation of a JSON value */ PHP_FUNCTION(MongoDB_BSON_fromJSON) { char* json; size_t json_len; bson_t bson = BSON_INITIALIZER; bson_error_t error = { 0 }; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(json, json_len) PHONGO_PARSE_PARAMETERS_END(); if (bson_init_from_json(&bson, (const char*) json, json_len, &error)) { RETVAL_STRINGL((const char*) bson_get_data(&bson), bson.len); bson_destroy(&bson); } else { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s", error.domain == BSON_ERROR_JSON ? error.message : "Error parsing JSON"); } } static void phongo_bson_to_json(INTERNAL_FUNCTION_PARAMETERS, php_phongo_json_mode_t mode) { char* data; size_t data_len; const bson_t* bson; bool eof = false; bson_reader_t* reader; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(data, data_len) PHONGO_PARSE_PARAMETERS_END(); reader = bson_reader_new_from_data((const unsigned char*) data, data_len); bson = bson_reader_read(reader, NULL); if (!bson) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not read document from BSON reader"); bson_reader_destroy(reader); return; } if (!php_phongo_bson_to_json(return_value, bson, mode)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not convert BSON document to a JSON string"); bson_reader_destroy(reader); return; } if (bson_reader_read(reader, &eof) || !eof) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Reading document did not exhaust input buffer"); } bson_reader_destroy(reader); } /* Returns the legacy extended JSON representation of a BSON value */ PHP_FUNCTION(MongoDB_BSON_toJSON) { phongo_bson_to_json(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHONGO_JSON_MODE_LEGACY); } /* Returns the canonical extended JSON representation of a BSON value */ PHP_FUNCTION(MongoDB_BSON_toCanonicalExtendedJSON) { phongo_bson_to_json(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHONGO_JSON_MODE_CANONICAL); } /* Returns the relaxed extended JSON representation of a BSON value */ PHP_FUNCTION(MongoDB_BSON_toRelaxedExtendedJSON) { phongo_bson_to_json(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHONGO_JSON_MODE_RELAXED); } mongodb-1.21.0/src/MongoDB/Exception/AuthenticationException.c0000644000175100001660000000167714760300420021164 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "AuthenticationException_arginfo.h" zend_class_entry* php_phongo_authenticationexception_ce; void php_phongo_authenticationexception_init_ce(INIT_FUNC_ARGS) { php_phongo_authenticationexception_ce = register_class_MongoDB_Driver_Exception_AuthenticationException(php_phongo_connectionexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/AuthenticationException_arginfo.h0000644000175100001660000000133114760300420022661 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: dfb57a5b65b8a075b239be872177213a182faf60 */ static const zend_function_entry class_MongoDB_Driver_Exception_AuthenticationException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_AuthenticationException(zend_class_entry *class_entry_MongoDB_Driver_Exception_ConnectionException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "AuthenticationException", class_MongoDB_Driver_Exception_AuthenticationException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_ConnectionException); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/BulkWriteException.c0000644000175100001660000000164114760300420020104 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include #include "php_phongo.h" #include "BulkWriteException_arginfo.h" zend_class_entry* php_phongo_bulkwriteexception_ce; void php_phongo_bulkwriteexception_init_ce(INIT_FUNC_ARGS) { php_phongo_bulkwriteexception_ce = register_class_MongoDB_Driver_Exception_BulkWriteException(php_phongo_writeexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/BulkWriteException_arginfo.h0000644000175100001660000000127314760300420021617 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 330d290dbbcd19c7f10afd7a08b3f57ad4497cd7 */ static const zend_function_entry class_MongoDB_Driver_Exception_BulkWriteException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_BulkWriteException(zend_class_entry *class_entry_MongoDB_Driver_Exception_WriteException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "BulkWriteException", class_MongoDB_Driver_Exception_BulkWriteException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_WriteException); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/CommandException.c0000644000175100001660000000245314760300420017554 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include #include "php_phongo.h" #include "phongo_error.h" #include "CommandException_arginfo.h" zend_class_entry* php_phongo_commandexception_ce; /* Returns the result document from the failed command. */ static PHP_METHOD(MongoDB_Driver_Exception_CommandException, getResultDocument) { zval* resultdocument; zval rv; PHONGO_PARSE_PARAMETERS_NONE(); resultdocument = zend_read_property(php_phongo_commandexception_ce, Z_OBJ_P(getThis()), ZEND_STRL("resultDocument"), 0, &rv); RETURN_ZVAL(resultdocument, 1, 0); } void php_phongo_commandexception_init_ce(INIT_FUNC_ARGS) { php_phongo_commandexception_ce = register_class_MongoDB_Driver_Exception_CommandException(php_phongo_serverexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/CommandException_arginfo.h0000644000175100001660000000274514760300420021272 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 55cb6773eee137316b8b5a78cd1050b061b2e24e */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Exception_CommandException_getResultDocument, 0, 0, IS_OBJECT, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Exception_CommandException, getResultDocument); static const zend_function_entry class_MongoDB_Driver_Exception_CommandException_methods[] = { ZEND_ME(MongoDB_Driver_Exception_CommandException, getResultDocument, arginfo_class_MongoDB_Driver_Exception_CommandException_getResultDocument, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_CommandException(zend_class_entry *class_entry_MongoDB_Driver_Exception_ServerException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "CommandException", class_MongoDB_Driver_Exception_CommandException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_ServerException); zval property_resultDocument_default_value; ZVAL_NULL(&property_resultDocument_default_value); zend_string *property_resultDocument_name = zend_string_init("resultDocument", sizeof("resultDocument") - 1, 1); zend_declare_property_ex(class_entry, property_resultDocument_name, &property_resultDocument_default_value, ZEND_ACC_PROTECTED, NULL); zend_string_release(property_resultDocument_name); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/ConnectionException.c0000644000175100001660000000165014760300420020273 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "ConnectionException_arginfo.h" zend_class_entry* php_phongo_connectionexception_ce; void php_phongo_connectionexception_init_ce(INIT_FUNC_ARGS) { php_phongo_connectionexception_ce = register_class_MongoDB_Driver_Exception_ConnectionException(php_phongo_runtimeexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/ConnectionException_arginfo.h0000644000175100001660000000130314760300420022000 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 722ab9f3f73ccb6493c68e6ce4ac888f1aec8955 */ static const zend_function_entry class_MongoDB_Driver_Exception_ConnectionException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_ConnectionException(zend_class_entry *class_entry_MongoDB_Driver_Exception_RuntimeException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "ConnectionException", class_MongoDB_Driver_Exception_ConnectionException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_RuntimeException); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/ConnectionTimeoutException.c0000644000175100001660000000171614760300420021645 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include #include "php_phongo.h" #include "ConnectionTimeoutException_arginfo.h" zend_class_entry* php_phongo_connectiontimeoutexception_ce; void php_phongo_connectiontimeoutexception_init_ce(INIT_FUNC_ARGS) { php_phongo_connectiontimeoutexception_ce = register_class_MongoDB_Driver_Exception_ConnectionTimeoutException(php_phongo_connectionexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/ConnectionTimeoutException_arginfo.h0000644000175100001660000000141714760300420023355 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 60470413296405ec96e76e4331835d8a27dd5ade */ static const zend_function_entry class_MongoDB_Driver_Exception_ConnectionTimeoutException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_ConnectionTimeoutException(zend_class_entry *class_entry_MongoDB_Driver_Exception_ConnectionException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "ConnectionTimeoutException", class_MongoDB_Driver_Exception_ConnectionTimeoutException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_ConnectionException); class_entry->ce_flags |= ZEND_ACC_FINAL; return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/EncryptionException.c0000644000175100001660000000165014760300420020326 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "EncryptionException_arginfo.h" zend_class_entry* php_phongo_encryptionexception_ce; void php_phongo_encryptionexception_init_ce(INIT_FUNC_ARGS) { php_phongo_encryptionexception_ce = register_class_MongoDB_Driver_Exception_EncryptionException(php_phongo_runtimeexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/EncryptionException_arginfo.h0000644000175100001660000000130314760300420022033 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 432323bdeb13c6e1ce5e0201f0957290f412d26d */ static const zend_function_entry class_MongoDB_Driver_Exception_EncryptionException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_EncryptionException(zend_class_entry *class_entry_MongoDB_Driver_Exception_RuntimeException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "EncryptionException", class_MongoDB_Driver_Exception_EncryptionException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_RuntimeException); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/Exception.c0000644000175100001660000000160614760300420016254 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "Exception_arginfo.h" zend_class_entry* php_phongo_exception_ce; void php_phongo_exception_init_ce(INIT_FUNC_ARGS) { php_phongo_exception_ce = register_class_MongoDB_Driver_Exception_Exception(zend_ce_throwable); } mongodb-1.21.0/src/MongoDB/Exception/Exception_arginfo.h0000644000175100001660000000120414760300420017760 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 0e426c19c65154d51a01669619579b7ab2b7f60c */ static const zend_function_entry class_MongoDB_Driver_Exception_Exception_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_Exception(zend_class_entry *class_entry_Throwable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "Exception", class_MongoDB_Driver_Exception_Exception_methods); class_entry = zend_register_internal_interface(&ce); zend_class_implements(class_entry, 1, class_entry_Throwable); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/ExecutionTimeoutException.c0000644000175100001660000000170514760300420021507 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include #include "php_phongo.h" #include "ExecutionTimeoutException_arginfo.h" zend_class_entry* php_phongo_executiontimeoutexception_ce; void php_phongo_executiontimeoutexception_init_ce(INIT_FUNC_ARGS) { php_phongo_executiontimeoutexception_ce = register_class_MongoDB_Driver_Exception_ExecutionTimeoutException(php_phongo_serverexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/ExecutionTimeoutException_arginfo.h0000644000175100001660000000140314760300420023214 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: e152c0d8d8a6b9d5cd6f43479fb32972ecd585d5 */ static const zend_function_entry class_MongoDB_Driver_Exception_ExecutionTimeoutException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_ExecutionTimeoutException(zend_class_entry *class_entry_MongoDB_Driver_Exception_ServerException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "ExecutionTimeoutException", class_MongoDB_Driver_Exception_ExecutionTimeoutException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_ServerException); class_entry->ce_flags |= ZEND_ACC_FINAL; return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/InvalidArgumentException.c0000644000175100001660000000177714760300420021277 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "InvalidArgumentException_arginfo.h" zend_class_entry* php_phongo_invalidargumentexception_ce; void php_phongo_invalidargumentexception_init_ce(INIT_FUNC_ARGS) { php_phongo_invalidargumentexception_ce = register_class_MongoDB_Driver_Exception_InvalidArgumentException(spl_ce_InvalidArgumentException, php_phongo_exception_ce); } mongodb-1.21.0/src/MongoDB/Exception/InvalidArgumentException_arginfo.h0000644000175100001660000000151714760300420023001 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 275625c4d5dfb49b5608867b883711c5a4dc2057 */ static const zend_function_entry class_MongoDB_Driver_Exception_InvalidArgumentException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_InvalidArgumentException(zend_class_entry *class_entry_InvalidArgumentException, zend_class_entry *class_entry_MongoDB_Driver_Exception_Exception) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "InvalidArgumentException", class_MongoDB_Driver_Exception_InvalidArgumentException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_InvalidArgumentException); zend_class_implements(class_entry, 1, class_entry_MongoDB_Driver_Exception_Exception); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/LogicException.c0000644000175100001660000000170314760300420017230 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "LogicException_arginfo.h" zend_class_entry* php_phongo_logicexception_ce; void php_phongo_logicexception_init_ce(INIT_FUNC_ARGS) { php_phongo_logicexception_ce = register_class_MongoDB_Driver_Exception_LogicException(spl_ce_LogicException, php_phongo_exception_ce); } mongodb-1.21.0/src/MongoDB/Exception/LogicException_arginfo.h0000644000175100001660000000142314760300420020741 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: e3bbd956f358c9c22d22617be4d56c4018bd0441 */ static const zend_function_entry class_MongoDB_Driver_Exception_LogicException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_LogicException(zend_class_entry *class_entry_LogicException, zend_class_entry *class_entry_MongoDB_Driver_Exception_Exception) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "LogicException", class_MongoDB_Driver_Exception_LogicException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_LogicException); zend_class_implements(class_entry, 1, class_entry_MongoDB_Driver_Exception_Exception); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/RuntimeException.c0000644000175100001660000000364314760300420017623 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_error.h" #include "RuntimeException_arginfo.h" zend_class_entry* php_phongo_runtimeexception_ce; static bool php_phongo_has_string_array_element(zval* labels, char* label) { HashTable* ht_data; if (Z_TYPE_P(labels) != IS_ARRAY) { return false; } ht_data = HASH_OF(labels); { zval* z_label; ZEND_HASH_FOREACH_VAL_IND(ht_data, z_label) { if ((Z_TYPE_P(z_label) == IS_STRING) && (strcmp(Z_STRVAL_P(z_label), label) == 0)) { return true; } } ZEND_HASH_FOREACH_END(); } return false; } /* Returns whether a specific error label has been set */ static PHP_METHOD(MongoDB_Driver_Exception_RuntimeException, hasErrorLabel) { char* label; size_t label_len; zval* error_labels; zval rv; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(label, label_len) PHONGO_PARSE_PARAMETERS_END(); error_labels = zend_read_property(php_phongo_runtimeexception_ce, Z_OBJ_P(getThis()), ZEND_STRL("errorLabels"), 0, &rv); RETURN_BOOL(php_phongo_has_string_array_element(error_labels, label)); } void php_phongo_runtimeexception_init_ce(INIT_FUNC_ARGS) { php_phongo_runtimeexception_ce = register_class_MongoDB_Driver_Exception_RuntimeException(spl_ce_RuntimeException, php_phongo_exception_ce); } mongodb-1.21.0/src/MongoDB/Exception/RuntimeException_arginfo.h0000644000175100001660000000312714760300420021332 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: c895df47a65fcadec95e6f0d4e3f98a0dae827d6 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Exception_RuntimeException_hasErrorLabel, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, errorLabel, IS_STRING, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Exception_RuntimeException, hasErrorLabel); static const zend_function_entry class_MongoDB_Driver_Exception_RuntimeException_methods[] = { ZEND_ME(MongoDB_Driver_Exception_RuntimeException, hasErrorLabel, arginfo_class_MongoDB_Driver_Exception_RuntimeException_hasErrorLabel, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_RuntimeException(zend_class_entry *class_entry_RuntimeException, zend_class_entry *class_entry_MongoDB_Driver_Exception_Exception) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "RuntimeException", class_MongoDB_Driver_Exception_RuntimeException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_RuntimeException); zend_class_implements(class_entry, 1, class_entry_MongoDB_Driver_Exception_Exception); zval property_errorLabels_default_value; ZVAL_NULL(&property_errorLabels_default_value); zend_string *property_errorLabels_name = zend_string_init("errorLabels", sizeof("errorLabels") - 1, 1); zend_declare_property_ex(class_entry, property_errorLabels_name, &property_errorLabels_default_value, ZEND_ACC_PROTECTED, NULL); zend_string_release(property_errorLabels_name); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/SSLConnectionException.c0000644000175100001660000000167214760300420020661 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "SSLConnectionException_arginfo.h" zend_class_entry* php_phongo_sslconnectionexception_ce; void php_phongo_sslconnectionexception_init_ce(INIT_FUNC_ARGS) { php_phongo_sslconnectionexception_ce = register_class_MongoDB_Driver_Exception_SSLConnectionException(php_phongo_connectionexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/SSLConnectionException_arginfo.h0000644000175100001660000000142314760300420022365 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 2948889569c0558ad634e3d05360b9d942dbb282 */ static const zend_function_entry class_MongoDB_Driver_Exception_SSLConnectionException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_SSLConnectionException(zend_class_entry *class_entry_MongoDB_Driver_Exception_ConnectionException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "SSLConnectionException", class_MongoDB_Driver_Exception_SSLConnectionException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_ConnectionException); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_DEPRECATED; return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/ServerException.c0000644000175100001660000000162414760300420017443 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include #include "php_phongo.h" #include "ServerException_arginfo.h" zend_class_entry* php_phongo_serverexception_ce; void php_phongo_serverexception_init_ce(INIT_FUNC_ARGS) { php_phongo_serverexception_ce = register_class_MongoDB_Driver_Exception_ServerException(php_phongo_runtimeexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/ServerException_arginfo.h0000644000175100001660000000126314760300420021154 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 62d8bf646599c54ba5a204b38042f80578435322 */ static const zend_function_entry class_MongoDB_Driver_Exception_ServerException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_ServerException(zend_class_entry *class_entry_MongoDB_Driver_Exception_RuntimeException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "ServerException", class_MongoDB_Driver_Exception_ServerException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_RuntimeException); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/UnexpectedValueException.c0000644000175100001660000000177714760300420021307 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "UnexpectedValueException_arginfo.h" zend_class_entry* php_phongo_unexpectedvalueexception_ce; void php_phongo_unexpectedvalueexception_init_ce(INIT_FUNC_ARGS) { php_phongo_unexpectedvalueexception_ce = register_class_MongoDB_Driver_Exception_UnexpectedValueException(spl_ce_UnexpectedValueException, php_phongo_exception_ce); } mongodb-1.21.0/src/MongoDB/Exception/UnexpectedValueException_arginfo.h0000644000175100001660000000151714760300420023011 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 463206b30ddfa600327f4ba731476ab4196939de */ static const zend_function_entry class_MongoDB_Driver_Exception_UnexpectedValueException_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_UnexpectedValueException(zend_class_entry *class_entry_UnexpectedValueException, zend_class_entry *class_entry_MongoDB_Driver_Exception_Exception) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "UnexpectedValueException", class_MongoDB_Driver_Exception_UnexpectedValueException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_UnexpectedValueException); zend_class_implements(class_entry, 1, class_entry_MongoDB_Driver_Exception_Exception); return class_entry; } mongodb-1.21.0/src/MongoDB/Exception/WriteException.c0000644000175100001660000000242214760300420017264 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include "php_phongo.h" #include "phongo_error.h" #include "WriteException_arginfo.h" zend_class_entry* php_phongo_writeexception_ce; /* Returns the WriteResult from the failed write operation. */ static PHP_METHOD(MongoDB_Driver_Exception_WriteException, getWriteResult) { zval* writeresult; zval rv; PHONGO_PARSE_PARAMETERS_NONE(); writeresult = zend_read_property(php_phongo_writeexception_ce, Z_OBJ_P(getThis()), ZEND_STRL("writeResult"), 0, &rv); RETURN_ZVAL(writeresult, 1, 0); } void php_phongo_writeexception_init_ce(INIT_FUNC_ARGS) { php_phongo_writeexception_ce = register_class_MongoDB_Driver_Exception_WriteException(php_phongo_serverexception_ce); } mongodb-1.21.0/src/MongoDB/Exception/WriteException_arginfo.h0000644000175100001660000000300414760300420020773 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: d68a9b6bb6ba6a1222689ffe95c58ce91b3a6704 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Exception_WriteException_getWriteResult, 0, 0, MongoDB\\Driver\\WriteResult, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Exception_WriteException, getWriteResult); static const zend_function_entry class_MongoDB_Driver_Exception_WriteException_methods[] = { ZEND_ME(MongoDB_Driver_Exception_WriteException, getWriteResult, arginfo_class_MongoDB_Driver_Exception_WriteException_getWriteResult, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Exception_WriteException(zend_class_entry *class_entry_MongoDB_Driver_Exception_ServerException) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Exception", "WriteException", class_MongoDB_Driver_Exception_WriteException_methods); class_entry = zend_register_internal_class_ex(&ce, class_entry_MongoDB_Driver_Exception_ServerException); class_entry->ce_flags |= ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED; zval property_writeResult_default_value; ZVAL_NULL(&property_writeResult_default_value); zend_string *property_writeResult_name = zend_string_init("writeResult", sizeof("writeResult") - 1, 1); zend_declare_property_ex(class_entry, property_writeResult_name, &property_writeResult_default_value, ZEND_ACC_PROTECTED, NULL); zend_string_release(property_writeResult_name); return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/CommandFailedEvent.c0000644000175100001660000002066014760300420020173 0ustar /* * Copyright 2016-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "MongoDB/Server.h" #include "CommandFailedEvent_arginfo.h" zend_class_entry* php_phongo_commandfailedevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_CommandFailedEvent) static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getCommandName) { php_phongo_commandfailedevent_t* intern; intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->command_name); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getDatabaseName) { php_phongo_commandfailedevent_t* intern; intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->database_name); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getDurationMicros) { php_phongo_commandfailedevent_t* intern; intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->duration_micros); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getError) { php_phongo_commandfailedevent_t* intern; intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ZVAL(&intern->z_error, 1, 0); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getHost) { php_phongo_commandfailedevent_t* intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getOperationId) { php_phongo_commandfailedevent_t* intern; char operation_id[24]; intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); snprintf(operation_id, sizeof(operation_id), "%" PRId64, intern->operation_id); RETVAL_STRING(operation_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getPort) { php_phongo_commandfailedevent_t* intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getReply) { php_phongo_commandfailedevent_t* intern; php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!php_phongo_bson_to_zval_ex(intern->reply, &state)) { zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getRequestId) { php_phongo_commandfailedevent_t* intern; char request_id[24]; intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); snprintf(request_id, sizeof(request_id), "%" PRId64, intern->request_id); RETVAL_STRING(request_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getServer) { php_phongo_commandfailedevent_t* intern; intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_server_init(return_value, &intern->manager, intern->server_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getServiceId) { php_phongo_commandfailedevent_t* intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!intern->has_service_id) { RETURN_NULL(); } phongo_objectid_new(return_value, &intern->service_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getServerConnectionId) { php_phongo_commandfailedevent_t* intern = Z_COMMANDFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); /* TODO: Use MONGOC_NO_SERVER_CONNECTION_ID once it is added to libmongoc's public API (CDRIVER-4176) */ if (intern->server_connection_id == -1) { RETURN_NULL(); } #if SIZEOF_ZEND_LONG == 4 if (intern->server_connection_id > INT32_MAX || intern->server_connection_id < INT32_MIN) { zend_error(E_WARNING, "Truncating 64-bit value %" PRId64 " for serverConnectionId", intern->server_connection_id); } #endif RETURN_LONG(intern->server_connection_id); } /* MongoDB\Driver\Monitoring\CommandFailedEvent object handlers */ static zend_object_handlers php_phongo_handler_commandfailedevent; static void php_phongo_commandfailedevent_free_object(zend_object* object) { php_phongo_commandfailedevent_t* intern = Z_OBJ_COMMANDFAILEDEVENT(object); zend_object_std_dtor(&intern->std); if (!Z_ISUNDEF(intern->z_error)) { zval_ptr_dtor(&intern->z_error); } if (!Z_ISUNDEF(intern->manager)) { zval_ptr_dtor(&intern->manager); } if (intern->reply) { bson_destroy(intern->reply); } if (intern->command_name) { efree(intern->command_name); } if (intern->database_name) { efree(intern->database_name); } } static zend_object* php_phongo_commandfailedevent_create_object(zend_class_entry* class_type) { php_phongo_commandfailedevent_t* intern = zend_object_alloc(sizeof(php_phongo_commandfailedevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_commandfailedevent; return &intern->std; } static HashTable* php_phongo_commandfailedevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_commandfailedevent_t* intern; zval retval = ZVAL_STATIC_INIT; char operation_id[24], request_id[24]; php_phongo_bson_state reply_state; PHONGO_BSON_INIT_STATE(reply_state); intern = Z_OBJ_COMMANDFAILEDEVENT(object); *is_temp = 1; array_init_size(&retval, 11); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); ADD_ASSOC_STRING(&retval, "commandName", intern->command_name); ADD_ASSOC_INT64(&retval, "durationMicros", intern->duration_micros); ADD_ASSOC_ZVAL_EX(&retval, "error", &intern->z_error); Z_ADDREF(intern->z_error); if (!php_phongo_bson_to_zval_ex(intern->reply, &reply_state)) { zval_ptr_dtor(&reply_state.zchild); goto done; } ADD_ASSOC_ZVAL(&retval, "reply", &reply_state.zchild); snprintf(operation_id, sizeof(operation_id), "%" PRId64, intern->operation_id); ADD_ASSOC_STRING(&retval, "operationId", operation_id); snprintf(request_id, sizeof(request_id), "%" PRId64, intern->request_id); ADD_ASSOC_STRING(&retval, "requestId", request_id); { zval server; phongo_server_init(&server, &intern->manager, intern->server_id); ADD_ASSOC_ZVAL_EX(&retval, "server", &server); } if (intern->has_service_id) { zval service_id; if (!phongo_objectid_new(&service_id, &intern->service_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "serviceId", &service_id); } else { ADD_ASSOC_NULL_EX(&retval, "serviceId"); } /* TODO: Use MONGOC_NO_SERVER_CONNECTION_ID once it is added to libmongoc's public API (CDRIVER-4176) */ if (intern->server_connection_id == -1) { ADD_ASSOC_NULL_EX(&retval, "serverConnectionId"); } else { ADD_ASSOC_LONG_EX(&retval, "serverConnectionId", intern->server_connection_id); } done: return Z_ARRVAL(retval); } void php_phongo_commandfailedevent_init_ce(INIT_FUNC_ARGS) { php_phongo_commandfailedevent_ce = register_class_MongoDB_Driver_Monitoring_CommandFailedEvent(); php_phongo_commandfailedevent_ce->create_object = php_phongo_commandfailedevent_create_object; memcpy(&php_phongo_handler_commandfailedevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_commandfailedevent.get_debug_info = php_phongo_commandfailedevent_get_debug_info; php_phongo_handler_commandfailedevent.free_obj = php_phongo_commandfailedevent_free_object; php_phongo_handler_commandfailedevent.offset = XtOffsetOf(php_phongo_commandfailedevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/CommandFailedEvent_arginfo.h0000644000175100001660000001353514760300420021710 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 46f531ec58d18fa7f4c5910ff14e6c3f5eda9605 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getCommandName, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getDatabaseName arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getCommandName ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getDurationMicros, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getError, 0, 0, Exception, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getHost arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getCommandName #define arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getOperationId arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getCommandName #define arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getPort arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getDurationMicros ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getReply, 0, 0, IS_OBJECT, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getRequestId arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getCommandName ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getServer, 0, 0, MongoDB\\Driver\\Server, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getServiceId, 0, 0, MongoDB\\BSON\\ObjectId, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getServerConnectionId, 0, 0, IS_LONG, 1) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getCommandName); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getDatabaseName); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getDurationMicros); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getError); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getOperationId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getReply); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getRequestId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getServer); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getServiceId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandFailedEvent, getServerConnectionId); static const zend_function_entry class_MongoDB_Driver_Monitoring_CommandFailedEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getCommandName, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getCommandName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getDatabaseName, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getDatabaseName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getDurationMicros, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getDurationMicros, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getError, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getError, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getOperationId, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getOperationId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getReply, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getReply, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getRequestId, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getRequestId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getServer, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL|ZEND_ACC_DEPRECATED) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getServiceId, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getServiceId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandFailedEvent, getServerConnectionId, arginfo_class_MongoDB_Driver_Monitoring_CommandFailedEvent_getServerConnectionId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_CommandFailedEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "CommandFailedEvent", class_MongoDB_Driver_Monitoring_CommandFailedEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/CommandStartedEvent.c0000644000175100001660000001756014760300420020422 0ustar /* * Copyright 2016-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "MongoDB/Server.h" #include "CommandStartedEvent_arginfo.h" zend_class_entry* php_phongo_commandstartedevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_CommandStartedEvent) static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getCommand) { php_phongo_commandstartedevent_t* intern; php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!php_phongo_bson_to_zval_ex(intern->command, &state)) { zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getCommandName) { php_phongo_commandstartedevent_t* intern; intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->command_name); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getDatabaseName) { php_phongo_commandstartedevent_t* intern; intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->database_name); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getHost) { php_phongo_commandstartedevent_t* intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getOperationId) { php_phongo_commandstartedevent_t* intern; char operation_id[24]; intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); snprintf(operation_id, sizeof(operation_id), "%" PRId64, intern->operation_id); RETVAL_STRING(operation_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getPort) { php_phongo_commandstartedevent_t* intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getRequestId) { php_phongo_commandstartedevent_t* intern; char request_id[24]; intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); snprintf(request_id, sizeof(request_id), "%" PRId64, intern->request_id); RETVAL_STRING(request_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getServer) { php_phongo_commandstartedevent_t* intern; intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_server_init(return_value, &intern->manager, intern->server_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getServiceId) { php_phongo_commandstartedevent_t* intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!intern->has_service_id) { RETURN_NULL(); } phongo_objectid_new(return_value, &intern->service_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getServerConnectionId) { php_phongo_commandstartedevent_t* intern = Z_COMMANDSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); /* TODO: Use MONGOC_NO_SERVER_CONNECTION_ID once it is added to libmongoc's public API (CDRIVER-4176) */ if (intern->server_connection_id == -1) { RETURN_NULL(); } #if SIZEOF_ZEND_LONG == 4 if (intern->server_connection_id > INT32_MAX || intern->server_connection_id < INT32_MIN) { zend_error(E_WARNING, "Truncating 64-bit value %" PRId64 " for serverConnectionId", intern->server_connection_id); } #endif RETURN_LONG(intern->server_connection_id); } /* MongoDB\Driver\Monitoring\CommandStartedEvent object handlers */ static zend_object_handlers php_phongo_handler_commandstartedevent; static void php_phongo_commandstartedevent_free_object(zend_object* object) { php_phongo_commandstartedevent_t* intern = Z_OBJ_COMMANDSTARTEDEVENT(object); zend_object_std_dtor(&intern->std); if (!Z_ISUNDEF(intern->manager)) { zval_ptr_dtor(&intern->manager); } if (intern->command) { bson_destroy(intern->command); } if (intern->command_name) { efree(intern->command_name); } if (intern->database_name) { efree(intern->database_name); } } static zend_object* php_phongo_commandstartedevent_create_object(zend_class_entry* class_type) { php_phongo_commandstartedevent_t* intern = zend_object_alloc(sizeof(php_phongo_commandstartedevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_commandstartedevent; return &intern->std; } static HashTable* php_phongo_commandstartedevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_commandstartedevent_t* intern; zval retval = ZVAL_STATIC_INIT; char operation_id[24], request_id[24]; php_phongo_bson_state command_state; PHONGO_BSON_INIT_STATE(command_state); intern = Z_OBJ_COMMANDSTARTEDEVENT(object); *is_temp = 1; array_init_size(&retval, 10); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); ADD_ASSOC_STRING(&retval, "commandName", intern->command_name); ADD_ASSOC_STRING(&retval, "databaseName", intern->database_name); if (!php_phongo_bson_to_zval_ex(intern->command, &command_state)) { zval_ptr_dtor(&command_state.zchild); goto done; } ADD_ASSOC_ZVAL(&retval, "command", &command_state.zchild); snprintf(operation_id, sizeof(operation_id), "%" PRId64, intern->operation_id); ADD_ASSOC_STRING(&retval, "operationId", operation_id); snprintf(request_id, sizeof(request_id), "%" PRId64, intern->request_id); ADD_ASSOC_STRING(&retval, "requestId", request_id); { zval server; phongo_server_init(&server, &intern->manager, intern->server_id); ADD_ASSOC_ZVAL_EX(&retval, "server", &server); } if (intern->has_service_id) { zval service_id; if (!phongo_objectid_new(&service_id, &intern->service_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "serviceId", &service_id); } else { ADD_ASSOC_NULL_EX(&retval, "serviceId"); } /* TODO: Use MONGOC_NO_SERVER_CONNECTION_ID once it is added to libmongoc's public API (CDRIVER-4176) */ if (intern->server_connection_id == -1) { ADD_ASSOC_NULL_EX(&retval, "serverConnectionId"); } else { ADD_ASSOC_LONG_EX(&retval, "serverConnectionId", intern->server_connection_id); } done: return Z_ARRVAL(retval); } void php_phongo_commandstartedevent_init_ce(INIT_FUNC_ARGS) { php_phongo_commandstartedevent_ce = register_class_MongoDB_Driver_Monitoring_CommandStartedEvent(); php_phongo_commandstartedevent_ce->create_object = php_phongo_commandstartedevent_create_object; memcpy(&php_phongo_handler_commandstartedevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_commandstartedevent.get_debug_info = php_phongo_commandstartedevent_get_debug_info; php_phongo_handler_commandstartedevent.free_obj = php_phongo_commandstartedevent_free_object; php_phongo_handler_commandstartedevent.offset = XtOffsetOf(php_phongo_commandstartedevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/CommandStartedEvent_arginfo.h0000644000175100001660000001214214760300420022123 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: f3b8360ca99550f786be74dde8a245a544e49286 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getCommand, 0, 0, IS_OBJECT, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getCommandName, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getDatabaseName arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getCommandName #define arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getHost arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getCommandName #define arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getOperationId arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getCommandName ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getPort, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getRequestId arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getCommandName ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getServer, 0, 0, MongoDB\\Driver\\Server, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getServiceId, 0, 0, MongoDB\\BSON\\ObjectId, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getServerConnectionId, 0, 0, IS_LONG, 1) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getCommand); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getCommandName); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getDatabaseName); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getOperationId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getRequestId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getServer); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getServiceId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandStartedEvent, getServerConnectionId); static const zend_function_entry class_MongoDB_Driver_Monitoring_CommandStartedEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getCommand, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getCommandName, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getCommandName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getDatabaseName, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getDatabaseName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getOperationId, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getOperationId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getRequestId, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getRequestId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getServer, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL|ZEND_ACC_DEPRECATED) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getServiceId, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getServiceId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandStartedEvent, getServerConnectionId, arginfo_class_MongoDB_Driver_Monitoring_CommandStartedEvent_getServerConnectionId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_CommandStartedEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "CommandStartedEvent", class_MongoDB_Driver_Monitoring_CommandStartedEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/CommandSubscriber.c0000644000175100001660000000163114760300420020105 0ustar /* * Copyright 2016-present MongoDB, 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. */ #include #include "php_phongo.h" #include "CommandSubscriber_arginfo.h" zend_class_entry* php_phongo_commandsubscriber_ce; void php_phongo_commandsubscriber_init_ce(INIT_FUNC_ARGS) { php_phongo_commandsubscriber_ce = register_class_MongoDB_Driver_Monitoring_CommandSubscriber(php_phongo_subscriber_ce); } mongodb-1.21.0/src/MongoDB/Monitoring/CommandSubscriber_arginfo.h0000644000175100001660000000402614760300420021620 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 3fb67ff709c10a3a2769af8572075da08cb100b4 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSubscriber_commandStarted, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\CommandStartedEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSubscriber_commandSucceeded, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\CommandSucceededEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSubscriber_commandFailed, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\CommandFailedEvent, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_Driver_Monitoring_CommandSubscriber_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_CommandSubscriber, commandStarted, arginfo_class_MongoDB_Driver_Monitoring_CommandSubscriber_commandStarted, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_CommandSubscriber, commandSucceeded, arginfo_class_MongoDB_Driver_Monitoring_CommandSubscriber_commandSucceeded, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_CommandSubscriber, commandFailed, arginfo_class_MongoDB_Driver_Monitoring_CommandSubscriber_commandFailed, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_CommandSubscriber(zend_class_entry *class_entry_MongoDB_Driver_Monitoring_Subscriber) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "CommandSubscriber", class_MongoDB_Driver_Monitoring_CommandSubscriber_methods); class_entry = zend_register_internal_interface(&ce); zend_class_implements(class_entry, 1, class_entry_MongoDB_Driver_Monitoring_Subscriber); return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/CommandSucceededEvent.c0000644000175100001660000002034214760300420020670 0ustar /* * Copyright 2016-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "MongoDB/Server.h" #include "CommandSucceededEvent_arginfo.h" zend_class_entry* php_phongo_commandsucceededevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_CommandSucceededEvent) static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getCommandName) { php_phongo_commandsucceededevent_t* intern; intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->command_name); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getDatabaseName) { php_phongo_commandsucceededevent_t* intern; intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->database_name); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getDurationMicros) { php_phongo_commandsucceededevent_t* intern; intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->duration_micros); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getHost) { php_phongo_commandsucceededevent_t* intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getOperationId) { php_phongo_commandsucceededevent_t* intern; char operation_id[24]; intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); snprintf(operation_id, sizeof(operation_id), "%" PRId64, intern->operation_id); RETVAL_STRING(operation_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getPort) { php_phongo_commandsucceededevent_t* intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getReply) { php_phongo_commandsucceededevent_t* intern; php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!php_phongo_bson_to_zval_ex(intern->reply, &state)) { zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getRequestId) { php_phongo_commandsucceededevent_t* intern; char request_id[24]; intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); snprintf(request_id, sizeof(request_id), "%" PRId64, intern->request_id); RETVAL_STRING(request_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServer) { php_phongo_commandsucceededevent_t* intern; intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_server_init(return_value, &intern->manager, intern->server_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServiceId) { php_phongo_commandsucceededevent_t* intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!intern->has_service_id) { RETURN_NULL(); } phongo_objectid_new(return_value, &intern->service_id); } static PHP_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServerConnectionId) { php_phongo_commandsucceededevent_t* intern = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); /* TODO: Use MONGOC_NO_SERVER_CONNECTION_ID once it is added to libmongoc's public API (CDRIVER-4176) */ if (intern->server_connection_id == -1) { RETURN_NULL(); } #if SIZEOF_ZEND_LONG == 4 if (intern->server_connection_id > INT32_MAX || intern->server_connection_id < INT32_MIN) { zend_error(E_WARNING, "Truncating 64-bit value %" PRId64 " for serverConnectionId", intern->server_connection_id); } #endif RETURN_LONG(intern->server_connection_id); } /* MongoDB\Driver\Monitoring\CommandSucceededEvent object handlers */ static zend_object_handlers php_phongo_handler_commandsucceededevent; static void php_phongo_commandsucceededevent_free_object(zend_object* object) { php_phongo_commandsucceededevent_t* intern = Z_OBJ_COMMANDSUCCEEDEDEVENT(object); zend_object_std_dtor(&intern->std); if (!Z_ISUNDEF(intern->manager)) { zval_ptr_dtor(&intern->manager); } if (intern->reply) { bson_destroy(intern->reply); } if (intern->command_name) { efree(intern->command_name); } if (intern->database_name) { efree(intern->database_name); } } static zend_object* php_phongo_commandsucceededevent_create_object(zend_class_entry* class_type) { php_phongo_commandsucceededevent_t* intern = zend_object_alloc(sizeof(php_phongo_commandsucceededevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_commandsucceededevent; return &intern->std; } static HashTable* php_phongo_commandsucceededevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_commandsucceededevent_t* intern; zval retval = ZVAL_STATIC_INIT; char operation_id[24], request_id[24]; php_phongo_bson_state reply_state; PHONGO_BSON_INIT_STATE(reply_state); intern = Z_OBJ_COMMANDSUCCEEDEDEVENT(object); *is_temp = 1; array_init_size(&retval, 10); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); ADD_ASSOC_STRING(&retval, "commandName", intern->command_name); ADD_ASSOC_INT64(&retval, "durationMicros", intern->duration_micros); if (!php_phongo_bson_to_zval_ex(intern->reply, &reply_state)) { zval_ptr_dtor(&reply_state.zchild); goto done; } ADD_ASSOC_ZVAL(&retval, "reply", &reply_state.zchild); snprintf(operation_id, sizeof(operation_id), "%" PRId64, intern->operation_id); ADD_ASSOC_STRING(&retval, "operationId", operation_id); snprintf(request_id, sizeof(request_id), "%" PRId64, intern->request_id); ADD_ASSOC_STRING(&retval, "requestId", request_id); { zval server; phongo_server_init(&server, &intern->manager, intern->server_id); ADD_ASSOC_ZVAL_EX(&retval, "server", &server); } if (intern->has_service_id) { zval service_id; if (!phongo_objectid_new(&service_id, &intern->service_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "serviceId", &service_id); } else { ADD_ASSOC_NULL_EX(&retval, "serviceId"); } /* TODO: Use MONGOC_NO_SERVER_CONNECTION_ID once it is added to libmongoc's public API (CDRIVER-4176) */ if (intern->server_connection_id == -1) { ADD_ASSOC_NULL_EX(&retval, "serverConnectionId"); } else { ADD_ASSOC_LONG_EX(&retval, "serverConnectionId", intern->server_connection_id); } done: return Z_ARRVAL(retval); } void php_phongo_commandsucceededevent_init_ce(INIT_FUNC_ARGS) { php_phongo_commandsucceededevent_ce = register_class_MongoDB_Driver_Monitoring_CommandSucceededEvent(); php_phongo_commandsucceededevent_ce->create_object = php_phongo_commandsucceededevent_create_object; memcpy(&php_phongo_handler_commandsucceededevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_commandsucceededevent.get_debug_info = php_phongo_commandsucceededevent_get_debug_info; php_phongo_handler_commandsucceededevent.free_obj = php_phongo_commandsucceededevent_free_object; php_phongo_handler_commandsucceededevent.offset = XtOffsetOf(php_phongo_commandsucceededevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/CommandSucceededEvent_arginfo.h0000644000175100001660000001320114760300420022376 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: f1367c3735acf21f72b420fa4adabaf7a3098713 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getCommandName, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getDatabaseName arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getCommandName ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getDurationMicros, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getHost arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getCommandName #define arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getOperationId arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getCommandName #define arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getPort arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getDurationMicros ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getReply, 0, 0, IS_OBJECT, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getRequestId arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getCommandName ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getServer, 0, 0, MongoDB\\Driver\\Server, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getServiceId, 0, 0, MongoDB\\BSON\\ObjectId, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getServerConnectionId, 0, 0, IS_LONG, 1) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getCommandName); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getDatabaseName); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getDurationMicros); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getOperationId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getReply); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getRequestId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServer); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServiceId); static ZEND_METHOD(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServerConnectionId); static const zend_function_entry class_MongoDB_Driver_Monitoring_CommandSucceededEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getCommandName, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getCommandName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getDatabaseName, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getDatabaseName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getDurationMicros, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getDurationMicros, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getOperationId, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getOperationId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getReply, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getReply, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getRequestId, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getRequestId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServer, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL|ZEND_ACC_DEPRECATED) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServiceId, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getServiceId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_CommandSucceededEvent, getServerConnectionId, arginfo_class_MongoDB_Driver_Monitoring_CommandSucceededEvent_getServerConnectionId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_CommandSucceededEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "CommandSucceededEvent", class_MongoDB_Driver_Monitoring_CommandSucceededEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/LogSubscriber.c0000644000175100001660000000164114760300420017251 0ustar /* * Copyright 2016-present MongoDB, 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. */ #include "mongoc/mongoc.h" #include #include "php_phongo.h" #include "LogSubscriber_arginfo.h" zend_class_entry* php_phongo_logsubscriber_ce; void php_phongo_logsubscriber_init_ce(INIT_FUNC_ARGS) { php_phongo_logsubscriber_ce = register_class_MongoDB_Driver_Monitoring_LogSubscriber(php_phongo_subscriber_ce); } mongodb-1.21.0/src/MongoDB/Monitoring/LogSubscriber_arginfo.h0000644000175100001660000000716014760300420020765 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 4920ad21bd26ea586d4322d49bf44c9c3530e494 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_LogSubscriber_log, 0, 3, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, level, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, domain, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, message, IS_STRING, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_Driver_Monitoring_LogSubscriber_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_LogSubscriber, log, arginfo_class_MongoDB_Driver_Monitoring_LogSubscriber_log, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_LogSubscriber(zend_class_entry *class_entry_MongoDB_Driver_Monitoring_Subscriber) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "LogSubscriber", class_MongoDB_Driver_Monitoring_LogSubscriber_methods); class_entry = zend_register_internal_interface(&ce); zend_class_implements(class_entry, 1, class_entry_MongoDB_Driver_Monitoring_Subscriber); zval const_LEVEL_ERROR_value; ZVAL_LONG(&const_LEVEL_ERROR_value, MONGOC_LOG_LEVEL_ERROR); zend_string *const_LEVEL_ERROR_name = zend_string_init_interned("LEVEL_ERROR", sizeof("LEVEL_ERROR") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LEVEL_ERROR_name, &const_LEVEL_ERROR_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_LEVEL_ERROR_name); ZEND_ASSERT(MONGOC_LOG_LEVEL_ERROR == 0); zval const_LEVEL_CRITICAL_value; ZVAL_LONG(&const_LEVEL_CRITICAL_value, MONGOC_LOG_LEVEL_CRITICAL); zend_string *const_LEVEL_CRITICAL_name = zend_string_init_interned("LEVEL_CRITICAL", sizeof("LEVEL_CRITICAL") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LEVEL_CRITICAL_name, &const_LEVEL_CRITICAL_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_LEVEL_CRITICAL_name); ZEND_ASSERT(MONGOC_LOG_LEVEL_CRITICAL == 1); zval const_LEVEL_WARNING_value; ZVAL_LONG(&const_LEVEL_WARNING_value, MONGOC_LOG_LEVEL_WARNING); zend_string *const_LEVEL_WARNING_name = zend_string_init_interned("LEVEL_WARNING", sizeof("LEVEL_WARNING") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LEVEL_WARNING_name, &const_LEVEL_WARNING_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_LEVEL_WARNING_name); ZEND_ASSERT(MONGOC_LOG_LEVEL_WARNING == 2); zval const_LEVEL_MESSAGE_value; ZVAL_LONG(&const_LEVEL_MESSAGE_value, MONGOC_LOG_LEVEL_MESSAGE); zend_string *const_LEVEL_MESSAGE_name = zend_string_init_interned("LEVEL_MESSAGE", sizeof("LEVEL_MESSAGE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LEVEL_MESSAGE_name, &const_LEVEL_MESSAGE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_LEVEL_MESSAGE_name); ZEND_ASSERT(MONGOC_LOG_LEVEL_MESSAGE == 3); zval const_LEVEL_INFO_value; ZVAL_LONG(&const_LEVEL_INFO_value, MONGOC_LOG_LEVEL_INFO); zend_string *const_LEVEL_INFO_name = zend_string_init_interned("LEVEL_INFO", sizeof("LEVEL_INFO") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LEVEL_INFO_name, &const_LEVEL_INFO_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_LEVEL_INFO_name); ZEND_ASSERT(MONGOC_LOG_LEVEL_INFO == 4); zval const_LEVEL_DEBUG_value; ZVAL_LONG(&const_LEVEL_DEBUG_value, MONGOC_LOG_LEVEL_DEBUG); zend_string *const_LEVEL_DEBUG_name = zend_string_init_interned("LEVEL_DEBUG", sizeof("LEVEL_DEBUG") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LEVEL_DEBUG_name, &const_LEVEL_DEBUG_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_LEVEL_DEBUG_name); ZEND_ASSERT(MONGOC_LOG_LEVEL_DEBUG == 5); return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/SDAMSubscriber.c0000644000175100001660000000161214760300420017252 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include #include "php_phongo.h" #include "SDAMSubscriber_arginfo.h" zend_class_entry* php_phongo_sdamsubscriber_ce; void php_phongo_sdamsubscriber_init_ce(INIT_FUNC_ARGS) { php_phongo_sdamsubscriber_ce = register_class_MongoDB_Driver_Monitoring_SDAMSubscriber(php_phongo_subscriber_ce); } mongodb-1.21.0/src/MongoDB/Monitoring/SDAMSubscriber_arginfo.h0000644000175100001660000001117114760300420020765 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 19ae065e2a8ad6c8f4945262d6cf58ea723e5aed */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverChanged, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\ServerChangedEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverClosed, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\ServerClosedEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverOpening, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\ServerOpeningEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverHeartbeatFailed, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\ServerHeartbeatFailedEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverHeartbeatStarted, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\ServerHeartbeatStartedEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverHeartbeatSucceeded, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\ServerHeartbeatSucceededEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_topologyChanged, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\TopologyChangedEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_topologyClosed, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\TopologyClosedEvent, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_topologyOpening, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, event, MongoDB\\Driver\\Monitoring\\TopologyOpeningEvent, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_Driver_Monitoring_SDAMSubscriber_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, serverChanged, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverChanged, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, serverClosed, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverClosed, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, serverOpening, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverOpening, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, serverHeartbeatFailed, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverHeartbeatFailed, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, serverHeartbeatStarted, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverHeartbeatStarted, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, serverHeartbeatSucceeded, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_serverHeartbeatSucceeded, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, topologyChanged, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_topologyChanged, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, topologyClosed, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_topologyClosed, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_Monitoring_SDAMSubscriber, topologyOpening, arginfo_class_MongoDB_Driver_Monitoring_SDAMSubscriber_topologyOpening, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_SDAMSubscriber(zend_class_entry *class_entry_MongoDB_Driver_Monitoring_Subscriber) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "SDAMSubscriber", class_MongoDB_Driver_Monitoring_SDAMSubscriber_methods); class_entry = zend_register_internal_interface(&ce); zend_class_implements(class_entry, 1, class_entry_MongoDB_Driver_Monitoring_Subscriber); return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/ServerChangedEvent.c0000644000175100001660000001175614760300420020236 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "mongoc/mongoc.h" #include #include #include "php_phongo.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "MongoDB/Server.h" #include "MongoDB/ServerDescription.h" #include "ServerChangedEvent_arginfo.h" zend_class_entry* php_phongo_serverchangedevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_ServerChangedEvent) /* Returns this event's host */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getHost) { php_phongo_serverchangedevent_t* intern = Z_SERVERCHANGEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } /* Returns this event's port */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getPort) { php_phongo_serverchangedevent_t* intern = Z_SERVERCHANGEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } /* Returns this event's new description */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getNewDescription) { php_phongo_serverchangedevent_t* intern = Z_SERVERCHANGEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_serverdescription_init(return_value, intern->new_server_description); } /* Returns this event's previous description */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getPreviousDescription) { php_phongo_serverchangedevent_t* intern = Z_SERVERCHANGEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_serverdescription_init(return_value, intern->old_server_description); } /* Returns this event's topology id */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getTopologyId) { php_phongo_serverchangedevent_t* intern = Z_SERVERCHANGEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_objectid_new(return_value, &intern->topology_id); } /* MongoDB\Driver\Monitoring\ServerChangedEvent object handlers */ static zend_object_handlers php_phongo_handler_serverchangedevent; static void php_phongo_serverchangedevent_free_object(zend_object* object) { php_phongo_serverchangedevent_t* intern = Z_OBJ_SERVERCHANGEDEVENT(object); zend_object_std_dtor(&intern->std); if (intern->new_server_description) { mongoc_server_description_destroy(intern->new_server_description); } if (intern->old_server_description) { mongoc_server_description_destroy(intern->old_server_description); } } static zend_object* php_phongo_serverchangedevent_create_object(zend_class_entry* class_type) { php_phongo_serverchangedevent_t* intern = zend_object_alloc(sizeof(php_phongo_serverchangedevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_serverchangedevent; return &intern->std; } static HashTable* php_phongo_serverchangedevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_serverchangedevent_t* intern; zval retval = ZVAL_STATIC_INIT; intern = Z_OBJ_SERVERCHANGEDEVENT(object); *is_temp = 1; array_init_size(&retval, 4); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); { zval topology_id; if (!phongo_objectid_new(&topology_id, &intern->topology_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "topologyId", &topology_id); } { zval new_sd; phongo_serverdescription_init(&new_sd, intern->new_server_description); ADD_ASSOC_ZVAL_EX(&retval, "newDescription", &new_sd); } { zval old_sd; phongo_serverdescription_init(&old_sd, intern->old_server_description); ADD_ASSOC_ZVAL_EX(&retval, "oldDescription", &old_sd); } done: return Z_ARRVAL(retval); } void php_phongo_serverchangedevent_init_ce(INIT_FUNC_ARGS) { php_phongo_serverchangedevent_ce = register_class_MongoDB_Driver_Monitoring_ServerChangedEvent(); php_phongo_serverchangedevent_ce->create_object = php_phongo_serverchangedevent_create_object; memcpy(&php_phongo_handler_serverchangedevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_serverchangedevent.get_debug_info = php_phongo_serverchangedevent_get_debug_info; php_phongo_handler_serverchangedevent.free_obj = php_phongo_serverchangedevent_free_object; php_phongo_handler_serverchangedevent.offset = XtOffsetOf(php_phongo_serverchangedevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/ServerChangedEvent_arginfo.h0000644000175100001660000000610314760300420021736 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: d681e2e9936f0846fe8ee7fa6eb25bb218d85902 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getPort, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getHost, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getNewDescription, 0, 0, MongoDB\\Driver\\ServerDescription, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getPreviousDescription arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getNewDescription ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getTopologyId, 0, 0, MongoDB\\BSON\\ObjectId, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getNewDescription); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getPreviousDescription); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerChangedEvent, getTopologyId); static const zend_function_entry class_MongoDB_Driver_Monitoring_ServerChangedEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_ServerChangedEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerChangedEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerChangedEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerChangedEvent, getNewDescription, arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getNewDescription, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerChangedEvent, getPreviousDescription, arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getPreviousDescription, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerChangedEvent, getTopologyId, arginfo_class_MongoDB_Driver_Monitoring_ServerChangedEvent_getTopologyId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_ServerChangedEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "ServerChangedEvent", class_MongoDB_Driver_Monitoring_ServerChangedEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/ServerClosedEvent.c0000644000175100001660000000730214760300420020106 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "ServerClosedEvent_arginfo.h" zend_class_entry* php_phongo_serverclosedevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_ServerClosedEvent) /* Returns this event's host */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerClosedEvent, getHost) { php_phongo_serverclosedevent_t* intern = Z_SERVERCLOSEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } /* Returns this event's port */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerClosedEvent, getPort) { php_phongo_serverclosedevent_t* intern = Z_SERVERCLOSEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } /* Returns this event's topology id */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerClosedEvent, getTopologyId) { php_phongo_serverclosedevent_t* intern = Z_SERVERCLOSEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_objectid_new(return_value, &intern->topology_id); } /* MongoDB\Driver\Monitoring\ServerClosedEvent object handlers */ static zend_object_handlers php_phongo_handler_serverclosedevent; static void php_phongo_serverclosedevent_free_object(zend_object* object) { php_phongo_serverclosedevent_t* intern = Z_OBJ_SERVERCLOSEDEVENT(object); zend_object_std_dtor(&intern->std); } static zend_object* php_phongo_serverclosedevent_create_object(zend_class_entry* class_type) { php_phongo_serverclosedevent_t* intern = zend_object_alloc(sizeof(php_phongo_serverclosedevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_serverclosedevent; return &intern->std; } static HashTable* php_phongo_serverclosedevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_serverclosedevent_t* intern; zval retval = ZVAL_STATIC_INIT; intern = Z_OBJ_SERVERCLOSEDEVENT(object); *is_temp = 1; array_init_size(&retval, 3); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); { zval topology_id; if (!phongo_objectid_new(&topology_id, &intern->topology_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "topologyId", &topology_id); } done: return Z_ARRVAL(retval); } void php_phongo_serverclosedevent_init_ce(INIT_FUNC_ARGS) { php_phongo_serverclosedevent_ce = register_class_MongoDB_Driver_Monitoring_ServerClosedEvent(); php_phongo_serverclosedevent_ce->create_object = php_phongo_serverclosedevent_create_object; memcpy(&php_phongo_handler_serverclosedevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_serverclosedevent.get_debug_info = php_phongo_serverclosedevent_get_debug_info; php_phongo_handler_serverclosedevent.free_obj = php_phongo_serverclosedevent_free_object; php_phongo_handler_serverclosedevent.offset = XtOffsetOf(php_phongo_serverclosedevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/ServerClosedEvent_arginfo.h0000644000175100001660000000424714760300420021625 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 05a48b4966fb49c82a6ef48b360a93fdc2919f77 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerClosedEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerClosedEvent_getPort, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerClosedEvent_getHost, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerClosedEvent_getTopologyId, 0, 0, MongoDB\\BSON\\ObjectId, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerClosedEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerClosedEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerClosedEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerClosedEvent, getTopologyId); static const zend_function_entry class_MongoDB_Driver_Monitoring_ServerClosedEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_ServerClosedEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_ServerClosedEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerClosedEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_ServerClosedEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerClosedEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_ServerClosedEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerClosedEvent, getTopologyId, arginfo_class_MongoDB_Driver_Monitoring_ServerClosedEvent_getTopologyId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_ServerClosedEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "ServerClosedEvent", class_MongoDB_Driver_Monitoring_ServerClosedEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/ServerHeartbeatFailedEvent.c0000644000175100001660000001123214760300420021676 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "phongo_error.h" #include "ServerHeartbeatFailedEvent_arginfo.h" zend_class_entry* php_phongo_serverheartbeatfailedevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent) /* Returns this event's duration in microseconds */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getDurationMicros) { php_phongo_serverheartbeatfailedevent_t* intern = Z_SERVERHEARTBEATFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->duration_micros); } /* Returns the error associated with the event */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getError) { php_phongo_serverheartbeatfailedevent_t* intern = Z_SERVERHEARTBEATFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ZVAL(&intern->z_error, 1, 0); } /* Returns this event's host */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getHost) { php_phongo_serverheartbeatfailedevent_t* intern = Z_SERVERHEARTBEATFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } /* Returns this event's port */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getPort) { php_phongo_serverheartbeatfailedevent_t* intern = Z_SERVERHEARTBEATFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } /* Returns whether this event came from an awaitable hello */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, isAwaited) { php_phongo_serverheartbeatfailedevent_t* intern = Z_SERVERHEARTBEATFAILEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_BOOL(intern->awaited); } /* MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent object handlers */ static zend_object_handlers php_phongo_handler_serverheartbeatfailedevent; static void php_phongo_serverheartbeatfailedevent_free_object(zend_object* object) { php_phongo_serverheartbeatfailedevent_t* intern = Z_OBJ_SERVERHEARTBEATFAILEDEVENT(object); zend_object_std_dtor(&intern->std); if (!Z_ISUNDEF(intern->z_error)) { zval_ptr_dtor(&intern->z_error); } } static zend_object* php_phongo_serverheartbeatfailedevent_create_object(zend_class_entry* class_type) { php_phongo_serverheartbeatfailedevent_t* intern = zend_object_alloc(sizeof(php_phongo_serverheartbeatfailedevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_serverheartbeatfailedevent; return &intern->std; } static HashTable* php_phongo_serverheartbeatfailedevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_serverheartbeatfailedevent_t* intern; zval retval = ZVAL_STATIC_INIT; intern = Z_OBJ_SERVERHEARTBEATFAILEDEVENT(object); *is_temp = 1; array_init_size(&retval, 5); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); ADD_ASSOC_BOOL_EX(&retval, "awaited", intern->awaited); ADD_ASSOC_INT64(&retval, "durationMicros", intern->duration_micros); ADD_ASSOC_ZVAL_EX(&retval, "error", &intern->z_error); Z_ADDREF(intern->z_error); return Z_ARRVAL(retval); } void php_phongo_serverheartbeatfailedevent_init_ce(INIT_FUNC_ARGS) { php_phongo_serverheartbeatfailedevent_ce = register_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent(); php_phongo_serverheartbeatfailedevent_ce->create_object = php_phongo_serverheartbeatfailedevent_create_object; memcpy(&php_phongo_handler_serverheartbeatfailedevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_serverheartbeatfailedevent.get_debug_info = php_phongo_serverheartbeatfailedevent_get_debug_info; php_phongo_handler_serverheartbeatfailedevent.free_obj = php_phongo_serverheartbeatfailedevent_free_object; php_phongo_handler_serverheartbeatfailedevent.offset = XtOffsetOf(php_phongo_serverheartbeatfailedevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/ServerHeartbeatFailedEvent_arginfo.h0000644000175100001660000000627414760300420023422 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: ba0a81f27f99579e332ef8d3a3a477b3ebe1ec31 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getDurationMicros, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getError, 0, 0, Exception, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getPort arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getDurationMicros ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getHost, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_isAwaited, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getDurationMicros); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getError); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, isAwaited); static const zend_function_entry class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getDurationMicros, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getDurationMicros, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getError, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getError, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent, isAwaited, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_isAwaited, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "ServerHeartbeatFailedEvent", class_MongoDB_Driver_Monitoring_ServerHeartbeatFailedEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/ServerHeartbeatStartedEvent.c0000644000175100001660000000755714760300420022137 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "phongo_error.h" #include "ServerHeartbeatStartedEvent_arginfo.h" zend_class_entry* php_phongo_serverheartbeatstartedevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent) /* Returns this event's host */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, getHost) { php_phongo_serverheartbeatstartedevent_t* intern = Z_SERVERHEARTBEATSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } /* Returns this event's port */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, getPort) { php_phongo_serverheartbeatstartedevent_t* intern = Z_SERVERHEARTBEATSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } /* Returns whether this event came from an awaitable hello */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, isAwaited) { php_phongo_serverheartbeatstartedevent_t* intern = Z_SERVERHEARTBEATSTARTEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_BOOL(intern->awaited); } /* MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent object handlers */ static zend_object_handlers php_phongo_handler_serverheartbeatstartedevent; static void php_phongo_serverheartbeatstartedevent_free_object(zend_object* object) { php_phongo_serverheartbeatstartedevent_t* intern = Z_OBJ_SERVERHEARTBEATSTARTEDEVENT(object); zend_object_std_dtor(&intern->std); } static zend_object* php_phongo_serverheartbeatstartedevent_create_object(zend_class_entry* class_type) { php_phongo_serverheartbeatstartedevent_t* intern = zend_object_alloc(sizeof(php_phongo_serverheartbeatstartedevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_serverheartbeatstartedevent; return &intern->std; } static HashTable* php_phongo_serverheartbeatstartedevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_serverheartbeatstartedevent_t* intern; zval retval = ZVAL_STATIC_INIT; intern = Z_OBJ_SERVERHEARTBEATSTARTEDEVENT(object); *is_temp = 1; array_init_size(&retval, 4); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); ADD_ASSOC_BOOL_EX(&retval, "awaited", intern->awaited); return Z_ARRVAL(retval); } void php_phongo_serverheartbeatstartedevent_init_ce(INIT_FUNC_ARGS) { php_phongo_serverheartbeatstartedevent_ce = register_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent(); php_phongo_serverheartbeatstartedevent_ce->create_object = php_phongo_serverheartbeatstartedevent_create_object; memcpy(&php_phongo_handler_serverheartbeatstartedevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_serverheartbeatstartedevent.get_debug_info = php_phongo_serverheartbeatstartedevent_get_debug_info; php_phongo_handler_serverheartbeatstartedevent.free_obj = php_phongo_serverheartbeatstartedevent_free_object; php_phongo_handler_serverheartbeatstartedevent.offset = XtOffsetOf(php_phongo_serverheartbeatstartedevent_t, std); return; } mongodb-1.21.0/src/MongoDB/Monitoring/ServerHeartbeatStartedEvent_arginfo.h0000644000175100001660000000452114760300420023635 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 7cb420cf908d682f770a9dbc20473e075af9ce53 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent_getPort, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent_getHost, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent_isAwaited, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, isAwaited); static const zend_function_entry class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent, isAwaited, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent_isAwaited, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "ServerHeartbeatStartedEvent", class_MongoDB_Driver_Monitoring_ServerHeartbeatStartedEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/ServerHeartbeatSucceededEvent.c0000644000175100001660000001220014760300420022372 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "phongo_error.h" #include "ServerHeartbeatSucceededEvent_arginfo.h" zend_class_entry* php_phongo_serverheartbeatsucceededevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent) /* Returns this event's duration in microseconds */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getDurationMicros) { php_phongo_serverheartbeatsucceededevent_t* intern = Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->duration_micros); } /* Returns this event's host */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getHost) { php_phongo_serverheartbeatsucceededevent_t* intern = Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } /* Returns this event's port */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getPort) { php_phongo_serverheartbeatsucceededevent_t* intern = Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } /* Returns this event's reply */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getReply) { php_phongo_serverheartbeatsucceededevent_t* intern = Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(getThis()); php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); PHONGO_PARSE_PARAMETERS_NONE(); if (!php_phongo_bson_to_zval_ex(intern->reply, &state)) { zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } /* Returns whether this event came from an awaitable hello */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, isAwaited) { php_phongo_serverheartbeatsucceededevent_t* intern = Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_BOOL(intern->awaited); } /* MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent object handlers */ static zend_object_handlers php_phongo_handler_serverheartbeatsucceededevent; static void php_phongo_serverheartbeatsucceededevent_free_object(zend_object* object) { php_phongo_serverheartbeatsucceededevent_t* intern = Z_OBJ_SERVERHEARTBEATSUCCEEDEDEVENT(object); zend_object_std_dtor(&intern->std); if (intern->reply) { bson_destroy(intern->reply); } } static zend_object* php_phongo_serverheartbeatsucceededevent_create_object(zend_class_entry* class_type) { php_phongo_serverheartbeatsucceededevent_t* intern = zend_object_alloc(sizeof(php_phongo_serverheartbeatsucceededevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_serverheartbeatsucceededevent; return &intern->std; } static HashTable* php_phongo_serverheartbeatsucceededevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_serverheartbeatsucceededevent_t* intern; zval retval = ZVAL_STATIC_INIT; php_phongo_bson_state reply_state; PHONGO_BSON_INIT_STATE(reply_state); intern = Z_OBJ_SERVERHEARTBEATSUCCEEDEDEVENT(object); *is_temp = 1; array_init_size(&retval, 4); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); ADD_ASSOC_BOOL_EX(&retval, "awaited", intern->awaited); ADD_ASSOC_INT64(&retval, "durationMicros", intern->duration_micros); if (!php_phongo_bson_to_zval_ex(intern->reply, &reply_state)) { zval_ptr_dtor(&reply_state.zchild); goto done; } ADD_ASSOC_ZVAL(&retval, "reply", &reply_state.zchild); done: return Z_ARRVAL(retval); } void php_phongo_serverheartbeatsucceededevent_init_ce(INIT_FUNC_ARGS) { php_phongo_serverheartbeatsucceededevent_ce = register_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent(); php_phongo_serverheartbeatsucceededevent_ce->create_object = php_phongo_serverheartbeatsucceededevent_create_object; memcpy(&php_phongo_handler_serverheartbeatsucceededevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_serverheartbeatsucceededevent.get_debug_info = php_phongo_serverheartbeatsucceededevent_get_debug_info; php_phongo_handler_serverheartbeatsucceededevent.free_obj = php_phongo_serverheartbeatsucceededevent_free_object; php_phongo_handler_serverheartbeatsucceededevent.offset = XtOffsetOf(php_phongo_serverheartbeatsucceededevent_t, std); return; } mongodb-1.21.0/src/MongoDB/Monitoring/ServerHeartbeatSucceededEvent_arginfo.h0000644000175100001660000000642414760300420024117 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: dce5c76853a5c0a532be89796806527d37d018a1 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getDurationMicros, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getReply, 0, 0, IS_OBJECT, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getPort arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getDurationMicros ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getHost, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_isAwaited, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getDurationMicros); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getReply); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, isAwaited); static const zend_function_entry class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getDurationMicros, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getDurationMicros, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getReply, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getReply, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent, isAwaited, arginfo_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_isAwaited, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "ServerHeartbeatSucceededEvent", class_MongoDB_Driver_Monitoring_ServerHeartbeatSucceededEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/ServerOpeningEvent.c0000644000175100001660000000734714760300420020305 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "ServerOpeningEvent_arginfo.h" zend_class_entry* php_phongo_serveropeningevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_ServerOpeningEvent) /* Returns this event's host */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerOpeningEvent, getHost) { php_phongo_serveropeningevent_t* intern = Z_SERVEROPENINGEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(intern->host.host); } /* Returns this event's port */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerOpeningEvent, getPort) { php_phongo_serveropeningevent_t* intern = Z_SERVEROPENINGEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(intern->host.port); } /* Returns this event's topology id */ static PHP_METHOD(MongoDB_Driver_Monitoring_ServerOpeningEvent, getTopologyId) { php_phongo_serveropeningevent_t* intern = Z_SERVEROPENINGEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_objectid_new(return_value, &intern->topology_id); } /* MongoDB\Driver\Monitoring\ServerOpeningEvent object handlers */ static zend_object_handlers php_phongo_handler_serveropeningevent; static void php_phongo_serveropeningevent_free_object(zend_object* object) { php_phongo_serveropeningevent_t* intern = Z_OBJ_SERVEROPENINGEVENT(object); zend_object_std_dtor(&intern->std); } static zend_object* php_phongo_serveropeningevent_create_object(zend_class_entry* class_type) { php_phongo_serveropeningevent_t* intern = zend_object_alloc(sizeof(php_phongo_serveropeningevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_serveropeningevent; return &intern->std; } static HashTable* php_phongo_serveropeningevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_serveropeningevent_t* intern; zval retval = ZVAL_STATIC_INIT; intern = Z_OBJ_SERVEROPENINGEVENT(object); *is_temp = 1; array_init_size(&retval, 3); ADD_ASSOC_STRING(&retval, "host", intern->host.host); ADD_ASSOC_LONG_EX(&retval, "port", intern->host.port); { zval topology_id; if (!phongo_objectid_new(&topology_id, &intern->topology_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "topologyId", &topology_id); } done: return Z_ARRVAL(retval); } void php_phongo_serveropeningevent_init_ce(INIT_FUNC_ARGS) { php_phongo_serveropeningevent_ce = register_class_MongoDB_Driver_Monitoring_ServerOpeningEvent(); php_phongo_serveropeningevent_ce->create_object = php_phongo_serveropeningevent_create_object; memcpy(&php_phongo_handler_serveropeningevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_serveropeningevent.get_debug_info = php_phongo_serveropeningevent_get_debug_info; php_phongo_handler_serveropeningevent.free_obj = php_phongo_serveropeningevent_free_object; php_phongo_handler_serveropeningevent.offset = XtOffsetOf(php_phongo_serveropeningevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/ServerOpeningEvent_arginfo.h0000644000175100001660000000427314760300420022012 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 017f3508070fe14083d8839f97ad0d6788470639 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerOpeningEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerOpeningEvent_getPort, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerOpeningEvent_getHost, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_ServerOpeningEvent_getTopologyId, 0, 0, MongoDB\\BSON\\ObjectId, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerOpeningEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerOpeningEvent, getPort); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerOpeningEvent, getHost); static ZEND_METHOD(MongoDB_Driver_Monitoring_ServerOpeningEvent, getTopologyId); static const zend_function_entry class_MongoDB_Driver_Monitoring_ServerOpeningEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_ServerOpeningEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_ServerOpeningEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerOpeningEvent, getPort, arginfo_class_MongoDB_Driver_Monitoring_ServerOpeningEvent_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerOpeningEvent, getHost, arginfo_class_MongoDB_Driver_Monitoring_ServerOpeningEvent_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_ServerOpeningEvent, getTopologyId, arginfo_class_MongoDB_Driver_Monitoring_ServerOpeningEvent_getTopologyId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_ServerOpeningEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "ServerOpeningEvent", class_MongoDB_Driver_Monitoring_ServerOpeningEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/Subscriber.c0000644000175100001660000000153614760300420016612 0ustar /* * Copyright 2016-present MongoDB, 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. */ #include #include "php_phongo.h" #include "Subscriber_arginfo.h" zend_class_entry* php_phongo_subscriber_ce; void php_phongo_subscriber_init_ce(INIT_FUNC_ARGS) { php_phongo_subscriber_ce = register_class_MongoDB_Driver_Monitoring_Subscriber(); } mongodb-1.21.0/src/MongoDB/Monitoring/Subscriber_arginfo.h0000644000175100001660000000105214760300420020315 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: f2e7d8f61aa5359716d9c2186c24ba68db5e96b4 */ static const zend_function_entry class_MongoDB_Driver_Monitoring_Subscriber_methods[] = { ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_Subscriber(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "Subscriber", class_MongoDB_Driver_Monitoring_Subscriber_methods); class_entry = zend_register_internal_interface(&ce); return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/TopologyChangedEvent.c0000644000175100001660000001070014760300420020570 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "mongoc/mongoc.h" #include #include #include "php_phongo.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "MongoDB/TopologyDescription.h" #include "TopologyChangedEvent_arginfo.h" zend_class_entry* php_phongo_topologychangedevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_TopologyChangedEvent) /* Returns this event's new description */ static PHP_METHOD(MongoDB_Driver_Monitoring_TopologyChangedEvent, getNewDescription) { php_phongo_topologychangedevent_t* intern = Z_TOPOLOGYCHANGEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_topologydescription_init(return_value, intern->new_topology_description); } /* Returns this event's previous description */ static PHP_METHOD(MongoDB_Driver_Monitoring_TopologyChangedEvent, getPreviousDescription) { php_phongo_topologychangedevent_t* intern = Z_TOPOLOGYCHANGEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_topologydescription_init(return_value, intern->old_topology_description); } /* Returns this event's topology id */ static PHP_METHOD(MongoDB_Driver_Monitoring_TopologyChangedEvent, getTopologyId) { php_phongo_topologychangedevent_t* intern = Z_TOPOLOGYCHANGEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_objectid_new(return_value, &intern->topology_id); } /* MongoDB\Driver\Monitoring\TopologyChangedEvent object handlers */ static zend_object_handlers php_phongo_handler_topologychangedevent; static void php_phongo_topologychangedevent_free_object(zend_object* object) { php_phongo_topologychangedevent_t* intern = Z_OBJ_TOPOLOGYCHANGEDEVENT(object); zend_object_std_dtor(&intern->std); if (intern->new_topology_description) { mongoc_topology_description_destroy(intern->new_topology_description); } if (intern->old_topology_description) { mongoc_topology_description_destroy(intern->old_topology_description); } } static zend_object* php_phongo_topologychangedevent_create_object(zend_class_entry* class_type) { php_phongo_topologychangedevent_t* intern = zend_object_alloc(sizeof(php_phongo_topologychangedevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_topologychangedevent; return &intern->std; } static HashTable* php_phongo_topologychangedevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_topologychangedevent_t* intern; zval retval = ZVAL_STATIC_INIT; intern = Z_OBJ_TOPOLOGYCHANGEDEVENT(object); *is_temp = 1; array_init_size(&retval, 3); { zval topology_id; if (!phongo_objectid_new(&topology_id, &intern->topology_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "topologyId", &topology_id); } { zval new_td; phongo_topologydescription_init(&new_td, intern->new_topology_description); ADD_ASSOC_ZVAL_EX(&retval, "newDescription", &new_td); } { zval old_td; phongo_topologydescription_init(&old_td, intern->old_topology_description); ADD_ASSOC_ZVAL_EX(&retval, "oldDescription", &old_td); } done: return Z_ARRVAL(retval); } void php_phongo_topologychangedevent_init_ce(INIT_FUNC_ARGS) { php_phongo_topologychangedevent_ce = register_class_MongoDB_Driver_Monitoring_TopologyChangedEvent(); php_phongo_topologychangedevent_ce->create_object = php_phongo_topologychangedevent_create_object; memcpy(&php_phongo_handler_topologychangedevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_topologychangedevent.get_debug_info = php_phongo_topologychangedevent_get_debug_info; php_phongo_handler_topologychangedevent.free_obj = php_phongo_topologychangedevent_free_object; php_phongo_handler_topologychangedevent.offset = XtOffsetOf(php_phongo_topologychangedevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/TopologyChangedEvent_arginfo.h0000644000175100001660000000455114760300420022311 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 20071882771d0743a38efc1d7d7d19659cfb637b */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent_getNewDescription, 0, 0, MongoDB\\Driver\\TopologyDescription, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent_getPreviousDescription arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent_getNewDescription ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent_getTopologyId, 0, 0, MongoDB\\BSON\\ObjectId, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_TopologyChangedEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_TopologyChangedEvent, getNewDescription); static ZEND_METHOD(MongoDB_Driver_Monitoring_TopologyChangedEvent, getPreviousDescription); static ZEND_METHOD(MongoDB_Driver_Monitoring_TopologyChangedEvent, getTopologyId); static const zend_function_entry class_MongoDB_Driver_Monitoring_TopologyChangedEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_TopologyChangedEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_TopologyChangedEvent, getNewDescription, arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent_getNewDescription, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_TopologyChangedEvent, getPreviousDescription, arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent_getPreviousDescription, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_TopologyChangedEvent, getTopologyId, arginfo_class_MongoDB_Driver_Monitoring_TopologyChangedEvent_getTopologyId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_TopologyChangedEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "TopologyChangedEvent", class_MongoDB_Driver_Monitoring_TopologyChangedEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/TopologyClosedEvent.c0000644000175100001660000000621414760300420020455 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "TopologyClosedEvent_arginfo.h" zend_class_entry* php_phongo_topologyclosedevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_TopologyClosedEvent) /* Returns this event's topology id */ static PHP_METHOD(MongoDB_Driver_Monitoring_TopologyClosedEvent, getTopologyId) { php_phongo_topologyclosedevent_t* intern = Z_TOPOLOGYCLOSEDEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_objectid_new(return_value, &intern->topology_id); } /* MongoDB\Driver\Monitoring\TopologyClosedEvent object handlers */ static zend_object_handlers php_phongo_handler_topologyclosedevent; static void php_phongo_topologyclosedevent_free_object(zend_object* object) { php_phongo_topologyclosedevent_t* intern = Z_OBJ_TOPOLOGYCLOSEDEVENT(object); zend_object_std_dtor(&intern->std); } static zend_object* php_phongo_topologyclosedevent_create_object(zend_class_entry* class_type) { php_phongo_topologyclosedevent_t* intern = zend_object_alloc(sizeof(php_phongo_topologyclosedevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_topologyclosedevent; return &intern->std; } static HashTable* php_phongo_topologyclosedevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_topologyclosedevent_t* intern; zval retval = ZVAL_STATIC_INIT; intern = Z_OBJ_TOPOLOGYCLOSEDEVENT(object); *is_temp = 1; array_init_size(&retval, 1); { zval topology_id; if (!phongo_objectid_new(&topology_id, &intern->topology_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "topologyId", &topology_id); } done: return Z_ARRVAL(retval); } void php_phongo_topologyclosedevent_init_ce(INIT_FUNC_ARGS) { php_phongo_topologyclosedevent_ce = register_class_MongoDB_Driver_Monitoring_TopologyClosedEvent(); php_phongo_topologyclosedevent_ce->create_object = php_phongo_topologyclosedevent_create_object; memcpy(&php_phongo_handler_topologyclosedevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_topologyclosedevent.get_debug_info = php_phongo_topologyclosedevent_get_debug_info; php_phongo_handler_topologyclosedevent.free_obj = php_phongo_topologyclosedevent_free_object; php_phongo_handler_topologyclosedevent.offset = XtOffsetOf(php_phongo_topologyclosedevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/TopologyClosedEvent_arginfo.h0000644000175100001660000000270114760300420022164 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: c636ee276d6ebc18186a6ef4b8f67c48f5b4c29c */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_TopologyClosedEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_TopologyClosedEvent_getTopologyId, 0, 0, MongoDB\\BSON\\ObjectId, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_TopologyClosedEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_TopologyClosedEvent, getTopologyId); static const zend_function_entry class_MongoDB_Driver_Monitoring_TopologyClosedEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_TopologyClosedEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_TopologyClosedEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_TopologyClosedEvent, getTopologyId, arginfo_class_MongoDB_Driver_Monitoring_TopologyClosedEvent_getTopologyId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_TopologyClosedEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "TopologyClosedEvent", class_MongoDB_Driver_Monitoring_TopologyClosedEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/TopologyOpeningEvent.c0000644000175100001660000000625314760300420020646 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "phongo_error.h" #include "BSON/ObjectId.h" #include "TopologyOpeningEvent_arginfo.h" zend_class_entry* php_phongo_topologyopeningevent_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Monitoring_TopologyOpeningEvent) /* Returns this event's topology id */ static PHP_METHOD(MongoDB_Driver_Monitoring_TopologyOpeningEvent, getTopologyId) { php_phongo_topologyopeningevent_t* intern = Z_TOPOLOGYOPENINGEVENT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_objectid_new(return_value, &intern->topology_id); } /* MongoDB\Driver\Monitoring\TopologyOpeningEvent object handlers */ static zend_object_handlers php_phongo_handler_topologyopeningevent; static void php_phongo_topologyopeningevent_free_object(zend_object* object) { php_phongo_topologyopeningevent_t* intern = Z_OBJ_TOPOLOGYOPENINGEVENT(object); zend_object_std_dtor(&intern->std); } static zend_object* php_phongo_topologyopeningevent_create_object(zend_class_entry* class_type) { php_phongo_topologyopeningevent_t* intern = zend_object_alloc(sizeof(php_phongo_topologyopeningevent_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_topologyopeningevent; return &intern->std; } static HashTable* php_phongo_topologyopeningevent_get_debug_info(zend_object* object, int* is_temp) { php_phongo_topologyopeningevent_t* intern; zval retval = ZVAL_STATIC_INIT; intern = Z_OBJ_TOPOLOGYOPENINGEVENT(object); *is_temp = 1; array_init_size(&retval, 1); { zval topology_id; if (!phongo_objectid_new(&topology_id, &intern->topology_id)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "topologyId", &topology_id); } done: return Z_ARRVAL(retval); } void php_phongo_topologyopeningevent_init_ce(INIT_FUNC_ARGS) { php_phongo_topologyopeningevent_ce = register_class_MongoDB_Driver_Monitoring_TopologyOpeningEvent(); php_phongo_topologyopeningevent_ce->create_object = php_phongo_topologyopeningevent_create_object; memcpy(&php_phongo_handler_topologyopeningevent, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_topologyopeningevent.get_debug_info = php_phongo_topologyopeningevent_get_debug_info; php_phongo_handler_topologyopeningevent.free_obj = php_phongo_topologyopeningevent_free_object; php_phongo_handler_topologyopeningevent.offset = XtOffsetOf(php_phongo_topologyopeningevent_t, std); } mongodb-1.21.0/src/MongoDB/Monitoring/TopologyOpeningEvent_arginfo.h0000644000175100001660000000271514760300420022357 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 6ab1a9ad8b25b5d09ce12c1b0fa0e69885432d6f */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_TopologyOpeningEvent___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Monitoring_TopologyOpeningEvent_getTopologyId, 0, 0, MongoDB\\BSON\\ObjectId, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Monitoring_TopologyOpeningEvent, __construct); static ZEND_METHOD(MongoDB_Driver_Monitoring_TopologyOpeningEvent, getTopologyId); static const zend_function_entry class_MongoDB_Driver_Monitoring_TopologyOpeningEvent_methods[] = { ZEND_ME(MongoDB_Driver_Monitoring_TopologyOpeningEvent, __construct, arginfo_class_MongoDB_Driver_Monitoring_TopologyOpeningEvent___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Monitoring_TopologyOpeningEvent, getTopologyId, arginfo_class_MongoDB_Driver_Monitoring_TopologyOpeningEvent_getTopologyId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Monitoring_TopologyOpeningEvent(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver\\Monitoring", "TopologyOpeningEvent", class_MongoDB_Driver_Monitoring_TopologyOpeningEvent_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Monitoring/functions.c0000644000175100001660000000606714760300420016523 0ustar /* * Copyright 2016-present MongoDB, 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. */ #include "mongoc/mongoc.h" #include #include "php_phongo.h" #include "phongo_apm.h" #include "phongo_error.h" #include "phongo_log.h" ZEND_EXTERN_MODULE_GLOBALS(mongodb) #define IS_APM_SUBSCRIBER(zv) \ instanceof_function(Z_OBJCE_P(zv), php_phongo_commandsubscriber_ce) || \ instanceof_function(Z_OBJCE_P(zv), php_phongo_sdamsubscriber_ce) #define IS_LOG_SUBSCRIBER(zv) instanceof_function(Z_OBJCE_P(zv), php_phongo_logsubscriber_ce) /* Registers a global event subscriber */ PHP_FUNCTION(MongoDB_Driver_Monitoring_addSubscriber) { zval* subscriber; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT_OF_CLASS(subscriber, php_phongo_subscriber_ce) PHONGO_PARSE_PARAMETERS_END(); // TODO: Consider throwing if subscriber is unsupported (see: PHPC-2289) if (IS_APM_SUBSCRIBER(subscriber)) { phongo_apm_add_subscriber(MONGODB_G(subscribers), subscriber); } if (IS_LOG_SUBSCRIBER(subscriber)) { phongo_log_add_logger(subscriber); } } /* Unregisters a global event subscriber */ PHP_FUNCTION(MongoDB_Driver_Monitoring_removeSubscriber) { zval* subscriber; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT_OF_CLASS(subscriber, php_phongo_subscriber_ce) PHONGO_PARSE_PARAMETERS_END(); if (IS_APM_SUBSCRIBER(subscriber)) { phongo_apm_remove_subscriber(MONGODB_G(subscribers), subscriber); } if (IS_LOG_SUBSCRIBER(subscriber)) { phongo_log_remove_logger(subscriber); } } /* Log a message through libmongoc (used for internal testing) */ PHP_FUNCTION(MongoDB_Driver_Monitoring_mongoc_log) { zend_long level; char * domain, *message; size_t domain_len, message_len; PHONGO_PARSE_PARAMETERS_START(3, 3) Z_PARAM_LONG(level) Z_PARAM_STRING(domain, domain_len) Z_PARAM_STRING(message, message_len) PHONGO_PARSE_PARAMETERS_END(); if (level < MONGOC_LOG_LEVEL_ERROR || level > MONGOC_LOG_LEVEL_TRACE) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected level to be >= %d and <= %d, %" PHONGO_LONG_FORMAT " given", MONGOC_LOG_LEVEL_ERROR, MONGOC_LOG_LEVEL_TRACE, level); return; } if (strlen(domain) != domain_len) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Domain cannot contain null bytes. Unexpected null byte after \"%s\".", domain); return; } if (strlen(message) != message_len) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Message cannot contain null bytes. Unexpected null byte after \"%s\".", message); return; } mongoc_log(level, domain, "%s", message); } mongodb-1.21.0/src/MongoDB/BulkWrite.c0000644000175100001660000004610514760300420014273 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "BulkWrite_arginfo.h" #include "MongoDB/WriteConcern.h" #define PHONGO_BULKWRITE_BYPASS_UNSET -1 zend_class_entry* php_phongo_bulkwrite_ce; /* Extracts the "_id" field of a BSON document into a return value. */ static void php_phongo_bulkwrite_extract_id(bson_t* doc, zval** return_value) { zval* id = NULL; php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); state.map.root.type = PHONGO_TYPEMAP_NATIVE_ARRAY; if (!php_phongo_bson_to_zval_ex(doc, &state)) { goto cleanup; } id = php_array_fetchc(&state.zchild, "_id"); if (id) { ZVAL_ZVAL(*return_value, id, 1, 0); } cleanup: zval_ptr_dtor(&state.zchild); } /* Returns whether any top-level field names in the document contain a "$". */ static inline bool php_phongo_bulkwrite_update_has_operators(bson_t* bupdate) { bson_iter_t iter; if (bson_iter_init(&iter, bupdate)) { while (bson_iter_next(&iter)) { if (strchr(bson_iter_key(&iter), '$')) { return true; } } } return false; } /* Returns whether the update document is considered an aggregation pipeline */ static inline bool php_phongo_bulkwrite_update_is_pipeline(bson_t* bupdate) { bson_iter_t iter; bson_iter_t child; const char* key; int i = 0; char* i_str; if (!bson_iter_init(&iter, bupdate)) { return false; } while (bson_iter_next(&iter)) { key = bson_iter_key(&iter); i_str = bson_strdup_printf("%d", i++); if (strcmp(key, i_str)) { bson_free(i_str); return false; } bson_free(i_str); if (BSON_ITER_HOLDS_DOCUMENT(&iter)) { if (!bson_iter_recurse(&iter, &child)) { return false; } if (!bson_iter_next(&child)) { return false; } key = bson_iter_key(&child); if (key[0] != '$') { return false; } } else { return false; } } /* should return false when the document is empty */ return i != 0; } /* Returns whether the BSON array's keys are a sequence of integer strings * starting with "0". BSON_APPEND_ARRAY considers it the caller's responsibility * to ensure that the array's keys are properly formatted. */ static inline bool php_phongo_bulkwrite_bson_array_has_valid_keys(bson_t* array) { bson_iter_t iter; if (bson_empty(array)) { return true; } if (bson_iter_init(&iter, array)) { char key[12]; int count = 0; while (bson_iter_next(&iter)) { bson_snprintf(key, sizeof(key), "%d", count); if (0 != strcmp(key, bson_iter_key(&iter))) { return false; } count++; } } return true; } /* Appends an array field for the given opts document and key. Returns true on * success; otherwise, false is returned and an exception is thrown. */ static bool php_phongo_bulkwrite_opts_append_array(bson_t* opts, const char* key, zval* zarr) { zval* value = php_array_fetch_deref(zarr, key); bson_t b = BSON_INITIALIZER; if (Z_TYPE_P(value) != IS_OBJECT && Z_TYPE_P(value) != IS_ARRAY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"%s\" option to be array or object, %s given", key, zend_get_type_by_const(Z_TYPE_P(value))); return false; } // Explicitly allow MongoDB\BSON\PackedArray for array values php_phongo_zval_to_bson(value, PHONGO_BSON_ALLOW_ROOT_ARRAY, &b, NULL); if (EG(exception)) { bson_destroy(&b); return false; } if (!php_phongo_bulkwrite_bson_array_has_valid_keys(&b)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "\"%s\" option has invalid keys for a BSON array", key); bson_destroy(&b); return false; } if (!BSON_APPEND_ARRAY(opts, key, &b)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", key); bson_destroy(&b); return false; } bson_destroy(&b); return true; } /* Appends a document field for the given opts document and key. Returns true on * success; otherwise, false is returned and an exception is thrown. */ static bool php_phongo_bulkwrite_opts_append_document(bson_t* opts, const char* key, zval* zarr) { zval* value = php_array_fetch_deref(zarr, key); bson_t b = BSON_INITIALIZER; if (Z_TYPE_P(value) != IS_OBJECT && Z_TYPE_P(value) != IS_ARRAY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"%s\" option to be array or object, %s given", key, zend_get_type_by_const(Z_TYPE_P(value))); return false; } php_phongo_zval_to_bson(value, PHONGO_BSON_NONE, &b, NULL); if (EG(exception)) { bson_destroy(&b); return false; } if (!BSON_APPEND_DOCUMENT(opts, key, &b)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", key); bson_destroy(&b); return false; } bson_destroy(&b); return true; } #define PHONGO_BULKWRITE_APPEND_BOOL(opt, value) \ if (!BSON_APPEND_BOOL(boptions, (opt), (value))) { \ phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", (opt)); \ return false; \ } #define PHONGO_BULKWRITE_APPEND_INT32(opt, value) \ if (!BSON_APPEND_INT32(boptions, (opt), (value))) { \ phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", (opt)); \ return false; \ } #define PHONGO_BULKWRITE_OPT_ARRAY(opt) \ if (zoptions && php_array_existsc(zoptions, (opt))) { \ if (!php_phongo_bulkwrite_opts_append_array(boptions, (opt), zoptions)) { \ return false; \ } \ } #define PHONGO_BULKWRITE_OPT_DOCUMENT(opt) \ if (zoptions && php_array_existsc(zoptions, (opt))) { \ if (!php_phongo_bulkwrite_opts_append_document(boptions, (opt), zoptions)) { \ return false; \ } \ } /* Initialize the "hint" option. Returns true on success; otherwise, false is * returned and an exception is thrown. * * The "hint" option must be a string or document. Check for both types and * merge into BSON options accordingly. */ static bool php_phongo_bulkwrite_opt_hint(bson_t* boptions, zval* zoptions) { /* The "hint" option (or "$hint" modifier) must be a string or document. * Check for both types and merge into BSON options accordingly. */ if (zoptions && php_array_existsc(zoptions, "hint")) { zend_uchar type = Z_TYPE_P(php_array_fetchc_deref(zoptions, "hint")); if (type == IS_STRING) { zval* value = php_array_fetchc_deref(zoptions, "hint"); if (!bson_append_utf8(boptions, "hint", 4, Z_STRVAL_P(value), Z_STRLEN_P(value))) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"hint\" option"); return false; } } else if (type == IS_OBJECT || type == IS_ARRAY) { PHONGO_BULKWRITE_OPT_DOCUMENT("hint"); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"hint\" option to be string, array, or object, %s given", zend_get_type_by_const(type)); return false; } } return true; } /* Applies options (including defaults) for an update operation. */ static bool php_phongo_bulkwrite_update_apply_options(bson_t* boptions, zval* zoptions) { bool multi = false, upsert = false; if (zoptions) { multi = php_array_fetchc_bool(zoptions, "multi"); upsert = php_array_fetchc_bool(zoptions, "upsert"); } PHONGO_BULKWRITE_APPEND_BOOL("multi", multi); PHONGO_BULKWRITE_APPEND_BOOL("upsert", upsert); PHONGO_BULKWRITE_OPT_ARRAY("arrayFilters"); PHONGO_BULKWRITE_OPT_DOCUMENT("collation"); PHONGO_BULKWRITE_OPT_DOCUMENT("sort"); if (!php_phongo_bulkwrite_opt_hint(boptions, zoptions)) { return false; } return true; } /* Applies options (including defaults) for a delete operation. */ static bool php_phongo_bulkwrite_delete_apply_options(bson_t* boptions, zval* zoptions) { int32_t limit = 0; if (zoptions) { limit = php_array_fetchc_bool(zoptions, "limit") ? 1 : 0; } PHONGO_BULKWRITE_APPEND_INT32("limit", limit); PHONGO_BULKWRITE_OPT_DOCUMENT("collation"); if (!php_phongo_bulkwrite_opt_hint(boptions, zoptions)) { return false; } return true; } #undef PHONGO_BULKWRITE_APPEND_BOOL #undef PHONGO_BULKWRITE_APPEND_INT32 #undef PHONGO_BULKWRITE_OPT_DOCUMENT /* Constructs a new BulkWrite */ static PHP_METHOD(MongoDB_Driver_BulkWrite, __construct) { php_phongo_bulkwrite_t* intern; zval* options = NULL; zend_bool ordered = 1; intern = Z_BULKWRITE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); if (options && php_array_existsc(options, "ordered")) { ordered = php_array_fetchc_bool(options, "ordered"); } intern->bulk = mongoc_bulk_operation_new(ordered); intern->ordered = ordered; intern->bypass = PHONGO_BULKWRITE_BYPASS_UNSET; intern->let = NULL; intern->num_ops = 0; intern->executed = false; if (options && php_array_existsc(options, "bypassDocumentValidation")) { zend_bool bypass = php_array_fetchc_bool(options, "bypassDocumentValidation"); mongoc_bulk_operation_set_bypass_document_validation(intern->bulk, bypass); intern->bypass = bypass; } if (options && php_array_existsc(options, "let")) { zval* value = php_array_fetchc_deref(options, "let"); if (Z_TYPE_P(value) != IS_OBJECT && Z_TYPE_P(value) != IS_ARRAY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"let\" option to be array or object, %s given", zend_get_type_by_const(Z_TYPE_P(value))); return; } intern->let = bson_new(); php_phongo_zval_to_bson(value, PHONGO_BSON_NONE, intern->let, NULL); if (EG(exception)) { return; } mongoc_bulk_operation_set_let(intern->bulk, intern->let); } if (options && php_array_existsc(options, "comment")) { zval* value = php_array_fetchc_deref(options, "comment"); intern->comment = ecalloc(1, sizeof(bson_value_t)); phongo_zval_to_bson_value(value, intern->comment); if (EG(exception)) { /* Exception should already have been thrown */ return; } mongoc_bulk_operation_set_comment(intern->bulk, intern->comment); } } /* Adds an insert operation to the BulkWrite */ static PHP_METHOD(MongoDB_Driver_BulkWrite, insert) { php_phongo_bulkwrite_t* intern; zval* zdocument; bson_t bdocument = BSON_INITIALIZER, boptions = BSON_INITIALIZER; bson_t* bson_out = NULL; bson_error_t error = { 0 }; intern = Z_BULKWRITE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY_OR_OBJECT(zdocument) PHONGO_PARSE_PARAMETERS_END(); php_phongo_zval_to_bson(zdocument, (PHONGO_BSON_ADD_ID | PHONGO_BSON_RETURN_ID), &bdocument, &bson_out); if (EG(exception)) { goto cleanup; } if (!bson_out) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "php_phongo_zval_to_bson() did not return an _id. Please file a bug report."); goto cleanup; } if (!mongoc_bulk_operation_insert_with_opts(intern->bulk, &bdocument, &boptions, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } intern->num_ops++; php_phongo_bulkwrite_extract_id(bson_out, &return_value); cleanup: bson_destroy(&bdocument); bson_destroy(&boptions); bson_clear(&bson_out); } /* Adds an update operation to the BulkWrite */ static PHP_METHOD(MongoDB_Driver_BulkWrite, update) { php_phongo_bulkwrite_t* intern; zval * zquery, *zupdate, *zoptions = NULL; bson_t bquery = BSON_INITIALIZER, bupdate = BSON_INITIALIZER, boptions = BSON_INITIALIZER; bson_error_t error = { 0 }; intern = Z_BULKWRITE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_ARRAY_OR_OBJECT(zquery) Z_PARAM_ARRAY_OR_OBJECT(zupdate) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(zoptions) PHONGO_PARSE_PARAMETERS_END(); php_phongo_zval_to_bson(zquery, PHONGO_BSON_NONE, &bquery, NULL); if (EG(exception)) { goto cleanup; } // Explicitly allow MongoDB\BSON\PackedArray for update pipelines php_phongo_zval_to_bson(zupdate, PHONGO_BSON_ALLOW_ROOT_ARRAY, &bupdate, NULL); if (EG(exception)) { goto cleanup; } if (!php_phongo_bulkwrite_update_apply_options(&boptions, zoptions)) { goto cleanup; } if (php_phongo_bulkwrite_update_has_operators(&bupdate) || php_phongo_bulkwrite_update_is_pipeline(&bupdate)) { if (zoptions && php_array_fetchc_bool(zoptions, "multi")) { if (!mongoc_bulk_operation_update_many_with_opts(intern->bulk, &bquery, &bupdate, &boptions, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } } else { if (!mongoc_bulk_operation_update_one_with_opts(intern->bulk, &bquery, &bupdate, &boptions, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } } } else { if (zoptions && php_array_fetchc_bool(zoptions, "multi")) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Replacement document conflicts with true \"multi\" option"); goto cleanup; } if (!mongoc_bulk_operation_replace_one_with_opts(intern->bulk, &bquery, &bupdate, &boptions, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } } intern->num_ops++; cleanup: bson_destroy(&bquery); bson_destroy(&bupdate); bson_destroy(&boptions); } /* Adds a delete operation to the BulkWrite */ static PHP_METHOD(MongoDB_Driver_BulkWrite, delete) { php_phongo_bulkwrite_t* intern; zval * zquery, *zoptions = NULL; bson_t bquery = BSON_INITIALIZER, boptions = BSON_INITIALIZER; bson_error_t error = { 0 }; intern = Z_BULKWRITE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ARRAY_OR_OBJECT(zquery) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(zoptions) PHONGO_PARSE_PARAMETERS_END(); php_phongo_zval_to_bson(zquery, PHONGO_BSON_NONE, &bquery, NULL); if (EG(exception)) { goto cleanup; } if (!php_phongo_bulkwrite_delete_apply_options(&boptions, zoptions)) { goto cleanup; } if (zoptions && php_array_fetchc_bool(zoptions, "limit")) { if (!mongoc_bulk_operation_remove_one_with_opts(intern->bulk, &bquery, &boptions, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } } else { if (!mongoc_bulk_operation_remove_many_with_opts(intern->bulk, &bquery, &boptions, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } } intern->num_ops++; cleanup: bson_destroy(&bquery); bson_destroy(&boptions); } /* Returns the number of operations that have been added to the BulkWrite */ static PHP_METHOD(MongoDB_Driver_BulkWrite, count) { php_phongo_bulkwrite_t* intern; intern = Z_BULKWRITE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->num_ops); } /* MongoDB\Driver\BulkWrite object handlers */ static zend_object_handlers php_phongo_handler_bulkwrite; static void php_phongo_bulkwrite_free_object(zend_object* object) { php_phongo_bulkwrite_t* intern = Z_OBJ_BULKWRITE(object); zend_object_std_dtor(&intern->std); if (intern->bulk) { mongoc_bulk_operation_destroy(intern->bulk); } if (intern->let) { bson_clear(&intern->let); } if (intern->comment) { bson_value_destroy(intern->comment); efree(intern->comment); } if (intern->database) { efree(intern->database); } if (intern->collection) { efree(intern->collection); } if (!Z_ISUNDEF(intern->session)) { zval_ptr_dtor(&intern->session); } } static zend_object* php_phongo_bulkwrite_create_object(zend_class_entry* class_type) { php_phongo_bulkwrite_t* intern = zend_object_alloc(sizeof(php_phongo_bulkwrite_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_bulkwrite; return &intern->std; } static HashTable* php_phongo_bulkwrite_get_debug_info(zend_object* object, int* is_temp) { zval retval = ZVAL_STATIC_INIT; php_phongo_bulkwrite_t* intern = NULL; *is_temp = 1; intern = Z_OBJ_BULKWRITE(object); array_init(&retval); if (intern->database) { ADD_ASSOC_STRING(&retval, "database", intern->database); } else { ADD_ASSOC_NULL_EX(&retval, "database"); } if (intern->collection) { ADD_ASSOC_STRING(&retval, "collection", intern->collection); } else { ADD_ASSOC_NULL_EX(&retval, "collection"); } ADD_ASSOC_BOOL_EX(&retval, "ordered", intern->ordered); if (intern->bypass != PHONGO_BULKWRITE_BYPASS_UNSET) { ADD_ASSOC_BOOL_EX(&retval, "bypassDocumentValidation", intern->bypass); } else { ADD_ASSOC_NULL_EX(&retval, "bypassDocumentValidation"); } if (intern->comment) { zval zv; if (!phongo_bson_value_to_zval_legacy(intern->comment, &zv)) { zval_ptr_dtor(&zv); goto done; } ADD_ASSOC_ZVAL_EX(&retval, "comment", &zv); } if (intern->let) { zval zv; if (!php_phongo_bson_to_zval(intern->let, &zv)) { zval_ptr_dtor(&zv); goto done; } ADD_ASSOC_ZVAL_EX(&retval, "let", &zv); } ADD_ASSOC_BOOL_EX(&retval, "executed", intern->executed); ADD_ASSOC_LONG_EX(&retval, "server_id", mongoc_bulk_operation_get_server_id(intern->bulk)); if (!Z_ISUNDEF(intern->session)) { ADD_ASSOC_ZVAL_EX(&retval, "session", &intern->session); Z_ADDREF(intern->session); } else { ADD_ASSOC_NULL_EX(&retval, "session"); } if (mongoc_bulk_operation_get_write_concern(intern->bulk)) { zval write_concern; php_phongo_write_concern_to_zval(&write_concern, mongoc_bulk_operation_get_write_concern(intern->bulk)); ADD_ASSOC_ZVAL_EX(&retval, "write_concern", &write_concern); } else { ADD_ASSOC_NULL_EX(&retval, "write_concern"); } done: return Z_ARRVAL(retval); } void php_phongo_bulkwrite_init_ce(INIT_FUNC_ARGS) { php_phongo_bulkwrite_ce = register_class_MongoDB_Driver_BulkWrite(zend_ce_countable); php_phongo_bulkwrite_ce->create_object = php_phongo_bulkwrite_create_object; memcpy(&php_phongo_handler_bulkwrite, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_bulkwrite.get_debug_info = php_phongo_bulkwrite_get_debug_info; php_phongo_handler_bulkwrite.free_obj = php_phongo_bulkwrite_free_object; php_phongo_handler_bulkwrite.offset = XtOffsetOf(php_phongo_bulkwrite_t, std); } mongodb-1.21.0/src/MongoDB/BulkWrite_arginfo.h0000644000175100001660000000507614760300420016007 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 1e91ce9db35aa0f3b77c3042099b02ac0fb381a9 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_BulkWrite___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_BulkWrite_count, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_BulkWrite_delete, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_MASK(0, filter, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, deleteOptions, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_BulkWrite_insert, 0, 1, IS_MIXED, 0) ZEND_ARG_TYPE_MASK(0, document, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_BulkWrite_update, 0, 2, IS_VOID, 0) ZEND_ARG_TYPE_MASK(0, filter, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_ARG_TYPE_MASK(0, newObj, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, updateOptions, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_BulkWrite, __construct); static ZEND_METHOD(MongoDB_Driver_BulkWrite, count); static ZEND_METHOD(MongoDB_Driver_BulkWrite, delete); static ZEND_METHOD(MongoDB_Driver_BulkWrite, insert); static ZEND_METHOD(MongoDB_Driver_BulkWrite, update); static const zend_function_entry class_MongoDB_Driver_BulkWrite_methods[] = { ZEND_ME(MongoDB_Driver_BulkWrite, __construct, arginfo_class_MongoDB_Driver_BulkWrite___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_BulkWrite, count, arginfo_class_MongoDB_Driver_BulkWrite_count, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_Driver_BulkWrite, delete, arginfo_class_MongoDB_Driver_BulkWrite_delete, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_Driver_BulkWrite, insert, arginfo_class_MongoDB_Driver_BulkWrite_insert, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_BulkWrite, update, arginfo_class_MongoDB_Driver_BulkWrite_update, ZEND_ACC_PUBLIC) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_BulkWrite(zend_class_entry *class_entry_Countable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "BulkWrite", class_MongoDB_Driver_BulkWrite_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; zend_class_implements(class_entry, 1, class_entry_Countable); return class_entry; } mongodb-1.21.0/src/MongoDB/ClientEncryption.c0000644000175100001660000010704614760300420015656 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "phongo_util.h" #include "ClientEncryption_arginfo.h" #include "BSON/Binary.h" #include "MongoDB/ClientEncryption.h" #include "MongoDB/Cursor.h" #include "MongoDB/Query.h" zend_class_entry* php_phongo_clientencryption_ce; /* Forward declarations */ static void phongo_clientencryption_create_datakey(php_phongo_clientencryption_t* clientencryption, zval* return_value, char* kms_provider, zval* options); static void phongo_clientencryption_encrypt(php_phongo_clientencryption_t* clientencryption, zval* zvalue, zval* zciphertext, zval* options); static void phongo_clientencryption_encrypt_expression(php_phongo_clientencryption_t* clientencryption, zval* zexpr, zval* return_value, zval* options); static void phongo_clientencryption_decrypt(php_phongo_clientencryption_t* clientencryption, zval* zciphertext, zval* zvalue); #define RETVAL_BSON_T(reply) \ do { \ php_phongo_bson_state state; \ PHONGO_BSON_INIT_STATE(state); \ if (!php_phongo_bson_to_zval_ex(&(reply), &state)) { \ zval_ptr_dtor(&state.zchild); \ goto cleanup; \ } \ RETVAL_ZVAL(&state.zchild, 0, 1); \ } while (0) #define RETVAL_OPTIONAL_BSON_T(reply) \ do { \ RETVAL_NULL(); \ if (!bson_empty(&(reply))) { \ RETVAL_BSON_T(reply); \ } \ } while (0) /* Returns true if keyid is a UUID Binary value with an appropriate data length; * otherwise, throws an exception and returns false. */ static bool validate_keyid(bson_value_t* keyid) { if (keyid->value_type != BSON_TYPE_BINARY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected keyid to have Binary BSON type, %s given", php_phongo_bson_type_to_string(keyid->value_type)); return false; } if (keyid->value.v_binary.subtype != BSON_SUBTYPE_UUID) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected keyid to have UUID Binary subtype (%d), %d given", BSON_SUBTYPE_UUID, keyid->value.v_binary.subtype); return false; } /* php_phongo_binary_init already enforces the data length for Binary objects * with UUID subtypes so we throw a different exception here. */ if (keyid->value.v_binary.data_len != PHONGO_BINARY_UUID_SIZE) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Expected keyid to have data length of %d bytes, %d given", PHONGO_BINARY_UUID_SIZE, keyid->value.v_binary.data_len); return false; } return true; } /* Constructs a new ClientEncryption */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, __construct) { zval* options; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(options) PHONGO_PARSE_PARAMETERS_END(); /* An exception will be thrown on error. */ phongo_clientencryption_init(Z_CLIENTENCRYPTION_OBJ_P(getThis()), options, NULL); } /* Adds a keyAltName to the keyAltNames array of the key document in the key vault collection with the given UUID (BSON binary subtype 0x04). Returns the previous version of the key document, or null if no document matched. */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, addKeyAltName) { zval* zkeyid = NULL; char* keyaltname = NULL; size_t keyaltname_len = 0; bson_value_t keyid = { 0 }; bson_t key_doc = BSON_INITIALIZER; bson_error_t error = { 0 }; PHONGO_PARSE_PARAMETERS_START(2, 2) Z_PARAM_OBJECT_OF_CLASS(zkeyid, php_phongo_binary_ce) Z_PARAM_STRING(keyaltname, keyaltname_len); PHONGO_PARSE_PARAMETERS_END(); phongo_zval_to_bson_value(zkeyid, &keyid); if (EG(exception)) { goto cleanup; } if (!validate_keyid(&keyid)) { /* Exception already thrown */ goto cleanup; } if (!mongoc_client_encryption_add_key_alt_name(Z_CLIENTENCRYPTION_OBJ_P(getThis())->client_encryption, &keyid, keyaltname, &key_doc, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } RETVAL_OPTIONAL_BSON_T(key_doc); cleanup: bson_value_destroy(&keyid); bson_destroy(&key_doc); } /* Creates a new key document and inserts into the key vault collection and returns its identifier (UUID as a BSON binary with subtype 0x04). */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, createDataKey) { char* kms_provider = NULL; size_t kms_provider_len = 0; zval* options = NULL; php_phongo_clientencryption_t* intern; intern = Z_CLIENTENCRYPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STRING(kms_provider, kms_provider_len) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); phongo_clientencryption_create_datakey(intern, return_value, kms_provider, options); } /* Removes the key document with the given UUID (BSON binary subtype 0x04) from the key vault collection. Returns the result of the internal deleteOne() operation on the key vault collection. */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, deleteKey) { zval* zkeyid = NULL; bson_value_t keyid = { 0 }; bson_t reply = BSON_INITIALIZER; bson_error_t error = { 0 }; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT_OF_CLASS(zkeyid, php_phongo_binary_ce) PHONGO_PARSE_PARAMETERS_END(); phongo_zval_to_bson_value(zkeyid, &keyid); if (EG(exception)) { goto cleanup; } if (!validate_keyid(&keyid)) { /* Exception already thrown */ goto cleanup; } if (!mongoc_client_encryption_delete_key(Z_CLIENTENCRYPTION_OBJ_P(getThis())->client_encryption, &keyid, &reply, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } if (bson_empty(&reply)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "mongoc_client_encryption_delete_key returned an empty document"); goto cleanup; } RETVAL_BSON_T(reply); cleanup: bson_value_destroy(&keyid); bson_destroy(&reply); } /* Encrypts a value with a given key and algorithm */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, encrypt) { zval* value = NULL; zval* options = NULL; php_phongo_clientencryption_t* intern; intern = Z_CLIENTENCRYPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ZVAL(value) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); phongo_clientencryption_encrypt(intern, value, return_value, options); } /* Encrypts a value with a given key and algorithm */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, encryptExpression) { zval* expr = NULL; zval* options = NULL; php_phongo_clientencryption_t* intern; intern = Z_CLIENTENCRYPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ZVAL(expr) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); phongo_clientencryption_encrypt_expression(intern, expr, return_value, options); } /* Decrypts an encrypted value (BSON binary of subtype 6). Returns the original BSON value */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, decrypt) { zval* ciphertext; php_phongo_clientencryption_t* intern; intern = Z_CLIENTENCRYPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT_OF_CLASS(ciphertext, php_phongo_binary_interface_ce) PHONGO_PARSE_PARAMETERS_END(); phongo_clientencryption_decrypt(intern, ciphertext, return_value); } /* Finds a single key document with the given UUID (BSON binary subtype 0x04). Returns the result of the internal find() operation on the key vault collection, or null if no document matched. */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, getKey) { zval* zkeyid = NULL; bson_value_t keyid = { 0 }; bson_t key_doc = BSON_INITIALIZER; bson_error_t error = { 0 }; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT_OF_CLASS(zkeyid, php_phongo_binary_ce) PHONGO_PARSE_PARAMETERS_END(); phongo_zval_to_bson_value(zkeyid, &keyid); if (EG(exception)) { goto cleanup; } if (!validate_keyid(&keyid)) { /* Exception already thrown */ goto cleanup; } if (!mongoc_client_encryption_get_key(Z_CLIENTENCRYPTION_OBJ_P(getThis())->client_encryption, &keyid, &key_doc, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } RETVAL_OPTIONAL_BSON_T(key_doc); cleanup: bson_value_destroy(&keyid); bson_destroy(&key_doc); } /* Returns a key document in the key vault collection with the given keyAltName, or null if no document matched. */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, getKeyByAltName) { char* keyaltname = NULL; size_t keyaltname_len = 0; bson_t key_doc = BSON_INITIALIZER; bson_error_t error = { 0 }; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(keyaltname, keyaltname_len); PHONGO_PARSE_PARAMETERS_END(); if (!mongoc_client_encryption_get_key_by_alt_name(Z_CLIENTENCRYPTION_OBJ_P(getThis())->client_encryption, keyaltname, &key_doc, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } RETVAL_OPTIONAL_BSON_T(key_doc); cleanup: bson_destroy(&key_doc); } /* Finds all documents in the key vault collection. Returns the result of the internal find() operation on the key vault collection as a cursor. */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, getKeys) { mongoc_cursor_t* cursor; bson_error_t error = { 0 }; php_phongo_clientencryption_t* intern; zval query = ZVAL_STATIC_INIT; intern = Z_CLIENTENCRYPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); /* mongoc_client_encryption_get_keys executes a query against its internal * key vault collection. The collection has a majority read concern, but the * query itself specifies no filter or options. Create an empty query object * and attach it to the cursor for the benefit of debugging. */ if (!phongo_query_init(&query, NULL, NULL)) { /* Exception already thrown */ goto cleanup; } cursor = mongoc_client_encryption_get_keys(intern->client_encryption, &error); if (!cursor) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } if (!phongo_cursor_init_for_query(return_value, &intern->key_vault_client_manager, cursor, intern->key_vault_namespace, &query, NULL, NULL)) { /* Exception already thrown */ mongoc_cursor_destroy(cursor); goto cleanup; } cleanup: zval_ptr_dtor(&query); } /* Removes a keyAltName from the keyAltNames array of the key document in the key vault collection with the given UUID (BSON binary subtype 0x04). Returns the previous version of the key document, or null if no document matched. */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, removeKeyAltName) { zval* zkeyid = NULL; char* keyaltname = NULL; size_t keyaltname_len = 0; bson_value_t keyid = { 0 }; bson_t key_doc = BSON_INITIALIZER; bson_error_t error = { 0 }; PHONGO_PARSE_PARAMETERS_START(2, 2) Z_PARAM_OBJECT_OF_CLASS(zkeyid, php_phongo_binary_ce) Z_PARAM_STRING(keyaltname, keyaltname_len); PHONGO_PARSE_PARAMETERS_END(); phongo_zval_to_bson_value(zkeyid, &keyid); if (EG(exception)) { goto cleanup; } if (!validate_keyid(&keyid)) { /* Exception already thrown */ goto cleanup; } if (!mongoc_client_encryption_remove_key_alt_name(Z_CLIENTENCRYPTION_OBJ_P(getThis())->client_encryption, &keyid, keyaltname, &key_doc, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } RETVAL_OPTIONAL_BSON_T(key_doc); cleanup: bson_value_destroy(&keyid); bson_destroy(&key_doc); } /* Decrypts multiple data keys and (re-)encrypts them with a new provider (and masterKey if applicable), or with their current provider if a new one is not given. Returns an object corresponding to the internal libmongoc result. */ static PHP_METHOD(MongoDB_Driver_ClientEncryption, rewrapManyDataKey) { zval* zfilter = NULL; zval* options = NULL; bson_t filter = BSON_INITIALIZER; char* provider = NULL; zend_bool free_provider = false; bson_t* masterkey = NULL; bson_error_t error = { 0 }; bson_t reply = BSON_INITIALIZER; mongoc_client_encryption_rewrap_many_datakey_result_t* result = NULL; const bson_t* bulk_write_result; PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ARRAY_OR_OBJECT(zfilter) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); php_phongo_zval_to_bson(zfilter, PHONGO_BSON_NONE, &filter, NULL); if (EG(exception)) { goto cleanup; } if (options && php_array_existsc(options, "provider")) { int provider_len; provider = php_array_fetchc_string(options, "provider", &provider_len, &free_provider); } if (options && php_array_existsc(options, "masterKey")) { zval* zmasterkey = php_array_fetchc_deref(options, "masterKey"); if (Z_TYPE_P(zmasterkey) != IS_OBJECT && Z_TYPE_P(zmasterkey) != IS_ARRAY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"masterKey\" option to be array or object, %s given", zend_zval_type_name(zmasterkey)); goto cleanup; } if (!provider) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "The \"masterKey\" option should not be specified without \"provider\""); goto cleanup; } masterkey = bson_new(); php_phongo_zval_to_bson(zmasterkey, PHONGO_BSON_NONE, masterkey, NULL); if (EG(exception)) { goto cleanup; } } result = mongoc_client_encryption_rewrap_many_datakey_result_new(); if (!mongoc_client_encryption_rewrap_many_datakey(Z_CLIENTENCRYPTION_OBJ_P(getThis())->client_encryption, &filter, provider, masterkey, result, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } bulk_write_result = mongoc_client_encryption_rewrap_many_datakey_result_get_bulk_write_result(result); if (bson_empty0(bulk_write_result)) { BSON_APPEND_NULL(&reply, "bulkWriteResult"); } else { BSON_APPEND_DOCUMENT(&reply, "bulkWriteResult", bulk_write_result); } RETVAL_BSON_T(reply); cleanup: if (free_provider) { efree(provider); } bson_destroy(&filter); bson_destroy(masterkey); mongoc_client_encryption_rewrap_many_datakey_result_destroy(result); } /* MongoDB\Driver\ClientEncryption object handlers */ static zend_object_handlers php_phongo_handler_clientencryption; static void php_phongo_clientencryption_free_object(zend_object* object) { php_phongo_clientencryption_t* intern = Z_OBJ_CLIENTENCRYPTION(object); zend_object_std_dtor(&intern->std); if (intern->client_encryption) { mongoc_client_encryption_destroy(intern->client_encryption); } /* Free the keyVaultClient last to ensure that a potential non-persistent * client outlives the mongoc_client_encryption_t as needed */ if (!Z_ISUNDEF(intern->key_vault_client_manager)) { zval_ptr_dtor(&intern->key_vault_client_manager); } if (intern->key_vault_namespace) { efree(intern->key_vault_namespace); } } static zend_object* php_phongo_clientencryption_create_object(zend_class_entry* class_type) { php_phongo_clientencryption_t* intern = zend_object_alloc(sizeof(php_phongo_clientencryption_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_clientencryption; return &intern->std; } static HashTable* php_phongo_clientencryption_get_debug_info(zend_object* object, int* is_temp) { php_phongo_clientencryption_t* intern = NULL; zval retval = ZVAL_STATIC_INIT; *is_temp = 1; intern = Z_OBJ_CLIENTENCRYPTION(object); array_init(&retval); return Z_ARRVAL(retval); } void php_phongo_clientencryption_init_ce(INIT_FUNC_ARGS) { php_phongo_clientencryption_ce = register_class_MongoDB_Driver_ClientEncryption(); php_phongo_clientencryption_ce->create_object = php_phongo_clientencryption_create_object; memcpy(&php_phongo_handler_clientencryption, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_clientencryption.get_debug_info = php_phongo_clientencryption_get_debug_info; php_phongo_handler_clientencryption.free_obj = php_phongo_clientencryption_free_object; php_phongo_handler_clientencryption.offset = XtOffsetOf(php_phongo_clientencryption_t, std); } #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION /* key_vault_client_manager is an output parameter and will be assigned to the * effective keyVaultClient. */ static mongoc_client_encryption_opts_t* phongo_clientencryption_opts_from_zval(zval* options, zval* default_key_vault_client_manager, zval** key_vault_client_manager) { mongoc_client_encryption_opts_t* opts = mongoc_client_encryption_opts_new(); *key_vault_client_manager = NULL; if (!options || Z_TYPE_P(options) != IS_ARRAY) { /* Returning opts as-is will defer to mongoc_client_encryption_new to * raise an error for missing required options */ return opts; } if (php_array_existsc(options, "keyVaultClient")) { zval* key_vault_client = php_array_fetchc_deref(options, "keyVaultClient"); if (Z_TYPE_P(key_vault_client) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(key_vault_client), php_phongo_manager_ce)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"keyVaultClient\" option to be %s, %s given", ZSTR_VAL(php_phongo_manager_ce->name), zend_zval_type_name(key_vault_client)); goto cleanup; } mongoc_client_encryption_opts_set_keyvault_client(opts, Z_MANAGER_OBJ_P(key_vault_client)->client); *key_vault_client_manager = key_vault_client; } else if (default_key_vault_client_manager) { mongoc_client_encryption_opts_set_keyvault_client(opts, Z_MANAGER_OBJ_P(default_key_vault_client_manager)->client); *key_vault_client_manager = default_key_vault_client_manager; } else { /* If the ClientEncryption object is being constructed directly, the * "keyVaultClient" option must be explicitly provided. */ phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "The \"keyVaultClient\" option is required when constructing a ClientEncryption object directly"); goto cleanup; } if (php_array_existsc(options, "keyVaultNamespace")) { char* key_vault_namespace; char* db_name; char* coll_name; int plen; zend_bool pfree; key_vault_namespace = php_array_fetchc_string(options, "keyVaultNamespace", &plen, &pfree); if (!phongo_split_namespace(key_vault_namespace, &db_name, &coll_name)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"keyVaultNamespace\" option to contain a full collection namespace"); if (pfree) { efree(key_vault_namespace); } goto cleanup; } mongoc_client_encryption_opts_set_keyvault_namespace(opts, db_name, coll_name); efree(db_name); efree(coll_name); if (pfree) { efree(key_vault_namespace); } } if (php_array_existsc(options, "kmsProviders")) { zval* kms_providers = php_array_fetchc_deref(options, "kmsProviders"); bson_t bson_providers = BSON_INITIALIZER; if (Z_TYPE_P(kms_providers) != IS_ARRAY && Z_TYPE_P(kms_providers) != IS_OBJECT) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"kmsProviders\" option to be an array or object, %s given", zend_zval_type_name(kms_providers)); goto cleanup; } php_phongo_zval_to_bson(kms_providers, PHONGO_BSON_NONE, &bson_providers, NULL); if (EG(exception)) { goto cleanup; } mongoc_client_encryption_opts_set_kms_providers(opts, &bson_providers); bson_destroy(&bson_providers); } if (php_array_existsc(options, "tlsOptions")) { zval* tls_options = php_array_fetchc_deref(options, "tlsOptions"); bson_t bson_options = BSON_INITIALIZER; if (Z_TYPE_P(tls_options) != IS_ARRAY && Z_TYPE_P(tls_options) != IS_OBJECT) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"tlsOptions\" option to be an array or object, %s given", zend_zval_type_name(tls_options)); goto cleanup; } php_phongo_zval_to_bson(tls_options, PHONGO_BSON_NONE, &bson_options, NULL); if (EG(exception)) { goto cleanup; } mongoc_client_encryption_opts_set_tls_opts(opts, &bson_options); bson_destroy(&bson_options); } return opts; cleanup: if (opts) { mongoc_client_encryption_opts_destroy(opts); } return NULL; } void phongo_clientencryption_init(php_phongo_clientencryption_t* intern, zval* options, zval* default_key_vault_client_manager) { mongoc_client_encryption_t* client_encryption; mongoc_client_encryption_opts_t* opts; zval* key_vault_client_manager = NULL; bson_error_t error = { 0 }; opts = phongo_clientencryption_opts_from_zval(options, default_key_vault_client_manager, &key_vault_client_manager); if (!opts) { /* Exception already thrown */ goto cleanup; } client_encryption = mongoc_client_encryption_new(opts, &error); if (!client_encryption) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } intern->client_encryption = client_encryption; /* Note: key_vault_client_manager should always be assigned if options were * successfully parsed by phongo_clientencryption_opts_from_zval, but let's * be defensive. */ if (key_vault_client_manager) { ZVAL_ZVAL(&intern->key_vault_client_manager, key_vault_client_manager, 1, 0); } /* Copy the key vault namespace, since it may be referenced later by * ClientEncryption::getKeys(). The namespace will already have been * validated by phongo_clientencryption_opts_from_zval. */ if (php_array_existsc(options, "keyVaultNamespace")) { char* key_vault_namespace; int plen; zend_bool pfree; key_vault_namespace = php_array_fetchc_string(options, "keyVaultNamespace", &plen, &pfree); intern->key_vault_namespace = estrdup(key_vault_namespace); if (pfree) { efree(key_vault_namespace); } } cleanup: if (opts) { mongoc_client_encryption_opts_destroy(opts); } } static mongoc_client_encryption_datakey_opts_t* phongo_clientencryption_datakey_opts_from_zval(zval* options) { mongoc_client_encryption_datakey_opts_t* opts; opts = mongoc_client_encryption_datakey_opts_new(); if (!options || Z_TYPE_P(options) != IS_ARRAY) { return opts; } if (php_array_existsc(options, "keyAltNames")) { zval* zkeyaltnames = php_array_fetchc_deref(options, "keyAltNames"); HashTable* ht_data; uint32_t keyaltnames_count; char** keyaltnames; uint32_t i = 0; uint32_t j = 0; bool failed = false; if (!zkeyaltnames || Z_TYPE_P(zkeyaltnames) != IS_ARRAY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected keyAltNames to be array, %s given", zend_zval_type_name(zkeyaltnames)); goto cleanup; } ht_data = HASH_OF(zkeyaltnames); keyaltnames_count = ht_data ? zend_hash_num_elements(ht_data) : 0; keyaltnames = ecalloc(keyaltnames_count, sizeof(char*)); { zend_string* string_key = NULL; zend_ulong num_key = 0; zval* keyaltname; ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, string_key, keyaltname) { if (i >= keyaltnames_count) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Iterating over too many keyAltNames. Please file a bug report"); failed = true; break; } if (Z_TYPE_P(keyaltname) != IS_STRING) { if (string_key) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected keyAltName with index \"%s\" to be string, %s given", ZSTR_VAL(string_key), zend_zval_type_name(keyaltname)); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected keyAltName with index \"%lu\" to be string, %s given", num_key, zend_zval_type_name(keyaltname)); } failed = true; break; } keyaltnames[i] = estrdup(Z_STRVAL_P(keyaltname)); i++; } ZEND_HASH_FOREACH_END(); } if (!failed) { mongoc_client_encryption_datakey_opts_set_keyaltnames(opts, keyaltnames, keyaltnames_count); } for (j = 0; j < i; j++) { efree(keyaltnames[j]); } efree(keyaltnames); if (failed) { goto cleanup; } } if (php_array_existsc(options, "keyMaterial")) { zval* keyMaterial = php_array_fetchc_deref(options, "keyMaterial"); if (Z_TYPE_P(keyMaterial) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(keyMaterial), php_phongo_binary_ce)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"keyMaterial\" option to be %s, %s given", ZSTR_VAL(php_phongo_binary_ce->name), zend_zval_type_name(keyMaterial)); goto cleanup; } mongoc_client_encryption_datakey_opts_set_keymaterial(opts, (uint8_t*) Z_BINARY_OBJ_P(keyMaterial)->data, Z_BINARY_OBJ_P(keyMaterial)->data_len); } if (php_array_existsc(options, "masterKey")) { zval* zmasterkey = php_array_fetchc_deref(options, "masterKey"); bson_t masterkey = BSON_INITIALIZER; if (Z_TYPE_P(zmasterkey) != IS_OBJECT && Z_TYPE_P(zmasterkey) != IS_ARRAY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"masterKey\" option to be array or object, %s given", zend_zval_type_name(zmasterkey)); goto cleanup; } php_phongo_zval_to_bson(zmasterkey, PHONGO_BSON_NONE, &masterkey, NULL); if (EG(exception)) { bson_destroy(&masterkey); goto cleanup; } mongoc_client_encryption_datakey_opts_set_masterkey(opts, &masterkey); bson_destroy(&masterkey); } return opts; cleanup: if (opts) { mongoc_client_encryption_datakey_opts_destroy(opts); } return NULL; } static void phongo_clientencryption_create_datakey(php_phongo_clientencryption_t* clientencryption, zval* return_value, char* kms_provider, zval* options) { mongoc_client_encryption_datakey_opts_t* opts; bson_value_t keyid = { 0 }; bson_error_t error = { 0 }; opts = phongo_clientencryption_datakey_opts_from_zval(options); if (!opts) { /* Exception already thrown */ goto cleanup; } if (!mongoc_client_encryption_create_datakey(clientencryption->client_encryption, kms_provider, opts, &keyid, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } if (!phongo_bson_value_to_zval(&keyid, return_value)) { /* Exception already thrown */ goto cleanup; } cleanup: if (opts) { mongoc_client_encryption_datakey_opts_destroy(opts); } bson_value_destroy(&keyid); } static mongoc_client_encryption_encrypt_range_opts_t* phongo_clientencryption_encrypt_range_opts_from_zval(zval* options) { mongoc_client_encryption_encrypt_range_opts_t* opts; opts = mongoc_client_encryption_encrypt_range_opts_new(); if (!options || Z_TYPE_P(options) != IS_ARRAY) { return opts; } if (php_array_existsc(options, "trimFactor")) { int64_t trimfactor = php_array_fetchc_long(options, "trimFactor"); if (trimfactor < 0 || trimfactor > INT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"trimFactor\" range option to be a positive 32-bit integer, %" PRId64 " given", trimfactor); goto cleanup; } mongoc_client_encryption_encrypt_range_opts_set_trim_factor(opts, (int32_t) trimfactor); } if (php_array_existsc(options, "sparsity")) { int64_t sparsity = php_array_fetchc_long(options, "sparsity"); if (sparsity < 0 || sparsity > INT64_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"sparsity\" range option to be a positive 64-bit integer, %" PRId64 " given", sparsity); goto cleanup; } mongoc_client_encryption_encrypt_range_opts_set_sparsity(opts, sparsity); } if (php_array_existsc(options, "precision")) { int64_t precision = php_array_fetchc_long(options, "precision"); if (precision < 0 || precision > INT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"precision\" range option to be a positive 32-bit integer, %" PRId64 " given", precision); goto cleanup; } mongoc_client_encryption_encrypt_range_opts_set_precision(opts, (int32_t) precision); } if (php_array_existsc(options, "min")) { bson_value_t min = { 0 }; phongo_zval_to_bson_value(php_array_fetchc(options, "min"), &min); if (EG(exception)) { bson_value_destroy(&min); goto cleanup; } mongoc_client_encryption_encrypt_range_opts_set_min(opts, &min); bson_value_destroy(&min); } if (php_array_existsc(options, "max")) { bson_value_t max = { 0 }; phongo_zval_to_bson_value(php_array_fetchc(options, "max"), &max); if (EG(exception)) { bson_value_destroy(&max); goto cleanup; } mongoc_client_encryption_encrypt_range_opts_set_max(opts, &max); bson_value_destroy(&max); } return opts; cleanup: if (opts) { mongoc_client_encryption_encrypt_range_opts_destroy(opts); } return NULL; } static mongoc_client_encryption_encrypt_opts_t* phongo_clientencryption_encrypt_opts_from_zval(zval* options) { mongoc_client_encryption_encrypt_opts_t* opts; opts = mongoc_client_encryption_encrypt_opts_new(); if (!options || Z_TYPE_P(options) != IS_ARRAY) { return opts; } if (php_array_existsc(options, "contentionFactor")) { mongoc_client_encryption_encrypt_opts_set_contention_factor(opts, php_array_fetchc_long(options, "contentionFactor")); } if (php_array_existsc(options, "keyId")) { bson_value_t keyid = { 0 }; phongo_zval_to_bson_value(php_array_fetchc(options, "keyId"), &keyid); if (EG(exception)) { bson_value_destroy(&keyid); goto cleanup; } mongoc_client_encryption_encrypt_opts_set_keyid(opts, &keyid); bson_value_destroy(&keyid); } if (php_array_existsc(options, "keyAltName")) { char* keyaltname; int plen; zend_bool pfree; keyaltname = php_array_fetchc_string(options, "keyAltName", &plen, &pfree); mongoc_client_encryption_encrypt_opts_set_keyaltname(opts, keyaltname); if (pfree) { efree(keyaltname); } } if (php_array_existsc(options, "algorithm")) { char* algorithm; int plen; zend_bool pfree; algorithm = php_array_fetchc_string(options, "algorithm", &plen, &pfree); mongoc_client_encryption_encrypt_opts_set_algorithm(opts, algorithm); if (pfree) { efree(algorithm); } } if (php_array_existsc(options, "queryType")) { char* querytype; int plen; zend_bool pfree; querytype = php_array_fetchc_string(options, "queryType", &plen, &pfree); mongoc_client_encryption_encrypt_opts_set_query_type(opts, querytype); if (pfree) { efree(querytype); } } if (php_array_existsc(options, "rangeOpts")) { mongoc_client_encryption_encrypt_range_opts_t* range_opts; range_opts = phongo_clientencryption_encrypt_range_opts_from_zval(php_array_fetchc_deref(options, "rangeOpts")); if (!range_opts) { /* Exception already thrown */ goto cleanup; } mongoc_client_encryption_encrypt_opts_set_range_opts(opts, range_opts); mongoc_client_encryption_encrypt_range_opts_destroy(range_opts); } return opts; cleanup: if (opts) { mongoc_client_encryption_encrypt_opts_destroy(opts); } return NULL; } static void phongo_clientencryption_encrypt(php_phongo_clientencryption_t* clientencryption, zval* zvalue, zval* zciphertext, zval* options) { mongoc_client_encryption_encrypt_opts_t* opts = NULL; bson_value_t ciphertext = { 0 }; bson_value_t value = { 0 }; bson_error_t error = { 0 }; phongo_zval_to_bson_value(zvalue, &value); if (EG(exception)) { goto cleanup; } opts = phongo_clientencryption_encrypt_opts_from_zval(options); if (!opts) { /* Exception already thrown */ goto cleanup; } if (!mongoc_client_encryption_encrypt(clientencryption->client_encryption, &value, opts, &ciphertext, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } if (!phongo_bson_value_to_zval(&ciphertext, zciphertext)) { /* Exception already thrown */ goto cleanup; } cleanup: if (opts) { mongoc_client_encryption_encrypt_opts_destroy(opts); } bson_value_destroy(&ciphertext); bson_value_destroy(&value); } static void phongo_clientencryption_encrypt_expression(php_phongo_clientencryption_t* clientencryption, zval* zexpr, zval* return_value, zval* options) { mongoc_client_encryption_encrypt_opts_t* opts = NULL; bson_t expr = BSON_INITIALIZER; bson_t expr_encrypted = BSON_INITIALIZER; bson_error_t error = { 0 }; php_phongo_zval_to_bson(zexpr, PHONGO_BSON_NONE, &expr, NULL); if (EG(exception)) { goto cleanup; } opts = phongo_clientencryption_encrypt_opts_from_zval(options); if (!opts) { /* Exception already thrown */ goto cleanup; } if (!mongoc_client_encryption_encrypt_expression(clientencryption->client_encryption, &expr, opts, &expr_encrypted, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } if (!php_phongo_bson_to_zval(&expr_encrypted, return_value)) { /* Exception already thrown */ goto cleanup; } cleanup: if (opts) { mongoc_client_encryption_encrypt_opts_destroy(opts); } bson_destroy(&expr); bson_destroy(&expr_encrypted); } static void phongo_clientencryption_decrypt(php_phongo_clientencryption_t* clientencryption, zval* zciphertext, zval* zvalue) { bson_value_t ciphertext = { 0 }; bson_value_t value = { 0 }; bson_error_t error = { 0 }; phongo_zval_to_bson_value(zciphertext, &ciphertext); if (EG(exception)) { goto cleanup; } if (!mongoc_client_encryption_decrypt(clientencryption->client_encryption, &ciphertext, &value, &error)) { phongo_throw_exception_from_bson_error_t(&error); goto cleanup; } /** Use the legacy decoder to return PHP types instead of BSON types */ if (!phongo_bson_value_to_zval_legacy(&value, zvalue)) { /* Exception already thrown */ goto cleanup; } cleanup: bson_value_destroy(&ciphertext); bson_value_destroy(&value); } #else /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */ void phongo_clientencryption_init(php_phongo_clientencryption_t* intern, zval* options, zval* default_key_vault_client_manager) { phongo_throw_exception_no_cse(PHONGO_ERROR_RUNTIME, "Cannot configure clientEncryption object."); } static void phongo_clientencryption_create_datakey(php_phongo_clientencryption_t* clientencryption, zval* return_value, char* kms_provider, zval* options) { phongo_throw_exception_no_cse(PHONGO_ERROR_RUNTIME, "Cannot create encryption key."); } static void phongo_clientencryption_encrypt(php_phongo_clientencryption_t* clientencryption, zval* zvalue, zval* zciphertext, zval* options) { phongo_throw_exception_no_cse(PHONGO_ERROR_RUNTIME, "Cannot encrypt value."); } static void phongo_clientencryption_encrypt_expression(php_phongo_clientencryption_t* clientencryption, zval* zexpr, zval* return_value, zval* options) { phongo_throw_exception_no_cse(PHONGO_ERROR_RUNTIME, "Cannot encrypt expression."); } static void phongo_clientencryption_decrypt(php_phongo_clientencryption_t* clientencryption, zval* zciphertext, zval* zvalue) { phongo_throw_exception_no_cse(PHONGO_ERROR_RUNTIME, "Cannot decrypt value."); } #endif /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */ mongodb-1.21.0/src/MongoDB/ClientEncryption.h0000644000175100001660000000153414760300420015656 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_CLIENTENCRYPTION_H #define PHONGO_CLIENTENCRYPTION_H #include void phongo_clientencryption_init(php_phongo_clientencryption_t* intern, zval* options, zval* default_key_vault_client_manager); #endif /* PHONGO_CLIENTENCRYPTION_H */ mongodb-1.21.0/src/MongoDB/ClientEncryption_arginfo.h0000644000175100001660000002652614760300420017373 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 29a1460703051cab24abd6b42228c90928e18049 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_addKeyAltName, 0, 2, IS_OBJECT, 1) ZEND_ARG_OBJ_INFO(0, keyId, MongoDB\\BSON\\Binary, 0) ZEND_ARG_TYPE_INFO(0, keyAltName, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_createDataKey, 0, 1, MongoDB\\BSON\\Binary, 0) ZEND_ARG_TYPE_INFO(0, kmsProvider, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_decrypt, 0, 1, IS_MIXED, 0) ZEND_ARG_OBJ_INFO(0, value, MongoDB\\BSON\\Binary, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_deleteKey, 0, 1, IS_OBJECT, 0) ZEND_ARG_OBJ_INFO(0, keyId, MongoDB\\BSON\\Binary, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_encrypt, 0, 1, MongoDB\\BSON\\Binary, 0) ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_encryptExpression, 0, 1, IS_OBJECT, 0) ZEND_ARG_TYPE_MASK(0, expr, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_getKey, 0, 1, IS_OBJECT, 1) ZEND_ARG_OBJ_INFO(0, keyId, MongoDB\\BSON\\Binary, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_getKeyByAltName, 0, 1, IS_OBJECT, 1) ZEND_ARG_TYPE_INFO(0, keyAltName, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_getKeys, 0, 0, MongoDB\\Driver\\Cursor, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_ClientEncryption_removeKeyAltName arginfo_class_MongoDB_Driver_ClientEncryption_addKeyAltName ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ClientEncryption_rewrapManyDataKey, 0, 1, IS_OBJECT, 0) ZEND_ARG_TYPE_MASK(0, filter, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_ClientEncryption, __construct); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, addKeyAltName); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, createDataKey); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, decrypt); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, deleteKey); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, encrypt); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, encryptExpression); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, getKey); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, getKeyByAltName); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, getKeys); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, removeKeyAltName); static ZEND_METHOD(MongoDB_Driver_ClientEncryption, rewrapManyDataKey); static const zend_function_entry class_MongoDB_Driver_ClientEncryption_methods[] = { ZEND_ME(MongoDB_Driver_ClientEncryption, __construct, arginfo_class_MongoDB_Driver_ClientEncryption___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, addKeyAltName, arginfo_class_MongoDB_Driver_ClientEncryption_addKeyAltName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, createDataKey, arginfo_class_MongoDB_Driver_ClientEncryption_createDataKey, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, decrypt, arginfo_class_MongoDB_Driver_ClientEncryption_decrypt, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, deleteKey, arginfo_class_MongoDB_Driver_ClientEncryption_deleteKey, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, encrypt, arginfo_class_MongoDB_Driver_ClientEncryption_encrypt, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, encryptExpression, arginfo_class_MongoDB_Driver_ClientEncryption_encryptExpression, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, getKey, arginfo_class_MongoDB_Driver_ClientEncryption_getKey, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, getKeyByAltName, arginfo_class_MongoDB_Driver_ClientEncryption_getKeyByAltName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, getKeys, arginfo_class_MongoDB_Driver_ClientEncryption_getKeys, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, removeKeyAltName, arginfo_class_MongoDB_Driver_ClientEncryption_removeKeyAltName, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ClientEncryption, rewrapManyDataKey, arginfo_class_MongoDB_Driver_ClientEncryption_rewrapManyDataKey, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_ClientEncryption(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "ClientEncryption", class_MongoDB_Driver_ClientEncryption_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; zval const_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC_value; zend_string *const_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC_value_str = zend_string_init(MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, strlen(MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC), 1); ZVAL_STR(&const_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC_value, const_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC_value_str); zend_string *const_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC_name = zend_string_init_interned("AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC", sizeof("AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC") - 1, 1); zend_declare_class_constant_ex(class_entry, const_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC_name, &const_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC_name); zval const_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM_value; zend_string *const_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM_value_str = zend_string_init(MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM, strlen(MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM), 1); ZVAL_STR(&const_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM_value, const_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM_value_str); zend_string *const_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM_name = zend_string_init_interned("AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM", sizeof("AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM") - 1, 1); zend_declare_class_constant_ex(class_entry, const_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM_name, &const_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM_name); zval const_ALGORITHM_INDEXED_value; zend_string *const_ALGORITHM_INDEXED_value_str = zend_string_init(MONGOC_ENCRYPT_ALGORITHM_INDEXED, strlen(MONGOC_ENCRYPT_ALGORITHM_INDEXED), 1); ZVAL_STR(&const_ALGORITHM_INDEXED_value, const_ALGORITHM_INDEXED_value_str); zend_string *const_ALGORITHM_INDEXED_name = zend_string_init_interned("ALGORITHM_INDEXED", sizeof("ALGORITHM_INDEXED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_ALGORITHM_INDEXED_name, &const_ALGORITHM_INDEXED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_ALGORITHM_INDEXED_name); zval const_ALGORITHM_UNINDEXED_value; zend_string *const_ALGORITHM_UNINDEXED_value_str = zend_string_init(MONGOC_ENCRYPT_ALGORITHM_UNINDEXED, strlen(MONGOC_ENCRYPT_ALGORITHM_UNINDEXED), 1); ZVAL_STR(&const_ALGORITHM_UNINDEXED_value, const_ALGORITHM_UNINDEXED_value_str); zend_string *const_ALGORITHM_UNINDEXED_name = zend_string_init_interned("ALGORITHM_UNINDEXED", sizeof("ALGORITHM_UNINDEXED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_ALGORITHM_UNINDEXED_name, &const_ALGORITHM_UNINDEXED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_ALGORITHM_UNINDEXED_name); zval const_ALGORITHM_RANGE_value; zend_string *const_ALGORITHM_RANGE_value_str = zend_string_init(MONGOC_ENCRYPT_ALGORITHM_RANGE, strlen(MONGOC_ENCRYPT_ALGORITHM_RANGE), 1); ZVAL_STR(&const_ALGORITHM_RANGE_value, const_ALGORITHM_RANGE_value_str); zend_string *const_ALGORITHM_RANGE_name = zend_string_init_interned("ALGORITHM_RANGE", sizeof("ALGORITHM_RANGE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_ALGORITHM_RANGE_name, &const_ALGORITHM_RANGE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_ALGORITHM_RANGE_name); zval const_ALGORITHM_RANGE_PREVIEW_value; zend_string *const_ALGORITHM_RANGE_PREVIEW_value_str = zend_string_init(MONGOC_ENCRYPT_ALGORITHM_RANGEPREVIEW, strlen(MONGOC_ENCRYPT_ALGORITHM_RANGEPREVIEW), 1); ZVAL_STR(&const_ALGORITHM_RANGE_PREVIEW_value, const_ALGORITHM_RANGE_PREVIEW_value_str); zend_string *const_ALGORITHM_RANGE_PREVIEW_name = zend_string_init_interned("ALGORITHM_RANGE_PREVIEW", sizeof("ALGORITHM_RANGE_PREVIEW") - 1, 1); zend_declare_class_constant_ex(class_entry, const_ALGORITHM_RANGE_PREVIEW_name, &const_ALGORITHM_RANGE_PREVIEW_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL); zend_string_release(const_ALGORITHM_RANGE_PREVIEW_name); zval const_QUERY_TYPE_EQUALITY_value; zend_string *const_QUERY_TYPE_EQUALITY_value_str = zend_string_init(MONGOC_ENCRYPT_QUERY_TYPE_EQUALITY, strlen(MONGOC_ENCRYPT_QUERY_TYPE_EQUALITY), 1); ZVAL_STR(&const_QUERY_TYPE_EQUALITY_value, const_QUERY_TYPE_EQUALITY_value_str); zend_string *const_QUERY_TYPE_EQUALITY_name = zend_string_init_interned("QUERY_TYPE_EQUALITY", sizeof("QUERY_TYPE_EQUALITY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_QUERY_TYPE_EQUALITY_name, &const_QUERY_TYPE_EQUALITY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_QUERY_TYPE_EQUALITY_name); zval const_QUERY_TYPE_RANGE_value; zend_string *const_QUERY_TYPE_RANGE_value_str = zend_string_init(MONGOC_ENCRYPT_QUERY_TYPE_RANGE, strlen(MONGOC_ENCRYPT_QUERY_TYPE_RANGE), 1); ZVAL_STR(&const_QUERY_TYPE_RANGE_value, const_QUERY_TYPE_RANGE_value_str); zend_string *const_QUERY_TYPE_RANGE_name = zend_string_init_interned("QUERY_TYPE_RANGE", sizeof("QUERY_TYPE_RANGE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_QUERY_TYPE_RANGE_name, &const_QUERY_TYPE_RANGE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_QUERY_TYPE_RANGE_name); zval const_QUERY_TYPE_RANGE_PREVIEW_value; zend_string *const_QUERY_TYPE_RANGE_PREVIEW_value_str = zend_string_init(MONGOC_ENCRYPT_QUERY_TYPE_RANGEPREVIEW, strlen(MONGOC_ENCRYPT_QUERY_TYPE_RANGEPREVIEW), 1); ZVAL_STR(&const_QUERY_TYPE_RANGE_PREVIEW_value, const_QUERY_TYPE_RANGE_PREVIEW_value_str); zend_string *const_QUERY_TYPE_RANGE_PREVIEW_name = zend_string_init_interned("QUERY_TYPE_RANGE_PREVIEW", sizeof("QUERY_TYPE_RANGE_PREVIEW") - 1, 1); zend_declare_class_constant_ex(class_entry, const_QUERY_TYPE_RANGE_PREVIEW_name, &const_QUERY_TYPE_RANGE_PREVIEW_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL); zend_string_release(const_QUERY_TYPE_RANGE_PREVIEW_name); return class_entry; } mongodb-1.21.0/src/MongoDB/Command.c0000644000175100001660000001212414760300420013733 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "Command_arginfo.h" zend_class_entry* php_phongo_command_ce; /* Initialize the "maxAwaitTimeMS" option. Returns true on success; otherwise, * false is returned and an exception is thrown. * * The "maxAwaitTimeMS" option is assigned to the cursor after query execution * via mongoc_cursor_set_max_await_time_ms(). */ static bool php_phongo_command_init_max_await_time_ms(php_phongo_command_t* intern, zval* options) { int64_t max_await_time_ms; if (!php_array_existsc(options, "maxAwaitTimeMS")) { return true; } max_await_time_ms = php_array_fetchc_long(options, "maxAwaitTimeMS"); if (max_await_time_ms < 0) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"maxAwaitTimeMS\" option to be >= 0, %" PRId64 " given", max_await_time_ms); return false; } if (max_await_time_ms > UINT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"maxAwaitTimeMS\" option to be <= %" PRIu32 ", %" PRId64 " given", UINT32_MAX, max_await_time_ms); return false; } intern->max_await_time_ms = (uint32_t) max_await_time_ms; return true; } /* Initializes the php_phongo_command_init from options argument. This * function will fall back to a modifier in the absence of a top-level option * (where applicable). */ static bool php_phongo_command_init(php_phongo_command_t* intern, zval* filter, zval* options) { bson_iter_t iter; bson_iter_t sub_iter; intern->bson = bson_new(); intern->batch_size = 0; intern->max_await_time_ms = 0; php_phongo_zval_to_bson(filter, PHONGO_BSON_NONE, intern->bson, NULL); /* Note: if any exceptions are thrown, we can simply return as PHP will * invoke php_phongo_query_free_object to destruct the object. */ if (EG(exception)) { return false; } if (bson_iter_init(&iter, intern->bson) && bson_iter_find_descendant(&iter, "cursor.batchSize", &sub_iter) && BSON_ITER_HOLDS_INT(&sub_iter)) { int64_t batch_size = bson_iter_as_int64(&sub_iter); if (batch_size >= 0 && batch_size <= UINT32_MAX) { intern->batch_size = (uint32_t) batch_size; } } if (!options) { return true; } if (!php_phongo_command_init_max_await_time_ms(intern, options)) { return false; } return true; } /* Constructs a new Command */ static PHP_METHOD(MongoDB_Driver_Command, __construct) { php_phongo_command_t* intern; zval* document; zval* options = NULL; intern = Z_COMMAND_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ARRAY_OR_OBJECT(document) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); php_phongo_command_init(intern, document, options); } /* MongoDB\Driver\Command object handlers */ static zend_object_handlers php_phongo_handler_command; static void php_phongo_command_free_object(zend_object* object) { php_phongo_command_t* intern = Z_OBJ_COMMAND(object); zend_object_std_dtor(&intern->std); if (intern->bson) { bson_clear(&intern->bson); } } static zend_object* php_phongo_command_create_object(zend_class_entry* class_type) { php_phongo_command_t* intern = zend_object_alloc(sizeof(php_phongo_command_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_command; return &intern->std; } static HashTable* php_phongo_command_get_debug_info(zend_object* object, int* is_temp) { php_phongo_command_t* intern; zval retval = ZVAL_STATIC_INIT; *is_temp = 1; intern = Z_OBJ_COMMAND(object); array_init_size(&retval, 1); if (intern->bson) { zval zv; if (!php_phongo_bson_to_zval(intern->bson, &zv)) { zval_ptr_dtor(&zv); goto done; } ADD_ASSOC_ZVAL_EX(&retval, "command", &zv); } else { ADD_ASSOC_NULL_EX(&retval, "command"); } done: return Z_ARRVAL(retval); } void php_phongo_command_init_ce(INIT_FUNC_ARGS) { php_phongo_command_ce = register_class_MongoDB_Driver_Command(); php_phongo_command_ce->create_object = php_phongo_command_create_object; memcpy(&php_phongo_handler_command, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_command.get_debug_info = php_phongo_command_get_debug_info; php_phongo_handler_command.free_obj = php_phongo_command_free_object; php_phongo_handler_command.offset = XtOffsetOf(php_phongo_command_t, std); } mongodb-1.21.0/src/MongoDB/Command_arginfo.h0000644000175100001660000000175414760300420015454 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: e613d505cab7a354e0e6b1e0395933169891021f */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Command___construct, 0, 0, 1) ZEND_ARG_TYPE_MASK(0, document, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, commandOptions, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Command, __construct); static const zend_function_entry class_MongoDB_Driver_Command_methods[] = { ZEND_ME(MongoDB_Driver_Command, __construct, arginfo_class_MongoDB_Driver_Command___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Command(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "Command", class_MongoDB_Driver_Command_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Cursor.c0000644000175100001660000003557514760300420013651 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include "php_phongo.h" #include "phongo_bson.h" #include "phongo_client.h" #include "phongo_error.h" #include "phongo_util.h" #include "MongoDB/Cursor.h" #include "MongoDB/Server.h" #include "Cursor_arginfo.h" zend_class_entry* php_phongo_cursor_ce; /* Check if the cursor is exhausted (i.e. ID is zero) and free any reference to * the session. Calling this function during iteration will allow an implicit * session to return to the pool immediately after a getMore indicates that the * server has no more results to return. */ static void php_phongo_cursor_free_session_if_exhausted(php_phongo_cursor_t* cursor) { if (mongoc_cursor_get_id(cursor->cursor)) { return; } if (!Z_ISUNDEF(cursor->session)) { zval_ptr_dtor(&cursor->session); ZVAL_UNDEF(&cursor->session); } } static void php_phongo_cursor_free_current(php_phongo_cursor_t* cursor) { if (!Z_ISUNDEF(cursor->visitor_data.zchild)) { zval_ptr_dtor(&cursor->visitor_data.zchild); ZVAL_UNDEF(&cursor->visitor_data.zchild); } } /* Sets a type map to use for BSON unserialization */ static PHP_METHOD(MongoDB_Driver_Cursor, setTypeMap) { php_phongo_cursor_t* intern; php_phongo_bson_state state; zval* typemap = NULL; bool restore_current_element = false; PHONGO_BSON_INIT_STATE(state); intern = Z_CURSOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY_OR_NULL(typemap) PHONGO_PARSE_PARAMETERS_END(); if (!php_phongo_bson_typemap_to_state(typemap, &state.map)) { return; } /* Check if the existing element needs to be freed before we overwrite * visitor_data, which contains the only reference to it. */ if (!Z_ISUNDEF(intern->visitor_data.zchild)) { php_phongo_cursor_free_current(intern); restore_current_element = true; } php_phongo_bson_typemap_dtor(&intern->visitor_data.map); intern->visitor_data = state; /* If the cursor has a current element, we just freed it and should restore * it with a new type map applied. */ if (restore_current_element && mongoc_cursor_current(intern->cursor)) { const bson_t* doc = mongoc_cursor_current(intern->cursor); if (!php_phongo_bson_to_zval_ex(doc, &intern->visitor_data)) { php_phongo_cursor_free_current(intern); } } } static int php_phongo_cursor_to_array_apply(zend_object_iterator* iter, void* puser) { zval* data; zval* return_value = (zval*) puser; data = iter->funcs->get_current_data(iter); if (EG(exception)) { return ZEND_HASH_APPLY_STOP; } if (Z_ISUNDEF_P(data)) { return ZEND_HASH_APPLY_STOP; } Z_TRY_ADDREF_P(data); add_next_index_zval(return_value, data); return ZEND_HASH_APPLY_KEEP; } static void php_phongo_cursor_id_new_from_id(zval* object, int64_t cursorid) { php_phongo_cursorid_t* intern; object_init_ex(object, php_phongo_cursorid_ce); intern = Z_CURSORID_OBJ_P(object); intern->id = cursorid; intern->initialized = true; } /* Returns an array of all result documents for this cursor */ static PHP_METHOD(MongoDB_Driver_Cursor, toArray) { PHONGO_PARSE_PARAMETERS_NONE(); array_init(return_value); if (spl_iterator_apply(getThis(), php_phongo_cursor_to_array_apply, (void*) return_value) != SUCCESS) { zval_dtor(return_value); RETURN_NULL(); } } /* Returns the CursorId for this cursor */ static PHP_METHOD(MongoDB_Driver_Cursor, getId) { php_phongo_cursor_t* intern; zend_bool asInt64 = false; intern = Z_CURSOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_BOOL(asInt64) PHONGO_PARSE_PARAMETERS_END(); if (asInt64) { phongo_int64_new(return_value, mongoc_cursor_get_id(intern->cursor)); } else { php_error_docref(NULL, E_DEPRECATED, "The method \"MongoDB\\Driver\\Cursor::getId\" will no longer return a \"MongoDB\\Driver\\CursorId\" instance in the future. Pass \"true\" as argument to change to the new behavior and receive a \"MongoDB\\BSON\\Int64\" instance instead."); php_phongo_cursor_id_new_from_id(return_value, mongoc_cursor_get_id(intern->cursor)); } } /* Returns the Server object to which this cursor is attached */ static PHP_METHOD(MongoDB_Driver_Cursor, getServer) { php_phongo_cursor_t* intern; intern = Z_CURSOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_server_init(return_value, &intern->manager, intern->server_id); } /* Checks if a cursor is still alive */ static PHP_METHOD(MongoDB_Driver_Cursor, isDead) { php_phongo_cursor_t* intern; intern = Z_CURSOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_BOOL(!mongoc_cursor_more(intern->cursor)); } static PHP_METHOD(MongoDB_Driver_Cursor, current) { php_phongo_cursor_t* intern = Z_CURSOR_OBJ_P(getThis()); zval* data; PHONGO_PARSE_PARAMETERS_NONE(); data = &intern->visitor_data.zchild; if (Z_ISUNDEF_P(data)) { RETURN_NULL(); } else { ZVAL_COPY_DEREF(return_value, data); } } static PHP_METHOD(MongoDB_Driver_Cursor, key) { php_phongo_cursor_t* intern = Z_CURSOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (Z_ISUNDEF(intern->visitor_data.zchild)) { RETURN_NULL(); } RETURN_LONG(intern->current); } static PHP_METHOD(MongoDB_Driver_Cursor, next) { php_phongo_cursor_t* intern = Z_CURSOR_OBJ_P(getThis()); const bson_t* doc; PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_cursor_free_current(intern); /* If the intern has already advanced, increment its position. Otherwise, * the first call to mongoc_cursor_next() will be made below and we should * leave its position at zero. */ if (intern->advanced) { intern->current++; } else { intern->advanced = true; } if (mongoc_cursor_next(intern->cursor, &doc)) { if (!php_phongo_bson_to_zval_ex(doc, &intern->visitor_data)) { /* Free invalid result, but don't return as we want to free the * session if the intern is exhausted. */ php_phongo_cursor_free_current(intern); } } else { bson_error_t error = { 0 }; const bson_t* doc = NULL; if (mongoc_cursor_error_document(intern->cursor, &error, &doc)) { /* Intentionally not destroying the intern as it will happen * naturally now that there are no more results */ phongo_throw_exception_from_bson_error_t_and_reply(&error, doc); } } php_phongo_cursor_free_session_if_exhausted(intern); } static PHP_METHOD(MongoDB_Driver_Cursor, valid) { php_phongo_cursor_t* intern = Z_CURSOR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_BOOL(!Z_ISUNDEF(intern->visitor_data.zchild)); } static PHP_METHOD(MongoDB_Driver_Cursor, rewind) { php_phongo_cursor_t* intern = Z_CURSOR_OBJ_P(getThis()); const bson_t* doc; PHONGO_PARSE_PARAMETERS_NONE(); /* If the cursor was never advanced (e.g. command cursor), do so now */ if (!intern->advanced) { intern->advanced = true; if (!phongo_cursor_advance_and_check_for_error(intern->cursor)) { /* Exception should already have been thrown */ return; } } if (intern->current > 0) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Cursors cannot rewind after starting iteration"); return; } php_phongo_cursor_free_current(intern); doc = mongoc_cursor_current(intern->cursor); if (doc) { if (!php_phongo_bson_to_zval_ex(doc, &intern->visitor_data)) { /* Free invalid result, but don't return as we want to free the * session if the intern is exhausted. */ php_phongo_cursor_free_current(intern); } } php_phongo_cursor_free_session_if_exhausted(intern); } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Cursor) /* MongoDB\Driver\Cursor object handlers */ static zend_object_handlers php_phongo_handler_cursor; static void php_phongo_cursor_free_object(zend_object* object) { php_phongo_cursor_t* intern = Z_OBJ_CURSOR(object); zend_object_std_dtor(&intern->std); /* If this Cursor was created in a different process, reset the client so * that mongoc_cursor_destroy does not issue a killCursors command for an * active cursor owned by a parent process. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager)); if (intern->cursor) { mongoc_cursor_destroy(intern->cursor); } if (intern->database) { efree(intern->database); } if (intern->collection) { efree(intern->collection); } if (!Z_ISUNDEF(intern->query)) { zval_ptr_dtor(&intern->query); } if (!Z_ISUNDEF(intern->command)) { zval_ptr_dtor(&intern->command); } if (!Z_ISUNDEF(intern->read_preference)) { zval_ptr_dtor(&intern->read_preference); } if (!Z_ISUNDEF(intern->session)) { zval_ptr_dtor(&intern->session); } if (!Z_ISUNDEF(intern->manager)) { zval_ptr_dtor(&intern->manager); } php_phongo_bson_typemap_dtor(&intern->visitor_data.map); php_phongo_cursor_free_current(intern); } static zend_object* php_phongo_cursor_create_object(zend_class_entry* class_type) { php_phongo_cursor_t* intern = zend_object_alloc(sizeof(php_phongo_cursor_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); PHONGO_SET_CREATED_BY_PID(intern); intern->std.handlers = &php_phongo_handler_cursor; return &intern->std; } static HashTable* php_phongo_cursor_get_debug_info(zend_object* object, int* is_temp) { php_phongo_cursor_t* intern; zval retval = ZVAL_STATIC_INIT; *is_temp = 1; intern = Z_OBJ_CURSOR(object); array_init_size(&retval, 10); if (intern->database) { ADD_ASSOC_STRING(&retval, "database", intern->database); } else { ADD_ASSOC_NULL_EX(&retval, "database"); } if (intern->collection) { ADD_ASSOC_STRING(&retval, "collection", intern->collection); } else { ADD_ASSOC_NULL_EX(&retval, "collection"); } if (!Z_ISUNDEF(intern->query)) { ADD_ASSOC_ZVAL_EX(&retval, "query", &intern->query); Z_ADDREF(intern->query); } else { ADD_ASSOC_NULL_EX(&retval, "query"); } if (!Z_ISUNDEF(intern->command)) { ADD_ASSOC_ZVAL_EX(&retval, "command", &intern->command); Z_ADDREF(intern->command); } else { ADD_ASSOC_NULL_EX(&retval, "command"); } if (!Z_ISUNDEF(intern->read_preference)) { ADD_ASSOC_ZVAL_EX(&retval, "readPreference", &intern->read_preference); Z_ADDREF(intern->read_preference); } else { ADD_ASSOC_NULL_EX(&retval, "readPreference"); } if (!Z_ISUNDEF(intern->session)) { ADD_ASSOC_ZVAL_EX(&retval, "session", &intern->session); Z_ADDREF(intern->session); } else { ADD_ASSOC_NULL_EX(&retval, "session"); } ADD_ASSOC_BOOL_EX(&retval, "isDead", !mongoc_cursor_more(intern->cursor)); ADD_ASSOC_LONG_EX(&retval, "currentIndex", intern->current); if (!Z_ISUNDEF(intern->visitor_data.zchild)) { ADD_ASSOC_ZVAL_EX(&retval, "currentDocument", &intern->visitor_data.zchild); Z_ADDREF(intern->visitor_data.zchild); } else { ADD_ASSOC_NULL_EX(&retval, "currentDocument"); } { zval server; phongo_server_init(&server, &intern->manager, intern->server_id); ADD_ASSOC_ZVAL_EX(&retval, "server", &server); } return Z_ARRVAL(retval); } void php_phongo_cursor_init_ce(INIT_FUNC_ARGS) { php_phongo_cursor_ce = register_class_MongoDB_Driver_Cursor(zend_ce_iterator, php_phongo_cursor_interface_ce); php_phongo_cursor_ce->create_object = php_phongo_cursor_create_object; memcpy(&php_phongo_handler_cursor, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_cursor.get_debug_info = php_phongo_cursor_get_debug_info; php_phongo_handler_cursor.free_obj = php_phongo_cursor_free_object; php_phongo_handler_cursor.offset = XtOffsetOf(php_phongo_cursor_t, std); } static void phongo_cursor_init(zval* return_value, zval* manager, mongoc_cursor_t* cursor, zval* readPreference, zval* session) { php_phongo_cursor_t* intern; object_init_ex(return_value, php_phongo_cursor_ce); intern = Z_CURSOR_OBJ_P(return_value); intern->cursor = cursor; intern->server_id = mongoc_cursor_get_server_id(cursor); intern->advanced = false; intern->current = 0; ZVAL_ZVAL(&intern->manager, manager, 1, 0); if (readPreference) { ZVAL_ZVAL(&intern->read_preference, readPreference, 1, 0); } if (session) { ZVAL_ZVAL(&intern->session, session, 1, 0); } } /* Initialize the cursor for a query and return whether there is an error. This * function always returns true. */ bool phongo_cursor_init_for_command(zval* return_value, zval* manager, mongoc_cursor_t* cursor, const char* db, zval* command, zval* readPreference, zval* session) { php_phongo_cursor_t* intern; phongo_cursor_init(return_value, manager, cursor, readPreference, session); intern = Z_CURSOR_OBJ_P(return_value); intern->database = estrdup(db); ZVAL_ZVAL(&intern->command, command, 1, 0); return true; } /* Initialize the cursor for a query and return whether there is an error. The * libmongoc cursor will be advanced once. On error, false is returned and an * exception is thrown. */ bool phongo_cursor_init_for_query(zval* return_value, zval* manager, mongoc_cursor_t* cursor, const char* namespace, zval* query, zval* readPreference, zval* session) { php_phongo_cursor_t* intern; /* Advancing the cursor before phongo_cursor_init ensures that a server * stream is obtained before mongoc_cursor_get_server_id() is called. */ if (!phongo_cursor_advance_and_check_for_error(cursor)) { /* Exception should already have been thrown */ return false; } phongo_cursor_init(return_value, manager, cursor, readPreference, session); intern = Z_CURSOR_OBJ_P(return_value); intern->advanced = true; /* The namespace should already have been validated, but we'll still check * for an error and throw accordingly. */ if (!phongo_split_namespace(namespace, &intern->database, &intern->collection)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Cannot initialize cursor with invalid namespace: %s", namespace); zval_ptr_dtor(return_value); return false; } ZVAL_ZVAL(&intern->query, query, 1, 0); return true; } /* Advance the cursor and return whether there is an error. On error, false is * returned and an exception is thrown. */ bool phongo_cursor_advance_and_check_for_error(mongoc_cursor_t* cursor) { const bson_t* doc = NULL; if (!mongoc_cursor_next(cursor, &doc)) { bson_error_t error = { 0 }; /* Check for connection related exceptions */ if (EG(exception)) { return false; } /* Could simply be no docs, which is not an error */ if (mongoc_cursor_error_document(cursor, &error, &doc)) { phongo_throw_exception_from_bson_error_t_and_reply(&error, doc); return false; } } return true; } mongodb-1.21.0/src/MongoDB/Cursor.h0000644000175100001660000000216014760300420013636 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_CURSOR_H #define PHONGO_CURSOR_H #include "mongoc/mongoc.h" #include bool phongo_cursor_init_for_command(zval* return_value, zval* manager, mongoc_cursor_t* cursor, const char* db, zval* command, zval* readPreference, zval* session); bool phongo_cursor_init_for_query(zval* return_value, zval* manager, mongoc_cursor_t* cursor, const char* namespace, zval* query, zval* readPreference, zval* session); bool phongo_cursor_advance_and_check_for_error(mongoc_cursor_t* cursor); #endif /* PHONGO_CURSOR_H */ mongodb-1.21.0/src/MongoDB/CursorId.c0000644000175100001660000001611614760300420014114 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "phongo_util.h" #include "CursorId_arginfo.h" zend_class_entry* php_phongo_cursorid_ce; /* Initialize the object from a numeric string and return whether it was * successful. An exception will be thrown on error. */ static bool php_phongo_cursorid_init_from_string(php_phongo_cursorid_t* intern, const char* s_id, size_t s_id_len) { int64_t id; if (!php_phongo_parse_int64(&id, s_id, s_id_len)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing \"%s\" as 64-bit id for %s initialization", s_id, ZSTR_VAL(php_phongo_cursorid_ce->name)); return false; } intern->id = id; intern->initialized = true; return true; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_cursorid_init_from_hash(php_phongo_cursorid_t* intern, HashTable* props) { zval* value; if ((value = zend_hash_str_find(props, "id", sizeof("id") - 1)) && Z_TYPE_P(value) == IS_STRING) { return php_phongo_cursorid_init_from_string(intern, Z_STRVAL_P(value), Z_STRLEN_P(value)); } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"id\" string field", ZSTR_VAL(php_phongo_cursorid_ce->name)); return false; } static HashTable* php_phongo_cursorid_get_properties_hash(zend_object* object, bool is_temp, bool is_serialize) { php_phongo_cursorid_t* intern; HashTable* props; intern = Z_OBJ_CURSORID(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 1); if (!intern->initialized) { return props; } { zval value; if (is_serialize) { ZVAL_INT64_STRING(&value, intern->id); } else { #if SIZEOF_ZEND_LONG == 4 if (intern->id > INT32_MAX || intern->id < INT32_MIN) { ZVAL_INT64_STRING(&value, intern->id); } else { ZVAL_LONG(&value, intern->id); } #else ZVAL_LONG(&value, intern->id); #endif } zend_hash_str_update(props, "id", sizeof("id") - 1, &value); } return props; } PHP_METHOD(MongoDB_Driver_CursorId, __set_state) { php_phongo_cursorid_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_cursorid_ce); intern = Z_CURSORID_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_cursorid_init_from_hash(intern, props); } /* Returns the string representation of the CursorId */ PHP_METHOD(MongoDB_Driver_CursorId, __toString) { php_phongo_cursorid_t* intern; char* tmp; int tmp_len; intern = Z_CURSORID_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); tmp_len = spprintf(&tmp, 0, "%" PRId64, intern->id); RETVAL_STRINGL(tmp, tmp_len); efree(tmp); } PHP_METHOD(MongoDB_Driver_CursorId, serialize) { php_phongo_cursorid_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_CURSORID_OBJ_P(getThis()); array_init_size(&retval, 1); ADD_ASSOC_INT64_AS_STRING(&retval, "id", intern->id); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } PHP_METHOD(MongoDB_Driver_CursorId, unserialize) { php_phongo_cursorid_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_CURSORID_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_cursorid_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_cursorid_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } PHP_METHOD(MongoDB_Driver_CursorId, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_cursorid_get_properties_hash(Z_OBJ_P(getThis()), true, true)); } PHP_METHOD(MongoDB_Driver_CursorId, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_cursorid_init_from_hash(Z_CURSORID_OBJ_P(getThis()), Z_ARRVAL_P(data)); } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_CursorId) /* MongoDB\Driver\CursorId object handlers */ static zend_object_handlers php_phongo_handler_cursorid; static void php_phongo_cursorid_free_object(zend_object* object) { php_phongo_cursorid_t* intern = Z_OBJ_CURSORID(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } } static zend_object* php_phongo_cursorid_create_object(zend_class_entry* class_type) { php_phongo_cursorid_t* intern = zend_object_alloc(sizeof(php_phongo_cursorid_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_cursorid; return &intern->std; } static HashTable* php_phongo_cursorid_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_cursorid_get_properties_hash(object, true, false); } static HashTable* php_phongo_cursorid_get_properties(zend_object* object) { return php_phongo_cursorid_get_properties_hash(object, false, false); } void php_phongo_cursorid_init_ce(INIT_FUNC_ARGS) { php_phongo_cursorid_ce = register_class_MongoDB_Driver_CursorId(zend_ce_serializable, zend_ce_stringable); php_phongo_cursorid_ce->create_object = php_phongo_cursorid_create_object; memcpy(&php_phongo_handler_cursorid, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_cursorid.get_debug_info = php_phongo_cursorid_get_debug_info; php_phongo_handler_cursorid.get_properties = php_phongo_cursorid_get_properties; php_phongo_handler_cursorid.free_obj = php_phongo_cursorid_free_object; php_phongo_handler_cursorid.offset = XtOffsetOf(php_phongo_cursorid_t, std); } mongodb-1.21.0/src/MongoDB/CursorId_arginfo.h0000644000175100001660000000576614760300420015637 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: f7c25df9cd8a81f89ac604821bae4a807d68ad78 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_CursorId___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_CursorId___set_state, 0, 1, MongoDB\\Driver\\CursorId, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_CursorId___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_CursorId_serialize arginfo_class_MongoDB_Driver_CursorId___toString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_CursorId_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_CursorId___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_CursorId___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_CursorId, __construct); static ZEND_METHOD(MongoDB_Driver_CursorId, __set_state); static ZEND_METHOD(MongoDB_Driver_CursorId, __toString); static ZEND_METHOD(MongoDB_Driver_CursorId, serialize); static ZEND_METHOD(MongoDB_Driver_CursorId, unserialize); static ZEND_METHOD(MongoDB_Driver_CursorId, __unserialize); static ZEND_METHOD(MongoDB_Driver_CursorId, __serialize); static const zend_function_entry class_MongoDB_Driver_CursorId_methods[] = { ZEND_ME(MongoDB_Driver_CursorId, __construct, arginfo_class_MongoDB_Driver_CursorId___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_CursorId, __set_state, arginfo_class_MongoDB_Driver_CursorId___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_CursorId, __toString, arginfo_class_MongoDB_Driver_CursorId___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_CursorId, serialize, arginfo_class_MongoDB_Driver_CursorId_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_CursorId, unserialize, arginfo_class_MongoDB_Driver_CursorId_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_CursorId, __unserialize, arginfo_class_MongoDB_Driver_CursorId___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_CursorId, __serialize, arginfo_class_MongoDB_Driver_CursorId___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_CursorId(zend_class_entry *class_entry_Serializable, zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "CursorId", class_MongoDB_Driver_CursorId_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 2, class_entry_Serializable, class_entry_Stringable); return class_entry; } mongodb-1.21.0/src/MongoDB/CursorInterface.c0000644000175100001660000000164414760300420015460 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include #include #include "php_phongo.h" #include "CursorInterface_arginfo.h" zend_class_entry* php_phongo_cursor_interface_ce; void php_phongo_cursor_interface_init_ce(INIT_FUNC_ARGS) { php_phongo_cursor_interface_ce = register_class_MongoDB_Driver_CursorInterface(zend_ce_traversable); } mongodb-1.21.0/src/MongoDB/CursorInterface_arginfo.h0000644000175100001660000000431414760300420017167 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 95f356a63692e1bb72d50c641e93a53113c43531 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_MongoDB_Driver_CursorInterface_getId, 0, 0, MongoDB\\Driver\\CursorId|MongoDB\\BSON\\Int64, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_CursorInterface_getServer, 0, 0, MongoDB\\Driver\\Server, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_CursorInterface_isDead, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_CursorInterface_setTypeMap, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, typemap, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_CursorInterface_toArray, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() static const zend_function_entry class_MongoDB_Driver_CursorInterface_methods[] = { ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_CursorInterface, getId, arginfo_class_MongoDB_Driver_CursorInterface_getId, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_CursorInterface, getServer, arginfo_class_MongoDB_Driver_CursorInterface_getServer, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_CursorInterface, isDead, arginfo_class_MongoDB_Driver_CursorInterface_isDead, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_CursorInterface, setTypeMap, arginfo_class_MongoDB_Driver_CursorInterface_setTypeMap, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_ABSTRACT_ME_WITH_FLAGS(MongoDB_Driver_CursorInterface, toArray, arginfo_class_MongoDB_Driver_CursorInterface_toArray, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_CursorInterface(zend_class_entry *class_entry_Traversable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "CursorInterface", class_MongoDB_Driver_CursorInterface_methods); class_entry = zend_register_internal_interface(&ce); zend_class_implements(class_entry, 1, class_entry_Traversable); return class_entry; } mongodb-1.21.0/src/MongoDB/Cursor_arginfo.h0000644000175100001660000000771414760300420015355 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: c2927c5d481f305b1579a8968eeecc39ba921ddd */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Cursor___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_MongoDB_Driver_Cursor_current, 0, 0, MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_MongoDB_Driver_Cursor_getId, 0, 0, MongoDB\\Driver\\CursorId|MongoDB\\BSON\\Int64, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, asInt64, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Cursor_getServer, 0, 0, MongoDB\\Driver\\Server, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Cursor_isDead, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Cursor_key, 0, 0, IS_LONG, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Cursor_next, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Cursor_rewind arginfo_class_MongoDB_Driver_Cursor_next ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Cursor_setTypeMap, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, typemap, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Cursor_toArray, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Cursor_valid arginfo_class_MongoDB_Driver_Cursor_isDead static ZEND_METHOD(MongoDB_Driver_Cursor, __construct); static ZEND_METHOD(MongoDB_Driver_Cursor, current); static ZEND_METHOD(MongoDB_Driver_Cursor, getId); static ZEND_METHOD(MongoDB_Driver_Cursor, getServer); static ZEND_METHOD(MongoDB_Driver_Cursor, isDead); static ZEND_METHOD(MongoDB_Driver_Cursor, key); static ZEND_METHOD(MongoDB_Driver_Cursor, next); static ZEND_METHOD(MongoDB_Driver_Cursor, rewind); static ZEND_METHOD(MongoDB_Driver_Cursor, setTypeMap); static ZEND_METHOD(MongoDB_Driver_Cursor, toArray); static ZEND_METHOD(MongoDB_Driver_Cursor, valid); static const zend_function_entry class_MongoDB_Driver_Cursor_methods[] = { ZEND_ME(MongoDB_Driver_Cursor, __construct, arginfo_class_MongoDB_Driver_Cursor___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Cursor, current, arginfo_class_MongoDB_Driver_Cursor_current, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_Driver_Cursor, getId, arginfo_class_MongoDB_Driver_Cursor_getId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Cursor, getServer, arginfo_class_MongoDB_Driver_Cursor_getServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Cursor, isDead, arginfo_class_MongoDB_Driver_Cursor_isDead, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Cursor, key, arginfo_class_MongoDB_Driver_Cursor_key, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_Driver_Cursor, next, arginfo_class_MongoDB_Driver_Cursor_next, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_Driver_Cursor, rewind, arginfo_class_MongoDB_Driver_Cursor_rewind, ZEND_ACC_PUBLIC) ZEND_ME(MongoDB_Driver_Cursor, setTypeMap, arginfo_class_MongoDB_Driver_Cursor_setTypeMap, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Cursor, toArray, arginfo_class_MongoDB_Driver_Cursor_toArray, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Cursor, valid, arginfo_class_MongoDB_Driver_Cursor_valid, ZEND_ACC_PUBLIC) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Cursor(zend_class_entry *class_entry_Iterator, zend_class_entry *class_entry_MongoDB_Driver_CursorInterface) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "Cursor", class_MongoDB_Driver_Cursor_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; zend_class_implements(class_entry, 2, class_entry_Iterator, class_entry_MongoDB_Driver_CursorInterface); return class_entry; } mongodb-1.21.0/src/MongoDB/Manager.c0000644000175100001660000006761114760300420013742 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_apm.h" #include "phongo_client.h" #include "phongo_error.h" #include "phongo_execute.h" #include "phongo_util.h" #include "MongoDB/ClientEncryption.h" #include "MongoDB/ReadConcern.h" #include "MongoDB/ReadPreference.h" #include "MongoDB/Server.h" #include "MongoDB/Session.h" #include "MongoDB/WriteConcern.h" #include "Manager_arginfo.h" #define PHONGO_MANAGER_URI_DEFAULT "mongodb://127.0.0.1/" /** * Manager abstracts a cluster of Server objects (i.e. socket connections). * * Typically, users will connect to a cluster using a URI, and the Manager will * perform tasks such as replica set discovery and create the necessary Server * objects. That said, it is also possible to create a Manager with an arbitrary * collection of Server objects using the static factory method (this can be * useful for testing or administration). * * Operation methods do not take socket-level options (e.g. socketTimeoutMS). * Those options should be specified during construction. */ zend_class_entry* php_phongo_manager_ce; /* Checks if driverOptions contains a stream context resource in the "context" * key and incorporates any of its SSL options into the base array that did not * already exist (i.e. array union). The "context" key is then unset from the * base array. * * This handles the merging of any legacy SSL context options and also makes * driverOptions suitable for serialization by removing the resource zval. */ static bool php_phongo_manager_merge_context_options(zval* zdriverOptions) { php_stream_context* context; zval * zcontext, *zcontextOptions; if (!php_array_existsc(zdriverOptions, "context")) { return true; } zcontext = php_array_fetchc_deref(zdriverOptions, "context"); context = php_stream_context_from_zval(zcontext, 1); if (!context) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "\"context\" driver option is not a valid Stream-Context resource"); return false; } zcontextOptions = php_array_fetchc_array(&context->options, "ssl"); if (!zcontextOptions) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Stream-Context resource does not contain \"ssl\" options array"); return false; } /* When running PHP in debug mode, php_error_docref duplicates the current * scope, leading to a COW violation in zend_hash_merge and * zend_symtable_str_del (called by php_array_unsetc). This macro allows * that violation in debug mode and is a NOOP when in non-debug. */ HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(zdriverOptions)); php_error_docref(NULL, E_DEPRECATED, "The \"context\" driver option is deprecated."); /* Perform array union (see: add_function() in zend_operators.c) */ zend_hash_merge(Z_ARRVAL_P(zdriverOptions), Z_ARRVAL_P(zcontextOptions), zval_add_ref, 0); php_array_unsetc(zdriverOptions, "context"); return true; } /* Prepare authMechanismProperties for BSON encoding by converting a boolean * value for the "CANONICALIZE_HOST_NAME" option to a string. * * Note: URI options are case-insensitive, so we must iterate through the * HashTable in order to detect options. */ static void php_phongo_manager_prep_authmechanismproperties(zval* properties) { HashTable* ht_data; if (Z_TYPE_P(properties) != IS_ARRAY && Z_TYPE_P(properties) != IS_OBJECT) { return; } ht_data = HASH_OF(properties); { zend_string* string_key = NULL; zend_ulong num_key = 0; zval* property; ZEND_HASH_FOREACH_KEY_VAL_IND(ht_data, num_key, string_key, property) { if (!string_key) { continue; } /* URI options are case-insensitive */ if (!strcasecmp(ZSTR_VAL(string_key), "CANONICALIZE_HOST_NAME")) { ZVAL_DEREF(property); if (Z_TYPE_P(property) != IS_STRING && zend_is_true(property)) { SEPARATE_ZVAL_NOREF(property); ZVAL_NEW_STR(property, zend_string_init(ZEND_STRL("true"), 0)); } } } ZEND_HASH_FOREACH_END(); } } /* Prepare URI options for BSON encoding. * * Read preference tag sets must be an array of documents. In order to ensure * that empty arrays serialize as empty documents, array elements will be * converted to objects. php_phongo_read_preference_tags_are_valid() handles * actual validation of the tag set structure. * * Auth mechanism properties must have string values, so a boolean true value * for the "CANONICALIZE_HOST_NAME" property will be converted to "true". * * Note: URI options are case-insensitive, so we must iterate through the * HashTable in order to detect options. */ static void php_phongo_manager_prep_uri_options(zval* options) { HashTable* ht_data; if (Z_TYPE_P(options) != IS_ARRAY) { return; } ht_data = HASH_OF(options); { zend_string* string_key = NULL; zend_ulong num_key = 0; zval* option; ZEND_HASH_FOREACH_KEY_VAL_IND(ht_data, num_key, string_key, option) { if (!string_key) { continue; } if (!strcasecmp(ZSTR_VAL(string_key), MONGOC_URI_READPREFERENCETAGS)) { ZVAL_DEREF(option); SEPARATE_ZVAL_NOREF(option); php_phongo_read_preference_prep_tagsets(option); continue; } if (!strcasecmp(ZSTR_VAL(string_key), MONGOC_URI_AUTHMECHANISMPROPERTIES)) { ZVAL_DEREF(option); SEPARATE_ZVAL_NOREF(option); php_phongo_manager_prep_authmechanismproperties(option); continue; } } ZEND_HASH_FOREACH_END(); } } /* Selects a server for an execute method. If "for_writes" is true, a primary * will be selected. Otherwise, a read preference will be used to select the * server. If zreadPreference is NULL, the client's read preference will be * used. If zsession is a session object in a sharded transaction, the session * will be checked whether it is pinned to a server. If so, that server will be * selected. Otherwise, server selection * * On success, server_id will be set and the function will return true; * otherwise, false is returned and an exception is thrown. */ static bool php_phongo_manager_select_server(bool for_writes, bool inherit_read_preference, zval* zreadPreference, zval* zsession, mongoc_client_t* client, uint32_t* server_id) { mongoc_server_description_t* selected_server; const mongoc_read_prefs_t* read_preference = NULL; bson_error_t error = { 0 }; if (zsession) { const mongoc_client_session_t* session = Z_SESSION_OBJ_P(zsession)->client_session; /* Attempt to fetch server pinned to session */ if (mongoc_client_session_get_server_id(session) > 0) { *server_id = mongoc_client_session_get_server_id(session); return true; } } if (!for_writes) { if (zreadPreference) { read_preference = phongo_read_preference_from_zval(zreadPreference); } else if (inherit_read_preference) { read_preference = mongoc_client_get_read_prefs(client); } } selected_server = mongoc_client_select_server(client, for_writes, read_preference, &error); if (selected_server) { *server_id = mongoc_server_description_id(selected_server); mongoc_server_description_destroy(selected_server); return true; } /* Check for connection related exceptions */ if (!EG(exception)) { phongo_throw_exception_from_bson_error_t(&error); } return false; } /* Constructs a new Manager */ static PHP_METHOD(MongoDB_Driver_Manager, __construct) { php_phongo_manager_t* intern; char* uri_string = NULL; size_t uri_string_len = 0; zval* options = NULL; zval* driverOptions = NULL; intern = Z_MANAGER_OBJ_P(getThis()); /* Separate the options and driverOptions zvals, since we may end up * modifying them in php_phongo_manager_prep_uri_options() and * php_phongo_manager_merge_context_options() below, respectively. */ PHONGO_PARSE_PARAMETERS_START(0, 3) Z_PARAM_OPTIONAL Z_PARAM_STRING_OR_NULL(uri_string, uri_string_len) Z_PARAM_ARRAY_EX(options, 1, 1) Z_PARAM_ARRAY_EX(driverOptions, 1, 1) PHONGO_PARSE_PARAMETERS_END(); if (options) { php_phongo_manager_prep_uri_options(options); } if (driverOptions && !php_phongo_manager_merge_context_options(driverOptions)) { /* Exception should already have been thrown */ return; } phongo_manager_init(intern, uri_string ? uri_string : PHONGO_MANAGER_URI_DEFAULT, options, driverOptions); if (EG(exception)) { return; } /* Update the request-scoped Manager registry */ if (!php_phongo_manager_register(intern)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Failed to add Manager to internal registry"); } } /* Registers an event subscriber for this Manager */ static PHP_METHOD(MongoDB_Driver_Manager, addSubscriber) { php_phongo_manager_t* intern; zval* subscriber; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT_OF_CLASS(subscriber, php_phongo_subscriber_ce) PHONGO_PARSE_PARAMETERS_END(); if (instanceof_function(Z_OBJCE_P(subscriber), php_phongo_logsubscriber_ce)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "LogSubscriber instances cannot be registered with a Manager"); } intern = Z_MANAGER_OBJ_P(getThis()); /* Lazily initialize the subscriber HashTable */ if (!intern->subscribers) { ALLOC_HASHTABLE(intern->subscribers); zend_hash_init(intern->subscribers, 0, NULL, ZVAL_PTR_DTOR, 0); } phongo_apm_add_subscriber(intern->subscribers, subscriber); } /* Return a ClientEncryption instance */ static PHP_METHOD(MongoDB_Driver_Manager, createClientEncryption) { zval* options; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(options) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_clientencryption_ce); /* An exception will be thrown on error. */ phongo_clientencryption_init(Z_CLIENTENCRYPTION_OBJ_P(return_value), options, getThis()); } /* Execute a Command */ static PHP_METHOD(MongoDB_Driver_Manager, executeCommand) { php_phongo_manager_t* intern; char* db; size_t db_len; zval* command; zval* options = NULL; bool free_options = false; zval* zreadPreference = NULL; zval* zsession = NULL; uint32_t server_id = 0; PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING_OR_NULL(db, db_len) Z_PARAM_OBJECT_OF_CLASS(command, php_phongo_command_ce) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); intern = Z_MANAGER_OBJ_P(getThis()); options = php_phongo_prep_legacy_option(options, "readPreference", &free_options); if (!phongo_parse_session(options, intern->client, NULL, &zsession)) { /* Exception should already have been thrown */ goto cleanup; } if (!phongo_parse_read_preference(options, &zreadPreference)) { /* Exception should already have been thrown */ goto cleanup; } if (!php_phongo_manager_select_server(false, false, zreadPreference, zsession, intern->client, &server_id)) { /* Exception should already have been thrown */ goto cleanup; } /* If the Manager was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, intern); phongo_execute_command(getThis(), PHONGO_COMMAND_RAW, db, command, options, server_id, return_value); cleanup: if (free_options) { php_phongo_prep_legacy_option_free(options); } } /* Execute a ReadCommand */ static PHP_METHOD(MongoDB_Driver_Manager, executeReadCommand) { php_phongo_manager_t* intern; char* db; size_t db_len; zval* command; zval* options = NULL; zval* zreadPreference = NULL; uint32_t server_id = 0; zval* zsession = NULL; PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING_OR_NULL(db, db_len) Z_PARAM_OBJECT_OF_CLASS(command, php_phongo_command_ce) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); intern = Z_MANAGER_OBJ_P(getThis()); if (!phongo_parse_session(options, intern->client, NULL, &zsession)) { /* Exception should already have been thrown */ return; } if (!phongo_parse_read_preference(options, &zreadPreference)) { /* Exception should already have been thrown */ return; } if (!php_phongo_manager_select_server(false, true, zreadPreference, zsession, intern->client, &server_id)) { /* Exception should already have been thrown */ return; } /* If the Manager was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, intern); phongo_execute_command(getThis(), PHONGO_COMMAND_READ, db, command, options, server_id, return_value); } /* Execute a WriteCommand */ static PHP_METHOD(MongoDB_Driver_Manager, executeWriteCommand) { php_phongo_manager_t* intern; char* db; size_t db_len; zval* command; zval* options = NULL; uint32_t server_id = 0; zval* zsession = NULL; PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING_OR_NULL(db, db_len) Z_PARAM_OBJECT_OF_CLASS(command, php_phongo_command_ce) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); intern = Z_MANAGER_OBJ_P(getThis()); if (!phongo_parse_session(options, intern->client, NULL, &zsession)) { /* Exception should already have been thrown */ return; } if (!php_phongo_manager_select_server(true, false, NULL, zsession, intern->client, &server_id)) { /* Exception should already have been thrown */ return; } /* If the Manager was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, intern); phongo_execute_command(getThis(), PHONGO_COMMAND_WRITE, db, command, options, server_id, return_value); } /* Execute a ReadWriteCommand */ static PHP_METHOD(MongoDB_Driver_Manager, executeReadWriteCommand) { php_phongo_manager_t* intern; char* db; size_t db_len; zval* command; zval* options = NULL; uint32_t server_id = 0; zval* zsession = NULL; PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING_OR_NULL(db, db_len) Z_PARAM_OBJECT_OF_CLASS(command, php_phongo_command_ce) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); intern = Z_MANAGER_OBJ_P(getThis()); if (!phongo_parse_session(options, intern->client, NULL, &zsession)) { /* Exception should already have been thrown */ return; } if (!php_phongo_manager_select_server(true, false, NULL, zsession, intern->client, &server_id)) { /* Exception should already have been thrown */ return; } /* If the Manager was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, intern); phongo_execute_command(getThis(), PHONGO_COMMAND_READ_WRITE, db, command, options, server_id, return_value); } /* Execute a Query */ static PHP_METHOD(MongoDB_Driver_Manager, executeQuery) { php_phongo_manager_t* intern; char* namespace; size_t namespace_len; zval* query; zval* options = NULL; bool free_options = false; zval* zreadPreference = NULL; uint32_t server_id = 0; zval* zsession = NULL; PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING_OR_NULL(namespace, namespace_len) Z_PARAM_OBJECT_OF_CLASS(query, php_phongo_query_ce) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); intern = Z_MANAGER_OBJ_P(getThis()); options = php_phongo_prep_legacy_option(options, "readPreference", &free_options); if (!phongo_parse_session(options, intern->client, NULL, &zsession)) { /* Exception should already have been thrown */ goto cleanup; } if (!phongo_parse_read_preference(options, &zreadPreference)) { /* Exception should already have been thrown */ goto cleanup; } if (!php_phongo_manager_select_server(false, true, zreadPreference, zsession, intern->client, &server_id)) { /* Exception should already have been thrown */ goto cleanup; } /* If the Manager was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, intern); phongo_execute_query(getThis(), namespace, query, options, server_id, return_value); cleanup: if (free_options) { php_phongo_prep_legacy_option_free(options); } } /* Executes a BulkWrite (i.e. any number of insert, update, and delete ops) */ static PHP_METHOD(MongoDB_Driver_Manager, executeBulkWrite) { php_phongo_manager_t* intern; char* namespace; size_t namespace_len; zval* zbulk; php_phongo_bulkwrite_t* bulk; zval* options = NULL; bool free_options = false; uint32_t server_id = 0; zval* zsession = NULL; PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING_OR_NULL(namespace, namespace_len) Z_PARAM_OBJECT_OF_CLASS(zbulk, php_phongo_bulkwrite_ce) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); intern = Z_MANAGER_OBJ_P(getThis()); bulk = Z_BULKWRITE_OBJ_P(zbulk); options = php_phongo_prep_legacy_option(options, "writeConcern", &free_options); if (!phongo_parse_session(options, intern->client, NULL, &zsession)) { /* Exception should already have been thrown */ return; } if (!php_phongo_manager_select_server(true, false, NULL, zsession, intern->client, &server_id)) { /* Exception should already have been thrown */ goto cleanup; } /* If the Server was created in a different process, reset the client so * that its session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, intern); phongo_execute_bulk_write(getThis(), namespace, bulk, options, server_id, return_value); cleanup: if (free_options) { php_phongo_prep_legacy_option_free(options); } } /* Returns the autoEncryption.encryptedFieldsMap driver option */ static PHP_METHOD(MongoDB_Driver_Manager, getEncryptedFieldsMap) { php_phongo_manager_t* intern; intern = Z_MANAGER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!Z_ISUNDEF(intern->enc_fields_map)) { RETURN_ZVAL(&intern->enc_fields_map, 1, 0); } } /* Returns the ReadConcern associated with this Manager */ static PHP_METHOD(MongoDB_Driver_Manager, getReadConcern) { php_phongo_manager_t* intern; intern = Z_MANAGER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_readconcern_init(return_value, mongoc_client_get_read_concern(intern->client)); } /* Returns the ReadPreference associated with this Manager */ static PHP_METHOD(MongoDB_Driver_Manager, getReadPreference) { php_phongo_manager_t* intern; intern = Z_MANAGER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_readpreference_init(return_value, mongoc_client_get_read_prefs(intern->client)); } /* Returns the Servers associated with this Manager */ static PHP_METHOD(MongoDB_Driver_Manager, getServers) { php_phongo_manager_t* intern; mongoc_server_description_t** sds; size_t i, n = 0; intern = Z_MANAGER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); sds = mongoc_client_get_server_descriptions(intern->client, &n); array_init_size(return_value, n); for (i = 0; i < n; i++) { zval obj; phongo_server_init(&obj, getThis(), mongoc_server_description_id(sds[i])); add_next_index_zval(return_value, &obj); } mongoc_server_descriptions_destroy_all(sds, n); } /* Returns the WriteConcern associated with this Manager */ static PHP_METHOD(MongoDB_Driver_Manager, getWriteConcern) { php_phongo_manager_t* intern; intern = Z_MANAGER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_writeconcern_init(return_value, mongoc_client_get_write_concern(intern->client)); } /* Unregisters an event subscriber for this Manager */ static PHP_METHOD(MongoDB_Driver_Manager, removeSubscriber) { php_phongo_manager_t* intern; zval* subscriber; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT_OF_CLASS(subscriber, php_phongo_subscriber_ce) PHONGO_PARSE_PARAMETERS_END(); intern = Z_MANAGER_OBJ_P(getThis()); /* NOP if subscribers HashTable was never initialized by addSubscriber */ if (!intern->subscribers) { return; } phongo_apm_remove_subscriber(intern->subscribers, subscriber); } /* Selects a Server for the given ReadPreference (default: primary). */ static PHP_METHOD(MongoDB_Driver_Manager, selectServer) { php_phongo_manager_t* intern; zval* zreadPreference = NULL; uint32_t server_id = 0; PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_OBJECT_OF_CLASS_OR_NULL(zreadPreference, php_phongo_readpreference_ce) PHONGO_PARSE_PARAMETERS_END(); intern = Z_MANAGER_OBJ_P(getThis()); if (!php_phongo_manager_select_server(false, false, zreadPreference, NULL, intern->client, &server_id)) { /* Exception should already have been thrown */ return; } phongo_server_init(return_value, getThis(), server_id); } /* Returns a new client session */ static PHP_METHOD(MongoDB_Driver_Manager, startSession) { php_phongo_manager_t* intern; zval* options = NULL; mongoc_session_opt_t* cs_opts = NULL; mongoc_client_session_t* cs; bson_error_t error = { 0 }; mongoc_transaction_opt_t* txn_opts = NULL; intern = Z_MANAGER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); if (options && php_array_existsc(options, "causalConsistency")) { cs_opts = mongoc_session_opts_new(); mongoc_session_opts_set_causal_consistency(cs_opts, php_array_fetchc_bool(options, "causalConsistency")); } if (options && php_array_existsc(options, "defaultTransactionOptions")) { zval* txn_options = php_array_fetchc_deref(options, "defaultTransactionOptions"); /* Thrown exception and return if the defaultTransactionOptions is not an array */ if (Z_TYPE_P(txn_options) != IS_ARRAY) { phongo_throw_exception( PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"defaultTransactionOptions\" option to be an array, %s given", zend_zval_type_name(txn_options)); goto cleanup; } /* Parse transaction options */ txn_opts = php_mongodb_session_parse_transaction_options(txn_options); /* If an exception is thrown while parsing, the txn_opts struct is also * NULL, so no need to free it here */ if (EG(exception)) { goto cleanup; } /* If the options are non-empty, add them to the client session opts struct */ if (txn_opts) { if (!cs_opts) { cs_opts = mongoc_session_opts_new(); } mongoc_session_opts_set_default_transaction_opts(cs_opts, txn_opts); mongoc_transaction_opts_destroy(txn_opts); } } if (options && php_array_existsc(options, "snapshot")) { if (!cs_opts) { cs_opts = mongoc_session_opts_new(); } mongoc_session_opts_set_snapshot(cs_opts, php_array_fetchc_bool(options, "snapshot")); } if (cs_opts && mongoc_session_opts_get_causal_consistency(cs_opts) && mongoc_session_opts_get_snapshot(cs_opts)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Only one of \"causalConsistency\" and \"snapshot\" can be enabled"); goto cleanup; } /* If the Manager was created in a different process, reset the client so * that its session pool is cleared. This will ensure that we do not re-use * a server session (i.e. LSID) created by a parent process. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, intern); cs = mongoc_client_start_session(intern->client, cs_opts, &error); if (cs) { phongo_session_init(return_value, getThis(), cs); } else { phongo_throw_exception_from_bson_error_t(&error); } cleanup: if (cs_opts) { mongoc_session_opts_destroy(cs_opts); } } /* MongoDB\Driver\Manager object handlers */ static zend_object_handlers php_phongo_handler_manager; static void php_phongo_manager_free_object(zend_object* object) { php_phongo_manager_t* intern = Z_OBJ_MANAGER(object); zend_object_std_dtor(&intern->std); if (intern->client) { /* Request-scoped clients will be removed from the registry and * destroyed. This is a NOP for persistent clients. The return value is * ignored because we can't reasonably report an error here. On the off * chance any request-scoped clients are missed, they will ultimately be * destroyed in RSHUTDOWN along with the registry HashTable. */ php_phongo_client_unregister(intern); } /* Update the request-scoped Manager registry. The return value is ignored * because it's possible that the Manager was never registered due to a * constructor exception. * * Note: this is done after unregistering a request-scoped client to ensure * APM events can be observed by per-client subscribers, which are collected * in phongo_apm_get_subscribers_to_notify. */ php_phongo_manager_unregister(intern); if (intern->client_hash) { efree(intern->client_hash); } if (!Z_ISUNDEF(intern->enc_fields_map)) { zval_ptr_dtor(&intern->enc_fields_map); } /* Free the keyVaultClient last to ensure that potential non-persistent * clients are destroyed in the correct order */ if (!Z_ISUNDEF(intern->key_vault_client_manager)) { zval_ptr_dtor(&intern->key_vault_client_manager); } if (intern->subscribers) { zend_hash_destroy(intern->subscribers); FREE_HASHTABLE(intern->subscribers); } } static zend_object* php_phongo_manager_create_object(zend_class_entry* class_type) { php_phongo_manager_t* intern = zend_object_alloc(sizeof(php_phongo_manager_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); PHONGO_SET_CREATED_BY_PID(intern); intern->std.handlers = &php_phongo_handler_manager; return &intern->std; } static HashTable* php_phongo_manager_get_debug_info(zend_object* object, int* is_temp) { php_phongo_manager_t* intern; mongoc_server_description_t** sds; size_t i, n = 0; zval retval = ZVAL_STATIC_INIT; zval cluster; *is_temp = 1; intern = Z_OBJ_MANAGER(object); array_init_size(&retval, 2); ADD_ASSOC_STRING(&retval, "uri", mongoc_uri_get_string(mongoc_client_get_uri(intern->client))); sds = mongoc_client_get_server_descriptions(intern->client, &n); array_init_size(&cluster, n); for (i = 0; i < n; i++) { zval obj; if (!php_phongo_server_to_zval(&obj, intern->client, sds[i])) { /* Exception already thrown */ zval_ptr_dtor(&obj); zval_ptr_dtor(&cluster); goto done; } add_next_index_zval(&cluster, &obj); } ADD_ASSOC_ZVAL_EX(&retval, "cluster", &cluster); done: mongoc_server_descriptions_destroy_all(sds, n); return Z_ARRVAL(retval); } void php_phongo_manager_init_ce(INIT_FUNC_ARGS) { php_phongo_manager_ce = register_class_MongoDB_Driver_Manager(); php_phongo_manager_ce->create_object = php_phongo_manager_create_object; memcpy(&php_phongo_handler_manager, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_manager.get_debug_info = php_phongo_manager_get_debug_info; php_phongo_handler_manager.free_obj = php_phongo_manager_free_object; php_phongo_handler_manager.offset = XtOffsetOf(php_phongo_manager_t, std); } mongodb-1.21.0/src/MongoDB/Manager_arginfo.h0000644000175100001660000001676414760300420015457 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: ce2904be644a230dc05dc1427f74c3717035eb06 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Manager___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, uri, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, uriOptions, IS_ARRAY, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, driverOptions, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Manager_addSubscriber, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, subscriber, MongoDB\\Driver\\Monitoring\\Subscriber, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_createClientEncryption, 0, 1, MongoDB\\Driver\\ClientEncryption, 0) ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_executeBulkWrite, 0, 2, MongoDB\\Driver\\WriteResult, 0) ZEND_ARG_TYPE_INFO(0, namespace, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, bulk, MongoDB\\Driver\\BulkWrite, 0) ZEND_ARG_OBJ_TYPE_MASK(0, options, MongoDB\\Driver\\WriteConcern, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_executeCommand, 0, 2, MongoDB\\Driver\\Cursor, 0) ZEND_ARG_TYPE_INFO(0, db, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, command, MongoDB\\Driver\\Command, 0) ZEND_ARG_OBJ_TYPE_MASK(0, options, MongoDB\\Driver\\ReadPreference, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_executeQuery, 0, 2, MongoDB\\Driver\\Cursor, 0) ZEND_ARG_TYPE_INFO(0, namespace, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, query, MongoDB\\Driver\\Query, 0) ZEND_ARG_OBJ_TYPE_MASK(0, options, MongoDB\\Driver\\ReadPreference, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_executeReadCommand, 0, 2, MongoDB\\Driver\\Cursor, 0) ZEND_ARG_TYPE_INFO(0, db, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, command, MongoDB\\Driver\\Command, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Manager_executeReadWriteCommand arginfo_class_MongoDB_Driver_Manager_executeReadCommand #define arginfo_class_MongoDB_Driver_Manager_executeWriteCommand arginfo_class_MongoDB_Driver_Manager_executeReadCommand ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_MongoDB_Driver_Manager_getEncryptedFieldsMap, 0, 0, MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_getReadConcern, 0, 0, MongoDB\\Driver\\ReadConcern, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_getReadPreference, 0, 0, MongoDB\\Driver\\ReadPreference, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Manager_getServers, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_getWriteConcern, 0, 0, MongoDB\\Driver\\WriteConcern, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Manager_removeSubscriber arginfo_class_MongoDB_Driver_Manager_addSubscriber ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_selectServer, 0, 0, MongoDB\\Driver\\Server, 0) ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, readPreference, MongoDB\\Driver\\ReadPreference, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Manager_startSession, 0, 0, MongoDB\\Driver\\Session, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Manager, __construct); static ZEND_METHOD(MongoDB_Driver_Manager, addSubscriber); static ZEND_METHOD(MongoDB_Driver_Manager, createClientEncryption); static ZEND_METHOD(MongoDB_Driver_Manager, executeBulkWrite); static ZEND_METHOD(MongoDB_Driver_Manager, executeCommand); static ZEND_METHOD(MongoDB_Driver_Manager, executeQuery); static ZEND_METHOD(MongoDB_Driver_Manager, executeReadCommand); static ZEND_METHOD(MongoDB_Driver_Manager, executeReadWriteCommand); static ZEND_METHOD(MongoDB_Driver_Manager, executeWriteCommand); static ZEND_METHOD(MongoDB_Driver_Manager, getEncryptedFieldsMap); static ZEND_METHOD(MongoDB_Driver_Manager, getReadConcern); static ZEND_METHOD(MongoDB_Driver_Manager, getReadPreference); static ZEND_METHOD(MongoDB_Driver_Manager, getServers); static ZEND_METHOD(MongoDB_Driver_Manager, getWriteConcern); static ZEND_METHOD(MongoDB_Driver_Manager, removeSubscriber); static ZEND_METHOD(MongoDB_Driver_Manager, selectServer); static ZEND_METHOD(MongoDB_Driver_Manager, startSession); static const zend_function_entry class_MongoDB_Driver_Manager_methods[] = { ZEND_ME(MongoDB_Driver_Manager, __construct, arginfo_class_MongoDB_Driver_Manager___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, addSubscriber, arginfo_class_MongoDB_Driver_Manager_addSubscriber, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, createClientEncryption, arginfo_class_MongoDB_Driver_Manager_createClientEncryption, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, executeBulkWrite, arginfo_class_MongoDB_Driver_Manager_executeBulkWrite, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, executeCommand, arginfo_class_MongoDB_Driver_Manager_executeCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, executeQuery, arginfo_class_MongoDB_Driver_Manager_executeQuery, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, executeReadCommand, arginfo_class_MongoDB_Driver_Manager_executeReadCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, executeReadWriteCommand, arginfo_class_MongoDB_Driver_Manager_executeReadWriteCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, executeWriteCommand, arginfo_class_MongoDB_Driver_Manager_executeWriteCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, getEncryptedFieldsMap, arginfo_class_MongoDB_Driver_Manager_getEncryptedFieldsMap, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, getReadConcern, arginfo_class_MongoDB_Driver_Manager_getReadConcern, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, getReadPreference, arginfo_class_MongoDB_Driver_Manager_getReadPreference, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, getServers, arginfo_class_MongoDB_Driver_Manager_getServers, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, getWriteConcern, arginfo_class_MongoDB_Driver_Manager_getWriteConcern, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, removeSubscriber, arginfo_class_MongoDB_Driver_Manager_removeSubscriber, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, selectServer, arginfo_class_MongoDB_Driver_Manager_selectServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Manager, startSession, arginfo_class_MongoDB_Driver_Manager_startSession, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Manager(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "Manager", class_MongoDB_Driver_Manager_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/Query.c0000644000175100001660000004773614760300420013503 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "MongoDB/Query.h" #include "MongoDB/ReadConcern.h" #include "Query_arginfo.h" zend_class_entry* php_phongo_query_ce; /* Appends a string field into the BSON options. Returns true on success; * otherwise, false is returned and an exception is thrown. */ static bool php_phongo_query_opts_append_string(bson_t* opts, const char* opts_key, zval* zarr, const char* zarr_key) { zval* value = php_array_fetch_deref(zarr, zarr_key); if (Z_TYPE_P(value) != IS_STRING) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"%s\" %s to be string, %s given", zarr_key, zarr_key[0] == '$' ? "modifier" : "option", zend_zval_type_name(value)); return false; } if (!bson_append_utf8(opts, opts_key, strlen(opts_key), Z_STRVAL_P(value), Z_STRLEN_P(value))) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", opts_key); return false; } return true; } /* Appends a document field for the given opts document and key. Returns true on * success; otherwise, false is returned and an exception is thrown. */ static bool php_phongo_query_opts_append_document(bson_t* opts, const char* opts_key, zval* zarr, const char* zarr_key) { zval* value = php_array_fetch_deref(zarr, zarr_key); bson_t b = BSON_INITIALIZER; if (Z_TYPE_P(value) != IS_OBJECT && Z_TYPE_P(value) != IS_ARRAY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"%s\" %s to be array or object, %s given", zarr_key, zarr_key[0] == '$' ? "modifier" : "option", zend_zval_type_name(value)); return false; } php_phongo_zval_to_bson(value, PHONGO_BSON_NONE, &b, NULL); if (EG(exception)) { bson_destroy(&b); return false; } if (!bson_validate(&b, BSON_VALIDATE_EMPTY_KEYS, NULL)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot use empty keys in \"%s\" %s", zarr_key, zarr_key[0] == '$' ? "modifier" : "option"); bson_destroy(&b); return false; } if (!BSON_APPEND_DOCUMENT(opts, opts_key, &b)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", opts_key); bson_destroy(&b); return false; } bson_destroy(&b); return true; } /* Appends an arbitrary BSON value for the given opts document and key. Returns * true on success; otherwise, false is returned and an exception is thrown. */ static bool php_phongo_query_opts_append_value(bson_t* opts, const char* opts_key, zval* zarr, const char* zarr_key) { bson_value_t value = { 0 }; phongo_zval_to_bson_value(php_array_fetch(zarr, zarr_key), &value); if (EG(exception)) { /* Exception should already have been thrown */ bson_value_destroy(&value); return false; } if (!BSON_APPEND_VALUE(opts, opts_key, &value)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", opts_key); bson_value_destroy(&value); return false; } bson_value_destroy(&value); return true; } #define PHONGO_QUERY_OPT_BOOL_EX(opt, zarr, key, deprecated) \ if ((zarr) && php_array_existsc((zarr), (key))) { \ if ((deprecated)) { \ php_error_docref(NULL, E_DEPRECATED, "The \"%s\" option is deprecated and will be removed in a future release", key); \ } \ if (!BSON_APPEND_BOOL(intern->opts, (opt), php_array_fetchc_bool((zarr), (key)))) { \ phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", (opt)); \ return false; \ } \ } #define PHONGO_QUERY_OPT_BOOL(opt, zarr, key) PHONGO_QUERY_OPT_BOOL_EX((opt), (zarr), (key), 0) #define PHONGO_QUERY_OPT_BOOL_DEPRECATED(opt, zarr, key) PHONGO_QUERY_OPT_BOOL_EX((opt), (zarr), (key), 1) #define PHONGO_QUERY_OPT_BSON_VALUE(opt, zarr, key) \ if ((zarr) && php_array_existsc((zarr), (key))) { \ if (!php_phongo_query_opts_append_value(intern->opts, (opt), (zarr), (key))) { \ return false; \ } \ } #define PHONGO_QUERY_OPT_DOCUMENT(opt, zarr, key) \ if ((zarr) && php_array_existsc((zarr), (key))) { \ if (!php_phongo_query_opts_append_document(intern->opts, (opt), (zarr), (key))) { \ return false; \ } \ } /* Note: handling of integer options will depend on SIZEOF_ZEND_LONG and we * are not converting strings to 64-bit integers for 32-bit platforms. */ #define PHONGO_QUERY_OPT_INT64_EX(opt, zarr, key, deprecated) \ if ((zarr) && php_array_existsc((zarr), (key))) { \ if ((deprecated)) { \ php_error_docref(NULL, E_DEPRECATED, "The \"%s\" option is deprecated and will be removed in a future release", key); \ } \ if (!BSON_APPEND_INT64(intern->opts, (opt), php_array_fetchc_long((zarr), (key)))) { \ phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"%s\" option", (opt)); \ return false; \ } \ } #define PHONGO_QUERY_OPT_INT64(opt, zarr, key) PHONGO_QUERY_OPT_INT64_EX((opt), (zarr), (key), 0) #define PHONGO_QUERY_OPT_INT64_DEPRECATED(opt, zarr, key) PHONGO_QUERY_OPT_INT64_EX((opt), (zarr), (key), 1) #define PHONGO_QUERY_OPT_STRING(opt, zarr, key) \ if ((zarr) && php_array_existsc((zarr), (key))) { \ if (!php_phongo_query_opts_append_string(intern->opts, (opt), (zarr), (key))) { \ return false; \ } \ } /* Initialize the "hint" option. Returns true on success; otherwise, false is * returned and an exception is thrown. * * The "hint" option (or "$hint" modifier) must be a string or document. Check * for both types and merge into BSON options accordingly. */ static bool php_phongo_query_init_hint(php_phongo_query_t* intern, zval* options, zval* modifiers) { /* The "hint" option (or "$hint" modifier) must be a string or document. * Check for both types and merge into BSON options accordingly. */ if (php_array_existsc(options, "hint")) { zend_uchar type = Z_TYPE_P(php_array_fetchc_deref(options, "hint")); if (type == IS_STRING) { PHONGO_QUERY_OPT_STRING("hint", options, "hint"); } else if (type == IS_OBJECT || type == IS_ARRAY) { PHONGO_QUERY_OPT_DOCUMENT("hint", options, "hint"); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"hint\" option to be string, array, or object, %s given", zend_get_type_by_const(type)); return false; } } else if (modifiers && php_array_existsc(modifiers, "$hint")) { zend_uchar type = Z_TYPE_P(php_array_fetchc_deref(modifiers, "$hint")); if (type == IS_STRING) { PHONGO_QUERY_OPT_STRING("hint", modifiers, "$hint"); } else if (type == IS_OBJECT || type == IS_ARRAY) { PHONGO_QUERY_OPT_DOCUMENT("hint", modifiers, "$hint"); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"$hint\" modifier to be string, array, or object, %s given", zend_get_type_by_const(type)); return false; } } return true; } /* Initialize the "limit" and "singleBatch" options. Returns true on success; * otherwise, false is returned and an exception is thrown. * * mongoc_collection_find_with_opts() requires a non-negative limit. For * backwards compatibility, a negative limit should be set as a positive value * and default singleBatch to true. */ static bool php_phongo_query_init_limit_and_singlebatch(php_phongo_query_t* intern, zval* options) { if (php_array_fetchc_long(options, "limit") < 0) { zend_long limit = php_array_fetchc_long(options, "limit"); php_error_docref(NULL, E_DEPRECATED, "Support for negative \"limit\" values is deprecated and will be removed in ext-mongodb 2.0"); if (!BSON_APPEND_INT64(intern->opts, "limit", -limit)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"limit\" option"); return false; } if (php_array_existsc(options, "singleBatch") && !php_array_fetchc_bool(options, "singleBatch")) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Negative \"limit\" option conflicts with false \"singleBatch\" option"); return false; } else { if (!BSON_APPEND_BOOL(intern->opts, "singleBatch", true)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"singleBatch\" option"); return false; } } } else { PHONGO_QUERY_OPT_INT64("limit", options, "limit"); PHONGO_QUERY_OPT_BOOL("singleBatch", options, "singleBatch"); } return true; } /* Initialize the "readConcern" option. Returns true on success; otherwise, * false is returned and an exception is thrown. * * The "readConcern" option should be a MongoDB\Driver\ReadConcern instance, * which must be converted to a mongoc_read_concern_t. */ static bool php_phongo_query_init_readconcern(php_phongo_query_t* intern, zval* options) { zval* read_concern; if (!php_array_existsc(options, "readConcern")) { return true; } read_concern = php_array_fetchc_deref(options, "readConcern"); if (Z_TYPE_P(read_concern) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(read_concern), php_phongo_readconcern_ce)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"readConcern\" option to be %s, %s given", ZSTR_VAL(php_phongo_readconcern_ce->name), zend_zval_type_name(read_concern)); return false; } intern->read_concern = mongoc_read_concern_copy(phongo_read_concern_from_zval(read_concern)); return true; } /* Initialize the "maxAwaitTimeMS" option. Returns true on success; otherwise, * false is returned and an exception is thrown. * * The "maxAwaitTimeMS" option is assigned to the cursor after query execution * via mongoc_cursor_set_max_await_time_ms(). */ static bool php_phongo_query_init_max_await_time_ms(php_phongo_query_t* intern, zval* options) { int64_t max_await_time_ms; if (!php_array_existsc(options, "maxAwaitTimeMS")) { return true; } max_await_time_ms = php_array_fetchc_long(options, "maxAwaitTimeMS"); if (max_await_time_ms < 0) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"maxAwaitTimeMS\" option to be >= 0, %" PRId64 " given", max_await_time_ms); return false; } if (max_await_time_ms > UINT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"maxAwaitTimeMS\" option to be <= %" PRIu32 ", %" PRId64 " given", UINT32_MAX, max_await_time_ms); return false; } intern->max_await_time_ms = (uint32_t) max_await_time_ms; return true; } /* Initializes the query from filter and options arguments and returns whether * an error occurred. If query is undefined, it will be initialized. * * This function will fall back to a modifier in the absence of a top-level * option (where applicable). */ bool phongo_query_init(zval* return_value, zval* filter, zval* options) { php_phongo_query_t* intern; zval* modifiers = NULL; if (Z_ISUNDEF_P(return_value)) { object_init_ex(return_value, php_phongo_query_ce); } if (Z_TYPE_P(return_value) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(return_value), php_phongo_query_ce)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Expected initialization object to be %s, %s given", ZSTR_VAL(php_phongo_query_ce->name), zend_zval_type_name(return_value)); return false; } intern = Z_QUERY_OBJ_P(return_value); intern->filter = bson_new(); intern->opts = bson_new(); intern->max_await_time_ms = 0; if (filter) { php_phongo_zval_to_bson(filter, PHONGO_BSON_NONE, intern->filter, NULL); } /* Note: if any exceptions are thrown, we can simply return as PHP will * invoke php_phongo_query_free_object to destruct the object. */ if (EG(exception)) { return false; } if (!bson_validate(intern->filter, BSON_VALIDATE_EMPTY_KEYS, NULL)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot use empty keys in filter document"); return false; } if (!options) { return true; } if (php_array_existsc(options, "modifiers")) { modifiers = php_array_fetchc_deref(options, "modifiers"); if (Z_TYPE_P(modifiers) != IS_ARRAY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"modifiers\" option to be array, %s given", zend_zval_type_name(modifiers)); return false; } php_error_docref(NULL, E_DEPRECATED, "The \"modifiers\" option is deprecated and will be removed in a future release"); } PHONGO_QUERY_OPT_BOOL("allowDiskUse", options, "allowDiskUse") PHONGO_QUERY_OPT_BOOL("allowPartialResults", options, "allowPartialResults") else PHONGO_QUERY_OPT_BOOL("allowPartialResults", options, "partial"); PHONGO_QUERY_OPT_BOOL("awaitData", options, "awaitData"); PHONGO_QUERY_OPT_INT64("batchSize", options, "batchSize"); PHONGO_QUERY_OPT_DOCUMENT("collation", options, "collation"); PHONGO_QUERY_OPT_BSON_VALUE("comment", options, "comment") else PHONGO_QUERY_OPT_BSON_VALUE("comment", modifiers, "$comment"); PHONGO_QUERY_OPT_BOOL("exhaust", options, "exhaust"); PHONGO_QUERY_OPT_DOCUMENT("let", options, "let"); PHONGO_QUERY_OPT_DOCUMENT("max", options, "max") else PHONGO_QUERY_OPT_DOCUMENT("max", modifiers, "$max"); PHONGO_QUERY_OPT_INT64_DEPRECATED("maxScan", options, "maxScan") else PHONGO_QUERY_OPT_INT64_DEPRECATED("maxScan", modifiers, "$maxScan"); PHONGO_QUERY_OPT_INT64("maxTimeMS", options, "maxTimeMS") else PHONGO_QUERY_OPT_INT64("maxTimeMS", modifiers, "$maxTimeMS"); PHONGO_QUERY_OPT_DOCUMENT("min", options, "min") else PHONGO_QUERY_OPT_DOCUMENT("min", modifiers, "$min"); PHONGO_QUERY_OPT_BOOL("noCursorTimeout", options, "noCursorTimeout"); PHONGO_QUERY_OPT_BOOL_DEPRECATED("oplogReplay", options, "oplogReplay"); PHONGO_QUERY_OPT_DOCUMENT("projection", options, "projection"); PHONGO_QUERY_OPT_BOOL("returnKey", options, "returnKey") else PHONGO_QUERY_OPT_BOOL("returnKey", modifiers, "$returnKey"); PHONGO_QUERY_OPT_BOOL("showRecordId", options, "showRecordId") else PHONGO_QUERY_OPT_BOOL("showRecordId", modifiers, "$showDiskLoc"); PHONGO_QUERY_OPT_INT64("skip", options, "skip"); PHONGO_QUERY_OPT_DOCUMENT("sort", options, "sort") else PHONGO_QUERY_OPT_DOCUMENT("sort", modifiers, "$orderby"); PHONGO_QUERY_OPT_BOOL_DEPRECATED("snapshot", options, "snapshot") else PHONGO_QUERY_OPT_BOOL_DEPRECATED("snapshot", modifiers, "$snapshot"); PHONGO_QUERY_OPT_BOOL("tailable", options, "tailable"); /* The "$explain" modifier should be converted to an "explain" option, which * libmongoc will later convert back to a modifier for the OP_QUERY code * path. This modifier will be ignored for the find command code path. */ PHONGO_QUERY_OPT_BOOL("explain", modifiers, "$explain"); if (!php_phongo_query_init_hint(intern, options, modifiers)) { return false; } if (!php_phongo_query_init_limit_and_singlebatch(intern, options)) { return false; } if (!php_phongo_query_init_readconcern(intern, options)) { return false; } if (!php_phongo_query_init_max_await_time_ms(intern, options)) { return false; } return true; } #undef PHONGO_QUERY_OPT_BOOL_EX #undef PHONGO_QUERY_OPT_BOOL #undef PHONGO_QUERY_OPT_BOOL_DEPRECATED #undef PHONGO_QUERY_OPT_BSON_VALUE #undef PHONGO_QUERY_OPT_DOCUMENT #undef PHONGO_QUERY_OPT_INT64_EX #undef PHONGO_QUERY_OPT_INT64 #undef PHONGO_QUERY_OPT_INT64_DEPRECATED #undef PHONGO_QUERY_OPT_STRING /* Constructs a new Query */ static PHP_METHOD(MongoDB_Driver_Query, __construct) { zval* filter; zval* options = NULL; PHONGO_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ARRAY_OR_OBJECT(filter) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); phongo_query_init(getThis(), filter, options); } /* MongoDB\Driver\Query object handlers */ static zend_object_handlers php_phongo_handler_query; static void php_phongo_query_free_object(zend_object* object) { php_phongo_query_t* intern = Z_OBJ_QUERY(object); zend_object_std_dtor(&intern->std); if (intern->filter) { bson_clear(&intern->filter); } if (intern->opts) { bson_clear(&intern->opts); } if (intern->read_concern) { mongoc_read_concern_destroy(intern->read_concern); } } static zend_object* php_phongo_query_create_object(zend_class_entry* class_type) { php_phongo_query_t* intern = zend_object_alloc(sizeof(php_phongo_query_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_query; return &intern->std; } static HashTable* php_phongo_query_get_debug_info(zend_object* object, int* is_temp) { php_phongo_query_t* intern; zval retval = ZVAL_STATIC_INIT; *is_temp = 1; intern = Z_OBJ_QUERY(object); array_init_size(&retval, 3); /* Avoid using PHONGO_TYPEMAP_NATIVE_ARRAY for decoding filter and opts * documents so that users can differentiate BSON arrays and documents. */ if (intern->filter) { zval zv; if (!php_phongo_bson_to_zval(intern->filter, &zv)) { zval_ptr_dtor(&zv); goto done; } ADD_ASSOC_ZVAL_EX(&retval, "filter", &zv); } else { ADD_ASSOC_NULL_EX(&retval, "filter"); } if (intern->opts) { zval zv; if (!php_phongo_bson_to_zval(intern->opts, &zv)) { zval_ptr_dtor(&zv); goto done; } ADD_ASSOC_ZVAL_EX(&retval, "options", &zv); } else { ADD_ASSOC_NULL_EX(&retval, "options"); } if (intern->read_concern) { zval read_concern; php_phongo_read_concern_to_zval(&read_concern, intern->read_concern); ADD_ASSOC_ZVAL_EX(&retval, "readConcern", &read_concern); } else { ADD_ASSOC_NULL_EX(&retval, "readConcern"); } done: return Z_ARRVAL(retval); } void php_phongo_query_init_ce(INIT_FUNC_ARGS) { php_phongo_query_ce = register_class_MongoDB_Driver_Query(); php_phongo_query_ce->create_object = php_phongo_query_create_object; memcpy(&php_phongo_handler_query, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_query.get_debug_info = php_phongo_query_get_debug_info; php_phongo_handler_query.free_obj = php_phongo_query_free_object; php_phongo_handler_query.offset = XtOffsetOf(php_phongo_query_t, std); } mongodb-1.21.0/src/MongoDB/Query.h0000644000175100001660000000140314760300420013465 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_QUERY_H #define PHONGO_QUERY_H #include bool phongo_query_init(zval* return_value, zval* filter, zval* options); #endif /* PHONGO_QUERY_H */ mongodb-1.21.0/src/MongoDB/Query_arginfo.h0000644000175100001660000000173014760300420015175 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 819affbb75a46cb68d88b46e0c7137590408b010 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Query___construct, 0, 0, 1) ZEND_ARG_TYPE_MASK(0, filter, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, queryOptions, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Query, __construct); static const zend_function_entry class_MongoDB_Driver_Query_methods[] = { ZEND_ME(MongoDB_Driver_Query, __construct, arginfo_class_MongoDB_Driver_Query___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Query(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "Query", class_MongoDB_Driver_Query_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/ReadConcern.c0000644000175100001660000002164214760300420014545 0ustar /* * Copyright 2015-present MongoDB, 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. */ #include "mongoc/mongoc.h" #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "ReadConcern_arginfo.h" zend_class_entry* php_phongo_readconcern_ce; /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_readconcern_init_from_hash(php_phongo_readconcern_t* intern, HashTable* props) { zval* level; intern->read_concern = mongoc_read_concern_new(); if ((level = zend_hash_str_find(props, "level", sizeof("level") - 1))) { if (Z_TYPE_P(level) == IS_STRING) { mongoc_read_concern_set_level(intern->read_concern, Z_STRVAL_P(level)); return true; } phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"level\" string field", ZSTR_VAL(php_phongo_readconcern_ce->name)); goto failure; } return true; failure: mongoc_read_concern_destroy(intern->read_concern); intern->read_concern = NULL; return false; } /* Constructs a new ReadConcern */ static PHP_METHOD(MongoDB_Driver_ReadConcern, __construct) { php_phongo_readconcern_t* intern; char* level = NULL; size_t level_len = 0; intern = Z_READCONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_STRING_OR_NULL(level, level_len) PHONGO_PARSE_PARAMETERS_END(); intern->read_concern = mongoc_read_concern_new(); if (level) { mongoc_read_concern_set_level(intern->read_concern, level); } } static PHP_METHOD(MongoDB_Driver_ReadConcern, __set_state) { php_phongo_readconcern_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_readconcern_ce); intern = Z_READCONCERN_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_readconcern_init_from_hash(intern, props); } /* Returns the ReadConcern "level" option */ static PHP_METHOD(MongoDB_Driver_ReadConcern, getLevel) { php_phongo_readconcern_t* intern; const char* level; intern = Z_READCONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); level = mongoc_read_concern_get_level(intern->read_concern); if (level) { RETURN_STRING(level); } RETURN_NULL(); } /* Returns whether the read concern has not been modified (i.e. constructed without a level or from a Manager with no read concern URI options). */ static PHP_METHOD(MongoDB_Driver_ReadConcern, isDefault) { php_phongo_readconcern_t* intern; intern = Z_READCONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_BOOL(mongoc_read_concern_is_default(intern->read_concern)); } static HashTable* php_phongo_readconcern_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_readconcern_t* intern; HashTable* props; const char* level; intern = Z_OBJ_READCONCERN(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 1); if (!intern->read_concern) { return props; } level = mongoc_read_concern_get_level(intern->read_concern); if (level) { zval z_level; ZVAL_STRING(&z_level, level); zend_hash_str_update(props, "level", sizeof("level") - 1, &z_level); } return props; } static PHP_METHOD(MongoDB_Driver_ReadConcern, bsonSerialize) { PHONGO_PARSE_PARAMETERS_NONE(); ZVAL_ARR(return_value, php_phongo_readconcern_get_properties_hash(Z_OBJ_P(getThis()), true)); convert_to_object(return_value); } static PHP_METHOD(MongoDB_Driver_ReadConcern, serialize) { php_phongo_readconcern_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; const char* level; intern = Z_READCONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!intern->read_concern) { return; } level = mongoc_read_concern_get_level(intern->read_concern); if (!level) { RETURN_STRING(""); } array_init_size(&retval, 1); ADD_ASSOC_STRING(&retval, "level", level); PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_Driver_ReadConcern, unserialize) { php_phongo_readconcern_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_READCONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); if (!serialized_len) { return; } PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_readconcern_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_readconcern_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_Driver_ReadConcern, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_readconcern_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_Driver_ReadConcern, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_readconcern_init_from_hash(Z_READCONCERN_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\Driver\ReadConcern object handlers */ static zend_object_handlers php_phongo_handler_readconcern; static void php_phongo_readconcern_free_object(zend_object* object) { php_phongo_readconcern_t* intern = Z_OBJ_READCONCERN(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } if (intern->read_concern) { mongoc_read_concern_destroy(intern->read_concern); } } static zend_object* php_phongo_readconcern_create_object(zend_class_entry* class_type) { php_phongo_readconcern_t* intern = zend_object_alloc(sizeof(php_phongo_readconcern_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_readconcern; return &intern->std; } static HashTable* php_phongo_readconcern_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_readconcern_get_properties_hash(object, true); } static HashTable* php_phongo_readconcern_get_properties(zend_object* object) { return php_phongo_readconcern_get_properties_hash(object, false); } void php_phongo_readconcern_init_ce(INIT_FUNC_ARGS) { php_phongo_readconcern_ce = register_class_MongoDB_Driver_ReadConcern(php_phongo_serializable_ce, zend_ce_serializable); php_phongo_readconcern_ce->create_object = php_phongo_readconcern_create_object; memcpy(&php_phongo_handler_readconcern, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_readconcern.get_debug_info = php_phongo_readconcern_get_debug_info; php_phongo_handler_readconcern.get_properties = php_phongo_readconcern_get_properties; php_phongo_handler_readconcern.free_obj = php_phongo_readconcern_free_object; php_phongo_handler_readconcern.offset = XtOffsetOf(php_phongo_readconcern_t, std); } void phongo_readconcern_init(zval* return_value, const mongoc_read_concern_t* read_concern) { php_phongo_readconcern_t* intern; object_init_ex(return_value, php_phongo_readconcern_ce); intern = Z_READCONCERN_OBJ_P(return_value); intern->read_concern = mongoc_read_concern_copy(read_concern); } const mongoc_read_concern_t* phongo_read_concern_from_zval(zval* zread_concern) { if (zread_concern) { php_phongo_readconcern_t* intern = Z_READCONCERN_OBJ_P(zread_concern); if (intern) { return intern->read_concern; } } return NULL; } void php_phongo_read_concern_to_zval(zval* retval, const mongoc_read_concern_t* read_concern) { const char* level = mongoc_read_concern_get_level(read_concern); array_init_size(retval, 1); if (level) { ADD_ASSOC_STRING(retval, "level", level); } } mongodb-1.21.0/src/MongoDB/ReadConcern.h0000644000175100001660000000176714760300420014560 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_READCONCERN_H #define PHONGO_READCONCERN_H #include "mongoc/mongoc.h" #include void phongo_readconcern_init(zval* return_value, const mongoc_read_concern_t* read_concern); const mongoc_read_concern_t* phongo_read_concern_from_zval(zval* zread_concern); void php_phongo_read_concern_to_zval(zval* retval, const mongoc_read_concern_t* read_concern); #endif /* PHONGO_READCONCERN_H */ mongodb-1.21.0/src/MongoDB/ReadConcern_arginfo.h0000644000175100001660000001440714760300420016260 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: d039252f9f7e9b8c30ba4794d488ad7c5cd493d2 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, level, IS_STRING, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern_getLevel, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern_isDefault, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern___set_state, 0, 1, MongoDB\\Driver\\ReadConcern, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern_bsonSerialize, 0, 0, stdClass, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern_serialize, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadConcern___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_ReadConcern, __construct); static ZEND_METHOD(MongoDB_Driver_ReadConcern, getLevel); static ZEND_METHOD(MongoDB_Driver_ReadConcern, isDefault); static ZEND_METHOD(MongoDB_Driver_ReadConcern, __set_state); static ZEND_METHOD(MongoDB_Driver_ReadConcern, bsonSerialize); static ZEND_METHOD(MongoDB_Driver_ReadConcern, serialize); static ZEND_METHOD(MongoDB_Driver_ReadConcern, unserialize); static ZEND_METHOD(MongoDB_Driver_ReadConcern, __unserialize); static ZEND_METHOD(MongoDB_Driver_ReadConcern, __serialize); static const zend_function_entry class_MongoDB_Driver_ReadConcern_methods[] = { ZEND_ME(MongoDB_Driver_ReadConcern, __construct, arginfo_class_MongoDB_Driver_ReadConcern___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadConcern, getLevel, arginfo_class_MongoDB_Driver_ReadConcern_getLevel, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadConcern, isDefault, arginfo_class_MongoDB_Driver_ReadConcern_isDefault, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadConcern, __set_state, arginfo_class_MongoDB_Driver_ReadConcern___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadConcern, bsonSerialize, arginfo_class_MongoDB_Driver_ReadConcern_bsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadConcern, serialize, arginfo_class_MongoDB_Driver_ReadConcern_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadConcern, unserialize, arginfo_class_MongoDB_Driver_ReadConcern_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadConcern, __unserialize, arginfo_class_MongoDB_Driver_ReadConcern___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadConcern, __serialize, arginfo_class_MongoDB_Driver_ReadConcern___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_ReadConcern(zend_class_entry *class_entry_MongoDB_BSON_Serializable, zend_class_entry *class_entry_Serializable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "ReadConcern", class_MongoDB_Driver_ReadConcern_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 2, class_entry_MongoDB_BSON_Serializable, class_entry_Serializable); zval const_LINEARIZABLE_value; zend_string *const_LINEARIZABLE_value_str = zend_string_init(MONGOC_READ_CONCERN_LEVEL_LINEARIZABLE, strlen(MONGOC_READ_CONCERN_LEVEL_LINEARIZABLE), 1); ZVAL_STR(&const_LINEARIZABLE_value, const_LINEARIZABLE_value_str); zend_string *const_LINEARIZABLE_name = zend_string_init_interned("LINEARIZABLE", sizeof("LINEARIZABLE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LINEARIZABLE_name, &const_LINEARIZABLE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_LINEARIZABLE_name); zval const_LOCAL_value; zend_string *const_LOCAL_value_str = zend_string_init(MONGOC_READ_CONCERN_LEVEL_LOCAL, strlen(MONGOC_READ_CONCERN_LEVEL_LOCAL), 1); ZVAL_STR(&const_LOCAL_value, const_LOCAL_value_str); zend_string *const_LOCAL_name = zend_string_init_interned("LOCAL", sizeof("LOCAL") - 1, 1); zend_declare_class_constant_ex(class_entry, const_LOCAL_name, &const_LOCAL_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_LOCAL_name); zval const_MAJORITY_value; zend_string *const_MAJORITY_value_str = zend_string_init(MONGOC_READ_CONCERN_LEVEL_MAJORITY, strlen(MONGOC_READ_CONCERN_LEVEL_MAJORITY), 1); ZVAL_STR(&const_MAJORITY_value, const_MAJORITY_value_str); zend_string *const_MAJORITY_name = zend_string_init_interned("MAJORITY", sizeof("MAJORITY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_MAJORITY_name, &const_MAJORITY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_MAJORITY_name); zval const_AVAILABLE_value; zend_string *const_AVAILABLE_value_str = zend_string_init(MONGOC_READ_CONCERN_LEVEL_AVAILABLE, strlen(MONGOC_READ_CONCERN_LEVEL_AVAILABLE), 1); ZVAL_STR(&const_AVAILABLE_value, const_AVAILABLE_value_str); zend_string *const_AVAILABLE_name = zend_string_init_interned("AVAILABLE", sizeof("AVAILABLE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_AVAILABLE_name, &const_AVAILABLE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_AVAILABLE_name); zval const_SNAPSHOT_value; zend_string *const_SNAPSHOT_value_str = zend_string_init(MONGOC_READ_CONCERN_LEVEL_SNAPSHOT, strlen(MONGOC_READ_CONCERN_LEVEL_SNAPSHOT), 1); ZVAL_STR(&const_SNAPSHOT_value, const_SNAPSHOT_value_str); zend_string *const_SNAPSHOT_name = zend_string_init_interned("SNAPSHOT", sizeof("SNAPSHOT") - 1, 1); zend_declare_class_constant_ex(class_entry, const_SNAPSHOT_name, &const_SNAPSHOT_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_SNAPSHOT_name); return class_entry; } mongodb-1.21.0/src/MongoDB/ReadPreference.c0000644000175100001660000006060314760300420015234 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_error.h" #include "MongoDB/ReadPreference.h" #include "ReadPreference_arginfo.h" zend_class_entry* php_phongo_readpreference_ce; /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_readpreference_init_from_hash(php_phongo_readpreference_t* intern, HashTable* props) { zval *mode, *tagSets, *maxStalenessSeconds, *hedge; if ((mode = zend_hash_str_find(props, "mode", sizeof("mode") - 1)) && Z_TYPE_P(mode) == IS_STRING) { if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_PRIMARY) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_PRIMARY); } else if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_PRIMARY_PREFERRED) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_PRIMARY_PREFERRED); } else if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_SECONDARY) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_SECONDARY); } else if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_SECONDARY_PREFERRED) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_SECONDARY_PREFERRED); } else if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_NEAREST) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_NEAREST); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires specific values for \"mode\" string field", ZSTR_VAL(php_phongo_readpreference_ce->name)); return false; } } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"mode\" field to be string", ZSTR_VAL(php_phongo_readpreference_ce->name)); return false; } if ((tagSets = zend_hash_str_find(props, "tags", sizeof("tags") - 1))) { ZVAL_DEREF(tagSets); if (Z_TYPE_P(tagSets) == IS_ARRAY) { bson_t* tags = bson_new(); /* Separate tagSets as php_phongo_read_preference_prep_tagsets may * modify these tags. */ SEPARATE_ZVAL_NOREF(tagSets); php_phongo_read_preference_prep_tagsets(tagSets); php_phongo_zval_to_bson(tagSets, PHONGO_BSON_NONE, (bson_t*) tags, NULL); if (!php_phongo_read_preference_tags_are_valid(tags)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"tags\" array field to have zero or more documents", ZSTR_VAL(php_phongo_readpreference_ce->name)); bson_destroy(tags); goto failure; } if (!bson_empty(tags) && (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"tags\" array field to not be present with \"primary\" mode", ZSTR_VAL(php_phongo_readpreference_ce->name)); bson_destroy(tags); goto failure; } mongoc_read_prefs_set_tags(intern->read_preference, tags); bson_destroy(tags); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"tags\" field to be array", ZSTR_VAL(php_phongo_readpreference_ce->name)); goto failure; } } if ((maxStalenessSeconds = zend_hash_str_find(props, "maxStalenessSeconds", sizeof("maxStalenessSeconds") - 1))) { if (Z_TYPE_P(maxStalenessSeconds) == IS_LONG) { if (Z_LVAL_P(maxStalenessSeconds) != MONGOC_NO_MAX_STALENESS) { if (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" field to not be present with \"primary\" mode", ZSTR_VAL(php_phongo_readpreference_ce->name)); goto failure; } if (Z_LVAL_P(maxStalenessSeconds) < MONGOC_SMALLEST_MAX_STALENESS_SECONDS) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" integer field to be >= %d", ZSTR_VAL(php_phongo_readpreference_ce->name), MONGOC_SMALLEST_MAX_STALENESS_SECONDS); goto failure; } if (Z_LVAL_P(maxStalenessSeconds) > INT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" integer field to be <= %" PRId32, ZSTR_VAL(php_phongo_readpreference_ce->name), INT32_MAX); goto failure; } } mongoc_read_prefs_set_max_staleness_seconds(intern->read_preference, Z_LVAL_P(maxStalenessSeconds)); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" field to be integer", ZSTR_VAL(php_phongo_readpreference_ce->name)); goto failure; } } if ((hedge = zend_hash_str_find(props, "hedge", sizeof("hedge") - 1))) { if (Z_TYPE_P(hedge) == IS_ARRAY || Z_TYPE_P(hedge) == IS_OBJECT) { bson_t* hedge_doc = bson_new(); if (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"hedge\" field to not be present with \"primary\" mode", ZSTR_VAL(php_phongo_readpreference_ce->name)); bson_destroy(hedge_doc); goto failure; } php_phongo_zval_to_bson(hedge, PHONGO_BSON_NONE, hedge_doc, NULL); if (EG(exception)) { bson_destroy(hedge_doc); goto failure; } mongoc_read_prefs_set_hedge(intern->read_preference, hedge_doc); bson_destroy(hedge_doc); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"hedge\" field to be an array or object", ZSTR_VAL(php_phongo_readpreference_ce->name)); goto failure; } } if (!mongoc_read_prefs_is_valid(intern->read_preference)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Read preference is not valid"); goto failure; } return true; failure: mongoc_read_prefs_destroy(intern->read_preference); intern->read_preference = NULL; return false; } static const char* php_phongo_readpreference_get_mode_string(mongoc_read_mode_t mode) { switch (mode) { case MONGOC_READ_PRIMARY: return PHONGO_READ_PRIMARY; case MONGOC_READ_PRIMARY_PREFERRED: return PHONGO_READ_PRIMARY_PREFERRED; case MONGOC_READ_SECONDARY: return PHONGO_READ_SECONDARY; case MONGOC_READ_SECONDARY_PREFERRED: return PHONGO_READ_SECONDARY_PREFERRED; case MONGOC_READ_NEAREST: return PHONGO_READ_NEAREST; default: /* Should never happen, but if it does: exception */ phongo_throw_exception(PHONGO_ERROR_LOGIC, "Mode '%d' should never have been passed to php_phongo_readpreference_get_mode_string, please file a bug report", mode); break; } return NULL; } /* Constructs a new ReadPreference */ static PHP_METHOD(MongoDB_Driver_ReadPreference, __construct) { php_phongo_readpreference_t* intern; zval* mode; zval* tagSets = NULL; zval* options = NULL; intern = Z_READPREFERENCE_OBJ_P(getThis()); /* Separate the tagSets zval, since we may end up modifying it in * php_phongo_read_preference_prep_tagsets() below. */ PHONGO_PARSE_PARAMETERS_START(1, 3) Z_PARAM_ZVAL(mode) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_EX(tagSets, 1, 1) Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); if (Z_TYPE_P(mode) == IS_LONG) { php_error_docref(NULL, E_DEPRECATED, "Passing an integer mode to \"MongoDB\\Driver\\ReadPreference::__construct\" is deprecated and will be removed in a future release."); switch (Z_LVAL_P(mode)) { case MONGOC_READ_PRIMARY: case MONGOC_READ_SECONDARY: case MONGOC_READ_PRIMARY_PREFERRED: case MONGOC_READ_SECONDARY_PREFERRED: case MONGOC_READ_NEAREST: intern->read_preference = mongoc_read_prefs_new(Z_LVAL_P(mode)); break; default: phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Invalid mode: %" PHONGO_LONG_FORMAT, Z_LVAL_P(mode)); return; } } else if (Z_TYPE_P(mode) == IS_STRING) { if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_PRIMARY) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_PRIMARY); } else if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_PRIMARY_PREFERRED) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_PRIMARY_PREFERRED); } else if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_SECONDARY) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_SECONDARY); } else if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_SECONDARY_PREFERRED) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_SECONDARY_PREFERRED); } else if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_NEAREST) == 0) { intern->read_preference = mongoc_read_prefs_new(MONGOC_READ_NEAREST); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Invalid mode: '%s'", Z_STRVAL_P(mode)); return; } } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected mode to be integer or string, %s given", zend_zval_type_name(mode)); return; } if (tagSets) { bson_t* tags = bson_new(); php_phongo_read_preference_prep_tagsets(tagSets); php_phongo_zval_to_bson(tagSets, PHONGO_BSON_NONE, (bson_t*) tags, NULL); if (!php_phongo_read_preference_tags_are_valid(tags)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "tagSets must be an array of zero or more documents"); bson_destroy(tags); return; } if (!bson_empty(tags) && (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "tagSets may not be used with primary mode"); bson_destroy(tags); return; } mongoc_read_prefs_set_tags(intern->read_preference, tags); bson_destroy(tags); } if (options && php_array_exists(options, "maxStalenessSeconds")) { zend_long maxStalenessSeconds = php_array_fetchc_long(options, "maxStalenessSeconds"); if (maxStalenessSeconds != MONGOC_NO_MAX_STALENESS) { if (maxStalenessSeconds < MONGOC_SMALLEST_MAX_STALENESS_SECONDS) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected maxStalenessSeconds to be >= %d, %" PHONGO_LONG_FORMAT " given", MONGOC_SMALLEST_MAX_STALENESS_SECONDS, maxStalenessSeconds); return; } if (maxStalenessSeconds > INT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected maxStalenessSeconds to be <= %" PRId32 ", %" PHONGO_LONG_FORMAT " given", INT32_MAX, maxStalenessSeconds); return; } if (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "maxStalenessSeconds may not be used with primary mode"); return; } } mongoc_read_prefs_set_max_staleness_seconds(intern->read_preference, maxStalenessSeconds); } if (options && php_array_exists(options, "hedge")) { zval* hedge = php_array_fetchc_deref(options, "hedge"); if (Z_TYPE_P(hedge) == IS_ARRAY || Z_TYPE_P(hedge) == IS_OBJECT) { bson_t* hedge_doc = bson_new(); if (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "hedge may not be used with primary mode"); bson_destroy(hedge_doc); return; } php_phongo_zval_to_bson(hedge, PHONGO_BSON_NONE, hedge_doc, NULL); if (EG(exception)) { bson_destroy(hedge_doc); return; } mongoc_read_prefs_set_hedge(intern->read_preference, hedge_doc); bson_destroy(hedge_doc); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"hedge\" field to be an array or object", ZSTR_VAL(php_phongo_readpreference_ce->name)); return; } } if (!mongoc_read_prefs_is_valid(intern->read_preference)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Read preference is not valid"); return; } } static PHP_METHOD(MongoDB_Driver_ReadPreference, __set_state) { php_phongo_readpreference_t* intern; HashTable* props; zval* array; /* Separate the zval, since we may end up modifying the "tags" element in * php_phongo_read_preference_prep_tagsets(), which is called from * php_phongo_readpreference_init_from_hash. */ PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY_EX(array, 0, 1) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_readpreference_ce); intern = Z_READPREFERENCE_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_readpreference_init_from_hash(intern, props); } /* Returns the ReadPreference hedge document */ static PHP_METHOD(MongoDB_Driver_ReadPreference, getHedge) { php_phongo_readpreference_t* intern; const bson_t* hedge; intern = Z_READPREFERENCE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); hedge = mongoc_read_prefs_get_hedge(intern->read_preference); if (!bson_empty0(hedge)) { php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); if (!php_phongo_bson_to_zval_ex(hedge, &state)) { zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } else { RETURN_NULL(); } } /* Returns the ReadPreference maxStalenessSeconds value */ static PHP_METHOD(MongoDB_Driver_ReadPreference, getMaxStalenessSeconds) { php_phongo_readpreference_t* intern; intern = Z_READPREFERENCE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(mongoc_read_prefs_get_max_staleness_seconds(intern->read_preference)); } /* Returns the ReadPreference mode */ static PHP_METHOD(MongoDB_Driver_ReadPreference, getMode) { php_phongo_readpreference_t* intern; intern = Z_READPREFERENCE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(mongoc_read_prefs_get_mode(intern->read_preference)); } /* Returns the ReadPreference mode as string */ static PHP_METHOD(MongoDB_Driver_ReadPreference, getModeString) { php_phongo_readpreference_t* intern; const char* mode_string; intern = Z_READPREFERENCE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); mode_string = php_phongo_readpreference_get_mode_string(mongoc_read_prefs_get_mode(intern->read_preference)); if (!mode_string) { /* Exception already thrown */ return; } RETURN_STRING(mode_string); } /* Returns the ReadPreference tag sets */ static PHP_METHOD(MongoDB_Driver_ReadPreference, getTagSets) { php_phongo_readpreference_t* intern; const bson_t* tags; intern = Z_READPREFERENCE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); tags = mongoc_read_prefs_get_tags(intern->read_preference); if (tags->len) { php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); if (!php_phongo_bson_to_zval_ex(tags, &state)) { zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } else { RETURN_NULL(); } } static HashTable* php_phongo_readpreference_get_properties_hash(zend_object* object, bool is_temp) { php_phongo_readpreference_t* intern; HashTable* props; const char* modeString = NULL; const bson_t* tags; const bson_t* hedge; mongoc_read_mode_t mode; intern = Z_OBJ_READPREFERENCE(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 4); if (!intern->read_preference) { return props; } tags = mongoc_read_prefs_get_tags(intern->read_preference); mode = mongoc_read_prefs_get_mode(intern->read_preference); modeString = php_phongo_readpreference_get_mode_string(mode); hedge = mongoc_read_prefs_get_hedge(intern->read_preference); if (modeString) { zval z_mode; ZVAL_STRING(&z_mode, modeString); zend_hash_str_update(props, "mode", sizeof("mode") - 1, &z_mode); } if (!bson_empty0(tags)) { php_phongo_bson_state state; /* Use PHONGO_TYPEMAP_NATIVE_ARRAY for the root type since tags is an * array; however, inner documents and arrays can use the default. */ PHONGO_BSON_INIT_STATE(state); state.map.root.type = PHONGO_TYPEMAP_NATIVE_ARRAY; if (!php_phongo_bson_to_zval_ex(tags, &state)) { zval_ptr_dtor(&state.zchild); goto done; } zend_hash_str_update(props, "tags", sizeof("tags") - 1, &state.zchild); } if (mongoc_read_prefs_get_max_staleness_seconds(intern->read_preference) != MONGOC_NO_MAX_STALENESS) { /* Note: valid values for maxStalesnessSeconds will not exceed the range * of 32-bit signed integers, so conditional encoding is not necessary. */ long maxStalenessSeconds = mongoc_read_prefs_get_max_staleness_seconds(intern->read_preference); zval z_max_ss; ZVAL_LONG(&z_max_ss, maxStalenessSeconds); zend_hash_str_update(props, "maxStalenessSeconds", sizeof("maxStalenessSeconds") - 1, &z_max_ss); } if (!bson_empty0(hedge)) { php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); if (!php_phongo_bson_to_zval_ex(hedge, &state)) { zval_ptr_dtor(&state.zchild); goto done; } zend_hash_str_update(props, "hedge", sizeof("hedge") - 1, &state.zchild); } done: return props; } static PHP_METHOD(MongoDB_Driver_ReadPreference, bsonSerialize) { PHONGO_PARSE_PARAMETERS_NONE(); ZVAL_ARR(return_value, php_phongo_readpreference_get_properties_hash(Z_OBJ_P(getThis()), true)); convert_to_object(return_value); } static PHP_METHOD(MongoDB_Driver_ReadPreference, serialize) { php_phongo_readpreference_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; const char* modeString = NULL; const bson_t* tags; const bson_t* hedge; int64_t maxStalenessSeconds; mongoc_read_mode_t mode; intern = Z_READPREFERENCE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!intern->read_preference) { return; } tags = mongoc_read_prefs_get_tags(intern->read_preference); mode = mongoc_read_prefs_get_mode(intern->read_preference); modeString = php_phongo_readpreference_get_mode_string(mode); maxStalenessSeconds = mongoc_read_prefs_get_max_staleness_seconds(intern->read_preference); hedge = mongoc_read_prefs_get_hedge(intern->read_preference); array_init_size(&retval, 4); if (modeString) { ADD_ASSOC_STRING(&retval, "mode", modeString); } if (!bson_empty0(tags)) { php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); if (!php_phongo_bson_to_zval_ex(tags, &state)) { zval_ptr_dtor(&state.zchild); return; } ADD_ASSOC_ZVAL_EX(&retval, "tags", &state.zchild); } if (maxStalenessSeconds != MONGOC_NO_MAX_STALENESS) { ADD_ASSOC_LONG_EX(&retval, "maxStalenessSeconds", maxStalenessSeconds); } if (!bson_empty0(hedge)) { php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); if (!php_phongo_bson_to_zval_ex(hedge, &state)) { zval_ptr_dtor(&state.zchild); return; } ADD_ASSOC_ZVAL_EX(&retval, "hedge", &state.zchild); } PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_Driver_ReadPreference, unserialize) { php_phongo_readpreference_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_READPREFERENCE_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); if (!serialized_len) { return; } PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_readpreference_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_readpreference_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_Driver_ReadPreference, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_readpreference_get_properties_hash(Z_OBJ_P(getThis()), true)); } static PHP_METHOD(MongoDB_Driver_ReadPreference, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_readpreference_init_from_hash(Z_READPREFERENCE_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\Driver\ReadPreference object handlers */ static zend_object_handlers php_phongo_handler_readpreference; static void php_phongo_readpreference_free_object(zend_object* object) { php_phongo_readpreference_t* intern = Z_OBJ_READPREFERENCE(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } if (intern->read_preference) { mongoc_read_prefs_destroy(intern->read_preference); } } static zend_object* php_phongo_readpreference_create_object(zend_class_entry* class_type) { php_phongo_readpreference_t* intern = zend_object_alloc(sizeof(php_phongo_readpreference_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_readpreference; return &intern->std; } static HashTable* php_phongo_readpreference_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_readpreference_get_properties_hash(object, true); } static HashTable* php_phongo_readpreference_get_properties(zend_object* object) { return php_phongo_readpreference_get_properties_hash(object, false); } void php_phongo_readpreference_init_ce(INIT_FUNC_ARGS) { php_phongo_readpreference_ce = register_class_MongoDB_Driver_ReadPreference(php_phongo_serializable_ce, zend_ce_serializable); php_phongo_readpreference_ce->create_object = php_phongo_readpreference_create_object; memcpy(&php_phongo_handler_readpreference, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_readpreference.get_debug_info = php_phongo_readpreference_get_debug_info; php_phongo_handler_readpreference.get_properties = php_phongo_readpreference_get_properties; php_phongo_handler_readpreference.free_obj = php_phongo_readpreference_free_object; php_phongo_handler_readpreference.offset = XtOffsetOf(php_phongo_readpreference_t, std); } void phongo_readpreference_init(zval* return_value, const mongoc_read_prefs_t* read_prefs) { php_phongo_readpreference_t* intern; object_init_ex(return_value, php_phongo_readpreference_ce); intern = Z_READPREFERENCE_OBJ_P(return_value); intern->read_preference = mongoc_read_prefs_copy(read_prefs); } const mongoc_read_prefs_t* phongo_read_preference_from_zval(zval* zread_preference) { if (zread_preference) { php_phongo_readpreference_t* intern = Z_READPREFERENCE_OBJ_P(zread_preference); if (intern) { return intern->read_preference; } } return NULL; } /* Prepare tagSets for BSON encoding by converting each array in the set to an * object. This ensures that empty arrays will serialize as empty documents. * * php_phongo_read_preference_tags_are_valid() handles actual validation of the * tag set structure. */ void php_phongo_read_preference_prep_tagsets(zval* tagSets) { HashTable* ht_data; zval* tagSet; if (Z_TYPE_P(tagSets) != IS_ARRAY) { return; } ht_data = HASH_OF(tagSets); ZEND_HASH_FOREACH_VAL_IND(ht_data, tagSet) { ZVAL_DEREF(tagSet); if (Z_TYPE_P(tagSet) == IS_ARRAY) { SEPARATE_ZVAL_NOREF(tagSet); convert_to_object(tagSet); } } ZEND_HASH_FOREACH_END(); } /* Checks if tags is valid to set on a mongoc_read_prefs_t. It may be null or an * array of one or more documents. */ bool php_phongo_read_preference_tags_are_valid(const bson_t* tags) { bson_iter_t iter; if (bson_empty0(tags)) { return true; } if (!bson_iter_init(&iter, tags)) { return false; } while (bson_iter_next(&iter)) { if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) { return false; } } return true; } mongodb-1.21.0/src/MongoDB/ReadPreference.h0000644000175100001660000000245114760300420015236 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_READPREFERENCE_H #define PHONGO_READPREFERENCE_H #include "bson/bson.h" #include "mongoc/mongoc.h" #include #define PHONGO_READ_PRIMARY "primary" #define PHONGO_READ_PRIMARY_PREFERRED "primaryPreferred" #define PHONGO_READ_SECONDARY "secondary" #define PHONGO_READ_SECONDARY_PREFERRED "secondaryPreferred" #define PHONGO_READ_NEAREST "nearest" void phongo_readpreference_init(zval* return_value, const mongoc_read_prefs_t* read_prefs); const mongoc_read_prefs_t* phongo_read_preference_from_zval(zval* zread_preference); void php_phongo_read_preference_prep_tagsets(zval* tagSets); bool php_phongo_read_preference_tags_are_valid(const bson_t* tags); #endif /* PHONGO_READPREFERENCE_H */ mongodb-1.21.0/src/MongoDB/ReadPreference_arginfo.h0000644000175100001660000002513014760300420016742 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 749f4ec07a374c2d9abb2dcb4cb1e7204d52923d */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference___construct, 0, 0, 1) ZEND_ARG_TYPE_MASK(0, mode, MAY_BE_STRING|MAY_BE_LONG, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, tagSets, IS_ARRAY, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference_getHedge, 0, 0, IS_OBJECT, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference_getMaxStalenessSeconds, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_ReadPreference_getMode arginfo_class_MongoDB_Driver_ReadPreference_getMaxStalenessSeconds ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference_getModeString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference_getTagSets, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference___set_state, 0, 1, MongoDB\\Driver\\ReadPreference, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference_bsonSerialize, 0, 0, stdClass, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_ReadPreference_serialize arginfo_class_MongoDB_Driver_ReadPreference_getModeString ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ReadPreference___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_ReadPreference___serialize arginfo_class_MongoDB_Driver_ReadPreference_getTagSets static ZEND_METHOD(MongoDB_Driver_ReadPreference, __construct); static ZEND_METHOD(MongoDB_Driver_ReadPreference, getHedge); static ZEND_METHOD(MongoDB_Driver_ReadPreference, getMaxStalenessSeconds); static ZEND_METHOD(MongoDB_Driver_ReadPreference, getMode); static ZEND_METHOD(MongoDB_Driver_ReadPreference, getModeString); static ZEND_METHOD(MongoDB_Driver_ReadPreference, getTagSets); static ZEND_METHOD(MongoDB_Driver_ReadPreference, __set_state); static ZEND_METHOD(MongoDB_Driver_ReadPreference, bsonSerialize); static ZEND_METHOD(MongoDB_Driver_ReadPreference, serialize); static ZEND_METHOD(MongoDB_Driver_ReadPreference, unserialize); static ZEND_METHOD(MongoDB_Driver_ReadPreference, __unserialize); static ZEND_METHOD(MongoDB_Driver_ReadPreference, __serialize); static const zend_function_entry class_MongoDB_Driver_ReadPreference_methods[] = { ZEND_ME(MongoDB_Driver_ReadPreference, __construct, arginfo_class_MongoDB_Driver_ReadPreference___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, getHedge, arginfo_class_MongoDB_Driver_ReadPreference_getHedge, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, getMaxStalenessSeconds, arginfo_class_MongoDB_Driver_ReadPreference_getMaxStalenessSeconds, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, getMode, arginfo_class_MongoDB_Driver_ReadPreference_getMode, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL|ZEND_ACC_DEPRECATED) ZEND_ME(MongoDB_Driver_ReadPreference, getModeString, arginfo_class_MongoDB_Driver_ReadPreference_getModeString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, getTagSets, arginfo_class_MongoDB_Driver_ReadPreference_getTagSets, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, __set_state, arginfo_class_MongoDB_Driver_ReadPreference___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, bsonSerialize, arginfo_class_MongoDB_Driver_ReadPreference_bsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, serialize, arginfo_class_MongoDB_Driver_ReadPreference_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, unserialize, arginfo_class_MongoDB_Driver_ReadPreference_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, __unserialize, arginfo_class_MongoDB_Driver_ReadPreference___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ReadPreference, __serialize, arginfo_class_MongoDB_Driver_ReadPreference___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_ReadPreference(zend_class_entry *class_entry_MongoDB_BSON_Serializable, zend_class_entry *class_entry_Serializable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "ReadPreference", class_MongoDB_Driver_ReadPreference_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 2, class_entry_MongoDB_BSON_Serializable, class_entry_Serializable); zval const_RP_PRIMARY_value; ZVAL_LONG(&const_RP_PRIMARY_value, MONGOC_READ_PRIMARY); zend_string *const_RP_PRIMARY_name = zend_string_init_interned("RP_PRIMARY", sizeof("RP_PRIMARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_RP_PRIMARY_name, &const_RP_PRIMARY_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL); zend_string_release(const_RP_PRIMARY_name); zval const_RP_PRIMARY_PREFERRED_value; ZVAL_LONG(&const_RP_PRIMARY_PREFERRED_value, MONGOC_READ_PRIMARY_PREFERRED); zend_string *const_RP_PRIMARY_PREFERRED_name = zend_string_init_interned("RP_PRIMARY_PREFERRED", sizeof("RP_PRIMARY_PREFERRED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_RP_PRIMARY_PREFERRED_name, &const_RP_PRIMARY_PREFERRED_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL); zend_string_release(const_RP_PRIMARY_PREFERRED_name); zval const_RP_SECONDARY_value; ZVAL_LONG(&const_RP_SECONDARY_value, MONGOC_READ_SECONDARY); zend_string *const_RP_SECONDARY_name = zend_string_init_interned("RP_SECONDARY", sizeof("RP_SECONDARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_RP_SECONDARY_name, &const_RP_SECONDARY_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL); zend_string_release(const_RP_SECONDARY_name); zval const_RP_SECONDARY_PREFERRED_value; ZVAL_LONG(&const_RP_SECONDARY_PREFERRED_value, MONGOC_READ_SECONDARY_PREFERRED); zend_string *const_RP_SECONDARY_PREFERRED_name = zend_string_init_interned("RP_SECONDARY_PREFERRED", sizeof("RP_SECONDARY_PREFERRED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_RP_SECONDARY_PREFERRED_name, &const_RP_SECONDARY_PREFERRED_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL); zend_string_release(const_RP_SECONDARY_PREFERRED_name); zval const_RP_NEAREST_value; ZVAL_LONG(&const_RP_NEAREST_value, MONGOC_READ_NEAREST); zend_string *const_RP_NEAREST_name = zend_string_init_interned("RP_NEAREST", sizeof("RP_NEAREST") - 1, 1); zend_declare_class_constant_ex(class_entry, const_RP_NEAREST_name, &const_RP_NEAREST_value, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL); zend_string_release(const_RP_NEAREST_name); zval const_PRIMARY_value; zend_string *const_PRIMARY_value_str = zend_string_init(PHONGO_READ_PRIMARY, strlen(PHONGO_READ_PRIMARY), 1); ZVAL_STR(&const_PRIMARY_value, const_PRIMARY_value_str); zend_string *const_PRIMARY_name = zend_string_init_interned("PRIMARY", sizeof("PRIMARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_PRIMARY_name, &const_PRIMARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_PRIMARY_name); zval const_PRIMARY_PREFERRED_value; zend_string *const_PRIMARY_PREFERRED_value_str = zend_string_init(PHONGO_READ_PRIMARY_PREFERRED, strlen(PHONGO_READ_PRIMARY_PREFERRED), 1); ZVAL_STR(&const_PRIMARY_PREFERRED_value, const_PRIMARY_PREFERRED_value_str); zend_string *const_PRIMARY_PREFERRED_name = zend_string_init_interned("PRIMARY_PREFERRED", sizeof("PRIMARY_PREFERRED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_PRIMARY_PREFERRED_name, &const_PRIMARY_PREFERRED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_PRIMARY_PREFERRED_name); zval const_SECONDARY_value; zend_string *const_SECONDARY_value_str = zend_string_init(PHONGO_READ_SECONDARY, strlen(PHONGO_READ_SECONDARY), 1); ZVAL_STR(&const_SECONDARY_value, const_SECONDARY_value_str); zend_string *const_SECONDARY_name = zend_string_init_interned("SECONDARY", sizeof("SECONDARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_SECONDARY_name, &const_SECONDARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_SECONDARY_name); zval const_SECONDARY_PREFERRED_value; zend_string *const_SECONDARY_PREFERRED_value_str = zend_string_init(PHONGO_READ_SECONDARY_PREFERRED, strlen(PHONGO_READ_SECONDARY_PREFERRED), 1); ZVAL_STR(&const_SECONDARY_PREFERRED_value, const_SECONDARY_PREFERRED_value_str); zend_string *const_SECONDARY_PREFERRED_name = zend_string_init_interned("SECONDARY_PREFERRED", sizeof("SECONDARY_PREFERRED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_SECONDARY_PREFERRED_name, &const_SECONDARY_PREFERRED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_SECONDARY_PREFERRED_name); zval const_NEAREST_value; zend_string *const_NEAREST_value_str = zend_string_init(PHONGO_READ_NEAREST, strlen(PHONGO_READ_NEAREST), 1); ZVAL_STR(&const_NEAREST_value, const_NEAREST_value_str); zend_string *const_NEAREST_name = zend_string_init_interned("NEAREST", sizeof("NEAREST") - 1, 1); zend_declare_class_constant_ex(class_entry, const_NEAREST_name, &const_NEAREST_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_NEAREST_name); zval const_NO_MAX_STALENESS_value; ZVAL_LONG(&const_NO_MAX_STALENESS_value, MONGOC_NO_MAX_STALENESS); zend_string *const_NO_MAX_STALENESS_name = zend_string_init_interned("NO_MAX_STALENESS", sizeof("NO_MAX_STALENESS") - 1, 1); zend_declare_class_constant_ex(class_entry, const_NO_MAX_STALENESS_name, &const_NO_MAX_STALENESS_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_NO_MAX_STALENESS_name); zval const_SMALLEST_MAX_STALENESS_SECONDS_value; ZVAL_LONG(&const_SMALLEST_MAX_STALENESS_SECONDS_value, MONGOC_SMALLEST_MAX_STALENESS_SECONDS); zend_string *const_SMALLEST_MAX_STALENESS_SECONDS_name = zend_string_init_interned("SMALLEST_MAX_STALENESS_SECONDS", sizeof("SMALLEST_MAX_STALENESS_SECONDS") - 1, 1); zend_declare_class_constant_ex(class_entry, const_SMALLEST_MAX_STALENESS_SECONDS_name, &const_SMALLEST_MAX_STALENESS_SECONDS_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_SMALLEST_MAX_STALENESS_SECONDS_name); return class_entry; } mongodb-1.21.0/src/MongoDB/Server.c0000644000175100001660000005510714760300420013633 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_client.h" #include "phongo_error.h" #include "phongo_execute.h" #include "phongo_util.h" #include "MongoDB/Server.h" #include "MongoDB/ServerDescription.h" #include "Server_arginfo.h" zend_class_entry* php_phongo_server_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Server) /* Executes a Command on this Server */ static PHP_METHOD(MongoDB_Driver_Server, executeCommand) { php_phongo_server_t* intern; char* db; size_t db_len; zval* command; zval* options = NULL; bool free_options = false; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(db, db_len) Z_PARAM_OBJECT_OF_CLASS(command, php_phongo_command_ce) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); options = php_phongo_prep_legacy_option(options, "readPreference", &free_options); /* If the Server was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager)); phongo_execute_command(&intern->manager, PHONGO_COMMAND_RAW, db, command, options, intern->server_id, return_value); if (free_options) { php_phongo_prep_legacy_option_free(options); } } /* Executes a ReadCommand on this Server */ static PHP_METHOD(MongoDB_Driver_Server, executeReadCommand) { php_phongo_server_t* intern; char* db; size_t db_len; zval* command; zval* options = NULL; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(db, db_len) Z_PARAM_OBJECT_OF_CLASS(command, php_phongo_command_ce) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); /* If the Server was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager)); phongo_execute_command(&intern->manager, PHONGO_COMMAND_READ, db, command, options, intern->server_id, return_value); } /* Executes a WriteCommand on this Server */ static PHP_METHOD(MongoDB_Driver_Server, executeWriteCommand) { php_phongo_server_t* intern; char* db; size_t db_len; zval* command; zval* options = NULL; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(db, db_len) Z_PARAM_OBJECT_OF_CLASS(command, php_phongo_command_ce) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); /* If the Server was created in a different process, reset the client so * that cursors created by this process can be differentiated. and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager)); phongo_execute_command(&intern->manager, PHONGO_COMMAND_WRITE, db, command, options, intern->server_id, return_value); } /* Executes a ReadWriteCommand on this Server */ static PHP_METHOD(MongoDB_Driver_Server, executeReadWriteCommand) { php_phongo_server_t* intern; char* db; size_t db_len; zval* command; zval* options = NULL; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(db, db_len) Z_PARAM_OBJECT_OF_CLASS(command, php_phongo_command_ce) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); /* If the Server was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager)); phongo_execute_command(&intern->manager, PHONGO_COMMAND_READ_WRITE, db, command, options, intern->server_id, return_value); } /* Executes a Query on this Server */ static PHP_METHOD(MongoDB_Driver_Server, executeQuery) { php_phongo_server_t* intern; char* namespace; size_t namespace_len; zval* query; zval* options = NULL; bool free_options = false; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(namespace, namespace_len) Z_PARAM_OBJECT_OF_CLASS(query, php_phongo_query_ce) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); options = php_phongo_prep_legacy_option(options, "readPreference", &free_options); /* If the Server was created in a different process, reset the client so * that cursors created by this process can be differentiated and its * session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager)); phongo_execute_query(&intern->manager, namespace, query, options, intern->server_id, return_value); if (free_options) { php_phongo_prep_legacy_option_free(options); } } /* Executes a BulkWrite (i.e. any number of insert, update, and delete ops) on this Server */ static PHP_METHOD(MongoDB_Driver_Server, executeBulkWrite) { php_phongo_server_t* intern; char* namespace; size_t namespace_len; zval* zbulk; php_phongo_bulkwrite_t* bulk; zval* options = NULL; bool free_options = false; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(namespace, namespace_len) Z_PARAM_OBJECT_OF_CLASS(zbulk, php_phongo_bulkwrite_ce) Z_PARAM_OPTIONAL Z_PARAM_ZVAL_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); bulk = Z_BULKWRITE_OBJ_P(zbulk); options = php_phongo_prep_legacy_option(options, "writeConcern", &free_options); /* If the Server was created in a different process, reset the client so * that its session pool is cleared. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager)); phongo_execute_bulk_write(&intern->manager, namespace, bulk, options, intern->server_id, return_value); if (free_options) { php_phongo_prep_legacy_option_free(options); } } /* Returns the hostname for this Server */ static PHP_METHOD(MongoDB_Driver_Server, getHost) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { RETVAL_STRING(mongoc_server_description_host(sd)->host); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* Returns the currently configured tags for this Server */ static PHP_METHOD(MongoDB_Driver_Server, getTags) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { const bson_t* hello_response = mongoc_server_description_hello_response(sd); bson_iter_t iter; if (bson_iter_init_find(&iter, hello_response, "tags") && BSON_ITER_HOLDS_DOCUMENT(&iter)) { const uint8_t* bytes; uint32_t len; php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); bson_iter_document(&iter, &len, &bytes); if (!php_phongo_bson_data_to_zval_ex(bytes, len, &state)) { /* Exception should already have been thrown */ zval_ptr_dtor(&state.zchild); mongoc_server_description_destroy(sd); return; } mongoc_server_description_destroy(sd); RETURN_ZVAL(&state.zchild, 0, 1); } array_init(return_value); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* Returns the last hello response for this Server or, in the case of a load balancer, the initial handshake response. */ static PHP_METHOD(MongoDB_Driver_Server, getInfo) { php_phongo_server_t* intern; mongoc_client_t* client; mongoc_server_description_t* sd; mongoc_server_description_t* handshake_sd = NULL; const bson_t* hello_response; php_phongo_bson_state state; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_SERVER_OBJ_P(getThis()); client = Z_MANAGER_OBJ_P(&intern->manager)->client; if (!(sd = mongoc_client_get_server_description(client, intern->server_id))) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); return; } hello_response = mongoc_server_description_hello_response(sd); /* If the server description is a load balancer, its hello_response will be * empty. Instead, report the hello_response from the handshake description * (i.e. backing server). */ if (!strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_LOAD_BALANCER].name)) { bson_error_t error = { 0 }; if (!(handshake_sd = mongoc_client_get_handshake_description(client, intern->server_id, NULL, &error))) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get handshake server description: %s", error.message); goto cleanup; } hello_response = mongoc_server_description_hello_response(handshake_sd); } PHONGO_BSON_INIT_DEBUG_STATE(state); if (!php_phongo_bson_to_zval_ex(hello_response, &state)) { /* Exception should already have been thrown */ zval_ptr_dtor(&state.zchild); goto cleanup; } RETVAL_ZVAL(&state.zchild, 0, 1); cleanup: if (handshake_sd) { mongoc_server_description_destroy(handshake_sd); } mongoc_server_description_destroy(sd); } /* Returns the measured latency (i.e. round trip time in milliseconds) for this Server, or null if unset. */ static PHP_METHOD(MongoDB_Driver_Server, getLatency) { php_phongo_server_t* intern; mongoc_server_description_t* sd; PHONGO_PARSE_PARAMETERS_NONE(); intern = Z_SERVER_OBJ_P(getThis()); if (!(sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); return; } /* TODO: Use MONGOC_RTT_UNSET once it is added to libmongoc's public API (CDRIVER-4176) */ if (mongoc_server_description_round_trip_time(sd) == -1) { RETVAL_NULL(); } else { RETVAL_LONG(mongoc_server_description_round_trip_time(sd)); } mongoc_server_description_destroy(sd); } /* Returns the port for this Server */ static PHP_METHOD(MongoDB_Driver_Server, getPort) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { RETVAL_LONG(mongoc_server_description_host(sd)->port); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* Returns the server description for this Server */ static PHP_METHOD(MongoDB_Driver_Server, getServerDescription) { mongoc_server_description_t* server_description; php_phongo_server_t* intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); server_description = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id); /* Avoid making another copy in phongo_serverdescription_init */ phongo_serverdescription_init_ex(return_value, server_description, false); } /* Returns the node type of this Server */ static PHP_METHOD(MongoDB_Driver_Server, getType) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { RETVAL_LONG(php_phongo_server_description_type(sd)); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* Returns whether this Server is a primary member of a replica set */ static PHP_METHOD(MongoDB_Driver_Server, isPrimary) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { RETVAL_BOOL(!strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_RS_PRIMARY].name)); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* Returns whether this Server is a secondary member of a replica set */ static PHP_METHOD(MongoDB_Driver_Server, isSecondary) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { RETVAL_BOOL(!strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_RS_SECONDARY].name)); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* Returns whether this Server is an arbiter member of a replica set */ static PHP_METHOD(MongoDB_Driver_Server, isArbiter) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { RETVAL_BOOL(!strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_RS_ARBITER].name)); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* Returns whether this Server is a hidden member of a replica set */ static PHP_METHOD(MongoDB_Driver_Server, isHidden) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { bson_iter_t iter; RETVAL_BOOL(bson_iter_init_find_case(&iter, mongoc_server_description_hello_response(sd), "hidden") && bson_iter_as_bool(&iter)); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* Returns whether this Server is a passive member of a replica set */ static PHP_METHOD(MongoDB_Driver_Server, isPassive) { php_phongo_server_t* intern; mongoc_server_description_t* sd; intern = Z_SERVER_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if ((sd = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern->manager)->client, intern->server_id))) { bson_iter_t iter; RETVAL_BOOL(bson_iter_init_find_case(&iter, mongoc_server_description_hello_response(sd), "passive") && bson_iter_as_bool(&iter)); mongoc_server_description_destroy(sd); return; } phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); } /* MongoDB\Driver\Server object handlers */ static zend_object_handlers php_phongo_handler_server; static int php_phongo_server_compare_objects(zval* o1, zval* o2) { php_phongo_server_t* intern1; php_phongo_server_t* intern2; mongoc_server_description_t *sd1, *sd2; int retval = 0; ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2); intern1 = Z_SERVER_OBJ_P(o1); intern2 = Z_SERVER_OBJ_P(o2); sd1 = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern1->manager)->client, intern1->server_id); sd2 = mongoc_client_get_server_description(Z_MANAGER_OBJ_P(&intern2->manager)->client, intern2->server_id); if (sd1 && sd2) { retval = strcasecmp(mongoc_server_description_host(sd1)->host_and_port, mongoc_server_description_host(sd2)->host_and_port); } else { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description(s)"); } if (sd1) { mongoc_server_description_destroy(sd1); } if (sd2) { mongoc_server_description_destroy(sd2); } return retval; } static void php_phongo_server_free_object(zend_object* object) { php_phongo_server_t* intern = Z_OBJ_SERVER(object); zend_object_std_dtor(&intern->std); if (!Z_ISUNDEF(intern->manager)) { zval_ptr_dtor(&intern->manager); } } static zend_object* php_phongo_server_create_object(zend_class_entry* class_type) { php_phongo_server_t* intern = zend_object_alloc(sizeof(php_phongo_server_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); PHONGO_SET_CREATED_BY_PID(intern); intern->std.handlers = &php_phongo_handler_server; return &intern->std; } static HashTable* php_phongo_server_get_debug_info(zend_object* object, int* is_temp) { php_phongo_server_t* intern = NULL; zval retval = ZVAL_STATIC_INIT; mongoc_client_t* client; mongoc_server_description_t* sd; *is_temp = 1; intern = Z_OBJ_SERVER(object); client = Z_MANAGER_OBJ_P(&intern->manager)->client; if (!(sd = mongoc_client_get_server_description(client, intern->server_id))) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get server description"); return NULL; } php_phongo_server_to_zval(&retval, client, sd); mongoc_server_description_destroy(sd); return Z_ARRVAL(retval); } void php_phongo_server_init_ce(INIT_FUNC_ARGS) { php_phongo_server_ce = register_class_MongoDB_Driver_Server(); php_phongo_server_ce->create_object = php_phongo_server_create_object; memcpy(&php_phongo_handler_server, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_server.compare = php_phongo_server_compare_objects; php_phongo_handler_server.get_debug_info = php_phongo_server_get_debug_info; php_phongo_handler_server.free_obj = php_phongo_server_free_object; php_phongo_handler_server.offset = XtOffsetOf(php_phongo_server_t, std); } void phongo_server_init(zval* return_value, zval* manager, uint32_t server_id) { php_phongo_server_t* server; object_init_ex(return_value, php_phongo_server_ce); server = Z_SERVER_OBJ_P(return_value); server->server_id = server_id; ZVAL_ZVAL(&server->manager, manager, 1, 0); } bool php_phongo_server_to_zval(zval* retval, mongoc_client_t* client, mongoc_server_description_t* sd) { mongoc_host_list_t* host = mongoc_server_description_host(sd); const bson_t* hello_response = mongoc_server_description_hello_response(sd); bson_iter_t iter; array_init(retval); ADD_ASSOC_STRING(retval, "host", host->host); ADD_ASSOC_LONG_EX(retval, "port", host->port); ADD_ASSOC_LONG_EX(retval, "type", php_phongo_server_description_type(sd)); ADD_ASSOC_BOOL_EX(retval, "is_primary", !strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_RS_PRIMARY].name)); ADD_ASSOC_BOOL_EX(retval, "is_secondary", !strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_RS_SECONDARY].name)); ADD_ASSOC_BOOL_EX(retval, "is_arbiter", !strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_RS_ARBITER].name)); ADD_ASSOC_BOOL_EX(retval, "is_hidden", bson_iter_init_find_case(&iter, hello_response, "hidden") && bson_iter_as_bool(&iter)); ADD_ASSOC_BOOL_EX(retval, "is_passive", bson_iter_init_find_case(&iter, hello_response, "passive") && bson_iter_as_bool(&iter)); if (bson_iter_init_find(&iter, hello_response, "tags") && BSON_ITER_HOLDS_DOCUMENT(&iter)) { const uint8_t* bytes; uint32_t len; php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); bson_iter_document(&iter, &len, &bytes); if (!php_phongo_bson_data_to_zval_ex(bytes, len, &state)) { /* Exception already thrown */ zval_ptr_dtor(&state.zchild); return false; } ADD_ASSOC_ZVAL_EX(retval, "tags", &state.zchild); } /* If the server description is a load balancer, its hello_response will be * empty. Instead, report the hello_response from the handshake description * (i.e. backing server). */ if (!strcmp(mongoc_server_description_type(sd), php_phongo_server_description_type_map[PHONGO_SERVER_LOAD_BALANCER].name)) { const bson_t* handshake_response; mongoc_server_description_t* handshake_sd; bson_error_t error = { 0 }; php_phongo_bson_state state; if (!(handshake_sd = mongoc_client_get_handshake_description(client, mongoc_server_description_id(sd), NULL, &error))) { phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Failed to get handshake server description: %s", error.message); return false; } PHONGO_BSON_INIT_DEBUG_STATE(state); handshake_response = mongoc_server_description_hello_response(handshake_sd); if (!php_phongo_bson_to_zval_ex(handshake_response, &state)) { /* Exception already thrown */ mongoc_server_description_destroy(handshake_sd); zval_ptr_dtor(&state.zchild); return false; } ADD_ASSOC_ZVAL_EX(retval, "last_hello_response", &state.zchild); mongoc_server_description_destroy(handshake_sd); } else { php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); if (!php_phongo_bson_to_zval_ex(hello_response, &state)) { /* Exception already thrown */ zval_ptr_dtor(&state.zchild); return false; } ADD_ASSOC_ZVAL_EX(retval, "last_hello_response", &state.zchild); } /* TODO: Use MONGOC_RTT_UNSET once it is added to libmongoc's public API (CDRIVER-4176) */ if (mongoc_server_description_round_trip_time(sd) == -1) { ADD_ASSOC_NULL_EX(retval, "round_trip_time"); } else { ADD_ASSOC_LONG_EX(retval, "round_trip_time", mongoc_server_description_round_trip_time(sd)); } return true; } mongodb-1.21.0/src/MongoDB/Server.h0000644000175100001660000000162214760300420013631 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_SERVER_H #define PHONGO_SERVER_H #include "mongoc/mongoc.h" #include void phongo_server_init(zval* return_value, zval* manager, uint32_t server_id); bool php_phongo_server_to_zval(zval* retval, mongoc_client_t* client, mongoc_server_description_t* sd); #endif /* PHONGO_SERVER_H */ mongodb-1.21.0/src/MongoDB/ServerApi.c0000644000175100001660000002477714760300420014276 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "mongoc/mongoc.h" #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "ServerApi_arginfo.h" zend_class_entry* php_phongo_serverapi_ce; static bool php_phongo_serverapi_create_libmongoc_object(mongoc_server_api_t** server_api, zend_string* version, bool strict_set, bool strict, bool deprecation_errors_set, bool deprecation_errors) { mongoc_server_api_version_t server_api_version; if (!mongoc_server_api_version_from_string(ZSTR_VAL(version), &server_api_version)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Server API version \"%s\" is not supported in this driver version", ZSTR_VAL(version)); return false; } if (*server_api) { phongo_throw_exception(PHONGO_ERROR_LOGIC, "Server API object already initialized. Please file a bug report as this should not happen."); return false; } *server_api = mongoc_server_api_new(server_api_version); if (strict_set) { mongoc_server_api_strict(*server_api, strict); } if (deprecation_errors_set) { mongoc_server_api_deprecation_errors(*server_api, deprecation_errors); } return true; } /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_serverapi_init_from_hash(php_phongo_serverapi_t* intern, HashTable* props) { zval* version; zval* strict; zval* deprecation_errors; version = zend_hash_str_find(props, ZEND_STRL("version")); if (!version || Z_TYPE_P(version) != IS_STRING) { // Exception phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"version\" field to be string", ZSTR_VAL(php_phongo_serverapi_ce->name)); return false; } if ((strict = zend_hash_str_find(props, ZEND_STRL("strict"))) && !ZVAL_IS_NULL(strict)) { if (Z_TYPE_P(strict) != IS_TRUE && Z_TYPE_P(strict) != IS_FALSE) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"strict\" field to be bool or null", ZSTR_VAL(php_phongo_serverapi_ce->name)); return false; } } if ((deprecation_errors = zend_hash_str_find(props, ZEND_STRL("deprecationErrors"))) && !ZVAL_IS_NULL(deprecation_errors)) { if (Z_TYPE_P(deprecation_errors) != IS_TRUE && Z_TYPE_P(deprecation_errors) != IS_FALSE) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"deprecationErrors\" field to be bool or null", ZSTR_VAL(php_phongo_serverapi_ce->name)); return false; } } return php_phongo_serverapi_create_libmongoc_object( &intern->server_api, Z_STR_P(version), strict && !ZVAL_IS_NULL(strict), strict && zval_is_true(strict), deprecation_errors && !ZVAL_IS_NULL(deprecation_errors), deprecation_errors && zval_is_true(deprecation_errors)); } /* Constructs a new ServerApi object */ static PHP_METHOD(MongoDB_Driver_ServerApi, __construct) { php_phongo_serverapi_t* intern; zend_string* version; zend_bool strict = 0; zend_bool strict_null = 1; zend_bool deprecation_errors = 0; zend_bool deprecation_errors_null = 1; intern = Z_SERVERAPI_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STR(version) Z_PARAM_OPTIONAL Z_PARAM_BOOL_EX(strict, strict_null, 1, 0) Z_PARAM_BOOL_EX(deprecation_errors, deprecation_errors_null, 1, 0) PHONGO_PARSE_PARAMETERS_END(); // Will throw on failure php_phongo_serverapi_create_libmongoc_object( &intern->server_api, version, (bool) !strict_null, (bool) strict, (bool) !deprecation_errors_null, (bool) deprecation_errors); } static PHP_METHOD(MongoDB_Driver_ServerApi, __set_state) { php_phongo_serverapi_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_serverapi_ce); intern = Z_SERVERAPI_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_serverapi_init_from_hash(intern, props); } static HashTable* php_phongo_serverapi_get_properties_hash(zend_object* object, bool is_temp, bool include_null) { php_phongo_serverapi_t* intern; HashTable* props; zval version, strict, deprecation_errors; bool is_set; intern = Z_OBJ_SERVERAPI(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 1); ZVAL_STRING(&version, mongoc_server_api_version_to_string(mongoc_server_api_get_version(intern->server_api))); zend_hash_str_add(props, "version", sizeof("version") - 1, &version); is_set = mongoc_optional_is_set(mongoc_server_api_get_strict(intern->server_api)); if (is_set) { ZVAL_BOOL(&strict, mongoc_optional_value(mongoc_server_api_get_strict(intern->server_api))); } else { ZVAL_NULL(&strict); } if (include_null || is_set) { zend_hash_str_add(props, "strict", sizeof("strict") - 1, &strict); } is_set = mongoc_optional_is_set(mongoc_server_api_get_deprecation_errors(intern->server_api)); if (is_set) { ZVAL_BOOL(&deprecation_errors, mongoc_optional_value(mongoc_server_api_get_deprecation_errors(intern->server_api))); } else { ZVAL_NULL(&deprecation_errors); } if (include_null || is_set) { zend_hash_str_add(props, "deprecationErrors", sizeof("deprecationErrors") - 1, &deprecation_errors); } return props; } static PHP_METHOD(MongoDB_Driver_ServerApi, bsonSerialize) { PHONGO_PARSE_PARAMETERS_NONE(); ZVAL_ARR(return_value, php_phongo_serverapi_get_properties_hash(Z_OBJ_P(getThis()), true, false)); convert_to_object(return_value); } static PHP_METHOD(MongoDB_Driver_ServerApi, serialize) { php_phongo_serverapi_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; intern = Z_SERVERAPI_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); array_init_size(&retval, 3); ADD_ASSOC_STRING(&retval, "version", mongoc_server_api_version_to_string(mongoc_server_api_get_version(intern->server_api))); if (mongoc_optional_is_set(mongoc_server_api_get_strict(intern->server_api))) { ADD_ASSOC_BOOL_EX(&retval, "strict", mongoc_optional_value(mongoc_server_api_get_strict(intern->server_api))); } else { ADD_ASSOC_NULL_EX(&retval, "strict"); } if (mongoc_optional_is_set(mongoc_server_api_get_deprecation_errors(intern->server_api))) { ADD_ASSOC_BOOL_EX(&retval, "deprecationErrors", mongoc_optional_value(mongoc_server_api_get_deprecation_errors(intern->server_api))); } else { ADD_ASSOC_NULL_EX(&retval, "deprecationErrors"); } PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_Driver_ServerApi, unserialize) { php_phongo_serverapi_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_SERVERAPI_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); if (!serialized_len) { return; } PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_serverapi_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_serverapi_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_Driver_ServerApi, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_serverapi_get_properties_hash(Z_OBJ_P(getThis()), true, true)); } static PHP_METHOD(MongoDB_Driver_ServerApi, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_serverapi_init_from_hash(Z_SERVERAPI_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\Driver\ServerApi object handlers */ static zend_object_handlers php_phongo_handler_serverapi; static void php_phongo_serverapi_free_object(zend_object* object) { php_phongo_serverapi_t* intern = Z_OBJ_SERVERAPI(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } if (intern->server_api) { mongoc_server_api_destroy(intern->server_api); } } static zend_object* php_phongo_serverapi_create_object(zend_class_entry* class_type) { php_phongo_serverapi_t* intern = zend_object_alloc(sizeof(php_phongo_serverapi_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_serverapi; return &intern->std; } static HashTable* php_phongo_serverapi_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_serverapi_get_properties_hash(object, true, true); } static HashTable* php_phongo_serverapi_get_properties(zend_object* object) { return php_phongo_serverapi_get_properties_hash(object, false, true); } void php_phongo_serverapi_init_ce(INIT_FUNC_ARGS) { php_phongo_serverapi_ce = register_class_MongoDB_Driver_ServerApi(php_phongo_serializable_ce, zend_ce_serializable); php_phongo_serverapi_ce->create_object = php_phongo_serverapi_create_object; memcpy(&php_phongo_handler_serverapi, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_serverapi.get_debug_info = php_phongo_serverapi_get_debug_info; php_phongo_handler_serverapi.get_properties = php_phongo_serverapi_get_properties; php_phongo_handler_serverapi.free_obj = php_phongo_serverapi_free_object; php_phongo_handler_serverapi.offset = XtOffsetOf(php_phongo_serverapi_t, std); } mongodb-1.21.0/src/MongoDB/ServerApi_arginfo.h0000644000175100001660000000721414760300420015773 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 44bcb97e14839e750c86309b7b9d2d861db89910 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_ServerApi___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, version, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, strict, _IS_BOOL, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, deprecationErrors, _IS_BOOL, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ServerApi___set_state, 0, 1, MongoDB\\Driver\\ServerApi, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_ServerApi_bsonSerialize, 0, 0, stdClass, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ServerApi_serialize, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ServerApi_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ServerApi___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ServerApi___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_ServerApi, __construct); static ZEND_METHOD(MongoDB_Driver_ServerApi, __set_state); static ZEND_METHOD(MongoDB_Driver_ServerApi, bsonSerialize); static ZEND_METHOD(MongoDB_Driver_ServerApi, serialize); static ZEND_METHOD(MongoDB_Driver_ServerApi, unserialize); static ZEND_METHOD(MongoDB_Driver_ServerApi, __unserialize); static ZEND_METHOD(MongoDB_Driver_ServerApi, __serialize); static const zend_function_entry class_MongoDB_Driver_ServerApi_methods[] = { ZEND_ME(MongoDB_Driver_ServerApi, __construct, arginfo_class_MongoDB_Driver_ServerApi___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerApi, __set_state, arginfo_class_MongoDB_Driver_ServerApi___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerApi, bsonSerialize, arginfo_class_MongoDB_Driver_ServerApi_bsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerApi, serialize, arginfo_class_MongoDB_Driver_ServerApi_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerApi, unserialize, arginfo_class_MongoDB_Driver_ServerApi_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerApi, __unserialize, arginfo_class_MongoDB_Driver_ServerApi___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerApi, __serialize, arginfo_class_MongoDB_Driver_ServerApi___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_ServerApi(zend_class_entry *class_entry_MongoDB_BSON_Serializable, zend_class_entry *class_entry_Serializable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "ServerApi", class_MongoDB_Driver_ServerApi_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 2, class_entry_MongoDB_BSON_Serializable, class_entry_Serializable); zval const_V1_value; zend_string *const_V1_value_str = zend_string_init("1", strlen("1"), 1); ZVAL_STR(&const_V1_value, const_V1_value_str); zend_string *const_V1_name = zend_string_init_interned("V1", sizeof("V1") - 1, 1); zend_declare_class_constant_ex(class_entry, const_V1_name, &const_V1_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_V1_name); return class_entry; } mongodb-1.21.0/src/MongoDB/ServerDescription.c0000644000175100001660000002344514760300420016037 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "MongoDB/ServerDescription.h" #include "ServerDescription_arginfo.h" zend_class_entry* php_phongo_serverdescription_ce; php_phongo_server_description_type_map_t php_phongo_server_description_type_map[PHONGO_SERVER_DESCRIPTION_TYPES] = { { PHONGO_SERVER_UNKNOWN, PHONGO_SERVER_TYPE_UNKNOWN }, { PHONGO_SERVER_STANDALONE, PHONGO_SERVER_TYPE_STANDALONE }, { PHONGO_SERVER_MONGOS, PHONGO_SERVER_TYPE_MONGOS }, { PHONGO_SERVER_POSSIBLE_PRIMARY, PHONGO_SERVER_TYPE_POSSIBLE_PRIMARY }, { PHONGO_SERVER_RS_PRIMARY, PHONGO_SERVER_TYPE_RS_PRIMARY }, { PHONGO_SERVER_RS_SECONDARY, PHONGO_SERVER_TYPE_RS_SECONDARY }, { PHONGO_SERVER_RS_ARBITER, PHONGO_SERVER_TYPE_RS_ARBITER }, { PHONGO_SERVER_RS_OTHER, PHONGO_SERVER_TYPE_RS_OTHER }, { PHONGO_SERVER_RS_GHOST, PHONGO_SERVER_TYPE_RS_GHOST }, { PHONGO_SERVER_LOAD_BALANCER, PHONGO_SERVER_TYPE_LOAD_BALANCER }, }; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_ServerDescription) /* Returns the most recent "hello" response */ static PHP_METHOD(MongoDB_Driver_ServerDescription, getHelloResponse) { php_phongo_serverdescription_t* intern; const bson_t* helloResponse; php_phongo_bson_state state; intern = Z_SERVERDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); /* Note: the hello response will be empty for load balancers since they are * not monitored. Unlike Server::getInfo(), we do not attempt to fetch the * corresponding handshake description, as that would require holding a * reference to the libmongoc client (and likely a Manager object) on the * ServerDescription and TopologyDescription classes. */ helloResponse = mongoc_server_description_hello_response(intern->server_description); PHONGO_BSON_INIT_DEBUG_STATE(state); if (!php_phongo_bson_to_zval_ex(helloResponse, &state)) { /* Exception should already have been thrown */ zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } /* Returns the server's hostname */ static PHP_METHOD(MongoDB_Driver_ServerDescription, getHost) { php_phongo_serverdescription_t* intern; intern = Z_SERVERDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(mongoc_server_description_host(intern->server_description)->host); } /* Returns the server's last update time, in microseconds */ static PHP_METHOD(MongoDB_Driver_ServerDescription, getLastUpdateTime) { php_phongo_serverdescription_t* intern; int64_t last_update_time; intern = Z_SERVERDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); last_update_time = mongoc_server_description_last_update_time(intern->server_description); #if SIZEOF_ZEND_LONG == 4 if (last_update_time > INT32_MAX || last_update_time < INT32_MIN) { zend_error(E_WARNING, "Truncating 64-bit value for lastUpdateTime"); } #endif RETVAL_LONG(last_update_time); } /* Returns the server's port */ static PHP_METHOD(MongoDB_Driver_ServerDescription, getPort) { php_phongo_serverdescription_t* intern; intern = Z_SERVERDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_LONG(mongoc_server_description_host(intern->server_description)->port); } /* Returns the server's round trip time, in milliseconds */ static PHP_METHOD(MongoDB_Driver_ServerDescription, getRoundTripTime) { php_phongo_serverdescription_t* intern; intern = Z_SERVERDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); /* TODO: Use MONGOC_RTT_UNSET once it is added to libmongoc's public API (CDRIVER-4176) */ if (mongoc_server_description_round_trip_time(intern->server_description) == -1) { RETVAL_NULL(); } else { RETVAL_LONG(mongoc_server_description_round_trip_time(intern->server_description)); } } /* Returns the server's node type */ static PHP_METHOD(MongoDB_Driver_ServerDescription, getType) { php_phongo_serverdescription_t* intern; intern = Z_SERVERDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(mongoc_server_description_type(intern->server_description)); } /* MongoDB\Driver\ServerDescription object handlers */ static zend_object_handlers php_phongo_handler_serverdescription; static void php_phongo_serverdescription_free_object(zend_object* object) { php_phongo_serverdescription_t* intern = Z_OBJ_SERVERDESCRIPTION(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } if (intern->server_description) { mongoc_server_description_destroy(intern->server_description); } } static zend_object* php_phongo_serverdescription_create_object(zend_class_entry* class_type) { php_phongo_serverdescription_t* intern = zend_object_alloc(sizeof(php_phongo_serverdescription_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_serverdescription; return &intern->std; } HashTable* php_phongo_serverdescription_get_properties_hash(zend_object* object, bool is_debug) { php_phongo_serverdescription_t* intern = NULL; HashTable* props; intern = Z_OBJ_SERVERDESCRIPTION(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_debug, intern, props, 6); if (!intern->server_description) { return props; } { zval host, port, type; mongoc_host_list_t* host_list = mongoc_server_description_host(intern->server_description); ZVAL_STRING(&host, host_list->host); zend_hash_str_update(props, "host", sizeof("host") - 1, &host); ZVAL_LONG(&port, host_list->port); zend_hash_str_update(props, "port", sizeof("port") - 1, &port); ZVAL_STRING(&type, mongoc_server_description_type(intern->server_description)); zend_hash_str_update(props, "type", sizeof("type") - 1, &type); } { const bson_t* hello_response = mongoc_server_description_hello_response(intern->server_description); php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); if (!php_phongo_bson_to_zval_ex(hello_response, &state)) { zval_ptr_dtor(&state.zchild); goto done; } zend_hash_str_update(props, "hello_response", sizeof("hello_response") - 1, &state.zchild); } { int64_t last_update_time; zval z_last_update_time; last_update_time = mongoc_server_description_last_update_time(intern->server_description); #if SIZEOF_ZEND_LONG == 4 if (last_update_time > INT32_MAX || last_update_time < INT32_MIN) { ZVAL_INT64_STRING(&z_last_update_time, last_update_time); } else { ZVAL_LONG(&z_last_update_time, last_update_time); } #else ZVAL_LONG(&z_last_update_time, last_update_time); #endif zend_hash_str_update(props, "last_update_time", sizeof("last_update_time") - 1, &z_last_update_time); } { zval round_trip_time; /* TODO: Use MONGOC_RTT_UNSET once it is added to libmongoc's public API (CDRIVER-4176) */ if (mongoc_server_description_round_trip_time(intern->server_description) == -1) { ZVAL_NULL(&round_trip_time); } else { ZVAL_LONG(&round_trip_time, mongoc_server_description_round_trip_time(intern->server_description)); } zend_hash_str_update(props, "round_trip_time", sizeof("round_trip_time") - 1, &round_trip_time); } done: return props; } static HashTable* php_phongo_serverdescription_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_serverdescription_get_properties_hash(object, true); } static HashTable* php_phongo_serverdescription_get_properties(zend_object* object) { return php_phongo_serverdescription_get_properties_hash(object, false); } void php_phongo_serverdescription_init_ce(INIT_FUNC_ARGS) { php_phongo_serverdescription_ce = register_class_MongoDB_Driver_ServerDescription(); php_phongo_serverdescription_ce->create_object = php_phongo_serverdescription_create_object; memcpy(&php_phongo_handler_serverdescription, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_serverdescription.get_debug_info = php_phongo_serverdescription_get_debug_info; php_phongo_handler_serverdescription.get_properties = php_phongo_serverdescription_get_properties; php_phongo_handler_serverdescription.free_obj = php_phongo_serverdescription_free_object; php_phongo_handler_serverdescription.offset = XtOffsetOf(php_phongo_serverdescription_t, std); } void phongo_serverdescription_init_ex(zval* return_value, mongoc_server_description_t* server_description, bool copy) { php_phongo_serverdescription_t* intern; object_init_ex(return_value, php_phongo_serverdescription_ce); intern = Z_SERVERDESCRIPTION_OBJ_P(return_value); intern->server_description = copy ? mongoc_server_description_new_copy(server_description) : server_description; } php_phongo_server_description_type_t php_phongo_server_description_type(mongoc_server_description_t* sd) { const char* name = mongoc_server_description_type(sd); int i; for (i = 0; i < PHONGO_SERVER_DESCRIPTION_TYPES; i++) { if (!strcmp(name, php_phongo_server_description_type_map[i].name)) { return php_phongo_server_description_type_map[i].type; } } return PHONGO_SERVER_UNKNOWN; } mongodb-1.21.0/src/MongoDB/ServerDescription.h0000644000175100001660000000507014760300420016036 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_SERVERDESCRIPTION_H #define PHONGO_SERVERDESCRIPTION_H #include "mongoc/mongoc.h" #include /* Note: these constants are derived from mongoc_server_description_type, since * since mongoc_server_description_type_t is private. */ #define PHONGO_SERVER_TYPE_UNKNOWN "Unknown" #define PHONGO_SERVER_TYPE_STANDALONE "Standalone" #define PHONGO_SERVER_TYPE_MONGOS "Mongos" #define PHONGO_SERVER_TYPE_POSSIBLE_PRIMARY "PossiblePrimary" #define PHONGO_SERVER_TYPE_RS_PRIMARY "RSPrimary" #define PHONGO_SERVER_TYPE_RS_SECONDARY "RSSecondary" #define PHONGO_SERVER_TYPE_RS_ARBITER "RSArbiter" #define PHONGO_SERVER_TYPE_RS_OTHER "RSOther" #define PHONGO_SERVER_TYPE_RS_GHOST "RSGhost" #define PHONGO_SERVER_TYPE_LOAD_BALANCER "LoadBalancer" /* This enum is necessary since mongoc_server_description_type_t is private and * we need to translate strings returned by mongoc_server_description_type() to * Server integer constants. */ typedef enum { PHONGO_SERVER_UNKNOWN = 0, PHONGO_SERVER_STANDALONE = 1, PHONGO_SERVER_MONGOS = 2, PHONGO_SERVER_POSSIBLE_PRIMARY = 3, PHONGO_SERVER_RS_PRIMARY = 4, PHONGO_SERVER_RS_SECONDARY = 5, PHONGO_SERVER_RS_ARBITER = 6, PHONGO_SERVER_RS_OTHER = 7, PHONGO_SERVER_RS_GHOST = 8, PHONGO_SERVER_LOAD_BALANCER = 9, PHONGO_SERVER_DESCRIPTION_TYPES = 10, } php_phongo_server_description_type_t; typedef struct { php_phongo_server_description_type_t type; const char* name; } php_phongo_server_description_type_map_t; extern php_phongo_server_description_type_map_t php_phongo_server_description_type_map[]; void phongo_serverdescription_init_ex(zval* return_value, mongoc_server_description_t* sd, bool copy); #define phongo_serverdescription_init(r, sd) phongo_serverdescription_init_ex((r), (sd), true) php_phongo_server_description_type_t php_phongo_server_description_type(mongoc_server_description_t* sd); #endif /* PHONGO_SERVERDESCRIPTION_H */ mongodb-1.21.0/src/MongoDB/ServerDescription_arginfo.h0000644000175100001660000002054614760300420017550 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 482425509937fc9119cf140099b41af3c4a20fde */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_ServerDescription___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ServerDescription_getHelloResponse, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ServerDescription_getHost, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ServerDescription_getLastUpdateTime, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_ServerDescription_getPort arginfo_class_MongoDB_Driver_ServerDescription_getLastUpdateTime ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_ServerDescription_getRoundTripTime, 0, 0, IS_LONG, 1) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_ServerDescription_getType arginfo_class_MongoDB_Driver_ServerDescription_getHost static ZEND_METHOD(MongoDB_Driver_ServerDescription, __construct); static ZEND_METHOD(MongoDB_Driver_ServerDescription, getHelloResponse); static ZEND_METHOD(MongoDB_Driver_ServerDescription, getHost); static ZEND_METHOD(MongoDB_Driver_ServerDescription, getLastUpdateTime); static ZEND_METHOD(MongoDB_Driver_ServerDescription, getPort); static ZEND_METHOD(MongoDB_Driver_ServerDescription, getRoundTripTime); static ZEND_METHOD(MongoDB_Driver_ServerDescription, getType); static const zend_function_entry class_MongoDB_Driver_ServerDescription_methods[] = { ZEND_ME(MongoDB_Driver_ServerDescription, __construct, arginfo_class_MongoDB_Driver_ServerDescription___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerDescription, getHelloResponse, arginfo_class_MongoDB_Driver_ServerDescription_getHelloResponse, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerDescription, getHost, arginfo_class_MongoDB_Driver_ServerDescription_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerDescription, getLastUpdateTime, arginfo_class_MongoDB_Driver_ServerDescription_getLastUpdateTime, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerDescription, getPort, arginfo_class_MongoDB_Driver_ServerDescription_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerDescription, getRoundTripTime, arginfo_class_MongoDB_Driver_ServerDescription_getRoundTripTime, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_ServerDescription, getType, arginfo_class_MongoDB_Driver_ServerDescription_getType, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_ServerDescription(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "ServerDescription", class_MongoDB_Driver_ServerDescription_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; zval const_TYPE_UNKNOWN_value; zend_string *const_TYPE_UNKNOWN_value_str = zend_string_init(PHONGO_SERVER_TYPE_UNKNOWN, strlen(PHONGO_SERVER_TYPE_UNKNOWN), 1); ZVAL_STR(&const_TYPE_UNKNOWN_value, const_TYPE_UNKNOWN_value_str); zend_string *const_TYPE_UNKNOWN_name = zend_string_init_interned("TYPE_UNKNOWN", sizeof("TYPE_UNKNOWN") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_UNKNOWN_name, &const_TYPE_UNKNOWN_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_UNKNOWN_name); zval const_TYPE_STANDALONE_value; zend_string *const_TYPE_STANDALONE_value_str = zend_string_init(PHONGO_SERVER_TYPE_STANDALONE, strlen(PHONGO_SERVER_TYPE_STANDALONE), 1); ZVAL_STR(&const_TYPE_STANDALONE_value, const_TYPE_STANDALONE_value_str); zend_string *const_TYPE_STANDALONE_name = zend_string_init_interned("TYPE_STANDALONE", sizeof("TYPE_STANDALONE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_STANDALONE_name, &const_TYPE_STANDALONE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_STANDALONE_name); zval const_TYPE_MONGOS_value; zend_string *const_TYPE_MONGOS_value_str = zend_string_init(PHONGO_SERVER_TYPE_MONGOS, strlen(PHONGO_SERVER_TYPE_MONGOS), 1); ZVAL_STR(&const_TYPE_MONGOS_value, const_TYPE_MONGOS_value_str); zend_string *const_TYPE_MONGOS_name = zend_string_init_interned("TYPE_MONGOS", sizeof("TYPE_MONGOS") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_MONGOS_name, &const_TYPE_MONGOS_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_MONGOS_name); zval const_TYPE_POSSIBLE_PRIMARY_value; zend_string *const_TYPE_POSSIBLE_PRIMARY_value_str = zend_string_init(PHONGO_SERVER_TYPE_POSSIBLE_PRIMARY, strlen(PHONGO_SERVER_TYPE_POSSIBLE_PRIMARY), 1); ZVAL_STR(&const_TYPE_POSSIBLE_PRIMARY_value, const_TYPE_POSSIBLE_PRIMARY_value_str); zend_string *const_TYPE_POSSIBLE_PRIMARY_name = zend_string_init_interned("TYPE_POSSIBLE_PRIMARY", sizeof("TYPE_POSSIBLE_PRIMARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_POSSIBLE_PRIMARY_name, &const_TYPE_POSSIBLE_PRIMARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_POSSIBLE_PRIMARY_name); zval const_TYPE_RS_PRIMARY_value; zend_string *const_TYPE_RS_PRIMARY_value_str = zend_string_init(PHONGO_SERVER_TYPE_RS_PRIMARY, strlen(PHONGO_SERVER_TYPE_RS_PRIMARY), 1); ZVAL_STR(&const_TYPE_RS_PRIMARY_value, const_TYPE_RS_PRIMARY_value_str); zend_string *const_TYPE_RS_PRIMARY_name = zend_string_init_interned("TYPE_RS_PRIMARY", sizeof("TYPE_RS_PRIMARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_PRIMARY_name, &const_TYPE_RS_PRIMARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_PRIMARY_name); zval const_TYPE_RS_SECONDARY_value; zend_string *const_TYPE_RS_SECONDARY_value_str = zend_string_init(PHONGO_SERVER_TYPE_RS_SECONDARY, strlen(PHONGO_SERVER_TYPE_RS_SECONDARY), 1); ZVAL_STR(&const_TYPE_RS_SECONDARY_value, const_TYPE_RS_SECONDARY_value_str); zend_string *const_TYPE_RS_SECONDARY_name = zend_string_init_interned("TYPE_RS_SECONDARY", sizeof("TYPE_RS_SECONDARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_SECONDARY_name, &const_TYPE_RS_SECONDARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_SECONDARY_name); zval const_TYPE_RS_ARBITER_value; zend_string *const_TYPE_RS_ARBITER_value_str = zend_string_init(PHONGO_SERVER_TYPE_RS_ARBITER, strlen(PHONGO_SERVER_TYPE_RS_ARBITER), 1); ZVAL_STR(&const_TYPE_RS_ARBITER_value, const_TYPE_RS_ARBITER_value_str); zend_string *const_TYPE_RS_ARBITER_name = zend_string_init_interned("TYPE_RS_ARBITER", sizeof("TYPE_RS_ARBITER") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_ARBITER_name, &const_TYPE_RS_ARBITER_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_ARBITER_name); zval const_TYPE_RS_OTHER_value; zend_string *const_TYPE_RS_OTHER_value_str = zend_string_init(PHONGO_SERVER_TYPE_RS_OTHER, strlen(PHONGO_SERVER_TYPE_RS_OTHER), 1); ZVAL_STR(&const_TYPE_RS_OTHER_value, const_TYPE_RS_OTHER_value_str); zend_string *const_TYPE_RS_OTHER_name = zend_string_init_interned("TYPE_RS_OTHER", sizeof("TYPE_RS_OTHER") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_OTHER_name, &const_TYPE_RS_OTHER_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_OTHER_name); zval const_TYPE_RS_GHOST_value; zend_string *const_TYPE_RS_GHOST_value_str = zend_string_init(PHONGO_SERVER_TYPE_RS_GHOST, strlen(PHONGO_SERVER_TYPE_RS_GHOST), 1); ZVAL_STR(&const_TYPE_RS_GHOST_value, const_TYPE_RS_GHOST_value_str); zend_string *const_TYPE_RS_GHOST_name = zend_string_init_interned("TYPE_RS_GHOST", sizeof("TYPE_RS_GHOST") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_GHOST_name, &const_TYPE_RS_GHOST_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_GHOST_name); zval const_TYPE_LOAD_BALANCER_value; zend_string *const_TYPE_LOAD_BALANCER_value_str = zend_string_init(PHONGO_SERVER_TYPE_LOAD_BALANCER, strlen(PHONGO_SERVER_TYPE_LOAD_BALANCER), 1); ZVAL_STR(&const_TYPE_LOAD_BALANCER_value, const_TYPE_LOAD_BALANCER_value_str); zend_string *const_TYPE_LOAD_BALANCER_name = zend_string_init_interned("TYPE_LOAD_BALANCER", sizeof("TYPE_LOAD_BALANCER") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_LOAD_BALANCER_name, &const_TYPE_LOAD_BALANCER_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_LOAD_BALANCER_name); return class_entry; } mongodb-1.21.0/src/MongoDB/Server_arginfo.h0000644000175100001660000002574514760300420015352 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 5edd7242100364c5e4beddc89b4d92dda70c09f6 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Server___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Server_executeBulkWrite, 0, 2, MongoDB\\Driver\\WriteResult, 0) ZEND_ARG_TYPE_INFO(0, namespace, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, bulkWrite, MongoDB\\Driver\\BulkWrite, 0) ZEND_ARG_OBJ_TYPE_MASK(0, options, MongoDB\\Driver\\WriteConcern, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Server_executeCommand, 0, 2, MongoDB\\Driver\\Cursor, 0) ZEND_ARG_TYPE_INFO(0, db, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, command, MongoDB\\Driver\\Command, 0) ZEND_ARG_OBJ_TYPE_MASK(0, options, MongoDB\\Driver\\ReadPreference, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Server_executeQuery, 0, 2, MongoDB\\Driver\\Cursor, 0) ZEND_ARG_TYPE_INFO(0, namespace, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, query, MongoDB\\Driver\\Query, 0) ZEND_ARG_OBJ_TYPE_MASK(0, options, MongoDB\\Driver\\ReadPreference, MAY_BE_ARRAY|MAY_BE_NULL, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Server_executeReadCommand, 0, 2, MongoDB\\Driver\\Cursor, 0) ZEND_ARG_TYPE_INFO(0, db, IS_STRING, 0) ZEND_ARG_OBJ_INFO(0, command, MongoDB\\Driver\\Command, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Server_executeReadWriteCommand arginfo_class_MongoDB_Driver_Server_executeReadCommand #define arginfo_class_MongoDB_Driver_Server_executeWriteCommand arginfo_class_MongoDB_Driver_Server_executeReadCommand ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Server_getHost, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Server_getInfo, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Server_getLatency, 0, 0, IS_LONG, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Server_getPort, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Server_getServerDescription, 0, 0, MongoDB\\Driver\\ServerDescription, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Server_getTags arginfo_class_MongoDB_Driver_Server_getInfo #define arginfo_class_MongoDB_Driver_Server_getType arginfo_class_MongoDB_Driver_Server_getPort ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Server_isArbiter, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Server_isHidden arginfo_class_MongoDB_Driver_Server_isArbiter #define arginfo_class_MongoDB_Driver_Server_isPassive arginfo_class_MongoDB_Driver_Server_isArbiter #define arginfo_class_MongoDB_Driver_Server_isPrimary arginfo_class_MongoDB_Driver_Server_isArbiter #define arginfo_class_MongoDB_Driver_Server_isSecondary arginfo_class_MongoDB_Driver_Server_isArbiter static ZEND_METHOD(MongoDB_Driver_Server, __construct); static ZEND_METHOD(MongoDB_Driver_Server, executeBulkWrite); static ZEND_METHOD(MongoDB_Driver_Server, executeCommand); static ZEND_METHOD(MongoDB_Driver_Server, executeQuery); static ZEND_METHOD(MongoDB_Driver_Server, executeReadCommand); static ZEND_METHOD(MongoDB_Driver_Server, executeReadWriteCommand); static ZEND_METHOD(MongoDB_Driver_Server, executeWriteCommand); static ZEND_METHOD(MongoDB_Driver_Server, getHost); static ZEND_METHOD(MongoDB_Driver_Server, getInfo); static ZEND_METHOD(MongoDB_Driver_Server, getLatency); static ZEND_METHOD(MongoDB_Driver_Server, getPort); static ZEND_METHOD(MongoDB_Driver_Server, getServerDescription); static ZEND_METHOD(MongoDB_Driver_Server, getTags); static ZEND_METHOD(MongoDB_Driver_Server, getType); static ZEND_METHOD(MongoDB_Driver_Server, isArbiter); static ZEND_METHOD(MongoDB_Driver_Server, isHidden); static ZEND_METHOD(MongoDB_Driver_Server, isPassive); static ZEND_METHOD(MongoDB_Driver_Server, isPrimary); static ZEND_METHOD(MongoDB_Driver_Server, isSecondary); static const zend_function_entry class_MongoDB_Driver_Server_methods[] = { ZEND_ME(MongoDB_Driver_Server, __construct, arginfo_class_MongoDB_Driver_Server___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, executeBulkWrite, arginfo_class_MongoDB_Driver_Server_executeBulkWrite, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, executeCommand, arginfo_class_MongoDB_Driver_Server_executeCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, executeQuery, arginfo_class_MongoDB_Driver_Server_executeQuery, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, executeReadCommand, arginfo_class_MongoDB_Driver_Server_executeReadCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, executeReadWriteCommand, arginfo_class_MongoDB_Driver_Server_executeReadWriteCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, executeWriteCommand, arginfo_class_MongoDB_Driver_Server_executeWriteCommand, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, getHost, arginfo_class_MongoDB_Driver_Server_getHost, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, getInfo, arginfo_class_MongoDB_Driver_Server_getInfo, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, getLatency, arginfo_class_MongoDB_Driver_Server_getLatency, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, getPort, arginfo_class_MongoDB_Driver_Server_getPort, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, getServerDescription, arginfo_class_MongoDB_Driver_Server_getServerDescription, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, getTags, arginfo_class_MongoDB_Driver_Server_getTags, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, getType, arginfo_class_MongoDB_Driver_Server_getType, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, isArbiter, arginfo_class_MongoDB_Driver_Server_isArbiter, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, isHidden, arginfo_class_MongoDB_Driver_Server_isHidden, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, isPassive, arginfo_class_MongoDB_Driver_Server_isPassive, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, isPrimary, arginfo_class_MongoDB_Driver_Server_isPrimary, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Server, isSecondary, arginfo_class_MongoDB_Driver_Server_isSecondary, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Server(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "Server", class_MongoDB_Driver_Server_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; zval const_TYPE_UNKNOWN_value; ZVAL_LONG(&const_TYPE_UNKNOWN_value, PHONGO_SERVER_UNKNOWN); zend_string *const_TYPE_UNKNOWN_name = zend_string_init_interned("TYPE_UNKNOWN", sizeof("TYPE_UNKNOWN") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_UNKNOWN_name, &const_TYPE_UNKNOWN_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_UNKNOWN_name); zval const_TYPE_STANDALONE_value; ZVAL_LONG(&const_TYPE_STANDALONE_value, PHONGO_SERVER_STANDALONE); zend_string *const_TYPE_STANDALONE_name = zend_string_init_interned("TYPE_STANDALONE", sizeof("TYPE_STANDALONE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_STANDALONE_name, &const_TYPE_STANDALONE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_STANDALONE_name); zval const_TYPE_MONGOS_value; ZVAL_LONG(&const_TYPE_MONGOS_value, PHONGO_SERVER_MONGOS); zend_string *const_TYPE_MONGOS_name = zend_string_init_interned("TYPE_MONGOS", sizeof("TYPE_MONGOS") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_MONGOS_name, &const_TYPE_MONGOS_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_MONGOS_name); zval const_TYPE_POSSIBLE_PRIMARY_value; ZVAL_LONG(&const_TYPE_POSSIBLE_PRIMARY_value, PHONGO_SERVER_POSSIBLE_PRIMARY); zend_string *const_TYPE_POSSIBLE_PRIMARY_name = zend_string_init_interned("TYPE_POSSIBLE_PRIMARY", sizeof("TYPE_POSSIBLE_PRIMARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_POSSIBLE_PRIMARY_name, &const_TYPE_POSSIBLE_PRIMARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_POSSIBLE_PRIMARY_name); zval const_TYPE_RS_PRIMARY_value; ZVAL_LONG(&const_TYPE_RS_PRIMARY_value, PHONGO_SERVER_RS_PRIMARY); zend_string *const_TYPE_RS_PRIMARY_name = zend_string_init_interned("TYPE_RS_PRIMARY", sizeof("TYPE_RS_PRIMARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_PRIMARY_name, &const_TYPE_RS_PRIMARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_PRIMARY_name); zval const_TYPE_RS_SECONDARY_value; ZVAL_LONG(&const_TYPE_RS_SECONDARY_value, PHONGO_SERVER_RS_SECONDARY); zend_string *const_TYPE_RS_SECONDARY_name = zend_string_init_interned("TYPE_RS_SECONDARY", sizeof("TYPE_RS_SECONDARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_SECONDARY_name, &const_TYPE_RS_SECONDARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_SECONDARY_name); zval const_TYPE_RS_ARBITER_value; ZVAL_LONG(&const_TYPE_RS_ARBITER_value, PHONGO_SERVER_RS_ARBITER); zend_string *const_TYPE_RS_ARBITER_name = zend_string_init_interned("TYPE_RS_ARBITER", sizeof("TYPE_RS_ARBITER") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_ARBITER_name, &const_TYPE_RS_ARBITER_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_ARBITER_name); zval const_TYPE_RS_OTHER_value; ZVAL_LONG(&const_TYPE_RS_OTHER_value, PHONGO_SERVER_RS_OTHER); zend_string *const_TYPE_RS_OTHER_name = zend_string_init_interned("TYPE_RS_OTHER", sizeof("TYPE_RS_OTHER") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_OTHER_name, &const_TYPE_RS_OTHER_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_OTHER_name); zval const_TYPE_RS_GHOST_value; ZVAL_LONG(&const_TYPE_RS_GHOST_value, PHONGO_SERVER_RS_GHOST); zend_string *const_TYPE_RS_GHOST_name = zend_string_init_interned("TYPE_RS_GHOST", sizeof("TYPE_RS_GHOST") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_RS_GHOST_name, &const_TYPE_RS_GHOST_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_RS_GHOST_name); zval const_TYPE_LOAD_BALANCER_value; ZVAL_LONG(&const_TYPE_LOAD_BALANCER_value, PHONGO_SERVER_LOAD_BALANCER); zend_string *const_TYPE_LOAD_BALANCER_name = zend_string_init_interned("TYPE_LOAD_BALANCER", sizeof("TYPE_LOAD_BALANCER") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_LOAD_BALANCER_name, &const_TYPE_LOAD_BALANCER_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_LOAD_BALANCER_name); return class_entry; } mongodb-1.21.0/src/MongoDB/Session.c0000644000175100001660000005107614760300420014011 0ustar /* * Copyright 2017-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_bson_encode.h" #include "phongo_client.h" #include "phongo_error.h" #include "MongoDB/ReadConcern.h" #include "MongoDB/ReadPreference.h" #include "MongoDB/Server.h" #include "MongoDB/Session.h" #include "MongoDB/WriteConcern.h" #include "Session_arginfo.h" #include "BSON/Timestamp.h" zend_class_entry* php_phongo_session_ce; #define SESSION_CHECK_LIVELINESS(i, m) \ if (!(i)->client_session) { \ phongo_throw_exception( \ PHONGO_ERROR_LOGIC, \ "Cannot call '%s', as the session has already been ended.", \ (m)); \ return; \ } static bool php_phongo_session_get_timestamp_parts(zval* obj, uint32_t* timestamp, uint32_t* increment) { bool retval = false; zval ztimestamp = ZVAL_STATIC_INIT; zval zincrement = ZVAL_STATIC_INIT; zend_call_method_with_0_params(Z_OBJ_P(obj), NULL, NULL, "getTimestamp", &ztimestamp); if (Z_ISUNDEF(ztimestamp) || EG(exception)) { goto cleanup; } zend_call_method_with_0_params(Z_OBJ_P(obj), NULL, NULL, "getIncrement", &zincrement); if (Z_ISUNDEF(zincrement) || EG(exception)) { goto cleanup; } *timestamp = Z_LVAL(ztimestamp); *increment = Z_LVAL(zincrement); retval = true; cleanup: if (!Z_ISUNDEF(ztimestamp)) { zval_ptr_dtor(&ztimestamp); } if (!Z_ISUNDEF(zincrement)) { zval_ptr_dtor(&zincrement); } return retval; } static const char* php_phongo_get_transaction_state_string(mongoc_transaction_state_t state) { switch (state) { case MONGOC_TRANSACTION_NONE: return PHONGO_TRANSACTION_NONE; case MONGOC_TRANSACTION_STARTING: return PHONGO_TRANSACTION_STARTING; case MONGOC_TRANSACTION_IN_PROGRESS: return PHONGO_TRANSACTION_IN_PROGRESS; case MONGOC_TRANSACTION_COMMITTED: return PHONGO_TRANSACTION_COMMITTED; case MONGOC_TRANSACTION_ABORTED: return PHONGO_TRANSACTION_ABORTED; default: phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Invalid transaction state %d given", (int) state); return NULL; } } static void php_phongo_transaction_options_to_zval(mongoc_client_session_t* cs, zval* retval) { mongoc_transaction_opt_t* opts; int64_t max_commit_time_ms; const mongoc_read_concern_t* read_concern; const mongoc_read_prefs_t* read_preference; const mongoc_write_concern_t* write_concern; if (!cs) { ZVAL_NULL(retval); return; } opts = mongoc_session_opts_get_transaction_opts(cs); if (!opts) { ZVAL_NULL(retval); return; } max_commit_time_ms = mongoc_transaction_opts_get_max_commit_time_ms(opts); read_concern = mongoc_transaction_opts_get_read_concern(opts); read_preference = mongoc_transaction_opts_get_read_prefs(opts); write_concern = mongoc_transaction_opts_get_write_concern(opts); array_init_size(retval, 4); if (max_commit_time_ms) { ADD_ASSOC_LONG_EX(retval, "maxCommitTimeMS", max_commit_time_ms); } if (!mongoc_read_concern_is_default(read_concern)) { zval zread_concern; phongo_readconcern_init(&zread_concern, read_concern); ADD_ASSOC_ZVAL_EX(retval, "readConcern", &zread_concern); } if (read_preference) { zval zread_preference; phongo_readpreference_init(&zread_preference, read_preference); ADD_ASSOC_ZVAL_EX(retval, "readPreference", &zread_preference); } if (!mongoc_write_concern_is_default(write_concern)) { zval zwrite_concern; phongo_writeconcern_init(&zwrite_concern, write_concern); ADD_ASSOC_ZVAL_EX(retval, "writeConcern", &zwrite_concern); } mongoc_transaction_opts_destroy(opts); } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_Session) /* Advances the cluster time for this Session */ static PHP_METHOD(MongoDB_Driver_Session, advanceClusterTime) { php_phongo_session_t* intern; zval* zcluster_time; bson_t cluster_time = BSON_INITIALIZER; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "advanceClusterTime") PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY_OR_OBJECT(zcluster_time) PHONGO_PARSE_PARAMETERS_END(); php_phongo_zval_to_bson(zcluster_time, PHONGO_BSON_NONE, &cluster_time, NULL); /* An exception may be thrown during BSON conversion */ if (EG(exception)) { goto cleanup; } mongoc_client_session_advance_cluster_time(intern->client_session, &cluster_time); cleanup: bson_destroy(&cluster_time); } /* Advances the operation time for this Session */ static PHP_METHOD(MongoDB_Driver_Session, advanceOperationTime) { php_phongo_session_t* intern; zval* ztimestamp; uint32_t timestamp = 0; uint32_t increment = 0; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "advanceOperationTime") PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_OBJECT_OF_CLASS(ztimestamp, php_phongo_timestamp_interface_ce) PHONGO_PARSE_PARAMETERS_END(); if (!php_phongo_session_get_timestamp_parts(ztimestamp, ×tamp, &increment)) { return; } mongoc_client_session_advance_operation_time(intern->client_session, timestamp, increment); } /* Returns the cluster time for this Session */ static PHP_METHOD(MongoDB_Driver_Session, getClusterTime) { php_phongo_session_t* intern; const bson_t* cluster_time; php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "getClusterTime") PHONGO_PARSE_PARAMETERS_NONE(); cluster_time = mongoc_client_session_get_cluster_time(intern->client_session); if (!cluster_time) { RETURN_NULL(); } if (!php_phongo_bson_to_zval_ex(cluster_time, &state)) { /* Exception should already have been thrown */ zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } /* Returns the logical session ID for this Session */ static PHP_METHOD(MongoDB_Driver_Session, getLogicalSessionId) { php_phongo_session_t* intern; const bson_t* lsid; php_phongo_bson_state state; PHONGO_BSON_INIT_STATE(state); intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "getLogicalSessionId") PHONGO_PARSE_PARAMETERS_NONE(); lsid = mongoc_client_session_get_lsid(intern->client_session); if (!php_phongo_bson_to_zval_ex(lsid, &state)) { /* Exception should already have been thrown */ zval_ptr_dtor(&state.zchild); return; } RETURN_ZVAL(&state.zchild, 0, 1); } /* Returns the operation time for this Session */ static PHP_METHOD(MongoDB_Driver_Session, getOperationTime) { php_phongo_session_t* intern; uint32_t timestamp, increment; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "getOperationTime") PHONGO_PARSE_PARAMETERS_NONE(); mongoc_client_session_get_operation_time(intern->client_session, ×tamp, &increment); /* mongoc_client_session_get_operation_time() returns 0 for both parts if * the session has not been used. According to the causal consistency spec, * the operation time for an unused session is null. */ if (timestamp == 0 && increment == 0) { RETURN_NULL(); } phongo_timestamp_new(return_value, increment, timestamp); } /* Returns the server this session is pinned to */ static PHP_METHOD(MongoDB_Driver_Session, getServer) { php_phongo_session_t* intern; uint32_t server_id = 0; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "getServer") PHONGO_PARSE_PARAMETERS_NONE(); server_id = mongoc_client_session_get_server_id(intern->client_session); /* For sessions without a pinned server, 0 is returned. */ if (!server_id) { RETURN_NULL(); } phongo_server_init(return_value, &intern->manager, server_id); } /* Returns options for the currently running transaction */ static PHP_METHOD(MongoDB_Driver_Session, getTransactionOptions) { php_phongo_session_t* intern; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "getTransactionOptions") PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_transaction_options_to_zval(intern->client_session, return_value); } /* Returns the current transaction state for this session */ static PHP_METHOD(MongoDB_Driver_Session, getTransactionState) { php_phongo_session_t* intern; const char* state; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "getTransactionState") PHONGO_PARSE_PARAMETERS_NONE(); state = php_phongo_get_transaction_state_string(mongoc_client_session_get_transaction_state(intern->client_session)); if (!state) { /* Exception already thrown */ return; } RETURN_STRING(state); } /* Creates a opts structure from an array optionally containing an RP, RC, * WC object, and/or maxCommitTimeMS int. Returns NULL if no options were found, * or there was an invalid option. If there was an invalid option or structure, * an exception will be thrown too. */ mongoc_transaction_opt_t* php_mongodb_session_parse_transaction_options(zval* options) { mongoc_transaction_opt_t* opts = NULL; if (php_array_existsc(options, "maxCommitTimeMS")) { int64_t max_commit_time_ms = php_array_fetchc_long(options, "maxCommitTimeMS"); if (max_commit_time_ms < 0) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"maxCommitTimeMS\" option to be >= 0, %" PRId64 " given", max_commit_time_ms); /* Freeing opts is not needed here, as it can't be set yet. The * code is here to keep it consistent with the others in case more * options are added before this one. */ if (opts) { mongoc_transaction_opts_destroy(opts); } return NULL; } if (max_commit_time_ms > UINT32_MAX) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"maxCommitTimeMS\" option to be <= %" PRIu32 ", %" PRId64 " given", UINT32_MAX, max_commit_time_ms); /* Freeing opts is not needed here, as it can't be set yet. The * code is here to keep it consistent with the others in case more * options are added before this one. */ if (opts) { mongoc_transaction_opts_destroy(opts); } return NULL; } if (!opts) { opts = mongoc_transaction_opts_new(); } mongoc_transaction_opts_set_max_commit_time_ms(opts, max_commit_time_ms); } if (php_array_existsc(options, "readConcern")) { zval* read_concern = php_array_fetchc_deref(options, "readConcern"); if (Z_TYPE_P(read_concern) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(read_concern), php_phongo_readconcern_ce)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"readConcern\" option to be %s, %s given", ZSTR_VAL(php_phongo_readconcern_ce->name), zend_zval_type_name(read_concern)); if (opts) { mongoc_transaction_opts_destroy(opts); } return NULL; } if (!opts) { opts = mongoc_transaction_opts_new(); } mongoc_transaction_opts_set_read_concern(opts, phongo_read_concern_from_zval(read_concern)); } if (php_array_existsc(options, "readPreference")) { zval* read_preference = php_array_fetchc_deref(options, "readPreference"); if (Z_TYPE_P(read_preference) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(read_preference), php_phongo_readpreference_ce)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"readPreference\" option to be %s, %s given", ZSTR_VAL(php_phongo_readpreference_ce->name), zend_zval_type_name(read_preference)); if (opts) { mongoc_transaction_opts_destroy(opts); } return NULL; } if (!opts) { opts = mongoc_transaction_opts_new(); } mongoc_transaction_opts_set_read_prefs(opts, phongo_read_preference_from_zval(read_preference)); } if (php_array_existsc(options, "writeConcern")) { zval* write_concern = php_array_fetchc_deref(options, "writeConcern"); if (Z_TYPE_P(write_concern) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(write_concern), php_phongo_writeconcern_ce)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"writeConcern\" option to be %s, %s given", ZSTR_VAL(php_phongo_writeconcern_ce->name), zend_zval_type_name(write_concern)); if (opts) { mongoc_transaction_opts_destroy(opts); } return NULL; } if (!opts) { opts = mongoc_transaction_opts_new(); } mongoc_transaction_opts_set_write_concern(opts, phongo_write_concern_from_zval(write_concern)); } return opts; } /* Starts a new transaction */ static PHP_METHOD(MongoDB_Driver_Session, startTransaction) { php_phongo_session_t* intern; zval* options = NULL; mongoc_transaction_opt_t* txn_options = NULL; bson_error_t error; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "startTransaction") PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_ARRAY_OR_NULL(options) PHONGO_PARSE_PARAMETERS_END(); if (options) { txn_options = php_mongodb_session_parse_transaction_options(options); } if (EG(exception)) { return; } if (!mongoc_client_session_start_transaction(intern->client_session, txn_options, &error)) { phongo_throw_exception_from_bson_error_t(&error); } if (txn_options) { mongoc_transaction_opts_destroy(txn_options); } } /* Commits an existing transaction */ static PHP_METHOD(MongoDB_Driver_Session, commitTransaction) { php_phongo_session_t* intern; bson_error_t error; bson_t reply; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "commitTransaction") PHONGO_PARSE_PARAMETERS_NONE(); if (!mongoc_client_session_commit_transaction(intern->client_session, &reply, &error)) { phongo_throw_exception_from_bson_error_t_and_reply(&error, &reply); } bson_destroy(&reply); } /* Aborts (rolls back) an existing transaction */ static PHP_METHOD(MongoDB_Driver_Session, abortTransaction) { php_phongo_session_t* intern; bson_error_t error; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "abortTransaction") PHONGO_PARSE_PARAMETERS_NONE(); if (!mongoc_client_session_abort_transaction(intern->client_session, &error)) { phongo_throw_exception_from_bson_error_t(&error); } } /* Ends the session, and a running transaction if active */ static PHP_METHOD(MongoDB_Driver_Session, endSession) { php_phongo_session_t* intern; intern = Z_SESSION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); mongoc_client_session_destroy(intern->client_session); intern->client_session = NULL; } /* Returns whether the session is dirty (i.e. was used with a command that encountered a network error) and will be discarded when returned to the server session pool. */ static PHP_METHOD(MongoDB_Driver_Session, isDirty) { php_phongo_session_t* intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "isDirty") PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_BOOL(mongoc_client_session_get_dirty(intern->client_session)); } /* Returns whether a multi-document transaction is in progress */ static PHP_METHOD(MongoDB_Driver_Session, isInTransaction) { php_phongo_session_t* intern; intern = Z_SESSION_OBJ_P(getThis()); SESSION_CHECK_LIVELINESS(intern, "isInTransaction") PHONGO_PARSE_PARAMETERS_NONE(); RETURN_BOOL(mongoc_client_session_in_transaction(intern->client_session)); } /* MongoDB\Driver\Session object handlers */ static zend_object_handlers php_phongo_handler_session; static void php_phongo_session_free_object(zend_object* object) { php_phongo_session_t* intern = Z_OBJ_SESSION(object); zend_object_std_dtor(&intern->std); /* If this Session was created in a different process, reset the client so * that its session pool is cleared and mongoc_client_session_destroy will * destroy the corresponding server session rather than return it to the * now-empty pool. This will ensure that we do not re-use a server session * (i.e. LSID) created by a parent process. */ PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, Z_MANAGER_OBJ_P(&intern->manager)); if (intern->client_session) { mongoc_client_session_destroy(intern->client_session); } if (!Z_ISUNDEF(intern->manager)) { zval_ptr_dtor(&intern->manager); } } static zend_object* php_phongo_session_create_object(zend_class_entry* class_type) { php_phongo_session_t* intern = zend_object_alloc(sizeof(php_phongo_session_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); PHONGO_SET_CREATED_BY_PID(intern); intern->std.handlers = &php_phongo_handler_session; return &intern->std; } static HashTable* php_phongo_session_get_debug_info(zend_object* object, int* is_temp) { php_phongo_session_t* intern = NULL; zval retval = ZVAL_STATIC_INIT; *is_temp = 1; intern = Z_OBJ_SESSION(object); array_init(&retval); if (!intern->client_session) { ADD_ASSOC_BOOL_EX(&retval, "ended", true); goto done; } { const bson_t* lsid = mongoc_client_session_get_lsid(intern->client_session); php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); if (!php_phongo_bson_to_zval_ex(lsid, &state)) { zval_ptr_dtor(&state.zchild); goto done; } ADD_ASSOC_ZVAL_EX(&retval, "logicalSessionId", &state.zchild); } { const bson_t* cluster_time = mongoc_client_session_get_cluster_time(intern->client_session); if (cluster_time) { php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); if (!php_phongo_bson_to_zval_ex(cluster_time, &state)) { zval_ptr_dtor(&state.zchild); goto done; } ADD_ASSOC_ZVAL_EX(&retval, "clusterTime", &state.zchild); } else { ADD_ASSOC_NULL_EX(&retval, "clusterTime"); } } { const mongoc_session_opt_t* cs_opts = mongoc_client_session_get_opts(intern->client_session); ADD_ASSOC_BOOL_EX(&retval, "causalConsistency", mongoc_session_opts_get_causal_consistency(cs_opts)); ADD_ASSOC_BOOL_EX(&retval, "snapshot", mongoc_session_opts_get_snapshot(cs_opts)); } { uint32_t timestamp, increment; mongoc_client_session_get_operation_time(intern->client_session, ×tamp, &increment); if (timestamp && increment) { zval ztimestamp; if (!phongo_timestamp_new(&ztimestamp, increment, timestamp)) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_ZVAL_EX(&retval, "operationTime", &ztimestamp); } else { ADD_ASSOC_NULL_EX(&retval, "operationTime"); } } { uint32_t server_id = mongoc_client_session_get_server_id(intern->client_session); if (server_id) { zval server; phongo_server_init(&server, &intern->manager, server_id); ADD_ASSOC_ZVAL_EX(&retval, "server", &server); } else { ADD_ASSOC_NULL_EX(&retval, "server"); } } ADD_ASSOC_BOOL_EX(&retval, "dirty", mongoc_client_session_get_dirty(intern->client_session)); ADD_ASSOC_BOOL_EX(&retval, "inTransaction", mongoc_client_session_in_transaction(intern->client_session)); { const char* state = php_phongo_get_transaction_state_string(mongoc_client_session_get_transaction_state(intern->client_session)); if (!state) { /* Exception should already have been thrown */ goto done; } ADD_ASSOC_STRING(&retval, "transactionState", state); } { zval txn_opts; php_phongo_transaction_options_to_zval(intern->client_session, &txn_opts); ADD_ASSOC_ZVAL_EX(&retval, "transactionOptions", &txn_opts); } done: return Z_ARRVAL(retval); } void php_phongo_session_init_ce(INIT_FUNC_ARGS) { php_phongo_session_ce = register_class_MongoDB_Driver_Session(); php_phongo_session_ce->create_object = php_phongo_session_create_object; memcpy(&php_phongo_handler_session, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_session.get_debug_info = php_phongo_session_get_debug_info; php_phongo_handler_session.free_obj = php_phongo_session_free_object; php_phongo_handler_session.offset = XtOffsetOf(php_phongo_session_t, std); } void phongo_session_init(zval* return_value, zval* manager, mongoc_client_session_t* client_session) { php_phongo_session_t* session; object_init_ex(return_value, php_phongo_session_ce); session = Z_SESSION_OBJ_P(return_value); session->client_session = client_session; ZVAL_ZVAL(&session->manager, manager, 1, 0); } mongodb-1.21.0/src/MongoDB/Session.h0000644000175100001660000000225414760300420014010 0ustar /* * Copyright 2017-present MongoDB, 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. */ #ifndef PHP_MONGODB_DRIVER_SESSION_H #define PHP_MONGODB_DRIVER_SESSION_H #include "mongoc/mongoc.h" #include #define PHONGO_TRANSACTION_NONE "none" #define PHONGO_TRANSACTION_STARTING "starting" #define PHONGO_TRANSACTION_IN_PROGRESS "in_progress" #define PHONGO_TRANSACTION_COMMITTED "committed" #define PHONGO_TRANSACTION_ABORTED "aborted" mongoc_transaction_opt_t* php_mongodb_session_parse_transaction_options(zval* txnOptions); void phongo_session_init(zval* return_value, zval* manager, mongoc_client_session_t* client_session); #endif /* PHP_MONGODB_DRIVER_SESSION_H */ mongodb-1.21.0/src/MongoDB/Session_arginfo.h0000644000175100001660000002073214760300420015516 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 22e0a387ed21d232c61f805ba258c4781a08a68e */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_Session___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_abortTransaction, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_advanceClusterTime, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_MASK(0, clusterTime, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_advanceOperationTime, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, operationTime, MongoDB\\BSON\\TimestampInterface, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Session_commitTransaction arginfo_class_MongoDB_Driver_Session_abortTransaction #define arginfo_class_MongoDB_Driver_Session_endSession arginfo_class_MongoDB_Driver_Session_abortTransaction ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_getClusterTime, 0, 0, IS_OBJECT, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_getLogicalSessionId, 0, 0, IS_OBJECT, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Session_getOperationTime, 0, 0, MongoDB\\BSON\\Timestamp, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_Session_getServer, 0, 0, MongoDB\\Driver\\Server, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_getTransactionOptions, 0, 0, IS_ARRAY, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_getTransactionState, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_isDirty, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_Session_isInTransaction arginfo_class_MongoDB_Driver_Session_isDirty ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_Session_startTransaction, 0, 0, IS_VOID, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_Session, __construct); static ZEND_METHOD(MongoDB_Driver_Session, abortTransaction); static ZEND_METHOD(MongoDB_Driver_Session, advanceClusterTime); static ZEND_METHOD(MongoDB_Driver_Session, advanceOperationTime); static ZEND_METHOD(MongoDB_Driver_Session, commitTransaction); static ZEND_METHOD(MongoDB_Driver_Session, endSession); static ZEND_METHOD(MongoDB_Driver_Session, getClusterTime); static ZEND_METHOD(MongoDB_Driver_Session, getLogicalSessionId); static ZEND_METHOD(MongoDB_Driver_Session, getOperationTime); static ZEND_METHOD(MongoDB_Driver_Session, getServer); static ZEND_METHOD(MongoDB_Driver_Session, getTransactionOptions); static ZEND_METHOD(MongoDB_Driver_Session, getTransactionState); static ZEND_METHOD(MongoDB_Driver_Session, isDirty); static ZEND_METHOD(MongoDB_Driver_Session, isInTransaction); static ZEND_METHOD(MongoDB_Driver_Session, startTransaction); static const zend_function_entry class_MongoDB_Driver_Session_methods[] = { ZEND_ME(MongoDB_Driver_Session, __construct, arginfo_class_MongoDB_Driver_Session___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, abortTransaction, arginfo_class_MongoDB_Driver_Session_abortTransaction, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, advanceClusterTime, arginfo_class_MongoDB_Driver_Session_advanceClusterTime, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, advanceOperationTime, arginfo_class_MongoDB_Driver_Session_advanceOperationTime, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, commitTransaction, arginfo_class_MongoDB_Driver_Session_commitTransaction, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, endSession, arginfo_class_MongoDB_Driver_Session_endSession, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, getClusterTime, arginfo_class_MongoDB_Driver_Session_getClusterTime, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, getLogicalSessionId, arginfo_class_MongoDB_Driver_Session_getLogicalSessionId, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, getOperationTime, arginfo_class_MongoDB_Driver_Session_getOperationTime, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, getServer, arginfo_class_MongoDB_Driver_Session_getServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, getTransactionOptions, arginfo_class_MongoDB_Driver_Session_getTransactionOptions, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, getTransactionState, arginfo_class_MongoDB_Driver_Session_getTransactionState, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, isDirty, arginfo_class_MongoDB_Driver_Session_isDirty, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, isInTransaction, arginfo_class_MongoDB_Driver_Session_isInTransaction, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_Session, startTransaction, arginfo_class_MongoDB_Driver_Session_startTransaction, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_Session(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "Session", class_MongoDB_Driver_Session_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; zval const_TRANSACTION_NONE_value; zend_string *const_TRANSACTION_NONE_value_str = zend_string_init(PHONGO_TRANSACTION_NONE, strlen(PHONGO_TRANSACTION_NONE), 1); ZVAL_STR(&const_TRANSACTION_NONE_value, const_TRANSACTION_NONE_value_str); zend_string *const_TRANSACTION_NONE_name = zend_string_init_interned("TRANSACTION_NONE", sizeof("TRANSACTION_NONE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TRANSACTION_NONE_name, &const_TRANSACTION_NONE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TRANSACTION_NONE_name); zval const_TRANSACTION_STARTING_value; zend_string *const_TRANSACTION_STARTING_value_str = zend_string_init(PHONGO_TRANSACTION_STARTING, strlen(PHONGO_TRANSACTION_STARTING), 1); ZVAL_STR(&const_TRANSACTION_STARTING_value, const_TRANSACTION_STARTING_value_str); zend_string *const_TRANSACTION_STARTING_name = zend_string_init_interned("TRANSACTION_STARTING", sizeof("TRANSACTION_STARTING") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TRANSACTION_STARTING_name, &const_TRANSACTION_STARTING_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TRANSACTION_STARTING_name); zval const_TRANSACTION_IN_PROGRESS_value; zend_string *const_TRANSACTION_IN_PROGRESS_value_str = zend_string_init(PHONGO_TRANSACTION_IN_PROGRESS, strlen(PHONGO_TRANSACTION_IN_PROGRESS), 1); ZVAL_STR(&const_TRANSACTION_IN_PROGRESS_value, const_TRANSACTION_IN_PROGRESS_value_str); zend_string *const_TRANSACTION_IN_PROGRESS_name = zend_string_init_interned("TRANSACTION_IN_PROGRESS", sizeof("TRANSACTION_IN_PROGRESS") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TRANSACTION_IN_PROGRESS_name, &const_TRANSACTION_IN_PROGRESS_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TRANSACTION_IN_PROGRESS_name); zval const_TRANSACTION_COMMITTED_value; zend_string *const_TRANSACTION_COMMITTED_value_str = zend_string_init(PHONGO_TRANSACTION_COMMITTED, strlen(PHONGO_TRANSACTION_COMMITTED), 1); ZVAL_STR(&const_TRANSACTION_COMMITTED_value, const_TRANSACTION_COMMITTED_value_str); zend_string *const_TRANSACTION_COMMITTED_name = zend_string_init_interned("TRANSACTION_COMMITTED", sizeof("TRANSACTION_COMMITTED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TRANSACTION_COMMITTED_name, &const_TRANSACTION_COMMITTED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TRANSACTION_COMMITTED_name); zval const_TRANSACTION_ABORTED_value; zend_string *const_TRANSACTION_ABORTED_value_str = zend_string_init(PHONGO_TRANSACTION_ABORTED, strlen(PHONGO_TRANSACTION_ABORTED), 1); ZVAL_STR(&const_TRANSACTION_ABORTED_value, const_TRANSACTION_ABORTED_value_str); zend_string *const_TRANSACTION_ABORTED_name = zend_string_init_interned("TRANSACTION_ABORTED", sizeof("TRANSACTION_ABORTED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TRANSACTION_ABORTED_name, &const_TRANSACTION_ABORTED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TRANSACTION_ABORTED_name); return class_entry; } mongodb-1.21.0/src/MongoDB/TopologyDescription.c0000644000175100001660000001504114760300420016376 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "mongoc/mongoc.h" #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "MongoDB/ReadPreference.h" #include "MongoDB/ServerDescription.h" #include "MongoDB/TopologyDescription.h" #include "TopologyDescription_arginfo.h" zend_class_entry* php_phongo_topologydescription_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_TopologyDescription) /* Returns an array of ServerDescription objects for all known servers in the topology */ static PHP_METHOD(MongoDB_Driver_TopologyDescription, getServers) { php_phongo_topologydescription_t* intern; mongoc_server_description_t** sds; size_t i, n = 0; intern = Z_TOPOLOGYDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); sds = mongoc_topology_description_get_servers(intern->topology_description, &n); array_init_size(return_value, n); for (i = 0; i < n; i++) { zval sd; phongo_serverdescription_init(&sd, sds[i]); add_next_index_zval(return_value, &sd); } mongoc_server_descriptions_destroy_all(sds, n); } /* Returns whether the topology has a readable server available */ static PHP_METHOD(MongoDB_Driver_TopologyDescription, hasReadableServer) { php_phongo_topologydescription_t* intern; const mongoc_read_prefs_t* read_preference = NULL; zval* z_read_preference = NULL; intern = Z_TOPOLOGYDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_OBJECT_OF_CLASS(z_read_preference, php_phongo_readpreference_ce) PHONGO_PARSE_PARAMETERS_END(); if (z_read_preference) { read_preference = phongo_read_preference_from_zval(z_read_preference); } RETVAL_BOOL(mongoc_topology_description_has_readable_server(intern->topology_description, read_preference)); } /* Returns whether the topology has a writable server available */ static PHP_METHOD(MongoDB_Driver_TopologyDescription, hasWritableServer) { php_phongo_topologydescription_t* intern = Z_TOPOLOGYDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_BOOL(mongoc_topology_description_has_writable_server(intern->topology_description)); } /* Returns the topology type */ static PHP_METHOD(MongoDB_Driver_TopologyDescription, getType) { php_phongo_topologydescription_t* intern = Z_TOPOLOGYDESCRIPTION_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETVAL_STRING(mongoc_topology_description_type(intern->topology_description)); } /* MongoDB\Driver\TopologyDescription object handlers */ static zend_object_handlers php_phongo_handler_topologydescription; static void php_phongo_topologydescription_free_object(zend_object* object) { php_phongo_topologydescription_t* intern = Z_OBJ_TOPOLOGYDESCRIPTION(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } if (intern->topology_description) { mongoc_topology_description_destroy(intern->topology_description); } } static zend_object* php_phongo_topologydescription_create_object(zend_class_entry* class_type) { php_phongo_topologydescription_t* intern = zend_object_alloc(sizeof(php_phongo_topologydescription_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_topologydescription; return &intern->std; } HashTable* php_phongo_topologydescription_get_properties_hash(zend_object* object, bool is_debug) { php_phongo_topologydescription_t* intern = NULL; HashTable* props; intern = Z_OBJ_TOPOLOGYDESCRIPTION(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_debug, intern, props, 2); if (!intern->topology_description) { return props; } { zval servers; size_t i, n = 0; mongoc_server_description_t** sds = mongoc_topology_description_get_servers(intern->topology_description, &n); array_init_size(&servers, n); for (i = 0; i < n; i++) { zval sd; phongo_serverdescription_init(&sd, sds[i]); add_next_index_zval(&servers, &sd); } zend_hash_str_update(props, "servers", sizeof("servers") - 1, &servers); mongoc_server_descriptions_destroy_all(sds, n); } { zval type; ZVAL_STRING(&type, mongoc_topology_description_type(intern->topology_description)); zend_hash_str_update(props, "type", sizeof("type") - 1, &type); } return props; } static HashTable* php_phongo_topologydescription_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_topologydescription_get_properties_hash(object, true); } static HashTable* php_phongo_topologydescription_get_properties(zend_object* object) { return php_phongo_topologydescription_get_properties_hash(object, false); } void php_phongo_topologydescription_init_ce(INIT_FUNC_ARGS) { php_phongo_topologydescription_ce = register_class_MongoDB_Driver_TopologyDescription(); php_phongo_topologydescription_ce->create_object = php_phongo_topologydescription_create_object; memcpy(&php_phongo_handler_topologydescription, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_topologydescription.get_debug_info = php_phongo_topologydescription_get_debug_info; php_phongo_handler_topologydescription.get_properties = php_phongo_topologydescription_get_properties; php_phongo_handler_topologydescription.free_obj = php_phongo_topologydescription_free_object; php_phongo_handler_topologydescription.offset = XtOffsetOf(php_phongo_topologydescription_t, std); } void phongo_topologydescription_init(zval* return_value, mongoc_topology_description_t* topology_description) { php_phongo_topologydescription_t* intern; object_init_ex(return_value, php_phongo_topologydescription_ce); intern = Z_TOPOLOGYDESCRIPTION_OBJ_P(return_value); intern->topology_description = mongoc_topology_description_new_copy(topology_description); } mongodb-1.21.0/src/MongoDB/TopologyDescription.h0000644000175100001660000000246214760300420016406 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_TOPOLOGYDESCRIPTION_H #define PHONGO_TOPOLOGYDESCRIPTION_H #include "mongoc/mongoc.h" #include /* Note: these constants are derived from _mongoc_topology_description_type, * since mongoc_topology_description_t is private. */ #define PHONGO_TOPOLOGY_UNKNOWN "Unknown" #define PHONGO_TOPOLOGY_SINGLE "Single" #define PHONGO_TOPOLOGY_SHARDED "Sharded" #define PHONGO_TOPOLOGY_REPLICA_SET_NO_PRIMARY "ReplicaSetNoPrimary" #define PHONGO_TOPOLOGY_REPLICA_SET_WITH_PRIMARY "ReplicaSetWithPrimary" #define PHONGO_TOPOLOGY_LOAD_BALANCED "LoadBalanced" void phongo_topologydescription_init(zval* return_value, mongoc_topology_description_t* topology_description); #endif /* PHONGO_TOPOLOGYDESCRIPTION_H */ mongodb-1.21.0/src/MongoDB/TopologyDescription_arginfo.h0000644000175100001660000001360714760300420020116 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 2cd175f4e81e332cd83adb867d51db77907ee8c7 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_TopologyDescription___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_TopologyDescription_getServers, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_TopologyDescription_getType, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_TopologyDescription_hasReadableServer, 0, 0, _IS_BOOL, 0) ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, readPreference, MongoDB\\Driver\\ReadPreference, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_TopologyDescription_hasWritableServer, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_TopologyDescription, __construct); static ZEND_METHOD(MongoDB_Driver_TopologyDescription, getServers); static ZEND_METHOD(MongoDB_Driver_TopologyDescription, getType); static ZEND_METHOD(MongoDB_Driver_TopologyDescription, hasReadableServer); static ZEND_METHOD(MongoDB_Driver_TopologyDescription, hasWritableServer); static const zend_function_entry class_MongoDB_Driver_TopologyDescription_methods[] = { ZEND_ME(MongoDB_Driver_TopologyDescription, __construct, arginfo_class_MongoDB_Driver_TopologyDescription___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_TopologyDescription, getServers, arginfo_class_MongoDB_Driver_TopologyDescription_getServers, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_TopologyDescription, getType, arginfo_class_MongoDB_Driver_TopologyDescription_getType, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_TopologyDescription, hasReadableServer, arginfo_class_MongoDB_Driver_TopologyDescription_hasReadableServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_TopologyDescription, hasWritableServer, arginfo_class_MongoDB_Driver_TopologyDescription_hasWritableServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_TopologyDescription(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "TopologyDescription", class_MongoDB_Driver_TopologyDescription_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; zval const_TYPE_UNKNOWN_value; zend_string *const_TYPE_UNKNOWN_value_str = zend_string_init(PHONGO_TOPOLOGY_UNKNOWN, strlen(PHONGO_TOPOLOGY_UNKNOWN), 1); ZVAL_STR(&const_TYPE_UNKNOWN_value, const_TYPE_UNKNOWN_value_str); zend_string *const_TYPE_UNKNOWN_name = zend_string_init_interned("TYPE_UNKNOWN", sizeof("TYPE_UNKNOWN") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_UNKNOWN_name, &const_TYPE_UNKNOWN_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_UNKNOWN_name); zval const_TYPE_SINGLE_value; zend_string *const_TYPE_SINGLE_value_str = zend_string_init(PHONGO_TOPOLOGY_SINGLE, strlen(PHONGO_TOPOLOGY_SINGLE), 1); ZVAL_STR(&const_TYPE_SINGLE_value, const_TYPE_SINGLE_value_str); zend_string *const_TYPE_SINGLE_name = zend_string_init_interned("TYPE_SINGLE", sizeof("TYPE_SINGLE") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_SINGLE_name, &const_TYPE_SINGLE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_SINGLE_name); zval const_TYPE_SHARDED_value; zend_string *const_TYPE_SHARDED_value_str = zend_string_init(PHONGO_TOPOLOGY_SHARDED, strlen(PHONGO_TOPOLOGY_SHARDED), 1); ZVAL_STR(&const_TYPE_SHARDED_value, const_TYPE_SHARDED_value_str); zend_string *const_TYPE_SHARDED_name = zend_string_init_interned("TYPE_SHARDED", sizeof("TYPE_SHARDED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_SHARDED_name, &const_TYPE_SHARDED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_SHARDED_name); zval const_TYPE_REPLICA_SET_NO_PRIMARY_value; zend_string *const_TYPE_REPLICA_SET_NO_PRIMARY_value_str = zend_string_init(PHONGO_TOPOLOGY_REPLICA_SET_NO_PRIMARY, strlen(PHONGO_TOPOLOGY_REPLICA_SET_NO_PRIMARY), 1); ZVAL_STR(&const_TYPE_REPLICA_SET_NO_PRIMARY_value, const_TYPE_REPLICA_SET_NO_PRIMARY_value_str); zend_string *const_TYPE_REPLICA_SET_NO_PRIMARY_name = zend_string_init_interned("TYPE_REPLICA_SET_NO_PRIMARY", sizeof("TYPE_REPLICA_SET_NO_PRIMARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_REPLICA_SET_NO_PRIMARY_name, &const_TYPE_REPLICA_SET_NO_PRIMARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_REPLICA_SET_NO_PRIMARY_name); zval const_TYPE_REPLICA_SET_WITH_PRIMARY_value; zend_string *const_TYPE_REPLICA_SET_WITH_PRIMARY_value_str = zend_string_init(PHONGO_TOPOLOGY_REPLICA_SET_WITH_PRIMARY, strlen(PHONGO_TOPOLOGY_REPLICA_SET_WITH_PRIMARY), 1); ZVAL_STR(&const_TYPE_REPLICA_SET_WITH_PRIMARY_value, const_TYPE_REPLICA_SET_WITH_PRIMARY_value_str); zend_string *const_TYPE_REPLICA_SET_WITH_PRIMARY_name = zend_string_init_interned("TYPE_REPLICA_SET_WITH_PRIMARY", sizeof("TYPE_REPLICA_SET_WITH_PRIMARY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_REPLICA_SET_WITH_PRIMARY_name, &const_TYPE_REPLICA_SET_WITH_PRIMARY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_REPLICA_SET_WITH_PRIMARY_name); zval const_TYPE_LOAD_BALANCED_value; zend_string *const_TYPE_LOAD_BALANCED_value_str = zend_string_init(PHONGO_TOPOLOGY_LOAD_BALANCED, strlen(PHONGO_TOPOLOGY_LOAD_BALANCED), 1); ZVAL_STR(&const_TYPE_LOAD_BALANCED_value, const_TYPE_LOAD_BALANCED_value_str); zend_string *const_TYPE_LOAD_BALANCED_name = zend_string_init_interned("TYPE_LOAD_BALANCED", sizeof("TYPE_LOAD_BALANCED") - 1, 1); zend_declare_class_constant_ex(class_entry, const_TYPE_LOAD_BALANCED_name, &const_TYPE_LOAD_BALANCED_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_LOAD_BALANCED_name); return class_entry; } mongodb-1.21.0/src/MongoDB/WriteConcern.c0000644000175100001660000004236014760300420014764 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "mongoc/mongoc.h" #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "phongo_util.h" #include "MongoDB/WriteConcern.h" #include "WriteConcern_arginfo.h" zend_class_entry* php_phongo_writeconcern_ce; /* Initialize the object from a HashTable and return whether it was successful. * An exception will be thrown on error. */ static bool php_phongo_writeconcern_init_from_hash(php_phongo_writeconcern_t* intern, HashTable* props) { zval *w, *wtimeout, *j; intern->write_concern = mongoc_write_concern_new(); if ((w = zend_hash_str_find(props, "w", sizeof("w") - 1))) { if (Z_TYPE_P(w) == IS_LONG) { if (Z_LVAL_P(w) < -3) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"w\" integer field to be >= -3", ZSTR_VAL(php_phongo_writeconcern_ce->name)); goto failure; } mongoc_write_concern_set_w(intern->write_concern, Z_LVAL_P(w)); } else if (Z_TYPE_P(w) == IS_STRING) { if (strcmp(Z_STRVAL_P(w), PHONGO_WRITE_CONCERN_W_MAJORITY) == 0) { mongoc_write_concern_set_w(intern->write_concern, MONGOC_WRITE_CONCERN_W_MAJORITY); } else { mongoc_write_concern_set_wtag(intern->write_concern, Z_STRVAL_P(w)); } } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"w\" field to be integer or string", ZSTR_VAL(php_phongo_writeconcern_ce->name)); goto failure; } } if ((wtimeout = zend_hash_str_find(props, "wtimeout", sizeof("wtimeout") - 1))) { if (Z_TYPE_P(wtimeout) == IS_LONG) { if (Z_LVAL_P(wtimeout) < 0) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"wtimeout\" integer field to be >= 0", ZSTR_VAL(php_phongo_writeconcern_ce->name)); goto failure; } mongoc_write_concern_set_wtimeout_int64(intern->write_concern, (int64_t) Z_LVAL_P(wtimeout)); } else if (Z_TYPE_P(wtimeout) == IS_STRING) { int64_t timeout; if (!php_phongo_parse_int64(&timeout, Z_STRVAL_P(wtimeout), Z_STRLEN_P(wtimeout))) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error parsing \"%s\" as 64-bit value for %s initialization", Z_STRVAL_P(wtimeout), ZSTR_VAL(php_phongo_writeconcern_ce->name)); return false; } mongoc_write_concern_set_wtimeout_int64(intern->write_concern, timeout); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"wtimeout\" field to be integer or string", ZSTR_VAL(php_phongo_writeconcern_ce->name)); goto failure; } } if ((j = zend_hash_str_find(props, "j", sizeof("j") - 1))) { if (Z_TYPE_P(j) == IS_TRUE || Z_TYPE_P(j) == IS_FALSE) { if (zend_is_true(j) && (mongoc_write_concern_get_w(intern->write_concern) == MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED || mongoc_write_concern_get_w(intern->write_concern) == MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot enable journaling when using w = 0"); goto failure; } mongoc_write_concern_set_journal(intern->write_concern, zend_is_true(j)); } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"j\" field to be boolean", ZSTR_VAL(php_phongo_writeconcern_ce->name)); goto failure; } } if (!mongoc_write_concern_is_valid(intern->write_concern)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Write concern is not valid"); goto failure; } return true; failure: mongoc_write_concern_destroy(intern->write_concern); intern->write_concern = NULL; return false; } /* Constructs a new WriteConcern */ static PHP_METHOD(MongoDB_Driver_WriteConcern, __construct) { php_phongo_writeconcern_t* intern; zval * w, *journal = NULL; zend_long wtimeout = 0; intern = Z_WRITECONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 3) Z_PARAM_ZVAL(w) Z_PARAM_OPTIONAL Z_PARAM_LONG(wtimeout) Z_PARAM_ZVAL(journal) PHONGO_PARSE_PARAMETERS_END(); intern->write_concern = mongoc_write_concern_new(); if (Z_TYPE_P(w) == IS_LONG) { if (Z_LVAL_P(w) < -3) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected w to be >= -3, %ld given", Z_LVAL_P(w)); return; } mongoc_write_concern_set_w(intern->write_concern, Z_LVAL_P(w)); } else if (Z_TYPE_P(w) == IS_STRING) { if (strcmp(Z_STRVAL_P(w), PHONGO_WRITE_CONCERN_W_MAJORITY) == 0) { mongoc_write_concern_set_w(intern->write_concern, MONGOC_WRITE_CONCERN_W_MAJORITY); } else { mongoc_write_concern_set_wtag(intern->write_concern, Z_STRVAL_P(w)); } } else { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected w to be integer or string, %s given", zend_zval_type_name(w)); return; } switch (ZEND_NUM_ARGS()) { case 3: if (journal && Z_TYPE_P(journal) != IS_NULL) { if (zend_is_true(journal) && (mongoc_write_concern_get_w(intern->write_concern) == MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED || mongoc_write_concern_get_w(intern->write_concern) == MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot enable journaling when using w = 0"); return; } mongoc_write_concern_set_journal(intern->write_concern, zend_is_true(journal)); } PHONGO_BREAK_INTENTIONALLY_MISSING case 2: if (wtimeout < 0) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected wtimeout to be >= 0, %" PHONGO_LONG_FORMAT " given", wtimeout); return; } mongoc_write_concern_set_wtimeout_int64(intern->write_concern, (int64_t) wtimeout); } if (!mongoc_write_concern_is_valid(intern->write_concern)) { phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Write concern is not valid"); return; } } static PHP_METHOD(MongoDB_Driver_WriteConcern, __set_state) { php_phongo_writeconcern_t* intern; HashTable* props; zval* array; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) PHONGO_PARSE_PARAMETERS_END(); object_init_ex(return_value, php_phongo_writeconcern_ce); intern = Z_WRITECONCERN_OBJ_P(return_value); props = Z_ARRVAL_P(array); php_phongo_writeconcern_init_from_hash(intern, props); } /* Returns the WriteConcern "w" option */ static PHP_METHOD(MongoDB_Driver_WriteConcern, getW) { php_phongo_writeconcern_t* intern; const char* wtag; intern = Z_WRITECONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); wtag = mongoc_write_concern_get_wtag(intern->write_concern); if (wtag) { RETURN_STRING(wtag); } if (mongoc_write_concern_get_wmajority(intern->write_concern)) { RETURN_STRING(PHONGO_WRITE_CONCERN_W_MAJORITY); } if (mongoc_write_concern_get_w(intern->write_concern) != MONGOC_WRITE_CONCERN_W_DEFAULT) { RETURN_LONG(mongoc_write_concern_get_w(intern->write_concern)); } RETURN_NULL(); } /* Returns the WriteConcern "wtimeout" option */ static PHP_METHOD(MongoDB_Driver_WriteConcern, getWtimeout) { php_phongo_writeconcern_t* intern; int64_t wtimeout; intern = Z_WRITECONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); wtimeout = mongoc_write_concern_get_wtimeout_int64(intern->write_concern); #if SIZEOF_ZEND_LONG == 4 if (wtimeout > INT32_MAX || wtimeout < INT32_MIN) { zend_error(E_WARNING, "Truncating 64-bit value for wTimeoutMS"); } #endif RETURN_LONG(wtimeout); } /* Returns the WriteConcern "journal" option */ static PHP_METHOD(MongoDB_Driver_WriteConcern, getJournal) { php_phongo_writeconcern_t* intern; intern = Z_WRITECONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (mongoc_write_concern_journal_is_set(intern->write_concern)) { RETURN_BOOL(mongoc_write_concern_get_journal(intern->write_concern)); } RETURN_NULL(); } /* Returns whether the write concern has not been modified (i.e. from a Manager with no write concern URI options). */ static PHP_METHOD(MongoDB_Driver_WriteConcern, isDefault) { php_phongo_writeconcern_t* intern; intern = Z_WRITECONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_BOOL(mongoc_write_concern_is_default(intern->write_concern)); } static HashTable* php_phongo_writeconcern_get_properties_hash(zend_object* object, bool is_temp, bool is_bson, bool is_serialize) { php_phongo_writeconcern_t* intern; HashTable* props; const char* wtag; int32_t w; int64_t wtimeout; intern = Z_OBJ_WRITECONCERN(object); PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, 4); if (!intern->write_concern) { return props; } wtag = mongoc_write_concern_get_wtag(intern->write_concern); w = mongoc_write_concern_get_w(intern->write_concern); wtimeout = mongoc_write_concern_get_wtimeout_int64(intern->write_concern); { zval z_w; if (wtag) { ZVAL_STRING(&z_w, wtag); zend_hash_str_update(props, "w", sizeof("w") - 1, &z_w); } else if (mongoc_write_concern_get_wmajority(intern->write_concern)) { ZVAL_STRING(&z_w, PHONGO_WRITE_CONCERN_W_MAJORITY); zend_hash_str_update(props, "w", sizeof("w") - 1, &z_w); } else if (w != MONGOC_WRITE_CONCERN_W_DEFAULT) { ZVAL_LONG(&z_w, w); zend_hash_str_update(props, "w", sizeof("w") - 1, &z_w); } if (mongoc_write_concern_journal_is_set(intern->write_concern)) { zval z_j; ZVAL_BOOL(&z_j, mongoc_write_concern_get_journal(intern->write_concern)); zend_hash_str_update(props, "j", sizeof("j") - 1, &z_j); } if (wtimeout != 0) { zval z_wtimeout; if (is_bson) { ZVAL_INT64(&z_wtimeout, wtimeout); } else if (is_serialize) { if (wtimeout > INT32_MAX || wtimeout < INT32_MIN) { ZVAL_INT64_STRING(&z_wtimeout, wtimeout); } else { ZVAL_LONG(&z_wtimeout, wtimeout); } } else { #if SIZEOF_ZEND_LONG == 4 if (wtimeout > INT32_MAX || wtimeout < INT32_MIN) { ZVAL_INT64_STRING(&z_wtimeout, wtimeout); } else { ZVAL_LONG(&z_wtimeout, wtimeout); } #else ZVAL_LONG(&z_wtimeout, wtimeout); #endif } zend_hash_str_update(props, "wtimeout", sizeof("wtimeout") - 1, &z_wtimeout); } } return props; } static PHP_METHOD(MongoDB_Driver_WriteConcern, bsonSerialize) { PHONGO_PARSE_PARAMETERS_NONE(); ZVAL_ARR(return_value, php_phongo_writeconcern_get_properties_hash(Z_OBJ_P(getThis()), true, true, false)); convert_to_object(return_value); } static PHP_METHOD(MongoDB_Driver_WriteConcern, serialize) { php_phongo_writeconcern_t* intern; zval retval; php_serialize_data_t var_hash; smart_str buf = { 0 }; const char* wtag; int32_t w; int64_t wtimeout; intern = Z_WRITECONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!intern->write_concern) { return; } wtag = mongoc_write_concern_get_wtag(intern->write_concern); w = mongoc_write_concern_get_w(intern->write_concern); wtimeout = mongoc_write_concern_get_wtimeout_int64(intern->write_concern); array_init_size(&retval, 3); if (wtag) { ADD_ASSOC_STRING(&retval, "w", wtag); } else if (mongoc_write_concern_get_wmajority(intern->write_concern)) { ADD_ASSOC_STRING(&retval, "w", PHONGO_WRITE_CONCERN_W_MAJORITY); } else if (w != MONGOC_WRITE_CONCERN_W_DEFAULT) { ADD_ASSOC_LONG_EX(&retval, "w", w); } if (mongoc_write_concern_journal_is_set(intern->write_concern)) { ADD_ASSOC_BOOL_EX(&retval, "j", mongoc_write_concern_get_journal(intern->write_concern)); } if (wtimeout != 0) { if (wtimeout > INT32_MAX || wtimeout < INT32_MIN) { ADD_ASSOC_INT64_AS_STRING(&retval, "wtimeout", wtimeout); } else { ADD_ASSOC_LONG_EX(&retval, "wtimeout", wtimeout); } } PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&buf, &retval, &var_hash); smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); PHONGO_RETVAL_SMART_STR(buf); smart_str_free(&buf); zval_ptr_dtor(&retval); } static PHP_METHOD(MongoDB_Driver_WriteConcern, unserialize) { php_phongo_writeconcern_t* intern; char* serialized; size_t serialized_len; zval props; php_unserialize_data_t var_hash; intern = Z_WRITECONCERN_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(serialized, serialized_len) PHONGO_PARSE_PARAMETERS_END(); if (!serialized_len) { return; } PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&props, (const unsigned char**) &serialized, (unsigned char*) serialized + serialized_len, &var_hash)) { zval_ptr_dtor(&props); phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s unserialization failed", ZSTR_VAL(php_phongo_writeconcern_ce->name)); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); php_phongo_writeconcern_init_from_hash(intern, HASH_OF(&props)); zval_ptr_dtor(&props); } static PHP_METHOD(MongoDB_Driver_WriteConcern, __serialize) { PHONGO_PARSE_PARAMETERS_NONE(); RETURN_ARR(php_phongo_writeconcern_get_properties_hash(Z_OBJ_P(getThis()), true, false, true)); } static PHP_METHOD(MongoDB_Driver_WriteConcern, __unserialize) { zval* data; PHONGO_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(data) PHONGO_PARSE_PARAMETERS_END(); php_phongo_writeconcern_init_from_hash(Z_WRITECONCERN_OBJ_P(getThis()), Z_ARRVAL_P(data)); } /* MongoDB\Driver\WriteConcern object handlers */ static zend_object_handlers php_phongo_handler_writeconcern; static void php_phongo_writeconcern_free_object(zend_object* object) { php_phongo_writeconcern_t* intern = Z_OBJ_WRITECONCERN(object); zend_object_std_dtor(&intern->std); if (intern->properties) { zend_hash_destroy(intern->properties); FREE_HASHTABLE(intern->properties); } if (intern->write_concern) { mongoc_write_concern_destroy(intern->write_concern); } } static zend_object* php_phongo_writeconcern_create_object(zend_class_entry* class_type) { php_phongo_writeconcern_t* intern = zend_object_alloc(sizeof(php_phongo_writeconcern_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_writeconcern; return &intern->std; } static HashTable* php_phongo_writeconcern_get_debug_info(zend_object* object, int* is_temp) { *is_temp = 1; return php_phongo_writeconcern_get_properties_hash(object, true, false, false); } static HashTable* php_phongo_writeconcern_get_properties(zend_object* object) { return php_phongo_writeconcern_get_properties_hash(object, false, false, false); } void php_phongo_writeconcern_init_ce(INIT_FUNC_ARGS) { php_phongo_writeconcern_ce = register_class_MongoDB_Driver_WriteConcern(php_phongo_serializable_ce, zend_ce_serializable); php_phongo_writeconcern_ce->create_object = php_phongo_writeconcern_create_object; memcpy(&php_phongo_handler_writeconcern, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_writeconcern.get_debug_info = php_phongo_writeconcern_get_debug_info; php_phongo_handler_writeconcern.get_properties = php_phongo_writeconcern_get_properties; php_phongo_handler_writeconcern.free_obj = php_phongo_writeconcern_free_object; php_phongo_handler_writeconcern.offset = XtOffsetOf(php_phongo_writeconcern_t, std); } void phongo_writeconcern_init(zval* return_value, const mongoc_write_concern_t* write_concern) { php_phongo_writeconcern_t* intern; object_init_ex(return_value, php_phongo_writeconcern_ce); intern = Z_WRITECONCERN_OBJ_P(return_value); intern->write_concern = mongoc_write_concern_copy(write_concern); } const mongoc_write_concern_t* phongo_write_concern_from_zval(zval* zwrite_concern) { if (zwrite_concern) { php_phongo_writeconcern_t* intern = Z_WRITECONCERN_OBJ_P(zwrite_concern); if (intern) { return intern->write_concern; } } return NULL; } void php_phongo_write_concern_to_zval(zval* retval, const mongoc_write_concern_t* write_concern) { const char* wtag = mongoc_write_concern_get_wtag(write_concern); const int32_t w = mongoc_write_concern_get_w(write_concern); const int64_t wtimeout = mongoc_write_concern_get_wtimeout_int64(write_concern); array_init_size(retval, 4); if (wtag) { ADD_ASSOC_STRING(retval, "w", wtag); } else if (mongoc_write_concern_get_wmajority(write_concern)) { ADD_ASSOC_STRING(retval, "w", PHONGO_WRITE_CONCERN_W_MAJORITY); } else if (w != MONGOC_WRITE_CONCERN_W_DEFAULT) { ADD_ASSOC_LONG_EX(retval, "w", w); } if (mongoc_write_concern_journal_is_set(write_concern)) { ADD_ASSOC_BOOL_EX(retval, "j", mongoc_write_concern_get_journal(write_concern)); } if (wtimeout != 0) { #if SIZEOF_ZEND_LONG == 4 if (wtimeout > INT32_MAX || wtimeout < INT32_MIN) { ADD_ASSOC_INT64_AS_STRING(retval, "wtimeout", wtimeout); } else { ADD_ASSOC_LONG_EX(retval, "wtimeout", wtimeout); } #else ADD_ASSOC_LONG_EX(retval, "wtimeout", wtimeout); #endif } } mongodb-1.21.0/src/MongoDB/WriteConcern.h0000644000175100001660000000206714760300420014771 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_WRITECONCERN_H #define PHONGO_WRITECONCERN_H #include "mongoc/mongoc.h" #include #define PHONGO_WRITE_CONCERN_W_MAJORITY "majority" void phongo_writeconcern_init(zval* return_value, const mongoc_write_concern_t* write_concern); const mongoc_write_concern_t* phongo_write_concern_from_zval(zval* zwrite_concern); void php_phongo_write_concern_to_zval(zval* retval, const mongoc_write_concern_t* write_concern); #endif /* PHONGO_WRITECONCERN_H */ mongodb-1.21.0/src/MongoDB/WriteConcernError.c0000644000175100001660000001152514760300420015775 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include "php_phongo.h" #include "phongo_error.h" #include "MongoDB/WriteConcernError.h" #include "WriteConcernError_arginfo.h" zend_class_entry* php_phongo_writeconcernerror_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_WriteConcernError) /* Returns the MongoDB error code */ static PHP_METHOD(MongoDB_Driver_WriteConcernError, getCode) { php_phongo_writeconcernerror_t* intern; intern = Z_WRITECONCERNERROR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->code); } /* Returns additional metadata for the error */ static PHP_METHOD(MongoDB_Driver_WriteConcernError, getInfo) { php_phongo_writeconcernerror_t* intern; intern = Z_WRITECONCERNERROR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!Z_ISUNDEF(intern->info)) { RETURN_ZVAL(&intern->info, 1, 0); } } /* Returns the actual error message from the server */ static PHP_METHOD(MongoDB_Driver_WriteConcernError, getMessage) { php_phongo_writeconcernerror_t* intern; intern = Z_WRITECONCERNERROR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!intern->message) { RETURN_STRING(""); } RETURN_STRING(intern->message); } /* MongoDB\Driver\WriteConcernError object handlers */ static zend_object_handlers php_phongo_handler_writeconcernerror; static void php_phongo_writeconcernerror_free_object(zend_object* object) { php_phongo_writeconcernerror_t* intern = Z_OBJ_WRITECONCERNERROR(object); zend_object_std_dtor(&intern->std); if (intern->message) { efree(intern->message); } if (!Z_ISUNDEF(intern->info)) { zval_ptr_dtor(&intern->info); } } static zend_object* php_phongo_writeconcernerror_create_object(zend_class_entry* class_type) { php_phongo_writeconcernerror_t* intern = zend_object_alloc(sizeof(php_phongo_writeconcernerror_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_writeconcernerror; return &intern->std; } static HashTable* php_phongo_writeconcernerror_get_debug_info(zend_object* object, int* is_temp) { php_phongo_writeconcernerror_t* intern; zval retval = ZVAL_STATIC_INIT; *is_temp = 1; intern = Z_OBJ_WRITECONCERNERROR(object); array_init_size(&retval, 3); ADD_ASSOC_STRING(&retval, "message", intern->message ? intern->message : ""); ADD_ASSOC_LONG_EX(&retval, "code", intern->code); if (!Z_ISUNDEF(intern->info)) { Z_ADDREF(intern->info); ADD_ASSOC_ZVAL_EX(&retval, "info", &intern->info); } else { ADD_ASSOC_NULL_EX(&retval, "info"); } return Z_ARRVAL(retval); } void php_phongo_writeconcernerror_init_ce(INIT_FUNC_ARGS) { php_phongo_writeconcernerror_ce = register_class_MongoDB_Driver_WriteConcernError(); php_phongo_writeconcernerror_ce->create_object = php_phongo_writeconcernerror_create_object; memcpy(&php_phongo_handler_writeconcernerror, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_writeconcernerror.get_debug_info = php_phongo_writeconcernerror_get_debug_info; php_phongo_handler_writeconcernerror.free_obj = php_phongo_writeconcernerror_free_object; php_phongo_handler_writeconcernerror.offset = XtOffsetOf(php_phongo_writeconcernerror_t, std); } zend_bool phongo_writeconcernerror_init(zval* return_value, bson_t* bson) { bson_iter_t iter; php_phongo_writeconcernerror_t* intern; object_init_ex(return_value, php_phongo_writeconcernerror_ce); intern = Z_WRITECONCERNERROR_OBJ_P(return_value); intern->code = 0; if (bson_iter_init_find(&iter, bson, "code") && BSON_ITER_HOLDS_INT32(&iter)) { intern->code = bson_iter_int32(&iter); } if (bson_iter_init_find(&iter, bson, "errmsg") && BSON_ITER_HOLDS_UTF8(&iter)) { uint32_t errmsg_len; const char* err_msg = bson_iter_utf8(&iter, &errmsg_len); intern->message = estrndup(err_msg, errmsg_len); } if (bson_iter_init_find(&iter, bson, "errInfo") && BSON_ITER_HOLDS_DOCUMENT(&iter)) { uint32_t len; const uint8_t* data = NULL; bson_iter_document(&iter, &len, &data); if (!php_phongo_bson_data_to_zval(data, len, &intern->info)) { zval_ptr_dtor(&intern->info); ZVAL_UNDEF(&intern->info); return false; } } return true; } mongodb-1.21.0/src/MongoDB/WriteConcernError.h0000644000175100001660000000150114760300420015773 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_WRITECONCERNERROR_H #define PHONGO_WRITECONCERNERROR_H #include "bson/bson.h" #include zend_bool phongo_writeconcernerror_init(zval* return_value, bson_t* bson); #endif /* PHONGO_WRITECONCERNERROR_H */ mongodb-1.21.0/src/MongoDB/WriteConcernError_arginfo.h0000644000175100001660000000366114760300420017511 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: a405afbb8eaa3bf544759f7a6ae9330ced7e7cc0 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcernError___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcernError_getCode, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcernError_getInfo, 0, 0, IS_OBJECT, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcernError_getMessage, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_WriteConcernError, __construct); static ZEND_METHOD(MongoDB_Driver_WriteConcernError, getCode); static ZEND_METHOD(MongoDB_Driver_WriteConcernError, getInfo); static ZEND_METHOD(MongoDB_Driver_WriteConcernError, getMessage); static const zend_function_entry class_MongoDB_Driver_WriteConcernError_methods[] = { ZEND_ME(MongoDB_Driver_WriteConcernError, __construct, arginfo_class_MongoDB_Driver_WriteConcernError___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcernError, getCode, arginfo_class_MongoDB_Driver_WriteConcernError_getCode, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcernError, getInfo, arginfo_class_MongoDB_Driver_WriteConcernError_getInfo, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcernError, getMessage, arginfo_class_MongoDB_Driver_WriteConcernError_getMessage, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_WriteConcernError(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "WriteConcernError", class_MongoDB_Driver_WriteConcernError_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/WriteConcern_arginfo.h0000644000175100001660000001222414760300420016472 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 5b78e4484cebcf558867cf47defea6ae25b42d76 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern___construct, 0, 0, 1) ZEND_ARG_TYPE_MASK(0, w, MAY_BE_STRING|MAY_BE_LONG, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, wtimeout, IS_LONG, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, journal, _IS_BOOL, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern_getJournal, 0, 0, _IS_BOOL, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_MongoDB_Driver_WriteConcern_getW, 0, 0, MAY_BE_STRING|MAY_BE_LONG|MAY_BE_NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern_getWtimeout, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern_isDefault, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern___set_state, 0, 1, MongoDB\\Driver\\WriteConcern, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern_bsonSerialize, 0, 0, stdClass, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern_serialize, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern_unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern___unserialize, 0, 1, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteConcern___serialize, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_WriteConcern, __construct); static ZEND_METHOD(MongoDB_Driver_WriteConcern, getJournal); static ZEND_METHOD(MongoDB_Driver_WriteConcern, getW); static ZEND_METHOD(MongoDB_Driver_WriteConcern, getWtimeout); static ZEND_METHOD(MongoDB_Driver_WriteConcern, isDefault); static ZEND_METHOD(MongoDB_Driver_WriteConcern, __set_state); static ZEND_METHOD(MongoDB_Driver_WriteConcern, bsonSerialize); static ZEND_METHOD(MongoDB_Driver_WriteConcern, serialize); static ZEND_METHOD(MongoDB_Driver_WriteConcern, unserialize); static ZEND_METHOD(MongoDB_Driver_WriteConcern, __unserialize); static ZEND_METHOD(MongoDB_Driver_WriteConcern, __serialize); static const zend_function_entry class_MongoDB_Driver_WriteConcern_methods[] = { ZEND_ME(MongoDB_Driver_WriteConcern, __construct, arginfo_class_MongoDB_Driver_WriteConcern___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, getJournal, arginfo_class_MongoDB_Driver_WriteConcern_getJournal, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, getW, arginfo_class_MongoDB_Driver_WriteConcern_getW, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, getWtimeout, arginfo_class_MongoDB_Driver_WriteConcern_getWtimeout, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, isDefault, arginfo_class_MongoDB_Driver_WriteConcern_isDefault, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, __set_state, arginfo_class_MongoDB_Driver_WriteConcern___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, bsonSerialize, arginfo_class_MongoDB_Driver_WriteConcern_bsonSerialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, serialize, arginfo_class_MongoDB_Driver_WriteConcern_serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, unserialize, arginfo_class_MongoDB_Driver_WriteConcern_unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, __unserialize, arginfo_class_MongoDB_Driver_WriteConcern___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteConcern, __serialize, arginfo_class_MongoDB_Driver_WriteConcern___serialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_WriteConcern(zend_class_entry *class_entry_MongoDB_BSON_Serializable, zend_class_entry *class_entry_Serializable) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "WriteConcern", class_MongoDB_Driver_WriteConcern_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; zend_class_implements(class_entry, 2, class_entry_MongoDB_BSON_Serializable, class_entry_Serializable); zval const_MAJORITY_value; zend_string *const_MAJORITY_value_str = zend_string_init(PHONGO_WRITE_CONCERN_W_MAJORITY, strlen(PHONGO_WRITE_CONCERN_W_MAJORITY), 1); ZVAL_STR(&const_MAJORITY_value, const_MAJORITY_value_str); zend_string *const_MAJORITY_name = zend_string_init_interned("MAJORITY", sizeof("MAJORITY") - 1, 1); zend_declare_class_constant_ex(class_entry, const_MAJORITY_name, &const_MAJORITY_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_MAJORITY_name); return class_entry; } mongodb-1.21.0/src/MongoDB/WriteError.c0000644000175100001660000001172514760300420014467 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include #include #include "php_phongo.h" #include "phongo_error.h" #include "MongoDB/WriteError.h" #include "WriteError_arginfo.h" zend_class_entry* php_phongo_writeerror_ce; PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_WriteError) /* Returns the MongoDB error code */ static PHP_METHOD(MongoDB_Driver_WriteError, getCode) { php_phongo_writeerror_t* intern; intern = Z_WRITEERROR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->code); } /* Returns the index of the operation in the BulkWrite to which this WriteError corresponds. */ static PHP_METHOD(MongoDB_Driver_WriteError, getIndex) { php_phongo_writeerror_t* intern; intern = Z_WRITEERROR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_LONG(intern->index); } /* Returns the actual error message from the server */ static PHP_METHOD(MongoDB_Driver_WriteError, getMessage) { php_phongo_writeerror_t* intern; intern = Z_WRITEERROR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_STRING(intern->message); } /* Returns additional metadata for the error */ static PHP_METHOD(MongoDB_Driver_WriteError, getInfo) { php_phongo_writeerror_t* intern; intern = Z_WRITEERROR_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); if (!Z_ISUNDEF(intern->info)) { RETURN_ZVAL(&intern->info, 1, 0); } } /* MongoDB\Driver\WriteError object handlers */ static zend_object_handlers php_phongo_handler_writeerror; static void php_phongo_writeerror_free_object(zend_object* object) { php_phongo_writeerror_t* intern = Z_OBJ_WRITEERROR(object); zend_object_std_dtor(&intern->std); if (intern->message) { efree(intern->message); } if (!Z_ISUNDEF(intern->info)) { zval_ptr_dtor(&intern->info); } } static zend_object* php_phongo_writeerror_create_object(zend_class_entry* class_type) { php_phongo_writeerror_t* intern = zend_object_alloc(sizeof(php_phongo_writeerror_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_writeerror; return &intern->std; } static HashTable* php_phongo_writeerror_get_debug_info(zend_object* object, int* is_temp) { php_phongo_writeerror_t* intern; zval retval = ZVAL_STATIC_INIT; *is_temp = 1; intern = Z_OBJ_WRITEERROR(object); array_init_size(&retval, 3); ADD_ASSOC_STRING(&retval, "message", intern->message); ADD_ASSOC_LONG_EX(&retval, "code", intern->code); ADD_ASSOC_LONG_EX(&retval, "index", intern->index); if (!Z_ISUNDEF(intern->info)) { Z_ADDREF(intern->info); ADD_ASSOC_ZVAL_EX(&retval, "info", &intern->info); } else { ADD_ASSOC_NULL_EX(&retval, "info"); } return Z_ARRVAL(retval); } void php_phongo_writeerror_init_ce(INIT_FUNC_ARGS) { php_phongo_writeerror_ce = register_class_MongoDB_Driver_WriteError(); php_phongo_writeerror_ce->create_object = php_phongo_writeerror_create_object; memcpy(&php_phongo_handler_writeerror, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_writeerror.get_debug_info = php_phongo_writeerror_get_debug_info; php_phongo_handler_writeerror.free_obj = php_phongo_writeerror_free_object; php_phongo_handler_writeerror.offset = XtOffsetOf(php_phongo_writeerror_t, std); } zend_bool phongo_writeerror_init(zval* return_value, bson_t* bson) { bson_iter_t iter; php_phongo_writeerror_t* intern; object_init_ex(return_value, php_phongo_writeerror_ce); intern = Z_WRITEERROR_OBJ_P(return_value); intern->code = 0; intern->index = 0; if (bson_iter_init_find(&iter, bson, "code") && BSON_ITER_HOLDS_INT32(&iter)) { intern->code = bson_iter_int32(&iter); } if (bson_iter_init_find(&iter, bson, "errmsg") && BSON_ITER_HOLDS_UTF8(&iter)) { uint32_t errmsg_len; const char* err_msg = bson_iter_utf8(&iter, &errmsg_len); intern->message = estrndup(err_msg, errmsg_len); } if (bson_iter_init_find(&iter, bson, "errInfo") && BSON_ITER_HOLDS_DOCUMENT(&iter)) { uint32_t len; const uint8_t* data = NULL; bson_iter_document(&iter, &len, &data); if (!php_phongo_bson_data_to_zval(data, len, &intern->info)) { zval_ptr_dtor(&intern->info); ZVAL_UNDEF(&intern->info); return false; } } if (bson_iter_init_find(&iter, bson, "index") && BSON_ITER_HOLDS_INT32(&iter)) { intern->index = bson_iter_int32(&iter); } return true; } mongodb-1.21.0/src/MongoDB/WriteError.h0000644000175100001660000000144514760300420014472 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_WRITEERROR_H #define PHONGO_WRITEERROR_H #include "bson/bson.h" #include zend_bool phongo_writeerror_init(zval* return_value, bson_t* bson); #endif /* PHONGO_WRITEERROR_H */ mongodb-1.21.0/src/MongoDB/WriteError_arginfo.h0000644000175100001660000000411014760300420016167 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 8f9ebc299c90e86c6a55ea39e02d5a1734d10402 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_WriteError___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteError_getCode, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_WriteError_getIndex arginfo_class_MongoDB_Driver_WriteError_getCode ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteError_getInfo, 0, 0, IS_OBJECT, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteError_getMessage, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_WriteError, __construct); static ZEND_METHOD(MongoDB_Driver_WriteError, getCode); static ZEND_METHOD(MongoDB_Driver_WriteError, getIndex); static ZEND_METHOD(MongoDB_Driver_WriteError, getInfo); static ZEND_METHOD(MongoDB_Driver_WriteError, getMessage); static const zend_function_entry class_MongoDB_Driver_WriteError_methods[] = { ZEND_ME(MongoDB_Driver_WriteError, __construct, arginfo_class_MongoDB_Driver_WriteError___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteError, getCode, arginfo_class_MongoDB_Driver_WriteError_getCode, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteError, getIndex, arginfo_class_MongoDB_Driver_WriteError_getIndex, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteError, getInfo, arginfo_class_MongoDB_Driver_WriteError_getInfo, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteError, getMessage, arginfo_class_MongoDB_Driver_WriteError_getMessage, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_WriteError(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "WriteError", class_MongoDB_Driver_WriteError_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/MongoDB/WriteResult.c0000644000175100001660000003237214760300420014655 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include "php_array_api.h" #include "php_phongo.h" #include "phongo_error.h" #include "MongoDB/Server.h" #include "MongoDB/WriteConcern.h" #include "MongoDB/WriteConcernError.h" #include "MongoDB/WriteError.h" #include "WriteResult_arginfo.h" #define PHONGO_WRITERESULT_CHECK_ACKNOWLEDGED(method) \ if (!mongoc_write_concern_is_acknowledged(intern->write_concern)) { \ php_error_docref(NULL, E_DEPRECATED, "Calling MongoDB\\Driver\\WriteResult::" method "() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0"); \ RETURN_NULL(); \ } #define PHONGO_WRITERESULT_RETURN_LONG_FROM_BSON_INT32(iter, bson, key) \ if (bson_iter_init_find((iter), (bson), (key)) && BSON_ITER_HOLDS_INT32((iter))) { \ RETURN_LONG(bson_iter_int32((iter))); \ } \ RETURN_LONG(0); zend_class_entry* php_phongo_writeresult_ce; static bool php_phongo_writeresult_get_writeconcernerror(php_phongo_writeresult_t* intern, zval* return_value) { bson_iter_t iter, child; zval writeconcernerror; ZVAL_NULL(return_value); if (bson_iter_init_find(&iter, intern->reply, "writeConcernErrors") && BSON_ITER_HOLDS_ARRAY(&iter) && bson_iter_recurse(&iter, &child)) { while (bson_iter_next(&child)) { bson_t cbson; uint32_t len; const uint8_t* data; if (!BSON_ITER_HOLDS_DOCUMENT(&child)) { continue; } bson_iter_document(&child, &len, &data); if (!bson_init_static(&cbson, data, len)) { continue; } if (!phongo_writeconcernerror_init(&writeconcernerror, &cbson)) { zval_ptr_dtor(&writeconcernerror); return false; } ZVAL_ZVAL(return_value, &writeconcernerror, 1, 1); return true; } } return true; } static bool php_phongo_writeresult_get_writeerrors(php_phongo_writeresult_t* intern, zval* return_value) { bson_iter_t iter, child; array_init(return_value); if (bson_iter_init_find(&iter, intern->reply, "writeErrors") && BSON_ITER_HOLDS_ARRAY(&iter) && bson_iter_recurse(&iter, &child)) { while (bson_iter_next(&child)) { bson_t cbson; uint32_t len; const uint8_t* data; zval writeerror; if (!BSON_ITER_HOLDS_DOCUMENT(&child)) { continue; } bson_iter_document(&child, &len, &data); if (!bson_init_static(&cbson, data, len)) { continue; } if (!phongo_writeerror_init(&writeerror, &cbson)) { zval_ptr_dtor(&writeerror); continue; } add_next_index_zval(return_value, &writeerror); } } return true; } static bool php_phongo_writeresult_get_error_replies(php_phongo_writeresult_t* intern, zval* return_value) { bson_iter_t iter, child; array_init(return_value); if (bson_iter_init_find(&iter, intern->reply, "errorReplies") && BSON_ITER_HOLDS_ARRAY(&iter) && bson_iter_recurse(&iter, &child)) { while (bson_iter_next(&child)) { uint32_t len; const uint8_t* data; zval error_reply; if (!BSON_ITER_HOLDS_DOCUMENT(&child)) { continue; } bson_iter_document(&child, &len, &data); php_phongo_bson_data_to_zval(data, len, &error_reply); add_next_index_zval(return_value, &error_reply); } } return true; } PHONGO_DISABLED_CONSTRUCTOR(MongoDB_Driver_WriteResult) /* Returns the number of documents that were inserted */ static PHP_METHOD(MongoDB_Driver_WriteResult, getInsertedCount) { bson_iter_t iter; php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); PHONGO_WRITERESULT_CHECK_ACKNOWLEDGED("getInsertedCount"); PHONGO_WRITERESULT_RETURN_LONG_FROM_BSON_INT32(&iter, intern->reply, "nInserted"); } /* Returns the number of documents that matched the update criteria */ static PHP_METHOD(MongoDB_Driver_WriteResult, getMatchedCount) { bson_iter_t iter; php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); PHONGO_WRITERESULT_CHECK_ACKNOWLEDGED("getMatchedCount"); PHONGO_WRITERESULT_RETURN_LONG_FROM_BSON_INT32(&iter, intern->reply, "nMatched"); } /* Returns the number of documents that were actually modified by an update */ static PHP_METHOD(MongoDB_Driver_WriteResult, getModifiedCount) { bson_iter_t iter; php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); PHONGO_WRITERESULT_CHECK_ACKNOWLEDGED("getModifiedCount"); PHONGO_WRITERESULT_RETURN_LONG_FROM_BSON_INT32(&iter, intern->reply, "nModified"); } /* Returns the number of documents that were deleted */ static PHP_METHOD(MongoDB_Driver_WriteResult, getDeletedCount) { bson_iter_t iter; php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); PHONGO_WRITERESULT_CHECK_ACKNOWLEDGED("getDeletedCount"); PHONGO_WRITERESULT_RETURN_LONG_FROM_BSON_INT32(&iter, intern->reply, "nRemoved"); } /* Returns the number of documents that were upserted */ static PHP_METHOD(MongoDB_Driver_WriteResult, getUpsertedCount) { bson_iter_t iter; php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); PHONGO_WRITERESULT_CHECK_ACKNOWLEDGED("getUpsertedCount"); PHONGO_WRITERESULT_RETURN_LONG_FROM_BSON_INT32(&iter, intern->reply, "nUpserted"); } /* Returns the Server from which the result originated */ static PHP_METHOD(MongoDB_Driver_WriteResult, getServer) { php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); phongo_server_init(return_value, &intern->manager, intern->server_id); } /* Returns the identifiers generated by the server for upsert operations. */ static PHP_METHOD(MongoDB_Driver_WriteResult, getUpsertedIds) { bson_iter_t iter, child; php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); PHONGO_WRITERESULT_CHECK_ACKNOWLEDGED("getUpsertedIds"); array_init(return_value); if (bson_iter_init_find(&iter, intern->reply, "upserted") && BSON_ITER_HOLDS_ARRAY(&iter) && bson_iter_recurse(&iter, &child)) { while (bson_iter_next(&child)) { uint32_t data_len; const uint8_t* data = NULL; php_phongo_bson_state state; /* Use PHONGO_TYPEMAP_NATIVE_ARRAY for the root type so we can * easily access the "index" and "_id" fields. */ PHONGO_BSON_INIT_STATE(state); state.map.root.type = PHONGO_TYPEMAP_NATIVE_ARRAY; if (!BSON_ITER_HOLDS_DOCUMENT(&child)) { continue; } bson_iter_document(&child, &data_len, &data); if (php_phongo_bson_data_to_zval_ex(data, data_len, &state)) { zval* zid = php_array_fetchc(&state.zchild, "_id"); add_index_zval(return_value, php_array_fetchc_long(&state.zchild, "index"), zid); zval_add_ref(zid); } zval_ptr_dtor(&state.zchild); } } } /* Return any write concern error that occurred */ static PHP_METHOD(MongoDB_Driver_WriteResult, getWriteConcernError) { php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_writeresult_get_writeconcernerror(intern, return_value); } /* Returns any write errors that occurred */ static PHP_METHOD(MongoDB_Driver_WriteResult, getWriteErrors) { php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_writeresult_get_writeerrors(intern, return_value); } static PHP_METHOD(MongoDB_Driver_WriteResult, getErrorReplies) { php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); php_phongo_writeresult_get_error_replies(intern, return_value); } /* Returns whether the write operation was acknowledged (based on the write concern). */ static PHP_METHOD(MongoDB_Driver_WriteResult, isAcknowledged) { php_phongo_writeresult_t* intern; intern = Z_WRITERESULT_OBJ_P(getThis()); PHONGO_PARSE_PARAMETERS_NONE(); RETURN_BOOL(mongoc_write_concern_is_acknowledged(intern->write_concern)); } /* MongoDB\Driver\WriteResult object handlers */ static zend_object_handlers php_phongo_handler_writeresult; static void php_phongo_writeresult_free_object(zend_object* object) { php_phongo_writeresult_t* intern = Z_OBJ_WRITERESULT(object); zend_object_std_dtor(&intern->std); if (intern->reply) { bson_destroy(intern->reply); } if (intern->write_concern) { mongoc_write_concern_destroy(intern->write_concern); } if (!Z_ISUNDEF(intern->manager)) { zval_ptr_dtor(&intern->manager); } } static zend_object* php_phongo_writeresult_create_object(zend_class_entry* class_type) { php_phongo_writeresult_t* intern = zend_object_alloc(sizeof(php_phongo_writeresult_t), class_type); zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); intern->std.handlers = &php_phongo_handler_writeresult; return &intern->std; } static HashTable* php_phongo_writeresult_get_debug_info(zend_object* object, int* is_temp) { php_phongo_writeresult_t* intern; zval retval = ZVAL_STATIC_INIT; bson_iter_t iter; intern = Z_OBJ_WRITERESULT(object); *is_temp = 1; array_init_size(&retval, 10); #define PHONGO_WRITERESULT_SCP(field) \ if (bson_iter_init_find(&iter, intern->reply, (field)) && BSON_ITER_HOLDS_INT32(&iter)) { \ ADD_ASSOC_LONG_EX(&retval, (field), bson_iter_int32(&iter)); \ } else { \ ADD_ASSOC_NULL_EX(&retval, (field)); \ } PHONGO_WRITERESULT_SCP("nInserted"); PHONGO_WRITERESULT_SCP("nMatched"); PHONGO_WRITERESULT_SCP("nModified"); PHONGO_WRITERESULT_SCP("nRemoved"); PHONGO_WRITERESULT_SCP("nUpserted"); #undef PHONGO_WRITERESULT_SCP if (bson_iter_init_find(&iter, intern->reply, "upserted") && BSON_ITER_HOLDS_ARRAY(&iter)) { uint32_t len; const uint8_t* data; php_phongo_bson_state state; PHONGO_BSON_INIT_DEBUG_STATE(state); bson_iter_array(&iter, &len, &data); if (!php_phongo_bson_data_to_zval_ex(data, len, &state)) { zval_ptr_dtor(&state.zchild); goto done; } ADD_ASSOC_ZVAL_EX(&retval, "upsertedIds", &state.zchild); } else { zval upsertedIds; array_init(&upsertedIds); ADD_ASSOC_ZVAL_EX(&retval, "upsertedIds", &upsertedIds); } { zval writeerrors; php_phongo_writeresult_get_writeerrors(intern, &writeerrors); ADD_ASSOC_ZVAL_EX(&retval, "writeErrors", &writeerrors); } { zval writeconcernerror; php_phongo_writeresult_get_writeconcernerror(intern, &writeconcernerror); ADD_ASSOC_ZVAL_EX(&retval, "writeConcernError", &writeconcernerror); } if (intern->write_concern) { zval write_concern; phongo_writeconcern_init(&write_concern, intern->write_concern); ADD_ASSOC_ZVAL_EX(&retval, "writeConcern", &write_concern); } else { ADD_ASSOC_NULL_EX(&retval, "writeConcern"); } { zval error_replies; php_phongo_writeresult_get_error_replies(intern, &error_replies); ADD_ASSOC_ZVAL_EX(&retval, "errorReplies", &error_replies); } done: return Z_ARRVAL(retval); } void php_phongo_writeresult_init_ce(INIT_FUNC_ARGS) { php_phongo_writeresult_ce = register_class_MongoDB_Driver_WriteResult(); php_phongo_writeresult_ce->create_object = php_phongo_writeresult_create_object; memcpy(&php_phongo_handler_writeresult, phongo_get_std_object_handlers(), sizeof(zend_object_handlers)); php_phongo_handler_writeresult.get_debug_info = php_phongo_writeresult_get_debug_info; php_phongo_handler_writeresult.free_obj = php_phongo_writeresult_free_object; php_phongo_handler_writeresult.offset = XtOffsetOf(php_phongo_writeresult_t, std); } php_phongo_writeresult_t* phongo_writeresult_init(zval* return_value, bson_t* reply, zval* manager, uint32_t server_id) { php_phongo_writeresult_t* writeresult; object_init_ex(return_value, php_phongo_writeresult_ce); writeresult = Z_WRITERESULT_OBJ_P(return_value); writeresult->reply = bson_copy(reply); writeresult->server_id = server_id; ZVAL_ZVAL(&writeresult->manager, manager, 1, 0); return writeresult; } mongodb-1.21.0/src/MongoDB/WriteResult.h0000644000175100001660000000153514760300420014657 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_WRITERESULT_H #define PHONGO_WRITERESULT_H #include "bson/bson.h" #include php_phongo_writeresult_t* phongo_writeresult_init(zval* return_value, bson_t* reply, zval* manager, uint32_t server_id); #endif /* PHONGO_WRITERESULT_H */ mongodb-1.21.0/src/MongoDB/WriteResult_arginfo.h0000644000175100001660000001105614760300420016363 0ustar /* This is a generated file, edit the .stub.php file instead. * Stub hash: 84f1690181585d88c4e7233a4c959d5f50dc1b40 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_Driver_WriteResult___construct, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteResult_getInsertedCount, 0, 0, IS_LONG, 1) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_WriteResult_getMatchedCount arginfo_class_MongoDB_Driver_WriteResult_getInsertedCount #define arginfo_class_MongoDB_Driver_WriteResult_getModifiedCount arginfo_class_MongoDB_Driver_WriteResult_getInsertedCount #define arginfo_class_MongoDB_Driver_WriteResult_getDeletedCount arginfo_class_MongoDB_Driver_WriteResult_getInsertedCount #define arginfo_class_MongoDB_Driver_WriteResult_getUpsertedCount arginfo_class_MongoDB_Driver_WriteResult_getInsertedCount ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_WriteResult_getServer, 0, 0, MongoDB\\Driver\\Server, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteResult_getUpsertedIds, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_Driver_WriteResult_getWriteConcernError, 0, 0, MongoDB\\Driver\\WriteConcernError, 1) ZEND_END_ARG_INFO() #define arginfo_class_MongoDB_Driver_WriteResult_getWriteErrors arginfo_class_MongoDB_Driver_WriteResult_getUpsertedIds #define arginfo_class_MongoDB_Driver_WriteResult_getErrorReplies arginfo_class_MongoDB_Driver_WriteResult_getUpsertedIds ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_Driver_WriteResult_isAcknowledged, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_Driver_WriteResult, __construct); static ZEND_METHOD(MongoDB_Driver_WriteResult, getInsertedCount); static ZEND_METHOD(MongoDB_Driver_WriteResult, getMatchedCount); static ZEND_METHOD(MongoDB_Driver_WriteResult, getModifiedCount); static ZEND_METHOD(MongoDB_Driver_WriteResult, getDeletedCount); static ZEND_METHOD(MongoDB_Driver_WriteResult, getUpsertedCount); static ZEND_METHOD(MongoDB_Driver_WriteResult, getServer); static ZEND_METHOD(MongoDB_Driver_WriteResult, getUpsertedIds); static ZEND_METHOD(MongoDB_Driver_WriteResult, getWriteConcernError); static ZEND_METHOD(MongoDB_Driver_WriteResult, getWriteErrors); static ZEND_METHOD(MongoDB_Driver_WriteResult, getErrorReplies); static ZEND_METHOD(MongoDB_Driver_WriteResult, isAcknowledged); static const zend_function_entry class_MongoDB_Driver_WriteResult_methods[] = { ZEND_ME(MongoDB_Driver_WriteResult, __construct, arginfo_class_MongoDB_Driver_WriteResult___construct, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getInsertedCount, arginfo_class_MongoDB_Driver_WriteResult_getInsertedCount, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getMatchedCount, arginfo_class_MongoDB_Driver_WriteResult_getMatchedCount, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getModifiedCount, arginfo_class_MongoDB_Driver_WriteResult_getModifiedCount, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getDeletedCount, arginfo_class_MongoDB_Driver_WriteResult_getDeletedCount, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getUpsertedCount, arginfo_class_MongoDB_Driver_WriteResult_getUpsertedCount, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getServer, arginfo_class_MongoDB_Driver_WriteResult_getServer, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getUpsertedIds, arginfo_class_MongoDB_Driver_WriteResult_getUpsertedIds, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getWriteConcernError, arginfo_class_MongoDB_Driver_WriteResult_getWriteConcernError, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getWriteErrors, arginfo_class_MongoDB_Driver_WriteResult_getWriteErrors, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, getErrorReplies, arginfo_class_MongoDB_Driver_WriteResult_getErrorReplies, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_Driver_WriteResult, isAcknowledged, arginfo_class_MongoDB_Driver_WriteResult_isAcknowledged, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_FE_END }; static zend_class_entry *register_class_MongoDB_Driver_WriteResult(void) { zend_class_entry ce, *class_entry; INIT_NS_CLASS_ENTRY(ce, "MongoDB\\Driver", "WriteResult", class_MongoDB_Driver_WriteResult_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } mongodb-1.21.0/src/contrib/php_array_api.h0000644000175100001660000004770314760300420015366 0ustar /* +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2018 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Sara Golemon (pollita@php.net) | +----------------------------------------------------------------------+ */ #ifndef PHP_ARRAY_API_H #define PHP_ARRAY_API_H #include "zend.h" #include "zend_execute.h" #include "zend_API.h" #include "zend_operators.h" #include "zend_hash.h" #include "zend_list.h" /** * All APIs in this file follow a general format: * * php_array_{$verb}{$modifier}_{$type}(zval *zarr, ...) * * $verb is one of: * exists - Boolean check whether the array offset exists * fetch - Retrieve the value at $zarr[$key] * unset - Delete the named offset from the array * * $modifier specifies what type of offset (key) is being used: * - NULL terminated string variable, unknown length * l - NULL terminated string variable, known length * l_safe - String variable of known length, not necessarily NULL terminated * n - Long (integer) offset * c - NULL terminated string literal (e.g. "foo" rather than foo) * z - zval* offset, type should be NULL, BOOL, LONG, DOUBLE, or STRING * * $type is specific to the "fetch" verb: * - Fetch a zval* of any type * bool - Fetch a zend_bool (converting as needed) * long - Fetch a long (converting as needed) * double - Fetch a double (converting as needed) * string - Fetch a string (converting as needed, caller may need to free) * array - Fetch an array (no conversion from other types) * object - Fetch an object (no conversion, type spec optional) * resource - Fetch a resource (no conversion, type spec mandatory) * * See the specific subsection for additional details */ /* isset($zarr[$key]) - Check for the existence of a key within an array * * zend_bool php_array_exists(zval *zarr, const char *key) * zend_bool php_array_existsc(zval *zarr, const char *litstr) * zend_bool php_array_existsl(zval *zarr, const char *key, int key_len) * zend_bool php_array_existsl_safe(zval *zarr, const char *key, int key_len) * zend_bool php_array_existsn(zval *zarr, unsigned long idx) * zend_bool php_array_existsz(zval *zarr, zval *key) */ static inline zend_bool php_array_exists(zval *zarr, const char *key) { return zend_symtable_str_exists(Z_ARRVAL_P(zarr), key, strlen(key)); } #define php_array_existsc(zarr, litstr) \ zend_symtable_str_exists(Z_ARRVAL_P(zarr), litstr, sizeof(litstr) - 1) #define php_array_existsl(zarr, key, len) \ zend_symtable_str_exists(Z_ARRVAL_P(zarr), key, len) static inline zend_bool php_array_existsl_safe(zval *zarr, const char *key, int key_len) { zend_string *keystr = zend_string_init(key, key_len, 0); zend_bool ret = zend_symtable_exists(Z_ARRVAL_P(zarr), keystr); zend_string_release(keystr); return ret; } #define php_array_existsn(zarr, idx) \ zend_hash_index_exists(Z_ARRVAL_P(zarr), idx) static inline zend_bool php_array_existsz(zval *zarr, zval *key) { switch (Z_TYPE_P(key)) { case IS_NULL: return php_array_existsc(zarr, ""); case IS_FALSE: return zend_hash_index_exists(Z_ARRVAL_P(zarr), 0); case IS_TRUE: return zend_hash_index_exists(Z_ARRVAL_P(zarr), 1); case IS_LONG: return zend_hash_index_exists(Z_ARRVAL_P(zarr), Z_LVAL_P(key)); case IS_DOUBLE: return zend_hash_index_exists(Z_ARRVAL_P(zarr), zend_dval_to_lval(Z_DVAL_P(key))); case IS_STRING: return php_array_existsl(zarr, Z_STRVAL_P(key), Z_STRLEN_P(key)); default: return 0; } } /* =$zarr[$key] - Fetch a zval (or appropriate type) from an array * * Methods returning pointers yield NULL on key not existing, * others yield 0, false, etc... as appropriate. * Callers needing to distinguish empty scalars from non-existent * scalars should use php_array_exists*() or fetch the zval then convert. * * If the type of the value does not match what is requested * it will be implicitly converted (if possible). * * See each type section for specific prototypes * * php_array_fetch* - Fetch a zval * php_array_fetch*_bool - Fetch a boolean * php_array_fetch*_long - Fetch a long * php_array_fetch*_double - Fetch a double * php_array_fetch*_string - Fetch a string (must be efree()'d by caller) * php_array_fetch*_array - Fetch an array * php_array_fetch*_resource - Fetch a resource or a specific type * php_array_fetch*_object - Fetch an object * * For each result type, there are six key forms: * php_array_fetch_T(zval *zarr, const char *key, ...) * NULL terminated string key * php_array_fetchc_T(zval *zarr, const char *litkey, ...) * String literal key * php_array_fetchl_T(zval *zarr, const char *key, int key_len, ...) * NULL terminated string key of known length * php_array_fetchl_safe_T(zval *zarr, const char *key, int key_len, ...) * String key of known length, may not be NULL terminated * php_array_fetchn_T(zval *zarr, unsigned long idx, ...) * Numeric key * php_array_fetchz_T(zval *zarr, zval *key, ...) * zval* key */ /* Fetch zval* * * zval *php_array_fetch(zval *zarr, const char *key) * zval *php_array_fetchl(zval *zarr, const char *key, int key_len) * zval *php_array_fetchl_safe(zval *zarr, const char *key, int key_len) * zval *php_array_fetchn(zval *zarr, unsigned long idx) * zval *php_array_fetchc(zval *zarr, const char *litstr) * zval *php_array_fetchz(zval *zarr, zval *key) */ static inline zval *php_array_fetchl(zval *zarr, const char *key, int key_len) { return zend_symtable_str_find(Z_ARRVAL_P(zarr), key, key_len); } static inline zval *php_array_fetch(zval *zarr, const char *key) { return php_array_fetchl(zarr, key, strlen(key)); } #define php_array_fetchc(zarr, litstr) php_array_fetchl(zarr, litstr, sizeof(litstr)-1) static inline zval *php_array_fetchl_safe(zval *zarr, const char *key, int key_len) { zend_string *keystr = zend_string_init(key, key_len, 0); zval *ret = zend_symtable_find(Z_ARRVAL_P(zarr), keystr); zend_string_release(keystr); return ret; } static inline zval *php_array_fetchn(zval *zarr, zend_ulong idx) { return zend_hash_index_find(Z_ARRVAL_P(zarr), idx); } static inline zval *php_array_fetchz(zval *zarr, zval *key) { switch (Z_TYPE_P(key)) { case IS_NULL: case IS_FALSE: return php_array_fetchn(zarr, 0); case IS_TRUE: return php_array_fetchn(zarr, 1); case IS_LONG: return php_array_fetchn(zarr, Z_LVAL_P(key)); case IS_DOUBLE: return php_array_fetchn(zarr, (zend_ulong) Z_DVAL_P(key)); case IS_STRING: return php_array_fetchl(zarr, Z_STRVAL_P(key), Z_STRLEN_P(key)); default: return NULL; } } static inline zval* zval_deref_safe(zval* z) { if (z) { ZVAL_DEREF(z); } return z; } /* Fetch zval*, resolving references * * zval *php_array_fetch_deref(zval *zarr, const char *key) * zval *php_array_fetchl_deref(zval *zarr, const char *key, int key_len) * zval *php_array_fetchl_safe_deref(zval *zarr, const char *key, int key_len) * zval *php_array_fetchn_deref(zval *zarr, unsigned long idx) * zval *php_array_fetchc_deref(zval *zarr, const char *litstr) * zval *php_array_fetchz_deref(zval *zarr, zval *key) */ static inline zval *php_array_fetchl_deref(zval *zarr, const char *key, int key_len) { return zval_deref_safe(php_array_fetchl(zarr, key, key_len)); } static inline zval *php_array_fetch_deref(zval *zarr, const char *key) { return zval_deref_safe(php_array_fetch(zarr, key)); } #define php_array_fetchc_deref(zarr, litstr) zval_deref_safe(php_array_fetchl(zarr, litstr, sizeof(litstr)-1)) static inline zval *php_array_fetchl_safe_deref(zval *zarr, const char *key, int key_len) { return zval_deref_safe(php_array_fetchl_safe(zarr, key, key_len)); } static inline zval *php_array_fetchn_deref(zval *zarr, zend_ulong idx) { return zval_deref_safe(php_array_fetchn(zarr, idx)); } static inline zval *php_array_fetchz_deref(zval *zarr, zval *key) { return zval_deref_safe(php_array_fetchz(zarr, key)); } #define PHP_ARRAY_FETCH_TYPE_MAP(ctype, ztype) \ static inline ctype php_array_fetch_##ztype(zval *zarr, const char *key) \ { return php_array_zval_to_##ztype(php_array_fetch_deref(zarr, key)); } \ static inline ctype php_array_fetchl_##ztype(zval *zarr, const char *key, int key_len) \ { return php_array_zval_to_##ztype(php_array_fetchl_deref(zarr, key, key_len)); } \ static inline ctype php_array_fetchl_safe_##ztype(zval *zarr, const char *key, int key_len) \ { return php_array_zval_to_##ztype(php_array_fetchl_safe_deref(zarr, key, key_len)); } \ static inline ctype php_array_fetchn_##ztype(zval *zarr, zend_ulong idx) \ { return php_array_zval_to_##ztype(php_array_fetchn_deref(zarr, idx)); } \ static inline ctype php_array_fetchz_##ztype(zval *zarr, zval *key) \ { return php_array_zval_to_##ztype(php_array_fetchz_deref(zarr, key)); } /* Fetch zend_bool * * zend_bool php_array_fetch_bool(zval *zarr, const char *key) * zend_bool php_array_fetchl_bool(zval *zarr, const char *key, int key_len) * zend_bool php_array_fetchl_safe_bool(zval *zarr, const char *key, int key_len) * zend_bool php_array_fetchn_bool(zval *zarr, unsigned long idx) * zend_bool php_array_fetchc_bool(zval *zarr, const char *litstr) * zend_bool php_array_fetchz_bool(zval *zarr, zval *key) */ static inline zend_bool php_array_zval_to_bool(zval *z) { return z && zend_is_true(z); } PHP_ARRAY_FETCH_TYPE_MAP(zend_bool, bool) #define php_array_fetchc_bool(zarr, litstr) \ php_array_zval_to_bool(php_array_fetchc_deref(zarr, litstr)) /* Fetch long * * long php_array_fetch_long(zval *zarr, const char *key) * long php_array_fetchl_long(zval *zarr, const char *key, int key_len) * long php_array_fetchl_safe_long(zval *zarr, const char *key, int key_len) * long php_array_fetchn_long(zval *zarr, unsigned long idx) * long php_array_fetchc_long(zval *zarr, const char *litstr) * long php_array_fetchz_long(zval *zarr, zval *key) */ static inline zend_long php_array_zval_to_long(zval *z) { if (!z) { return 0; } switch(Z_TYPE_P(z)) { case IS_NULL: case IS_FALSE: return 0; case IS_TRUE: return 1; case IS_LONG: return Z_LVAL_P(z); default: { zval c = *z; zval_copy_ctor(&c); convert_to_long(&c); return Z_LVAL(c); } } } PHP_ARRAY_FETCH_TYPE_MAP(zend_long, long) #define php_array_fetchc_long(zarr, litstr) \ php_array_zval_to_long(php_array_fetchc_deref(zarr, litstr)) /* Fetch double * * double php_array_fetch_double(zval *zarr, const char *key) * double php_array_fetchl_double(zval *zarr, const char *key, int key_len) * double php_array_fetchl_safe_double(zval *zarr, const char *key, int key_len) * double php_array_fetchn_double(zval *zarr, unsigned long idx) * double php_array_fetchc_double(zval *zarr, const char *litstr) * double php_array_fetchz_double(zval *zarr, zval *key) */ static inline double php_array_zval_to_double(zval *z) { if (!z) { return 0.0; } switch (Z_TYPE_P(z)) { case IS_NULL: case IS_FALSE: return 0.0; case IS_TRUE: return 1.0; case IS_LONG: return (double) Z_LVAL_P(z); case IS_DOUBLE: return Z_DVAL_P(z); default: { zval c = *z; zval_copy_ctor(&c); convert_to_double(&c); return Z_DVAL(c); } } } PHP_ARRAY_FETCH_TYPE_MAP(double, double) #define php_array_fetchc_double(zarr, litstr) \ php_array_zval_to_double(php_array_fetchc_deref(zarr, litstr)) /* Fetch string * * If the pfree is set to 1 on exit, then the return value is owned by the caller * and must be efree()'d once it is no longer in use. * * plen is populated with the binary safe length of the string returned. * * char *php_array_fetch_string(zval *zarr, const char *key, int *plen, zend_bool *pfree) * char *php_array_fetchl_string(zval *zarr, const char *key, int key_len, int *plen, zend_bool *pfree) * char *php_array_fetchl_safe_string(zval *zarr, const char *key, int key_len, int *plen, zend_bool *pfree) * char *php_array_fetchn_string(zval *zarr, unsigned long idx, int *plen, zend_bool *pfree) * char *php_array_fetchc_string(zval *zarr, const char *litstr, int *plen, zend_bool *pfree) * char *php_array_fetchz_string(zval *zarr, zval *key, int *plen, zend_bool *pfree) */ static inline char *php_array_zval_to_string(zval *z, int *plen, zend_bool *pfree) { *plen = 0; *pfree = 0; if (!z) { return NULL; } switch (Z_TYPE_P(z)) { case IS_NULL: return (char *) ""; case IS_STRING: *plen = Z_STRLEN_P(z); return Z_STRVAL_P(z); default: { zval c = *z; zval_copy_ctor(&c); convert_to_string(&c); *pfree = ! IS_INTERNED(Z_STR(c)); *plen = Z_STRLEN(c); return Z_STRVAL(c); } } } #define php_array_fetch_string(zarr, key, plen, pfree) \ php_array_zval_to_string(php_array_fetch_deref(zarr, key), plen, pfree) #define php_array_fetchl_string(zarr, key, key_len, plen, pfree) \ php_array_zval_to_string(php_array_fetchl_deref(zarr, key, key_len), plen, pfree) #define php_array_fetchl_safe_string(zarr, key, key_len, plen, pfree) \ php_array_zval_to_string(php_array_fetchl_safe_deref(zarr, key, key_le), plen, pfree) #define php_array_fetchn_string(zarr, idx, plen, pfree) \ php_array_zval_to_string(php_array_fetchn_deref(zarr, idx), plen, pfree) #define php_array_fetchc_string(zarr, litstr, plen, pfree) \ php_array_zval_to_string(php_array_fetchc_deref(zarr, litstr), plen, pfree) #define php_array_fetchz_string(zarr, key, plen, pfree) \ php_array_zval_to_string(php_array_fetchz_deref(zarr, key), plen, pfree) /* Fetch array * * No implicit conversion is performed. * * If the value is an array, then that zval is returned, * otherwise NULL is returned. * * zval *php_array_fetch_array(zval *zarr, const char *key) * zval *php_array_fetchl_array(zval *zarr, const char *key, int key_len) * zval *php_array_fetchl_safe_array(zval *zarr, const char *key, int key_len) * zval *php_array_fetchn_array(zval *zarr, unsigned long idx) * zval *php_array_fetchc_array(zval *zarr, const char *litstr) * zval *php_array_fetchz_array(zval *zarr, zval *key) */ static inline zval *php_array_zval_to_array(zval *zarr) { return zarr && Z_TYPE_P(zarr) == IS_ARRAY ? zarr : NULL; } PHP_ARRAY_FETCH_TYPE_MAP(zval*, array) #define php_array_fetchc_array(zarr, litstr) \ php_array_zval_to_array(php_array_fetchc_deref(zarr, litstr)) /* count($arr) - Count number of elements in the array * * int php_array_count(zval *arr) */ #define php_array_count(zarr) zend_hash_num_elements(Z_ARRVAL_P(zarr)) /* Fetch resource * * No implicit conversion is performed. * * If the value is a resource of the named type, * then the pointer for it is returned, * otherwise NULL is returned. * * To test for multiple resource types (e.g. 'stream' and 'persistent stream') * Fetch a generic zval* and use Zend's ZEND_FETCH_RESOURCE() macro. * * zval *php_array_fetch_resource(zval *zarr, const char *key, int le) * zval *php_array_fetchl_resource(zval *zarr, const char *key, int key_len, int le) * zval *php_array_fetchl_safe_resource(zval *zarr, const char *key, int key_len, int le) * zval *php_array_fetchn_resource(zval *zarr, unsigned long idx, int le) * zval *php_array_fetchc_resource(zval *zarr, const char *litstr, int le) * zval *php_array_fetchz_resource(zval *zarr, zval *key, int le) */ static inline void *php_array_zval_to_resource(zval *z, int le) { return zend_fetch_resource_ex(z, NULL, le); } #define php_array_fetch_resource(zarr, key, le) \ php_array_zval_to_resource(php_array_fetch_deref(zarr, key), le) #define php_array_fetchl_resource(zarr, key, key_len, le) \ php_array_zval_to_resource(php_array_fetchl_deref(zarr, key, key_len), le) #define php_array_fetchl_safe_resource(zarr, key, key_len, le) \ php_array_zval_to_resource(php_array_fetchl_safe_deref(zarr, key, key_len), le) #define php_array_fetchn_resource(zarr, idx, le) \ php_array_zval_to_resource(php_array_fetchn_deref(zarr, idx), le) #define php_array_fetchc_resource(zarr, litstr, le) \ php_array_zval_to_resource(php_array_fetchc_deref(zarr, litstr), le) #define php_array_fetchz_resource(zarr, key, le) \ php_array_zval_to_resource(php_array_fetchz_deref(zarr, key), le) /* Fetch Object * * Fetch an object of a specific or non-specific type (pass ce == NULL) * * No implicit conversion is performed * * zval *php_array_fetch_object(zval *zarr, const char *key, zend_class_entry *ce) * zval *php_array_fetchl_object(zval *zarr, const char *key, int key_len, zend_class_entry *ce) * zval *php_array_fetchl_safe_object(zval *zarr, const char *key, int key_len, zend_class_entry *ce) * zval *php_array_fetchn_object(zval *zarr, unsigned long idx, zend_class_entry *ce) * zval *php_array_fetchc_object(zval *zarr, const char *litstr, zend_class_entry *ce) * zval *php_array_fetchz_object(zval *zarr, zval *key, zend_class_entry *ce) */ static inline zval *php_array_zval_to_object(zval *z, zend_class_entry *ce) { if (!z || Z_TYPE_P(z) != IS_OBJECT) { return NULL; } return (!ce) || instanceof_function(Z_OBJCE_P(z), ce) ? z : NULL; } #define php_array_fetch_object(zarr, key, ce) \ php_array_zval_to_object(php_array_fetch_deref(zarr, key), ce) #define php_array_fetchl_object(zarr, key, len, ce) \ php_array_zval_to_object(php_array_fetchl_deref(zarr, key, len), ce) #define php_array_fetchl_safe_object(zarr, key, len, ce) \ php_array_zval_to_object(php_array_fetchl_safe_deref(zarr, key, len), ce) #define php_array_fetchn_object(zarr, idx, ce) \ php_array_zval_to_object(php_array_fetchn_deref(zarr, idx), ce) #define php_array_fetchc_object(zarr, litstr, ce) \ php_array_zval_to_object(php_array_fetchc_deref(zarr, litstr), ce) #define php_array_fetchz_object(zarr, key, ce) \ php_array_zval_to_object(php_array_fetchz_deref(zarr, key), ce) /* unset($zarr[$key]) - Erase a key from an array * * void php_array_unset(zval *zarr, const char *key) * void php_array_unsetl(zval *zarr, const char *key, int key_len) * void php_array_unsetl_safe(zval *zarr, const char *key, int key_len) * void php_array_unsetn(zval *zarr, long idx) * void php_array_unsetc(zval *zarr, const char *litstr) * void php_array_unsetz(zval *zarr, zval *key) */ static inline void php_array_unset(zval *zarr, const char *key) { zend_symtable_str_del(Z_ARRVAL_P(zarr), key, strlen(key)); } #define php_array_unsetl(zarr, key, len) \ zend_symtable_str_del(Z_ARRVAL_P(zarr), key, len) static inline void php_array_unsetl_safe(zval *zarr, const char *key, int key_len) { char *k = estrndup(key, key_len); zend_symtable_str_del(Z_ARRVAL_P(zarr), k, key_len); efree(k); } #define php_array_unsetn(zarr, idx) \ zend_symtable_index_del(Z_ARRVAL_P(zarr), idx) #define php_array_unsetc(zarr, litstr) \ zend_symtable_str_del(Z_ARRVAL_P(zarr), litstr, sizeof(litstr) - 1) static inline void php_array_unsetz(zval *zarr, zval *key) { switch (Z_TYPE_P(key)) { case IS_NULL: case IS_FALSE: zend_hash_index_del(Z_ARRVAL_P(zarr), 0); return; case IS_TRUE: zend_hash_index_del(Z_ARRVAL_P(zarr), 1); return; case IS_LONG: zend_hash_index_del(Z_ARRVAL_P(zarr), Z_LVAL_P(key)); return; case IS_DOUBLE: zend_hash_index_del(Z_ARRVAL_P(zarr), (zend_ulong) Z_DVAL_P(key)); break; case IS_STRING: php_array_unsetl(zarr, Z_STRVAL_P(key), Z_STRLEN_P(key)); break; } } #endif /* PHP_ARRAY_API_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-atomic-private.h0000644000175100001660000011117314760300420022132 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_ATOMIC_PRIVATE_H #define MONGO_C_DRIVER_COMMON_ATOMIC_PRIVATE_H #include // BSON_INLINE #ifdef _MSC_VER #include #endif enum mcommon_memory_order { mcommon_memory_order_seq_cst, mcommon_memory_order_acquire, mcommon_memory_order_release, mcommon_memory_order_relaxed, mcommon_memory_order_acq_rel, mcommon_memory_order_consume, }; #if defined(_M_ARM) /* MSVC memorder atomics are only avail on ARM */ #define MSVC_MEMORDER_SUFFIX(X) X #else #define MSVC_MEMORDER_SUFFIX(X) #endif #if defined(USE_LEGACY_GCC_ATOMICS) || (!defined(__clang__) && __GNUC__ == 4) || defined(__xlC__) #define MCOMMON_USE_LEGACY_GCC_ATOMICS #else #undef MCOMMON_USE_LEGACY_GCC_ATOMICS #endif /* Not all GCC-like compilers support the current __atomic built-ins. Older * GCC (pre-5) used different built-ins named with the __sync prefix. When * compiling with such older GCC versions, it is necessary to use the applicable * functions, which requires redefining BSON_IF_GNU_LIKE and defining the * additional MCOMMON_IF_GNU_LEGACY_ATOMICS macro here. */ #ifdef MCOMMON_USE_LEGACY_GCC_ATOMICS #undef BSON_IF_GNU_LIKE #define BSON_IF_GNU_LIKE(...) #define MCOMMON_IF_GNU_LEGACY_ATOMICS(...) __VA_ARGS__ #else #define MCOMMON_IF_GNU_LEGACY_ATOMICS(...) #endif /* CDRIVER-4229 zSeries with gcc 4.8.4 produces illegal instructions for int and * int32 atomic intrinsics. */ #if defined(__s390__) || defined(__s390x__) || defined(__zarch__) #define MCOMMON_EMULATE_INT32 #define MCOMMON_EMULATE_INT #endif /* CDRIVER-4264 Contrary to documentation, VS 2013 targeting x86 does not * correctly/consistently provide _InterlockedPointerExchange. */ #if defined(_MSC_VER) && _MSC_VER < 1900 && defined(_M_IX86) #define MCOMMON_EMULATE_PTR #endif #define DEF_ATOMIC_OP(MSVC_Intrinsic, GNU_Intrinsic, GNU_Legacy_Intrinsic, Order, ...) \ do { \ switch (Order) { \ case mcommon_memory_order_acq_rel: \ BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQ_REL);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case mcommon_memory_order_seq_cst: \ BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_SEQ_CST);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case mcommon_memory_order_acquire: \ BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQUIRE);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case mcommon_memory_order_consume: \ BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_CONSUME);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case mcommon_memory_order_release: \ BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_rel)) (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELEASE);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case mcommon_memory_order_relaxed: \ BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_nf)) (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELAXED);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ default: \ BSON_UNREACHABLE ("Invalid mcommon_memory_order value"); \ } \ } while (0) #define DEF_ATOMIC_CMPEXCH_STRONG(VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue) \ do { \ BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 (_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \ Ptr, NewValue, ExpectActualVar);) \ BSON_IF_GNU_LIKE ((void) __atomic_compare_exchange_n (Ptr, \ &ExpectActualVar, \ NewValue, \ false, /* Not weak */ \ GNU_MemOrder, \ GNU_MemOrder);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (__typeof__ (ExpectActualVar) _val; \ _val = __sync_val_compare_and_swap (Ptr, ExpectActualVar, NewValue); \ ExpectActualVar = _val;) \ } while (0) #define DEF_ATOMIC_CMPEXCH_WEAK(VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue) \ do { \ BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 (_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \ Ptr, NewValue, ExpectActualVar);) \ BSON_IF_GNU_LIKE ((void) __atomic_compare_exchange_n (Ptr, \ &ExpectActualVar, \ NewValue, \ true, /* Yes weak */ \ GNU_MemOrder, \ GNU_MemOrder);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (__typeof__ (ExpectActualVar) _val; \ _val = __sync_val_compare_and_swap (Ptr, ExpectActualVar, NewValue); \ ExpectActualVar = _val;) \ } while (0) #define DECL_ATOMIC_INTEGRAL(NamePart, Type, VCIntrinSuffix) \ static BSON_INLINE Type mcommon_atomic_##NamePart##_fetch_add ( \ Type volatile *a, Type addend, enum mcommon_memory_order ord) \ { \ DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchangeAdd, VCIntrinSuffix), \ __atomic_fetch_add, \ __sync_fetch_and_add, \ ord, \ a, \ addend); \ } \ \ static BSON_INLINE Type mcommon_atomic_##NamePart##_fetch_sub ( \ Type volatile *a, Type subtrahend, enum mcommon_memory_order ord) \ { \ /* MSVC doesn't have a subtract intrinsic, so just reuse addition */ \ BSON_IF_MSVC (return mcommon_atomic_##NamePart##_fetch_add (a, -subtrahend, ord);) \ BSON_IF_GNU_LIKE (DEF_ATOMIC_OP (~, __atomic_fetch_sub, ~, ord, a, subtrahend);) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (DEF_ATOMIC_OP (~, ~, __sync_fetch_and_sub, ord, a, subtrahend);) \ } \ \ static BSON_INLINE Type mcommon_atomic_##NamePart##_fetch (Type volatile const *a, enum mcommon_memory_order order) \ { \ /* MSVC doesn't have a load intrinsic, so just add zero */ \ BSON_IF_MSVC (return mcommon_atomic_##NamePart##_fetch_add ((Type volatile *) a, 0, order);) \ /* GNU doesn't want RELEASE order for the fetch operation, so we can't \ * just use DEF_ATOMIC_OP. */ \ BSON_IF_GNU_LIKE (switch (order) { \ case mcommon_memory_order_release: /* Fall back to seqcst */ \ case mcommon_memory_order_acq_rel: /* Fall back to seqcst */ \ case mcommon_memory_order_seq_cst: \ return __atomic_load_n (a, __ATOMIC_SEQ_CST); \ case mcommon_memory_order_acquire: \ return __atomic_load_n (a, __ATOMIC_ACQUIRE); \ case mcommon_memory_order_consume: \ return __atomic_load_n (a, __ATOMIC_CONSUME); \ case mcommon_memory_order_relaxed: \ return __atomic_load_n (a, __ATOMIC_RELAXED); \ default: \ BSON_UNREACHABLE ("Invalid mcommon_memory_order value"); \ }) \ MCOMMON_IF_GNU_LEGACY_ATOMICS ({ \ BSON_UNUSED (order); \ __sync_synchronize (); \ return *a; \ }) \ } \ \ static BSON_INLINE Type mcommon_atomic_##NamePart##_exchange ( \ Type volatile *a, Type value, enum mcommon_memory_order ord) \ { \ BSON_IF_MSVC (DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchange, VCIntrinSuffix), ~, ~, ord, a, value);) \ /* GNU doesn't want CONSUME order for the exchange operation, so we \ * cannot use DEF_ATOMIC_OP. */ \ BSON_IF_GNU_LIKE (switch (ord) { \ case mcommon_memory_order_acq_rel: \ return __atomic_exchange_n (a, value, __ATOMIC_ACQ_REL); \ case mcommon_memory_order_release: \ return __atomic_exchange_n (a, value, __ATOMIC_RELEASE); \ case mcommon_memory_order_seq_cst: \ return __atomic_exchange_n (a, value, __ATOMIC_SEQ_CST); \ case mcommon_memory_order_consume: /* Fall back to acquire */ \ case mcommon_memory_order_acquire: \ return __atomic_exchange_n (a, value, __ATOMIC_ACQUIRE); \ case mcommon_memory_order_relaxed: \ return __atomic_exchange_n (a, value, __ATOMIC_RELAXED); \ default: \ BSON_UNREACHABLE ("Invalid mcommon_memory_order value"); \ }) \ MCOMMON_IF_GNU_LEGACY_ATOMICS (BSON_UNUSED (ord); return __sync_val_compare_and_swap (a, *a, value);) \ } \ \ static BSON_INLINE Type mcommon_atomic_##NamePart##_compare_exchange_strong ( \ Type volatile *a, Type expect, Type new_value, enum mcommon_memory_order ord) \ { \ Type actual = expect; \ switch (ord) { \ case mcommon_memory_order_release: \ case mcommon_memory_order_acq_rel: \ case mcommon_memory_order_seq_cst: \ DEF_ATOMIC_CMPEXCH_STRONG (VCIntrinSuffix, , __ATOMIC_SEQ_CST, a, actual, new_value); \ break; \ case mcommon_memory_order_acquire: \ DEF_ATOMIC_CMPEXCH_STRONG ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, a, actual, new_value); \ break; \ case mcommon_memory_order_consume: \ DEF_ATOMIC_CMPEXCH_STRONG ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, a, actual, new_value); \ break; \ case mcommon_memory_order_relaxed: \ DEF_ATOMIC_CMPEXCH_STRONG ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, a, actual, new_value); \ break; \ default: \ BSON_UNREACHABLE ("Invalid mcommon_memory_order value"); \ } \ return actual; \ } \ \ static BSON_INLINE Type mcommon_atomic_##NamePart##_compare_exchange_weak ( \ Type volatile *a, Type expect, Type new_value, enum mcommon_memory_order ord) \ { \ Type actual = expect; \ switch (ord) { \ case mcommon_memory_order_release: \ case mcommon_memory_order_acq_rel: \ case mcommon_memory_order_seq_cst: \ DEF_ATOMIC_CMPEXCH_WEAK (VCIntrinSuffix, , __ATOMIC_SEQ_CST, a, actual, new_value); \ break; \ case mcommon_memory_order_acquire: \ DEF_ATOMIC_CMPEXCH_WEAK ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, a, actual, new_value); \ break; \ case mcommon_memory_order_consume: \ DEF_ATOMIC_CMPEXCH_WEAK ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, a, actual, new_value); \ break; \ case mcommon_memory_order_relaxed: \ DEF_ATOMIC_CMPEXCH_WEAK (VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, a, actual, new_value); \ break; \ default: \ BSON_UNREACHABLE ("Invalid mcommon_memory_order value"); \ } \ return actual; \ } #define DECL_ATOMIC_STDINT(Name, VCSuffix) DECL_ATOMIC_INTEGRAL (Name, Name##_t, VCSuffix) #if defined(_MSC_VER) || defined(MCOMMON_USE_LEGACY_GCC_ATOMICS) /* MSVC and GCC require built-in types (not typedefs) for their atomic * intrinsics. */ #if defined(_MSC_VER) #define DECL_ATOMIC_INTEGRAL_INT8 char #define DECL_ATOMIC_INTEGRAL_INT32 long #define DECL_ATOMIC_INTEGRAL_INT long #else #define DECL_ATOMIC_INTEGRAL_INT8 signed char #define DECL_ATOMIC_INTEGRAL_INT32 int #define DECL_ATOMIC_INTEGRAL_INT int #endif DECL_ATOMIC_INTEGRAL (int8, DECL_ATOMIC_INTEGRAL_INT8, 8) DECL_ATOMIC_INTEGRAL (int16, short, 16) #if !defined(MCOMMON_EMULATE_INT32) DECL_ATOMIC_INTEGRAL (int32, DECL_ATOMIC_INTEGRAL_INT32, ) #endif #if !defined(MCOMMON_EMULATE_INT) DECL_ATOMIC_INTEGRAL (int, DECL_ATOMIC_INTEGRAL_INT, ) #endif #else /* Other compilers that we support provide generic intrinsics */ DECL_ATOMIC_STDINT (int8, 8) DECL_ATOMIC_STDINT (int16, 16) #if !defined(MCOMMON_EMULATE_INT32) DECL_ATOMIC_STDINT (int32, ) #endif #if !defined(MCOMMON_EMULATE_INT) DECL_ATOMIC_INTEGRAL (int, int, ) #endif #endif #ifndef DECL_ATOMIC_INTEGRAL_INT32 #define DECL_ATOMIC_INTEGRAL_INT32 int32_t #endif #define _mcommon_emul_atomic_int64_fetch_add COMMON_NAME (emul_atomic_int64_fetch_add) #define _mcommon_emul_atomic_int64_exchange COMMON_NAME (emul_atomic_int64_exchange) #define _mcommon_emul_atomic_int64_compare_exchange_strong COMMON_NAME (emul_atomic_int64_compare_exchange_strong) #define _mcommon_emul_atomic_int64_compare_exchange_weak COMMON_NAME (emul_atomic_int64_compare_exchange_weak) #define _mcommon_emul_atomic_int32_fetch_add COMMON_NAME (emul_atomic_int32_fetch_add) #define _mcommon_emul_atomic_int32_exchange COMMON_NAME (emul_atomic_int32_exchange) #define _mcommon_emul_atomic_int32_compare_exchange_strong COMMON_NAME (emul_atomic_int32_compare_exchange_strong) #define _mcommon_emul_atomic_int32_compare_exchange_weak COMMON_NAME (emul_atomic_int32_compare_exchange_weak) #define _mcommon_emul_atomic_int_fetch_add COMMON_NAME (emul_atomic_int_fetch_add) #define _mcommon_emul_atomic_int_exchange COMMON_NAME (emul_atomic_int_exchange) #define _mcommon_emul_atomic_int_compare_exchange_strong COMMON_NAME (emul_atomic_int_compare_exchange_strong) #define _mcommon_emul_atomic_int_compare_exchange_weak COMMON_NAME (emul_atomic_int_compare_exchange_weak) #define _mcommon_emul_atomic_ptr_exchange COMMON_NAME (emul_atomic_ptr_exchange) #define mcommon_thrd_yield COMMON_NAME (thrd_yield) int64_t _mcommon_emul_atomic_int64_fetch_add (int64_t volatile *val, int64_t v, enum mcommon_memory_order); int64_t _mcommon_emul_atomic_int64_exchange (int64_t volatile *val, int64_t v, enum mcommon_memory_order); int64_t _mcommon_emul_atomic_int64_compare_exchange_strong (int64_t volatile *val, int64_t expect_value, int64_t new_value, enum mcommon_memory_order); int64_t _mcommon_emul_atomic_int64_compare_exchange_weak (int64_t volatile *val, int64_t expect_value, int64_t new_value, enum mcommon_memory_order); int32_t _mcommon_emul_atomic_int32_fetch_add (int32_t volatile *val, int32_t v, enum mcommon_memory_order); int32_t _mcommon_emul_atomic_int32_exchange (int32_t volatile *val, int32_t v, enum mcommon_memory_order); int32_t _mcommon_emul_atomic_int32_compare_exchange_strong (int32_t volatile *val, int32_t expect_value, int32_t new_value, enum mcommon_memory_order); int32_t _mcommon_emul_atomic_int32_compare_exchange_weak (int32_t volatile *val, int32_t expect_value, int32_t new_value, enum mcommon_memory_order); int _mcommon_emul_atomic_int_fetch_add (int volatile *val, int v, enum mcommon_memory_order); int _mcommon_emul_atomic_int_exchange (int volatile *val, int v, enum mcommon_memory_order); int _mcommon_emul_atomic_int_compare_exchange_strong (int volatile *val, int expect_value, int new_value, enum mcommon_memory_order); int _mcommon_emul_atomic_int_compare_exchange_weak (int volatile *val, int expect_value, int new_value, enum mcommon_memory_order); void * _mcommon_emul_atomic_ptr_exchange (void *volatile *val, void *v, enum mcommon_memory_order); void mcommon_thrd_yield (void); #if (defined(_MSC_VER) && !defined(_M_IX86)) || (defined(__LP64__) && __LP64__) /* (64-bit intrinsics are only available in x64) */ #ifdef _MSC_VER DECL_ATOMIC_INTEGRAL (int64, __int64, 64) #else DECL_ATOMIC_STDINT (int64, 64) #endif #else static BSON_INLINE int64_t mcommon_atomic_int64_fetch (const int64_t volatile *val, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int64_fetch_add ((int64_t volatile *) val, 0, order); } static BSON_INLINE int64_t mcommon_atomic_int64_fetch_add (int64_t volatile *val, int64_t v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int64_fetch_add (val, v, order); } static BSON_INLINE int64_t mcommon_atomic_int64_fetch_sub (int64_t volatile *val, int64_t v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int64_fetch_add (val, -v, order); } static BSON_INLINE int64_t mcommon_atomic_int64_exchange (int64_t volatile *val, int64_t v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int64_exchange (val, v, order); } static BSON_INLINE int64_t mcommon_atomic_int64_compare_exchange_strong (int64_t volatile *val, int64_t expect_value, int64_t new_value, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int64_compare_exchange_strong (val, expect_value, new_value, order); } static BSON_INLINE int64_t mcommon_atomic_int64_compare_exchange_weak (int64_t volatile *val, int64_t expect_value, int64_t new_value, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int64_compare_exchange_weak (val, expect_value, new_value, order); } #endif #if defined(MCOMMON_EMULATE_INT32) static BSON_INLINE int32_t mcommon_atomic_int32_fetch (const int32_t volatile *val, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int32_fetch_add ((int32_t volatile *) val, 0, order); } static BSON_INLINE int32_t mcommon_atomic_int32_fetch_add (int32_t volatile *val, int32_t v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int32_fetch_add (val, v, order); } static BSON_INLINE int32_t mcommon_atomic_int32_fetch_sub (int32_t volatile *val, int32_t v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int32_fetch_add (val, -v, order); } static BSON_INLINE int32_t mcommon_atomic_int32_exchange (int32_t volatile *val, int32_t v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int32_exchange (val, v, order); } static BSON_INLINE int32_t mcommon_atomic_int32_compare_exchange_strong (int32_t volatile *val, int32_t expect_value, int32_t new_value, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int32_compare_exchange_strong (val, expect_value, new_value, order); } static BSON_INLINE int32_t mcommon_atomic_int32_compare_exchange_weak (int32_t volatile *val, int32_t expect_value, int32_t new_value, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int32_compare_exchange_weak (val, expect_value, new_value, order); } #endif /* MCOMMON_EMULATE_INT32 */ #if defined(MCOMMON_EMULATE_INT) static BSON_INLINE int mcommon_atomic_int_fetch (const int volatile *val, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int_fetch_add ((int volatile *) val, 0, order); } static BSON_INLINE int mcommon_atomic_int_fetch_add (int volatile *val, int v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int_fetch_add (val, v, order); } static BSON_INLINE int mcommon_atomic_int_fetch_sub (int volatile *val, int v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int_fetch_add (val, -v, order); } static BSON_INLINE int mcommon_atomic_int_exchange (int volatile *val, int v, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int_exchange (val, v, order); } static BSON_INLINE int mcommon_atomic_int_compare_exchange_strong (int volatile *val, int expect_value, int new_value, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int_compare_exchange_strong (val, expect_value, new_value, order); } static BSON_INLINE int mcommon_atomic_int_compare_exchange_weak (int volatile *val, int expect_value, int new_value, enum mcommon_memory_order order) { return _mcommon_emul_atomic_int_compare_exchange_weak (val, expect_value, new_value, order); } #endif /* MCOMMON_EMULATE_INT */ static BSON_INLINE void * mcommon_atomic_ptr_exchange (void *volatile *ptr, void *new_value, enum mcommon_memory_order ord) { #if defined(MCOMMON_EMULATE_PTR) return _mcommon_emul_atomic_ptr_exchange (ptr, new_value, ord); #elif defined(MCOMMON_USE_LEGACY_GCC_ATOMICS) /* The older __sync_val_compare_and_swap also takes oldval */ DEF_ATOMIC_OP (_InterlockedExchangePointer, , __sync_val_compare_and_swap, ord, ptr, *ptr, new_value); #else DEF_ATOMIC_OP (_InterlockedExchangePointer, __atomic_exchange_n, , ord, ptr, new_value); #endif } static BSON_INLINE void * mcommon_atomic_ptr_compare_exchange_strong (void *volatile *ptr, void *expect, void *new_value, enum mcommon_memory_order ord) { switch (ord) { case mcommon_memory_order_release: case mcommon_memory_order_acq_rel: case mcommon_memory_order_seq_cst: DEF_ATOMIC_CMPEXCH_STRONG (Pointer, , __ATOMIC_SEQ_CST, ptr, expect, new_value); return expect; case mcommon_memory_order_relaxed: DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, ptr, expect, new_value); return expect; case mcommon_memory_order_consume: DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, ptr, expect, new_value); return expect; case mcommon_memory_order_acquire: DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, ptr, expect, new_value); return expect; default: BSON_UNREACHABLE ("Invalid mcommon_memory_order value"); } } static BSON_INLINE void * mcommon_atomic_ptr_compare_exchange_weak (void *volatile *ptr, void *expect, void *new_value, enum mcommon_memory_order ord) { switch (ord) { case mcommon_memory_order_release: case mcommon_memory_order_acq_rel: case mcommon_memory_order_seq_cst: DEF_ATOMIC_CMPEXCH_WEAK (Pointer, , __ATOMIC_SEQ_CST, ptr, expect, new_value); return expect; case mcommon_memory_order_relaxed: DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, ptr, expect, new_value); return expect; case mcommon_memory_order_consume: DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, ptr, expect, new_value); return expect; case mcommon_memory_order_acquire: DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, ptr, expect, new_value); return expect; default: BSON_UNREACHABLE ("Invalid mcommon_memory_order value"); } } static BSON_INLINE void * mcommon_atomic_ptr_fetch (void *volatile const *ptr, enum mcommon_memory_order ord) { return mcommon_atomic_ptr_compare_exchange_strong ((void *volatile *) ptr, NULL, NULL, ord); } #undef DECL_ATOMIC_STDINT #undef DECL_ATOMIC_INTEGRAL #undef DEF_ATOMIC_OP #undef DEF_ATOMIC_CMPEXCH_STRONG #undef DEF_ATOMIC_CMPEXCH_WEAK #undef MSVC_MEMORDER_SUFFIX /** * @brief Generate a full-fence memory barrier at the call site. */ static BSON_INLINE void mcommon_atomic_thread_fence (void) { BSON_IF_MSVC (MemoryBarrier ();) BSON_IF_GNU_LIKE (__sync_synchronize ();) MCOMMON_IF_GNU_LEGACY_ATOMICS (__sync_synchronize ();) } #ifdef MCOMMON_USE_LEGACY_GCC_ATOMICS #undef BSON_IF_GNU_LIKE #define BSON_IF_GNU_LIKE(...) __VA_ARGS__ #endif #undef MCOMMON_IF_GNU_LEGACY_ATOMICS #undef MCOMMON_USE_LEGACY_GCC_ATOMICS #undef MCOMMON_EMULATE_PTR #undef MCOMMON_EMULATE_INT32 #undef MCOMMON_EMULATE_INT #endif /* MONGO_C_DRIVER_COMMON_ATOMIC_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-atomic.c0000644000175100001660000001453514760300420020461 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef BSON_OS_UNIX /* For sched_yield() */ #include #endif void mcommon_thrd_yield (void) { BSON_IF_WINDOWS (SwitchToThread ();) BSON_IF_POSIX (sched_yield ();) } /** * Some platforms do not support compiler intrinsics for atomic operations. * We emulate that here using a spin lock and regular arithmetic operations */ static int8_t gEmulAtomicLock = 0; static void _lock_emul_atomic (void) { int i; if (mcommon_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, mcommon_memory_order_acquire) == 0) { /* Successfully took the spinlock */ return; } /* Failed. Try taking ten more times, then begin sleeping. */ for (i = 0; i < 10; ++i) { if (mcommon_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, mcommon_memory_order_acquire) == 0) { /* Succeeded in taking the lock */ return; } } /* Still don't have the lock. Spin and yield */ while (mcommon_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, mcommon_memory_order_acquire) != 0) { mcommon_thrd_yield (); } } static void _unlock_emul_atomic (void) { int64_t rv = mcommon_atomic_int8_exchange (&gEmulAtomicLock, 0, mcommon_memory_order_release); BSON_ASSERT (rv == 1 && "Released atomic lock while not holding it"); } int64_t _mcommon_emul_atomic_int64_fetch_add (volatile int64_t *p, int64_t n, enum mcommon_memory_order _unused) { int64_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p += n; _unlock_emul_atomic (); return ret; } int64_t _mcommon_emul_atomic_int64_exchange (volatile int64_t *p, int64_t n, enum mcommon_memory_order _unused) { int64_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p = n; _unlock_emul_atomic (); return ret; } int64_t _mcommon_emul_atomic_int64_compare_exchange_strong (volatile int64_t *p, int64_t expect_value, int64_t new_value, enum mcommon_memory_order _unused) { int64_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; if (ret == expect_value) { *p = new_value; } _unlock_emul_atomic (); return ret; } int64_t _mcommon_emul_atomic_int64_compare_exchange_weak (volatile int64_t *p, int64_t expect_value, int64_t new_value, enum mcommon_memory_order order) { /* We're emulating. We can't do a weak version. */ return _mcommon_emul_atomic_int64_compare_exchange_strong (p, expect_value, new_value, order); } int32_t _mcommon_emul_atomic_int32_fetch_add (volatile int32_t *p, int32_t n, enum mcommon_memory_order _unused) { int32_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p += n; _unlock_emul_atomic (); return ret; } int32_t _mcommon_emul_atomic_int32_exchange (volatile int32_t *p, int32_t n, enum mcommon_memory_order _unused) { int32_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p = n; _unlock_emul_atomic (); return ret; } int32_t _mcommon_emul_atomic_int32_compare_exchange_strong (volatile int32_t *p, int32_t expect_value, int32_t new_value, enum mcommon_memory_order _unused) { int32_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; if (ret == expect_value) { *p = new_value; } _unlock_emul_atomic (); return ret; } int32_t _mcommon_emul_atomic_int32_compare_exchange_weak (volatile int32_t *p, int32_t expect_value, int32_t new_value, enum mcommon_memory_order order) { /* We're emulating. We can't do a weak version. */ return _mcommon_emul_atomic_int32_compare_exchange_strong (p, expect_value, new_value, order); } int _mcommon_emul_atomic_int_fetch_add (volatile int *p, int n, enum mcommon_memory_order _unused) { int ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p += n; _unlock_emul_atomic (); return ret; } int _mcommon_emul_atomic_int_exchange (volatile int *p, int n, enum mcommon_memory_order _unused) { int ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p = n; _unlock_emul_atomic (); return ret; } int _mcommon_emul_atomic_int_compare_exchange_strong (volatile int *p, int expect_value, int new_value, enum mcommon_memory_order _unused) { int ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; if (ret == expect_value) { *p = new_value; } _unlock_emul_atomic (); return ret; } int _mcommon_emul_atomic_int_compare_exchange_weak (volatile int *p, int expect_value, int new_value, enum mcommon_memory_order order) { /* We're emulating. We can't do a weak version. */ return _mcommon_emul_atomic_int_compare_exchange_strong (p, expect_value, new_value, order); } void * _mcommon_emul_atomic_ptr_exchange (void *volatile *p, void *n, enum mcommon_memory_order _unused) { void *ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p = n; _unlock_emul_atomic (); return ret; } mongodb-1.21.0/src/libmongoc/src/common/src/common-b64-private.h0000644000175100001660000000441614760300420021252 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_B64_PRIVATE_H #define MONGO_C_DRIVER_COMMON_B64_PRIVATE_H #include #define mcommon_b64_ntop_calculate_target_size COMMON_NAME (b64_ntop_calculate_target_size) #define mcommon_b64_pton_calculate_target_size COMMON_NAME (b64_pton_calculate_target_size) #define mcommon_b64_ntop COMMON_NAME (b64_ntop) #define mcommon_b64_pton COMMON_NAME (b64_pton) /** * When encoding from "network" (raw data) to "presentation" (base64 encoded). * Includes the trailing null byte. */ size_t mcommon_b64_ntop_calculate_target_size (size_t raw_size); /* When encoding from "presentation" (base64 encoded) to "network" (raw data). * This may be an overestimate if the base64 data includes spaces. For a more * accurate size, call b64_pton (src, NULL, 0), which will read the src * data and return an exact size. */ size_t mcommon_b64_pton_calculate_target_size (size_t base64_encoded_size); /* Returns the number of bytes written (excluding NULL byte) to target on * success or -1 on error. Adds a trailing NULL byte. * Encodes from "network" (raw data) to "presentation" (base64 encoded), * hence the obscure name "ntop". */ int mcommon_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize); /** If target is not NULL, the number of bytes written to target on success or * -1 on error. If target is NULL, returns the exact number of bytes that would * be written to target on decoding. Encodes from "presentation" (base64 * encoded) to "network" (raw data), hence the obscure name "pton". */ int mcommon_b64_pton (char const *src, uint8_t *target, size_t targsize); #endif /* MONGO_C_DRIVER_COMMON_B64_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-b64.c0000644000175100001660000004524614760300420017603 0ustar /* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #define Assert(Cond) \ if (!(Cond)) \ abort () static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) * The following encoding technique is taken from RFC 1521 by Borenstein * and Freed. It is reproduced here in a slightly edited form for * convenience. * * A 65-character subset of US-ASCII is used, enabling 6 bits to be * represented per printable character. (The extra 65th character, "=", * is used to signify a special processing function.) * * The encoding process represents 24-bit groups of input bits as output * strings of 4 encoded characters. Proceeding from left to right, a * 24-bit input group is formed by concatenating 3 8-bit input groups. * These 24 bits are then treated as 4 concatenated 6-bit groups, each * of which is translated into a single digit in the base64 alphabet. * * Each 6-bit group is used as an index into an array of 64 printable * characters. The character referenced by the index is placed in the * output string. * * Table 1: The Base64 Alphabet * * Value Encoding Value Encoding Value Encoding Value Encoding * 0 A 17 R 34 i 51 z * 1 B 18 S 35 j 52 0 * 2 C 19 T 36 k 53 1 * 3 D 20 U 37 l 54 2 * 4 E 21 V 38 m 55 3 * 5 F 22 W 39 n 56 4 * 6 G 23 X 40 o 57 5 * 7 H 24 Y 41 p 58 6 * 8 I 25 Z 42 q 59 7 * 9 J 26 a 43 r 60 8 * 10 K 27 b 44 s 61 9 * 11 L 28 c 45 t 62 + * 12 M 29 d 46 u 63 / * 13 N 30 e 47 v * 14 O 31 f 48 w (pad) = * 15 P 32 g 49 x * 16 Q 33 h 50 y * * Special processing is performed if fewer than 24 bits are available * at the end of the data being encoded. A full encoding quantum is * always completed at the end of a quantity. When fewer than 24 input * bits are available in an input group, zero bits are added (on the * right) to form an integral number of 6-bit groups. Padding at the * end of the data is performed using the '=' character. * * Since all base64 input is an integral number of octets, only the * following cases can arise: * * (1) the final quantum of encoding input is an integral * multiple of 24 bits; here, the final unit of encoded * output will be an integral multiple of 4 characters * with no "=" padding, * (2) the final quantum of encoding input is exactly 8 bits; * here, the final unit of encoded output will be two * characters followed by two "=" padding characters, or * (3) the final quantum of encoding input is exactly 16 bits; * here, the final unit of encoded output will be three * characters followed by one "=" padding character. */ int mcommon_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; size_t i; if (!target) { return -1; } while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; Assert (output[0] < 64); Assert (output[1] < 64); Assert (output[2] < 64); Assert (output[3] < 64); if (datalength + 4 > targsize) { return -1; } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) { input[i] = *src++; } output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); Assert (output[0] < 64); Assert (output[1] < 64); Assert (output[2] < 64); if (datalength + 4 > targsize) { return -1; } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) { target[datalength++] = Pad64; } else { target[datalength++] = Base64[output[2]]; } target[datalength++] = Pad64; } if (datalength >= targsize) { return -1; } target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (int) datalength; } /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ static uint8_t mongoc_b64rmap[256]; static const uint8_t mongoc_b64rmap_special = 0xf0; static const uint8_t mongoc_b64rmap_end = 0xfd; static const uint8_t mongoc_b64rmap_space = 0xfe; static const uint8_t mongoc_b64rmap_invalid = 0xff; /* initializing the reverse map isn't thread safe, do it in pthread_once */ #if defined(BSON_OS_UNIX) #include #define mongoc_common_once_t pthread_once_t #define mongoc_common_once pthread_once #define MONGOC_COMMON_ONCE_FUN(n) void n (void) #define MONGOC_COMMON_ONCE_RETURN return #define MONGOC_COMMON_ONCE_INIT PTHREAD_ONCE_INIT #else #define mongoc_common_once_t INIT_ONCE #define MONGOC_COMMON_ONCE_INIT INIT_ONCE_STATIC_INIT #define mongoc_common_once(o, c) InitOnceExecuteOnce (o, c, NULL, NULL) #define MONGOC_COMMON_ONCE_FUN(n) BOOL CALLBACK n (PINIT_ONCE _ignored_a, PVOID _ignored_b, PVOID *_ignored_c) #define MONGOC_COMMON_ONCE_RETURN return true #endif static MONGOC_COMMON_ONCE_FUN (bson_b64_initialize_rmap) { int i; unsigned char ch; /* Null: end of string, stop parsing */ mongoc_b64rmap[0] = mongoc_b64rmap_end; for (i = 1; i < 256; ++i) { ch = (unsigned char) i; /* Whitespaces */ if (bson_isspace (ch)) mongoc_b64rmap[i] = mongoc_b64rmap_space; /* Padding: stop parsing */ else if (ch == Pad64) mongoc_b64rmap[i] = mongoc_b64rmap_end; /* Non-base64 char */ else mongoc_b64rmap[i] = mongoc_b64rmap_invalid; } /* Fill reverse mapping for base64 chars */ for (i = 0; Base64[i] != '\0'; ++i) mongoc_b64rmap[(uint8_t) Base64[i]] = i; MONGOC_COMMON_ONCE_RETURN; } static int mongoc_b64_pton_do (char const *src, uint8_t *target, size_t targsize) { int tarindex, state; uint8_t ch, ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = mongoc_b64rmap[ch]; if (ofs >= mongoc_b64rmap_special) { /* Ignore whitespaces */ if (ofs == mongoc_b64rmap_space) continue; /* End of base64 characters */ if (ofs == mongoc_b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: if ((size_t) tarindex >= targsize) return (-1); target[tarindex] = ofs << 2; state = 1; break; case 1: if ((size_t) tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 4; target[tarindex + 1] = (ofs & 0x0f) << 4; tarindex++; state = 2; break; case 2: if ((size_t) tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 2; target[tarindex + 1] = (ofs & 0x03) << 6; tarindex++; state = 3; break; case 3: if ((size_t) tarindex >= targsize) return (-1); target[tarindex] |= ofs; tarindex++; state = 0; break; default: abort (); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void) NULL; ch != '\0'; ch = *src++) if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void) NULL; ch != '\0'; ch = *src++) if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target[tarindex] != 0) return (-1); default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } static int mongoc_b64_pton_len (char const *src) { int tarindex, state; uint8_t ch, ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = mongoc_b64rmap[ch]; if (ofs >= mongoc_b64rmap_special) { /* Ignore whitespaces */ if (ofs == mongoc_b64rmap_space) continue; /* End of base64 characters */ if (ofs == mongoc_b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: state = 1; break; case 1: tarindex++; state = 2; break; case 2: tarindex++; state = 3; break; case 3: tarindex++; state = 0; break; default: abort (); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void) NULL; ch != '\0'; ch = *src++) if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void) NULL; ch != '\0'; ch = *src++) if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) return (-1); default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } int mcommon_b64_pton (char const *src, uint8_t *target, size_t targsize) { static mongoc_common_once_t once = MONGOC_COMMON_ONCE_INIT; mongoc_common_once (&once, bson_b64_initialize_rmap); if (!src) { return -1; } if (target) return mongoc_b64_pton_do (src, target, targsize); else return mongoc_b64_pton_len (src); } size_t mcommon_b64_ntop_calculate_target_size (size_t raw_size) { size_t num_bits = raw_size * 8; /* Calculate how many groups of six bits this contains, adding 5 to round up * to the nearest group of 6. */ size_t num_b64_chars = (num_bits + 5) / 6; /* Round to nearest set of four. */ size_t num_b64_chars_with_padding = 4 * ((num_b64_chars + 3) / 4); /* Add one for NULL byte. */ return num_b64_chars_with_padding + 1; } size_t mcommon_b64_pton_calculate_target_size (size_t base64_encoded_size) { /* Without inspecting the data, we don't know how many padding characters * there are. Assuming none, that means each character represents 6 bits of * data. */ size_t num_bits = base64_encoded_size * 6; /* Round down to the nearest group of eight. */ return num_bits / 8; } mongodb-1.21.0/src/libmongoc/src/common/src/common-bits-private.h0000644000175100001660000000233114760300420021612 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_BITS_PRIVATE_H #define MONGO_C_DRIVER_COMMON_BITS_PRIVATE_H #include // Round up to the next power of two uint32_t value. Saturates on overflow. static BSON_INLINE uint32_t mcommon_next_power_of_two_u32 (uint32_t v) { if (v == 0) { return 1; } // https://graphics.stanford.edu/%7Eseander/bithacks.html#RoundUpPowerOf2 v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; if (v == 0) { return UINT32_MAX; } else { return v; } } #endif /* MONGO_C_DRIVER_COMMON_BITS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-bson-dsl-private.h0000644000175100001660000020120614760300420022374 0ustar #include #ifndef MONGO_C_DRIVER_COMMON_BSON_DSL_PRIVATE_H #define MONGO_C_DRIVER_COMMON_BSON_DSL_PRIVATE_H /** * @file common-bson-dsl-private.h * @brief Define a C-preprocessor DSL for working with BSON objects * * This file defines an embedded DSL for working with BSON objects consisely and * correctly. * * For more information about using this DSL, refer to `bson-dsl.md`. */ #include #include enum { /// Toggle this value to enable/disable debug output for all bsonDSL /// operations (printed to stderr). You can also set a constant /// BSON_DSL_DEBUG within the scope of a DSL command to selectively debug /// only the commands within that scope. BSON_DSL_DEBUG = 0 }; #define _bson_thread_local BSON_IF_GNU_LIKE (__thread) BSON_IF_MSVC (__declspec (thread)) #define _bson_comdat \ BSON_IF_WINDOWS (__declspec (selectany)) \ BSON_IF_POSIX (__attribute__ ((weak))) #ifdef __GNUC__ // GCC has a bug handling pragma statements that disable warnings within complex // nested macro expansions. If we're GCC, just disable -Wshadow outright: BSON_IF_GNU_LIKE (_Pragma ("GCC diagnostic ignored \"-Wshadow\"")) #endif #define _bsonDSL_disableWarnings() \ if (1) { \ BSON_IF_GNU_LIKE (_Pragma ("GCC diagnostic push");) \ BSON_IF_GNU_LIKE (_Pragma ("GCC diagnostic ignored \"-Wshadow\"");) \ } else \ ((void) 0) #define _bsonDSL_restoreWarnings() \ if (1) { \ BSON_IF_GNU_LIKE (_Pragma ("GCC diagnostic pop");) \ } else \ ((void) 0) /** * @brief Parse the given BSON document. * * @param doc A bson_t object to walk. (Not a pointer) */ #define bsonParse(Document, ...) \ _bsonDSL_begin ("bsonParse(%s)", _bsonDSL_str (Document)); \ _bsonDSL_disableWarnings (); \ bsonParseError = NULL; \ BSON_MAYBE_UNUSED bool _bvHalt = false; \ BSON_MAYBE_UNUSED const bool _bvContinue = false; \ BSON_MAYBE_UNUSED const bool _bvBreak = false; \ _bsonDSL_eval (_bsonParse ((Document), __VA_ARGS__)); \ _bsonDSL_restoreWarnings (); \ _bsonDSL_end /** * @brief Visit each element of a BSON document */ #define bsonVisitEach(Document, ...) \ _bsonDSL_begin ("bsonVisitEach(%s)", _bsonDSL_str (Document)); \ _bsonDSL_disableWarnings (); \ BSON_MAYBE_UNUSED bool _bvHalt = false; \ _bsonDSL_eval (_bsonVisitEach ((Document), __VA_ARGS__)); \ _bsonDSL_restoreWarnings (); \ _bsonDSL_end #define bsonBuildContext (*_bsonBuildContextThreadLocalPtr) #define bsonVisitContext (*_bsonVisitContextThreadLocalPtr) #define bsonVisitIter (bsonVisitContext.iter) /// Begin any function-like macro by opening a new scope and writing a debug /// message. #define _bsonDSL_begin(Str, ...) \ if (true) { \ _bsonDSLDebug (Str, __VA_ARGS__); \ ++_bson_dsl_indent /// End a function-like macro scope. #define _bsonDSL_end \ --_bson_dsl_indent; \ } \ else ((void) 0) /** * @brief Expands to a call to bson_append_{Kind}, with the three first * arguments filled in by the DSL context variables. */ #define _bsonBuildAppendArgs bsonBuildContext.doc, bsonBuildContext.key, bsonBuildContext.key_len /** * The _bsonDocOperation_XYZ macros handle the top-level bsonBuild() * items, and any nested doc() items, with XYZ being the doc-building * subcommand. */ #define _bsonDocOperation(Command, _ignore, _count) \ if (!bsonBuildError) { \ _bsonDocOperation_##Command; \ if (bsonBuildError) { \ _bsonDSLDebug ("Stopping doc() due to bsonBuildError: [%s]", bsonBuildError); \ } \ } #define _bsonValueOperation(P) _bsonValueOperation_##P /// key-value pair with explicit key length #define _bsonDocOperation_kvl(String, Len, Element) \ _bsonDSL_begin ("\"%s\" => [%s]", String, _bsonDSL_strElide (30, Element)); \ const char *_bbString = (String); \ const uint64_t length = (Len); \ if (mcommon_in_range_unsigned (int, length)) { \ _bbCtx.key = _bbString; \ _bbCtx.key_len = (int) length; \ _bsonValueOperation (Element); \ } else { \ bsonBuildError = "Out-of-range key string length value"; \ } \ _bsonDSL_end /// Key-value pair with a C-string #define _bsonDocOperation_kv(String, Element) _bsonDocOperation_kvl ((String), strlen ((String)), Element) /// Execute arbitrary code #define _bsonDocOperation_do(...) \ _bsonDSL_begin ("do(%s)", _bsonDSL_strElide (30, __VA_ARGS__)); \ do { \ __VA_ARGS__; \ } while (0); \ if (bsonBuildError) { \ _bsonDSLDebug ("do() set bsonBuildError: [%s]", bsonBuildError); \ } \ _bsonDSL_end /// We must defer expansion of the nested doc() to allow "recursive" evaluation #define _bsonValueOperation_doc _bsonValueOperationDeferred_doc _bsonDSL_nothing () #define _bsonArrayOperation_doc(...) _bsonArrayAppendValue (doc (__VA_ARGS__)) #define _bsonValueOperationDeferred_doc(...) \ _bsonDSL_begin ("doc(%s)", _bsonDSL_strElide (30, __VA_ARGS__)); \ /* Write to this variable as the child: */ \ bson_t _bbChildDoc = BSON_INITIALIZER; \ if (!bson_append_document_begin (_bsonBuildAppendArgs, &_bbChildDoc)) { \ bsonBuildError = "Error while initializing child document: " _bsonDSL_str (__VA_ARGS__); \ } else { \ _bsonBuildAppend (_bbChildDoc, __VA_ARGS__); \ if (!bsonBuildError) { \ if (!bson_append_document_end (bsonBuildContext.doc, &_bbChildDoc)) { \ bsonBuildError = "Error while finalizing document: " _bsonDSL_str (__VA_ARGS__); \ } \ } \ } \ _bsonDSL_end /// We must defer expansion of the nested array() to allow "recursive" /// evaluation #define _bsonValueOperation_array _bsonValueOperationDeferred_array _bsonDSL_nothing () #define _bsonArrayOperation_array(...) _bsonArrayAppendValue (array (__VA_ARGS__)) #define _bsonValueOperationDeferred_array(...) \ _bsonDSL_begin ("array(%s)", _bsonDSL_strElide (30, __VA_ARGS__)); \ /* Write to this variable as the child array: */ \ bson_t _bbArray = BSON_INITIALIZER; \ if (!bson_append_array_begin (_bsonBuildAppendArgs, &_bbArray)) { \ bsonBuildError = "Error while initializing child array: " _bsonDSL_str (__VA_ARGS__); \ } else { \ _bsonBuildArray (_bbArray, __VA_ARGS__); \ if (!bsonBuildError) { \ if (!bson_append_array_end (bsonBuildContext.doc, &_bbArray)) { \ bsonBuildError = "Error while finalizing child array: " _bsonDSL_str (__VA_ARGS__); \ } \ } else { \ _bsonDSLDebug ("Got bsonBuildError: [%s]", bsonBuildError); \ } \ } \ _bsonDSL_end /// Append a UTF-8 string with an explicit length #define _bsonValueOperation_utf8_w_len(String, Len) \ if (!bson_append_utf8 (_bsonBuildAppendArgs, (String), (int) (Len))) { \ bsonBuildError = "Error while appending utf8 string: " _bsonDSL_str (String); \ } else \ ((void) 0) #define _bsonArrayOperation_utf8_w_len(X) _bsonArrayAppendValue (utf8_w_len (X)) /// Append a "cstr" as UTF-8 #define _bsonValueOperation_cstr(String) _bsonValueOperation_utf8_w_len ((String), strlen (String)) #define _bsonArrayOperation_cstr(X) _bsonArrayAppendValue (cstr (X)) /// Append an int32 #define _bsonValueOperation_int32(Integer) \ if (!bson_append_int32 (_bsonBuildAppendArgs, (Integer))) { \ bsonBuildError = "Error while appending int32(" _bsonDSL_str (Integer) ")"; \ } else \ ((void) 0) #define _bsonArrayOperation_int32(X) _bsonArrayAppendValue (int32 (X)) /// Append an int64 #define _bsonValueOperation_int64(Integer) \ if (!bson_append_int64 (_bsonBuildAppendArgs, (Integer))) { \ bsonBuildError = "Error while appending int64(" _bsonDSL_str (Integer) ")"; \ } else \ ((void) 0) #define _bsonArrayOperation_int64(X) _bsonArrayAppendValue (int64 (X)) /// Append the value referenced by a given iterator #define _bsonValueOperation_iterValue(Iter) \ if (!bson_append_iter (_bsonBuildAppendArgs, &(Iter))) { \ bsonBuildError = "Error while appending iterValue(" _bsonDSL_str (Iter) ")"; \ } else \ ((void) 0) #define _bsonArrayOperation_iterValue(X) _bsonArrayAppendValue (iterValue (X)) /// Append the BSON document referenced by the given pointer #define _bsonValueOperation_bson(Doc) \ if (!bson_append_document (_bsonBuildAppendArgs, &(Doc))) { \ bsonBuildError = "Error while appending subdocument: bson(" _bsonDSL_str (Doc) ")"; \ } else \ ((void) 0) #define _bsonArrayOperation_bson(X) _bsonArrayAppendValue (bson (X)) /// Append the BSON document referenced by the given pointer as an array #define _bsonValueOperation_bsonArray(Arr) \ if (!bson_append_array (_bsonBuildAppendArgs, &(Arr))) { \ bsonBuildError = "Error while appending subdocument array: " \ "bsonArray(" _bsonDSL_str (Arr) ")"; \ } else \ ((void) 0) #define _bsonArrayOperation_bsonArray(X) _bsonArrayAppendValue (bsonArray (X)) #define _bsonValueOperation_bool(b) \ if (!bson_append_bool (_bsonBuildAppendArgs, (b))) { \ bsonBuildError = "Error while appending bool(" _bsonDSL_str (b) ")"; \ } else \ ((void) 0) #define _bsonArrayOperation_boolean(X) _bsonArrayAppendValue (boolean (X)) #define _bsonValueOperation_boolean(b) _bsonValueOperation_bool (b) #define _bsonValueOperation_oid(o) \ if (!bson_append_oid (_bsonBuildAppendArgs, (o))) { \ bsonBuildError = "Error while appending oid(" _bsonDSL_str (o) ")"; \ } else \ ((void) 0) #define _bsonArrayOperation_oid(X) _bsonArrayAppendValue (oid (X)) #define _bsonValueOperation_null \ if (!bson_append_null (_bsonBuildAppendArgs)) { \ bsonBuildError = "Error while appending a null"; \ } else \ ((void) 0) #define _bsonArrayOperation_null _bsonValueOperation (null) #define _bsonArrayOperation_value(X) _bsonArrayAppendValue (value (X)) #define _bsonValueOperation_value(Value) \ _bsonDSL_begin ("value(%s)", _bsonDSL_str (Value)); \ if (!bson_append_value (_bsonBuildAppendArgs, &(Value))) { \ bsonBuildError = "Error while appending value(" _bsonDSL_str (Value) ")"; \ } \ _bsonDSL_end /// Insert the given BSON document into the parent document in-place #define _bsonDocOperation_insert(OtherBSON, Pred) \ _bsonDSL_begin ("Insert other document: [%s]", _bsonDSL_str (OtherBSON)); \ const bool _bvHalt = false; /* Required for _bsonVisitEach() */ \ _bsonVisitEach (OtherBSON, if (Pred, then (do (_bsonDocOperation_iterElement (bsonVisitIter))))); \ _bsonDSL_end #define _bsonDocOperation_insertFromIter(Iter, Pred) \ _bsonDSL_begin ("Insert document from iterator: [%s]", _bsonDSL_str (Iter)); \ bson_t _bbDocFromIter = _bson_dsl_iter_as_doc (&(Iter)); \ if (_bbDocFromIter.len == 0) { \ _bsonDSLDebug ("NOTE: Skipping insert of non-document value from iterator"); \ } else { \ _bsonDocOperation_insert (_bbDocFromIter, Pred); \ } \ _bsonDSL_end #define _bsonDocOperation_iterElement(Iter) \ _bsonDSL_begin ("Insert element from bson_iter_t [%s]", _bsonDSL_str (Iter)); \ bson_iter_t _bbIter = (Iter); \ _bsonDocOperation_kvl (bson_iter_key (&_bbIter), bson_iter_key_len (&_bbIter), iterValue (_bbIter)); \ _bsonDSL_end /// Insert the given BSON document into the parent array. Keys of the given /// document are discarded and it is treated as an array of values. #define _bsonArrayOperation_insert(OtherArr, Pred) \ _bsonDSL_begin ("Insert other array: [%s]", _bsonDSL_str (OtherArr)); \ _bsonVisitEach (OtherArr, if (Pred, then (do (_bsonArrayOperation_iterValue (bsonVisitIter))))); \ _bsonDSL_end #define _bsonArrayAppendValue(ValueOperation) \ _bsonDSL_begin ("[%d] => [%s]", (int) bsonBuildContext.index, _bsonDSL_strElide (30, ValueOperation)); \ /* Set the doc key to the array index as a string: */ \ _bsonBuild_setKeyToArrayIndex (bsonBuildContext.index); \ /* Append a value: */ \ _bsonValueOperation_##ValueOperation; \ /* Increment the array index: */ \ ++_bbCtx.index; \ _bsonDSL_end #define _bsonDocOperationIfThen_then _bsonBuildAppendWithCurrentContext #define _bsonDocOperationIfElse_else _bsonBuildAppendWithCurrentContext #define _bsonDocOperationIfThenElse(Condition, Then, Else) \ if ((Condition)) { \ _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ _bsonDocOperationIfThen_##Then; \ } else { \ _bsonDSLDebug ("Taking FALSE branch: [%s]", _bsonDSL_str (Else)); \ _bsonDocOperationIfElse_##Else; \ } #define _bsonDocOperationIfThen(Condition, Then) \ if ((Condition)) { \ _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ _bsonDocOperationIfThen_##Then; \ } #define _bsonDocOperation_if(Condition, ...) \ _bsonDSL_begin ("Conditional append on [%s]", _bsonDSL_str (Condition)); \ /* Pick a sub-macro depending on if there are one or two args */ \ _bsonDSL_ifElse (_bsonDSL_hasComma (__VA_ARGS__), _bsonDocOperationIfThenElse, _bsonDocOperationIfThen) ( \ Condition, __VA_ARGS__); \ _bsonDSL_end #define _bsonArrayOperationIfThen_then _bsonBuildArrayWithCurrentContext #define _bsonArrayOperationIfElse_else _bsonBuildArrayWithCurrentContext #define _bsonArrayOperationIfThenElse(Condition, Then, Else) \ if ((Condition)) { \ _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ _bsonArrayOperationIfThen_##Then; \ } else { \ _bsonDSLDebug ("Taking FALSE branch: [%s]", _bsonDSL_str (Else)); \ _bsonArrayOperationIfElse_##Else; \ } #define _bsonArrayOperationIfThen(Condition, Then) \ if ((Condition)) { \ _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ _bsonArrayOperationIfThen_##Then; \ } #define _bsonArrayOperation_if(Condition, ...) \ _bsonDSL_begin ("Conditional value on [%s]", _bsonDSL_str (Condition)); \ /* Pick a sub-macro depending on if there are one or two args */ \ _bsonDSL_ifElse (_bsonDSL_hasComma (__VA_ARGS__), _bsonArrayOperationIfThenElse, _bsonArrayOperationIfThen) ( \ Condition, __VA_ARGS__); \ _bsonDSL_end #define _bsonValueOperationIf_then(X) _bsonValueOperation_##X #define _bsonValueOperationIf_else(X) _bsonValueOperation_##X #define _bsonValueOperation_if(Condition, Then, Else) \ if ((Condition)) { \ _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ _bsonValueOperationIf_##Then; \ } else { \ _bsonDSLDebug ("Taking FALSE branch: [%s]", _bsonDSL_str (Else)); \ _bsonValueOperationIf_##Else; \ } #define _bsonBuild_setKeyToArrayIndex(Idx) \ _bbCtx.key_len = bson_snprintf (_bbCtx.index_key_str, sizeof _bbCtx.index_key_str, "%d", (int) _bbCtx.index); \ _bbCtx.key = _bbCtx.index_key_str /// Handle an element of array() #define _bsonArrayOperation(Element, _nil, _count) \ if (!bsonBuildError) { \ _bsonArrayOperation_##Element; \ } #define _bsonBuildAppendWithCurrentContext(...) _bsonDSL_mapMacro (_bsonDocOperation, ~, __VA_ARGS__) #define _bsonBuildArrayWithCurrentContext(...) _bsonDSL_mapMacro (_bsonArrayOperation, ~, __VA_ARGS__) #define _bsonDSL_Type_double BSON_TYPE_DOUBLE #define _bsonDSL_Type_utf8 BSON_TYPE_UTF8 #define _bsonDSL_Type_doc BSON_TYPE_DOCUMENT #define _bsonDSL_Type_array BSON_TYPE_ARRAY #define _bsonDSL_Type_binary BSON_TYPE_BINARY #define _bsonDSL_Type_undefined BSON_TYPE_UNDEFINED #define _bsonDSL_Type_oid BSON_TYPE_OID // Use `boolean`, not `bool`. `bool` may be defined as a macro to `_Bool` or `int`: #define _bsonDSL_Type_boolean BSON_TYPE_BOOL #define _bsonDSL_Type_date_time BSON_TYPE_DATE_TIME #define _bsonDSL_Type_null BSON_TYPE_NULL #define _bsonDSL_Type_regex BSON_TYPE_REGEX #define _bsonDSL_Type_dbpointer BSON_TYPE_DBPOINTER #define _bsonDSL_Type_code BSON_TYPE_CODE #define _bsonDSL_Type_codewscope BSON_TYPE_CODEWSCOPE #define _bsonDSL_Type_int32 BSON_TYPE_INT32 #define _bsonDSL_Type_timestamp BSON_TYPE_TIMESTAMP #define _bsonDSL_Type_int64 BSON_TYPE_INT64 #define _bsonDSL_Type_decimal128 BSON_TYPE_DECIMAL128 #define _bsonDSL_Type_string __NOTE__No_type_named__string__did_you_mean__utf8 #define _bsonVisitOperation_halt _bvHalt = true #define _bsonVisitOperation_if(Predicate, ...) \ _bsonDSL_begin ("if(%s)", _bsonDSL_str (Predicate)); \ _bsonDSL_ifElse (_bsonDSL_hasComma (__VA_ARGS__), _bsonVisit_ifThenElse, _bsonVisit_ifThen) (Predicate, \ __VA_ARGS__); \ _bsonDSL_end #define _bsonVisit_ifThenElse(Predicate, Then, Else) \ if (bsonPredicate (Predicate)) { \ _bsonDSLDebug ("then:"); \ _bsonVisit_ifThen_##Then; \ } else { \ _bsonDSLDebug ("else:"); \ _bsonVisit_ifElse_##Else; \ } #define _bsonVisit_ifThen(Predicate, Then) \ if (bsonPredicate (Predicate)) { \ _bsonDSLDebug ("then:"); \ _bsonVisit_ifThen_##Then; \ } else { \ _bsonDSLDebug ("[else nothing]"); \ } #define _bsonVisit_ifThen_then _bsonVisit_applyOps #define _bsonVisit_ifElse_else _bsonVisit_applyOps #define _bsonVisitOperation_storeBool(Dest) \ _bsonDSL_begin ("storeBool(%s)", _bsonDSL_str (Dest)); \ (Dest) = bson_iter_as_bool (&bsonVisitIter); \ _bsonDSL_end #define _bsonVisitOperation_storeStrRef(Dest) \ _bsonDSL_begin ("storeStrRef(%s)", _bsonDSL_str (Dest)); \ (Dest) = bson_iter_utf8 (&bsonVisitIter, NULL); \ _bsonDSL_end #define _bsonVisitOperation_storeStrDup(Dest) \ _bsonDSL_begin ("storeStrDup(%s)", _bsonDSL_str (Dest)); \ (Dest) = bson_iter_dup_utf8 (&bsonVisitIter, NULL); \ _bsonDSL_end #define _bsonVisitOperation_storeDocDup(Dest) \ _bsonDSL_begin ("storeDocDup(%s)", _bsonDSL_str (Dest)); \ bson_t _bvDoc = BSON_INITIALIZER; \ _bson_dsl_iter_as_doc (&_bvDoc, &bsonVisitIter); \ if (_bvDoc.len) { \ bson_copy_to (&_bvDoc, &(Dest)); \ } \ _bsonDSL_end #define _bsonVisitOperation_storeDocRef(Dest) \ _bsonDSL_begin ("storeDocRef(%s)", _bsonDSL_str (Dest)); \ _bson_dsl_iter_as_doc (&(Dest), &bsonVisitIter); \ _bsonDSL_end #define _bsonVisitOperation_storeDocDupPtr(Dest) \ _bsonDSL_begin ("storeDocDupPtr(%s)", _bsonDSL_str (Dest)); \ bson_t _bvDoc = BSON_INITIALIZER; \ _bson_dsl_iter_as_doc (&_bvDoc, &bsonVisitIter); \ if (_bvDoc.len) { \ (Dest) = bson_copy (&_bvDoc); \ } \ _bsonDSL_end #define _bsonVisitOperation_storeInt32(Dest) \ _bsonDSL_begin ("storeInt32(%s)", _bsonDSL_str (Dest)); \ (Dest) = bson_iter_int32 (&bsonVisitIter); \ _bsonDSL_end #define _bsonVisitOperation_do(...) \ _bsonDSL_begin ("do: %s", _bsonDSL_strElide (30, __VA_ARGS__)); \ do { \ __VA_ARGS__; \ } while (0); \ _bsonDSL_end #define _bsonVisitOperation_appendTo(BSON) \ _bsonDSL_begin ("appendTo(%s)", _bsonDSL_str (BSON)); \ if (!bson_append_iter ( \ &(BSON), bson_iter_key (&bsonVisitIter), (int) bson_iter_key_len (&bsonVisitIter), &bsonVisitIter)) { \ bsonParseError = "Error in appendTo(" _bsonDSL_str (BSON) ")"; \ } \ _bsonDSL_end #define _bsonVisitCase_when(Pred, ...) \ _bsonDSL_begin ("when: [%s]", _bsonDSL_str (Pred)); \ _bvCaseMatched = _bsonPredicate (Pred); \ if (_bvCaseMatched) { \ _bsonVisit_applyOps (__VA_ARGS__); \ } \ _bsonDSL_end #define _bsonVisitCase_else(...) \ _bsonDSL_begin ("else:%s", ""); \ _bvCaseMatched = true; \ _bsonVisit_applyOps (__VA_ARGS__); \ _bsonDSL_end #define _bsonVisitCase(Pair, _nil, _count) \ if (!_bvCaseMatched) { \ _bsonVisitCase_##Pair; \ } else \ ((void) 0); #define _bsonVisitOperation_case(...) \ _bsonDSL_begin ("case:%s", ""); \ BSON_MAYBE_UNUSED bool _bvCaseMatched = false; \ _bsonDSL_mapMacro (_bsonVisitCase, ~, __VA_ARGS__); \ _bsonDSL_end #define _bsonVisitOperation_append _bsonVisitOneApplyDeferred_append _bsonDSL_nothing () #define _bsonVisitOneApplyDeferred_append(Doc, ...) \ _bsonDSL_begin ("append to [%s] : %s", _bsonDSL_str (Doc), _bsonDSL_strElide (30, __VA_ARGS__)); \ _bsonBuildAppend (Doc, __VA_ARGS__); \ if (bsonBuildError) { \ bsonParseError = bsonBuildError; \ } \ _bsonDSL_end #define _bsonVisitEach(Doc, ...) \ _bsonDSL_begin ("visitEach(%s)", _bsonDSL_str (Doc)); \ do { \ /* Reset the context */ \ struct _bsonVisitContext_t _bvCtx = { \ .doc = &(Doc), \ .parent = _bsonVisitContextThreadLocalPtr, \ .index = 0, \ }; \ _bsonVisitContextThreadLocalPtr = &_bvCtx; \ bsonParseError = NULL; \ /* Iterate over each element of the document */ \ if (!bson_iter_init (&_bvCtx.iter, &(Doc))) { \ bsonParseError = "Invalid BSON data [a]"; \ } \ BSON_MAYBE_UNUSED bool _bvBreak = false; \ BSON_MAYBE_UNUSED bool _bvContinue = false; \ while (bson_iter_next (&_bvCtx.iter) && !_bvHalt && !bsonParseError && !_bvBreak) { \ _bvContinue = false; \ _bsonVisit_applyOps (__VA_ARGS__); \ ++_bvCtx.index; \ } \ if (bsonVisitIter.err_off) { \ bsonParseError = "Invalid BSON data [b]"; \ } \ /* Restore the dsl context */ \ _bsonVisitContextThreadLocalPtr = _bvCtx.parent; \ } while (0); \ _bsonDSL_end #define _bsonVisitOperation_visitEach _bsonVisitOperation_visitEachDeferred _bsonDSL_nothing () #define _bsonVisitOperation_visitEachDeferred(...) \ _bsonDSL_begin ("visitEach:%s", ""); \ do { \ const uint8_t *data; \ uint32_t len; \ bson_type_t typ = bson_iter_type_unsafe (&bsonVisitIter); \ if (typ == BSON_TYPE_ARRAY) \ bson_iter_array (&bsonVisitIter, &len, &data); \ else if (typ == BSON_TYPE_DOCUMENT) \ bson_iter_document (&bsonVisitIter, &len, &data); \ else { \ _bsonDSLDebug ("(Skipping visitEach() of non-array/document value)"); \ break; \ } \ bson_t inner; \ BSON_ASSERT (bson_init_static (&inner, data, len)); \ _bsonVisitEach (inner, __VA_ARGS__); \ } while (0); \ _bsonDSL_end #define _bsonVisitOperation_nop _bsonDSLDebug ("[nop]") #define _bsonVisitOperation_parse(...) \ do { \ const uint8_t *data; \ uint32_t len; \ bson_type_t typ = bson_iter_type (&bsonVisitIter); \ if (typ == BSON_TYPE_ARRAY) \ bson_iter_array (&bsonVisitIter, &len, &data); \ else if (typ == BSON_TYPE_DOCUMENT) \ bson_iter_document (&bsonVisitIter, &len, &data); \ else { \ _bsonDSLDebug ("Ignoring parse() for non-document/array value"); \ break; \ } \ bson_t inner; \ BSON_ASSERT (bson_init_static (&inner, data, len)); \ _bsonParse (inner, __VA_ARGS__); \ } while (0); #define _bsonVisitOperation_continue _bvContinue = true #define _bsonVisitOperation_break _bvBreak = _bvContinue = true #define _bsonVisitOperation_require(Predicate) \ _bsonDSL_begin ("require(%s)", _bsonDSL_str (Predicate)); \ if (!bsonPredicate (Predicate)) { \ bsonParseError = "Element requirement failed: " _bsonDSL_str (Predicate); \ } \ _bsonDSL_end #define _bsonVisitOperation_error(S) bsonParseError = (S) #define _bsonVisitOperation_errorf(S, ...) (bsonParseError = _bson_dsl_errorf (&(S), __VA_ARGS__)) #define _bsonVisitOperation_dupPath(S) \ _bsonDSL_begin ("dupPath(%s)", _bsonDSL_str (S)); \ _bson_dsl_dupPath (&(S)); \ _bsonDSL_end #define _bsonVisit_applyOp(P, _const, _count) \ do { \ if (!_bvContinue && !_bvHalt && !bsonParseError) { \ _bsonVisitOperation_##P; \ } \ } while (0); #define _bsonParse(Doc, ...) \ do { \ BSON_MAYBE_UNUSED const bson_t *_bpDoc = &(Doc); \ /* Keep track of which elements have been visited based on their index*/ \ uint64_t _bpVisitBits_static[4] = {0}; \ BSON_MAYBE_UNUSED uint64_t *_bpVisitBits = _bpVisitBits_static; \ BSON_MAYBE_UNUSED size_t _bpNumVisitBitInts = sizeof _bpVisitBits_static / sizeof (uint64_t); \ BSON_MAYBE_UNUSED bool _bpFoundElement = false; \ _bsonParse_applyOps (__VA_ARGS__); \ /* We may have allocated for visit bits */ \ if (_bpVisitBits != _bpVisitBits_static) { \ bson_free (_bpVisitBits); \ } \ } while (0) #define _bsonParse_applyOps(...) _bsonDSL_mapMacro (_bsonParse_applyOp, ~, __VA_ARGS__) /// Parse one entry referrenced by the context iterator #define _bsonParse_applyOp(P, _nil, Counter) \ do { \ if (!_bvHalt && !bsonParseError) { \ _bsonParseOperation_##P; \ } \ } while (0); #define _bsonParseMarkVisited(Index) \ if (1) { \ const size_t nth_int = Index / 64u; \ const size_t nth_bit = Index % 64u; \ while (nth_int >= _bpNumVisitBitInts) { \ /* Say that five times, fast: */ \ size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ uint64_t *new_visit_bit_ints = bson_malloc0 (sizeof (uint64_t) * new_num_visit_bit_ints); \ memcpy (new_visit_bit_ints, _bpVisitBits, sizeof (uint64_t) * _bpNumVisitBitInts); \ if (_bpVisitBits != _bpVisitBits_static) { \ bson_free (_bpVisitBits); \ } \ _bpVisitBits = new_visit_bit_ints; \ _bpNumVisitBitInts = new_num_visit_bit_ints; \ } \ \ _bpVisitBits[nth_int] |= (UINT64_C (1) << nth_bit); \ } else \ ((void) 0) #define _bsonParseDidVisitNth(Index) _bsonParseDidVisitNth_1 (Index / 64u, Index % 64u) #define _bsonParseDidVisitNth_1(NthInt, NthBit) \ (NthInt < _bpNumVisitBitInts && (_bpVisitBits[NthInt] & (UINT64_C (1) << NthBit))) #define _bsonParseOperation_find(Predicate, ...) \ _bsonDSL_begin ("find(%s)", _bsonDSL_str (Predicate)); \ _bpFoundElement = false; \ _bsonVisitEach ( \ *_bpDoc, \ if (Predicate, \ then (do (_bsonParseMarkVisited (bsonVisitContext.index); _bpFoundElement = true), __VA_ARGS__, break))); \ if (!_bpFoundElement && !bsonParseError) { \ _bsonDSLDebug ("[not found]"); \ } \ _bsonDSL_end #define _bsonParseOperation_require(Predicate, ...) \ _bsonDSL_begin ("require(%s)", _bsonDSL_str (Predicate)); \ _bpFoundElement = false; \ _bsonVisitEach ( \ *_bpDoc, \ if (Predicate, \ then (do (_bsonParseMarkVisited (bsonVisitContext.index); _bpFoundElement = true), __VA_ARGS__, break))); \ if (!_bpFoundElement && !bsonParseError) { \ bsonParseError = "Failed to find a required element: " _bsonDSL_str (Predicate); \ } \ _bsonDSL_end #define _bsonParseOperation_visitOthers(...) \ _bsonDSL_begin ("visitOthers(%s)", _bsonDSL_strElide (30, __VA_ARGS__)); \ _bsonVisitEach (*_bpDoc, if (not(eval (_bsonParseDidVisitNth (bsonVisitContext.index))), then (__VA_ARGS__))); \ _bsonDSL_end #define bsonPredicate(P) _bsonPredicate _bsonDSL_nothing () (P) #define _bsonPredicate(P) _bsonPredicate_Condition_##P #define _bsonPredicate_Condition_ __NOTE__Missing_name_for_a_predicate_expression #define _bsonPredicate_Condition_allOf(...) (1 _bsonDSL_mapMacro (_bsonPredicateAnd, ~, __VA_ARGS__)) #define _bsonPredicate_Condition_anyOf(...) (0 _bsonDSL_mapMacro (_bsonPredicateOr, ~, __VA_ARGS__)) #define _bsonPredicate_Condition_not(...) (!(0 _bsonDSL_mapMacro (_bsonPredicateOr, ~, __VA_ARGS__))) #define _bsonPredicateAnd(Pred, _ignore, _ignore1) &&_bsonPredicate _bsonDSL_nothing () (Pred) #define _bsonPredicateOr(Pred, _ignore, _ignore2) || _bsonPredicate _bsonDSL_nothing () (Pred) #define _bsonPredicate_Condition_eval(X) (X) #define _bsonPredicate_Condition_key(...) \ (_bson_dsl_key_is_anyof (bson_iter_key (&bsonVisitIter), \ bson_iter_key_len (&bsonVisitIter), \ true /* case senstive */, \ __VA_ARGS__, \ NULL)) #define _bsonPredicate_Condition_iKey(...) \ (_bson_dsl_key_is_anyof (bson_iter_key (&bsonVisitIter), \ bson_iter_key_len (&bsonVisitIter), \ false /* case insenstive */, \ __VA_ARGS__, \ NULL)) #define _bsonPredicate_Condition_type(Type) (bson_iter_type (&bsonVisitIter) == _bsonDSL_Type_##Type) #define _bsonPredicate_Condition_keyWithType(Key, Type) \ (_bsonPredicate_Condition_allOf _bsonDSL_nothing () (key (Key), type (Type))) #define _bsonPredicate_Condition_iKeyWithType(Key, Type) \ (_bsonPredicate_Condition_allOf _bsonDSL_nothing () (iKey (Key), type (Type))) #define _bsonPredicate_Condition_lastElement (_bson_dsl_iter_is_last_element (&bsonVisitIter)) #define _bsonPredicate_Condition_isNumeric BSON_ITER_HOLDS_NUMBER (&bsonVisitIter) #define _bsonPredicate_Condition_1 1 #define _bsonPredicate_Condition_0 0 #define _bsonPredicate_Condition_true true #define _bsonPredicate_Condition_false false #define _bsonPredicate_Condition_isTrue (bson_iter_as_bool (&bsonVisitIter)) #define _bsonPredicate_Condition_isFalse (!bson_iter_as_bool (&bsonVisitIter)) #define _bsonPredicate_Condition_empty (_bson_dsl_is_empty_bson (&bsonVisitIter)) #define _bsonPredicate_Condition_strEqual(S) (_bson_dsl_test_strequal (S, true)) #define _bsonPredicate_Condition_iStrEqual(S) (_bson_dsl_test_strequal (S, false)) #define _bsonPredicate_Condition_eq(Type, Value) (_bsonPredicate_Condition_type (Type) && bsonAs (Type) == Value) #define _bsonParseOperation_else _bsonParse_deferredElse _bsonDSL_nothing () #define _bsonParse_deferredElse(...) \ if (!_bpFoundElement) { \ _bsonDSL_begin ("else:%s", ""); \ _bsonParse_applyOps (__VA_ARGS__); \ _bsonDSL_end; \ } else \ ((void) 0) #define _bsonParseOperation_do(...) \ _bsonDSL_begin ("do: %s", _bsonDSL_strElide (30, __VA_ARGS__)); \ do { \ __VA_ARGS__; \ } while (0); \ _bsonDSL_end #define _bsonParseOperation_halt _bvHalt = true #define _bsonParseOperation_error(S) bsonParseError = (S) #define _bsonParseOperation_errorf(S, ...) (bsonParseError = _bson_dsl_errorf (&(S), __VA_ARGS__)) /// Perform conditional parsing #define _bsonParseOperation_if(Condition, ...) \ _bsonDSL_begin ("if(%s)", _bsonDSL_str (Condition)); \ /* Pick a sub-macro depending on if there are one or two args */ \ _bsonDSL_ifElse (_bsonDSL_hasComma (__VA_ARGS__), _bsonParse_ifThenElse, _bsonParse_ifThen) (Condition, \ __VA_ARGS__); \ _bsonDSL_end #define _bsonParse_ifThen_then _bsonParse_applyOps #define _bsonParse_ifElse_else _bsonParse_applyOps #define _bsonParse_ifThenElse(Condition, Then, Else) \ if ((Condition)) { \ _bsonDSLDebug ("then:"); \ _bsonParse_ifThen_##Then; \ } else { \ _bsonDSLDebug ("else:"); \ _bsonParse_ifElse_##Else; \ } #define _bsonParse_ifThen(Condition, Then) \ if ((Condition)) { \ _bsonDSLDebug ("%s", _bsonDSL_str (Then)); \ _bsonParse_ifThen_##Then; \ } else { \ _bsonDSLDebug ("[else nothing]"); \ } #define _bsonParseOperation_append _bsonParseOperationDeferred_append _bsonDSL_nothing () #define _bsonParseOperationDeferred_append(Doc, ...) \ _bsonDSL_begin ("append to [%s] : %s", _bsonDSL_str (Doc), _bsonDSL_strElide (30, __VA_ARGS__)); \ _bsonBuildAppend (Doc, __VA_ARGS__); \ if (bsonBuildError) { \ bsonParseError = bsonBuildError; \ } \ _bsonDSL_end #define _bsonVisit_applyOps _bsonVisit_applyOpsDeferred _bsonDSL_nothing () #define _bsonVisit_applyOpsDeferred(...) \ do { \ _bsonDSL_mapMacro (_bsonVisit_applyOp, ~, __VA_ARGS__); \ } while (0); #define bsonBuildArray(BSON, ...) \ _bsonDSL_begin ("bsonBuildArray(%s, %s)", _bsonDSL_str (BSON), _bsonDSL_strElide (30, __VA_ARGS__)); \ _bsonDSL_eval (_bsonBuildArray (BSON, __VA_ARGS__)); \ _bsonDSL_end #define _bsonBuildArray(BSON, ...) \ do { \ _bsonDSL_disableWarnings (); \ struct _bsonBuildContext_t _bbCtx = { \ .doc = &(BSON), \ .parent = _bsonBuildContextThreadLocalPtr, \ .index = 0, \ }; \ _bsonBuildContextThreadLocalPtr = &_bbCtx; \ _bsonBuildArrayWithCurrentContext (__VA_ARGS__); \ _bsonBuildContextThreadLocalPtr = _bbCtx.parent; \ _bsonDSL_restoreWarnings (); \ } while (0) /** * @brief Build a BSON document by appending to an existing bson_t document * * @param Pointer The document upon which to append * @param ... The Document elements to append to the document */ #define bsonBuildAppend(BSON, ...) _bsonDSL_eval (_bsonBuildAppend (BSON, __VA_ARGS__)) #define _bsonBuildAppend(BSON, ...) \ _bsonDSL_begin ("Appending to document '%s'", _bsonDSL_str (BSON)); \ _bsonDSL_disableWarnings (); \ /* Save the dsl context */ \ struct _bsonBuildContext_t _bbCtx = { \ .doc = &(BSON), \ .parent = _bsonBuildContextThreadLocalPtr, \ }; \ /* Reset the context */ \ _bsonBuildContextThreadLocalPtr = &_bbCtx; \ bsonBuildError = NULL; \ _bsonBuildAppendWithCurrentContext (__VA_ARGS__); \ /* Restore the dsl context */ \ _bsonBuildContextThreadLocalPtr = _bbCtx.parent; \ _bsonDSL_restoreWarnings (); \ _bsonDSL_end /** * @brief Build a new BSON document and assign the value into the given * pointer. */ #define bsonBuild(BSON, ...) \ _bsonDSL_begin ("Build a new document for '%s'", _bsonDSL_str (BSON)); \ bson_t *_bbDest = &(BSON); \ bson_init (_bbDest); \ bsonBuildAppend (*_bbDest, __VA_ARGS__); \ _bsonDSL_end /** * @brief Declare a variable and build it with the BSON DSL @see bsonBuild */ #define bsonBuildDecl(Variable, ...) \ bson_t Variable = BSON_INITIALIZER; \ bsonBuild (Variable, __VA_ARGS__) struct _bsonBuildContext_t { /// The document that is being built bson_t *doc; /// The key that is pending an append const char *key; /// The length of the string given in 'key' int key_len; /// The index of the array being built (if applicable) size_t index; /// A buffer for formatting key strings char index_key_str[16]; /// The parent context (if building a sub-document) struct _bsonBuildContext_t *parent; }; /// A pointer to the current thread's bsonBuild context _bson_thread_local _bson_comdat struct _bsonBuildContext_t *_bsonBuildContextThreadLocalPtr = NULL; struct _bsonVisitContext_t { const bson_t *doc; bson_iter_t iter; const struct _bsonVisitContext_t *parent; size_t index; }; /// A pointer to the current thread's bsonVisit/bsonParse context _bson_thread_local _bson_comdat struct _bsonVisitContext_t const *_bsonVisitContextThreadLocalPtr = NULL; /** * @brief The most recent error from a bsonBuild() DSL command. * * If NULL, no error occurred. Users can assign a value to this string to * indicate failure. */ _bson_thread_local _bson_comdat const char *bsonBuildError = NULL; /** * @brief The most recent error from a buildVisit() or bsonParse() DSL command. * * If NULL, no error occurred. Users can assign a value to this string to * indicate an error. * * If this string becomes non-NULL, the current bsonVisit()/bsonParse() will * halt and return. * * Upon entering a new bsonVisit()/bsonParse(), this will be reset to NULL. */ _bson_thread_local _bson_comdat const char *bsonParseError = NULL; #define _bsonDSLDebug(...) _bson_dsl_debug (BSON_DSL_DEBUG, __FILE__, __LINE__, BSON_FUNC, __VA_ARGS__) static BSON_INLINE bool _bson_dsl_test_strequal (const char *string, bool case_sensitive) { bson_iter_t it = bsonVisitIter; if (bson_iter_type (&it) == BSON_TYPE_UTF8) { uint32_t len; const char *s = bson_iter_utf8 (&it, &len); if (len != (uint32_t) strlen (string)) { return false; } if (case_sensitive) { return memcmp (string, s, len) == 0; } else { return bson_strcasecmp (string, s) == 0; } } return false; } static BSON_INLINE bool _bson_dsl_key_is_anyof (const char *key, const size_t keylen, int case_sensitive, ...) { va_list va; va_start (va, case_sensitive); const char *str; while ((str = va_arg (va, const char *))) { size_t str_len = strlen (str); if (str_len != keylen) { continue; } if (case_sensitive) { if (memcmp (str, key, str_len) == 0) { va_end (va); return true; } } else { if (bson_strcasecmp (str, key) == 0) { va_end (va); return true; } } } va_end (va); return false; } static BSON_INLINE void _bson_dsl_iter_as_doc (bson_t *into, const bson_iter_t *it) { uint32_t len = 0; const uint8_t *dataptr = NULL; if (BSON_ITER_HOLDS_ARRAY (it)) { bson_iter_array (it, &len, &dataptr); } else if (BSON_ITER_HOLDS_DOCUMENT (it)) { bson_iter_document (it, &len, &dataptr); } if (dataptr) { BSON_ASSERT (bson_init_static (into, dataptr, len)); } } static BSON_INLINE bool _bson_dsl_is_empty_bson (const bson_iter_t *it) { bson_t d = BSON_INITIALIZER; _bson_dsl_iter_as_doc (&d, it); return d.len == 5; // Empty documents/arrays have byte-size of five } static BSON_INLINE bool _bson_dsl_iter_is_last_element (const bson_iter_t *it) { bson_iter_t dup = *it; return !bson_iter_next (&dup) && dup.err_off == 0; } _bson_thread_local _bson_comdat int _bson_dsl_indent = 0; static BSON_INLINE void BSON_GNUC_PRINTF (5, 6) _bson_dsl_debug (bool do_debug, const char *file, int line, const char *func, const char *string, ...) { if (do_debug) { fprintf (stderr, "%s:%d: [%s] bson_dsl: ", file, line, func); for (int i = 0; i < _bson_dsl_indent; ++i) { fputs (" ", stderr); } va_list va; va_start (va, string); vfprintf (stderr, string, va); va_end (va); fputc ('\n', stderr); fflush (stderr); } } static BSON_INLINE char *BSON_GNUC_PRINTF (2, 3) _bson_dsl_errorf (char **const into, const char *const fmt, ...) { if (*into) { bson_free (*into); *into = NULL; } va_list args; va_start (args, fmt); *into = bson_strdupv_printf (fmt, args); va_end (args); return *into; } static BSON_INLINE void _bson_dsl_dupPath (char **into) { if (*into) { bson_free (*into); *into = NULL; } char *acc = bson_strdup (""); for (const struct _bsonVisitContext_t *ctx = &bsonVisitContext; ctx; ctx = ctx->parent) { char *prev = acc; if (ctx->parent && BSON_ITER_HOLDS_ARRAY (&ctx->parent->iter)) { // We're an array element acc = bson_strdup_printf ("[%d]%s", (int) ctx->index, prev); } else { // We're a document element acc = bson_strdup_printf (".%s%s", bson_iter_key (&ctx->iter), prev); } bson_free (prev); } *into = bson_strdup_printf ("$%s", acc); bson_free (acc); } static BSON_INLINE const char * _bsonVisitIterAs_cstr (void) { return bson_iter_utf8 (&bsonVisitIter, NULL); } static BSON_INLINE int32_t _bsonVisitIterAs_int32 (void) { return bson_iter_int32 (&bsonVisitIter); } static BSON_INLINE bool _bsonVisitIterAs_boolean (void) { return bson_iter_as_bool (&bsonVisitIter); } #define bsonAs(Type) _bsonDSL_paste (_bsonVisitIterAs_, Type) () /// Convert the given argument into a string without inhibitting macro expansion #define _bsonDSL_str(...) _bsonDSL_str_1 (__VA_ARGS__) // Empty quotes "" are to ensure a string appears. Old MSVC has a bug // where empty #__VA_ARGS__ just vanishes. #define _bsonDSL_str_1(...) "" #__VA_ARGS__ #define _bsonDSL_strElide(MaxLen, ...) \ (strlen (_bsonDSL_str (__VA_ARGS__)) > (MaxLen) ? "[...]" : _bsonDSL_str (__VA_ARGS__)) /// Paste two tokens: #define _bsonDSL_paste(a, ...) _bsonDSL_paste_impl (a, __VA_ARGS__) #define _bsonDSL_paste_impl(a, ...) a##__VA_ARGS__ /// Paste three tokens: #define _bsonDSL_paste3(a, b, c) _bsonDSL_paste (a, _bsonDSL_paste (b, c)) /// Paste four tokens: #define _bsonDSL_paste4(a, b, c, d) _bsonDSL_paste (a, _bsonDSL_paste3 (b, c, d)) // clang-format off /// Now we need a MAP() macro. This idiom is common, but fairly opaque. Below is /// some crazy preprocessor trickery to implement it. Fortunately, once we have /// MAP(), the remainder of this file is straightforward. This implementation /// isn't the simplest one possible, but is one that supports the old /// non-compliant MSVC preprocessor. /* Expands to nothing. Used to defer a function-like macro and to ignore arguments */ #define _bsonDSL_nothing(...) /// Expand to the 64th argument. See below for why this is useful. #define _bsonDSL_pick64th(\ _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ _61, _62, _63, ...) \ _63 /** * @brief Expands to 1 if the given arguments contain any top-level commas, zero otherwise. * * There is an expansion of __VA_ARGS__, followed by 62 '1' arguments, followed * by single '0'. If __VA_ARGS__ contains no commas, pick64th() will return the * single zero. If __VA_ARGS__ contains any top-level commas, the series of ones * will shift to the right and pick64th will return one of those ones. (This only * works __VA_ARGS__ contains fewer than 62 commas, which is a somewhat reasonable * limit.) The _bsonDSL_nothing() is a workaround for MSVC's bad preprocessor that * expands __VA_ARGS__ incorrectly. * * If we have __VA_OPT__, this can be a lot simpler. */ #define _bsonDSL_hasComma(...) \ _bsonDSL_pick64th \ _bsonDSL_nothing() (__VA_ARGS__, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, ~) /** * Expands to a single comma if "invoked" as a function-like macro. * (This will make sense, I promise.) */ #define _bsonDSL_commaIfRHSHasParens(...) , /** * @brief Expand to 1 if given no arguments, otherwise 0. * * This could be done much more simply using __VA_OPT__, but we need to work on * older compilers. */ #define _bsonDSL_isEmpty(...) \ _bsonDSL_isEmpty_1(\ /* Expands to '1' if __VA_ARGS__ contains any top-level commas */ \ _bsonDSL_hasComma(__VA_ARGS__), \ /* Expands to '1' if __VA_ARGS__ begins with a parenthesis, because \ * that will cause an "invocation" of _bsonDSL_commaIfRHSHasParens, \ * which immediately expands to a single comma. */ \ _bsonDSL_hasComma(_bsonDSL_commaIfRHSHasParens __VA_ARGS__), \ /* Expands to '1' if __VA_ARGS__ expands to a function-like macro name \ * that then expands to anything containing a top-level comma */ \ _bsonDSL_hasComma(__VA_ARGS__ ()), \ /* Expands to '1' if __VA_ARGS__ expands to nothing. */ \ _bsonDSL_hasComma(_bsonDSL_commaIfRHSHasParens __VA_ARGS__ ())) /** * A helper for isEmpty(): If given (0, 0, 0, 1), expands as: * - first: _bsonDSL_hasComma(_bsonDSL_isEmpty_CASE_0001) * - then: _bsonDSL_hasComma(,) * - then: 1 * Given any other aruments: * - first: _bsonDSL_hasComma(_bsonDSL_isEmpty_CASE_) * - then: 0 */ #define _bsonDSL_isEmpty_1(_1, _2, _3, _4) \ _bsonDSL_hasComma(_bsonDSL_paste(_bsonDSL_isEmpty_CASE_, _bsonDSL_paste4(_1, _2, _3, _4))) #define _bsonDSL_isEmpty_CASE_0001 , /** * @brief Expand to the first argument if `Cond` is 1, the second argument if `Cond` is 0 */ #define _bsonDSL_ifElse(Cond, IfTrue, IfFalse) \ /* Suppress expansion of the two branches by using the '#' operator */ \ _bsonDSL_nothing(#IfTrue, #IfFalse) \ /* Concat the cond 1/0 with a prefix macro: */ \ _bsonDSL_paste(_bsonDSL_ifElse_PICK_, Cond)(IfTrue, IfFalse) #define _bsonDSL_ifElse_PICK_1(IfTrue, IfFalse) \ /* Expand the first operand, throw away the second */ \ IfTrue _bsonDSL_nothing(#IfFalse) #define _bsonDSL_ifElse_PICK_0(IfTrue, IfFalse) \ /* Expand to the second operand, throw away the first */ \ IfFalse _bsonDSL_nothing(#IfTrue) #ifdef _MSC_VER // MSVC's "traditional" preprocessor requires many more expansion passes, // but GNU and Clang are very slow when evaluating hugely nested expansions // and generate massive macro expansion backtraces. #define _bsonDSL_eval_1(...) __VA_ARGS__ #define _bsonDSL_eval_2(...) _bsonDSL_eval_1(_bsonDSL_eval_1(_bsonDSL_eval_1(_bsonDSL_eval_1(_bsonDSL_eval_1(__VA_ARGS__))))) #define _bsonDSL_eval_4(...) _bsonDSL_eval_2(_bsonDSL_eval_2(_bsonDSL_eval_2(_bsonDSL_eval_2(_bsonDSL_eval_2(__VA_ARGS__))))) #define _bsonDSL_eval_8(...) _bsonDSL_eval_4(_bsonDSL_eval_4(_bsonDSL_eval_4(_bsonDSL_eval_4(_bsonDSL_eval_4(__VA_ARGS__))))) #define _bsonDSL_eval_16(...) _bsonDSL_eval_8(_bsonDSL_eval_8(_bsonDSL_eval_8(_bsonDSL_eval_8(_bsonDSL_eval_8(__VA_ARGS__))))) #define _bsonDSL_eval(...) _bsonDSL_eval_16(_bsonDSL_eval_16(_bsonDSL_eval_16(_bsonDSL_eval_16(_bsonDSL_eval_16(__VA_ARGS__))))) #else // Each level of "eval" applies double the expansions of the previous level. #define _bsonDSL_eval_1(...) __VA_ARGS__ #define _bsonDSL_eval_2(...) _bsonDSL_eval_1(_bsonDSL_eval_1(__VA_ARGS__)) #define _bsonDSL_eval_4(...) _bsonDSL_eval_2(_bsonDSL_eval_2(__VA_ARGS__)) #define _bsonDSL_eval_8(...) _bsonDSL_eval_4(_bsonDSL_eval_4(__VA_ARGS__)) #define _bsonDSL_eval_16(...) _bsonDSL_eval_8(_bsonDSL_eval_8(__VA_ARGS__)) #define _bsonDSL_eval_32(...) _bsonDSL_eval_16(_bsonDSL_eval_16(__VA_ARGS__)) #define _bsonDSL_eval(...) _bsonDSL_eval_32(__VA_ARGS__) #endif /** * Finally, the Map() macro that allows us to do the magic, which we've been * building up to all along. * * The dance with mapMacro_first, mapMacro_final, and _bsonDSL_nothing * conditional on argument count is to prevent warnings from pre-C99 about * passing no arguments to the '...' parameters. Yet again, if we had C99 and * __VA_OPT__ this would be simpler. */ #define _bsonDSL_mapMacro(Action, Constant, ...) \ /* Pick our first action based on the content of '...': */ \ _bsonDSL_ifElse( \ /* If given no arguments: */\ _bsonDSL_isEmpty(__VA_ARGS__), \ /* expand to _bsonDSL_nothing */ \ _bsonDSL_nothing, \ /* Otherwise, expand to mapMacro_first: */ \ _bsonDSL_mapMacro_first) \ /* Now "invoke" the chosen macro: */ \ _bsonDSL_nothing() (Action, Constant, __VA_ARGS__) #define _bsonDSL_mapMacro_first(Action, Constant, ...) \ /* Select our next step based on whether we have one or more arguments: */ \ _bsonDSL_ifElse( \ /* If '...' contains more than one argument (has a top-level comma): */ \ _bsonDSL_hasComma(__VA_ARGS__), \ /* Begin the mapMacro loop with mapMacro_A: */ \ _bsonDSL_mapMacro_A, \ /* Otherwise skip to the final step of the loop: */ \ _bsonDSL_mapMacro_final) \ /* Invoke the chosen macro, setting the counter to zero: */ \ _bsonDSL_nothing() (Action, Constant, 0, __VA_ARGS__) /// Handle the last expansion in a mapMacro sequence. #define _bsonDSL_mapMacro_final(Action, Constant, Counter, FinalElement) \ Action(FinalElement, Constant, Counter) /** * mapMacro_A and mapMacro_B are identical and just invoke each other. */ #define _bsonDSL_mapMacro_A(Action, Constant, Counter, Head, ...) \ /* First evaluate the action once: */ \ Action(Head, Constant, Counter) \ /* Pick our next step: */ \ _bsonDSL_ifElse( \ /* If '...' contains more than one argument (has a top-level comma): */ \ _bsonDSL_hasComma(__VA_ARGS__), \ /* Jump to the other mapMacro: */ \ _bsonDSL_mapMacro_B, \ /* Otherwise go to mapMacro_final */ \ _bsonDSL_mapMacro_final) \ /* Invoke the next step of the map: */ \ _bsonDSL_nothing() (Action, Constant, Counter + 1, __VA_ARGS__) #define _bsonDSL_mapMacro_B(Action, Constant, Counter, Head, ...) \ Action(Head, Constant, Counter) \ _bsonDSL_ifElse(_bsonDSL_hasComma(__VA_ARGS__), _bsonDSL_mapMacro_A, _bsonDSL_mapMacro_final) \ _bsonDSL_nothing() (Action, Constant, Counter + 1, __VA_ARGS__) // clang-format on #endif // MONGO_C_DRIVER_COMMON_BSON_DSL_PRIVATE_H mongodb-1.21.0/src/libmongoc/src/common/src/common-cmp-private.h0000644000175100001660000002050214760300420021430 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_CMP_PRIVATE_H #define MONGO_C_DRIVER_COMMON_CMP_PRIVATE_H #include /* ssize_t, BSON_CONCAT */ #include #include #include BSON_BEGIN_DECLS /* Based on the "Safe Integral Comparisons" proposal merged in C++20: * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0586r2.html * * Due to lack of type deduction in C, relational comparison functions (e.g. * `cmp_less`) are defined in sets of four "functions" according to the * signedness of each value argument, e.g.: * - mcommon_cmp_less_ss (signed-value, signed-value) * - mcommon_cmp_less_uu (unsigned-value, unsigned-value) * - mcommon_cmp_less_su (signed-value, unsigned-value) * - mcommon_cmp_less_us (unsigned-value, signed-value) * * Similarly, the `in_range` function is defined as a set of two "functions" * according to the signedness of the value argument: * - mcommon_in_range_signed (Type, signed-value) * - mcommon_in_range_unsigned (Type, unsigned-value) * * The user must take care to use the correct signedness for the provided * argument(s). Enabling compiler warnings for implicit sign conversions is * recommended. */ #define MCOMMON_CMP_SET(op, ss, uu, su, us) \ static BSON_INLINE bool BSON_CONCAT3 (mcommon_cmp_, op, _ss) (int64_t t, int64_t u) \ { \ return (ss); \ } \ \ static BSON_INLINE bool BSON_CONCAT3 (mcommon_cmp_, op, _uu) (uint64_t t, uint64_t u) \ { \ return (uu); \ } \ \ static BSON_INLINE bool BSON_CONCAT3 (mcommon_cmp_, op, _su) (int64_t t, uint64_t u) \ { \ return (su); \ } \ \ static BSON_INLINE bool BSON_CONCAT3 (mcommon_cmp_, op, _us) (uint64_t t, int64_t u) \ { \ return (us); \ } MCOMMON_CMP_SET (equal, t == u, t == u, t < 0 ? false : (uint64_t) (t) == u, u < 0 ? false : t == (uint64_t) (u)) MCOMMON_CMP_SET (not_equal, !mcommon_cmp_equal_ss (t, u), !mcommon_cmp_equal_uu (t, u), !mcommon_cmp_equal_su (t, u), !mcommon_cmp_equal_us (t, u)) MCOMMON_CMP_SET (less, t < u, t < u, t < 0 ? true : (uint64_t) (t) < u, u < 0 ? false : t < (uint64_t) (u)) MCOMMON_CMP_SET (greater, mcommon_cmp_less_ss (u, t), mcommon_cmp_less_uu (u, t), mcommon_cmp_less_us (u, t), mcommon_cmp_less_su (u, t)) MCOMMON_CMP_SET (less_equal, !mcommon_cmp_greater_ss (t, u), !mcommon_cmp_greater_uu (t, u), !mcommon_cmp_greater_su (t, u), !mcommon_cmp_greater_us (t, u)) MCOMMON_CMP_SET (greater_equal, !mcommon_cmp_less_ss (t, u), !mcommon_cmp_less_uu (t, u), !mcommon_cmp_less_su (t, u), !mcommon_cmp_less_us (t, u)) #undef MCOMMON_CMP_SET /* Return true if the given value is within the range of the corresponding * signed type. The suffix must match the signedness of the given value. */ #define MCOMMON_IN_RANGE_SET_SIGNED(Type, min, max) \ static BSON_INLINE bool BSON_CONCAT3 (mcommon_in_range, _##Type, _signed) (int64_t value) \ { \ return mcommon_cmp_greater_equal_ss (value, min) && mcommon_cmp_less_equal_ss (value, max); \ } \ \ static BSON_INLINE bool BSON_CONCAT3 (mcommon_in_range, _##Type, _unsigned) (uint64_t value) \ { \ return mcommon_cmp_greater_equal_us (value, min) && mcommon_cmp_less_equal_us (value, max); \ } /* Return true if the given value is within the range of the corresponding * unsigned type. The suffix must match the signedness of the given value. */ #define MCOMMON_IN_RANGE_SET_UNSIGNED(Type, max) \ static BSON_INLINE bool BSON_CONCAT3 (mcommon_in_range, _##Type, _signed) (int64_t value) \ { \ return mcommon_cmp_greater_equal_su (value, 0u) && mcommon_cmp_less_equal_su (value, max); \ } \ \ static BSON_INLINE bool BSON_CONCAT3 (mcommon_in_range, _##Type, _unsigned) (uint64_t value) \ { \ return mcommon_cmp_less_equal_uu (value, max); \ } MCOMMON_IN_RANGE_SET_SIGNED (signed_char, SCHAR_MIN, SCHAR_MAX) MCOMMON_IN_RANGE_SET_SIGNED (short, SHRT_MIN, SHRT_MAX) MCOMMON_IN_RANGE_SET_SIGNED (int, INT_MIN, INT_MAX) MCOMMON_IN_RANGE_SET_SIGNED (long, LONG_MIN, LONG_MAX) MCOMMON_IN_RANGE_SET_SIGNED (long_long, LLONG_MIN, LLONG_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (unsigned_char, UCHAR_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (unsigned_short, USHRT_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (unsigned_int, UINT_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (unsigned_long, ULONG_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (unsigned_long_long, ULLONG_MAX) MCOMMON_IN_RANGE_SET_SIGNED (int8_t, INT8_MIN, INT8_MAX) MCOMMON_IN_RANGE_SET_SIGNED (int16_t, INT16_MIN, INT16_MAX) MCOMMON_IN_RANGE_SET_SIGNED (int32_t, INT32_MIN, INT32_MAX) MCOMMON_IN_RANGE_SET_SIGNED (int64_t, INT64_MIN, INT64_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (uint8_t, UINT8_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (uint16_t, UINT16_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (uint32_t, UINT32_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (uint64_t, UINT64_MAX) MCOMMON_IN_RANGE_SET_SIGNED (ssize_t, SSIZE_MIN, SSIZE_MAX) MCOMMON_IN_RANGE_SET_UNSIGNED (size_t, SIZE_MAX) #undef MCOMMON_IN_RANGE_SET_SIGNED #undef MCOMMON_IN_RANGE_SET_UNSIGNED /* Return true if the value with *signed* type is in the representable range of * Type and false otherwise. */ #define mcommon_in_range_signed(Type, value) BSON_CONCAT3 (mcommon_in_range, _##Type, _signed) (value) /* Return true if the value with *unsigned* type is in the representable range * of Type and false otherwise. */ #define mcommon_in_range_unsigned(Type, value) BSON_CONCAT3 (mcommon_in_range, _##Type, _unsigned) (value) BSON_END_DECLS #endif /* MONGO_C_DRIVER_COMMON_CMP_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-config.h0000644000175100001660000000027214760300420020450 0ustar #ifndef COMMON_CONFIG_H #define COMMON_CONFIG_H #define MONGOC_ENABLE_DEBUG_ASSERTIONS 1 #if MONGOC_ENABLE_DEBUG_ASSERTIONS != 1 # undef MONGOC_ENABLE_DEBUG_ASSERTIONS #endif #endif mongodb-1.21.0/src/libmongoc/src/common/src/common-config.h.in0000644000175100001660000000033114760300420021051 0ustar #ifndef COMMON_CONFIG_H #define COMMON_CONFIG_H #define MONGOC_ENABLE_DEBUG_ASSERTIONS @MONGOC_ENABLE_DEBUG_ASSERTIONS@ #if MONGOC_ENABLE_DEBUG_ASSERTIONS != 1 # undef MONGOC_ENABLE_DEBUG_ASSERTIONS #endif #endif mongodb-1.21.0/src/libmongoc/src/common/src/common-json-private.h0000644000175100001660000004333114760300420021627 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_JSON_PRIVATE_H #define MONGO_C_DRIVER_COMMON_JSON_PRIVATE_H #include #define mcommon_iso8601_string_append COMMON_NAME (iso8601_string_append) #define mcommon_json_append_escaped COMMON_NAME (json_append_escaped) #define mcommon_json_append_value_double COMMON_NAME (json_append_value_double) #define mcommon_json_append_value_decimal128 COMMON_NAME (json_append_value_decimal128) #define mcommon_json_append_value_oid COMMON_NAME (json_append_value_oid) #define mcommon_json_append_value_binary COMMON_NAME (json_append_value_binary) #define mcommon_json_append_value_date_time COMMON_NAME (json_append_value_date_time) #define mcommon_json_append_value_timestamp COMMON_NAME (json_append_value_timestamp) #define mcommon_json_append_value_regex COMMON_NAME (json_append_value_regex) #define mcommon_json_append_value_dbpointer COMMON_NAME (json_append_value_dbpointer) #define mcommon_json_append_value_code COMMON_NAME (json_append_value_code) #define mcommon_json_append_value_codewscope COMMON_NAME (json_append_value_codewscope) #define mcommon_json_append_value_symbol COMMON_NAME (json_append_value_symbol) #define mcommon_json_append_bson_values COMMON_NAME (json_append_bson_values) #define mcommon_json_append_bson_document COMMON_NAME (json_append_bson_document) #define mcommon_json_append_bson_array COMMON_NAME (json_append_bson_array) // Needed by libbson and common-json #ifndef BSON_MAX_RECURSION #define BSON_MAX_RECURSION 200 #endif // Needed by libbson and common-json #define BSON_REGEX_OPTIONS_SORTED "ilmsux" /** * @brief Append an ISO 8601 formatted date, given 64-bit milliseconds since the epoch * @param append A bounded string append, initialized with mcommon_string_set_append() * @param msec_since_epoch Milliseconds since Jan 1 1970 UTC * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_iso8601_string_append (mcommon_string_append_t *append, int64_t msec_since_epoch); /** * @brief Append a UTF-8 string with all special characters escaped * * @param append A bounded string append, initialized with mcommon_string_set_append() * @param str UTF-8 string to escape and append * @param len Length of 'str' in bytes * @param allow_nul true if internal "00" bytes or "C0 80" sequences should be encoded as "\u0000", false to treat * them as invalid data * @returns true on success, false if this 'append' has exceeded its max length or if we encountered invalid UTF-8 or * disallowed NUL bytes in 'str' * * The string may include internal NUL characters. It does not need to be NUL terminated. * The two-byte sequence "C0 80" is also interpreted as an internal NUL, for historical reasons. This sequence is * considered invalid according to RFC3629. */ bool mcommon_json_append_escaped (mcommon_string_append_t *append, const char *str, uint32_t len, bool allow_nul); /** * @brief Append a comma separator string to appear between values * @param append A bounded string append, initialized with mcommon_string_set_append() * @returns true on success, false if this 'append' has exceeded its max length */ static BSON_INLINE bool mcommon_json_append_separator (mcommon_string_append_t *append) { return mcommon_string_append (append, ", "); } /** * @brief Append a quoted and escaped key and key-value separator * @param append A bounded string append, initialized with mcommon_string_set_append() * @param str UTF-8 string to escape and append * @param len Length of 'str' in bytes * @returns true on success, false if this 'append' has exceeded its max length or if we encountered invalid UTF-8 or * disallowed NUL bytes in 'str' * * See mcommon_json_append_escaped. NUL values in keys are never allowed. */ static BSON_INLINE bool mcommon_json_append_key (mcommon_string_append_t *append, const char *str, uint32_t len) { return mcommon_string_append (append, "\"") && mcommon_json_append_escaped (append, str, len, false) && mcommon_string_append (append, "\" : "); } /** * @brief Append a quoted and escaped string * @param append A bounded string append, initialized with mcommon_string_set_append() * @param str UTF-8 string to escape and append * @param len Length of 'str' in bytes * @param allow_nul true if internal "00" bytes or "C0 80" sequences should be encoded as "\u0000", false to treat them * as invalid data * @returns true on success, false if this 'append' has exceeded its max length or if we encountered invalid UTF-8 or * disallowed NUL bytes in 'str' * * See mcommon_json_append_escaped. */ static BSON_INLINE bool mcommon_json_append_value_utf8 (mcommon_string_append_t *append, const char *str, uint32_t len, bool allow_nul) { return mcommon_string_append (append, "\"") && mcommon_json_append_escaped (append, str, len, allow_nul) && mcommon_string_append (append, "\""); } /** * @brief Append an int32_t value, serialized according to a bson_json_mode_t * @param append A bounded string append, initialized with mcommon_string_set_append() * @param value Integer value * @param mode One of the JSON serialization modes, as a bson_json_mode_t. * @returns true on success, false if this 'append' has exceeded its max length */ static BSON_INLINE bool mcommon_json_append_value_int32 (mcommon_string_append_t *append, int32_t value, bson_json_mode_t mode) { return mode == BSON_JSON_MODE_CANONICAL ? mcommon_string_append_printf (append, "{ \"$numberInt\" : \"%" PRId32 "\" }", value) : mcommon_string_append_printf (append, "%" PRId32, value); } /** * @brief Append an int64_t value, serialized according to a bson_json_mode_t * @param append A bounded string append, initialized with mcommon_string_set_append() * @param value Integer value * @param mode One of the JSON serialization modes, as a bson_json_mode_t. * @returns true on success, false if this 'append' has exceeded its max length */ static BSON_INLINE bool mcommon_json_append_value_int64 (mcommon_string_append_t *append, int64_t value, bson_json_mode_t mode) { return mode == BSON_JSON_MODE_CANONICAL ? mcommon_string_append_printf (append, "{ \"$numberLong\" : \"%" PRId64 "\" }", value) : mcommon_string_append_printf (append, "%" PRId64, value); } /** * @brief Append a JSON compatible bool value * @param append A bounded string append, initialized with mcommon_string_set_append() * @param bool Boolean value * @returns true on success, false if this 'append' has exceeded its max length */ static BSON_INLINE bool mcommon_json_append_value_bool (mcommon_string_append_t *append, bool value) { return mcommon_string_append (append, value ? "true" : "false"); } /** * @brief Append an $undefined value * @param append A bounded string append, initialized with mcommon_string_set_append() * @returns true on success, false if this 'append' has exceeded its max length */ static BSON_INLINE bool mcommon_json_append_value_undefined (mcommon_string_append_t *append) { return mcommon_string_append (append, "{ \"$undefined\" : true }"); } /** * @brief Append a null value * @param append A bounded string append, initialized with mcommon_string_set_append() * @returns true on success, false if this 'append' has exceeded its max length */ static BSON_INLINE bool mcommon_json_append_value_null (mcommon_string_append_t *append) { return mcommon_string_append (append, "null"); } /** * @brief Append a $minKey value * @param append A bounded string append, initialized with mcommon_string_set_append() * @returns true on success, false if this 'append' has exceeded its max length */ static BSON_INLINE bool mcommon_json_append_value_minkey (mcommon_string_append_t *append) { return mcommon_string_append (append, "{ \"$minKey\" : 1 }"); } /** * @brief Append a $maxKey value * @param append A bounded string append, initialized with mcommon_string_set_append() * @returns true on success, false if this 'append' has exceeded its max length */ static BSON_INLINE bool mcommon_json_append_value_maxkey (mcommon_string_append_t *append) { return mcommon_string_append (append, "{ \"$maxKey\" : 1 }"); } /** * @brief Append a double-precision floating point value * @param append A bounded string append, initialized with mcommon_string_set_append() * @param value Double-precision floating point value * @param mode One of the JSON serialization modes, as a bson_json_mode_t. * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_double (mcommon_string_append_t *append, double value, bson_json_mode_t mode); /** * @brief Append a decimal128 value * @param append A bounded string append, initialized with mcommon_string_set_append() * @param value decimal128 value to copy * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_decimal128 (mcommon_string_append_t *append, const bson_decimal128_t *value); /** * @brief Append the $oid JSON serialization of an ObjectId value * @param append A bounded string append, initialized with mcommon_string_set_append() * @param value bson_oid_t value to copy * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_oid (mcommon_string_append_t *append, const bson_oid_t *value); /** * @brief Append the JSON serialization of a BSON binary value * @param append A bounded string append, initialized with mcommon_string_set_append() * @param subtype Subtype code, identifying the format within the base64-encoded binary block * @param bytes Bytes to be base64 encoded * @param byte_count Number of bytes * @param mode One of the JSON serialization modes, as a bson_json_mode_t * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_binary (mcommon_string_append_t *append, bson_subtype_t subtype, const uint8_t *bytes, uint32_t byte_count, bson_json_mode_t mode); /** * @brief Append the JSON serialization of a BSON date and time * @param append A bounded string append, initialized with mcommon_string_set_append() * @param msec_since_epoch Milliseconds since Jan 1 1970 * @param mode One of the JSON serialization modes, as a bson_json_mode_t * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_date_time (mcommon_string_append_t *append, int64_t msec_since_epoch, bson_json_mode_t mode); /** * @brief Append the JSON serialization of a BSON timestamp value * @param append A bounded string append, initialized with mcommon_string_set_append() * @param timestamp 32-bit timestamp value * @param increment 32-bit increment value * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_timestamp (mcommon_string_append_t *append, uint32_t timestamp, uint32_t increment); /** * @brief Append the JSON serialization of a BSON regular expression * @param append A bounded string append, initialized with mcommon_string_set_append() * @param pattern Regular expression pattern, as a UTF-8 string * @param pattern_len Length of pattern string, in bytes * @param options Regular expression options, as a UTF-8 string * @param options_len Length of the options string, in bytes * @param mode One of the JSON serialization modes, as a bson_json_mode_t * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_regex (mcommon_string_append_t *append, const char *pattern, uint32_t pattern_len, const char *options, size_t options_len, bson_json_mode_t mode); /** * @brief Append the JSON serialization of a BSON legacy DBPointer * @param append A bounded string append, initialized with mcommon_string_set_append() * @param collection Collection name, as a UTF-8 string * @param collection_len Length of collection name string, in bytes * @param oid Optional ObjectId reference, or NULL * @param mode One of the JSON serialization modes, as a bson_json_mode_t * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_dbpointer (mcommon_string_append_t *append, const char *collection, uint32_t collection_len, const bson_oid_t *oid, bson_json_mode_t mode); /** * @brief Append the JSON serialization of a BSON legacy code object * @param append A bounded string append, initialized with mcommon_string_set_append() * @param code Code string, in UTF-8 * @param code_len Length of code string, in bytes * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_code (mcommon_string_append_t *append, const char *code, uint32_t code_len); /** * @brief Append the JSON serialization of a BSON legacy code-with-scope object * @param append A bounded string append, initialized with mcommon_string_set_append() * @param code Code string, in UTF-8 * @param code_len Length of code string, in bytes * @param scope Scope as a bson_t document * @param mode One of the JSON serialization modes, as a bson_json_mode_t * @param max_depth Maximum allowed number of document/array nesting levels below this one * @returns true if the input bson was valid, even if we reached max length. false on invalid BSON. */ bool mcommon_json_append_value_codewscope (mcommon_string_append_t *append, const char *code, uint32_t code_len, const bson_t *scope, bson_json_mode_t mode, unsigned max_depth); /** * @brief Append the JSON serialization of a BSON legacy symbol object * @param append A bounded string append, initialized with mcommon_string_set_append() * @param symbol Symbol string, in UTF-8 * @param symbol_len Length of symbol string, in bytes * @param mode One of the JSON serialization modes, as a bson_json_mode_t. * @returns true on success, false if this 'append' has exceeded its max length */ bool mcommon_json_append_value_symbol (mcommon_string_append_t *append, const char *symbol, uint32_t symbol_len, bson_json_mode_t mode); /** * @brief Append all JSON-serialized values from a bson_t * @param append A bounded string append, initialized with mcommon_string_set_append() * @param bson bson_t document or array * @param mode One of the JSON serialization modes, as a bson_json_mode_t * @param has_keys true if this is a document, false if this is an array * @param max_depth Maximum allowed number of document/array nesting levels below this one * @returns true if the input bson was valid, even if we reached max length. false on invalid BSON. * * This generates keys, values, and separators but does not enclose the result in {} or []. * Note that the return value reflects the status of BSON decoding, not string appending. * The append status can be read using mcommon_string_status_from_append() if needed. * If encoding was stopped early due to the max depth limit or max length, invalid input may go unnoticed. */ bool mcommon_json_append_bson_values ( mcommon_string_append_t *append, const bson_t *bson, bson_json_mode_t mode, bool has_keys, unsigned max_depth); /** * @brief Append a BSON document serialized as a JSON document * @param append A bounded string append, initialized with mcommon_string_set_append() * @param bson bson_t document * @param mode One of the JSON serialization modes, as a bson_json_mode_t * @param max_depth Maximum allowed number of document/array nesting levels *including* this one. If zero, appends "{ * ... }". * @returns true if the input bson was valid, even if we reached max length. false on invalid BSON. */ bool mcommon_json_append_bson_document (mcommon_string_append_t *append, const bson_t *bson, bson_json_mode_t mode, unsigned max_depth); /** * @brief Append a BSON document serialized as a JSON array * @param append A bounded string append, initialized with mcommon_string_set_append() * @param bson bson_t to interpret as an array * @param mode One of the JSON serialization modes, as a bson_json_mode_t * @param max_depth Maximum allowed number of document/array nesting levels *including* this one. If zero, appends "[ * ... ]". * @returns true if the input bson was valid, even if we reached max length. false on invalid BSON. */ bool mcommon_json_append_bson_array (mcommon_string_append_t *append, const bson_t *bson, bson_json_mode_t mode, unsigned max_depth); #endif /* MONGO_C_DRIVER_COMMON_JSON_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-json.c0000644000175100001660000006656214760300420020165 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include typedef struct { mcommon_string_append_t *append; unsigned max_depth; bson_json_mode_t mode; bool has_keys; bool not_first_item; bool is_corrupt; } mcommon_json_append_visit_t; static bool mcommon_json_append_visit_utf8 ( const bson_iter_t *iter, const char *key, size_t v_utf8_len, const char *v_utf8, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); if (!mcommon_in_range_unsigned (uint32_t, v_utf8_len)) { mcommon_string_append_overflow (state->append); return true; } return !mcommon_json_append_value_utf8 (state->append, v_utf8, (uint32_t) v_utf8_len, true); } static bool mcommon_json_append_visit_int32 (const bson_iter_t *iter, const char *key, int32_t v_int32, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_int32 (state->append, v_int32, state->mode); } static bool mcommon_json_append_visit_int64 (const bson_iter_t *iter, const char *key, int64_t v_int64, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_int64 (state->append, v_int64, state->mode); } static bool mcommon_json_append_visit_decimal128 (const bson_iter_t *iter, const char *key, const bson_decimal128_t *value, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_decimal128 (state->append, value); } static bool mcommon_json_append_visit_double (const bson_iter_t *iter, const char *key, double v_double, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_double (state->append, v_double, state->mode); } static bool mcommon_json_append_visit_undefined (const bson_iter_t *iter, const char *key, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_undefined (state->append); } static bool mcommon_json_append_visit_null (const bson_iter_t *iter, const char *key, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_null (state->append); } static bool mcommon_json_append_visit_oid (const bson_iter_t *iter, const char *key, const bson_oid_t *oid, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_oid (state->append, oid); } static bool mcommon_json_append_visit_binary (const bson_iter_t *iter, const char *key, bson_subtype_t v_subtype, size_t v_binary_len, const uint8_t *v_binary, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); if (!mcommon_in_range_unsigned (uint32_t, v_binary_len)) { mcommon_string_append_overflow (state->append); return true; } return !mcommon_json_append_value_binary (state->append, v_subtype, v_binary, (uint32_t) v_binary_len, state->mode); } static bool mcommon_json_append_visit_bool (const bson_iter_t *iter, const char *key, bool v_bool, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_bool (state->append, v_bool); } static bool mcommon_json_append_visit_date_time (const bson_iter_t *iter, const char *key, int64_t msec_since_epoch, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_date_time (state->append, msec_since_epoch, state->mode); } static bool mcommon_json_append_visit_regex ( const bson_iter_t *iter, const char *key, const char *v_regex, const char *v_options, void *data) { mcommon_json_append_visit_t *state = data; size_t v_regex_len = strlen (v_regex); size_t v_options_len = strlen (v_options); BSON_UNUSED (iter); BSON_UNUSED (key); if (!mcommon_in_range_unsigned (uint32_t, v_regex_len)) { mcommon_string_append_overflow (state->append); return true; } return !mcommon_json_append_value_regex ( state->append, v_regex, (uint32_t) v_regex_len, v_options, v_options_len, state->mode); } static bool mcommon_json_append_visit_timestamp ( const bson_iter_t *iter, const char *key, uint32_t v_timestamp, uint32_t v_increment, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_timestamp (state->append, v_timestamp, v_increment); } static bool mcommon_json_append_visit_dbpointer (const bson_iter_t *iter, const char *key, size_t v_collection_len, const char *v_collection, const bson_oid_t *v_oid, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); if (!mcommon_in_range_unsigned (uint32_t, v_collection_len)) { mcommon_string_append_overflow (state->append); return true; } return !mcommon_json_append_value_dbpointer ( state->append, v_collection, (uint32_t) v_collection_len, v_oid, state->mode); } static bool mcommon_json_append_visit_minkey (const bson_iter_t *iter, const char *key, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_minkey (state->append); } static bool mcommon_json_append_visit_maxkey (const bson_iter_t *iter, const char *key, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_json_append_value_maxkey (state->append); } static bool mcommon_json_append_visit_before (const bson_iter_t *iter, const char *key, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); if (!mcommon_string_status_from_append (state->append)) { return true; } if (state->not_first_item) { if (!mcommon_json_append_separator (state->append)) { return true; } } else { state->not_first_item = true; } if (state->has_keys) { size_t key_len = strlen (key); if (!mcommon_in_range_unsigned (uint32_t, key_len)) { mcommon_string_append_overflow (state->append); return true; } if (!mcommon_json_append_key (state->append, key, (uint32_t) key_len)) { return true; } } return false; } static bool mcommon_json_append_visit_after (const bson_iter_t *iter, const char *key, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); return !mcommon_string_status_from_append (state->append); } static void mcommon_json_append_visit_corrupt (const bson_iter_t *iter, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); state->is_corrupt = true; } static bool mcommon_json_append_visit_code ( const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); if (!mcommon_in_range_unsigned (uint32_t, v_code_len)) { mcommon_string_append_overflow (state->append); return true; } return !mcommon_json_append_value_code (state->append, v_code, (uint32_t) v_code_len); } static bool mcommon_json_append_visit_symbol ( const bson_iter_t *iter, const char *key, size_t v_symbol_len, const char *v_symbol, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); if (!mcommon_in_range_unsigned (uint32_t, v_symbol_len)) { mcommon_string_append_overflow (state->append); return true; } return !mcommon_json_append_value_symbol (state->append, v_symbol, (uint32_t) v_symbol_len, state->mode); } static bool mcommon_json_append_visit_codewscope ( const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, const bson_t *v_scope, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); if (!mcommon_in_range_unsigned (uint32_t, v_code_len)) { mcommon_string_append_overflow (state->append); return true; } if (mcommon_json_append_value_codewscope ( state->append, v_code, (uint32_t) v_code_len, v_scope, state->mode, state->max_depth)) { return !mcommon_string_status_from_append (state->append); } else { state->is_corrupt = true; return true; } } static bool mcommon_json_append_visit_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); if (mcommon_json_append_bson_document (state->append, v_document, state->mode, state->max_depth)) { return !mcommon_string_status_from_append (state->append); } else { state->is_corrupt = true; return true; } } static bool mcommon_json_append_visit_array (const bson_iter_t *iter, const char *key, const bson_t *v_array, void *data) { mcommon_json_append_visit_t *state = data; BSON_UNUSED (iter); BSON_UNUSED (key); if (mcommon_json_append_bson_array (state->append, v_array, state->mode, state->max_depth)) { return !mcommon_string_status_from_append (state->append); } else { state->is_corrupt = true; return true; } } bool mcommon_json_append_bson_values ( mcommon_string_append_t *append, const bson_t *bson, bson_json_mode_t mode, bool has_keys, unsigned max_depth) { mcommon_json_append_visit_t state = {.append = append, .max_depth = max_depth, .mode = mode, .has_keys = has_keys}; bson_iter_t iter; if (!bson_iter_init (&iter, bson)) { return false; } static const bson_visitor_t visitors = { mcommon_json_append_visit_before, mcommon_json_append_visit_after, mcommon_json_append_visit_corrupt, mcommon_json_append_visit_double, mcommon_json_append_visit_utf8, mcommon_json_append_visit_document, mcommon_json_append_visit_array, mcommon_json_append_visit_binary, mcommon_json_append_visit_undefined, mcommon_json_append_visit_oid, mcommon_json_append_visit_bool, mcommon_json_append_visit_date_time, mcommon_json_append_visit_null, mcommon_json_append_visit_regex, mcommon_json_append_visit_dbpointer, mcommon_json_append_visit_code, mcommon_json_append_visit_symbol, mcommon_json_append_visit_codewscope, mcommon_json_append_visit_int32, mcommon_json_append_visit_timestamp, mcommon_json_append_visit_int64, mcommon_json_append_visit_maxkey, mcommon_json_append_visit_minkey, NULL, /* visit_unsupported_type */ mcommon_json_append_visit_decimal128, }; /* Note that early exit from bson_iter_visit_all does not affect our success, which is based only on BSON validity. * BSON errors will set is_corrupt if they prevent full traversal, but non-fatal parse errors (like invalid UTF-8) * may let bson_iter_visit_all() succeed while leaving an error status in iter.err_off. */ (void) bson_iter_visit_all (&iter, &visitors, &state); return iter.err_off == 0 && !state.is_corrupt; } static BSON_INLINE bool mcommon_json_append_bson_container (mcommon_string_append_t *append, const bson_t *bson, bson_json_mode_t mode, unsigned max_depth, bool has_keys, const char *empty, const char *begin_non_empty, const char *end_non_empty, const char *omitted) { // Note that the return value here is bson validity, not append status. if (bson_empty (bson)) { (void) mcommon_string_append (append, empty); return true; } else if (max_depth == 0) { (void) mcommon_string_append (append, omitted); return true; } else { (void) mcommon_string_append (append, begin_non_empty); bool result = mcommon_json_append_bson_values (append, bson, mode, has_keys, max_depth - 1u); (void) mcommon_string_append (append, end_non_empty); return result; } } bool mcommon_json_append_bson_document (mcommon_string_append_t *append, const bson_t *bson, bson_json_mode_t mode, unsigned max_depth) { return mcommon_json_append_bson_container (append, bson, mode, max_depth, true, "{ }", "{ ", " }", "{ ... }"); } bool mcommon_json_append_bson_array (mcommon_string_append_t *append, const bson_t *bson, bson_json_mode_t mode, unsigned max_depth) { return mcommon_json_append_bson_container (append, bson, mode, max_depth, false, "[ ]", "[ ", " ]", "[ ... ]"); } /** * @brief Like mcommon_string_append_printf (append, "\\u%04x", c) but intended to be more optimizable. */ static BSON_INLINE bool mcommon_json_append_hex_char (mcommon_string_append_t *append, uint16_t c) { static const char digit_table[] = "0123456789abcdef"; char hex_char[6]; hex_char[0] = '\\'; hex_char[1] = 'u'; hex_char[2] = digit_table[0xf & (c >> 12)]; hex_char[3] = digit_table[0xf & (c >> 8)]; hex_char[4] = digit_table[0xf & (c >> 4)]; hex_char[5] = digit_table[0xf & c]; return mcommon_string_append_bytes (append, hex_char, 6); } /** * @brief Test whether a byte may require special processing in mcommon_json_append_escaped. * @returns true for bytes in the range 0x00 - 0x1F, '\\', '\"', and 0xC0. */ static BSON_INLINE bool mcommon_json_append_escaped_considers_byte_as_special (uint8_t byte) { static const uint64_t table[4] = { 0x00000004ffffffffull, // 0x00-0x1F (control), 0x22 (") 0x0000000010000000ull, // 0x5C (') 0x0000000000000000ull, // none 0x0000000000000001ull, // 0xC0 (Possible two-byte NUL) }; return 0 != (table[byte >> 6] & (1ull << (byte & 0x3f))); } /** * @brief Measure the number of consecutive non-special bytes. */ static BSON_INLINE uint32_t mcommon_json_append_escaped_count_non_special_bytes (const char *str, uint32_t len) { uint32_t result = 0; // Good candidate for architecture-specific optimizations. // SSE4 strcspn is nearly what we want, but our table of special bytes would be too large (34 > 16) while (len) { if (mcommon_json_append_escaped_considers_byte_as_special ((uint8_t) *str)) { break; } result++; str++; len--; } return result; } bool mcommon_json_append_escaped (mcommon_string_append_t *append, const char *str, uint32_t len, bool allow_nul) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (str); // Repeatedly handle runs of zero or more non-special bytes punctuated by a potentially-special sequence. uint32_t non_special_len = mcommon_json_append_escaped_count_non_special_bytes (str, len); while (len) { if (!mcommon_string_append_bytes (append, str, non_special_len)) { return false; } str += non_special_len; len -= non_special_len; if (len) { char c = *str; switch (c) { case '"': if (!mcommon_string_append (append, "\\\"")) { return false; } break; case '\\': if (!mcommon_string_append (append, "\\\\")) { return false; } break; case '\b': if (!mcommon_string_append (append, "\\b")) { return false; } break; case '\f': if (!mcommon_string_append (append, "\\f")) { return false; } break; case '\n': if (!mcommon_string_append (append, "\\n")) { return false; } break; case '\r': if (!mcommon_string_append (append, "\\r")) { return false; } break; case '\t': if (!mcommon_string_append (append, "\\t")) { return false; } break; case '\0': if (!allow_nul || !mcommon_json_append_hex_char (append, 0)) { return false; } break; case '\xc0': // Could be a 2-byte NUL, or could begin another non-special run if (len >= 2 && str[1] == '\x80') { if (!allow_nul || !mcommon_json_append_hex_char (append, 0)) { return false; } str++; len--; } else { // Wasn't "C0 80". Begin a non-special run with the "C0" byte, which is usually special. non_special_len = mcommon_json_append_escaped_count_non_special_bytes (str + 1, len - 1) + 1; continue; } break; default: BSON_ASSERT (c > 0x00 && c < 0x20); if (!mcommon_json_append_hex_char (append, c)) { return false; } break; } str++; len--; non_special_len = mcommon_json_append_escaped_count_non_special_bytes (str, len); } } return mcommon_string_status_from_append (append); } bool mcommon_iso8601_string_append (mcommon_string_append_t *append, int64_t msec_since_epoch) { time_t t; int64_t msec_part; char buf[64]; msec_part = msec_since_epoch % 1000; t = (time_t) (msec_since_epoch / 1000); #ifdef BSON_HAVE_GMTIME_R { struct tm posix_date; gmtime_r (&t, &posix_date); strftime (buf, sizeof buf, "%Y-%m-%dT%H:%M:%S", &posix_date); } #elif defined(_MSC_VER) { /* Windows gmtime_s is thread-safe */ struct tm time_buf; gmtime_s (&time_buf, &t); strftime (buf, sizeof buf, "%Y-%m-%dT%H:%M:%S", &time_buf); } #else strftime (buf, sizeof buf, "%Y-%m-%dT%H:%M:%S", gmtime (&t)); #endif if (msec_part) { return mcommon_string_append_printf (append, "%s.%03" PRId64 "Z", buf, msec_part); } else { return mcommon_string_append_printf (append, "%sZ", buf); } } bool mcommon_json_append_value_double (mcommon_string_append_t *append, double value, bson_json_mode_t mode) { /* Determine if legacy (i.e. unwrapped) output should be used. Relaxed mode * will use this for nan and inf values, which we check manually since old * platforms may not have isinf or isnan. */ bool legacy = mode == BSON_JSON_MODE_LEGACY || (mode == BSON_JSON_MODE_RELAXED && !(value != value || value * 0 != 0)); if (!legacy) { mcommon_string_append (append, "{ \"$numberDouble\" : \""); } if (!legacy && value != value) { mcommon_string_append (append, "NaN"); } else if (!legacy && value * 0 != 0) { if (value > 0) { mcommon_string_append (append, "Infinity"); } else { mcommon_string_append (append, "-Infinity"); } } else { const mcommon_string_t *string = mcommon_string_from_append (append); uint32_t start_len = string->len; if (mcommon_string_append_printf (append, "%.20g", value)) { /* ensure trailing ".0" to distinguish "3" from "3.0" */ if (strspn (&string->str[start_len], "0123456789-") == string->len - start_len) { mcommon_string_append (append, ".0"); } } } if (!legacy) { mcommon_string_append (append, "\" }"); } return mcommon_string_status_from_append (append); } bool mcommon_json_append_value_decimal128 (mcommon_string_append_t *append, const bson_decimal128_t *value) { char decimal128_string[BSON_DECIMAL128_STRING]; bson_decimal128_to_string (value, decimal128_string); return mcommon_string_append (append, "{ \"$numberDecimal\" : \"") && mcommon_string_append (append, decimal128_string) && mcommon_string_append (append, "\" }"); } bool mcommon_json_append_value_oid (mcommon_string_append_t *append, const bson_oid_t *value) { return mcommon_string_append (append, "{ \"$oid\" : \"") && mcommon_string_append_oid_as_hex (append, value) && mcommon_string_append (append, "\" }"); } bool mcommon_json_append_value_binary (mcommon_string_append_t *append, bson_subtype_t subtype, const uint8_t *bytes, uint32_t byte_count, bson_json_mode_t mode) { if (mode == BSON_JSON_MODE_CANONICAL || mode == BSON_JSON_MODE_RELAXED) { return mcommon_string_append (append, "{ \"$binary\" : { \"base64\" : \"") && mcommon_string_append_base64_encode (append, bytes, byte_count) && mcommon_string_append_printf (append, "\", \"subType\" : \"%02x\" } }", subtype); } else { return mcommon_string_append (append, "{ \"$binary\" : \"") && mcommon_string_append_base64_encode (append, bytes, byte_count) && mcommon_string_append_printf (append, "\", \"$type\" : \"%02x\" }", subtype); } } bool mcommon_json_append_value_date_time (mcommon_string_append_t *append, int64_t msec_since_epoch, bson_json_mode_t mode) { const int64_t y10k = 253402300800000; // 10000-01-01T00:00:00Z in milliseconds since the epoch. if (mode == BSON_JSON_MODE_CANONICAL || (mode == BSON_JSON_MODE_RELAXED && (msec_since_epoch < 0 || msec_since_epoch >= y10k))) { return mcommon_string_append_printf ( append, "{ \"$date\" : { \"$numberLong\" : \"%" PRId64 "\" } }", msec_since_epoch); } else if (mode == BSON_JSON_MODE_RELAXED) { return mcommon_string_append (append, "{ \"$date\" : \"") && mcommon_iso8601_string_append (append, msec_since_epoch) && mcommon_string_append (append, "\" }"); } else { return mcommon_string_append_printf (append, "{ \"$date\" : %" PRId64 " }", msec_since_epoch); } } bool mcommon_json_append_value_timestamp (mcommon_string_append_t *append, uint32_t timestamp, uint32_t increment) { BSON_ASSERT_PARAM (append); return mcommon_string_append_printf ( append, "{ \"$timestamp\" : { \"t\" : %u, \"i\" : %u } }", timestamp, increment); } bool mcommon_json_append_value_regex (mcommon_string_append_t *append, const char *pattern, uint32_t pattern_len, const char *options, size_t options_len, bson_json_mode_t mode) { if (mode == BSON_JSON_MODE_CANONICAL || mode == BSON_JSON_MODE_RELAXED) { return mcommon_string_append (append, "{ \"$regularExpression\" : { \"pattern\" : \"") && mcommon_json_append_escaped (append, pattern, pattern_len, false) && mcommon_string_append (append, "\", \"options\" : \"") && mcommon_string_append_selected_chars (append, BSON_REGEX_OPTIONS_SORTED, options, options_len) && mcommon_string_append (append, "\" } }"); } else { return mcommon_string_append (append, "{ \"$regex\" : \"") && mcommon_json_append_escaped (append, pattern, pattern_len, false) && mcommon_string_append (append, "\", \"$options\" : \"") && mcommon_string_append_selected_chars (append, BSON_REGEX_OPTIONS_SORTED, options, options_len) && mcommon_string_append (append, "\" }"); } } bool mcommon_json_append_value_dbpointer (mcommon_string_append_t *append, const char *collection, uint32_t collection_len, const bson_oid_t *oid, bson_json_mode_t mode) { if (mode == BSON_JSON_MODE_CANONICAL || mode == BSON_JSON_MODE_RELAXED) { return mcommon_string_append (append, "{ \"$dbPointer\" : { \"$ref\" : \"") && mcommon_json_append_escaped (append, collection, collection_len, false) && mcommon_string_append (append, "\"") && (!oid || (mcommon_string_append (append, ", \"$id\" : ") && mcommon_json_append_value_oid (append, oid))) && mcommon_string_append (append, " } }"); } else { return mcommon_string_append (append, "{ \"$ref\" : \"") && mcommon_json_append_escaped (append, collection, collection_len, false) && mcommon_string_append (append, "\"") && (!oid || (mcommon_string_append (append, ", \"$id\" : \"") && mcommon_string_append_oid_as_hex (append, oid))) && mcommon_string_append (append, "\" }"); } } bool mcommon_json_append_value_code (mcommon_string_append_t *append, const char *code, uint32_t code_len) { return mcommon_string_append (append, "{ \"$code\" : \"") && mcommon_json_append_escaped (append, code, code_len, true) && mcommon_string_append (append, "\" }"); } bool mcommon_json_append_value_codewscope (mcommon_string_append_t *append, const char *code, uint32_t code_len, const bson_t *scope, bson_json_mode_t mode, unsigned max_depth) { // Note that the return value here is bson validity, not append status. (void) mcommon_string_append (append, "{ \"$code\" : \""); (void) mcommon_json_append_escaped (append, code, code_len, true); (void) mcommon_string_append (append, "\", \"$scope\" : "); bool result = mcommon_json_append_bson_document (append, scope, mode, max_depth); (void) mcommon_string_append (append, " }"); return result; } bool mcommon_json_append_value_symbol (mcommon_string_append_t *append, const char *symbol, uint32_t symbol_len, bson_json_mode_t mode) { if (mode == BSON_JSON_MODE_CANONICAL || mode == BSON_JSON_MODE_RELAXED) { return mcommon_string_append (append, "{ \"$symbol\" : \"") && mcommon_json_append_escaped (append, symbol, symbol_len, true) && mcommon_string_append (append, "\" }"); } else { return mcommon_json_append_value_utf8 (append, symbol, symbol_len, true); } } mongodb-1.21.0/src/libmongoc/src/common/src/common-macros-private.h0000644000175100001660000001050214760300420022134 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_MACROS_PRIVATE_H #define MONGO_C_DRIVER_COMMON_MACROS_PRIVATE_H /* Test only assert. Is a noop unless -DENABLE_DEBUG_ASSERTIONS=ON is set * during configuration */ #if defined(MONGOC_ENABLE_DEBUG_ASSERTIONS) && defined(BSON_OS_UNIX) #define MONGOC_DEBUG_ASSERT(statement) BSON_ASSERT (statement) #else #define MONGOC_DEBUG_ASSERT(statement) ((void) 0) #endif #if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #define MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("GCC diagnostic push") #define MC_PRAGMA_DIAGNOSTIC_POP _Pragma ("GCC diagnostic pop") #elif defined(__clang__) #define MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("clang diagnostic push") #define MC_PRAGMA_DIAGNOSTIC_POP _Pragma ("clang diagnostic pop") #elif defined(_MSC_VER) #define MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("warning ( push )") #define MC_PRAGMA_DIAGNOSTIC_POP _Pragma ("warning ( pop )") #else #define MC_PRAGMA_DIAGNOSTIC_PUSH #define MC_PRAGMA_DIAGNOSTIC_POP #endif // `MC_ENABLE_CONVERSION_WARNING_BEGIN` enables -Wconversion to check for potentially unsafe integer conversions. // The `mcommon_in_range_*` functions can help address these warnings by ensuring a cast is within bounds. #if defined(__GNUC__) #define MC_ENABLE_CONVERSION_WARNING_BEGIN MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("GCC diagnostic warning \"-Wconversion\"") #define MC_ENABLE_CONVERSION_WARNING_END MC_PRAGMA_DIAGNOSTIC_POP #elif defined(__clang__) #define MC_ENABLE_CONVERSION_WARNING_BEGIN \ MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("clang diagnostic warning \"-Wconversion\"") #define MC_ENABLE_CONVERSION_WARNING_END MC_PRAGMA_DIAGNOSTIC_POP #else #define MC_ENABLE_CONVERSION_WARNING_BEGIN #define MC_ENABLE_CONVERSION_WARNING_END #endif // Disable the -Wcast-function-type-strict warning. #define MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_BEGIN #define MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_END #if defined(__clang__) #if __has_warning("-Wcast-function-type-strict") #undef MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_BEGIN #undef MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_END #define MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_BEGIN \ MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("clang diagnostic ignored \"-Wcast-function-type-strict\"") #define MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_END MC_PRAGMA_DIAGNOSTIC_POP #endif // __has_warning("-Wcast-function-type-strict") #endif // defined(__clang__) #if defined(__GNUC__) #define BEGIN_IGNORE_DEPRECATIONS \ MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #define END_IGNORE_DEPRECATIONS MC_PRAGMA_DIAGNOSTIC_POP #elif defined(__clang__) #define BEGIN_IGNORE_DEPRECATIONS \ MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("clang diagnostic ignored \"-Wdeprecated-declarations\"") #define END_IGNORE_DEPRECATIONS MC_PRAGMA_DIAGNOSTIC_PUSH #else #define BEGIN_IGNORE_DEPRECATIONS #define END_IGNORE_DEPRECATIONS #endif // Disable the -Wimplicit warning (including -Wimplicit-int and -Wimplicit-function-declaration). #if defined(__GNUC__) #define MC_DISABLE_IMPLICIT_WARNING_BEGIN MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("GCC diagnostic ignored \"-Wimplicit\"") #define MC_DISABLE_IMPLICIT_WARNING_END MC_PRAGMA_DIAGNOSTIC_POP #elif defined(__clang__) #define MC_DISABLE_IMPLICIT_WARNING_BEGIN MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("clang diagnostic ignored \"-Wimplicit\"") #define MC_DISABLE_IMPLICIT_WARNING_END MC_PRAGMA_DIAGNOSTIC_POP #elif defined(_MSC_VER) #define MC_DISABLE_IMPLICIT_WARNING_BEGIN MC_PRAGMA_DIAGNOSTIC_PUSH _Pragma ("warning (disable : 4013 4431)") #define MC_DISABLE_IMPLICIT_WARNING_END MC_PRAGMA_DIAGNOSTIC_POP #else #define MC_DISABLE_IMPLICIT_WARNING_BEGIN #define MC_DISABLE_IMPLICIT_WARNING_END #endif #endif /* MONGO_C_DRIVER_COMMON_MACROS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-md5-private.h0000644000175100001660000000222014760300420021333 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_MD5_PRIVATE_H #define MONGO_C_DRIVER_COMMON_MD5_PRIVATE_H #include BSON_BEGIN_DECLS #define mcommon_md5_init COMMON_NAME (md5_init) #define mcommon_md5_append COMMON_NAME (md5_append) #define mcommon_md5_finish COMMON_NAME (md5_finish) void mcommon_md5_init (bson_md5_t *pms); void mcommon_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes); void mcommon_md5_finish (bson_md5_t *pms, uint8_t digest[16]); BSON_END_DECLS #endif /* MONGO_C_DRIVER_COMMON_MD5_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-md5.c0000644000175100001660000003106414760300420017666 0ustar /* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ /* * The following MD5 implementation has been modified to use types as * specified in libbson. */ #include #include #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #if BSON_BYTE_ORDER == BSON_BIG_ENDIAN #define BYTE_ORDER 1 #else #define BYTE_ORDER -1 #endif #define T_MASK ((uint32_t) ~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void bson_md5_process (bson_md5_t *md5, const uint8_t *data) { uint32_t a = md5->abcd[0]; uint32_t b = md5->abcd[1]; uint32_t c = md5->abcd[2]; uint32_t d = md5->abcd[3]; uint32_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ uint32_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ uint32_t xbuf[16]; const uint32_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const uint8_t *) &w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!(((uintptr_t) data) & 3u)) { /* data are properly aligned */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wcast-align" #endif X = (const uint32_t *) data; #ifdef __clang__ #pragma clang diagnostic pop #endif } else { /* not aligned */ memcpy (xbuf, data, sizeof (xbuf)); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const uint8_t *xp = data; int i; #if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ #else #define xbuf X /* (static only) */ #endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + F (b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT (t, s) + b /* Do the following 16 operations. */ SET (a, b, c, d, 0, 7, T1); SET (d, a, b, c, 1, 12, T2); SET (c, d, a, b, 2, 17, T3); SET (b, c, d, a, 3, 22, T4); SET (a, b, c, d, 4, 7, T5); SET (d, a, b, c, 5, 12, T6); SET (c, d, a, b, 6, 17, T7); SET (b, c, d, a, 7, 22, T8); SET (a, b, c, d, 8, 7, T9); SET (d, a, b, c, 9, 12, T10); SET (c, d, a, b, 10, 17, T11); SET (b, c, d, a, 11, 22, T12); SET (a, b, c, d, 12, 7, T13); SET (d, a, b, c, 13, 12, T14); SET (c, d, a, b, 14, 17, T15); SET (b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + G (b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT (t, s) + b /* Do the following 16 operations. */ SET (a, b, c, d, 1, 5, T17); SET (d, a, b, c, 6, 9, T18); SET (c, d, a, b, 11, 14, T19); SET (b, c, d, a, 0, 20, T20); SET (a, b, c, d, 5, 5, T21); SET (d, a, b, c, 10, 9, T22); SET (c, d, a, b, 15, 14, T23); SET (b, c, d, a, 4, 20, T24); SET (a, b, c, d, 9, 5, T25); SET (d, a, b, c, 14, 9, T26); SET (c, d, a, b, 3, 14, T27); SET (b, c, d, a, 8, 20, T28); SET (a, b, c, d, 13, 5, T29); SET (d, a, b, c, 2, 9, T30); SET (c, d, a, b, 7, 14, T31); SET (b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti) \ t = a + H (b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT (t, s) + b /* Do the following 16 operations. */ SET (a, b, c, d, 5, 4, T33); SET (d, a, b, c, 8, 11, T34); SET (c, d, a, b, 11, 16, T35); SET (b, c, d, a, 14, 23, T36); SET (a, b, c, d, 1, 4, T37); SET (d, a, b, c, 4, 11, T38); SET (c, d, a, b, 7, 16, T39); SET (b, c, d, a, 10, 23, T40); SET (a, b, c, d, 13, 4, T41); SET (d, a, b, c, 0, 11, T42); SET (c, d, a, b, 3, 16, T43); SET (b, c, d, a, 6, 23, T44); SET (a, b, c, d, 9, 4, T45); SET (d, a, b, c, 12, 11, T46); SET (c, d, a, b, 15, 16, T47); SET (b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + I (b, c, d) + X[k] + Ti; \ a = ROTATE_LEFT (t, s) + b /* Do the following 16 operations. */ SET (a, b, c, d, 0, 6, T49); SET (d, a, b, c, 7, 10, T50); SET (c, d, a, b, 14, 15, T51); SET (b, c, d, a, 5, 21, T52); SET (a, b, c, d, 12, 6, T53); SET (d, a, b, c, 3, 10, T54); SET (c, d, a, b, 10, 15, T55); SET (b, c, d, a, 1, 21, T56); SET (a, b, c, d, 8, 6, T57); SET (d, a, b, c, 15, 10, T58); SET (c, d, a, b, 6, 15, T59); SET (b, c, d, a, 13, 21, T60); SET (a, b, c, d, 4, 6, T61); SET (d, a, b, c, 11, 10, T62); SET (c, d, a, b, 2, 15, T63); SET (b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ md5->abcd[0] += a; md5->abcd[1] += b; md5->abcd[2] += c; md5->abcd[3] += d; } void mcommon_md5_init (bson_md5_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void mcommon_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes) { const uint8_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; uint32_t nbits = (uint32_t) (nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy (pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; bson_md5_process (pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) bson_md5_process (pms, p); /* Process a final partial block. */ if (left) memcpy (pms->buf, p, left); } void mcommon_md5_finish (bson_md5_t *pms, uint8_t digest[16]) { static const uint8_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (uint8_t) (pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ mcommon_md5_append (pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ mcommon_md5_append (pms, data, sizeof (data)); for (i = 0; i < 16; ++i) digest[i] = (uint8_t) (pms->abcd[i >> 2] >> ((i & 3) << 3)); } mongodb-1.21.0/src/libmongoc/src/common/src/common-oid-private.h0000644000175100001660000000170614760300420021431 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_OID_PRIVATE_H #define MONGO_C_DRIVER_COMMON_OID_PRIVATE_H #include BSON_BEGIN_DECLS extern const bson_oid_t kZeroObjectId; void mcommon_oid_set_zero (bson_oid_t *oid); bool mcommon_oid_is_zero (const bson_oid_t *oid); BSON_END_DECLS #endif /* MONGO_C_DRIVER_COMMON_OID_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-oid.c0000644000175100001660000000162014760300420017747 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include const bson_oid_t kZeroObjectId = {{0}}; void mcommon_oid_set_zero (bson_oid_t *oid) { BSON_ASSERT (oid); memset (oid, 0, sizeof *oid); } bool mcommon_oid_is_zero (const bson_oid_t *oid) { BSON_ASSERT (oid); return bson_oid_equal_unsafe (oid, &kZeroObjectId); } mongodb-1.21.0/src/libmongoc/src/common/src/common-prelude.h0000644000175100001660000000210014760300420020633 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(MONGOC_INSIDE) && !defined(MONGOC_COMPILATION) && !defined(BSON_COMPILATION) && !defined(BSON_INSIDE) #error "Only or can be included directly." #endif #define COMMON_NAME_1(a, b) COMMON_NAME_2 (a, b) #define COMMON_NAME_2(a, b) a##_##b #if defined(MCOMMON_NAME_PREFIX) && !defined(__INTELLISENSE__) #define COMMON_NAME(Name) COMMON_NAME_1 (MCOMMON_NAME_PREFIX, Name) #else #define COMMON_NAME(Name) COMMON_NAME_1 (mcommon, Name) #endif mongodb-1.21.0/src/libmongoc/src/common/src/common-string-private.h0000644000175100001660000006556314760300420022177 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_STRING_PRIVATE_H #define MONGO_C_DRIVER_COMMON_STRING_PRIVATE_H #include #include #include /* Until the deprecated bson_string_t is removed, this must have the same members in the same order, so we can safely * cast between the two types. Afterward, we are free to modify the memory layout as needed. * * In mcommon_string_t, 'str' is guaranteed to be NUL terminated and SHOULD be valid UTF-8. mcommon_string_t operations * MUST maintain the validity of valid UTF-8 strings. * * Unused portions of the buffer may be uninitialized, and must not be compared or copied. * * 'len' is measured in bytes, not including the NUL terminator. * * 'alloc' is the actual length of the bson_malloc() allocation in bytes, including the required space for NUL * termination. * * When we use 'capacity', it refers to the largest 'len' that the buffer could store. alloc == capacity + 1. */ typedef struct mcommon_string_t { char *str; uint32_t len; uint32_t alloc; } mcommon_string_t; /* Parameters and outcome for a bounded append operation on a mcommon_string_t. Individual type-specific append * functions can consume this struct to communicate bounds info. "max_len_exceeded" can be tested any time an * algorithmic exit is convenient; the actual appended content will be limited by max_len. Truncation is guaranteed not * to split a valid UTF-8 byte sequence. * * Members are here to support inline definitions; not intended for direct access. * * Multiple mcommon_string_append_t may simultaneously refer to the same 'string' but this usage is not recommended. * * 'max_len_exceeded' only includes operations undertaken on this specific mcommon_string_append_t. It will not be set * if the string was already overlong, or if a different mcommon_string_append_t experiences an overage. */ typedef struct mcommon_string_append_t { mcommon_string_t *_string; uint32_t _max_len; bool _max_len_exceeded; } mcommon_string_append_t; #define mcommon_string_new_with_capacity COMMON_NAME (string_new_with_capacity) #define mcommon_string_new_with_buffer COMMON_NAME (string_new_with_buffer) #define mcommon_string_destroy COMMON_NAME (string_destroy) #define mcommon_string_destroy_with_steal COMMON_NAME (string_destroy_with_steal) #define mcommon_string_grow_to_capacity COMMON_NAME (string_grow_to_capacity) #define mcommon_string_append_selected_chars COMMON_NAME (string_append_selected_chars) #define mcommon_string_append_bytes_internal COMMON_NAME (string_append_bytes_internal) #define mcommon_string_append_bytes_all_or_none COMMON_NAME (string_append_bytes_all_or_none) #define mcommon_string_append_unichar_internal COMMON_NAME (string_append_unichar_internal) #define mcommon_string_append_base64_encode COMMON_NAME (string_append_base64_encode) #define mcommon_string_append_oid_as_hex COMMON_NAME (string_append_oid_as_hex) #define mcommon_string_append_printf COMMON_NAME (string_append_printf) #define mcommon_string_append_vprintf COMMON_NAME (string_append_vprintf) bool mcommon_string_append_bytes_internal (mcommon_string_append_t *append, const char *str, uint32_t len); bool mcommon_string_append_unichar_internal (mcommon_string_append_t *append, bson_unichar_t unichar); /** * @brief Allocate a new mcommon_string_t with a copy of the supplied initializer string and an explicit buffer * capacity. * * @param str Initializer string, should be valid UTF-8. * @param length Length of initializer string, in bytes. * @param min_capacity Minimum string capacity, in bytes, the buffer must be able to store without reallocating. Does * not include the NUL terminator. Must be less than UINT32_MAX. * @returns A new mcommon_string_t that must be freed with mcommon_string_destroy() or * mcommon_string_destroy_with_steal() and bson_free(). It will hold 'str' in its entirety, even if the requested * min_capacity was smaller. */ mcommon_string_t * mcommon_string_new_with_capacity (const char *str, uint32_t length, uint32_t min_capacity); /** * @brief Allocate a new mcommon_string_t with a copy of the supplied initializer string and a minimum-capacity buffer * * @param str NUL terminated string, should be valid UTF-8. Must be less than UINT32_MAX bytes long, overlong input * causes a runtime assertion failure. * @returns A new mcommon_string_t that must be freed with mcommon_string_destroy() or * mcommon_string_destroy_with_steal() and bson_free(). */ static BSON_INLINE mcommon_string_t * mcommon_string_new (const char *str) { BSON_ASSERT_PARAM (str); size_t length = strlen (str); BSON_ASSERT (mcommon_in_range_unsigned (uint32_t, length) && (uint32_t) length < UINT32_MAX); return mcommon_string_new_with_capacity (str, (uint32_t) length, 0); } /** * @brief Allocate a new mcommon_string_t, taking ownership of an existing buffer * * @param buffer Buffer to adopt, suitable for bson_free() and bson_realloc(). * @param length Length of the string data, in bytes, not including the required NUL terminator. If string data is * present, it should be valid UTF-8. * @param alloc Actual allocated size of the buffer, in bytes, including room for NUL termination. * @returns A new mcommon_string_t that must be freed with mcommon_string_destroy() or * mcommon_string_destroy_with_steal() and bson_free(). */ mcommon_string_t * mcommon_string_new_with_buffer (char *buffer, uint32_t length, uint32_t alloc); /** * @brief Deallocate a mcommon_string_t and its internal buffer * @param string String allocated with mcommon_string_new, or NULL. */ void mcommon_string_destroy (mcommon_string_t *string); /** * @brief Deallocate a mcommon_string_t and return its internal buffer as a NUL-terminated C string. * @param string String allocated with mcommon_string_new, or NULL. * @returns A freestanding NUL-terminated string in a buffer that must be freed with bson_free(), or NULL if 'string' * was NULL. */ char * mcommon_string_destroy_with_steal (mcommon_string_t *string); /** * @brief Truncate the string to zero length without deallocating the buffer * @param string String to clear */ static BSON_INLINE void mcommon_string_clear (mcommon_string_t *string) { BSON_ASSERT_PARAM (string); string->len = 0; string->str[0] = '\0'; } /** * @brief Test if the string has zero length * @param string String to test */ static BSON_INLINE bool mcommon_string_is_empty (const mcommon_string_t *string) { BSON_ASSERT_PARAM (string); return string->len == 0; } /** * @brief Test if the string begins with a C string * @param string mcommon_string_t to test * @param substring prefix to match, as a NUL terminated C string. */ static BSON_INLINE bool mcommon_string_starts_with_str (const mcommon_string_t *string, const char *substring) { BSON_ASSERT_PARAM (string); BSON_ASSERT_PARAM (substring); size_t substring_len = strlen (substring); uint32_t string_len = string->len; if (mcommon_in_range_unsigned (uint32_t, substring_len) && (uint32_t) substring_len <= string_len) { return 0 == memcmp (string->str, substring, substring_len); } else { return false; } } /** * @brief Test if the string ends with a C string * @param string mcommon_string_t to test * @param substring suffix to match, as a NUL terminated C string. */ static BSON_INLINE bool mcommon_string_ends_with_str (const mcommon_string_t *string, const char *substring) { BSON_ASSERT_PARAM (string); BSON_ASSERT_PARAM (substring); size_t substring_len = strlen (substring); uint32_t string_len = string->len; if (mcommon_in_range_unsigned (uint32_t, substring_len) && (uint32_t) substring_len <= string_len) { uint32_t offset = string_len - (uint32_t) substring_len; return 0 == memcmp (string->str + offset, substring, substring_len); } else { return false; } } /** * @brief Grow a mcommon_string_t buffer if necessary to ensure a minimum capacity * * @param string String allocated with mcommon_string_new * @param capacity Minimum string length, in bytes, the buffer must be able to store without reallocating. Does not * include the NUL terminator. Must be less than UINT32_MAX. * * If a reallocation is necessary, the actual allocation size will be chosen as the next highest power-of-two above the * minimum needed to store 'capacity' as well as the NUL terminator. */ void mcommon_string_grow_to_capacity (mcommon_string_t *string, uint32_t capacity); /** * @brief Set an append operation for this string, with an explicit length limit * @param string String allocated with mcommon_string_new * @param new_append Pointer to an uninitialized mcommon_string_append_t * @param max_len Maximum allowed length for the resulting string, in bytes. Must be less than UINT32_MAX. * * The mcommon_string_append_t does not need to be deallocated. It is no longer usable if the underlying * mcommon_string_t is freed. * * If the string was already over maximum length, it will not be modified. All append operations are guaranteed not to * lengthen the string beyond max_len. Truncations are guaranteed to happen at UTF-8 code point boundaries. */ static BSON_INLINE void mcommon_string_set_append_with_limit (mcommon_string_t *string, mcommon_string_append_t *new_append, uint32_t max_len) { BSON_ASSERT_PARAM (string); BSON_ASSERT_PARAM (new_append); BSON_ASSERT (max_len < UINT32_MAX); new_append->_string = string; new_append->_max_len = max_len; new_append->_max_len_exceeded = false; } /** * @brief Set an append operation for this string * @param string String allocated with mcommon_string_new * @param new_append Pointer to an uninitialized mcommon_string_append_t * * The mcommon_string_append_t does not need to be deallocated. It is no longer usable if the underlying * mcommon_string_t is freed. * * The maximum string length will be set to the largest representable by the data type, UINT32_MAX - 1. */ static BSON_INLINE void mcommon_string_set_append (mcommon_string_t *string, mcommon_string_append_t *new_append) { BSON_ASSERT_PARAM (string); BSON_ASSERT_PARAM (new_append); mcommon_string_set_append_with_limit (string, new_append, UINT32_MAX - 1u); } /** * @brief Allocate an empty mcommon_string_t with the specified initial capacity, and set an append operation for it * with maximum length * @param new_append Pointer to an uninitialized mcommon_string_append_t * @param capacity Initial capacity for the string, in bytes, not including NUL termination * * Allocates a new mcommon_string_t, which will need to be deallocated by the caller. * The mcommon_string_append_t itself does not need to be deallocated. * * The initial mcommon_string_t buffer will be allocated to have room for the given number of string bytes, not * including the NUL terminator. The maximum append length will be set to the largest representable by the data type, * UINT32_MAX - 1. * * This is a shortcut for mcommon_string_new_with_capacity() combined with mcommon_string_set_append(). */ static BSON_INLINE void mcommon_string_new_with_capacity_as_append (mcommon_string_append_t *new_append, uint32_t capacity) { BSON_ASSERT_PARAM (new_append); mcommon_string_set_append (mcommon_string_new_with_capacity ("", 0, capacity), new_append); } /** * @brief Allocate an empty mcommon_string_t with default initial capacity, and set an append operation for it with * maximum length * @param new_append Pointer to an uninitialized mcommon_string_append_t * * Allocates a new mcommon_string_t, which will need to be deallocated by the caller. * The mcommon_string_append_t itself does not need to be deallocated. * * The maximum string length will be set to the largest representable by the data type, UINT32_MAX - 1. * The new string will be allocated with a small default capacity. * * This method is intended to be the most convenient way to start growing a string. If a reasonable guess * can be made about the final size of the string, it's better to call mcommon_string_new_with_capacity_as_append() * or mcommon_string_new_with_capacity() and mcommon_string_set_append(). */ static BSON_INLINE void mcommon_string_new_as_append (mcommon_string_append_t *new_append) { BSON_ASSERT_PARAM (new_append); mcommon_string_new_with_capacity_as_append (new_append, 32); } /** * @brief Begin appending to a new empty mcommon_string_t with a given capacity and a matching max append length. * @param new_append Pointer to an uninitialized mcommon_string_append_t * @param capacity Fixed capacity for the string, in bytes, not including NUL termination * * Allocates a new mcommon_string_t, which will need to be deallocated by the caller. * The mcommon_string_append_t itself does not need to be deallocated. * The string buffer will not need to resize for operations performed through the resulting mcommon_string_append_t. */ static BSON_INLINE void mcommon_string_new_as_fixed_capacity_append (mcommon_string_append_t *new_append, uint32_t capacity) { BSON_ASSERT_PARAM (new_append); mcommon_string_set_append_with_limit (mcommon_string_new_with_capacity ("", 0, capacity), new_append, capacity); } /** * @brief Check the status of an append operation. * @param append Append operation, initialized with mcommon_string_set_append * @returns true if the append operation has no permanent error status. false if the max length has been exceeded. */ static BSON_INLINE bool mcommon_string_status_from_append (const mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); return !append->_max_len_exceeded; } /** * @brief Get a mcommon_string_t pointer to a mcommon_string_append_t destination. * @param append Append operation, initialized with mcommon_string_set_append * @returns Pointer to the mcommon_string_t destination. * * The mcommon_string_append_t includes a plain mcommon_string_t pointer with no fixed ownership semantics. * Depending on usage, it may be a string with borrowed ownership or the append operation may be its primary owner. */ static BSON_INLINE mcommon_string_t * mcommon_string_from_append (const mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); return append->_string; } /** * @brief Get the current string buffer for an mcommon_string_append_t destination. * @param append Append operation, initialized with mcommon_string_set_append * @returns String buffer pointer, NUL terminated, invalidated if the string is destroyed and by any operation that may * grow the string. * * Shortcut for mcommon_string_from_append(append)->str */ static BSON_INLINE char * mcommon_str_from_append (const mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); return mcommon_string_from_append (append)->str; } /** * @brief Get the current string length for an mcommon_string_append_t destination. * @param append Append operation, initialized with mcommon_string_set_append * @returns Snapshot of the current string length * * Shortcut for mcommon_string_from_append(append)->len */ static BSON_INLINE uint32_t mcommon_strlen_from_append (const mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); return mcommon_string_from_append (append)->len; } /** * @brief Deallocate the mcommon_string_t destination associated with an mcommon_string_append_t * @param append Append operation, initialized with mcommon_string_set_append * The append operation will no longer be usable after this call. */ static BSON_INLINE void mcommon_string_from_append_destroy (const mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); mcommon_string_destroy (mcommon_string_from_append (append)); } /** * @brief Truncate the append destination string to zero length without deallocating its buffer. * @param append Append operation, initialized with mcommon_string_set_append * This is equivalent to mcommon_string_clear() combined with mcommon_string_from_append(). */ static BSON_INLINE void mcommon_string_from_append_clear (const mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); mcommon_string_clear (mcommon_string_from_append (append)); } /** * @brief Deallocate the mcommon_string_t destination associated with an mcommon_string_append_t and return its internal * buffer * @param append Append operation, initialized with mcommon_string_set_append * @returns A freestanding NUL-terminated string in a buffer that must be freed with bson_free() * The append operation will no longer be usable after this call. */ static BSON_INLINE char * mcommon_string_from_append_destroy_with_steal (const mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); return mcommon_string_destroy_with_steal (mcommon_string_from_append (append)); } /** * @brief Test if the append destination ends with a C string * @param string mcommon_string_append_t with the string to test * @param substring suffix to match, as a NUL terminated C string. */ static BSON_INLINE bool mcommon_string_from_append_ends_with_str (const mcommon_string_append_t *append, const char *substring) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (substring); return mcommon_string_ends_with_str (mcommon_string_from_append (append), substring); } /** * @brief Test if the append destination has zero length * @param string mcommon_string_append_t with the string to test */ static BSON_INLINE bool mcommon_string_from_append_is_empty (const mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); return mcommon_string_is_empty (mcommon_string_from_append (append)); } /** * @brief Signal an explicit overflow during string append * @param append Append operation, initialized with mcommon_string_set_append * * Future calls to mcommon_string_status_from_append() return false, exactly as if an overlong append was attempted and * failed. This should be used for cases when a logical overflow is occurring but it was detected early enough that no * actual append was attempted. */ static BSON_INLINE void mcommon_string_append_overflow (mcommon_string_append_t *append) { BSON_ASSERT_PARAM (append); append->_max_len_exceeded = true; } /** * @brief Append selected characters from a template * @param append Append operation, initialized with mcommon_string_set_append * @param template UTF-8 string listing allowed characters in the desired order * @param selector UTF-8 string that chooses which template characters are appended * @param selector_len Length of the selector string, in bytes * * Sort and filter lists of option characters. The template should list all allowed options in their desired order. * This implementation does not support multi-byte template characters. ASSERTs that each template character is <= * '\x7f'. Selectors may contain untrusted data, template should not. */ bool mcommon_string_append_selected_chars (mcommon_string_append_t *append, const char *template, const char *selector, size_t selector_len); /** * @brief Append a string with known length to the mcommon_string_t * @param append Append operation, initialized with mcommon_string_set_append * @param str String to append a copy of, should be valid UTF-8 * @param len Length of 'str', in bytes * @returns true if the append operation has no permanent error status. false if the max length has been exceeded. * * If the string must be truncated to fit in the limit set by mcommon_string_set_append_with_limit, it will always be * split in-between UTF-8 code points. */ static BSON_INLINE bool mcommon_string_append_bytes (mcommon_string_append_t *append, const char *str, uint32_t len) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (str); if (BSON_UNLIKELY (!mcommon_string_status_from_append (append))) { return false; } mcommon_string_t *string = append->_string; char *buffer = string->str; uint64_t alloc = (uint64_t) string->alloc; uint64_t old_len = (uint64_t) string->len; uint64_t max_len = (uint64_t) append->_max_len; uint64_t new_len = old_len + (uint64_t) len; uint64_t new_len_with_nul = new_len + 1; // Fast path: no truncation, no buffer growing if (BSON_LIKELY (new_len <= max_len && new_len_with_nul <= alloc)) { memcpy (buffer + old_len, str, len); buffer[new_len] = '\0'; string->len = (uint32_t) new_len; return true; } // Other cases are not inlined return mcommon_string_append_bytes_internal (append, str, len); } /** * @brief Append a NUL-terminated UTF-8 string to the mcommon_string_t * @param append Append operation, initialized with mcommon_string_set_append * @param str NUL-terminated string to append a copy of * @returns true if the append operation has no permanent error status. false if the max length has been exceeded. * * If the string must be truncated to fit in the limit set by mcommon_string_set_append_with_limit, it will always be * split in-between UTF-8 code points. */ static BSON_INLINE bool mcommon_string_append (mcommon_string_append_t *append, const char *str) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (str); return mcommon_string_append_bytes (append, str, strlen (str)); } /** * @brief Append an entire string with known length to the mcommon_string_t or fail, without truncating. * @param append Append operation, initialized with mcommon_string_set_append * @param str UTF-8 string to append a copy of * @param len Length of 'str', in bytes * @returns true if the append operation has no permanent error status. false if the max length has been exceeded. * * Atomic version of mcommon_string_append_bytes. If string does not fit completely, it is not truncated. * The destination string is only modified if the entire append operation can be completed. */ bool mcommon_string_append_bytes_all_or_none (mcommon_string_append_t *append, const char *str, uint32_t len); /** * @brief Append an entire NUL-terminated UTF-8 string to the mcommon_string_t or fail, without truncating. * @param append Append operation, initialized with mcommon_string_set_append * @param str NUL-terminated UTF-8 sequence to append a copy of * @returns true if the append operation has no permanent error status. false if the max length has been exceeded. * * Atomic version of mcommon_string_append. If string does not fit completely, it is not truncated. * The destination string is only modified if the entire append operation can be completed. */ static BSON_INLINE bool mcommon_string_append_all_or_none (mcommon_string_append_t *append, const char *str) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (str); return mcommon_string_append_bytes_all_or_none (append, str, strlen (str)); } /** * @brief Append base64 encoded bytes to an mcommon_string_t * @param append Append operation, initialized with mcommon_string_set_append * @param bytes Bytes to be encoded * @param len Number of bytes to encoded * @returns true if the append operation has no permanent error status. false if the max length has been exceeded. */ bool mcommon_string_append_base64_encode (mcommon_string_append_t *append, const uint8_t *bytes, uint32_t len); /** * @brief Append an ObjectId as a hex string * @param append Append operation, initialized with mcommon_string_set_append * @param value bson_oid_t value to copy * @returns true if the append operation has no permanent error status. false if the max length has been exceeded. */ bool mcommon_string_append_oid_as_hex (mcommon_string_append_t *append, const bson_oid_t *value); /** * @brief Append printf() formatted text to a mcommon_string_t * @param append Append operation, initialized with mcommon_string_set_append * @param format printf() format string * @param ... Format string arguments * @returns true if the append operation has no permanent error status, and this operation has succeeded. false if the * max length has been surpassed or this printf() experienced an unrecoverable error. * * Writes the printf() result directly into the mcommon_string_t buffer, growing it as needed. * * If the string must be truncated to fit in the limit set by mcommon_string_set_append_with_limit, it will always be * split in-between UTF-8 code points. */ bool mcommon_string_append_printf (mcommon_string_append_t *append, const char *format, ...) BSON_GNUC_PRINTF (2, 3); /** * @brief Variant of mcommon_string_append_printf() that takes a va_list * @param append Append operation, initialized with mcommon_string_set_append * @param format printf() format string * @param args Format string arguments * @returns true if the append operation has no permanent error status, and this operation has succeeded. false if the * max length has been surpassed or this printf() experienced an unrecoverable error. * * Writes the printf() result directly into the mcommon_string_t buffer, growing it as needed. * * If the string must be truncated to fit in the limit set by mcommon_string_set_append_with_limit, it will always be * split in-between UTF-8 code points. */ bool mcommon_string_append_vprintf (mcommon_string_append_t *append, const char *format, va_list args) BSON_GNUC_PRINTF (2, 0); /** * @brief Append one code point to a mcommon_string_t * @param append Append operation, initialized with mcommon_string_set_append * @param unichar Code point to append, as a bson_unichar_t * @returns true if the append operation has no permanent error status. false if the max length has been exceeded. * * Guaranteed not to truncate. The character will fully append or no change will be made. */ static BSON_INLINE bool mcommon_string_append_unichar (mcommon_string_append_t *append, bson_unichar_t unichar) { BSON_ASSERT_PARAM (append); if (BSON_UNLIKELY (!mcommon_string_status_from_append (append))) { return false; } mcommon_string_t *string = append->_string; BSON_ASSERT (string); char *buffer = string->str; uint64_t alloc = (uint64_t) string->alloc; uint64_t old_len = (uint64_t) string->len; uint64_t max_len = (uint64_t) append->_max_len; // Fast path: single-byte character, no truncation, no buffer growing if (BSON_LIKELY (unichar <= 0x7f)) { uint64_t new_len = old_len + 1; uint64_t new_len_with_nul = new_len + 1; if (BSON_LIKELY (new_len <= max_len && new_len_with_nul <= alloc)) { buffer[old_len] = (char) unichar; buffer[new_len] = '\0'; string->len = new_len; return true; } } // Other cases are not inlined return mcommon_string_append_unichar_internal (append, unichar); } #endif /* MONGO_C_DRIVER_COMMON_STRING_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-string.c0000644000175100001660000003416214760300420020511 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include mcommon_string_t * mcommon_string_new_with_capacity (const char *str, uint32_t length, uint32_t min_capacity) { BSON_ASSERT_PARAM (str); BSON_ASSERT (length < UINT32_MAX && min_capacity < UINT32_MAX); uint32_t capacity = BSON_MAX (length, min_capacity); uint32_t alloc = capacity + 1u; char *buffer = bson_malloc (alloc); memcpy (buffer, str, length); buffer[length] = '\0'; return mcommon_string_new_with_buffer (buffer, length, alloc); } mcommon_string_t * mcommon_string_new_with_buffer (char *buffer, uint32_t length, uint32_t alloc) { BSON_ASSERT_PARAM (buffer); BSON_ASSERT (length < UINT32_MAX && alloc >= length + 1u); BSON_ASSERT (buffer[length] == '\0'); mcommon_string_t *string = bson_malloc0 (sizeof *string); string->str = buffer; string->len = length; string->alloc = alloc; return string; } void mcommon_string_destroy (mcommon_string_t *string) { if (string) { bson_free (mcommon_string_destroy_with_steal (string)); } } char * mcommon_string_destroy_with_steal (mcommon_string_t *string) { if (string) { char *buffer = string->str; BSON_ASSERT (buffer[string->len] == '\0'); bson_free (string); return buffer; } else { return NULL; } } void mcommon_string_grow_to_capacity (mcommon_string_t *string, uint32_t capacity) { BSON_ASSERT_PARAM (string); BSON_ASSERT (capacity < UINT32_MAX); uint32_t min_alloc_needed = capacity + 1u; if (string->alloc < min_alloc_needed) { uint32_t alloc = mcommon_next_power_of_two_u32 (min_alloc_needed); string->str = bson_realloc (string->str, alloc); string->alloc = alloc; } } // Handle cases omitted from the inlined mcommon_string_append_bytes() bool mcommon_string_append_bytes_internal (mcommon_string_append_t *append, const char *str, uint32_t len) { mcommon_string_t *string = append->_string; BSON_ASSERT (string); uint32_t old_len = string->len; uint32_t max_len = append->_max_len; BSON_ASSERT (max_len < UINT32_MAX); uint32_t max_append_len = old_len < max_len ? max_len - old_len : 0; uint32_t truncated_append_len = len; if (len > max_append_len) { // Search for an actual append length, <= the maximum allowed, which preserves UTF-8 validity append->_max_len_exceeded = true; truncated_append_len = mcommon_utf8_truncate_len (str, max_append_len); } uint32_t new_len = old_len + truncated_append_len; BSON_ASSERT (new_len <= max_len); mcommon_string_grow_to_capacity (string, new_len); char *buffer = string->str; memcpy (buffer + old_len, str, truncated_append_len); buffer[new_len] = '\0'; string->len = new_len; return mcommon_string_status_from_append (append); } // Variant of mcommon_string_append_bytes() that grows but never truncates bool mcommon_string_append_bytes_all_or_none (mcommon_string_append_t *append, const char *str, uint32_t len) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (str); if (BSON_UNLIKELY (!mcommon_string_status_from_append (append))) { return false; } mcommon_string_t *string = append->_string; BSON_ASSERT (string); uint32_t old_len = string->len; uint32_t max_len = append->_max_len; BSON_ASSERT (max_len < UINT32_MAX); uint32_t max_append_len = old_len < max_len ? max_len - old_len : 0; if (len > max_append_len) { append->_max_len_exceeded = true; return false; } uint32_t new_len = old_len + len; BSON_ASSERT (new_len <= max_len); mcommon_string_grow_to_capacity (string, new_len); char *buffer = string->str; memcpy (buffer + old_len, str, len); buffer[new_len] = '\0'; string->len = new_len; return mcommon_string_status_from_append (append); } bool mcommon_string_append_unichar_internal (mcommon_string_append_t *append, bson_unichar_t unichar) { mcommon_string_t *string = append->_string; uint32_t old_len = string->len; uint32_t max_len = append->_max_len; BSON_ASSERT (max_len < UINT32_MAX); char max_utf8_sequence[6]; uint32_t max_append_len = old_len < max_len ? max_len - old_len : 0; // Usually we can write the UTF-8 sequence directly if (BSON_LIKELY (max_append_len >= sizeof max_utf8_sequence)) { uint32_t actual_sequence_len; mcommon_string_grow_to_capacity (string, old_len + sizeof max_utf8_sequence); char *buffer = string->str; mcommon_utf8_from_unichar (unichar, buffer + old_len, &actual_sequence_len); BSON_ASSERT (actual_sequence_len <= sizeof max_utf8_sequence); BSON_ASSERT (append->_max_len_exceeded == false); uint32_t new_len = old_len + actual_sequence_len; buffer[new_len] = '\0'; string->len = new_len; return true; } // If we are near max_len, avoid growing the buffer beyond it. uint32_t actual_sequence_len; mcommon_utf8_from_unichar (unichar, max_utf8_sequence, &actual_sequence_len); return mcommon_string_append_bytes_internal (append, max_utf8_sequence, actual_sequence_len); } bool mcommon_string_append_base64_encode (mcommon_string_append_t *append, const uint8_t *bytes, uint32_t len) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (bytes); if (BSON_UNLIKELY (!mcommon_string_status_from_append (append))) { return false; } mcommon_string_t *string = append->_string; uint32_t old_len = string->len; uint32_t max_len = append->_max_len; BSON_ASSERT (max_len < UINT32_MAX); uint32_t max_append_len = old_len < max_len ? max_len - old_len : 0; // Note that mcommon_b64_ntop_calculate_target_size includes room for NUL. // mcommon_b64_ntop includes NUL in the input (buffer size) but not in the return value (string length). size_t encoded_target_len = mcommon_b64_ntop_calculate_target_size ((size_t) len) - 1; if (encoded_target_len <= (size_t) max_append_len) { // No truncation needed. Grow the buffer and encode directly. mcommon_string_grow_to_capacity (string, old_len + encoded_target_len); BSON_ASSERT (encoded_target_len == mcommon_b64_ntop (bytes, (size_t) len, string->str + old_len, encoded_target_len + 1)); BSON_ASSERT (mcommon_in_range_unsigned (uint32_t, encoded_target_len)); string->len = old_len + (uint32_t) encoded_target_len; return true; } else if (max_append_len == 0) { // Truncation to a zero-length append mcommon_string_append_overflow (append); return false; } else { /* We expect to append at least one byte, and truncate. * Encoding only produces single-byte UTF-8 sequences, so the result always has exactly the maximum length. * * mcommon_b64_ntop() can't truncate without failing. To do this without allocating a full size temporary buffer * or rewriting mcommon_b64_ntop, we can partition the write into three parts: a 'direct' portion made from entire * non-truncated units of 3 bytes in and 4 characters out, a truncated 'remainder', and an ignored portion. * Remainders longer than 3 bytes in / 4 bytes out are never necessary, and further portions of the input data * will not be used. */ mcommon_string_grow_to_capacity (string, max_len); char *buffer = string->str; uint32_t remainder_truncated_len = max_append_len % 4; uint32_t direct_encoded_len = max_append_len - remainder_truncated_len; uint32_t direct_input_len = mcommon_b64_pton_calculate_target_size ((size_t) direct_encoded_len); BSON_ASSERT (direct_input_len % 3 == 0); BSON_ASSERT (direct_input_len < len); BSON_ASSERT (direct_encoded_len == mcommon_b64_ntop (bytes, (size_t) direct_input_len, string->str + old_len, direct_encoded_len + 1)); char remainder_buffer[5]; uint32_t remainder_input_len = BSON_MIN (3, len - direct_input_len); BSON_ASSERT (remainder_input_len > 0); uint32_t remainder_encoded_len = mcommon_b64_ntop_calculate_target_size ((size_t) remainder_input_len) - 1; BSON_ASSERT (remainder_encoded_len > remainder_truncated_len); BSON_ASSERT (remainder_encoded_len == mcommon_b64_ntop (bytes + direct_input_len, (size_t) remainder_input_len, remainder_buffer, sizeof remainder_buffer)); memcpy (buffer + old_len + direct_encoded_len, remainder_buffer, remainder_encoded_len); BSON_ASSERT (old_len + direct_encoded_len + remainder_truncated_len == max_len); buffer[max_len] = '\0'; string->len = max_len; mcommon_string_append_overflow (append); return false; } } bool mcommon_string_append_oid_as_hex (mcommon_string_append_t *append, const bson_oid_t *value) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (value); char oid_str[25]; bson_oid_to_string (value, oid_str); return mcommon_string_append (append, oid_str); } bool mcommon_string_append_selected_chars (mcommon_string_append_t *append, const char *template, const char *selector, size_t selector_len) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (template); BSON_ASSERT_PARAM (selector); for (uint8_t template_char; (template_char = (uint8_t) * template); template ++) { BSON_ASSERT (template_char <= 0x7f); if (memchr (selector, template_char, selector_len) && !mcommon_string_append_unichar (append, template_char)) { return false; } } return mcommon_string_status_from_append (append); } bool mcommon_string_append_printf (mcommon_string_append_t *append, const char *format, ...) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (format); va_list args; va_start (args, format); bool ret = mcommon_string_append_vprintf (append, format, args); va_end (args); return ret; } bool mcommon_string_append_vprintf (mcommon_string_append_t *append, const char *format, va_list args) { BSON_ASSERT_PARAM (append); BSON_ASSERT_PARAM (format); if (BSON_UNLIKELY (!mcommon_string_status_from_append (append))) { return false; } mcommon_string_t *string = append->_string; uint32_t old_len = string->len; uint32_t max_len = append->_max_len; BSON_ASSERT (max_len < UINT32_MAX); uint32_t max_append_len = old_len < max_len ? max_len - old_len : 0; // Initial minimum buffer length; increases on retry. uint32_t min_format_buffer_capacity = 16; while (true) { // Allocate room for a format buffer at the end of the string. // It will be at least this round's min_format_buffer_capacity, but if we happen to have extra space allocated we // do want that to be available to vsnprintf(). min_format_buffer_capacity = BSON_MIN (min_format_buffer_capacity, max_append_len); mcommon_string_grow_to_capacity (string, old_len + min_format_buffer_capacity); uint32_t alloc = string->alloc; BSON_ASSERT (alloc > 0 && alloc - 1u >= old_len); char *format_buffer = string->str + old_len; uint32_t actual_format_buffer_capacity = BSON_MIN (alloc - 1u - old_len, max_append_len); BSON_ASSERT (actual_format_buffer_capacity >= min_format_buffer_capacity); BSON_ASSERT (actual_format_buffer_capacity < UINT32_MAX); uint32_t format_buffer_alloc = actual_format_buffer_capacity + 1u; va_list args_copy; va_copy (args_copy, args); int format_result = bson_vsnprintf (format_buffer, format_buffer_alloc, format, args_copy); va_end (args_copy); if (format_result > -1 && mcommon_in_range_signed (uint32_t, format_result) && (uint32_t) format_result <= actual_format_buffer_capacity) { // Successful result, no truncation. format_buffer[format_result] = '\0'; string->len = old_len + (uint32_t) format_result; BSON_ASSERT (string->len <= append->_max_len); BSON_ASSERT (append->_max_len_exceeded == false); return true; } if (actual_format_buffer_capacity == max_append_len) { // No more space to grow into, this must be the final result. if (format_result > -1 && mcommon_in_range_signed (uint32_t, format_result) && (uint32_t) format_result < UINT32_MAX) { // We have truncated output from vsnprintf. Clean it up by removing // any partial UTF-8 sequences that might be left on the end. uint32_t truncated_append_len = mcommon_utf8_truncate_len ( format_buffer, BSON_MIN (actual_format_buffer_capacity, (uint32_t) format_result)); BSON_ASSERT (truncated_append_len <= actual_format_buffer_capacity); format_buffer[truncated_append_len] = '\0'; string->len = old_len + truncated_append_len; append->_max_len_exceeded = true; return false; } // Error from vsnprintf; This operation fails, but we do not set max_len_exceeded. return false; } // Choose a larger format_buffer_len and try again. Length will be clamped to max_append_len above. if (format_result > -1 && mcommon_in_range_signed (uint32_t, format_result) && (uint32_t) format_result < UINT32_MAX) { min_format_buffer_capacity = (uint32_t) format_result + 1u; } else if (min_format_buffer_capacity < UINT32_MAX / 2) { min_format_buffer_capacity *= 2; } else { min_format_buffer_capacity = UINT32_MAX - 1u; } } } mongodb-1.21.0/src/libmongoc/src/common/src/common-thread-private.h0000644000175100001660000001701514760300420022125 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #ifndef MONGO_C_DRIVER_COMMON_THREAD_PRIVATE_H #define MONGO_C_DRIVER_COMMON_THREAD_PRIVATE_H #define BSON_INSIDE #include #include #include #undef BSON_INSIDE BSON_BEGIN_DECLS #define mcommon_thread_create COMMON_NAME (thread_create) #define mcommon_thread_join COMMON_NAME (thread_join) #if defined(BSON_OS_UNIX) #include #define BSON_ONCE_FUN(n) void n (void) #define BSON_ONCE_RETURN return #define BSON_ONCE_INIT PTHREAD_ONCE_INIT #define bson_once(o, c) \ do { \ BSON_ASSERT (pthread_once ((o), (c)) == 0); \ } while (0) #define bson_once_t pthread_once_t #define bson_thread_t pthread_t #define BSON_THREAD_FUN(_function_name, _arg_name) void *(_function_name) (void *(_arg_name)) #define BSON_THREAD_FUN_TYPE(_function_name) void *(*(_function_name)) (void *) #define BSON_THREAD_RETURN return NULL /* this macro can be defined as a as a build configuration option * with -DENABLE_DEBUG_ASSERTIONS=ON. its purpose is to allow for functions * that require a mutex to be locked on entry to assert that the mutex * is actually locked. * this can prevent bugs where a caller forgets to lock the mutex. */ #ifndef MONGOC_ENABLE_DEBUG_ASSERTIONS #define bson_mutex_destroy(m) \ do { \ BSON_ASSERT (pthread_mutex_destroy ((m)) == 0); \ } while (0) #define bson_mutex_init(_n) \ do { \ BSON_ASSERT (pthread_mutex_init ((_n), NULL) == 0); \ } while (0) #define bson_mutex_lock(m) \ do { \ BSON_ASSERT (pthread_mutex_lock ((m)) == 0); \ } while (0) #define bson_mutex_t pthread_mutex_t #define bson_mutex_unlock(m) \ do { \ BSON_ASSERT (pthread_mutex_unlock ((m)) == 0); \ } while (0) #else typedef struct { pthread_t lock_owner; pthread_mutex_t wrapped_mutex; bool valid_tid; } bson_mutex_t; #define bson_mutex_destroy(mutex) \ do { \ BSON_ASSERT (pthread_mutex_destroy (&(mutex)->wrapped_mutex) == 0); \ } while (0); #define bson_mutex_init(mutex) \ do { \ BSON_ASSERT (pthread_mutex_init (&(mutex)->wrapped_mutex, NULL) == 0); \ (mutex)->valid_tid = false; \ } while (0); #define bson_mutex_lock(mutex) \ do { \ BSON_ASSERT (pthread_mutex_lock (&(mutex)->wrapped_mutex) == 0); \ (mutex)->lock_owner = pthread_self (); \ (mutex)->valid_tid = true; \ } while (0); #define bson_mutex_unlock(mutex) \ do { \ (mutex)->valid_tid = false; \ BSON_ASSERT (pthread_mutex_unlock (&(mutex)->wrapped_mutex) == 0); \ } while (0); #endif #else #include #define BSON_ONCE_FUN(n) BOOL CALLBACK n (PINIT_ONCE _ignored_a, PVOID _ignored_b, PVOID *_ignored_c) #define BSON_ONCE_INIT INIT_ONCE_STATIC_INIT #define BSON_ONCE_RETURN return true #define bson_mutex_destroy DeleteCriticalSection #define bson_mutex_init InitializeCriticalSection #define bson_mutex_lock EnterCriticalSection #define bson_mutex_t CRITICAL_SECTION #define bson_mutex_unlock LeaveCriticalSection #define bson_once(o, c) \ do { \ BSON_ASSERT (InitOnceExecuteOnce ((o), (c), NULL, NULL)); \ } while (0) #define bson_once_t INIT_ONCE #define bson_thread_t HANDLE #define BSON_THREAD_FUN(_function_name, _arg_name) unsigned (__stdcall _function_name) (void *(_arg_name)) #define BSON_THREAD_FUN_TYPE(_function_name) unsigned (__stdcall * _function_name) (void *) #define BSON_THREAD_RETURN return 0 #endif /* Functions that require definitions get the common prefix (_mongoc for * libmongoc or _bson for libbson) to avoid duplicate symbols when linking both * libbson and libmongoc statically. */ int mcommon_thread_join (bson_thread_t thread); // mcommon_thread_create returns 0 on success. Returns a non-zero error code on // error. Callers may use `bson_strerror_r` to get an error message from the // returned error code. int mcommon_thread_create (bson_thread_t *thread, BSON_THREAD_FUN_TYPE (func), void *arg); #if defined(MONGOC_ENABLE_DEBUG_ASSERTIONS) && defined(BSON_OS_UNIX) #define mcommon_mutex_is_locked COMMON_NAME (mutex_is_locked) bool mcommon_mutex_is_locked (bson_mutex_t *mutex); #endif /** * @brief A shared mutex (a read-write lock) * * A shared mutex can be locked in 'shared' mode or 'exclusive' mode. Only one * thread may hold exclusive mode at a time. Any number of threads may hold * the lock in shared mode simultaneously. No thread can hold in exclusive mode * while another thread holds in shared mode, and vice-versa. */ typedef struct bson_shared_mutex_t { BSON_IF_WINDOWS (SRWLOCK native;) BSON_IF_POSIX (pthread_rwlock_t native;) } bson_shared_mutex_t; static BSON_INLINE void bson_shared_mutex_init (bson_shared_mutex_t *mtx) { BSON_IF_WINDOWS (InitializeSRWLock (&mtx->native)); BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_init (&mtx->native, NULL) == 0);) } static BSON_INLINE void bson_shared_mutex_destroy (bson_shared_mutex_t *mtx) { BSON_IF_WINDOWS ((void) mtx;) BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_destroy (&mtx->native) == 0);) } static BSON_INLINE void bson_shared_mutex_lock_shared (bson_shared_mutex_t *mtx) { BSON_IF_WINDOWS (AcquireSRWLockShared (&mtx->native);) BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_rdlock (&mtx->native) == 0);) } static BSON_INLINE void bson_shared_mutex_lock (bson_shared_mutex_t *mtx) { BSON_IF_WINDOWS (AcquireSRWLockExclusive (&mtx->native);) BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_wrlock (&mtx->native) == 0);) } static BSON_INLINE void bson_shared_mutex_unlock (bson_shared_mutex_t *mtx) { BSON_IF_WINDOWS (ReleaseSRWLockExclusive (&mtx->native);) BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_unlock (&mtx->native) == 0);) } static BSON_INLINE void bson_shared_mutex_unlock_shared (bson_shared_mutex_t *mtx) { BSON_IF_WINDOWS (ReleaseSRWLockShared (&mtx->native);) BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_unlock (&mtx->native) == 0);) } BSON_END_DECLS #endif /* MONGO_C_DRIVER_COMMON_THREAD_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/common/src/common-thread.c0000644000175100001660000000362114760300420020446 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #if defined(BSON_OS_UNIX) int mcommon_thread_create (bson_thread_t *thread, BSON_THREAD_FUN_TYPE (func), void *arg) { BSON_ASSERT_PARAM (thread); BSON_ASSERT_PARAM (func); BSON_OPTIONAL_PARAM (arg); // optional. return pthread_create (thread, NULL, func, arg); } int mcommon_thread_join (bson_thread_t thread) { return pthread_join (thread, NULL); } #if defined(MONGOC_ENABLE_DEBUG_ASSERTIONS) && defined(BSON_OS_UNIX) bool mcommon_mutex_is_locked (bson_mutex_t *mutex) { return mutex->valid_tid && pthread_equal (pthread_self (), mutex->lock_owner); } #endif #else int mcommon_thread_create (bson_thread_t *thread, BSON_THREAD_FUN_TYPE (func), void *arg) { BSON_ASSERT_PARAM (thread); BSON_ASSERT_PARAM (func); BSON_OPTIONAL_PARAM (arg); // optional. *thread = (HANDLE) _beginthreadex (NULL, 0, func, arg, 0, NULL); if (0 == *thread) { return errno; } return 0; } int mcommon_thread_join (bson_thread_t thread) { int ret; /* zero indicates success for WaitForSingleObject. */ ret = WaitForSingleObject (thread, INFINITE); if (WAIT_OBJECT_0 != ret) { return ret; } /* zero indicates failure for CloseHandle. */ ret = CloseHandle (thread); if (0 == ret) { return 1; } return 0; } #endif mongodb-1.21.0/src/libmongoc/src/common/src/common-utf8-private.h0000644000175100001660000001224414760300420021543 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGO_C_DRIVER_COMMON_UTF8_PRIVATE_H #define MONGO_C_DRIVER_COMMON_UTF8_PRIVATE_H #include /* *-------------------------------------------------------------------------- * * mcommon_utf8_get_sequence -- * * Determine the sequence length of the first UTF-8 character in * @utf8. The sequence length is stored in @seq_length and the mask * for the first character is stored in @first_mask. * * Returns: * None. * * Side effects: * @seq_length is set. * @first_mask is set. * *-------------------------------------------------------------------------- */ static BSON_INLINE void mcommon_utf8_get_sequence (const char *utf8, /* IN */ uint8_t *seq_length, /* OUT */ uint8_t *first_mask) /* OUT */ { unsigned char c = *(const unsigned char *) utf8; uint8_t m; uint8_t n; /* * See the following[1] for a description of what the given multi-byte * sequences will be based on the bits set of the first byte. We also need * to mask the first byte based on that. All subsequent bytes are masked * against 0x3F. * * [1] http://www.joelonsoftware.com/articles/Unicode.html */ if ((c & 0x80) == 0) { n = 1; m = 0x7F; } else if ((c & 0xE0) == 0xC0) { n = 2; m = 0x1F; } else if ((c & 0xF0) == 0xE0) { n = 3; m = 0x0F; } else if ((c & 0xF8) == 0xF0) { n = 4; m = 0x07; } else { n = 0; m = 0; } *seq_length = n; *first_mask = m; } /* *-------------------------------------------------------------------------- * * mcommon_utf8_from_unichar -- * * Converts the unichar to a sequence of utf8 bytes and stores those * in @utf8. The number of bytes in the sequence are stored in @len. * * Parameters: * @unichar: A bson_unichar_t. * @utf8: A location for the multi-byte sequence. * @len: A location for number of bytes stored in @utf8. * * Returns: * None. * * Side effects: * @utf8 is set. * @len is set. * *-------------------------------------------------------------------------- */ static BSON_INLINE void mcommon_utf8_from_unichar (bson_unichar_t unichar, /* IN */ char utf8[BSON_ENSURE_ARRAY_PARAM_SIZE (6)], /* OUT */ uint32_t *len) /* OUT */ { BSON_ASSERT_PARAM (len); if (unichar <= 0x7F) { utf8[0] = unichar; *len = 1; } else if (unichar <= 0x7FF) { *len = 2; utf8[0] = 0xC0 | ((unichar >> 6) & 0x3F); utf8[1] = 0x80 | ((unichar) & 0x3F); } else if (unichar <= 0xFFFF) { *len = 3; utf8[0] = 0xE0 | ((unichar >> 12) & 0xF); utf8[1] = 0x80 | ((unichar >> 6) & 0x3F); utf8[2] = 0x80 | ((unichar) & 0x3F); } else if (unichar <= 0x1FFFFF) { *len = 4; utf8[0] = 0xF0 | ((unichar >> 18) & 0x7); utf8[1] = 0x80 | ((unichar >> 12) & 0x3F); utf8[2] = 0x80 | ((unichar >> 6) & 0x3F); utf8[3] = 0x80 | ((unichar) & 0x3F); } else { *len = 0; } } /* * @brief Calculate a truncation length that preserves UTF-8 validity * @param str String data, at least 'len' bytes long. * @returns A new length <= 'len' * * When 'str' is a valid UTF-8 string with length >= 'len' bytes, * this calculates a new length, less than or equal to 'len', which * guarantees that the string will be truncated in-between code points. */ static BSON_INLINE uint32_t mcommon_utf8_truncate_len (const char *str, uint32_t len) { uint32_t resulting_len = len; while (resulting_len > 0) { if (BSON_LIKELY ((uint8_t) str[resulting_len - 1u] <= 0x7f)) { // Single-byte sequence, always a fine place to stop return resulting_len; } // Search for the last byte that could begin a UTF-8 sequence uint32_t seq_begin_at = resulting_len - 1u; while (((uint8_t) str[seq_begin_at] & 0xc0) == 0x80) { if (seq_begin_at > 0) { seq_begin_at--; } else { return 0; } } uint8_t seq_length, first_mask_unused; mcommon_utf8_get_sequence (str + seq_begin_at, &seq_length, &first_mask_unused); if (seq_begin_at + seq_length == resulting_len) { // Sequence is complete, we can truncate here. return resulting_len; } // Sequence was truncated or invalid; resume search prior to it's beginning. resulting_len = seq_begin_at; } return 0; } #endif /* MONGO_C_DRIVER_COMMON_UTF8_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_azure_request.h0000644000175100001660000001040214760300420024703 0ustar /* * Copyright 2020-present MongoDB, 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. */ #ifndef KMS_AZURE_REQUEST_H #define KMS_AZURE_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif /* Constructs an oauth client credentials grant request for Azure. * See * https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#get-a-token. * * Parameters: * All parameters must be NULL terminated strings. * - host: The value of the Host header. This should be a custom host or * "login.microsoftonline.com". * - scope: The oauth scope. This should be a custom scope or * "https%3A%2F%2Fvault.azure.net%2F.default". Must be URL encoded. * - tenant_id: The Azure tenant ID. * - client_id: The client ID to authenticate. * - client_secret: The client secret to authenticate. * - opt: Additional options. This must have the Azure provider set via * kms_request_opt_set_provider. * * Returns: A new kms_request_t. * Always returns a new kms_request_t, even on error. * Caller must check if an error occurred by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_azure_request_oauth_new (const char *host, const char *scope, const char *tenant_id, const char *client_id, const char *client_secret, const kms_request_opt_t *opt); /* Constructs a wrapkey request for Azure. * See https://docs.microsoft.com/en-us/rest/api/keyvault/wrapkey/wrapkey * * Parameters: * All parameters must be NULL terminated strings. * - host: The value of the Host header, like "mykeyvault.vault.azure.net". * - access_token: The access_token obtained from an oauth response as a * base64url encoded string. * - key_name: The azure key name. * - key_version: An optional key version. May be NULL or empty string. * - plaintext: The plaintext key to encrypt. * - plaintext_len: The number of bytes of plaintext. * - opt: Additional options. This must have the Azure provider set via * kms_request_opt_set_provider. */ KMS_MSG_EXPORT (kms_request_t *) kms_azure_request_wrapkey_new (const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *plaintext, size_t plaintext_len, const kms_request_opt_t *opt); /* Constructs an unwrapkey request for Azure. * See https://docs.microsoft.com/en-us/rest/api/keyvault/unwrapkey/unwrapkey * * Parameters: * All parameters must be NULL terminated strings. * - host: The value of the Host header, like "mykeyvault.vault.azure.net". * - access_token: The access_token obtained from an oauth response as a * base64url encoded string. * - key_name: The azure key name. * - key_version: An optional key version. May be NULL or empty string. * - ciphertext: The ciphertext key to decrypt. * - ciphertext_len: The number of bytes of ciphertext. * - opt: Additional options. This must have the Azure provider set via * kms_request_opt_set_provider. */ KMS_MSG_EXPORT (kms_request_t *) kms_azure_request_unwrapkey_new (const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *ciphertext, size_t ciphertext_len, const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_AZURE_REQUEST_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_b64.h0000644000175100001660000000367114760300420022412 0ustar /* * Copyright 2018-present MongoDB 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. */ #ifndef KMS_MESSAGE_B64_H #define KMS_MESSAGE_B64_H #include "kms_message.h" #include #include #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (void) kms_message_b64_initialize_rmap (void); KMS_MSG_EXPORT (int) kms_message_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize); KMS_MSG_EXPORT (int) kms_message_b64_pton (char const *src, uint8_t *target, size_t targsize); /* src and target may be the same string. Assumes no whitespace in src. */ KMS_MSG_EXPORT (int) kms_message_b64_to_b64url (const char *src, size_t srclength, char *target, size_t targsize); KMS_MSG_EXPORT (int) kms_message_b64url_to_b64 (const char *src, size_t srclength, char *target, size_t targsize); /* Convenience conversions which return copies. */ char * kms_message_raw_to_b64 (const uint8_t *raw, size_t raw_len); uint8_t * kms_message_b64_to_raw (const char *b64, size_t *out); char * kms_message_raw_to_b64url (const uint8_t *raw, size_t raw_len); uint8_t * kms_message_b64url_to_raw (const char *b64url, size_t *out); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_MESSAGE_B64_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_caller_identity_request.h0000644000175100001660000000174514760300420026742 0ustar /* * Copyright 2019-present MongoDB, 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. */ #ifndef KMS_CALLER_IDENTITY_REQUEST_H #define KMS_CALLER_IDENTITY_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (kms_request_t *) kms_caller_identity_request_new (const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_CALLER_IDENTITY_REQUEST_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_decrypt_request.h0000644000175100001660000000204214760300420025230 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_DECRYPT_REQUEST_H #define KMS_DECRYPT_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (kms_request_t *) kms_decrypt_request_new (const uint8_t *ciphertext_blob, size_t len, const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_DECRYPT_REQUEST_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_encrypt_request.h0000644000175100001660000000212714760300420025246 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_ENCRYPT_REQUEST_H #define KMS_ENCRYPT_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (kms_request_t *) kms_encrypt_request_new (const uint8_t *plaintext, size_t plaintext_length, const char *key_id, const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_ENCRYPT_REQUEST_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_gcp_request.h0000644000175100001660000001162214760300420024333 0ustar /* * Copyright 2020-present MongoDB, 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. */ #ifndef KMS_GCP_REQUEST_H #define KMS_GCP_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif /* Constructs an oauth client credentials request for GCP. * See https://developers.google.com/identity/protocols/oauth2/service-account * * Parameters: * - host: The host header, like "oauth2.googleapis.com". * - email: The email for the service account to authenticate. * - audience: The "aud" field in the JSON Web Token (JWT). Should be a URL * like "https://oauth2.googleapis.com/token" * - scope: The "scope" field in the JSON Web Token (JWT). Should be a URL * like "https://www.googleapis.com/auth/cloudkms". * - private_key_data: Bytes pointing to a PKCS#8 private key. * - private_key_len: The length of private_key_data. * - opt: Request options. The provider must be set to KMS_REQUEST_PROVIDER_GCP * with kms_request_opt_set_provider. Callers that want to use a custom crypto * callback to sign the request should set the callback on opt with * kms_request_opt_set_crypto_hook_rsaes_pkcs1_v1_5. * * Returns: A new kms_request_t. * Always returns a new kms_request_t, even on error. * Caller must check if an error occurred by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_gcp_request_oauth_new (const char *host, const char *email, const char *audience, const char *scope, const char *private_key_data, size_t private_key_len, const kms_request_opt_t *opt); /* Constructs the encrypt request for GCP. * See * https://cloud.google.com/kms/docs/encrypt-decrypt#kms-encrypt-symmetric-api * * Parameters: * - host: The value of the Host header, like "cloudkms.googleapis.com". * - project_id: The project id. * - location: The location id, like "global". * - key_ring_name: The key ring name. * - key_name: The key name. * - key_version: The optional key version. May be NULL. * - plaintext: The plaintext key to encrypt. * - plaintext_len: The number of bytes of plaintext. * - opt: Request options. The provider must be set to KMS_REQUEST_PROVIDER_GCP * with kms_request_opt_set_provider. * * Returns: A new kms_request_t. * Always returns a new kms_request_t, even on error. * Caller must check if an error occurred by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_gcp_request_encrypt_new (const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const char *key_version, const uint8_t *plaintext, size_t plaintext_len, const kms_request_opt_t *opt); /* Constructs the decrypt request for GCP. * See * https://cloud.google.com/kms/docs/encrypt-decrypt#kms-decrypt-symmetric-api * * Parameters: * - host: The value of the Host header, like "cloudkms.googleapis.com". * - project_id: The project id. * - location: The location id, like "global". * - key_ring_name: The key ring name. * - key_name: The key name. * - ciphertext: The ciphertext key to encrypt. * - ciphertext_len: The number of bytes of ciphertext. * - opt: Request options. The provider must be set to KMS_REQUEST_PROVIDER_GCP * with kms_request_opt_set_provider. * * Returns: A new kms_request_t. * Always returns a new kms_request_t, even on error. * Caller must check if an error occurred by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_gcp_request_decrypt_new (const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const uint8_t *ciphertext, size_t ciphertext_len, const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_GCP_REQUEST_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_kmip_request.h0000644000175100001660000000516714760300420024531 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_REQUEST_H #define KMS_KMIP_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include #ifdef __cplusplus extern "C" { #endif #define KMS_KMIP_REQUEST_SECRETDATA_LENGTH 96 /* kms_kmip_request_register_secretdata_new creates a KMIP Register request with * a SecretData payload of length KMS_KMIP_REQUEST_SECRETDATA_LENGTH. * - len must be KMS_KMIP_REQUEST_SECRETDATA_LENGTH. * - Callers must check for an error by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_register_secretdata_new (void *reserved, const uint8_t *data, size_t len); /* kms_kmip_request_activate_new creates a KMIP Activate request with the * provided unique identifer. * - unique_identifier must be a NULL terminated string. * - Callers must check for an error by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_activate_new (void *reserved, const char *unique_identifier); /* kms_kmip_request_get_new creates a KMIP Get request with the provided unique * identifer. * - unique_identifier must be a NULL terminated string. * - Callers must check for an error by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_get_new (void *reserved, const char *unique_identifier); KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_create_new (void *reserved); KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_encrypt_new (void *reserved, const char *unique_identifier, const uint8_t *plaintext, size_t len); KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_decrypt_new (void *reserved, const char *unique_identifier, const uint8_t *ciphertext, size_t len, const uint8_t *iv, size_t iv_len); #ifdef __cplusplus } #endif #endif /* KMS_KMIP_REQUEST_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_kmip_response.h0000644000175100001660000000312714760300420024671 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESPONSE_H #define KMS_KMIP_RESPONSE_H #include "kms_message_defines.h" #include #include "kms_response.h" /* kms_kmip_response_get_unique_identifier returns the UniqueIdentifier in the * first BatchItem in a ResponseMessage. * - Returns a NULL terminated string that the caller must free. * - Returns NULL on error and sets an error on kms_response_t. */ KMS_MSG_EXPORT (char *) kms_kmip_response_get_unique_identifier (kms_response_t *res); /* kms_kmip_response_get_secretdata returns the KeyMaterial in the * first BatchItem in a ResponseMessage. * - Caller must free returned data. * - Returns NULL on error and sets an error on kms_response_t. */ KMS_MSG_EXPORT (uint8_t *) kms_kmip_response_get_secretdata (kms_response_t *res, size_t *secretdatalen); KMS_MSG_EXPORT (uint8_t *) kms_kmip_response_get_data (kms_response_t *res, size_t *datalen); KMS_MSG_EXPORT (uint8_t *) kms_kmip_response_get_iv (kms_response_t *res, size_t *datalen); #endif /* KMS_KMIP_RESPONSE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_kmip_response_parser.h0000644000175100001660000000154714760300420026251 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESPONSE_PARSER_H #define KMS_KMIP_RESPONSE_PARSER_H #include "kms_message_defines.h" #include "kms_response_parser.h" KMS_MSG_EXPORT (kms_response_parser_t *) kms_kmip_response_parser_new (void *reserved); #endif /* KMS_KMIP_RESPONSE_PARSER_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_message.h0000644000175100001660000000203514760300420023434 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_H #define KMS_MESSAGE_H #include #include "kms_message_defines.h" #include "kms_kmip_request.h" #include "kms_kmip_response.h" #include "kms_kmip_response_parser.h" #include "kms_request_opt.h" #include "kms_request.h" #include "kms_response.h" #include "kms_response_parser.h" #include "kms_caller_identity_request.h" #include "kms_decrypt_request.h" #include "kms_encrypt_request.h" #endif /* KMS_MESSAGE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_message_defines.h0000644000175100001660000000322014760300420025126 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_DEFINES_H #define KMS_MESSAGE_DEFINES_H #ifdef _MSC_VER #ifdef KMS_MSG_STATIC #define KMS_MSG_API #elif defined(KMS_MSG_COMPILATION) #define KMS_MSG_API __declspec(dllexport) #else #define KMS_MSG_API __declspec(dllimport) #endif #define KMS_MSG_CALL __cdecl #elif defined(__GNUC__) #ifdef KMS_MSG_STATIC #define KMS_MSG_API #elif defined(KMS_MSG_COMPILATION) #define KMS_MSG_API __attribute__ ((visibility ("default"))) #else #define KMS_MSG_API #endif #define KMS_MSG_CALL #endif #define KMS_MSG_EXPORT(type) KMS_MSG_API type KMS_MSG_CALL #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (int) kms_message_init (void); KMS_MSG_EXPORT (void) kms_message_cleanup (void); #ifdef __cplusplus } /* extern "C" */ #endif #ifdef _MSC_VER #include #pragma warning(disable : 4142) #ifndef _SSIZE_T_DEFINED #define _SSIZE_T_DEFINED typedef SSIZE_T ssize_t; #endif #pragma warning(default : 4142) #endif #if defined(_MSC_VER) #define KMS_MSG_INLINE __inline #else #define KMS_MSG_INLINE __inline__ #endif #endif /* KMS_MESSAGE_DEFINES_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_request.h0000644000175100001660000000651514760300420023507 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_REQUEST_H #define KMS_REQUEST_H #include "kms_message_defines.h" #include "kms_request_opt.h" #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* A KMS request is general enough to create arbitrary HTTP requests, but also * supports generating AWS signature v4. */ typedef struct _kms_request_t kms_request_t; KMS_MSG_EXPORT (kms_request_t *) kms_request_new (const char *method, const char *path_and_query, const kms_request_opt_t *opt); KMS_MSG_EXPORT (void) kms_request_destroy (kms_request_t *request); KMS_MSG_EXPORT (const char *) kms_request_get_error (kms_request_t *request); /* Begin: AWS specific */ KMS_MSG_EXPORT (bool) kms_request_set_date (kms_request_t *request, const struct tm *tm); KMS_MSG_EXPORT (bool) kms_request_set_region (kms_request_t *request, const char *region); KMS_MSG_EXPORT (bool) kms_request_set_service (kms_request_t *request, const char *service); KMS_MSG_EXPORT (bool) kms_request_set_access_key_id (kms_request_t *request, const char *akid); KMS_MSG_EXPORT (bool) kms_request_set_secret_key (kms_request_t *request, const char *key); /* End: AWS specific */ KMS_MSG_EXPORT (bool) kms_request_add_header_field (kms_request_t *request, const char *field_name, const char *value); KMS_MSG_EXPORT (bool) kms_request_append_header_field_value (kms_request_t *request, const char *value, size_t len); KMS_MSG_EXPORT (bool) kms_request_append_payload (kms_request_t *request, const char *payload, size_t len); /* Begin: AWS specific */ KMS_MSG_EXPORT (char *) kms_request_get_canonical (kms_request_t *request); KMS_MSG_EXPORT (const char *) kms_request_get_canonical_header (kms_request_t *request, const char *header); KMS_MSG_EXPORT (char *) kms_request_get_string_to_sign (kms_request_t *request); KMS_MSG_EXPORT (bool) kms_request_get_signing_key (kms_request_t *request, unsigned char *key); KMS_MSG_EXPORT (char *) kms_request_get_signature (kms_request_t *request); KMS_MSG_EXPORT (char *) kms_request_get_signed (kms_request_t *request); /* End: AWS specific */ KMS_MSG_EXPORT (void) kms_request_free_string (char *ptr); /* Finalize and obtain a plain HTTP request (no signing). */ KMS_MSG_EXPORT (char *) kms_request_to_string (kms_request_t *request); /* kms_request_to_bytes returns the data for a request. * - Returns NULL on error and sets an error on request. */ KMS_MSG_EXPORT (const uint8_t *) kms_request_to_bytes (kms_request_t *request, size_t *len); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_REQUEST_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_request_opt.h0000644000175100001660000000555014760300420024367 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_REQUEST_OPT_H #define KMS_REQUEST_OPT_H #include "kms_message_defines.h" #include #include #ifdef __cplusplus extern "C" { #endif typedef struct _kms_request_opt_t kms_request_opt_t; typedef size_t kms_request_provider_t; #define KMS_REQUEST_PROVIDER_AWS 0 #define KMS_REQUEST_PROVIDER_AZURE 1 #define KMS_REQUEST_PROVIDER_GCP 2 #define KMS_REQUEST_PROVIDER_KMIP 3 KMS_MSG_EXPORT (kms_request_opt_t *) kms_request_opt_new (void); /* The default provider is AWS. This will automatically set extra headers. * Returns false if provider is invalid. */ KMS_MSG_EXPORT (bool) kms_request_opt_set_provider (kms_request_opt_t *opt, kms_request_provider_t provider); KMS_MSG_EXPORT (void) kms_request_opt_destroy (kms_request_opt_t *request); KMS_MSG_EXPORT (void) kms_request_opt_set_connection_close (kms_request_opt_t *opt, bool connection_close); KMS_MSG_EXPORT (void) kms_request_opt_set_crypto_hooks (kms_request_opt_t *opt, bool (*sha256) (void *ctx, const char *input, size_t len, unsigned char *hash_out), bool (*sha256_hmac) (void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out), void *ctx); KMS_MSG_EXPORT (void) kms_request_opt_set_crypto_hook_sign_rsaes_pkcs1_v1_5 ( kms_request_opt_t *opt, bool (*sign_rsaes_pkcs1_v1_5) (void *ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out), void *ctx); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_REQUEST_OPT_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_response.h0000644000175100001660000000230014760300420023641 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_RESPONSE_H #define KMS_RESPONSE_H #include "kms_message_defines.h" #include #include #ifdef __cplusplus extern "C" { #endif typedef struct _kms_response_t kms_response_t; KMS_MSG_EXPORT (int) kms_response_get_status (kms_response_t *response); KMS_MSG_EXPORT (const char *) kms_response_get_body (kms_response_t *response, size_t *len); KMS_MSG_EXPORT (void) kms_response_destroy (kms_response_t *response); KMS_MSG_EXPORT (const char *) kms_response_get_error (const kms_response_t *response); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_RESPONSE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message/kms_response_parser.h0000644000175100001660000000361514760300420025227 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_RESPONSE_PARSER_H #define KMS_RESPONSE_PARSER_H #include "kms_message_defines.h" #include "kms_response.h" #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct _kms_response_parser_t kms_response_parser_t; KMS_MSG_EXPORT (kms_response_parser_t *) kms_response_parser_new (void); KMS_MSG_EXPORT (int) kms_response_parser_wants_bytes (kms_response_parser_t *parser, int32_t max); KMS_MSG_EXPORT (bool) kms_response_parser_feed (kms_response_parser_t *parser, uint8_t *buf, uint32_t len); KMS_MSG_EXPORT (kms_response_t *) kms_response_parser_get_response (kms_response_parser_t *parser); /* kms_response_parser_status returns the HTTP response status if one was * parsed. * - Calling on a KMIP parser is an error. * - Returns an int for the HTTP status or 0 on error. */ KMS_MSG_EXPORT (int) kms_response_parser_status (kms_response_parser_t *parser); KMS_MSG_EXPORT (const char *) kms_response_parser_error (kms_response_parser_t *parser); KMS_MSG_EXPORT (void) kms_response_parser_destroy (kms_response_parser_t *parser); KMS_MSG_EXPORT (void) kms_response_parser_reset (kms_response_parser_t *parser); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_RESPONSE_PARSER_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/hexlify.c0000644000175100001660000000276214760300420020312 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message_private.h" #include #include #include #include char * hexlify (const uint8_t *buf, size_t len) { char *hex_chars = malloc (len * 2 + 1); KMS_ASSERT (hex_chars); char *p = hex_chars; size_t i; for (i = 0; i < len; i++) { p += sprintf (p, "%02x", buf[i]); } *p = '\0'; return hex_chars; } /* Returns -1 on error. */ int unhexlify (const char *in, size_t len) { int i; int byte; int total = 0; int multiplier = 1; for (i = (int) len - 1; i >= 0; i--) { char c = *(in + i); if (c >= '0' && c <= '9') { byte = c - 48; } else if (c >= 'a' && c <= 'f') { byte = c - 97 + 10; } else if (c >= 'A' && c <= 'F') { byte = c - 65 + 10; } else { return -1; } total += byte * multiplier; multiplier *= 16; } return total; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/hexlify.h0000644000175100001660000000134214760300420020310 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include #include char * hexlify (const uint8_t *buf, size_t len); int unhexlify (const char *in, size_t len);mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_azure_request.c0000644000175100001660000001550214760300420022406 0ustar /* * Copyright 2020-present MongoDB, 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. */ #include "kms_message/kms_azure_request.h" #include "kms_message/kms_b64.h" #include "kms_message_private.h" #include "kms_request_opt_private.h" #include "kms_request_str.h" /* * Request has the following form: * * POST /{tenant ID}/oauth2/v2.0/token HTTP/1.1 * Host: {host of identify platform URL} * Content-Type: application/x-www-form-urlencoded * * client_id={client ID} * &scope=https%3A%2F%2Fvault.azure.net%2F.default * &client_secret={client secret} * &grant_type=client_credentials */ kms_request_t * kms_azure_request_oauth_new (const char *host, const char *scope, const char *tenant_id, const char *client_id, const char *client_secret, const kms_request_opt_t *opt) { char *path_and_query = NULL; char *payload = NULL; kms_request_t *req; kms_request_str_t *str; str = kms_request_str_new (); kms_request_str_appendf (str, "/%s/oauth2/v2.0/token", tenant_id); path_and_query = kms_request_str_detach (str); str = kms_request_str_new (); kms_request_str_appendf ( str, "client_id=%s&scope=%s&client_secret=%s&grant_type=client_credentials", client_id, scope, client_secret); payload = kms_request_str_detach (str); req = kms_request_new ("POST", path_and_query, opt); if (opt->provider != KMS_REQUEST_PROVIDER_AZURE) { KMS_ERROR (req, "Expected KMS request with provider type: Azure"); goto done; } if (kms_request_get_error (req)) { goto done; } if (!kms_request_add_header_field ( req, "Content-Type", "application/x-www-form-urlencoded")) { goto done; } if (!kms_request_add_header_field (req, "Host", host)) { goto done; } if (!kms_request_add_header_field (req, "Accept", "application/json")) { goto done; } if (!kms_request_append_payload (req, payload, strlen (payload))) { goto done; } done: kms_request_free_string (path_and_query); kms_request_free_string (payload); return req; } static kms_request_t * _wrap_unwrap_common (const char *wrap_unwrap, const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *value, size_t value_len, const kms_request_opt_t *opt) { char *path_and_query = NULL; char *payload = NULL; char *bearer_token_value = NULL; char *value_base64url = NULL; kms_request_t *req; kms_request_str_t *str; str = kms_request_str_new (); /* {vaultBaseUrl}/keys/{key-name}/{key-version}/wrapkey?api-version=7.1 */ kms_request_str_appendf (str, "/keys/%s/%s/%s?api-version=7.1", key_name, key_version ? key_version : "", wrap_unwrap); path_and_query = kms_request_str_detach (str); req = kms_request_new ("POST", path_and_query, opt); if (opt->provider != KMS_REQUEST_PROVIDER_AZURE) { KMS_ERROR (req, "Expected KMS request with provider type: Azure"); goto done; } if (kms_request_get_error (req)) { goto done; } value_base64url = kms_message_raw_to_b64url (value, value_len); if (!value_base64url) { KMS_ERROR (req, "Could not bases64url-encode plaintext"); goto done; } str = kms_request_str_new (); kms_request_str_appendf ( str, "{\"alg\": \"RSA-OAEP-256\", \"value\": \"%s\"}", value_base64url); payload = kms_request_str_detach (str); str = kms_request_str_new (); kms_request_str_appendf (str, "Bearer %s", access_token); bearer_token_value = kms_request_str_detach (str); if (!kms_request_add_header_field ( req, "Authorization", bearer_token_value)) { goto done; } if (!kms_request_add_header_field ( req, "Content-Type", "application/json")) { goto done; } if (!kms_request_add_header_field (req, "Host", host)) { goto done; } if (!kms_request_add_header_field (req, "Accept", "application/json")) { goto done; } if (!kms_request_append_payload (req, payload, strlen (payload))) { goto done; } done: kms_request_free_string (path_and_query); kms_request_free_string (payload); kms_request_free_string (bearer_token_value); kms_request_free_string (value_base64url); return req; } /* * Request has the following form: * * POST /keys/{key-name}/{key-version}/wrapkey?api-version=7.1 * Host: {host of key vault endpoint} * Authentication: Bearer {token} * Content-Type: application/json * * { * "alg": "RSA-OAEP-256" * "value": "base64url encoded data" * } */ kms_request_t * kms_azure_request_wrapkey_new (const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *plaintext, size_t plaintext_len, const kms_request_opt_t *opt) { return _wrap_unwrap_common ("wrapkey", host, access_token, key_name, key_version, plaintext, plaintext_len, opt); } kms_request_t * kms_azure_request_unwrapkey_new (const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *ciphertext, size_t ciphertext_len, const kms_request_opt_t *opt) { return _wrap_unwrap_common ("unwrapkey", host, access_token, key_name, key_version, ciphertext, ciphertext_len, opt); }mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_b64.c0000644000175100001660000004742314760300420020112 0ustar /* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include #include "kms_message/kms_b64.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) * The following encoding technique is taken from RFC 1521 by Borenstein * and Freed. It is reproduced here in a slightly edited form for * convenience. * * A 65-character subset of US-ASCII is used, enabling 6 bits to be * represented per printable character. (The extra 65th character, "=", * is used to signify a special processing function.) * * The encoding process represents 24-bit groups of input bits as output * strings of 4 encoded characters. Proceeding from left to right, a * 24-bit input group is formed by concatenating 3 8-bit input groups. * These 24 bits are then treated as 4 concatenated 6-bit groups, each * of which is translated into a single digit in the base64 alphabet. * * Each 6-bit group is used as an index into an array of 64 printable * characters. The character referenced by the index is placed in the * output string. * * Table 1: The Base64 Alphabet * * Value Encoding Value Encoding Value Encoding Value Encoding * 0 A 17 R 34 i 51 z * 1 B 18 S 35 j 52 0 * 2 C 19 T 36 k 53 1 * 3 D 20 U 37 l 54 2 * 4 E 21 V 38 m 55 3 * 5 F 22 W 39 n 56 4 * 6 G 23 X 40 o 57 5 * 7 H 24 Y 41 p 58 6 * 8 I 25 Z 42 q 59 7 * 9 J 26 a 43 r 60 8 * 10 K 27 b 44 s 61 9 * 11 L 28 c 45 t 62 + * 12 M 29 d 46 u 63 / * 13 N 30 e 47 v * 14 O 31 f 48 w (pad) = * 15 P 32 g 49 x * 16 Q 33 h 50 y * * Special processing is performed if fewer than 24 bits are available * at the end of the data being encoded. A full encoding quantum is * always completed at the end of a quantity. When fewer than 24 input * bits are available in an input group, zero bits are added (on the * right) to form an integral number of 6-bit groups. Padding at the * end of the data is performed using the '=' character. * * Since all base64 input is an integral number of octets, only the * following cases can arise: * * (1) the final quantum of encoding input is an integral * multiple of 24 bits; here, the final unit of encoded * output will be an integral multiple of 4 characters * with no "=" padding, * (2) the final quantum of encoding input is exactly 8 bits; * here, the final unit of encoded output will be two * characters followed by two "=" padding characters, or * (3) the final quantum of encoding input is exactly 16 bits; * here, the final unit of encoded output will be three * characters followed by one "=" padding character. */ int kms_message_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; size_t i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = (uint8_t) (((input[0] & 0x03) << 4) + (input[1] >> 4)); output[2] = (uint8_t) (((input[1] & 0x0f) << 2) + (input[2] >> 6)); output[3] = input[2] & 0x3f; KMS_ASSERT (output[0] < 64); KMS_ASSERT (output[1] < 64); KMS_ASSERT (output[2] < 64); KMS_ASSERT (output[3] < 64); if (datalength + 4 > targsize) { return -1; } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) { input[i] = *src++; } output[0] = input[0] >> 2; output[1] = (uint8_t) (((input[0] & 0x03) << 4) + (input[1] >> 4)); output[2] = (uint8_t) (((input[1] & 0x0f) << 2) + (input[2] >> 6)); KMS_ASSERT (output[0] < 64); KMS_ASSERT (output[1] < 64); KMS_ASSERT (output[2] < 64); if (datalength + 4 > targsize) { return -1; } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) { target[datalength++] = Pad64; } else { target[datalength++] = Base64[output[2]]; } target[datalength++] = Pad64; } if (datalength >= targsize) { return -1; } target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (int) datalength; } /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ static uint8_t b64rmap[256]; static const uint8_t b64rmap_special = 0xf0; static const uint8_t b64rmap_end = 0xfd; static const uint8_t b64rmap_space = 0xfe; static const uint8_t b64rmap_invalid = 0xff; void kms_message_b64_initialize_rmap (void) { uint16_t i; unsigned char ch; /* Null: end of string, stop parsing */ b64rmap[0] = b64rmap_end; for (i = 1; i < 256; ++i) { ch = (unsigned char) i; /* Whitespaces */ if (isspace (ch)) b64rmap[i] = b64rmap_space; /* Padding: stop parsing */ else if (ch == Pad64) b64rmap[i] = b64rmap_end; /* Non-base64 char */ else b64rmap[i] = b64rmap_invalid; } /* Fill reverse mapping for base64 chars */ for (i = 0; Base64[i] != '\0'; ++i) b64rmap[(uint8_t) Base64[i]] = (uint8_t) i; } static int b64_pton_do (char const *src, uint8_t *target, size_t targsize) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = b64rmap[ch]; if (ofs >= b64rmap_special) { /* Ignore whitespaces */ if (ofs == b64rmap_space) continue; /* End of base64 characters */ if (ofs == b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: if ((size_t) tarindex >= targsize) return (-1); target[tarindex] = (uint8_t) (ofs << 2); state = 1; break; case 1: if ((size_t) tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 4; target[tarindex + 1] = (uint8_t) ((ofs & 0x0f) << 4); tarindex++; state = 2; break; case 2: if ((size_t) tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 2; target[tarindex + 1] = (uint8_t) ((ofs & 0x03) << 6); tarindex++; state = 3; break; case 3: if ((size_t) tarindex >= targsize) return (-1); target[tarindex] |= ofs; tarindex++; state = 0; break; default: abort (); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void) NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void) NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target[tarindex] != 0) return (-1); default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } static int b64_pton_len (char const *src) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = b64rmap[ch]; if (ofs >= b64rmap_special) { /* Ignore whitespaces */ if (ofs == b64rmap_space) continue; /* End of base64 characters */ if (ofs == b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: state = 1; break; case 1: tarindex++; state = 2; break; case 2: tarindex++; state = 3; break; case 3: tarindex++; state = 0; break; default: abort (); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void) NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void) NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) return (-1); default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } int kms_message_b64_pton (char const *src, uint8_t *target, size_t targsize) { if (target) return b64_pton_do (src, target, targsize); else return b64_pton_len (src); } int kms_message_b64_to_b64url (const char *src, size_t srclength, char *target, size_t targsize) { size_t i; for (i = 0; i < srclength; i++) { if (i >= targsize) { return -1; } target[i] = src[i]; if (target[i] == '+') { target[i] = '-'; } else if (target[i] == '/') { target[i] = '_'; } } /* NULL terminate if room. */ if (i < targsize) { target[i] = '\0'; } return (int) i; } int kms_message_b64url_to_b64 (const char *src, size_t srclength, char *target, size_t targsize) { size_t i; size_t boundary; for (i = 0; i < srclength; i++) { if (i >= targsize) { return -1; } target[i] = src[i]; if (target[i] == '-') { target[i] = '+'; } else if (target[i] == '_') { target[i] = '/'; } } /* Pad to four byte boundary. */ boundary = 4 * ((i + 3) / 4); for (; i < boundary; i++) { if (i >= targsize) { return -1; } target[i] = '='; } /* NULL terminate if room. */ if (i < targsize) { target[i] = '\0'; } return (int) i; } char * kms_message_raw_to_b64 (const uint8_t *raw, size_t raw_len) { char *b64; size_t b64_len; b64_len = (raw_len / 3 + 1) * 4 + 1; b64 = malloc (b64_len); memset (b64, 0, b64_len); if (-1 == kms_message_b64_ntop (raw, raw_len, b64, b64_len)) { free (b64); return NULL; } return b64; } uint8_t * kms_message_b64_to_raw (const char *b64, size_t *out) { uint8_t *raw; int ret; size_t b64len; b64len = strlen (b64); raw = (uint8_t *) malloc (b64len + 1); memset (raw, 0, b64len + 1); ret = kms_message_b64_pton (b64, raw, b64len); if (ret > 0) { *out = (size_t) ret; return raw; } free (raw); return NULL; } char * kms_message_raw_to_b64url (const uint8_t *raw, size_t raw_len) { char *b64; size_t b64len; b64 = kms_message_raw_to_b64 (raw, raw_len); if (!b64) { return NULL; } b64len = strlen (b64); if (-1 == kms_message_b64_to_b64url (b64, b64len, b64, b64len)) { free (b64); return NULL; } return b64; } uint8_t * kms_message_b64url_to_raw (const char *b64url, size_t *out) { char *b64; size_t capacity; uint8_t *raw; size_t b64urllen; b64urllen = strlen(b64url); /* Add four for padding '=' characters. */ capacity = b64urllen + 4; b64 = malloc (capacity); memset (b64, 0, capacity); if (-1 == kms_message_b64url_to_b64 (b64url, b64urllen, b64, capacity)) { free (b64); return NULL; } raw = kms_message_b64_to_raw (b64, out); free (b64); return raw; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_caller_identity_request.c0000644000175100001660000000275014760300420024434 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_message/kms_b64.h" #include "kms_request_str.h" kms_request_t * kms_caller_identity_request_new (const kms_request_opt_t *opt) { kms_request_t *request; kms_request_str_t *payload = NULL; request = kms_request_new ("POST", "/", opt); if (kms_request_get_error (request)) { goto done; } if (!(kms_request_add_header_field ( request, "Content-Type", "application/x-www-form-urlencoded"))) { goto done; } payload = kms_request_str_new (); kms_request_str_appendf (payload, "Action=GetCallerIdentity&Version=2011-06-15"); if (!kms_request_append_payload (request, payload->str, payload->len)) { KMS_ERROR (request, "Could not append payload"); goto done; } done: kms_request_str_destroy (payload); return request; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_crypto.h0000644000175100001660000000436414760300420021041 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_KMS_CRYPTO_H #define KMS_MESSAGE_KMS_CRYPTO_H #include #include typedef struct { bool (*sha256) (void *ctx, const char *input, size_t len, unsigned char *hash_out); bool (*sha256_hmac) (void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out); bool (*sign_rsaes_pkcs1_v1_5) (void *sign_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out); void *ctx; void *sign_ctx; } _kms_crypto_t; int kms_crypto_init (void); void kms_crypto_cleanup (void); bool kms_sha256 (void *ctx, const char *input, size_t len, unsigned char *hash_out); bool kms_sha256_hmac (void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out); /* signature_out must be a preallocated buffer of 256 bytes (or greater). */ bool kms_sign_rsaes_pkcs1_v1_5 (void *sign_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out); #endif /* KMS_MESSAGE_KMS_CRYPTO_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_crypto_apple.c0000644000175100001660000001076714760300420022221 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #include "kms_message_private.h" /* KMS_ASSERT */ #ifdef KMS_MESSAGE_ENABLE_CRYPTO_COMMON_CRYPTO #include #include #include #include #include #include int kms_crypto_init (void) { return 0; } void kms_crypto_cleanup (void) { } bool kms_sha256 (void *unused_ctx, const char *input, size_t len, unsigned char *hash_out) { CC_SHA256_CTX ctx; CC_SHA256_Init (&ctx); KMS_ASSERT (len <= (size_t) UINT32_MAX); CC_SHA256_Update (&ctx, input, (uint32_t) len); CC_SHA256_Final (hash_out, &ctx); return true; } bool kms_sha256_hmac (void *unused_ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) { CCHmac (kCCHmacAlgSHA256, key_input, key_len, input, len, hash_out); return true; } static void safe_CFRelease (CFTypeRef ptr) { if (ptr) { CFRelease (ptr); } } bool kms_sign_rsaes_pkcs1_v1_5 (void *unused_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out) { CFDataRef key_data_ref = NULL; CFDataRef pass_ref = NULL; SecItemImportExportKeyParameters import_params; OSStatus status; /* TODO: I think the expected format should be kSecFormatWrappedPKCS8, but * GCP keys appear to only load for kSecFormatBSAFE. */ SecExternalFormat format = kSecFormatUnknown; SecExternalItemType type = kSecItemTypePrivateKey; CFArrayRef out_ref = NULL; SecKeyRef key_ref = NULL; CFDataRef data_to_sign_ref = NULL; CFErrorRef error_ref; CFDataRef signature_ref = NULL; bool ret = false; key_data_ref = CFDataCreate (NULL /* default allocator */, (const uint8_t *) private_key, (CFIndex) private_key_len); if (!key_data_ref) { goto cleanup; } memset (&import_params, 0, sizeof (SecItemImportExportKeyParameters)); import_params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; /* Give an empty password. SecItemImport returns an error expecting a * password. */ pass_ref = CFDataCreate (NULL, NULL, 0); if (!pass_ref) { goto cleanup; } import_params.passphrase = (CFTypeRef) pass_ref; status = SecItemImport (key_data_ref, NULL /* extension. */, &format, &type, 0, &import_params, NULL /* keychain */, &out_ref); if (status != errSecSuccess) { goto cleanup; } if (1 != CFArrayGetCount (out_ref)) { goto cleanup; } key_ref = (SecKeyRef) CFArrayGetValueAtIndex (out_ref, 0); KMS_ASSERT (input_len <= (size_t) LONG_MAX); data_to_sign_ref = CFDataCreate (NULL, (const uint8_t *) input, (long) input_len); if (!data_to_sign_ref) { goto cleanup; } error_ref = NULL; signature_ref = SecKeyCreateSignature (key_ref, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256, data_to_sign_ref, &error_ref); if (!signature_ref) { goto cleanup; } memcpy (signature_out, CFDataGetBytePtr (signature_ref), (size_t) CFDataGetLength (signature_ref)); ret = true; cleanup: safe_CFRelease (key_data_ref); safe_CFRelease (pass_ref); safe_CFRelease (out_ref); safe_CFRelease (data_to_sign_ref); safe_CFRelease (signature_ref); return ret; } #endif /* KMS_MESSAGE_ENABLE_CRYPTO_COMMON_CRYPTO */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_crypto_libcrypto.c0000644000175100001660000000650414760300420023121 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #include "kms_message_private.h" #ifdef KMS_MESSAGE_ENABLE_CRYPTO_LIBCRYPTO #include #include #include #include /* INT_MAX, LONG_MAX */ #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) static EVP_MD_CTX * EVP_MD_CTX_new (void) { return calloc (sizeof (EVP_MD_CTX), 1); } static void EVP_MD_CTX_free (EVP_MD_CTX *ctx) { EVP_MD_CTX_cleanup (ctx); free (ctx); } #endif int kms_crypto_init (void) { return 0; } void kms_crypto_cleanup (void) { } bool kms_sha256 (void *unused_ctx, const char *input, size_t len, unsigned char *hash_out) { EVP_MD_CTX *digest_ctxp = EVP_MD_CTX_new (); bool rval = false; if (1 != EVP_DigestInit_ex (digest_ctxp, EVP_sha256 (), NULL)) { goto cleanup; } if (1 != EVP_DigestUpdate (digest_ctxp, input, len)) { goto cleanup; } rval = (1 == EVP_DigestFinal_ex (digest_ctxp, hash_out, NULL)); cleanup: EVP_MD_CTX_free (digest_ctxp); return rval; } bool kms_sha256_hmac (void *unused_ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) { KMS_ASSERT (key_len <= INT_MAX); return HMAC (EVP_sha256 (), key_input, (int) key_len, (unsigned char *) input, len, hash_out, NULL) != NULL; } bool kms_sign_rsaes_pkcs1_v1_5 (void *unused_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out) { EVP_MD_CTX *ctx; EVP_PKEY *pkey = NULL; bool ret = false; size_t signature_out_len = 256; ctx = EVP_MD_CTX_new (); KMS_ASSERT (private_key_len <= LONG_MAX); pkey = d2i_PrivateKey (EVP_PKEY_RSA, NULL, (const unsigned char **) &private_key, (long) private_key_len); if (!pkey) { goto cleanup; } ret = EVP_DigestSignInit (ctx, NULL, EVP_sha256 (), NULL /* engine */, pkey); if (ret != 1) { goto cleanup; } ret = EVP_DigestSignUpdate (ctx, input, input_len); if (ret != 1) { goto cleanup; } ret = EVP_DigestSignFinal (ctx, signature_out, &signature_out_len); if (ret != 1) { goto cleanup; } ret = true; cleanup: EVP_MD_CTX_free (ctx); EVP_PKEY_free (pkey); return ret; } #endif /* KMS_MESSAGE_ENABLE_CRYPTO_LIBCRYPTO */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_crypto_none.c0000644000175100001660000000321314760300420022043 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #ifndef KMS_MESSAGE_ENABLE_CRYPTO int kms_crypto_init (void) { return 0; } void kms_crypto_cleanup (void) { } bool kms_sha256 (void *unused_ctx, const char *input, size_t len, unsigned char *hash_out) { /* only gets called if hooks were mistakenly not set */ return false; } bool kms_sha256_hmac (void *unused_ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) { /* only gets called if hooks were mistakenly not set */ return false; } bool kms_sign_rsaes_pkcs1_v1_5 (void *unused_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out) { /* only gets called if hooks were mistakenly not set */ return false; } #endif /* KMS_MESSAGE_ENABLE_CRYPTO */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_crypto_windows.c0000644000175100001660000001651514760300420022607 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #ifdef KMS_MESSAGE_ENABLE_CRYPTO_CNG // tell windows.h not to include a bunch of headers we don't need: #define WIN32_LEAN_AND_MEAN // Tell windows.h not to define any NT status codes, so that we can // get the definitions from ntstatus.h, which has a more complete list. #define WIN32_NO_STATUS #include #undef WIN32_NO_STATUS // Obtain a definition for the ntstatus type. #include // Add back in the status definitions so that macro expansions for // things like STILL_ACTIVE and WAIT_OBJECT_O can be resolved (they // expand to STATUS_ codes). #include #include #include static BCRYPT_ALG_HANDLE _algoSHA256 = 0; static BCRYPT_ALG_HANDLE _algoSHA256Hmac = 0; static BCRYPT_ALG_HANDLE _algoRSA = 0; #define SHA_256_HASH_LEN 32 int kms_crypto_init (void) { if (BCryptOpenAlgorithmProvider ( &_algoSHA256, BCRYPT_SHA256_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0) != STATUS_SUCCESS) { return 1; } if (BCryptOpenAlgorithmProvider (&_algoSHA256Hmac, BCRYPT_SHA256_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG) != STATUS_SUCCESS) { return 2; } if (BCryptOpenAlgorithmProvider ( &_algoRSA, BCRYPT_RSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0) != STATUS_SUCCESS) { return 3; } return 0; } void kms_crypto_cleanup (void) { (void) BCryptCloseAlgorithmProvider (_algoSHA256, 0); (void) BCryptCloseAlgorithmProvider (_algoSHA256Hmac, 0); (void) BCryptCloseAlgorithmProvider (_algoRSA, 0); } bool kms_sha256 (void *unused_ctx, const char *input, size_t len, unsigned char *hash_out) { BCRYPT_HASH_HANDLE hHash; NTSTATUS status = BCryptCreateHash (_algoSHA256, &hHash, NULL, 0, NULL, 0, 0); if (status != STATUS_SUCCESS) { return 0; } status = BCryptHashData (hHash, (PUCHAR) (input), (ULONG) len, 0); if (status != STATUS_SUCCESS) { goto cleanup; } // Hardcode output length status = BCryptFinishHash (hHash, hash_out, 256 / 8, 0); if (status != STATUS_SUCCESS) { goto cleanup; } cleanup: (void) BCryptDestroyHash (hHash); return status == STATUS_SUCCESS ? 1 : 0; } bool kms_sha256_hmac (void *unused_ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) { BCRYPT_HASH_HANDLE hHash; NTSTATUS status = BCryptCreateHash ( _algoSHA256Hmac, &hHash, NULL, 0, (PUCHAR) key_input, (ULONG) key_len, 0); if (status != STATUS_SUCCESS) { return 0; } status = BCryptHashData (hHash, (PUCHAR) input, (ULONG) len, 0); if (status != STATUS_SUCCESS) { goto cleanup; } // Hardcode output length status = BCryptFinishHash (hHash, hash_out, 256 / 8, 0); if (status != STATUS_SUCCESS) { goto cleanup; } cleanup: (void) BCryptDestroyHash (hHash); return status == STATUS_SUCCESS ? 1 : 0; } bool kms_sign_rsaes_pkcs1_v1_5 (void *unused_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out) { bool success = false; bool ret = false; LPBYTE blob_private = NULL; DWORD blob_private_len = 0; LPBYTE raw_private = NULL; DWORD raw_private_len = 0; NTSTATUS status; BCRYPT_KEY_HANDLE hKey = NULL; BCRYPT_PKCS1_PADDING_INFO padding_PKCS1; unsigned char *hash_value = NULL; DWORD hash_length = 256; success = CryptDecodeObjectEx (X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, (BYTE*) private_key, (DWORD) private_key_len, 0, NULL, NULL, &blob_private_len); if (!success) { goto cleanup; } blob_private = (LPBYTE) calloc (1, blob_private_len); success = CryptDecodeObjectEx (X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, (BYTE*) private_key, (DWORD) private_key_len, 0, NULL, blob_private, &blob_private_len); if (!success) { goto cleanup; } CRYPT_PRIVATE_KEY_INFO *privateKeyInfo = (CRYPT_PRIVATE_KEY_INFO *) blob_private; success = CryptDecodeObjectEx (X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, privateKeyInfo->PrivateKey.pbData, (DWORD) privateKeyInfo->PrivateKey.cbData, 0, NULL, NULL, &raw_private_len); if (!success) { goto cleanup; } raw_private = (LPBYTE) calloc (1, raw_private_len); success = CryptDecodeObjectEx (X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, privateKeyInfo->PrivateKey.pbData, (DWORD) privateKeyInfo->PrivateKey.cbData, 0, NULL, raw_private, &raw_private_len); if (!success) { goto cleanup; } status = BCryptImportKeyPair ( _algoRSA, NULL, LEGACY_RSAPRIVATE_BLOB, &hKey, raw_private, raw_private_len, 0); if (!NT_SUCCESS (status)) { goto cleanup; } hash_value = calloc (1, SHA_256_HASH_LEN); if(!kms_sha256 (NULL, input, input_len, hash_value)) { goto cleanup; } padding_PKCS1.pszAlgId = BCRYPT_SHA256_ALGORITHM; status = BCryptSignHash (hKey, &padding_PKCS1, hash_value, SHA_256_HASH_LEN, signature_out, hash_length, &hash_length, BCRYPT_PAD_PKCS1); if (!NT_SUCCESS (status)) { goto cleanup; } ret = true; cleanup: BCryptDestroyKey(hKey); free (blob_private); free (raw_private); free (hash_value); return ret; } #endif /* KMS_MESSAGE_ENABLE_CRYPTO_CNG */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_decrypt_request.c0000644000175100001660000000410014760300420022722 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_message/kms_b64.h" #include "kms_request_str.h" kms_request_t * kms_decrypt_request_new (const uint8_t *ciphertext_blob, size_t len, const kms_request_opt_t *opt) { kms_request_t *request; size_t b64_len; char *b64 = NULL; kms_request_str_t *payload = NULL; request = kms_request_new ("POST", "/", opt); if (kms_request_get_error (request)) { goto done; } if (!(kms_request_add_header_field ( request, "Content-Type", "application/x-amz-json-1.1") && kms_request_add_header_field ( request, "X-Amz-Target", "TrentService.Decrypt"))) { goto done; } b64_len = (len / 3 + 1) * 4 + 1; if (!(b64 = malloc (b64_len))) { KMS_ERROR (request, "Could not allocate %d bytes for base64-encoding payload", (int) b64_len); goto done; } if (kms_message_b64_ntop (ciphertext_blob, len, b64, b64_len) == -1) { KMS_ERROR (request, "Could not base64-encode ciphertext blob"); goto done; } payload = kms_request_str_new (); kms_request_str_appendf (payload, "{\"CiphertextBlob\": \"%s\"}", b64); if (!kms_request_append_payload (request, payload->str, payload->len)) { KMS_ERROR (request, "Could not append payload"); goto done; } done: free (b64); kms_request_str_destroy (payload); return request; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_encrypt_request.c0000644000175100001660000000427214760300420022746 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_message/kms_b64.h" #include "kms_request_str.h" kms_request_t * kms_encrypt_request_new (const uint8_t *plaintext, size_t plaintext_length, const char *key_id, const kms_request_opt_t *opt) { kms_request_t *request; size_t b64_len; char *b64 = NULL; kms_request_str_t *payload = NULL; request = kms_request_new ("POST", "/", opt); if (kms_request_get_error (request)) { goto done; } if (!(kms_request_add_header_field ( request, "Content-Type", "application/x-amz-json-1.1") && kms_request_add_header_field ( request, "X-Amz-Target", "TrentService.Encrypt"))) { goto done; } b64_len = (plaintext_length / 3 + 1) * 4 + 1; if (!(b64 = malloc (b64_len))) { KMS_ERROR (request, "Could not allocate %d bytes for base64-encoding payload", (int) b64_len); goto done; } if (kms_message_b64_ntop ( (const uint8_t *) plaintext, plaintext_length, b64, b64_len) == -1) { KMS_ERROR (request, "Could not base64-encode plaintext"); goto done; } payload = kms_request_str_new (); kms_request_str_appendf ( payload, "{\"Plaintext\": \"%s\", \"KeyId\": \"%s\"}", b64, key_id); if (!kms_request_append_payload (request, payload->str, payload->len)) { KMS_ERROR (request, "Could not append payload"); goto done; } done: free (b64); kms_request_str_destroy (payload); return request; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_endian_private.h0000644000175100001660000001213414760300420022503 0ustar /* * Copyright 2021-present MongoDB, 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. */ /* This file is copied and modified from libbson's bson-endian.h. */ #ifndef KMS_ENDIAN_PRIVATE_H #define KMS_ENDIAN_PRIVATE_H #include #include "kms_message/kms_message_defines.h" /* Define a fallback for __has_builtin for compatibility with non-clang compilers. */ #ifndef __has_builtin #define __has_builtin(x) 0 #endif #if defined(__clang__) && __has_builtin(__builtin_bswap16) && \ __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) #define KMS_UINT16_SWAP_LE_BE(v) __builtin_bswap16 (v) #define KMS_UINT32_SWAP_LE_BE(v) __builtin_bswap32 (v) #define KMS_UINT64_SWAP_LE_BE(v) __builtin_bswap64 (v) #elif defined(__GNUC__) && (__GNUC__ >= 4) #if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3) #define KMS_UINT32_SWAP_LE_BE(v) __builtin_bswap32 ((uint32_t) v) #define KMS_UINT64_SWAP_LE_BE(v) __builtin_bswap64 ((uint64_t) v) #endif #if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8) #define KMS_UINT16_SWAP_LE_BE(v) __builtin_bswap16 ((uint32_t) v) #endif #endif #ifndef KMS_UINT16_SWAP_LE_BE #define KMS_UINT16_SWAP_LE_BE(v) __kms_uint16_swap_slow ((uint16_t) v) #endif #ifndef KMS_UINT32_SWAP_LE_BE #define KMS_UINT32_SWAP_LE_BE(v) __kms_uint32_swap_slow ((uint32_t) v) #endif #ifndef KMS_UINT64_SWAP_LE_BE #define KMS_UINT64_SWAP_LE_BE(v) __kms_uint64_swap_slow ((uint64_t) v) #endif #if defined(KMS_MESSAGE_LITTLE_ENDIAN) #define KMS_UINT16_FROM_LE(v) ((uint16_t) v) #define KMS_UINT16_TO_LE(v) ((uint16_t) v) #define KMS_UINT16_FROM_BE(v) KMS_UINT16_SWAP_LE_BE (v) #define KMS_UINT16_TO_BE(v) KMS_UINT16_SWAP_LE_BE (v) #define KMS_UINT32_FROM_LE(v) ((uint32_t) v) #define KMS_UINT32_TO_LE(v) ((uint32_t) v) #define KMS_UINT32_FROM_BE(v) KMS_UINT32_SWAP_LE_BE (v) #define KMS_UINT32_TO_BE(v) KMS_UINT32_SWAP_LE_BE (v) #define KMS_UINT64_FROM_LE(v) ((uint64_t) v) #define KMS_UINT64_TO_LE(v) ((uint64_t) v) #define KMS_UINT64_FROM_BE(v) KMS_UINT64_SWAP_LE_BE (v) #define KMS_UINT64_TO_BE(v) KMS_UINT64_SWAP_LE_BE (v) #elif defined(KMS_MESSAGE_BIG_ENDIAN) #define KMS_UINT16_FROM_LE(v) KMS_UINT16_SWAP_LE_BE (v) #define KMS_UINT16_TO_LE(v) KMS_UINT16_SWAP_LE_BE (v) #define KMS_UINT16_FROM_BE(v) ((uint16_t) v) #define KMS_UINT16_TO_BE(v) ((uint16_t) v) #define KMS_UINT32_FROM_LE(v) KMS_UINT32_SWAP_LE_BE (v) #define KMS_UINT32_TO_LE(v) KMS_UINT32_SWAP_LE_BE (v) #define KMS_UINT32_FROM_BE(v) ((uint32_t) v) #define KMS_UINT32_TO_BE(v) ((uint32_t) v) #define KMS_UINT64_FROM_LE(v) KMS_UINT64_SWAP_LE_BE (v) #define KMS_UINT64_TO_LE(v) KMS_UINT64_SWAP_LE_BE (v) #define KMS_UINT64_FROM_BE(v) ((uint64_t) v) #define KMS_UINT64_TO_BE(v) ((uint64_t) v) #else #error "The endianness of target architecture is unknown." #endif /* *-------------------------------------------------------------------------- * * __kms_uint16_swap_slow -- * * Fallback endianness conversion for 16-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static KMS_MSG_INLINE uint16_t __kms_uint16_swap_slow (uint16_t v) /* IN */ { return (uint16_t) (((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8)); } /* *-------------------------------------------------------------------------- * * __kms_uint32_swap_slow -- * * Fallback endianness conversion for 32-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static KMS_MSG_INLINE uint32_t __kms_uint32_swap_slow (uint32_t v) /* IN */ { return ((v & 0x000000FFU) << 24) | ((v & 0x0000FF00U) << 8) | ((v & 0x00FF0000U) >> 8) | ((v & 0xFF000000U) >> 24); } /* *-------------------------------------------------------------------------- * * __kms_uint64_swap_slow -- * * Fallback endianness conversion for 64-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static KMS_MSG_INLINE uint64_t __kms_uint64_swap_slow (uint64_t v) /* IN */ { return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) | ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) | ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) | ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56); } #endif /* KMS_ENDIAN_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_gcp_request.c0000644000175100001660000002353614760300420022037 0ustar /* * Copyright 2020-present MongoDB, 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. */ #include "kms_message/kms_gcp_request.h" #include "kms_message/kms_b64.h" #include "kms_message_private.h" #include "kms_request_opt_private.h" /* Set a default expiration of 5 minutes for JSON Web Tokens (GCP allows up to * one hour) */ #define JWT_EXPIRATION_SECS 5 * 60 #define SIGNATURE_LEN 256 kms_request_t * kms_gcp_request_oauth_new (const char *host, const char *email, const char *audience, const char *scope, const char *private_key_data, size_t private_key_len, const kms_request_opt_t *opt) { kms_request_t *req = NULL; kms_request_str_t *str = NULL; time_t issued_at; /* base64 encoding of {"alg":"RS256","typ":"JWT"} */ const char *jwt_header_b64url = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"; char *jwt_claims_b64url = NULL; char *jwt_header_and_claims_b64url = NULL; uint8_t *jwt_signature = NULL; char *jwt_signature_b64url = NULL; char *jwt_assertion_b64url = NULL; char *payload = NULL; req = kms_request_new ("POST", "/token", opt); if (opt->provider != KMS_REQUEST_PROVIDER_GCP) { KMS_ERROR (req, "Expected KMS request with provider type: GCP"); goto done; } if (kms_request_get_error (req)) { goto done; } /* Produce the signed JWT .. */ issued_at = time (NULL); str = kms_request_str_new (); kms_request_str_appendf (str, "{\"iss\": \"%s\", \"aud\": \"%s\", \"scope\": " "\"%s\", \"iat\": %lu, \"exp\": %lu}", email, audience, scope, (unsigned long) issued_at, (unsigned long) issued_at + JWT_EXPIRATION_SECS); jwt_claims_b64url = kms_message_raw_to_b64url ((const uint8_t *) str->str, str->len); kms_request_str_destroy (str); if (!jwt_claims_b64url) { KMS_ERROR (req, "Failed to base64url encode JWT claims"); goto done; } str = kms_request_str_new (); kms_request_str_appendf (str, "%s.%s", jwt_header_b64url, jwt_claims_b64url); jwt_header_and_claims_b64url = kms_request_str_detach (str); /* Produce the signature of . */ req->crypto.sign_rsaes_pkcs1_v1_5 = kms_sign_rsaes_pkcs1_v1_5; if (opt->crypto.sign_rsaes_pkcs1_v1_5) { req->crypto.sign_rsaes_pkcs1_v1_5 = opt->crypto.sign_rsaes_pkcs1_v1_5; req->crypto.sign_ctx = opt->crypto.sign_ctx; } jwt_signature = calloc (1, SIGNATURE_LEN); if (!req->crypto.sign_rsaes_pkcs1_v1_5 ( req->crypto.sign_ctx, private_key_data, private_key_len, jwt_header_and_claims_b64url, strlen (jwt_header_and_claims_b64url), jwt_signature)) { KMS_ERROR (req, "Failed to create GCP oauth request signature"); goto done; } jwt_signature_b64url = kms_message_raw_to_b64url (jwt_signature, SIGNATURE_LEN); if (!jwt_signature_b64url) { KMS_ERROR (req, "Failed to base64url encode JWT signature"); goto done; } str = kms_request_str_new (); kms_request_str_appendf (str, "%s.%s.%s", jwt_header_b64url, jwt_claims_b64url, jwt_signature_b64url); jwt_assertion_b64url = kms_request_str_detach (str); str = kms_request_str_new_from_chars ("grant_type=urn%3Aietf%3Aparams%3Aoauth%" "3Agrant-type%3Ajwt-bearer&assertion=", -1); kms_request_str_append_chars (str, jwt_assertion_b64url, -1); payload = kms_request_str_detach (str); if (!kms_request_add_header_field ( req, "Content-Type", "application/x-www-form-urlencoded")) { goto done; } if (!kms_request_add_header_field (req, "Host", host)) { goto done; } if (!kms_request_add_header_field (req, "Accept", "application/json")) { goto done; } if (!kms_request_append_payload (req, payload, strlen (payload))) { goto done; } done: free (jwt_signature); free (jwt_signature_b64url); free (jwt_claims_b64url); free (jwt_header_and_claims_b64url); free (jwt_assertion_b64url); free (payload); return req; } static kms_request_t * _encrypt_decrypt_common (const char *encrypt_decrypt, const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const char *key_version, const uint8_t *value, size_t value_len, const kms_request_opt_t *opt) { char *path_and_query = NULL; char *payload = NULL; char *bearer_token_value = NULL; char *value_base64 = NULL; kms_request_t *req; kms_request_str_t *str; str = kms_request_str_new (); /* /v1/projects/{project-id}/locations/{location}/keyRings/{key-ring-name}/cryptoKeys/{key-name} */ kms_request_str_appendf ( str, "/v1/projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", project_id, location, key_ring_name, key_name); if (key_version && strlen (key_version) > 0) { kms_request_str_appendf (str, "/cryptoKeyVersions/%s", key_version); } kms_request_str_appendf (str, ":%s", encrypt_decrypt); path_and_query = kms_request_str_detach (str); req = kms_request_new ("POST", path_and_query, opt); if (opt->provider != KMS_REQUEST_PROVIDER_GCP) { KMS_ERROR (req, "Expected KMS request with provider type: GCP"); goto done; } if (kms_request_get_error (req)) { goto done; } value_base64 = kms_message_raw_to_b64 (value, value_len); if (!value_base64) { KMS_ERROR (req, "Could not bases64-encode plaintext"); goto done; } str = kms_request_str_new (); if (0 == strcmp ("encrypt", encrypt_decrypt)) { kms_request_str_appendf (str, "{\"plaintext\": \"%s\"}", value_base64); } else { kms_request_str_appendf (str, "{\"ciphertext\": \"%s\"}", value_base64); } payload = kms_request_str_detach (str); str = kms_request_str_new (); kms_request_str_appendf (str, "Bearer %s", access_token); bearer_token_value = kms_request_str_detach (str); if (!kms_request_add_header_field ( req, "Authorization", bearer_token_value)) { goto done; } if (!kms_request_add_header_field ( req, "Content-Type", "application/json")) { goto done; } if (!kms_request_add_header_field (req, "Host", host)) { goto done; } if (!kms_request_add_header_field (req, "Accept", "application/json")) { goto done; } if (!kms_request_append_payload (req, payload, strlen (payload))) { goto done; } done: kms_request_free_string (path_and_query); kms_request_free_string (payload); kms_request_free_string (bearer_token_value); kms_request_free_string (value_base64); return req; } kms_request_t * kms_gcp_request_encrypt_new (const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const char *key_version, const uint8_t *plaintext, size_t plaintext_len, const kms_request_opt_t *opt) { return _encrypt_decrypt_common ("encrypt", host, access_token, project_id, location, key_ring_name, key_name, key_version, plaintext, plaintext_len, opt); } kms_request_t * kms_gcp_request_decrypt_new (const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const uint8_t *ciphertext, size_t ciphertext_len, const kms_request_opt_t *opt) { return _encrypt_decrypt_common ("decrypt", host, access_token, project_id, location, key_ring_name, key_name, NULL /* key_version */, ciphertext, ciphertext_len, opt); }mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_item_type_private.h0000644000175100001660000000331014760300420024260 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_ITEM_TYPE_PRIVATE_H #define KMS_KMIP_ITEM_TYPE_PRIVATE_H #include "kms_message/kms_message_defines.h" #define KMS_XMACRO \ KMS_X (Structure, 0x01) \ KMS_X (Integer, 0x02) \ KMS_X (LongInteger, 0x03) \ KMS_X (BigInteger, 0x04) \ KMS_X (Enumeration, 0x05) \ KMS_X (Boolean, 0x06) \ KMS_X (TextString, 0x07) \ KMS_X (ByteString, 0x08) \ KMS_X (DateTime, 0x09) \ KMS_X_LAST (Interval, 0x0A) /* Generate an enum with each item_type value. */ #define KMS_X(ITEM_TYPE, VAL) KMIP_ITEM_TYPE_##ITEM_TYPE = VAL, #define KMS_X_LAST(ITEM_TYPE, VAL) KMIP_ITEM_TYPE_##ITEM_TYPE = VAL typedef enum { KMS_XMACRO } kmip_item_type_t; #undef KMS_X #undef KMS_X_LAST #define KMS_X(ITEM_TYPE, VAL) \ case KMIP_ITEM_TYPE_##ITEM_TYPE: \ return #ITEM_TYPE; #define KMS_X_LAST KMS_X static KMS_MSG_INLINE const char * kmip_item_type_to_string (kmip_item_type_t item_type) { switch (item_type) { default: return "Unknown KMIP item type"; KMS_XMACRO } } #undef KMS_X #undef KMS_X_LAST #undef KMS_XMACRO #endif /* KMS_KMIP_ITEM_TYPE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_reader_writer.c0000644000175100001660000003133314760300420023366 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "kms_kmip_reader_writer_private.h" #include "kms_endian_private.h" #include "kms_request_str.h" #include #define MAX_KMIP_WRITER_POSITIONS 10 /* KMIP encodes signed integers with two's complement. * Parsing functions read Integer / LongInteger as int32_t / int64_t by * reinterpreting byte representation. * Ensure that platform represents integers in two's complement. * See: https://stackoverflow.com/a/64843863/774658 */ #if (-1 & 3) != 3 #error Error: Twos complement integer representation is required. #endif struct _kmip_writer_t { kms_request_str_t *buffer; size_t positions[MAX_KMIP_WRITER_POSITIONS]; size_t cur_pos; }; kmip_writer_t * kmip_writer_new (void) { kmip_writer_t *writer = calloc (1, sizeof (kmip_writer_t)); writer->buffer = kms_request_str_new (); return writer; } void kmip_writer_destroy (kmip_writer_t *writer) { kms_request_str_destroy (writer->buffer); free (writer); } void kmip_writer_write_u8 (kmip_writer_t *writer, uint8_t value) { char *c = (char *) &value; kms_request_str_append_chars (writer->buffer, c, 1); } void kmip_writer_write_u16 (kmip_writer_t *writer, uint16_t value) { uint16_t v = KMS_UINT16_TO_BE (value); char *c = (char *) &v; kms_request_str_append_chars (writer->buffer, c, 2); } void kmip_writer_write_u32 (kmip_writer_t *writer, uint32_t value) { uint32_t v = KMS_UINT32_TO_BE (value); char *c = (char *) &v; kms_request_str_append_chars (writer->buffer, c, 4); } void kmip_writer_write_u64 (kmip_writer_t *writer, uint64_t value) { uint64_t v = KMS_UINT64_TO_BE (value); char *c = (char *) &v; kms_request_str_append_chars (writer->buffer, c, 8); } void kmip_writer_write_tag_enum (kmip_writer_t *writer, kmip_tag_type_t tag) { /* The 0x42 prefix is for tags built into the protocol. */ /* The 0x54 prefix is for extension tags. */ kmip_writer_write_u8 (writer, 0x42); kmip_writer_write_u16 (writer, (uint16_t) tag); } static size_t compute_padded_length (size_t len) { if (len % 8 == 0) { return len; } size_t padding = 8 - (len % 8); return len + padding; } void kmip_writer_write_string (kmip_writer_t *writer, kmip_tag_type_t tag, const char *str, size_t len) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_TextString); kmip_writer_write_u32 (writer, (uint32_t) len); size_t i; for (i = 0; i < len; i++) { kmip_writer_write_u8 (writer, (uint8_t) str[i]); } size_t padded_length = compute_padded_length (len); for (i = 0; i < padded_length - len; i++) { kmip_writer_write_u8 (writer, 0); } } void kmip_writer_write_bytes (kmip_writer_t *writer, kmip_tag_type_t tag, const char *str, size_t len) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_ByteString); kmip_writer_write_u32 (writer, (uint32_t) len); size_t i; for (i = 0; i < len; i++) { kmip_writer_write_u8 (writer, (uint8_t) str[i]); } size_t padded_length = compute_padded_length (len); for (i = 0; i < padded_length - len; i++) { kmip_writer_write_u8 (writer, 0); } } void kmip_writer_write_integer (kmip_writer_t *writer, kmip_tag_type_t tag, int32_t value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_Integer); kmip_writer_write_u32 (writer, 4); KMS_ASSERT (value >= 0); kmip_writer_write_u32 (writer, (uint32_t) value); kmip_writer_write_u32 (writer, 0); } void kmip_writer_write_long_integer (kmip_writer_t *writer, kmip_tag_type_t tag, int64_t value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_LongInteger); kmip_writer_write_u32 (writer, 8); KMS_ASSERT (value >= 0); kmip_writer_write_u64 (writer, (uint64_t) value); } void kmip_writer_write_enumeration (kmip_writer_t *writer, kmip_tag_type_t tag, int32_t value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_Enumeration); kmip_writer_write_u32 (writer, 4); KMS_ASSERT (value >= 0); kmip_writer_write_u32 (writer, (uint32_t) value); kmip_writer_write_u32 (writer, 0); } void kmip_writer_write_bool (kmip_writer_t *writer, kmip_tag_type_t tag, bool value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_Boolean); kmip_writer_write_u32 (writer, 8); kmip_writer_write_u64(writer, (uint64_t) value); } void kmip_writer_write_datetime (kmip_writer_t *writer, kmip_tag_type_t tag, int64_t value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_DateTime); kmip_writer_write_u32 (writer, 8); KMS_ASSERT (value >= 0); kmip_writer_write_u64 (writer, (uint64_t) value); } void kmip_writer_begin_struct (kmip_writer_t *writer, kmip_tag_type_t tag) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_Structure); size_t pos = writer->buffer->len; kmip_writer_write_u32 (writer, 0); KMS_ASSERT(writer->cur_pos < MAX_KMIP_WRITER_POSITIONS); writer->cur_pos++; writer->positions[writer->cur_pos] = pos; } void kmip_writer_close_struct (kmip_writer_t *writer) { size_t current_pos = writer->buffer->len; KMS_ASSERT(writer->cur_pos > 0); size_t start_pos = writer->positions[writer->cur_pos]; writer->cur_pos--; /* offset by 4 */ uint32_t len = (uint32_t) (current_pos - start_pos - 4); uint32_t v = KMS_UINT32_TO_BE (len); char *c = (char *) &v; memcpy (writer->buffer->str + start_pos, c, 4); } const uint8_t * kmip_writer_get_buffer (kmip_writer_t *writer, size_t* len) { *len = writer->buffer->len; return (const uint8_t*) writer->buffer->str; } struct _kmip_reader_t { uint8_t *ptr; size_t pos; size_t len; }; kmip_reader_t * kmip_reader_new (uint8_t *ptr, size_t len) { kmip_reader_t *reader = calloc (1, sizeof (kmip_reader_t)); reader->ptr = ptr; reader->len = len; return reader; } void kmip_reader_destroy (kmip_reader_t *reader) { free (reader); } bool kmip_reader_in_place (kmip_reader_t *reader, size_t pos, size_t len, kmip_reader_t *out_reader) { /* Everything should be padding to 8 byte boundaries. */ len = compute_padded_length (len); if ((pos + len) > reader->len) { return false; } memset (out_reader, 0, sizeof (kmip_reader_t)); out_reader->ptr = reader->ptr + reader->pos; out_reader->len = len; return true; } bool kmip_reader_has_data (kmip_reader_t *reader) { return reader->pos < reader->len; } #define CHECK_REMAINING_BUFFER_AND_RET(read_size) \ if ((reader->pos + (read_size)) > reader->len) { \ return false; \ } bool kmip_reader_read_u8 (kmip_reader_t *reader, uint8_t *value) { CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint8_t)); *value = *(reader->ptr + reader->pos); reader->pos += sizeof (uint8_t); return true; } bool kmip_reader_read_u16 (kmip_reader_t *reader, uint16_t *value) { CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint16_t)); uint16_t temp; memcpy (&temp, reader->ptr + reader->pos, sizeof (uint16_t)); *value = KMS_UINT16_FROM_BE (temp); reader->pos += sizeof (uint16_t); return true; } bool kmip_reader_read_u32 (kmip_reader_t *reader, uint32_t *value) { CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint32_t)); uint32_t temp; memcpy (&temp, reader->ptr + reader->pos, sizeof (uint32_t)); *value = KMS_UINT32_FROM_BE (temp); reader->pos += sizeof (uint32_t); return true; } bool kmip_reader_read_u64 (kmip_reader_t *reader, uint64_t *value) { CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint64_t)); uint64_t temp; memcpy (&temp, reader->ptr + reader->pos, sizeof (uint64_t)); *value = KMS_UINT64_FROM_BE (temp); reader->pos += sizeof (uint64_t); return true; } bool kmip_reader_read_bytes (kmip_reader_t *reader, uint8_t **ptr, size_t length) { size_t advance_length = compute_padded_length (length); CHECK_REMAINING_BUFFER_AND_RET (advance_length); *ptr = reader->ptr + reader->pos; reader->pos += advance_length; return true; } #define CHECK_AND_RET(x) \ if (!(x)) { \ return false; \ } bool kmip_reader_read_tag (kmip_reader_t *reader, kmip_tag_type_t *tag) { uint8_t tag_first; CHECK_AND_RET (kmip_reader_read_u8 (reader, &tag_first)); if (tag_first != 0x42) { return false; } uint16_t tag_second; CHECK_AND_RET (kmip_reader_read_u16 (reader, &tag_second)); *tag = (kmip_tag_type_t) (0x420000 + tag_second); return true; } bool kmip_reader_read_length (kmip_reader_t *reader, uint32_t *length) { return kmip_reader_read_u32 (reader, length); } bool kmip_reader_read_type (kmip_reader_t *reader, kmip_item_type_t *type) { uint8_t u8; CHECK_AND_RET (kmip_reader_read_u8 (reader, &u8)); *type = (kmip_item_type_t) u8; return true; } bool kmip_reader_read_enumeration (kmip_reader_t *reader, uint32_t *enum_value) { CHECK_AND_RET (kmip_reader_read_u32 (reader, enum_value)); /* Skip 4 bytes because enums are padded. */ uint32_t ignored; return kmip_reader_read_u32 (reader, &ignored); } bool kmip_reader_read_bool (kmip_reader_t *reader, bool *value) { uint64_t u64; CHECK_AND_RET (kmip_reader_read_u64 (reader, &u64)); *value = (bool) u64; return true; } bool kmip_reader_read_integer (kmip_reader_t *reader, int32_t *value) { CHECK_AND_RET (kmip_reader_read_u32 (reader, (uint32_t*) value)); /* Skip 4 bytes because integers are padded. */ uint32_t ignored; return kmip_reader_read_u32 (reader, &ignored); } bool kmip_reader_read_long_integer (kmip_reader_t *reader, int64_t *value) { return kmip_reader_read_u64 (reader, (uint64_t*) value); } bool kmip_reader_read_string (kmip_reader_t *reader, uint8_t **ptr, size_t length) { return kmip_reader_read_bytes (reader, ptr, length); } bool kmip_reader_find (kmip_reader_t *reader, kmip_tag_type_t search_tag, kmip_item_type_t type, size_t *pos, size_t *length) { reader->pos = 0; while (kmip_reader_has_data (reader)) { kmip_tag_type_t read_tag; CHECK_AND_RET (kmip_reader_read_tag (reader, &read_tag)); kmip_item_type_t read_type; CHECK_AND_RET (kmip_reader_read_type (reader, &read_type)); uint32_t read_length; CHECK_AND_RET (kmip_reader_read_length (reader, &read_length)); if (read_tag == search_tag && read_type == type) { *pos = reader->pos; *length = read_length; return true; } size_t advance_length = read_length; advance_length = compute_padded_length (advance_length); CHECK_REMAINING_BUFFER_AND_RET (advance_length); /* Skip to the next type. */ reader->pos += advance_length; } return false; } bool kmip_reader_find_and_recurse (kmip_reader_t *reader, kmip_tag_type_t tag) { size_t pos; size_t length; if (!kmip_reader_find (reader, tag, KMIP_ITEM_TYPE_Structure, &pos, &length)) { return false; } reader->pos = 0; reader->ptr = reader->ptr + pos; reader->len = length; return true; } bool kmip_reader_find_and_read_enum (kmip_reader_t *reader, kmip_tag_type_t tag, uint32_t *value) { size_t pos; size_t length; if (!kmip_reader_find (reader, tag, KMIP_ITEM_TYPE_Enumeration, &pos, &length)) { return false; } kmip_reader_t temp_reader; if (!kmip_reader_in_place (reader, pos, length, &temp_reader)) { return false; } return kmip_reader_read_enumeration (&temp_reader, value); } bool kmip_reader_find_and_read_bytes (kmip_reader_t *reader, kmip_tag_type_t tag, uint8_t **out_ptr, size_t *out_len) { size_t pos; if (!kmip_reader_find (reader, tag, KMIP_ITEM_TYPE_ByteString, &pos, out_len)) { return false; } kmip_reader_t temp_reader; if (!kmip_reader_in_place (reader, pos, *out_len, &temp_reader)) { return false; } return kmip_reader_read_bytes (&temp_reader, out_ptr, *out_len); } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_reader_writer_private.h0000644000175100001660000001043614760300420025126 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_READER_WRITER_PRIVATE_H #define KMS_KMIP_READER_WRITER_PRIVATE_H #include "kms_kmip_item_type_private.h" #include "kms_kmip_tag_type_private.h" #include "kms_message_private.h" #include typedef struct _kmip_writer_t kmip_writer_t; kmip_writer_t * kmip_writer_new (void); void kmip_writer_destroy (kmip_writer_t *writer); void kmip_writer_write_u8 (kmip_writer_t *writer, uint8_t value); void kmip_writer_write_u16 (kmip_writer_t *writer, uint16_t value); void kmip_writer_write_u32 (kmip_writer_t *writer, uint32_t value); void kmip_writer_write_u64 (kmip_writer_t *writer, uint64_t value); void kmip_writer_write_tag_enum (kmip_writer_t *writer, kmip_tag_type_t tag); void kmip_writer_write_string (kmip_writer_t *writer, kmip_tag_type_t tag, const char *str, size_t len); void kmip_writer_write_bytes (kmip_writer_t *writer, kmip_tag_type_t tag, const char *str, size_t len); void kmip_writer_write_integer (kmip_writer_t *writer, kmip_tag_type_t tag, int32_t value); void kmip_writer_write_long_integer (kmip_writer_t *writer, kmip_tag_type_t tag, int64_t value); void kmip_writer_write_enumeration (kmip_writer_t *writer, kmip_tag_type_t tag, int32_t value); void kmip_writer_write_bool (kmip_writer_t *writer, kmip_tag_type_t tag, bool value); void kmip_writer_write_datetime (kmip_writer_t *writer, kmip_tag_type_t tag, int64_t value); void kmip_writer_begin_struct (kmip_writer_t *writer, kmip_tag_type_t tag); void kmip_writer_close_struct (kmip_writer_t *writer); const uint8_t * kmip_writer_get_buffer (kmip_writer_t *writer, size_t* len); typedef struct _kmip_reader_t kmip_reader_t; kmip_reader_t * kmip_reader_new (uint8_t *ptr, size_t len); void kmip_reader_destroy (kmip_reader_t *reader); bool kmip_reader_in_place (kmip_reader_t *reader, size_t pos, size_t len, kmip_reader_t *out_reader); bool kmip_reader_has_data (kmip_reader_t *reader); bool kmip_reader_read_u8 (kmip_reader_t *reader, uint8_t *value); bool kmip_reader_read_u16 (kmip_reader_t *reader, uint16_t *value); bool kmip_reader_read_u32 (kmip_reader_t *reader, uint32_t *value); bool kmip_reader_read_u64 (kmip_reader_t *reader, uint64_t *value); bool kmip_reader_read_tag (kmip_reader_t *reader, kmip_tag_type_t *tag); bool kmip_reader_read_length (kmip_reader_t *reader, uint32_t *length); bool kmip_reader_read_type (kmip_reader_t *reader, kmip_item_type_t *type); bool kmip_reader_read_enumeration (kmip_reader_t *reader, uint32_t *enum_value); bool kmip_reader_read_bool (kmip_reader_t *reader, bool *value); bool kmip_reader_read_integer (kmip_reader_t *reader, int32_t *value); bool kmip_reader_read_long_integer (kmip_reader_t *reader, int64_t *value); bool kmip_reader_read_bytes (kmip_reader_t *reader, uint8_t **ptr, size_t length); bool kmip_reader_read_string (kmip_reader_t *reader, uint8_t **ptr, size_t length); /* kmip_reader_find does not descend structures. * To find and descend into a structure use kmip_reader_find_and_recurse. */ bool kmip_reader_find (kmip_reader_t *reader, kmip_tag_type_t search_tag, kmip_item_type_t type, size_t *pos, size_t *length); bool kmip_reader_find_and_recurse (kmip_reader_t *reader, kmip_tag_type_t tag); bool kmip_reader_find_and_read_enum (kmip_reader_t *reader, kmip_tag_type_t tag, uint32_t *value); bool kmip_reader_find_and_read_bytes (kmip_reader_t *reader, kmip_tag_type_t tag, uint8_t **out_ptr, size_t *out_len); #endif /* KMS_KMIP_READER_WRITER_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_request.c0000644000175100001660000004724014760300420022224 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "kms_message/kms_kmip_request.h" #include "kms_kmip_tag_type_private.h" #include "kms_message_private.h" #include "kms_kmip_reader_writer_private.h" #include #include static void copy_writer_buffer (kms_request_t *req, kmip_writer_t *writer) { const uint8_t *buf; size_t buflen; buf = kmip_writer_get_buffer (writer, &buflen); req->kmip.data = malloc (buflen); memcpy (req->kmip.data, buf, buflen); req->kmip.len = (uint32_t) buflen; } kms_request_t * kms_kmip_request_register_secretdata_new (void *reserved, const uint8_t *data, size_t len) { /* Create a KMIP Register request with a 96 byte SecretData of this form: */ kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; if (len != KMS_KMIP_REQUEST_SECRETDATA_LENGTH) { KMS_ERROR (req, "expected SecretData length of %d, got %" PRIu32, KMS_KMIP_REQUEST_SECRETDATA_LENGTH, len); return req; } writer = kmip_writer_new (); kmip_writer_begin_struct (writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 0); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x03 == Register */ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, 0x03); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); /* 0x07 == SecretData */ kmip_writer_write_enumeration (writer, KMIP_TAG_ObjectType, 0x07); kmip_writer_begin_struct (writer, KMIP_TAG_TemplateAttribute); // Add required Cryptographic Usage Mask attribute. { kmip_writer_begin_struct (writer, KMIP_TAG_Attribute); const char *cryptographicUsageMaskStr = "Cryptographic Usage Mask"; kmip_writer_write_string (writer, KMIP_TAG_AttributeName, cryptographicUsageMaskStr, strlen (cryptographicUsageMaskStr)); // Use 0 because the Secret Data object is not used in cryptographic // operations on the KMIP server. kmip_writer_write_integer (writer, KMIP_TAG_AttributeValue, 0); kmip_writer_close_struct (writer); } kmip_writer_close_struct (writer); /* KMIP_TAG_TemplateAttribute */ kmip_writer_begin_struct (writer, KMIP_TAG_SecretData); /* 0x02 = Seed */ kmip_writer_write_enumeration (writer, KMIP_TAG_SecretDataType, 0x02); kmip_writer_begin_struct (writer, KMIP_TAG_KeyBlock); /* 0x02 = Opaque */ kmip_writer_write_enumeration (writer, KMIP_TAG_KeyFormatType, 0x02); kmip_writer_begin_struct (writer, KMIP_TAG_KeyValue); kmip_writer_write_bytes ( writer, KMIP_TAG_KeyMaterial, (const char *) data, len); kmip_writer_close_struct (writer); /* KMIP_TAG_KeyValue */ kmip_writer_close_struct (writer); /* KMIP_TAG_KeyBlock */ kmip_writer_close_struct (writer); /* KMIP_TAG_SecretData */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } kms_request_t * kms_kmip_request_activate_new (void *reserved, const char *unique_identifer) { /* Create a KMIP Activate request of this form: */ kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; writer = kmip_writer_new (); kmip_writer_begin_struct (writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 0); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x12 == Activate */ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, 0x12); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); kmip_writer_write_string (writer, KMIP_TAG_UniqueIdentifier, unique_identifer, strlen (unique_identifer)); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } kms_request_t * kms_kmip_request_get_new (void *reserved, const char *unique_identifer) { /* Create a KMIP Get request of this form: */ kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; writer = kmip_writer_new (); kmip_writer_begin_struct (writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 0); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x0A == Get */ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, 0x0A); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); kmip_writer_write_string (writer, KMIP_TAG_UniqueIdentifier, unique_identifer, strlen (unique_identifer)); /* 0x01 = Raw */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ /* Copy the KMIP writer buffer to a KMIP request. */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } kms_request_t * kms_kmip_request_create_new (void *reserved) { /* Create a KMIP Create request of this form: */ kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; writer = kmip_writer_new(); kmip_writer_begin_struct(writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 2); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x01 == Create */ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, 0x01); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); /* 0x02 == symmetric key */ kmip_writer_write_enumeration(writer, KMIP_TAG_ObjectType, 0x02); { kmip_writer_begin_struct (writer, KMIP_TAG_TemplateAttribute); kmip_writer_begin_struct (writer, KMIP_TAG_Attribute); const char *cryptographicAlgorithmStr = "Cryptographic Algorithm"; kmip_writer_write_string (writer, KMIP_TAG_AttributeName, cryptographicAlgorithmStr, strlen (cryptographicAlgorithmStr)); kmip_writer_write_enumeration (writer, KMIP_TAG_AttributeValue, 3 /* AES */); kmip_writer_close_struct (writer); kmip_writer_begin_struct (writer, KMIP_TAG_Attribute); const char *cryptographicLengthStr = "Cryptographic Length"; kmip_writer_write_string (writer, KMIP_TAG_AttributeName, cryptographicLengthStr, strlen (cryptographicLengthStr)); kmip_writer_write_integer (writer, KMIP_TAG_AttributeValue, 256); kmip_writer_close_struct (writer); kmip_writer_begin_struct (writer, KMIP_TAG_Attribute); const char *cryptographicUsageMaskStr = "Cryptographic Usage Mask"; kmip_writer_write_string (writer, KMIP_TAG_AttributeName, cryptographicUsageMaskStr, strlen (cryptographicUsageMaskStr)); kmip_writer_write_integer (writer, KMIP_TAG_AttributeValue, 4 | 8 /* Encrypt | Decrypt */); kmip_writer_close_struct (writer); kmip_writer_close_struct (writer); /* KMIP_TAG_TemplateAttribute */ } kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ /* Copy the KMIP writer buffer to a KMIP request. */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } static kms_request_t * kmip_encrypt_decrypt (const char* unique_identifer, const uint8_t *data, size_t len, const uint8_t *iv_data, size_t iv_len, bool encrypt) { kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; writer = kmip_writer_new(); kmip_writer_begin_struct(writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 2); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x1F == Encrypt, 0x20 == Decrypt*/ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, encrypt ? 0x1F : 0x20); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); kmip_writer_write_string (writer, KMIP_TAG_UniqueIdentifier, unique_identifer, strlen (unique_identifer)); kmip_writer_begin_struct (writer, KMIP_TAG_CryptographicParameters); kmip_writer_write_enumeration(writer, KMIP_TAG_BlockCipherMode, 1 /* CBC */); kmip_writer_write_enumeration(writer, KMIP_TAG_PaddingMethod, 3 /* PKCS5 */); kmip_writer_write_enumeration(writer, KMIP_TAG_CryptographicAlgorithm, 3 /* AES */); if (encrypt) kmip_writer_write_bool(writer, KMIP_TAG_RandomIV, true); kmip_writer_close_struct(writer); /* KMIP_TAG_CryptographicParameters */ kmip_writer_write_bytes(writer, KMIP_TAG_Data, (char *) data, len); if (!encrypt) kmip_writer_write_bytes(writer, KMIP_TAG_IVCounterNonce, (char *) iv_data, iv_len); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ /* Copy the KMIP writer buffer to a KMIP request. */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } kms_request_t * kms_kmip_request_encrypt_new (void *reserved, const char* unique_identifer, const uint8_t *plaintext, size_t len) { /* Create a KMIP Encrypt request of this form: */ return kmip_encrypt_decrypt(unique_identifer, plaintext, len, NULL, 0, true); } kms_request_t * kms_kmip_request_decrypt_new (void *reserved, const char* unique_identifer, const uint8_t *ciphertext, size_t len, const uint8_t *iv_data, size_t iv_len) { /* Create a KMIP Decrypt request of this form: */ return kmip_encrypt_decrypt(unique_identifer, ciphertext, len, iv_data, iv_len, false); } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_response.c0000644000175100001660000003611314760300420022367 0ustar #include "kms_message/kms_kmip_response.h" #include "kms_kmip_item_type_private.h" #include "kms_kmip_tag_type_private.h" #include "kms_message_private.h" #include "kms_kmip_reader_writer_private.h" #include "kms_kmip_result_reason_private.h" #include "kms_kmip_result_status_private.h" #include #include #include /* CHAR_BIT */ static bool check_and_require_kmip (kms_response_t *res) { if (res->provider != KMS_REQUEST_PROVIDER_KMIP) { KMS_ERROR (res, "Function requires KMIP request"); return false; } return true; } /* Example of an error message: */ static bool kms_kmip_response_ok (kms_response_t *res) { kmip_reader_t *reader = NULL; size_t pos; size_t len; uint32_t result_status; uint32_t result_reason = 0; const char *result_message = ""; uint32_t result_message_len = 0; bool ok = false; reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } /* Look for optional Result Reason. */ if (kmip_reader_find (reader, KMIP_TAG_ResultReason, KMIP_ITEM_TYPE_Enumeration, &pos, &len)) { if (!kmip_reader_read_enumeration (reader, &result_reason)) { KMS_ERROR (res, "unable to read result reason value"); goto fail; } } /* Look for optional Result Message. */ if (kmip_reader_find (reader, KMIP_TAG_ResultMessage, KMIP_ITEM_TYPE_TextString, &pos, &len)) { if (!kmip_reader_read_string ( reader, (uint8_t **) &result_message, len)) { KMS_ERROR (res, "unable to read result message value"); goto fail; } result_message_len = (uint32_t) len; } /* Look for required Result Status. */ if (!kmip_reader_find (reader, KMIP_TAG_ResultStatus, KMIP_ITEM_TYPE_Enumeration, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResultStatus)); goto fail; } if (!kmip_reader_read_enumeration (reader, &result_status)) { KMS_ERROR (res, "unable to read result status value"); goto fail; } if (result_status != KMIP_RESULT_STATUS_OperationSuccess) { KMS_ERROR (res, "KMIP response error. Result Status (%" PRIu32 "): %s. Result Reason (%" PRIu32 "): %s. Result Message: %.*s", result_status, kmip_result_status_to_string (result_status), result_reason, kmip_result_reason_to_string (result_reason), result_message_len, result_message); goto fail; } ok = true; fail: kmip_reader_destroy (reader); return ok; } /* Example of a successful response to a Register request: */ char * kms_kmip_response_get_unique_identifier (kms_response_t *res) { kmip_reader_t *reader = NULL; size_t pos; size_t len; char *uid = NULL; kms_request_str_t *nullterminated = NULL; if (!check_and_require_kmip (res)) { goto fail; } if (!kms_kmip_response_ok (res)) { goto fail; } reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponsePayload)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponsePayload)); goto fail; } if (!kmip_reader_find (reader, KMIP_TAG_UniqueIdentifier, KMIP_ITEM_TYPE_TextString, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_UniqueIdentifier)); goto fail; } if (!kmip_reader_read_string (reader, (uint8_t **) &uid, len)) { KMS_ERROR (res, "unable to read unique identifier"); goto fail; } KMS_ASSERT (len <= SSIZE_MAX); nullterminated = kms_request_str_new_from_chars (uid, (ssize_t) len); fail: kmip_reader_destroy (reader); return kms_request_str_detach (nullterminated); } /* Example of a successful response to an Encrypt request: */ uint8_t * kms_kmip_response_get_iv (kms_response_t *res, size_t *datalen) { kmip_reader_t *reader = NULL; size_t pos; size_t len; uint8_t *data = NULL; uint8_t *tmp; if (!check_and_require_kmip (res)) { goto fail; } if (!kms_kmip_response_ok (res)) { goto fail; } reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponsePayload)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponsePayload)); goto fail; } if (!kmip_reader_find (reader, KMIP_TAG_IVCounterNonce, KMIP_ITEM_TYPE_ByteString, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_Data)); goto fail; } if (!kmip_reader_read_bytes (reader, &tmp, len)) { KMS_ERROR (res, "unable to read data bytes"); goto fail; } data = malloc (len); memcpy (data, tmp, len); *datalen = len; fail: kmip_reader_destroy (reader); return data; } /* Example of a successful response to a Decrypt request: */ uint8_t * kms_kmip_response_get_data (kms_response_t *res, size_t *datalen) { kmip_reader_t *reader = NULL; size_t pos; size_t len; uint8_t *data = NULL; uint8_t *tmp; if (!check_and_require_kmip (res)) { goto fail; } if (!kms_kmip_response_ok (res)) { goto fail; } reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponsePayload)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponsePayload)); goto fail; } if (!kmip_reader_find (reader, KMIP_TAG_Data, KMIP_ITEM_TYPE_ByteString, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_Data)); goto fail; } if (!kmip_reader_read_bytes (reader, &tmp, len)) { KMS_ERROR (res, "unable to read data bytes"); goto fail; } data = malloc (len); memcpy (data, tmp, len); *datalen = len; fail: kmip_reader_destroy (reader); return data; } /* Example of a successful response to a Get request: */ uint8_t * kms_kmip_response_get_secretdata (kms_response_t *res, size_t *secretdatalen) { kmip_reader_t *reader = NULL; size_t pos; size_t len; uint8_t *secretdata = NULL; uint8_t *tmp; if (!check_and_require_kmip (res)) { goto fail; } if (!kms_kmip_response_ok (res)) { goto fail; } reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponsePayload)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponsePayload)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_SecretData)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_SecretData)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_KeyBlock)) { KMS_ERROR ( res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_KeyBlock)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_KeyValue)) { KMS_ERROR ( res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_KeyValue)); goto fail; } if (!kmip_reader_find (reader, KMIP_TAG_KeyMaterial, KMIP_ITEM_TYPE_ByteString, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_KeyMaterial)); goto fail; } if (!kmip_reader_read_bytes (reader, &tmp, len)) { KMS_ERROR (res, "unable to read secretdata bytes"); goto fail; } secretdata = malloc (len); memcpy (secretdata, tmp, len); *secretdatalen = len; fail: kmip_reader_destroy (reader); return secretdata; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_response_parser.c0000644000175100001660000001050714760300420023742 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "kms_message/kms_kmip_response_parser.h" #include "kms_endian_private.h" #include "kms_kmip_response_parser_private.h" #include "kms_message_private.h" #include "kms_request_str.h" struct _kms_kmip_response_parser_t { uint32_t first_len; uint32_t bytes_fed; kms_request_str_t *buf; bool failed; char error[512]; }; /* FIRST_LENGTH_OFFSET is the offset of the first Length in a TTLV sequence. The * sequence is: Tag (3 bytes), Type (1 byte), Length (4 bytes), Value (Length * bytes). */ static const uint32_t FIRST_LENGTH_OFFSET = 4; /* _parser_destroy destroys the fields of parser, but not the parser itself. */ static void _parser_destroy (kms_kmip_response_parser_t *parser) { kms_request_str_destroy (parser->buf); } /* _parser_init initializes the members of parser. */ static void _parser_init (kms_kmip_response_parser_t *parser) { memset (parser, 0, sizeof (*parser)); parser->buf = kms_request_str_new (); } kms_response_parser_t * kms_kmip_response_parser_new (void *reserved) { kms_response_parser_t *parser = kms_response_parser_new (); parser->kmip = malloc (sizeof (kms_kmip_response_parser_t)); _parser_init (parser->kmip); return parser; } int32_t kms_kmip_response_parser_wants_bytes (const kms_kmip_response_parser_t *parser, int32_t max) { int32_t wants_bytes; uint32_t total_len; uint32_t want_bytes_pending; if (parser->bytes_fed < KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH) { wants_bytes = KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH - (int32_t) parser->bytes_fed; } else { KMS_ASSERT (parser->first_len <= UINT32_MAX - KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH); total_len = parser->first_len + KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH; KMS_ASSERT (total_len >= parser->bytes_fed); want_bytes_pending = total_len - parser->bytes_fed; KMS_ASSERT (want_bytes_pending <= (uint32_t) INT32_MAX); wants_bytes = (int32_t) want_bytes_pending; } if (max < wants_bytes) { return max; } return wants_bytes; } bool kms_kmip_response_parser_feed (kms_kmip_response_parser_t *parser, const uint8_t *buf, uint32_t len) { kms_request_str_append_chars (parser->buf, (char *) buf, len); parser->bytes_fed += len; if (parser->first_len > 0) { if (parser->bytes_fed > parser->first_len + KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH) { KMS_ERROR (parser, "KMIP parser was fed too much data"); return false; } } else if (parser->first_len == 0 && parser->bytes_fed >= KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH) { uint32_t temp; memcpy (&temp, parser->buf->str + FIRST_LENGTH_OFFSET, sizeof (uint32_t)); parser->first_len = KMS_UINT32_FROM_BE (temp); } return true; } kms_response_t * kms_kmip_response_parser_get_response (kms_kmip_response_parser_t *parser) { kms_response_t *res; if (kms_kmip_response_parser_wants_bytes (parser, 1) != 0) { KMS_ERROR (parser, "KMIP parser does not have a complete message"); return NULL; } res = calloc (1, sizeof (kms_response_t)); res->provider = KMS_REQUEST_PROVIDER_KMIP; res->kmip.len = (uint32_t) parser->buf->len; res->kmip.data = (uint8_t *) kms_request_str_detach (parser->buf); parser->buf = NULL; /* Reinitialize for reuse. */ _parser_destroy (parser); _parser_init (parser); return res; } const char * kms_kmip_response_parser_error (const kms_kmip_response_parser_t *parser) { return parser->failed ? parser->error : NULL; } void kms_kmip_response_parser_destroy (kms_kmip_response_parser_t *parser) { if (!parser) { return; } _parser_destroy (parser); free (parser); } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_response_parser_private.h0000644000175100001660000000370314760300420025501 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESPONSE_PARSER_PRIVATE_H #define KMS_KMIP_RESPONSE_PARSER_PRIVATE_H #include "kms_message/kms_response.h" #include #include /* kms_kmip_response_parser_t is a private type used for parsing a KMIP * response. */ typedef struct _kms_kmip_response_parser_t kms_kmip_response_parser_t; /* KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH is the number of bytes needed by the * parser to determine the total length of the message being parsed. * It includes the first Length in a TTLV sequence. The sequence is: Tag (3 * bytes), Type (1 byte), Length (4 bytes), Value (Length bytes). */ #define KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH 8 int32_t kms_kmip_response_parser_wants_bytes (const kms_kmip_response_parser_t *parser, int32_t max); bool kms_kmip_response_parser_feed (kms_kmip_response_parser_t *parser, const uint8_t *buf, uint32_t len); /* kms_kmip_response_parser_get_response returns a kms_response_t and resets the * parser. */ kms_response_t * kms_kmip_response_parser_get_response (kms_kmip_response_parser_t *parser); void kms_kmip_response_parser_destroy (kms_kmip_response_parser_t *parser); const char * kms_kmip_response_parser_error (const kms_kmip_response_parser_t *parser); #endif /* KMS_KMIP_RESPONSE_PARSER_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_result_reason_private.h0000644000175100001660000000765714760300420025170 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESULT_REASON_PRIVATE_H #define KMS_KMIP_RESULT_REASON_PRIVATE_H #include "kms_message/kms_message_defines.h" /* clang-format off */ #define KMS_XMACRO \ KMS_X (ItemNotFound, "Item Not Found", 0x00000001) \ KMS_X (ResponseTooLarge, "Response Too Large", 0x00000002) \ KMS_X (AuthenticationNotSuccessful, "Authentication Not Successful", 0x00000003) \ KMS_X (InvalidMessage, "Invalid Message", 0x00000004) \ KMS_X (OperationNotSupported, "Operation Not Supported", 0x00000005) \ KMS_X (MissingData, "Missing Data", 0x00000006) \ KMS_X (InvalidField, "Invalid Field", 0x00000007) \ KMS_X (FeatureNotSupported, "Feature Not Supported", 0x00000008) \ KMS_X (OperationCanceledByRequester, "Operation Canceled By Requester", 0x00000009) \ KMS_X (CryptographicFailure, "Cryptographic Failure", 0x0000000A) \ KMS_X (IllegalOperation, "Illegal Operation", 0x0000000B) \ KMS_X (PermissionDenied, "Permission Denied", 0x0000000C) \ KMS_X (Objectarchived, "Object archived", 0x0000000D) \ KMS_X (IndexOutofBounds, "Index Out of Bounds", 0x0000000E) \ KMS_X (ApplicationNamespaceNotSupported, "Application Namespace Not Supported", 0x0000000F) \ KMS_X (KeyFormatTypeNotSupported, "Key Format Type Not Supported", 0x00000010) \ KMS_X (KeyCompressionTypeNotSupported, "Key Compression Type Not Supported", 0x00000011) \ KMS_X (EncodingOptionError, "Encoding Option Error", 0x00000012) \ KMS_X (KeyValueNotPresent, "Key Value Not Present", 0x00000013) \ KMS_X (AttestationRequired, "Attestation Required", 0x00000014) \ KMS_X (AttestationFailed, "Attestation Failed", 0x00000015) \ KMS_X (Sensitive, "Sensitive", 0x00000016) \ KMS_X (NotExtractable, "Not Extractable", 0x00000017) \ KMS_X (ObjectAlreadyExists, "Object Already Exists", 0x00000018) \ KMS_X_LAST (GeneralFailure, "General Failure", 0x00000100) /* clang-format on */ /* Generate an enum with each result_reason value. */ #define KMS_X(RESULT_REASON, STR, VAL) KMIP_RESULT_REASON_##RESULT_REASON = VAL, #define KMS_X_LAST(RESULT_REASON, STR, VAL) \ KMIP_RESULT_REASON_##RESULT_REASON = VAL typedef enum { KMS_XMACRO } kmip_result_reason_t; #undef KMS_X #undef KMS_X_LAST #define KMS_X(RESULT_REASON, STR, VAL) \ case KMIP_RESULT_REASON_##RESULT_REASON: \ return STR; #define KMS_X_LAST KMS_X static KMS_MSG_INLINE const char * kmip_result_reason_to_string (kmip_result_reason_t result_reason) { switch (result_reason) { default: return "Unknown KMIP result reason"; KMS_XMACRO } } #undef KMS_X #undef KMS_X_LAST #undef KMS_XMACRO #endif /* KMS_KMIP_RESULT_REASON_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_result_status_private.h0000644000175100001660000000340714760300420025211 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESULT_STATUS_PRIVATE_H #define KMS_KMIP_RESULT_STATUS_PRIVATE_H #include "kms_message/kms_message_defines.h" #define KMS_XMACRO \ KMS_X (OperationSuccess, "Success", 0x00000000) \ KMS_X (OperationFailed, "Operation Failed", 0x00000001) \ KMS_X (OperationPending, "Operation Pending", 0x00000002) \ KMS_X_LAST (OperationUndone, "Operation Undone", 0x00000003) /* Generate an enum with each result_status value. */ #define KMS_X(RESULT_STATUS, STR, VAL) KMIP_RESULT_STATUS_##RESULT_STATUS = VAL, #define KMS_X_LAST(RESULT_STATUS, STR, VAL) \ KMIP_RESULT_STATUS_##RESULT_STATUS = VAL typedef enum { KMS_XMACRO } kmip_result_status_t; #undef KMS_X #undef KMS_X_LAST #define KMS_X(RESULT_STATUS, STR, VAL) \ case KMIP_RESULT_STATUS_##RESULT_STATUS: \ return STR; #define KMS_X_LAST KMS_X static KMS_MSG_INLINE const char * kmip_result_status_to_string (kmip_result_status_t result_status) { switch (result_status) { default: return "Unknown KMIP result status"; KMS_XMACRO } } #undef KMS_X #undef KMS_X_LAST #undef KMS_XMACRO #endif /* KMS_KMIP_RESULT_STATUS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kmip_tag_type_private.h0000644000175100001660000007036614760300420024114 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_TAG_TYPE_PRIVATE_H #define KMS_KMIP_TAG_TYPE_PRIVATE_H #include "kms_message/kms_message_defines.h" /* clang-format off */ #define KMS_XMACRO \ KMS_X (ActivationDate, 0x420001) \ KMS_X (ApplicationData, 0x420002) \ KMS_X (ApplicationNamespace, 0x420003) \ KMS_X (ApplicationSpecificInformation, 0x420004) \ KMS_X (ArchiveDate, 0x420005) \ KMS_X (AsynchronousCorrelationValue, 0x420006) \ KMS_X (AsynchronousIndicator, 0x420007) \ KMS_X (Attribute, 0x420008) \ KMS_X (AttributeIndex, 0x420009) \ KMS_X (AttributeName, 0x42000A) \ KMS_X (AttributeValue, 0x42000B) \ KMS_X (Authentication, 0x42000C) \ KMS_X (BatchCount, 0x42000D) \ KMS_X (BatchErrorContinuationOption, 0x42000E) \ KMS_X (BatchItem, 0x42000F) \ KMS_X (BatchOrderOption, 0x420010) \ KMS_X (BlockCipherMode, 0x420011) \ KMS_X (CancellationResult, 0x420012) \ KMS_X (Certificate, 0x420013) \ KMS_X (CertificateIdentifier, 0x420014) /* deprecated as of version 1.1 */ \ KMS_X (CertificateIssuer, 0x420015) /* deprecated as of version 1.1 */ \ KMS_X (CertificateIssuerAlternativeName, 0x420016) /* deprecated as of version 1.1 */ \ KMS_X (CertificateIssuerDistinguishedName, 0x420017) /* deprecated as of version 1.1 */ \ KMS_X (CertificateRequest, 0x420018) \ KMS_X (CertificateRequestType, 0x420019) \ KMS_X (CertificateSubject, 0x42001A) /* deprecated as of version 1.1 */ \ KMS_X (CertificateSubjectAlternativeName, 0x42001B) /* deprecated as of version 1.1 */ \ KMS_X (CertificateSubjectDistinguishedName, 0x42001C) /* deprecated as of version 1.1 */ \ KMS_X (CertificateType, 0x42001D) \ KMS_X (CertificateValue, 0x42001E) \ KMS_X (CommonTemplateAttribute, 0x42001F) \ KMS_X (CompromiseDate, 0x420020) \ KMS_X (CompromiseOccurrenceDate, 0x420021) \ KMS_X (ContactInformation, 0x420022) \ KMS_X (Credential, 0x420023) \ KMS_X (CredentialType, 0x420024) \ KMS_X (CredentialValue, 0x420025) \ KMS_X (CriticalityIndicator, 0x420026) \ KMS_X (CRTCoefficient, 0x420027) \ KMS_X (CryptographicAlgorithm, 0x420028) \ KMS_X (CryptographicDomainParameters, 0x420029) \ KMS_X (CryptographicLength, 0x42002A) \ KMS_X (CryptographicParameters, 0x42002B) \ KMS_X (CryptographicUsageMask, 0x42002C) \ KMS_X (CustomAttribute, 0x42002D) \ KMS_X (D, 0x42002E) \ KMS_X (DeactivationDate, 0x42002F) \ KMS_X (DerivationData, 0x420030) \ KMS_X (DerivationMethod, 0x420031) \ KMS_X (DerivationParameters, 0x420032) \ KMS_X (DestroyDate, 0x420033) \ KMS_X (Digest, 0x420034) \ KMS_X (DigestValue, 0x420035) \ KMS_X (EncryptionKeyInformation, 0x420036) \ KMS_X (G, 0x420037) \ KMS_X (HashingAlgorithm, 0x420038) \ KMS_X (InitialDate, 0x420039) \ KMS_X (InitializationVector, 0x42003A) \ KMS_X (Issuer, 0x42003B) /* deprecated as of version 1.1 */ \ KMS_X (IterationCount, 0x42003C) \ KMS_X (IVCounterNonce, 0x42003D) \ KMS_X (J, 0x42003E) \ KMS_X (Key, 0x42003F) \ KMS_X (KeyBlock, 0x420040) \ KMS_X (KeyCompressionType, 0x420041) \ KMS_X (KeyFormatType, 0x420042) \ KMS_X (KeyMaterial, 0x420043) \ KMS_X (KeyPartIdentifier, 0x420044) \ KMS_X (KeyValue, 0x420045) \ KMS_X (KeyWrappingData, 0x420046) \ KMS_X (KeyWrappingSpecification, 0x420047) \ KMS_X (LastChangeDate, 0x420048) \ KMS_X (LeaseTime, 0x420049) \ KMS_X (Link, 0x42004A) \ KMS_X (LinkType, 0x42004B) \ KMS_X (LinkedObjectIdentifier, 0x42004C) \ KMS_X (MACSignature, 0x42004D) \ KMS_X (MACSignatureKeyInformation, 0x42004E) \ KMS_X (MaximumItems, 0x42004F) \ KMS_X (MaximumResponseSize, 0x420050) \ KMS_X (MessageExtension, 0x420051) \ KMS_X (Modulus, 0x420052) \ KMS_X (Name, 0x420053) \ KMS_X (NameType, 0x420054) \ KMS_X (NameValue, 0x420055) \ KMS_X (ObjectGroup, 0x420056) \ KMS_X (ObjectType, 0x420057) \ KMS_X (Offset, 0x420058) \ KMS_X (OpaqueDataType, 0x420059) \ KMS_X (OpaqueDataValue, 0x42005A) \ KMS_X (OpaqueObject, 0x42005B) \ KMS_X (Operation, 0x42005C) \ KMS_X (OperationPolicyName, 0x42005D) /* deprecated */ \ KMS_X (P, 0x42005E) \ KMS_X (PaddingMethod, 0x42005F) \ KMS_X (PrimeExponentP, 0x420060) \ KMS_X (PrimeExponentQ, 0x420061) \ KMS_X (PrimeFieldSize, 0x420062) \ KMS_X (PrivateExponent, 0x420063) \ KMS_X (PrivateKey, 0x420064) \ KMS_X (PrivateKeyTemplateAttribute, 0x420065) \ KMS_X (PrivateKeyUniqueIdentifier, 0x420066) \ KMS_X (ProcessStartDate, 0x420067) \ KMS_X (ProtectStopDate, 0x420068) \ KMS_X (ProtocolVersion, 0x420069) \ KMS_X (ProtocolVersionMajor, 0x42006A) \ KMS_X (ProtocolVersionMinor, 0x42006B) \ KMS_X (PublicExponent, 0x42006C) \ KMS_X (PublicKey, 0x42006D) \ KMS_X (PublicKeyTemplateAttribute, 0x42006E) \ KMS_X (PublicKeyUniqueIdentifier, 0x42006F) \ KMS_X (PutFunction, 0x420070) \ KMS_X (Q, 0x420071) \ KMS_X (QString, 0x420072) \ KMS_X (Qlength, 0x420073) \ KMS_X (QueryFunction, 0x420074) \ KMS_X (RecommendedCurve, 0x420075) \ KMS_X (ReplacedUniqueIdentifier, 0x420076) \ KMS_X (RequestHeader, 0x420077) \ KMS_X (RequestMessage, 0x420078) \ KMS_X (RequestPayload, 0x420079) \ KMS_X (ResponseHeader, 0x42007A) \ KMS_X (ResponseMessage, 0x42007B) \ KMS_X (ResponsePayload, 0x42007C) \ KMS_X (ResultMessage, 0x42007D) \ KMS_X (ResultReason, 0x42007E) \ KMS_X (ResultStatus, 0x42007F) \ KMS_X (RevocationMessage, 0x420080) \ KMS_X (RevocationReason, 0x420081) \ KMS_X (RevocationReasonCode, 0x420082) \ KMS_X (KeyRoleType, 0x420083) \ KMS_X (Salt, 0x420084) \ KMS_X (SecretData, 0x420085) \ KMS_X (SecretDataType, 0x420086) \ KMS_X (SerialNumber, 0x420087) /* deprecated as of version 1.1 */ \ KMS_X (ServerInformation, 0x420088) \ KMS_X (SplitKey, 0x420089) \ KMS_X (SplitKeyMethod, 0x42008A) \ KMS_X (SplitKeyParts, 0x42008B) \ KMS_X (SplitKeyThreshold, 0x42008C) \ KMS_X (State, 0x42008D) \ KMS_X (StorageStatusMask, 0x42008E) \ KMS_X (SymmetricKey, 0x42008F) \ KMS_X (Template, 0x420090) \ KMS_X (TemplateAttribute, 0x420091) \ KMS_X (TimeStamp, 0x420092) \ KMS_X (UniqueBatchItemID, 0x420093) \ KMS_X (UniqueIdentifier, 0x420094) \ KMS_X (UsageLimits, 0x420095) \ KMS_X (UsageLimitsCount, 0x420096) \ KMS_X (UsageLimitsTotal, 0x420097) \ KMS_X (UsageLimitsUnit, 0x420098) \ KMS_X (Username, 0x420099) \ KMS_X (ValidityDate, 0x42009A) \ KMS_X (ValidityIndicator, 0x42009B) \ KMS_X (VendorExtension, 0x42009C) \ KMS_X (VendorIdentification, 0x42009D) \ KMS_X (WrappingMethod, 0x42009E) \ KMS_X (X, 0x42009F) \ KMS_X (Y, 0x4200A0) \ KMS_X (Password, 0x4200A1) \ KMS_X (DeviceIdentifier, 0x4200A2) \ KMS_X (EncodingOption, 0x4200A3) \ KMS_X (ExtensionInformation, 0x4200A4) \ KMS_X (ExtensionName, 0x4200A5) \ KMS_X (ExtensionTag, 0x4200A6) \ KMS_X (ExtensionType, 0x4200A7) \ KMS_X (Fresh, 0x4200A8) \ KMS_X (MachineIdentifier, 0x4200A9) \ KMS_X (MediaIdentifier, 0x4200AA) \ KMS_X (NetworkIdentifier, 0x4200AB) \ KMS_X (ObjectGroupMember, 0x4200AC) \ KMS_X (CertificateLength, 0x4200AD) \ KMS_X (DigitalSignatureAlgorithm, 0x4200AE) \ KMS_X (CertificateSerialNumber, 0x4200AF) \ KMS_X (DeviceSerialNumber, 0x4200B0) \ KMS_X (IssuerAlternativeName, 0x4200B1) \ KMS_X (IssuerDistinguishedName, 0x4200B2) \ KMS_X (SubjectAlternativeName, 0x4200B3) \ KMS_X (SubjectDistinguishedName, 0x4200B4) \ KMS_X (X509CertificateIdentifier, 0x4200B5) \ KMS_X (X509CertificateIssuer, 0x4200B6) \ KMS_X (X509CertificateSubject, 0x4200B7) \ KMS_X (KeyValueLocation, 0x4200B8) \ KMS_X (KeyValueLocationValue, 0x4200B9) \ KMS_X (KeyValueLocationType, 0x4200BA) \ KMS_X (KeyValuePresent, 0x4200BB) \ KMS_X (OriginalCreationDate, 0x4200BC) \ KMS_X (PGPKey, 0x4200BD) \ KMS_X (PGPKeyVersion, 0x4200BE) \ KMS_X (AlternativeName, 0x4200BF) \ KMS_X (AlternativeNameValue, 0x4200C0) \ KMS_X (AlternativeNameType, 0x4200C1) \ KMS_X (Data, 0x4200C2) \ KMS_X (SignatureData, 0x4200C3) \ KMS_X (DataLength, 0x4200C4) \ KMS_X (RandomIV, 0x4200C5) \ KMS_X (MACData, 0x4200C6) \ KMS_X (AttestationType, 0x4200C7) \ KMS_X (Nonce, 0x4200C8) \ KMS_X (NonceID, 0x4200C9) \ KMS_X (NonceValue, 0x4200CA) \ KMS_X (AttestationMeasurement, 0x4200CB) \ KMS_X (AttestationAssertion, 0x4200CC) \ KMS_X (IVLength, 0x4200CD) \ KMS_X (TagLength, 0x4200CE) \ KMS_X (FixedFieldLength, 0x4200CF) \ KMS_X (CounterLength, 0x4200D0) \ KMS_X (InitialCounterValue, 0x4200D1) \ KMS_X (InvocationFieldLength, 0x4200D2) \ KMS_X (AttestationCapableIndicator, 0x4200D3) \ KMS_X (OffsetItems, 0x4200D4) \ KMS_X (LocatedItems, 0x4200D5) \ KMS_X (CorrelationValue, 0x4200D6) \ KMS_X (InitIndicator, 0x4200D7) \ KMS_X (FinalIndicator, 0x4200D8) \ KMS_X (RNGParameters, 0x4200D9) \ KMS_X (RNGAlgorithm, 0x4200DA) \ KMS_X (DRBGAlgorithm, 0x4200DB) \ KMS_X (FIPS186Variation, 0x4200DC) \ KMS_X (PredictionResistance, 0x4200DD) \ KMS_X (RandomNumberGenerator, 0x4200DE) \ KMS_X (ValidationInformation, 0x4200DF) \ KMS_X (ValidationAuthorityType, 0x4200E0) \ KMS_X (ValidationAuthorityCountry, 0x4200E1) \ KMS_X (ValidationAuthorityURI, 0x4200E2) \ KMS_X (ValidationVersionMajor, 0x4200E3) \ KMS_X (ValidationVersionMinor, 0x4200E4) \ KMS_X (ValidationType, 0x4200E5) \ KMS_X (ValidationLevel, 0x4200E6) \ KMS_X (ValidationCertificateIdentifier, 0x4200E7) \ KMS_X (ValidationCertificateURI, 0x4200E8) \ KMS_X (ValidationVendorURI, 0x4200E9) \ KMS_X (ValidationProfile, 0x4200EA) \ KMS_X (ProfileInformation, 0x4200EB) \ KMS_X (ProfileName, 0x4200EC) \ KMS_X (ServerURI, 0x4200ED) \ KMS_X (ServerPort, 0x4200EE) \ KMS_X (StreamingCapability, 0x4200EF) \ KMS_X (AsynchronousCapability, 0x4200F0) \ KMS_X (AttestationCapability, 0x4200F1) \ KMS_X (UnwrapMode, 0x4200F2) \ KMS_X (DestroyAction, 0x4200F3) \ KMS_X (ShreddingAlgorithm, 0x4200F4) \ KMS_X (RNGMode, 0x4200F5) \ KMS_X (ClientRegistrationMethod, 0x4200F6) \ KMS_X (CapabilityInformation, 0x4200F7) \ KMS_X (KeyWrapType, 0x4200F8) \ KMS_X (BatchUndoCapability, 0x4200F9) \ KMS_X (BatchContinueCapability, 0x4200FA) \ KMS_X (PKCS12FriendlyName, 0x4200FB) \ KMS_X (Description, 0x4200FC) \ KMS_X (Comment, 0x4200FD) \ KMS_X (AuthenticatedEncryptionAdditionalData, 0x4200FE) \ KMS_X (AuthenticatedEncryptionTag, 0x4200FF) \ KMS_X (SaltLength, 0x420100) \ KMS_X (MaskGenerator, 0x420101) \ KMS_X (MaskGeneratorHashingAlgorithm, 0x420102) \ KMS_X (PSource, 0x420103) \ KMS_X (TrailerField, 0x420104) \ KMS_X (ClientCorrelationValue, 0x420105) \ KMS_X (ServerCorrelationValue, 0x420106) \ KMS_X (DigestedData, 0x420107) \ KMS_X (CertificateSubjectCN, 0x420108) \ KMS_X (CertificateSubjectO, 0x420109) \ KMS_X (CertificateSubjectOU, 0x42010A) \ KMS_X (CertificateSubjectEmail, 0x42010B) \ KMS_X (CertificateSubjectC, 0x42010C) \ KMS_X (CertificateSubjectST, 0x42010D) \ KMS_X (CertificateSubjectL, 0x42010E) \ KMS_X (CertificateSubjectUID, 0x42010F) \ KMS_X (CertificateSubjectSerialNumber, 0x420110) \ KMS_X (CertificateSubjectTitle, 0x420111) \ KMS_X (CertificateSubjectDC, 0x420112) \ KMS_X (CertificateSubjectDNQualifier, 0x420113) \ KMS_X (CertificateIssuerCN, 0x420114) \ KMS_X (CertificateIssuerO, 0x420115) \ KMS_X (CertificateIssuerOU, 0x420116) \ KMS_X (CertificateIssuerEmail, 0x420117) \ KMS_X (CertificateIssuerC, 0x420118) \ KMS_X (CertificateIssuerST, 0x420119) \ KMS_X (CertificateIssuerL, 0x42011A) \ KMS_X (CertificateIssuerUID, 0x42011B) \ KMS_X (CertificateIssuerSerialNumber, 0x42011C) \ KMS_X (CertificateIssuerTitle, 0x42011D) \ KMS_X (CertificateIssuerDC, 0x42011E) \ KMS_X (CertificateIssuerDNQualifier, 0x42011F) \ KMS_X (Sensitive, 0x420120) \ KMS_X (AlwaysSensitive, 0x420121) \ KMS_X (Extractable, 0x420122) \ KMS_X (NeverExtractable, 0x420123) \ KMS_X (ReplaceExisting, 0x420124) \ KMS_X_LAST (Attributes, 0x420125) /* clang-format on */ /* Generate an enum with each tag value. */ #define KMS_X(TAG, VAL) KMIP_TAG_##TAG = VAL, #define KMS_X_LAST(TAG, VAL) KMIP_TAG_##TAG = VAL typedef enum { KMS_XMACRO } kmip_tag_type_t; #undef KMS_X #undef KMS_X_LAST #define KMS_X(TAG, VAL) \ case KMIP_TAG_##TAG: \ return #TAG; #define KMS_X_LAST KMS_X static KMS_MSG_INLINE const char * kmip_tag_to_string (kmip_tag_type_t tag) { switch (tag) { default: return "Unknown KMIP tag"; KMS_XMACRO } } #undef KMS_X #undef KMS_X_LAST #undef KMS_XMACRO #endif /* KMS_KMIP_TAG_TYPE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kv_list.c0000644000175100001660000000627414760300420021171 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_kv_list.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_request_str.h" #include "kms_port.h" #include "sort.h" static void kv_init (kms_kv_t *kv, kms_request_str_t *key, kms_request_str_t *value) { kv->key = kms_request_str_dup (key); kv->value = kms_request_str_dup (value); } static void kv_cleanup (kms_kv_t *kv) { kms_request_str_destroy (kv->key); kms_request_str_destroy (kv->value); } kms_kv_list_t * kms_kv_list_new (void) { kms_kv_list_t *lst = malloc (sizeof (kms_kv_list_t)); KMS_ASSERT (lst); lst->size = 16; lst->kvs = malloc (lst->size * sizeof (kms_kv_t)); KMS_ASSERT (lst->kvs); lst->len = 0; return lst; } void kms_kv_list_destroy (kms_kv_list_t *lst) { size_t i; if (!lst) { return; } for (i = 0; i < lst->len; i++) { kv_cleanup (&lst->kvs[i]); } free (lst->kvs); free (lst); } void kms_kv_list_add (kms_kv_list_t *lst, kms_request_str_t *key, kms_request_str_t *value) { if (lst->len == lst->size) { lst->size *= 2; lst->kvs = realloc (lst->kvs, lst->size * sizeof (kms_kv_t)); KMS_ASSERT (lst->kvs); } kv_init (&lst->kvs[lst->len], key, value); ++lst->len; } const kms_kv_t * kms_kv_list_find (const kms_kv_list_t *lst, const char *key) { size_t i; for (i = 0; i < lst->len; i++) { if (0 == kms_strcasecmp (lst->kvs[i].key->str, key)) { return &lst->kvs[i]; } } return NULL; } void kms_kv_list_del (kms_kv_list_t *lst, const char *key) { size_t i; for (i = 0; i < lst->len; i++) { if (0 == strcmp (lst->kvs[i].key->str, key)) { kv_cleanup (&lst->kvs[i]); memmove (&lst->kvs[i], &lst->kvs[i + 1], sizeof (kms_kv_t) * (lst->len - i - 1)); lst->len--; } } } kms_kv_list_t * kms_kv_list_dup (const kms_kv_list_t *lst) { kms_kv_list_t *dup; size_t i; if (lst->len == 0) { return kms_kv_list_new (); } dup = malloc (sizeof (kms_kv_list_t)); KMS_ASSERT (dup); dup->size = dup->len = lst->len; dup->kvs = malloc (lst->len * sizeof (kms_kv_t)); KMS_ASSERT (dup->kvs); for (i = 0; i < lst->len; i++) { kv_init (&dup->kvs[i], lst->kvs[i].key, lst->kvs[i].value); } return dup; } void kms_kv_list_sort (kms_kv_list_t *lst, int (*cmp) (const void *, const void *)) { /* A stable sort is required to sort headers when creating canonical * requests. qsort is not stable. */ insertionsort ( (unsigned char *) (lst->kvs), lst->len, sizeof (kms_kv_t), cmp); } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_kv_list.h0000644000175100001660000000272714760300420021175 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_KV_LIST_H #define KMS_KV_LIST_H #include "kms_message/kms_message.h" #include "kms_request_str.h" #include #include #include /* key-value pair */ typedef struct { kms_request_str_t *key; kms_request_str_t *value; } kms_kv_t; typedef struct { kms_kv_t *kvs; size_t len; size_t size; } kms_kv_list_t; kms_kv_list_t * kms_kv_list_new (void); void kms_kv_list_destroy (kms_kv_list_t *lst); void kms_kv_list_add (kms_kv_list_t *lst, kms_request_str_t *key, kms_request_str_t *value); const kms_kv_t * kms_kv_list_find (const kms_kv_list_t *lst, const char *key); void kms_kv_list_del (kms_kv_list_t *lst, const char *key); kms_kv_list_t * kms_kv_list_dup (const kms_kv_list_t *lst); void kms_kv_list_sort (kms_kv_list_t *lst, int (*cmp) (const void *, const void *)); #endif /* KMS_KV_LIST_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message.c0000644000175100001660000000213014760300420021125 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message/kms_b64.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_crypto.h" #include #include void kms_set_error (char *error, size_t size, const char *fmt, ...) { va_list va; va_start (va, fmt); (void) vsnprintf (error, size, fmt, va); va_end (va); } int kms_message_init (void) { kms_message_b64_initialize_rmap (); return kms_crypto_init (); } void kms_message_cleanup (void) { kms_crypto_cleanup (); } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_message_private.h0000644000175100001660000000776514760300420022707 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_PRIVATE_H #define KMS_MESSAGE_PRIVATE_H #include #include "kms_message/kms_message.h" #include "kms_request_str.h" #include "kms_kv_list.h" #include "kms_crypto.h" #include "kms_kmip_response_parser_private.h" /* Sadly, Windows does not define SSIZE_MAX. It is defined in bson-compat.h, * but only since 1.22.x, so copy this from bson-compat.h for now. */ #ifndef SSIZE_MAX #define SSIZE_MAX \ (ssize_t) ( \ (((size_t) 0x01u) << (sizeof (ssize_t) * (size_t) CHAR_BIT - 1u)) - 1u) #endif struct _kms_request_t { char error[512]; bool failed; bool finalized; /* Begin: AWS specific */ kms_request_str_t *region; kms_request_str_t *service; kms_request_str_t *access_key_id; kms_request_str_t *secret_key; kms_request_str_t *datetime; kms_request_str_t *date; /* End: AWS specific */ kms_request_str_t *method; kms_request_str_t *path; kms_request_str_t *query; kms_request_str_t *payload; kms_kv_list_t *query_params; kms_kv_list_t *header_fields; /* turn off for tests only, not in public kms_request_opt_t API */ bool auto_content_length; _kms_crypto_t crypto; kms_request_str_t *to_string; kms_request_provider_t provider; /* TODO (MONGOCRYPT-342): make a union for each KMS provider type. kms_request_provider_t provider; union { struct {} aws; struct {} azure; struct {} gcp; struct {} kmip; } */ struct { uint8_t *data; uint32_t len; } kmip; }; struct _kms_response_t { int status; kms_kv_list_t *headers; kms_request_str_t *body; /* TODO (MONGOCRYPT-347): make a union for each KMS provider type. */ char error[512]; bool failed; kms_request_provider_t provider; struct { uint8_t *data; uint32_t len; } kmip; }; typedef enum { PARSING_STATUS_LINE, PARSING_HEADER, PARSING_BODY, PARSING_CHUNK_LENGTH, PARSING_CHUNK, PARSING_DONE } kms_response_parser_state_t; struct _kms_response_parser_t { char error[512]; bool failed; kms_response_t *response; kms_request_str_t *raw_response; int content_length; int start; /* start of the current thing getting parsed. */ /* Support two types of HTTP 1.1 responses. * - "Content-Length: x" header is present, indicating the body length. * - "Transfer-Encoding: chunked" header is present, indicating a stream of * chunks. */ bool transfer_encoding_chunked; int chunk_size; kms_response_parser_state_t state; /* TODO: MONGOCRYPT-348 reorganize this struct to better separate fields for * HTTP parsing and fields for KMIP parsing. */ kms_kmip_response_parser_t *kmip; }; #define CHECK_FAILED \ do { \ if (request->failed) { \ return false; \ } \ } while (0) void kms_set_error (char *error, size_t size, const char *fmt, ...); #define KMS_ERROR(obj, ...) \ do { \ obj->failed = true; \ kms_set_error (obj->error, sizeof (obj->error), __VA_ARGS__); \ } while (0) #define KMS_ASSERT(stmt) \ if (!(stmt)) { \ fprintf (stderr, "%s failed\n", #stmt); \ abort (); \ } #endif /* KMS_MESSAGE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_port.c0000644000175100001660000000157014760300420020474 0ustar /* * Copyright 2020-present MongoDB, 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. */ #include "kms_port.h" #if defined(_WIN32) #include #include char * kms_strndup (const char *src, size_t len) { char *dst = (char *) malloc (len + 1); if (!dst) { return 0; } memcpy (dst, src, len); dst[len] = '\0'; return dst; } #endif mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_port.h0000644000175100001660000000157414760300420020505 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_PORT_H #define KMS_PORT_H #include #if defined(_WIN32) #define kms_strcasecmp _stricmp char * kms_strndup (const char *src, size_t len); #else #include #define kms_strndup strndup #define kms_strcasecmp strcasecmp #endif #endif /* KMS_PORT_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_request.c0000644000175100001660000006073014760300420021203 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_request_opt_private.h" #include "kms_port.h" #include /* CHAR_BIT */ static kms_kv_list_t * parse_query_params (kms_request_str_t *q) { kms_kv_list_t *lst = kms_kv_list_new (); char *p = q->str; char *end = q->str + q->len; char *amp, *equals; kms_request_str_t *k, *v; do { equals = strchr ((const char *) p, '='); if (!equals) { kms_kv_list_destroy (lst); return NULL; } amp = strchr ((const char *) equals, '&'); if (!amp) { amp = end; } k = kms_request_str_new_from_chars (p, equals - p); v = kms_request_str_new_from_chars (equals + 1, amp - equals - 1); kms_kv_list_add (lst, k, v); kms_request_str_destroy (k); kms_request_str_destroy (v); p = amp + 1; } while (p < end); return lst; } static bool check_and_prohibit_kmip (kms_request_t *req) { if (req->provider == KMS_REQUEST_PROVIDER_KMIP) { KMS_ERROR (req, "Function not applicable to KMIP"); return false; } return true; } kms_request_t * kms_request_new (const char *method, const char *path_and_query, const kms_request_opt_t *opt) { kms_request_t *request = calloc (1, sizeof (kms_request_t)); const char *question_mark; KMS_ASSERT (request); if (opt && opt->provider) { request->provider = opt->provider; } else { request->provider = KMS_REQUEST_PROVIDER_AWS; } if (!check_and_prohibit_kmip (request)) { return request; } /* parsing may set failed to true */ request->failed = false; request->finalized = false; request->region = kms_request_str_new (); request->service = kms_request_str_new (); request->access_key_id = kms_request_str_new (); request->secret_key = kms_request_str_new (); question_mark = strchr (path_and_query, '?'); if (question_mark) { request->path = kms_request_str_new_from_chars ( path_and_query, question_mark - path_and_query); request->query = kms_request_str_new_from_chars (question_mark + 1, -1); request->query_params = parse_query_params (request->query); if (!request->query_params) { KMS_ERROR (request, "Cannot parse query: %s", request->query->str); } } else { request->path = kms_request_str_new_from_chars (path_and_query, -1); request->query = kms_request_str_new (); request->query_params = kms_kv_list_new (); } request->payload = kms_request_str_new (); request->date = kms_request_str_new (); request->datetime = kms_request_str_new (); request->method = kms_request_str_new_from_chars (method, -1); request->header_fields = kms_kv_list_new (); request->auto_content_length = true; /* For AWS KMS requests, add a X-Amz-Date header. */ if (request->provider == KMS_REQUEST_PROVIDER_AWS && !kms_request_set_date (request, NULL)) { return request; } if (opt && opt->connection_close) { if (!kms_request_add_header_field (request, "Connection", "close")) { return request; } } if (opt && opt->crypto.sha256) { memcpy (&request->crypto, &opt->crypto, sizeof (opt->crypto)); } else { request->crypto.sha256 = kms_sha256; request->crypto.sha256_hmac = kms_sha256_hmac; } return request; } void kms_request_destroy (kms_request_t *request) { kms_request_str_destroy (request->region); kms_request_str_destroy (request->service); kms_request_str_destroy (request->access_key_id); kms_request_str_destroy (request->secret_key); kms_request_str_destroy (request->method); kms_request_str_destroy (request->path); kms_request_str_destroy (request->query); kms_request_str_destroy (request->payload); kms_request_str_destroy (request->datetime); kms_request_str_destroy (request->date); kms_kv_list_destroy (request->query_params); kms_kv_list_destroy (request->header_fields); kms_request_str_destroy (request->to_string); free (request->kmip.data); free (request); } const char * kms_request_get_error (kms_request_t *request) { return request->failed ? request->error : NULL; } #define AMZ_DT_FORMAT "YYYYmmDDTHHMMSSZ" bool kms_request_set_date (kms_request_t *request, const struct tm *tm) { char buf[sizeof AMZ_DT_FORMAT]; struct tm tmp_tm; if (request->failed) { return false; } if (!check_and_prohibit_kmip (request)) { return false; } if (!tm) { /* use current time */ time_t t; time (&t); #if defined(KMS_MESSAGE_HAVE_GMTIME_R) gmtime_r (&t, &tmp_tm); #elif defined(_MSC_VER) gmtime_s (&tmp_tm, &t); #else tmp_tm = *gmtime (&t); #endif tm = &tmp_tm; } if (0 == strftime (buf, sizeof AMZ_DT_FORMAT, "%Y%m%dT%H%M%SZ", tm)) { KMS_ERROR (request, "Invalid tm struct"); return false; } kms_request_str_set_chars (request->date, buf, sizeof "YYYYmmDD" - 1); kms_request_str_set_chars (request->datetime, buf, sizeof AMZ_DT_FORMAT - 1); kms_kv_list_del (request->header_fields, "X-Amz-Date"); if (!kms_request_add_header_field (request, "X-Amz-Date", buf)) { return false; } return true; } #undef AMZ_DT_FORMAT bool kms_request_set_region (kms_request_t *request, const char *region) { if (!check_and_prohibit_kmip (request)) { return false; } kms_request_str_set_chars (request->region, region, -1); return true; } bool kms_request_set_service (kms_request_t *request, const char *service) { if (!check_and_prohibit_kmip (request)) { return false; } kms_request_str_set_chars (request->service, service, -1); return true; } bool kms_request_set_access_key_id (kms_request_t *request, const char *akid) { if (!check_and_prohibit_kmip (request)) { return false; } kms_request_str_set_chars (request->access_key_id, akid, -1); return true; } bool kms_request_set_secret_key (kms_request_t *request, const char *key) { if (!check_and_prohibit_kmip (request)) { return false; } kms_request_str_set_chars (request->secret_key, key, -1); return true; } bool kms_request_add_header_field (kms_request_t *request, const char *field_name, const char *value) { kms_request_str_t *k, *v; CHECK_FAILED; if (!check_and_prohibit_kmip (request)) { return false; } k = kms_request_str_new_from_chars (field_name, -1); v = kms_request_str_new_from_chars (value, -1); kms_kv_list_add (request->header_fields, k, v); kms_request_str_destroy (k); kms_request_str_destroy (v); return true; } bool kms_request_append_header_field_value (kms_request_t *request, const char *value, size_t len) { kms_request_str_t *v; CHECK_FAILED; if (!check_and_prohibit_kmip (request)) { return false; } if (request->header_fields->len == 0) { KMS_ERROR ( request, "Ensure the request has at least one header field before calling %s", __func__); } v = request->header_fields->kvs[request->header_fields->len - 1].value; KMS_ASSERT (len <= SSIZE_MAX); kms_request_str_append_chars (v, value, (ssize_t) len); return true; } bool kms_request_append_payload (kms_request_t *request, const char *payload, size_t len) { CHECK_FAILED; if (!check_and_prohibit_kmip (request)) { return false; } KMS_ASSERT (len <= SSIZE_MAX); kms_request_str_append_chars (request->payload, payload, (ssize_t) len); return true; } /* docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html * * "Sort the parameter names by character code point in ascending order. For * example, a parameter name that begins with the uppercase letter F precedes a * parameter name that begins with a lowercase letter b." */ static int cmp_query_params (const void *a, const void *b) { int r = strcmp (((kms_kv_t *) a)->key->str, ((kms_kv_t *) b)->key->str); if (r != 0) { return r; } /* not in docs, but tested in get-vanilla-query-order-key: sort by value */ return strcmp (((kms_kv_t *) a)->value->str, ((kms_kv_t *) b)->value->str); } static void append_canonical_query (kms_request_t *request, kms_request_str_t *str) { size_t i; kms_kv_list_t *lst; if (!request->query_params->len) { return; } lst = kms_kv_list_dup (request->query_params); kms_kv_list_sort (lst, cmp_query_params); for (i = 0; i < lst->len; i++) { kms_request_str_append_escaped (str, lst->kvs[i].key, true); kms_request_str_append_char (str, '='); kms_request_str_append_escaped (str, lst->kvs[i].value, true); if (i < lst->len - 1) { kms_request_str_append_char (str, '&'); } } kms_kv_list_destroy (lst); } /* "lst" is a sorted list of headers */ static void append_canonical_headers (kms_kv_list_t *lst, kms_request_str_t *str) { size_t i; kms_kv_t *kv; const kms_request_str_t *previous_key = NULL; /* aws docs: "To create the canonical headers list, convert all header names * to lowercase and remove leading spaces and trailing spaces. Convert * sequential spaces in the header value to a single space." "Do not sort the * values in headers that have multiple values." */ for (i = 0; i < lst->len; i++) { kv = &lst->kvs[i]; if (previous_key && 0 == kms_strcasecmp (previous_key->str, kv->key->str)) { /* duplicate header */ kms_request_str_append_char (str, ','); kms_request_str_append_stripped (str, kv->value); continue; } if (i > 0) { kms_request_str_append_newline (str); } kms_request_str_append_lowercase (str, kv->key); kms_request_str_append_char (str, ':'); kms_request_str_append_stripped (str, kv->value); previous_key = kv->key; } kms_request_str_append_newline (str); } static void append_signed_headers (kms_kv_list_t *lst, kms_request_str_t *str) { size_t i; kms_kv_t *kv; const kms_request_str_t *previous_key = NULL; for (i = 0; i < lst->len; i++) { kv = &lst->kvs[i]; if (previous_key && 0 == kms_strcasecmp (previous_key->str, kv->key->str)) { /* duplicate header */ continue; } if (0 == kms_strcasecmp (kv->key->str, "connection")) { continue; } kms_request_str_append_lowercase (str, kv->key); if (i < lst->len - 1) { kms_request_str_append_char (str, ';'); } previous_key = kv->key; } } static bool finalize (kms_request_t *request) { kms_kv_list_t *lst; kms_request_str_t *k; kms_request_str_t *v; if (request->failed) { return false; } if (request->finalized) { return true; } request->finalized = true; lst = request->header_fields; if (!kms_kv_list_find (lst, "Host")) { if (request->provider != KMS_REQUEST_PROVIDER_AWS) { KMS_ERROR (request, "Required Host header not set"); return false; } /* For AWS requests, derive a default Host header from region + service. * E.g. "kms.us-east-1.amazonaws.com" */ k = kms_request_str_new_from_chars ("Host", -1); v = kms_request_str_dup (request->service); kms_request_str_append_char (v, '.'); kms_request_str_append (v, request->region); kms_request_str_append_chars (v, ".amazonaws.com", -1); kms_kv_list_add (lst, k, v); kms_request_str_destroy (k); kms_request_str_destroy (v); } if (!kms_kv_list_find (lst, "Content-Length") && request->payload->len && request->auto_content_length) { k = kms_request_str_new_from_chars ("Content-Length", -1); v = kms_request_str_new (); kms_request_str_appendf (v, "%zu", request->payload->len); kms_kv_list_add (lst, k, v); kms_request_str_destroy (k); kms_request_str_destroy (v); } return true; } /* docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html * * "Build the canonical headers list by sorting the (lowercase) headers by * character code... Do not sort the values in headers that have multiple * values." */ static int cmp_header_field_names (const void *a, const void *b) { return kms_strcasecmp (((kms_kv_t *) a)->key->str, ((kms_kv_t *) b)->key->str); } static kms_kv_list_t * canonical_headers (const kms_request_t *request) { kms_kv_list_t *lst; KMS_ASSERT (request->finalized); lst = kms_kv_list_dup (request->header_fields); kms_kv_list_sort (lst, cmp_header_field_names); kms_kv_list_del (lst, "Connection"); return lst; } char * kms_request_get_canonical (kms_request_t *request) { kms_request_str_t *canonical; kms_request_str_t *normalized; kms_kv_list_t *lst; if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } if (!finalize (request)) { return NULL; } canonical = kms_request_str_new (); kms_request_str_append (canonical, request->method); kms_request_str_append_newline (canonical); normalized = kms_request_str_path_normalized (request->path); kms_request_str_append_escaped (canonical, normalized, false); kms_request_str_destroy (normalized); kms_request_str_append_newline (canonical); append_canonical_query (request, canonical); kms_request_str_append_newline (canonical); lst = canonical_headers (request); append_canonical_headers (lst, canonical); kms_request_str_append_newline (canonical); append_signed_headers (lst, canonical); kms_kv_list_destroy (lst); kms_request_str_append_newline (canonical); if (!kms_request_str_append_hashed ( &request->crypto, canonical, request->payload)) { KMS_ERROR (request, "could not generate hash"); kms_request_str_destroy (canonical); return NULL; } return kms_request_str_detach (canonical); } const char * kms_request_get_canonical_header (kms_request_t *request, const char *header) { const kms_kv_t *value; if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } if (!finalize (request)) { return NULL; } value = kms_kv_list_find (request->header_fields, header); if (!value) { return NULL; } return value->value->str; } char * kms_request_get_string_to_sign (kms_request_t *request) { bool success = false; kms_request_str_t *sts; kms_request_str_t *creq = NULL; /* canonical request */ if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } if (!finalize (request)) { return NULL; } sts = kms_request_str_new (); kms_request_str_append_chars (sts, "AWS4-HMAC-SHA256\n", -1); kms_request_str_append (sts, request->datetime); kms_request_str_append_newline (sts); /* credential scope, like "20150830/us-east-1/service/aws4_request" */ kms_request_str_append (sts, request->date); kms_request_str_append_char (sts, '/'); kms_request_str_append (sts, request->region); kms_request_str_append_char (sts, '/'); kms_request_str_append (sts, request->service); kms_request_str_append_chars (sts, "/aws4_request\n", -1); creq = kms_request_str_wrap (kms_request_get_canonical (request), -1); if (!creq) { goto done; } if (!kms_request_str_append_hashed (&request->crypto, sts, creq)) { goto done; } success = true; done: kms_request_str_destroy (creq); if (!success) { kms_request_str_destroy (sts); sts = NULL; } return kms_request_str_detach (sts); } static bool kms_request_hmac (_kms_crypto_t *crypto, unsigned char *out, kms_request_str_t *key, kms_request_str_t *data) { return crypto->sha256_hmac ( crypto->ctx, key->str, key->len, data->str, data->len, out); } static bool kms_request_hmac_again (_kms_crypto_t *crypto, unsigned char *out, unsigned char *in, kms_request_str_t *data) { return crypto->sha256_hmac ( crypto->ctx, (const char *) in, 32, data->str, data->len, out); } bool kms_request_get_signing_key (kms_request_t *request, unsigned char *key) { bool success = false; kms_request_str_t *aws4_plus_secret = NULL; kms_request_str_t *aws4_request = NULL; unsigned char k_date[32]; unsigned char k_region[32]; unsigned char k_service[32]; if (request->failed) { return false; } if (!check_and_prohibit_kmip (request)) { return false; } /* docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html * Pseudocode for deriving a signing key * * kSecret = your secret access key * kDate = HMAC("AWS4" + kSecret, Date) * kRegion = HMAC(kDate, Region) * kService = HMAC(kRegion, Service) * kSigning = HMAC(kService, "aws4_request") */ aws4_plus_secret = kms_request_str_new_from_chars ("AWS4", -1); kms_request_str_append (aws4_plus_secret, request->secret_key); aws4_request = kms_request_str_new_from_chars ("aws4_request", -1); if (!(kms_request_hmac ( &request->crypto, k_date, aws4_plus_secret, request->date) && kms_request_hmac_again ( &request->crypto, k_region, k_date, request->region) && kms_request_hmac_again ( &request->crypto, k_service, k_region, request->service) && kms_request_hmac_again ( &request->crypto, key, k_service, aws4_request))) { goto done; } success = true; done: kms_request_str_destroy (aws4_plus_secret); kms_request_str_destroy (aws4_request); return success; } char * kms_request_get_signature (kms_request_t *request) { bool success = false; kms_kv_list_t *lst = NULL; kms_request_str_t *sig = NULL; kms_request_str_t *sts = NULL; unsigned char signing_key[32]; unsigned char signature[32]; if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } sts = kms_request_str_wrap (kms_request_get_string_to_sign (request), -1); if (!sts) { goto done; } sig = kms_request_str_new (); kms_request_str_append_chars (sig, "AWS4-HMAC-SHA256 Credential=", -1); kms_request_str_append (sig, request->access_key_id); kms_request_str_append_char (sig, '/'); kms_request_str_append (sig, request->date); kms_request_str_append_char (sig, '/'); kms_request_str_append (sig, request->region); kms_request_str_append_char (sig, '/'); kms_request_str_append (sig, request->service); kms_request_str_append_chars (sig, "/aws4_request, SignedHeaders=", -1); lst = canonical_headers (request); append_signed_headers (lst, sig); kms_request_str_append_chars (sig, ", Signature=", -1); if (!(kms_request_get_signing_key (request, signing_key) && kms_request_hmac_again ( &request->crypto, signature, signing_key, sts))) { goto done; } kms_request_str_append_hex (sig, signature, sizeof (signature)); success = true; done: kms_kv_list_destroy (lst); kms_request_str_destroy (sts); if (!success) { kms_request_str_destroy (sig); sig = NULL; } return kms_request_str_detach (sig); } void kms_request_validate (kms_request_t *request) { if (!check_and_prohibit_kmip (request)) { return; } if (0 == request->region->len) { KMS_ERROR (request, "Region not set"); } else if (0 == request->service->len) { KMS_ERROR (request, "Service not set"); } else if (0 == request->access_key_id->len) { KMS_ERROR (request, "Access key ID not set"); } else if (0 == request->method->len) { KMS_ERROR (request, "Method not set"); } else if (0 == request->path->len) { KMS_ERROR (request, "Path not set"); } else if (0 == request->date->len) { KMS_ERROR (request, "Date not set"); } else if (0 == request->secret_key->len) { KMS_ERROR (request, "Secret key not set"); } } /* append_http_endofline appends an HTTP end-of-line marker: "\r\n". */ static void append_http_endofline (kms_request_str_t *str) { kms_request_str_append_chars (str, "\r\n", 2); } char * kms_request_get_signed (kms_request_t *request) { bool success = false; kms_kv_list_t *lst = NULL; char *signature = NULL; kms_request_str_t *sreq = NULL; size_t i; kms_request_validate (request); if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } if (!finalize (request)) { return NULL; } sreq = kms_request_str_new (); /* like "POST / HTTP/1.1" */ kms_request_str_append (sreq, request->method); kms_request_str_append_char (sreq, ' '); kms_request_str_append (sreq, request->path); if (request->query->len) { kms_request_str_append_char (sreq, '?'); kms_request_str_append (sreq, request->query); } kms_request_str_append_chars (sreq, " HTTP/1.1", -1); append_http_endofline (sreq); /* headers */ lst = kms_kv_list_dup (request->header_fields); kms_kv_list_sort (lst, cmp_header_field_names); for (i = 0; i < lst->len; i++) { kms_request_str_append (sreq, lst->kvs[i].key); kms_request_str_append_char (sreq, ':'); kms_request_str_append (sreq, lst->kvs[i].value); append_http_endofline (sreq); } /* authorization header */ signature = kms_request_get_signature (request); if (!signature) { goto done; } /* note space after ':', to match test .sreq files */ kms_request_str_append_chars (sreq, "Authorization: ", -1); kms_request_str_append_chars (sreq, signature, -1); /* body */ if (request->payload->len) { append_http_endofline (sreq); append_http_endofline (sreq); kms_request_str_append (sreq, request->payload); } success = true; done: free (signature); kms_kv_list_destroy (lst); if (!success) { kms_request_str_destroy (sreq); sreq = NULL; } return kms_request_str_detach (sreq); } char * kms_request_to_string (kms_request_t *request) { kms_kv_list_t *lst = NULL; kms_request_str_t *sreq = NULL; size_t i; if (!finalize (request)) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } if (request->to_string) { return kms_request_str_detach (kms_request_str_dup (request->to_string)); } sreq = kms_request_str_new (); /* like "POST / HTTP/1.1" */ kms_request_str_append (sreq, request->method); kms_request_str_append_char (sreq, ' '); kms_request_str_append (sreq, request->path); if (request->query->len) { kms_request_str_append_char (sreq, '?'); kms_request_str_append (sreq, request->query); } kms_request_str_append_chars (sreq, " HTTP/1.1", -1); append_http_endofline (sreq); /* headers */ lst = kms_kv_list_dup (request->header_fields); kms_kv_list_sort (lst, cmp_header_field_names); for (i = 0; i < lst->len; i++) { kms_request_str_append (sreq, lst->kvs[i].key); kms_request_str_append_char (sreq, ':'); kms_request_str_append (sreq, lst->kvs[i].value); append_http_endofline (sreq); } append_http_endofline (sreq); /* body */ if (request->payload->len) { kms_request_str_append (sreq, request->payload); } kms_kv_list_destroy (lst); request->to_string = kms_request_str_dup (sreq); return kms_request_str_detach (sreq); } void kms_request_free_string (char *ptr) { free (ptr); } const uint8_t * kms_request_to_bytes (kms_request_t *request, size_t *len) { if (request->provider == KMS_REQUEST_PROVIDER_KMIP) { *len = request->kmip.len; return request->kmip.data; } if (!request->to_string && !kms_request_to_string (request)) { return NULL; } KMS_ASSERT (request->to_string); *len = request->to_string->len; return (const uint8_t*) request->to_string->str; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_request_opt.c0000644000175100001660000000550114760300420022060 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_request_opt_private.h" #include kms_request_opt_t * kms_request_opt_new (void) { return calloc (1, sizeof (kms_request_opt_t)); } void kms_request_opt_destroy (kms_request_opt_t *request) { free (request); } void kms_request_opt_set_connection_close (kms_request_opt_t *opt, bool connection_close) { opt->connection_close = connection_close; } void kms_request_opt_set_crypto_hooks (kms_request_opt_t *opt, bool (*sha256) (void *ctx, const char *input, size_t len, unsigned char *hash_out), bool (*sha256_hmac) (void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out), void *ctx) { opt->crypto.sha256 = sha256; opt->crypto.sha256_hmac = sha256_hmac; opt->crypto.ctx = ctx; } bool kms_request_opt_set_provider (kms_request_opt_t *opt, kms_request_provider_t provider) { if (provider != KMS_REQUEST_PROVIDER_AWS && provider != KMS_REQUEST_PROVIDER_AZURE && provider != KMS_REQUEST_PROVIDER_GCP && provider != KMS_REQUEST_PROVIDER_KMIP) { return false; } opt->provider = provider; return true; } void kms_request_opt_set_crypto_hook_sign_rsaes_pkcs1_v1_5 ( kms_request_opt_t *opt, bool (*sign_rsaes_pkcs1_v1_5) (void *sign_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out), void *sign_ctx) { opt->crypto.sign_rsaes_pkcs1_v1_5 = sign_rsaes_pkcs1_v1_5; opt->crypto.sign_ctx = sign_ctx; }mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_request_opt_private.h0000644000175100001660000000170414760300420023620 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_REQUEST_OPT_PRIVATE_H #define KMS_REQUEST_OPT_PRIVATE_H #include "kms_message/kms_message_defines.h" #include "kms_message/kms_request_opt.h" #include "kms_crypto.h" #include struct _kms_request_opt_t { bool connection_close; _kms_crypto_t crypto; kms_request_provider_t provider; }; #endif /* KMS_REQUEST_OPT_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_request_str.c0000644000175100001660000002776314760300420022104 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "hexlify.h" #include "kms_crypto.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_request_str.h" #include "kms_port.h" #include #include #include #include #include /* CHAR_BIT */ bool rfc_3986_tab[256] = {0}; bool kms_initialized = false; static void tables_init (void) { int i; if (kms_initialized) { return; } for (i = 0; i < 256; ++i) { rfc_3986_tab[i] = isalnum (i) || i == '~' || i == '-' || i == '.' || i == '_'; } kms_initialized = true; } kms_request_str_t * kms_request_str_new (void) { kms_request_str_t *s = malloc (sizeof (kms_request_str_t)); KMS_ASSERT (s); s->len = 0; s->size = 16; s->str = malloc (s->size); KMS_ASSERT (s->str); s->str[0] = '\0'; return s; } kms_request_str_t * kms_request_str_new_from_chars (const char *chars, ssize_t len) { kms_request_str_t *s = malloc (sizeof (kms_request_str_t)); KMS_ASSERT (s); size_t actual_len; actual_len = len < 0 ? strlen (chars) : (size_t) len; s->size = actual_len + 1; s->str = malloc (s->size); KMS_ASSERT (s->str); memcpy (s->str, chars, actual_len); s->str[actual_len] = '\0'; s->len = actual_len; return s; } kms_request_str_t * kms_request_str_wrap (char *chars, ssize_t len) { kms_request_str_t *s; if (!chars) { return NULL; } s = malloc (sizeof (kms_request_str_t)); KMS_ASSERT (s); s->str = chars; s->len = len < 0 ? strlen (chars) : (size_t) len; s->size = s->len; return s; } void kms_request_str_destroy (kms_request_str_t *str) { if (!str) { return; } free (str->str); free (str); } char * kms_request_str_detach (kms_request_str_t *str) { if (!str) { return NULL; } char *r = str->str; free (str); return r; } const char * kms_request_str_get (kms_request_str_t *str) { return str->str; } bool kms_request_str_reserve (kms_request_str_t *str, size_t size) { size_t next_size = str->len + size + 1; if (str->size < next_size) { /* next power of 2 */ --next_size; next_size |= next_size >> 1U; next_size |= next_size >> 2U; next_size |= next_size >> 4U; next_size |= next_size >> 8U; next_size |= next_size >> 16U; ++next_size; str->size = next_size; str->str = realloc (str->str, next_size); } return str->str != NULL; } kms_request_str_t * kms_request_str_dup (kms_request_str_t *str) { kms_request_str_t *dup = malloc (sizeof (kms_request_str_t)); KMS_ASSERT (dup); dup->str = kms_strndup (str->str, str->len); dup->len = str->len; dup->size = str->len + 1; return dup; } void kms_request_str_set_chars (kms_request_str_t *str, const char *chars, ssize_t len) { size_t actual_len = len < 0 ? strlen (chars) : (size_t) len; kms_request_str_reserve (str, actual_len); /* adds 1 for nil */ memcpy (str->str, chars, actual_len + 1); str->len = actual_len; } bool kms_request_str_ends_with (kms_request_str_t *str, kms_request_str_t *suffix) { if (str->len >= suffix->len && 0 == strncmp ( &str->str[str->len - suffix->len], suffix->str, suffix->len)) { return true; } return false; } void kms_request_str_append (kms_request_str_t *str, kms_request_str_t *appended) { size_t next_len = str->len + appended->len; kms_request_str_reserve (str, next_len); memcpy (str->str + str->len, appended->str, appended->len); str->len += appended->len; str->str[str->len] = '\0'; } void kms_request_str_append_char (kms_request_str_t *str, char c) { kms_request_str_reserve (str, 1); *(str->str + str->len) = c; ++str->len; str->str[str->len] = '\0'; } void kms_request_str_append_chars (kms_request_str_t *str, const char *appended, ssize_t len) { size_t str_len; if (len < 0) { str_len = strlen (appended); } else { str_len = (size_t) len; } kms_request_str_reserve (str, str_len); memcpy (str->str + str->len, appended, str_len); str->len += str_len; str->str[str->len] = '\0'; } void kms_request_str_append_newline (kms_request_str_t *str) { kms_request_str_append_char (str, '\n'); } void kms_request_str_append_lowercase (kms_request_str_t *str, kms_request_str_t *appended) { size_t i; char *p; i = str->len; kms_request_str_append (str, appended); /* downcase the chars from the old end to the new end of str */ for (; i < str->len; ++i) { p = &str->str[i]; /* ignore UTF-8 non-ASCII chars, which have 1 in the top bit */ if (((unsigned int) (*p) & (0x1U << 7U)) == 0) { *p = (char) tolower (*p); } } } void kms_request_str_appendf (kms_request_str_t *str, const char *format, ...) { va_list args; size_t remaining; int n; KMS_ASSERT (format); while (true) { remaining = str->size - str->len; va_start (args, format); n = vsnprintf (&str->str[str->len], remaining, format, args); va_end (args); if (n > -1 && (size_t) n < remaining) { /* success */ str->len += (size_t) n; return; } if (n > -1) { kms_request_str_reserve (str, (size_t) n); } else { /* TODO: error! */ abort (); } } } void kms_request_str_append_escaped (kms_request_str_t *str, kms_request_str_t *appended, bool escape_slash) { uint8_t *in; uint8_t *out; size_t i; tables_init (); /* might replace each input char with 3 output chars: "%AB" */ kms_request_str_reserve (str, 3 * appended->len); in = (uint8_t *) appended->str; out = (uint8_t *) str->str + str->len; for (i = 0; i < appended->len; ++i) { if (rfc_3986_tab[*in] || (*in == '/' && !escape_slash)) { *out = *in; ++out; ++str->len; } else { sprintf ((char *) out, "%%%02X", *in); out += 3; str->len += 3; } ++in; } } void kms_request_str_append_stripped (kms_request_str_t *str, kms_request_str_t *appended) { const char *src = appended->str; const char *end = appended->str + appended->len; bool space = false; bool comma = false; kms_request_str_reserve (str, appended->len); /* msvcrt is unhappy when it gets non-ANSI characters in isspace */ while (*src >= 0 && isspace (*src)) { ++src; } while (src < end) { /* replace newlines with commas. not documented but see * get-header-value-multiline.creq */ if (*src == '\n') { comma = true; space = false; } else if (*src >= 0 && isspace (*src)) { space = true; } else { if (comma) { kms_request_str_append_char (str, ','); comma = false; space = false; } /* is there a run of spaces waiting to be written as one space? */ if (space) { kms_request_str_append_char (str, ' '); space = false; } kms_request_str_append_char (str, *src); } ++src; } } bool kms_request_str_append_hashed (_kms_crypto_t *crypto, kms_request_str_t *str, kms_request_str_t *appended) { uint8_t hash[32] = {0}; char *hex_chars; if (!crypto->sha256 (crypto->ctx, appended->str, appended->len, hash)) { return false; } hex_chars = hexlify (hash, sizeof (hash)); kms_request_str_append_chars (str, hex_chars, 2 * sizeof (hash)); free (hex_chars); return true; } bool kms_request_str_append_hex (kms_request_str_t *str, unsigned char *data, size_t len) { char *hex_chars; hex_chars = hexlify (data, len); KMS_ASSERT (len <= SSIZE_MAX / 2); kms_request_str_append_chars (str, hex_chars, (ssize_t) (len * 2)); free (hex_chars); return true; } static bool starts_with (char *s, const char *prefix) { if (strstr (s, prefix) == s) { return true; } return false; } /* remove from last slash to the end, but don't remove slash from start */ static void delete_last_segment (kms_request_str_t *str, bool is_absolute) { ssize_t i; if (!str->len) { return; } KMS_ASSERT (str->len < SSIZE_MAX); for (i = (ssize_t) str->len - 1; i >= 0; --i) { if (str->str[i] == '/') { if (i == 0 && is_absolute) { str->len = 1; } else { str->len = (size_t) i; } goto done; } } /* no slashes */ str->len = 0; done: str->str[str->len] = '\0'; } /* follow algorithm in https://tools.ietf.org/html/rfc3986#section-5.2.4, * the block comments are copied from there */ kms_request_str_t * kms_request_str_path_normalized (kms_request_str_t *str) { kms_request_str_t *slash = kms_request_str_new_from_chars ("/", 1); kms_request_str_t *out = kms_request_str_new (); char *in = strdup (str->str); char *p = in; char *end = in + str->len; bool is_absolute = (*p == '/'); if (0 == strcmp (p, "/")) { goto done; } while (p < end) { /* If the input buffer begins with a prefix of "../" or "./", * then remove that prefix from the input buffer */ if (starts_with (p, "../")) { p += 3; } else if (starts_with (p, "./")) { p += 2; } /* otherwise, if the input buffer begins with a prefix of "/./" or "/.", * where "." is a complete path segment, then replace that prefix with "/" * in the input buffer */ else if (starts_with (p, "/./")) { p += 2; } else if (0 == strcmp (p, "/.")) { break; } /* otherwise, if the input buffer begins with a prefix of "/../" or "/..", * where ".." is a complete path segment, then replace that prefix with * "/" in the input buffer and remove the last segment and its preceding * "/" (if any) from the output buffer */ else if (starts_with (p, "/../")) { p += 3; delete_last_segment (out, is_absolute); } else if (0 == strcmp (p, "/..")) { delete_last_segment (out, is_absolute); break; } /* otherwise, if the input buffer consists only of "." or "..", then remove that from the input buffer */ else if (0 == strcmp (p, ".") || 0 == strcmp (p, "..")) { break; } /* otherwise, move the first path segment in the input buffer to the end * of the output buffer, including the initial "/" character (if any) and * any subsequent characters up to, but not including, the next "/" * character or the end of the input buffer. */ else { char *next_slash = strchr (p + 1, '/'); if (!next_slash) { next_slash = end; } /* fold repeated slashes */ if (kms_request_str_ends_with (out, slash) && *p == '/') { ++p; } /* normalize "a/../b" as "b", not as "/b" */ if (out->len == 0 && !is_absolute && *p == '/') { ++p; } kms_request_str_append_chars (out, p, next_slash - p); p = next_slash; } } done: free (in); kms_request_str_destroy (slash); if (!out->len) { kms_request_str_append_char (out, '/'); } return out; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_request_str.h0000644000175100001660000000640214760300420022074 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_KMS_REQUEST_STR_H #define KMS_MESSAGE_KMS_REQUEST_STR_H #include "kms_message/kms_message.h" #include "kms_crypto.h" #include #include #include #include typedef struct { char *str; size_t len; size_t size; } kms_request_str_t; KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_new (void); KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_new_from_chars (const char *chars, ssize_t len); KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_wrap (char *chars, ssize_t len); KMS_MSG_EXPORT (void) kms_request_str_destroy (kms_request_str_t *str); KMS_MSG_EXPORT (char *) kms_request_str_detach (kms_request_str_t *str); KMS_MSG_EXPORT (bool) kms_request_str_reserve (kms_request_str_t *str, size_t size); KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_dup (kms_request_str_t *str); KMS_MSG_EXPORT (void) kms_request_str_set_chars (kms_request_str_t *str, const char *chars, ssize_t len); KMS_MSG_EXPORT (bool) kms_request_str_ends_with (kms_request_str_t *str, kms_request_str_t *suffix); KMS_MSG_EXPORT (void) kms_request_str_append (kms_request_str_t *str, kms_request_str_t *appended); KMS_MSG_EXPORT (void) kms_request_str_append_char (kms_request_str_t *str, char c); KMS_MSG_EXPORT (void) kms_request_str_append_chars (kms_request_str_t *str, const char *appended, ssize_t len); KMS_MSG_EXPORT (void) kms_request_str_append_newline (kms_request_str_t *str); KMS_MSG_EXPORT (void) kms_request_str_append_lowercase (kms_request_str_t *str, kms_request_str_t *appended); KMS_MSG_EXPORT (void) kms_request_str_appendf (kms_request_str_t *str, const char *format, ...); KMS_MSG_EXPORT (void) kms_request_strdupf (kms_request_str_t *str, const char *format, ...); KMS_MSG_EXPORT (void) kms_request_str_append_escaped (kms_request_str_t *str, kms_request_str_t *appended, bool escape_slash); KMS_MSG_EXPORT (void) kms_request_str_append_stripped (kms_request_str_t *str, kms_request_str_t *appended); KMS_MSG_EXPORT (bool) kms_request_str_append_hashed (_kms_crypto_t *crypto, kms_request_str_t *str, kms_request_str_t *appended); KMS_MSG_EXPORT (bool) kms_request_str_append_hex (kms_request_str_t *str, unsigned char *data, size_t len); KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_path_normalized (kms_request_str_t *str); #endif // KMS_MESSAGE_KMS_REQUEST_STR_H mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_response.c0000644000175100001660000000246314760300420021350 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_request_str.h" void kms_response_destroy (kms_response_t *response) { if (response == NULL) { return; } free (response->kmip.data); kms_kv_list_destroy (response->headers); kms_request_str_destroy (response->body); free (response); } const char * kms_response_get_body (kms_response_t *response, size_t *len) { if (len) { *len = response->body->len; } return response->body->str; } int kms_response_get_status (kms_response_t *response) { return response->status; } const char * kms_response_get_error (const kms_response_t *response) { return response->failed ? response->error : NULL; } mongodb-1.21.0/src/libmongoc/src/kms-message/src/kms_response_parser.c0000644000175100001660000002626514760300420022732 0ustar #include "kms_message/kms_response_parser.h" #include "kms_message_private.h" #include "kms_kmip_response_parser_private.h" #include #include #include #include #include "hexlify.h" /* destroys the members of parser, but not the parser itself. */ static void _parser_destroy (kms_response_parser_t *parser) { kms_request_str_destroy (parser->raw_response); parser->raw_response = NULL; parser->content_length = -1; kms_response_destroy (parser->response); parser->response = NULL; kms_kmip_response_parser_destroy (parser->kmip); } /* initializes the members of parser. */ static void _parser_init (kms_response_parser_t *parser) { parser->raw_response = kms_request_str_new (); parser->content_length = -1; parser->response = calloc (1, sizeof (kms_response_t)); KMS_ASSERT (parser->response); parser->response->headers = kms_kv_list_new (); parser->state = PARSING_STATUS_LINE; parser->start = 0; parser->failed = false; parser->chunk_size = 0; parser->transfer_encoding_chunked = false; parser->kmip = NULL; } void kms_response_parser_reset (kms_response_parser_t *parser) { KMS_ASSERT(!parser->kmip); // KMIP is not-yet supported. _parser_destroy(parser); _parser_init(parser); } kms_response_parser_t * kms_response_parser_new (void) { kms_response_parser_t *parser = malloc (sizeof (kms_response_parser_t)); KMS_ASSERT (parser); _parser_init (parser); return parser; } int kms_response_parser_wants_bytes (kms_response_parser_t *parser, int32_t max) { if (parser->kmip) { return kms_kmip_response_parser_wants_bytes (parser->kmip, max); } switch (parser->state) { case PARSING_DONE: return 0; case PARSING_STATUS_LINE: case PARSING_HEADER: return max; case PARSING_CHUNK_LENGTH: return max; case PARSING_CHUNK: /* add 2 for trailing \r\n */ return (parser->chunk_size + 2) - ((int) parser->raw_response->len - parser->start); case PARSING_BODY: KMS_ASSERT (parser->content_length != -1); return parser->content_length - ((int) parser->raw_response->len - parser->start); default: KMS_ASSERT (false && "Invalid kms_response_parser HTTP state"); } return -1; } static bool _parse_int (const char *str, int *result) { char *endptr = NULL; int64_t long_result; errno = 0; long_result = strtol (str, &endptr, 10); if (endptr == str) { /* No digits were parsed. Consider this an error */ return false; } if (endptr != NULL && *endptr != '\0') { /* endptr points to the first invalid character. */ return false; } if (errno == EINVAL || errno == ERANGE) { return false; } if (long_result > INT32_MAX || long_result < INT32_MIN) { return false; } *result = (int) long_result; return true; } /* parse an int from a substring inside of a string. */ static bool _parse_int_from_view (const char *str, int start, int end, int *result) { KMS_ASSERT (end >= start); char *num_str = malloc ((size_t) (end - start + 1)); KMS_ASSERT (num_str); bool ret; strncpy (num_str, str + start, (size_t) (end - start)); num_str[end - start] = '\0'; ret = _parse_int (num_str, result); free (num_str); return ret; } static bool _parse_hex_from_view (const char *str, int len, int *result) { KMS_ASSERT (len >= 0); *result = unhexlify (str, (size_t) len); if (*result < 0) { return false; } return true; } /* returns true if char is "linear white space". This *ignores* the folding case * of CRLF followed by WSP. See https://stackoverflow.com/a/21072806/774658 */ static bool _is_lwsp (char c) { return c == ' ' || c == 0x09 /* HTAB */; } /* parse a header line or status line. */ static kms_response_parser_state_t _parse_line (kms_response_parser_t *parser, int end) { int i = parser->start; const char *raw = parser->raw_response->str; kms_response_t *response = parser->response; if (parser->state == PARSING_STATUS_LINE) { /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ int j; int status; if (strncmp (raw + i, "HTTP/1.1 ", 9) != 0) { KMS_ERROR (parser, "Could not parse HTTP-Version."); return PARSING_DONE; } i += 9; for (j = i; j < end; j++) { if (raw[j] == ' ') break; } if (!_parse_int_from_view (raw, i, j, &status)) { KMS_ERROR (parser, "Could not parse Status-Code."); return PARSING_DONE; } response->status = status; /* ignore the Reason-Phrase. */ return PARSING_HEADER; } else if (parser->state == PARSING_HEADER) { /* Treating a header as: * message-header = field-name ":" [ field-value ] CRLF * This is not completely correct, and does not take folding into acct. * See https://tools.ietf.org/html/rfc822#section-3.1 */ int j; kms_request_str_t *key; kms_request_str_t *val; if (i == end) { /* empty line, this signals the start of the body. */ if (parser->transfer_encoding_chunked) { return PARSING_CHUNK_LENGTH; } return PARSING_BODY; } for (j = i; j < end; j++) { if (raw[j] == ':') break; } if (j == end) { KMS_ERROR (parser, "Could not parse header, no colon found."); return PARSING_DONE; } key = kms_request_str_new_from_chars (raw + i, j - i); i = j + 1; /* remove leading and trailing whitespace from the value. */ for (j = i; j < end; j++) { if (!_is_lwsp (raw[j])) break; } i = j; /* find the end of the header by backtracking. */ for (j = end; j > i; j--) { if (!_is_lwsp (raw[j])) break; } if (i == j) { val = kms_request_str_new (); } else { val = kms_request_str_new_from_chars (raw + i, j - i); } kms_kv_list_add (response->headers, key, val); /* if we have *not* read the Content-Length yet, check. */ if (parser->content_length == -1 && strcmp (key->str, "Content-Length") == 0) { if (!_parse_int (val->str, &parser->content_length)) { KMS_ERROR (parser, "Could not parse Content-Length header."); kms_request_str_destroy (key); kms_request_str_destroy (val); return PARSING_DONE; } } if (0 == strcmp (key->str, "Transfer-Encoding")) { if (0 == strcmp (val->str, "chunked")) { parser->transfer_encoding_chunked = true; } else { KMS_ERROR (parser, "Unsupported Transfer-Encoding: %s", val->str); kms_request_str_destroy (key); kms_request_str_destroy (val); return PARSING_DONE; } } kms_request_str_destroy (key); kms_request_str_destroy (val); return PARSING_HEADER; } else if (parser->state == PARSING_CHUNK_LENGTH) { int result = 0; if (!_parse_hex_from_view (raw + i, end - i, &result)) { KMS_ERROR (parser, "Failed to parse hex chunk length."); return PARSING_DONE; } parser->chunk_size = result; return PARSING_CHUNK; } return PARSING_DONE; } bool kms_response_parser_feed (kms_response_parser_t *parser, uint8_t *buf, uint32_t len) { kms_request_str_t *raw = parser->raw_response; int curr, body_read, chunk_read; if (parser->kmip) { return kms_kmip_response_parser_feed (parser->kmip, buf, len); } curr = (int) raw->len; kms_request_str_append_chars (raw, (char *) buf, len); /* process the new data appended. */ while (curr < (int) raw->len) { switch (parser->state) { case PARSING_STATUS_LINE: case PARSING_HEADER: case PARSING_CHUNK_LENGTH: /* find the next \r\n. */ if (curr && strncmp (raw->str + (curr - 1), "\r\n", 2) == 0) { parser->state = _parse_line (parser, curr - 1); parser->start = curr + 1; } curr++; if (parser->state == PARSING_BODY && parser->content_length <= 0) { /* Ok, no Content-Length header, or explicitly 0, so empty body */ parser->response->body = kms_request_str_new (); parser->state = PARSING_DONE; } break; case PARSING_BODY: body_read = (int) raw->len - parser->start; if (parser->content_length == -1 || body_read > parser->content_length) { KMS_ERROR (parser, "Unexpected: exceeded content length"); return false; } /* check if we have the entire body. */ if (body_read == parser->content_length) { parser->response->body = kms_request_str_new_from_chars ( raw->str + parser->start, parser->content_length); parser->state = PARSING_DONE; } curr = (int) raw->len; break; case PARSING_CHUNK: chunk_read = (int) raw->len - parser->start; /* check if we've read the full chunk and the trailing \r\n */ if (chunk_read >= parser->chunk_size + 2) { if (!parser->response->body) { parser->response->body = kms_request_str_new (); } kms_request_str_append_chars (parser->response->body, raw->str + parser->start, parser->chunk_size); curr = parser->start + parser->chunk_size + 2; parser->start = curr; if (parser->chunk_size == 0) { /* last chunk. */ parser->state = PARSING_DONE; } else { parser->state = PARSING_CHUNK_LENGTH; } } else { curr = (int) raw->len; } break; case PARSING_DONE: KMS_ERROR (parser, "Unexpected extra HTTP content"); return false; default: KMS_ASSERT (false && "Invalid kms_response_parser HTTP state"); } } if (parser->failed) { return false; } return true; } /* steals the response from the parser. */ kms_response_t * kms_response_parser_get_response (kms_response_parser_t *parser) { kms_response_t *response; if (parser->kmip) { return kms_kmip_response_parser_get_response (parser->kmip); } response = parser->response; parser->response = NULL; /* reset the parser. */ _parser_destroy (parser); _parser_init (parser); return response; } int kms_response_parser_status (kms_response_parser_t *parser) { if (!parser) { return 0; } if (parser->kmip) { KMS_ERROR (parser, "kms_response_parser_status not applicable to KMIP"); return 0; } if (!parser->response) { return 0; } return parser->response->status; } const char * kms_response_parser_error (kms_response_parser_t *parser) { if (!parser) { return NULL; } if (parser->kmip) { return kms_kmip_response_parser_error (parser->kmip); } return parser->error; } void kms_response_parser_destroy (kms_response_parser_t *parser) { _parser_destroy (parser); free (parser); } mongodb-1.21.0/src/libmongoc/src/kms-message/src/sort.c0000644000175100001660000000506614760300420017631 0ustar /* * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Peter McIlroy. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /** * This code is originally from: * https://github.com/freebsd/freebsd/blob/e7c6cef9514d3bb1f14a30a5ee871231523e43db/lib/libc/stdlib/merge.c */ #include /* * This is to avoid out-of-bounds addresses in sorting the * last 4 elements. */ typedef int (*cmp_t) (const void *, const void *); #define CMP(x, y) cmp (x, y) #define swap(a, b) \ { \ s = b; \ i = size; \ do { \ tmp = *a; \ *a++ = *s; \ *s++ = tmp; \ } while (--i); \ a -= size; \ } void insertionsort (unsigned char *a, size_t n, size_t size, cmp_t cmp) { unsigned char *ai, *s, *t, *u, tmp; size_t i; for (ai = a + size; --n >= 1; ai += size) for (t = ai; t > a; t -= size) { u = t - size; if (CMP (u, t) <= 0) break; swap (u, t); } } mongodb-1.21.0/src/libmongoc/src/kms-message/src/sort.h0000644000175100001660000000133514760300420017631 0ustar /* * Copyright 2018-present MongoDB, 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. */ typedef int (*cmp_t) (const void *, const void *); void insertionsort (unsigned char *a, size_t n, size_t size, cmp_t cmp); mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bcon.c0000644000175100001660000006500714760300420017741 0ustar /* * @file bcon.c * @brief BCON (BSON C Object Notation) Implementation */ /* Copyright 2009-present MongoDB, 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. */ #include #include #include /* These stack manipulation macros are used to manage append recursion in * bcon_append_ctx_va(). They take care of some awkward dereference rules (the * real bson object isn't in the stack, but accessed by pointer) and add in run * time asserts to make sure we don't blow the stack in either direction */ #define STACK_ELE(_delta, _name) (ctx->stack[(_delta) + ctx->n]._name) #define STACK_BSON(_delta) (((_delta) + ctx->n) == 0 ? bson : &STACK_ELE (_delta, bson)) #define STACK_ITER(_delta) (((_delta) + ctx->n) == 0 ? &root_iter : &STACK_ELE (_delta, iter)) #define STACK_BSON_PARENT STACK_BSON (-1) #define STACK_BSON_CHILD STACK_BSON (0) #define STACK_ITER_PARENT STACK_ITER (-1) #define STACK_ITER_CHILD STACK_ITER (0) #define STACK_I STACK_ELE (0, i) #define STACK_IS_ARRAY STACK_ELE (0, is_array) #define STACK_PUSH_ARRAY(statement) \ do { \ BSON_ASSERT (ctx->n < (BCON_STACK_MAX - 1)); \ ctx->n++; \ STACK_I = 0; \ STACK_IS_ARRAY = 1; \ statement; \ } while (0) #define STACK_PUSH_DOC(statement) \ do { \ BSON_ASSERT (ctx->n < (BCON_STACK_MAX - 1)); \ ctx->n++; \ STACK_IS_ARRAY = 0; \ statement; \ } while (0) #define STACK_POP_ARRAY(statement) \ do { \ BSON_ASSERT (STACK_IS_ARRAY); \ BSON_ASSERT (ctx->n != 0); \ statement; \ ctx->n--; \ } while (0) #define STACK_POP_DOC(statement) \ do { \ BSON_ASSERT (!STACK_IS_ARRAY); \ BSON_ASSERT (ctx->n != 0); \ statement; \ ctx->n--; \ } while (0) /* This is a landing pad union for all of the types we can process with bcon. * We need actual storage for this to capture the return value of va_arg, which * takes multiple calls to get everything we need for some complex types */ typedef union bcon_append { char *UTF8; double DOUBLE; bson_t *DOCUMENT; bson_t *ARRAY; bson_t *BCON; struct { bson_subtype_t subtype; uint8_t *binary; uint32_t length; } BIN; bson_oid_t *OID; bool BOOL; int64_t DATE_TIME; struct { char *regex; char *flags; } REGEX; struct { char *collection; bson_oid_t *oid; } DBPOINTER; const char *CODE; char *SYMBOL; struct { const char *js; bson_t *scope; } CODEWSCOPE; int32_t INT32; struct { uint32_t timestamp; uint32_t increment; } TIMESTAMP; int64_t INT64; bson_decimal128_t *DECIMAL128; const bson_iter_t *ITER; } bcon_append_t; /* same as bcon_append_t. Some extra symbols and varying types that handle the * differences between bson_append and bson_iter */ typedef union bcon_extract { bson_type_t TYPE; bson_iter_t *ITER; const char *key; const char **UTF8; double *DOUBLE; bson_t *DOCUMENT; bson_t *ARRAY; struct { bson_subtype_t *subtype; const uint8_t **binary; uint32_t *length; } BIN; const bson_oid_t **OID; bool *BOOL; int64_t *DATE_TIME; struct { const char **regex; const char **flags; } REGEX; struct { const char **collection; const bson_oid_t **oid; } DBPOINTER; const char **CODE; const char **SYMBOL; struct { const char **js; bson_t *scope; } CODEWSCOPE; int32_t *INT32; struct { uint32_t *timestamp; uint32_t *increment; } TIMESTAMP; int64_t *INT64; bson_decimal128_t *DECIMAL128; } bcon_extract_t; static const char *gBconMagic = "BCON_MAGIC"; static const char *gBconeMagic = "BCONE_MAGIC"; const char * bson_bcon_magic (void) { return gBconMagic; } const char * bson_bcone_magic (void) { return gBconeMagic; } static void _noop (void) { } /* appends val to the passed bson object. Meant to be a super simple dispatch * table */ static void _bcon_append_single (bson_t *bson, bcon_type_t type, const char *key, bcon_append_t *val) { switch ((int) type) { case BCON_TYPE_UTF8: BSON_ASSERT (bson_append_utf8 (bson, key, -1, val->UTF8, -1)); break; case BCON_TYPE_DOUBLE: BSON_ASSERT (bson_append_double (bson, key, -1, val->DOUBLE)); break; case BCON_TYPE_BIN: { BSON_ASSERT (bson_append_binary (bson, key, -1, val->BIN.subtype, val->BIN.binary, val->BIN.length)); break; } case BCON_TYPE_UNDEFINED: BSON_ASSERT (bson_append_undefined (bson, key, -1)); break; case BCON_TYPE_OID: BSON_ASSERT (bson_append_oid (bson, key, -1, val->OID)); break; case BCON_TYPE_BOOL: BSON_ASSERT (bson_append_bool (bson, key, -1, (bool) val->BOOL)); break; case BCON_TYPE_DATE_TIME: BSON_ASSERT (bson_append_date_time (bson, key, -1, val->DATE_TIME)); break; case BCON_TYPE_NULL: BSON_ASSERT (bson_append_null (bson, key, -1)); break; case BCON_TYPE_REGEX: { BSON_ASSERT (bson_append_regex (bson, key, -1, val->REGEX.regex, val->REGEX.flags)); break; } case BCON_TYPE_DBPOINTER: { BSON_ASSERT (bson_append_dbpointer (bson, key, -1, val->DBPOINTER.collection, val->DBPOINTER.oid)); break; } case BCON_TYPE_CODE: BSON_ASSERT (bson_append_code (bson, key, -1, val->CODE)); break; case BCON_TYPE_SYMBOL: BSON_ASSERT (bson_append_symbol (bson, key, -1, val->SYMBOL, -1)); break; case BCON_TYPE_CODEWSCOPE: BSON_ASSERT (bson_append_code_with_scope (bson, key, -1, val->CODEWSCOPE.js, val->CODEWSCOPE.scope)); break; case BCON_TYPE_INT32: BSON_ASSERT (bson_append_int32 (bson, key, -1, val->INT32)); break; case BCON_TYPE_TIMESTAMP: { BSON_ASSERT (bson_append_timestamp (bson, key, -1, val->TIMESTAMP.timestamp, val->TIMESTAMP.increment)); break; } case BCON_TYPE_INT64: BSON_ASSERT (bson_append_int64 (bson, key, -1, val->INT64)); break; case BCON_TYPE_DECIMAL128: BSON_ASSERT (bson_append_decimal128 (bson, key, -1, val->DECIMAL128)); break; case BCON_TYPE_MAXKEY: BSON_ASSERT (bson_append_maxkey (bson, key, -1)); break; case BCON_TYPE_MINKEY: BSON_ASSERT (bson_append_minkey (bson, key, -1)); break; case BCON_TYPE_ARRAY: { BSON_ASSERT (bson_append_array (bson, key, -1, val->ARRAY)); break; } case BCON_TYPE_DOCUMENT: { BSON_ASSERT (bson_append_document (bson, key, -1, val->DOCUMENT)); break; } case BCON_TYPE_ITER: BSON_ASSERT (bson_append_iter (bson, key, -1, val->ITER)); break; default: BSON_ASSERT (0); break; } } #define CHECK_TYPE(_type) \ do { \ if (bson_iter_type (iter) != (_type)) { \ return false; \ } \ } while (0) /* extracts the value under the iterator and writes it to val. returns false * if the iterator type doesn't match the token type. * * There are two magic tokens: * * BCONE_SKIP - * Let's us verify that a key has a type, without caring about its value. * This allows for wider declarative BSON verification * * BCONE_ITER - * Returns the underlying iterator. This could allow for more complicated, * procedural verification (if a parameter could have multiple types). * */ static bool _bcon_extract_single (const bson_iter_t *iter, bcon_type_t type, bcon_extract_t *val) { switch ((int) type) { case BCON_TYPE_UTF8: CHECK_TYPE (BSON_TYPE_UTF8); *val->UTF8 = bson_iter_utf8 (iter, NULL); break; case BCON_TYPE_DOUBLE: CHECK_TYPE (BSON_TYPE_DOUBLE); *val->DOUBLE = bson_iter_double (iter); break; case BCON_TYPE_BIN: CHECK_TYPE (BSON_TYPE_BINARY); bson_iter_binary (iter, val->BIN.subtype, val->BIN.length, val->BIN.binary); break; case BCON_TYPE_UNDEFINED: CHECK_TYPE (BSON_TYPE_UNDEFINED); break; case BCON_TYPE_OID: CHECK_TYPE (BSON_TYPE_OID); *val->OID = bson_iter_oid (iter); break; case BCON_TYPE_BOOL: CHECK_TYPE (BSON_TYPE_BOOL); *val->BOOL = bson_iter_bool (iter); break; case BCON_TYPE_DATE_TIME: CHECK_TYPE (BSON_TYPE_DATE_TIME); *val->DATE_TIME = bson_iter_date_time (iter); break; case BCON_TYPE_NULL: CHECK_TYPE (BSON_TYPE_NULL); break; case BCON_TYPE_REGEX: CHECK_TYPE (BSON_TYPE_REGEX); *val->REGEX.regex = bson_iter_regex (iter, val->REGEX.flags); break; case BCON_TYPE_DBPOINTER: CHECK_TYPE (BSON_TYPE_DBPOINTER); bson_iter_dbpointer (iter, NULL, val->DBPOINTER.collection, val->DBPOINTER.oid); break; case BCON_TYPE_CODE: CHECK_TYPE (BSON_TYPE_CODE); *val->CODE = bson_iter_code (iter, NULL); break; case BCON_TYPE_SYMBOL: CHECK_TYPE (BSON_TYPE_SYMBOL); *val->SYMBOL = bson_iter_symbol (iter, NULL); break; case BCON_TYPE_CODEWSCOPE: { const uint8_t *buf; uint32_t len; CHECK_TYPE (BSON_TYPE_CODEWSCOPE); *val->CODEWSCOPE.js = bson_iter_codewscope (iter, NULL, &len, &buf); BSON_ASSERT (bson_init_static (val->CODEWSCOPE.scope, buf, len)); break; } case BCON_TYPE_INT32: CHECK_TYPE (BSON_TYPE_INT32); *val->INT32 = bson_iter_int32 (iter); break; case BCON_TYPE_TIMESTAMP: CHECK_TYPE (BSON_TYPE_TIMESTAMP); bson_iter_timestamp (iter, val->TIMESTAMP.timestamp, val->TIMESTAMP.increment); break; case BCON_TYPE_INT64: CHECK_TYPE (BSON_TYPE_INT64); *val->INT64 = bson_iter_int64 (iter); break; case BCON_TYPE_DECIMAL128: CHECK_TYPE (BSON_TYPE_DECIMAL128); BSON_ASSERT (bson_iter_decimal128 (iter, val->DECIMAL128)); break; case BCON_TYPE_MAXKEY: CHECK_TYPE (BSON_TYPE_MAXKEY); break; case BCON_TYPE_MINKEY: CHECK_TYPE (BSON_TYPE_MINKEY); break; case BCON_TYPE_ARRAY: { const uint8_t *buf; uint32_t len; CHECK_TYPE (BSON_TYPE_ARRAY); bson_iter_array (iter, &len, &buf); BSON_ASSERT (bson_init_static (val->ARRAY, buf, len)); break; } case BCON_TYPE_DOCUMENT: { const uint8_t *buf; uint32_t len; CHECK_TYPE (BSON_TYPE_DOCUMENT); bson_iter_document (iter, &len, &buf); BSON_ASSERT (bson_init_static (val->DOCUMENT, buf, len)); break; } case BCON_TYPE_SKIP: CHECK_TYPE (val->TYPE); break; case BCON_TYPE_ITER: memcpy (val->ITER, iter, sizeof *iter); break; default: BSON_ASSERT (0); break; } return true; } /* Consumes ap, storing output values into u and returning the type of the * captured token. * * The basic workflow goes like this: * * 1. Look at the current arg. It will be a char * * a. If it's a NULL, we're done processing. * b. If it's BCON_MAGIC (a symbol with storage in this module) * I. The next token is the type * II. The type specifies how many args to eat and their types * c. Otherwise it's either recursion related or a raw string * I. If the first byte is '{', '}', '[', or ']' pass back an * appropriate recursion token * II. If not, just call it a UTF8 token and pass that back */ static bcon_type_t _bcon_append_tokenize (va_list *ap, bcon_append_t *u) { char *mark; bcon_type_t type; mark = va_arg (*ap, char *); BSON_ASSERT (mark != BCONE_MAGIC); if (mark == NULL) { type = BCON_TYPE_END; } else if (mark == BCON_MAGIC) { type = va_arg (*ap, bcon_type_t); switch ((int) type) { case BCON_TYPE_UTF8: u->UTF8 = va_arg (*ap, char *); break; case BCON_TYPE_DOUBLE: u->DOUBLE = va_arg (*ap, double); break; case BCON_TYPE_DOCUMENT: u->DOCUMENT = va_arg (*ap, bson_t *); break; case BCON_TYPE_ARRAY: u->ARRAY = va_arg (*ap, bson_t *); break; case BCON_TYPE_BIN: u->BIN.subtype = va_arg (*ap, bson_subtype_t); u->BIN.binary = va_arg (*ap, uint8_t *); u->BIN.length = va_arg (*ap, uint32_t); break; case BCON_TYPE_UNDEFINED: break; case BCON_TYPE_OID: u->OID = va_arg (*ap, bson_oid_t *); break; case BCON_TYPE_BOOL: u->BOOL = va_arg (*ap, int); break; case BCON_TYPE_DATE_TIME: u->DATE_TIME = va_arg (*ap, int64_t); break; case BCON_TYPE_NULL: break; case BCON_TYPE_REGEX: u->REGEX.regex = va_arg (*ap, char *); u->REGEX.flags = va_arg (*ap, char *); break; case BCON_TYPE_DBPOINTER: u->DBPOINTER.collection = va_arg (*ap, char *); u->DBPOINTER.oid = va_arg (*ap, bson_oid_t *); break; case BCON_TYPE_CODE: u->CODE = va_arg (*ap, char *); break; case BCON_TYPE_SYMBOL: u->SYMBOL = va_arg (*ap, char *); break; case BCON_TYPE_CODEWSCOPE: u->CODEWSCOPE.js = va_arg (*ap, char *); u->CODEWSCOPE.scope = va_arg (*ap, bson_t *); break; case BCON_TYPE_INT32: u->INT32 = va_arg (*ap, int32_t); break; case BCON_TYPE_TIMESTAMP: u->TIMESTAMP.timestamp = va_arg (*ap, uint32_t); u->TIMESTAMP.increment = va_arg (*ap, uint32_t); break; case BCON_TYPE_INT64: u->INT64 = va_arg (*ap, int64_t); break; case BCON_TYPE_DECIMAL128: u->DECIMAL128 = va_arg (*ap, bson_decimal128_t *); break; case BCON_TYPE_MAXKEY: break; case BCON_TYPE_MINKEY: break; case BCON_TYPE_BCON: u->BCON = va_arg (*ap, bson_t *); break; case BCON_TYPE_ITER: u->ITER = va_arg (*ap, const bson_iter_t *); break; default: BSON_ASSERT (0); break; } } else { switch (mark[0]) { case '{': type = BCON_TYPE_DOC_START; break; case '}': type = BCON_TYPE_DOC_END; break; case '[': type = BCON_TYPE_ARRAY_START; break; case ']': type = BCON_TYPE_ARRAY_END; break; default: type = BCON_TYPE_UTF8; u->UTF8 = mark; break; } } return type; } /* Consumes ap, storing output values into u and returning the type of the * captured token. * * The basic workflow goes like this: * * 1. Look at the current arg. It will be a char * * a. If it's a NULL, we're done processing. * b. If it's BCONE_MAGIC (a symbol with storage in this module) * I. The next token is the type * II. The type specifies how many args to eat and their types * c. Otherwise it's either recursion related or a raw string * I. If the first byte is '{', '}', '[', or ']' pass back an * appropriate recursion token * II. If not, just call it a UTF8 token and pass that back */ static bcon_type_t _bcon_extract_tokenize (va_list *ap, bcon_extract_t *u) { char *mark; bcon_type_t type; mark = va_arg (*ap, char *); BSON_ASSERT (mark != BCON_MAGIC); if (mark == NULL) { type = BCON_TYPE_END; } else if (mark == BCONE_MAGIC) { type = va_arg (*ap, bcon_type_t); switch ((int) type) { case BCON_TYPE_UTF8: u->UTF8 = va_arg (*ap, const char **); break; case BCON_TYPE_DOUBLE: u->DOUBLE = va_arg (*ap, double *); break; case BCON_TYPE_DOCUMENT: u->DOCUMENT = va_arg (*ap, bson_t *); break; case BCON_TYPE_ARRAY: u->ARRAY = va_arg (*ap, bson_t *); break; case BCON_TYPE_BIN: u->BIN.subtype = va_arg (*ap, bson_subtype_t *); u->BIN.binary = va_arg (*ap, const uint8_t **); u->BIN.length = va_arg (*ap, uint32_t *); break; case BCON_TYPE_UNDEFINED: break; case BCON_TYPE_OID: u->OID = va_arg (*ap, const bson_oid_t **); break; case BCON_TYPE_BOOL: u->BOOL = va_arg (*ap, bool *); break; case BCON_TYPE_DATE_TIME: u->DATE_TIME = va_arg (*ap, int64_t *); break; case BCON_TYPE_NULL: break; case BCON_TYPE_REGEX: u->REGEX.regex = va_arg (*ap, const char **); u->REGEX.flags = va_arg (*ap, const char **); break; case BCON_TYPE_DBPOINTER: u->DBPOINTER.collection = va_arg (*ap, const char **); u->DBPOINTER.oid = va_arg (*ap, const bson_oid_t **); break; case BCON_TYPE_CODE: u->CODE = va_arg (*ap, const char **); break; case BCON_TYPE_SYMBOL: u->SYMBOL = va_arg (*ap, const char **); break; case BCON_TYPE_CODEWSCOPE: u->CODEWSCOPE.js = va_arg (*ap, const char **); u->CODEWSCOPE.scope = va_arg (*ap, bson_t *); break; case BCON_TYPE_INT32: u->INT32 = va_arg (*ap, int32_t *); break; case BCON_TYPE_TIMESTAMP: u->TIMESTAMP.timestamp = va_arg (*ap, uint32_t *); u->TIMESTAMP.increment = va_arg (*ap, uint32_t *); break; case BCON_TYPE_INT64: u->INT64 = va_arg (*ap, int64_t *); break; case BCON_TYPE_DECIMAL128: u->DECIMAL128 = va_arg (*ap, bson_decimal128_t *); break; case BCON_TYPE_MAXKEY: break; case BCON_TYPE_MINKEY: break; case BCON_TYPE_SKIP: u->TYPE = va_arg (*ap, bson_type_t); break; case BCON_TYPE_ITER: u->ITER = va_arg (*ap, bson_iter_t *); break; default: BSON_ASSERT (0); break; } } else { switch (mark[0]) { case '{': type = BCON_TYPE_DOC_START; break; case '}': type = BCON_TYPE_DOC_END; break; case '[': type = BCON_TYPE_ARRAY_START; break; case ']': type = BCON_TYPE_ARRAY_END; break; default: type = BCON_TYPE_RAW; u->key = mark; break; } } return type; } /* This trivial utility function is useful for concatenating a bson object onto * the end of another, ignoring the keys from the source bson object and * continuing to use and increment the keys from the source. It's only useful * when called from bcon_append_ctx_va */ static void _bson_concat_array (bson_t *dest, const bson_t *src, bcon_append_ctx_t *ctx) { bson_iter_t iter; const char *key; char i_str[16]; bool r; r = bson_iter_init (&iter, src); if (!r) { fprintf (stderr, "Invalid BSON document, possible memory coruption.\n"); return; } STACK_I--; while (bson_iter_next (&iter)) { bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); STACK_I++; BSON_ASSERT (bson_append_iter (dest, key, -1, &iter)); } } /* Append_ctx_va consumes the va_list until NULL is found, appending into bson * as tokens are found. It can receive or return an in-progress bson object * via the ctx param. It can also operate on the middle of a va_list, and so * can be wrapped inside of another varargs function. * * Note that passing in a va_list that isn't perferectly formatted for BCON * ingestion will almost certainly result in undefined behavior * * The workflow relies on the passed ctx object, which holds a stack of bson * objects, along with metadata (if the emedded layer is an array, and which * element it is on if so). We iterate, generating tokens from the va_list, * until we reach an END token. If any errors occur, we just blow up (the * var_args stuff is already incredibly fragile to mistakes, and we have no way * of introspecting, so just don't screw it up). * * There are also a few STACK_* macros in here which manipulate ctx that are * defined up top. * */ void bcon_append_ctx_va (bson_t *bson, bcon_append_ctx_t *ctx, va_list *ap) { bcon_type_t type; const char *key; char i_str[16]; bcon_append_t u = {0}; while (1) { if (STACK_IS_ARRAY) { bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); STACK_I++; } else { type = _bcon_append_tokenize (ap, &u); if (type == BCON_TYPE_END) { return; } if (type == BCON_TYPE_DOC_END) { STACK_POP_DOC (bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); continue; } if (type == BCON_TYPE_BCON) { bson_concat (STACK_BSON_CHILD, u.BCON); continue; } BSON_ASSERT (type == BCON_TYPE_UTF8); key = u.UTF8; } type = _bcon_append_tokenize (ap, &u); BSON_ASSERT (type != BCON_TYPE_END); switch ((int) type) { case BCON_TYPE_BCON: BSON_ASSERT (STACK_IS_ARRAY); _bson_concat_array (STACK_BSON_CHILD, u.BCON, ctx); break; case BCON_TYPE_DOC_START: STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, key, -1, STACK_BSON_CHILD)); break; case BCON_TYPE_DOC_END: STACK_POP_DOC (bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); break; case BCON_TYPE_ARRAY_START: STACK_PUSH_ARRAY (bson_append_array_begin (STACK_BSON_PARENT, key, -1, STACK_BSON_CHILD)); break; case BCON_TYPE_ARRAY_END: STACK_POP_ARRAY (bson_append_array_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); break; default: _bcon_append_single (STACK_BSON_CHILD, type, key, &u); break; } } } /* extract_ctx_va consumes the va_list until NULL is found, extracting values * as tokens are found. It can receive or return an in-progress bson object * via the ctx param. It can also operate on the middle of a va_list, and so * can be wrapped inside of another varargs function. * * Note that passing in a va_list that isn't perferectly formatted for BCON * ingestion will almost certainly result in undefined behavior * * The workflow relies on the passed ctx object, which holds a stack of iterator * objects, along with metadata (if the emedded layer is an array, and which * element it is on if so). We iterate, generating tokens from the va_list, * until we reach an END token. If any errors occur, we just blow up (the * var_args stuff is already incredibly fragile to mistakes, and we have no way * of introspecting, so just don't screw it up). * * There are also a few STACK_* macros in here which manipulate ctx that are * defined up top. * * The function returns true if all tokens could be successfully matched, false * otherwise. * */ bool bcon_extract_ctx_va (bson_t *bson, bcon_extract_ctx_t *ctx, va_list *ap) { bcon_type_t type; const char *key; bson_iter_t root_iter; bson_iter_t current_iter; char i_str[16]; bcon_extract_t u = {0}; BSON_ASSERT (bson_iter_init (&root_iter, bson)); while (1) { if (STACK_IS_ARRAY) { bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); STACK_I++; } else { type = _bcon_extract_tokenize (ap, &u); if (type == BCON_TYPE_END) { return true; } if (type == BCON_TYPE_DOC_END) { STACK_POP_DOC (_noop ()); continue; } BSON_ASSERT (type == BCON_TYPE_RAW); key = u.key; } type = _bcon_extract_tokenize (ap, &u); BSON_ASSERT (type != BCON_TYPE_END); if (type == BCON_TYPE_DOC_END) { STACK_POP_DOC (_noop ()); } else if (type == BCON_TYPE_ARRAY_END) { STACK_POP_ARRAY (_noop ()); } else { memcpy (¤t_iter, STACK_ITER_CHILD, sizeof current_iter); if (!bson_iter_find (¤t_iter, key)) { return false; } switch ((int) type) { case BCON_TYPE_DOC_START: if (bson_iter_type (¤t_iter) != BSON_TYPE_DOCUMENT) { return false; } STACK_PUSH_DOC (bson_iter_recurse (¤t_iter, STACK_ITER_CHILD)); break; case BCON_TYPE_ARRAY_START: if (bson_iter_type (¤t_iter) != BSON_TYPE_ARRAY) { return false; } STACK_PUSH_ARRAY (bson_iter_recurse (¤t_iter, STACK_ITER_CHILD)); break; default: if (!_bcon_extract_single (¤t_iter, type, &u)) { return false; } break; } } } } void bcon_extract_ctx_init (bcon_extract_ctx_t *ctx) { ctx->n = 0; ctx->stack[0].is_array = false; } bool bcon_extract (bson_t *bson, ...) { va_list ap; bcon_extract_ctx_t ctx; bool r; bcon_extract_ctx_init (&ctx); va_start (ap, bson); r = bcon_extract_ctx_va (bson, &ctx, &ap); va_end (ap); return r; } void bcon_append (bson_t *bson, ...) { va_list ap; bcon_append_ctx_t ctx; bcon_append_ctx_init (&ctx); va_start (ap, bson); bcon_append_ctx_va (bson, &ctx, &ap); va_end (ap); } void bcon_append_ctx (bson_t *bson, bcon_append_ctx_t *ctx, ...) { va_list ap; va_start (ap, ctx); bcon_append_ctx_va (bson, ctx, &ap); va_end (ap); } void bcon_extract_ctx (bson_t *bson, bcon_extract_ctx_t *ctx, ...) { va_list ap; va_start (ap, ctx); bcon_extract_ctx_va (bson, ctx, &ap); va_end (ap); } void bcon_append_ctx_init (bcon_append_ctx_t *ctx) { ctx->n = 0; ctx->stack[0].is_array = 0; } bson_t * bcon_new (void *unused, ...) { va_list ap; bcon_append_ctx_t ctx; bson_t *bson; bcon_append_ctx_init (&ctx); bson = bson_new (); va_start (ap, unused); bcon_append_ctx_va (bson, &ctx, &ap); va_end (ap); return bson; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bcon.h0000644000175100001660000002443214760300420017743 0ustar /* * @file bcon.h * @brief BCON (BSON C Object Notation) Declarations */ #include /* Copyright 2009-present MongoDB, 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. */ #ifndef BCON_H_ #define BCON_H_ #include BSON_BEGIN_DECLS #define BCON_STACK_MAX 100 #define BCON_ENSURE_DECLARE(fun, type) \ static BSON_INLINE type bcon_ensure_##fun (type _t) \ { \ return _t; \ } #define BCON_ENSURE(fun, val) bcon_ensure_##fun (val) #define BCON_ENSURE_STORAGE(fun, val) bcon_ensure_##fun (&(val)) BCON_ENSURE_DECLARE (const_char_ptr, const char *) BCON_ENSURE_DECLARE (const_char_ptr_ptr, const char **) BCON_ENSURE_DECLARE (double, double) BCON_ENSURE_DECLARE (double_ptr, double *) BCON_ENSURE_DECLARE (const_bson_ptr, const bson_t *) BCON_ENSURE_DECLARE (bson_ptr, bson_t *) BCON_ENSURE_DECLARE (subtype, bson_subtype_t) BCON_ENSURE_DECLARE (subtype_ptr, bson_subtype_t *) BCON_ENSURE_DECLARE (const_uint8_ptr, const uint8_t *) BCON_ENSURE_DECLARE (const_uint8_ptr_ptr, const uint8_t **) BCON_ENSURE_DECLARE (uint32, uint32_t) BCON_ENSURE_DECLARE (uint32_ptr, uint32_t *) BCON_ENSURE_DECLARE (const_oid_ptr, const bson_oid_t *) BCON_ENSURE_DECLARE (const_oid_ptr_ptr, const bson_oid_t **) BCON_ENSURE_DECLARE (int32, int32_t) BCON_ENSURE_DECLARE (int32_ptr, int32_t *) BCON_ENSURE_DECLARE (int64, int64_t) BCON_ENSURE_DECLARE (int64_ptr, int64_t *) BCON_ENSURE_DECLARE (const_decimal128_ptr, const bson_decimal128_t *) BCON_ENSURE_DECLARE (bool, bool) BCON_ENSURE_DECLARE (bool_ptr, bool *) BCON_ENSURE_DECLARE (bson_type, bson_type_t) BCON_ENSURE_DECLARE (bson_iter_ptr, bson_iter_t *) BCON_ENSURE_DECLARE (const_bson_iter_ptr, const bson_iter_t *) #define BCON_UTF8(_val) BCON_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE (const_char_ptr, (_val)) #define BCON_DOUBLE(_val) BCON_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE (double, (_val)) #define BCON_DOCUMENT(_val) BCON_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE (const_bson_ptr, (_val)) #define BCON_ARRAY(_val) BCON_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE (const_bson_ptr, (_val)) #define BCON_BIN(_subtype, _binary, _length) \ BCON_MAGIC, BCON_TYPE_BIN, BCON_ENSURE (subtype, (_subtype)), BCON_ENSURE (const_uint8_ptr, (_binary)), \ BCON_ENSURE (uint32, (_length)) #define BCON_UNDEFINED BCON_MAGIC, BCON_TYPE_UNDEFINED #define BCON_OID(_val) BCON_MAGIC, BCON_TYPE_OID, BCON_ENSURE (const_oid_ptr, (_val)) #define BCON_BOOL(_val) BCON_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE (bool, (_val)) #define BCON_DATE_TIME(_val) BCON_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE (int64, (_val)) #define BCON_NULL BCON_MAGIC, BCON_TYPE_NULL #define BCON_REGEX(_regex, _flags) \ BCON_MAGIC, BCON_TYPE_REGEX, BCON_ENSURE (const_char_ptr, (_regex)), BCON_ENSURE (const_char_ptr, (_flags)) #define BCON_DBPOINTER(_collection, _oid) \ BCON_MAGIC, BCON_TYPE_DBPOINTER, BCON_ENSURE (const_char_ptr, (_collection)), BCON_ENSURE (const_oid_ptr, (_oid)) #define BCON_CODE(_val) BCON_MAGIC, BCON_TYPE_CODE, BCON_ENSURE (const_char_ptr, (_val)) #define BCON_SYMBOL(_val) BCON_MAGIC, BCON_TYPE_SYMBOL, BCON_ENSURE (const_char_ptr, (_val)) #define BCON_CODEWSCOPE(_js, _scope) \ BCON_MAGIC, BCON_TYPE_CODEWSCOPE, BCON_ENSURE (const_char_ptr, (_js)), BCON_ENSURE (const_bson_ptr, (_scope)) #define BCON_INT32(_val) BCON_MAGIC, BCON_TYPE_INT32, BCON_ENSURE (int32, (_val)) #define BCON_TIMESTAMP(_timestamp, _increment) \ BCON_MAGIC, BCON_TYPE_TIMESTAMP, BCON_ENSURE (int32, (_timestamp)), BCON_ENSURE (int32, (_increment)) #define BCON_INT64(_val) BCON_MAGIC, BCON_TYPE_INT64, BCON_ENSURE (int64, (_val)) #define BCON_DECIMAL128(_val) BCON_MAGIC, BCON_TYPE_DECIMAL128, BCON_ENSURE (const_decimal128_ptr, (_val)) #define BCON_MAXKEY BCON_MAGIC, BCON_TYPE_MAXKEY #define BCON_MINKEY BCON_MAGIC, BCON_TYPE_MINKEY #define BCON(_val) BCON_MAGIC, BCON_TYPE_BCON, BCON_ENSURE (const_bson_ptr, (_val)) #define BCON_ITER(_val) BCON_MAGIC, BCON_TYPE_ITER, BCON_ENSURE (const_bson_iter_ptr, (_val)) #define BCONE_UTF8(_val) BCONE_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) #define BCONE_DOUBLE(_val) BCONE_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE_STORAGE (double_ptr, (_val)) #define BCONE_DOCUMENT(_val) BCONE_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE_STORAGE (bson_ptr, (_val)) #define BCONE_ARRAY(_val) BCONE_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE_STORAGE (bson_ptr, (_val)) #define BCONE_BIN(subtype, binary, length) \ BCONE_MAGIC, BCON_TYPE_BIN, BCON_ENSURE_STORAGE (subtype_ptr, (subtype)), \ BCON_ENSURE_STORAGE (const_uint8_ptr_ptr, (binary)), BCON_ENSURE_STORAGE (uint32_ptr, (length)) #define BCONE_UNDEFINED BCONE_MAGIC, BCON_TYPE_UNDEFINED #define BCONE_OID(_val) BCONE_MAGIC, BCON_TYPE_OID, BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_val)) #define BCONE_BOOL(_val) BCONE_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE_STORAGE (bool_ptr, (_val)) #define BCONE_DATE_TIME(_val) BCONE_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE_STORAGE (int64_ptr, (_val)) #define BCONE_NULL BCONE_MAGIC, BCON_TYPE_NULL #define BCONE_REGEX(_regex, _flags) \ BCONE_MAGIC, BCON_TYPE_REGEX, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_regex)), \ BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_flags)) #define BCONE_DBPOINTER(_collection, _oid) \ BCONE_MAGIC, BCON_TYPE_DBPOINTER, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_collection)), \ BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_oid)) #define BCONE_CODE(_val) BCONE_MAGIC, BCON_TYPE_CODE, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) #define BCONE_SYMBOL(_val) BCONE_MAGIC, BCON_TYPE_SYMBOL, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) #define BCONE_CODEWSCOPE(_js, _scope) \ BCONE_MAGIC, BCON_TYPE_CODEWSCOPE, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_js)), \ BCON_ENSURE_STORAGE (bson_ptr, (_scope)) #define BCONE_INT32(_val) BCONE_MAGIC, BCON_TYPE_INT32, BCON_ENSURE_STORAGE (int32_ptr, (_val)) #define BCONE_TIMESTAMP(_timestamp, _increment) \ BCONE_MAGIC, BCON_TYPE_TIMESTAMP, BCON_ENSURE_STORAGE (int32_ptr, (_timestamp)), \ BCON_ENSURE_STORAGE (int32_ptr, (_increment)) #define BCONE_INT64(_val) BCONE_MAGIC, BCON_TYPE_INT64, BCON_ENSURE_STORAGE (int64_ptr, (_val)) #define BCONE_DECIMAL128(_val) BCONE_MAGIC, BCON_TYPE_DECIMAL128, BCON_ENSURE_STORAGE (const_decimal128_ptr, (_val)) #define BCONE_MAXKEY BCONE_MAGIC, BCON_TYPE_MAXKEY #define BCONE_MINKEY BCONE_MAGIC, BCON_TYPE_MINKEY #define BCONE_SKIP(_val) BCONE_MAGIC, BCON_TYPE_SKIP, BCON_ENSURE (bson_type, (_val)) #define BCONE_ITER(_val) BCONE_MAGIC, BCON_TYPE_ITER, BCON_ENSURE_STORAGE (bson_iter_ptr, (_val)) #define BCON_MAGIC bson_bcon_magic () #define BCONE_MAGIC bson_bcone_magic () typedef enum { BCON_TYPE_UTF8, BCON_TYPE_DOUBLE, BCON_TYPE_DOCUMENT, BCON_TYPE_ARRAY, BCON_TYPE_BIN, BCON_TYPE_UNDEFINED, BCON_TYPE_OID, BCON_TYPE_BOOL, BCON_TYPE_DATE_TIME, BCON_TYPE_NULL, BCON_TYPE_REGEX, BCON_TYPE_DBPOINTER, BCON_TYPE_CODE, BCON_TYPE_SYMBOL, BCON_TYPE_CODEWSCOPE, BCON_TYPE_INT32, BCON_TYPE_TIMESTAMP, BCON_TYPE_INT64, BCON_TYPE_DECIMAL128, BCON_TYPE_MAXKEY, BCON_TYPE_MINKEY, BCON_TYPE_BCON, BCON_TYPE_ARRAY_START, BCON_TYPE_ARRAY_END, BCON_TYPE_DOC_START, BCON_TYPE_DOC_END, BCON_TYPE_END, BCON_TYPE_RAW, BCON_TYPE_SKIP, BCON_TYPE_ITER, BCON_TYPE_ERROR, } bcon_type_t; typedef struct bcon_append_ctx_frame { int i; bool is_array; bson_t bson; } bcon_append_ctx_frame_t; typedef struct bcon_extract_ctx_frame { int i; bool is_array; bson_iter_t iter; } bcon_extract_ctx_frame_t; typedef struct _bcon_append_ctx_t { bcon_append_ctx_frame_t stack[BCON_STACK_MAX]; int n; } bcon_append_ctx_t; typedef struct _bcon_extract_ctx_t { bcon_extract_ctx_frame_t stack[BCON_STACK_MAX]; int n; } bcon_extract_ctx_t; BSON_EXPORT (void) bcon_append (bson_t *bson, ...) BSON_GNUC_NULL_TERMINATED; BSON_EXPORT (void) bcon_append_ctx (bson_t *bson, bcon_append_ctx_t *ctx, ...) BSON_GNUC_NULL_TERMINATED; BSON_EXPORT (void) bcon_append_ctx_va (bson_t *bson, bcon_append_ctx_t *ctx, va_list *va); BSON_EXPORT (void) bcon_append_ctx_init (bcon_append_ctx_t *ctx); BSON_EXPORT (void) bcon_extract_ctx_init (bcon_extract_ctx_t *ctx); BSON_EXPORT (void) bcon_extract_ctx (bson_t *bson, bcon_extract_ctx_t *ctx, ...) BSON_GNUC_NULL_TERMINATED; BSON_EXPORT (bool) bcon_extract_ctx_va (bson_t *bson, bcon_extract_ctx_t *ctx, va_list *ap); BSON_EXPORT (bool) bcon_extract (bson_t *bson, ...) BSON_GNUC_NULL_TERMINATED; BSON_EXPORT (bool) bcon_extract_va (bson_t *bson, bcon_extract_ctx_t *ctx, ...) BSON_GNUC_NULL_TERMINATED; BSON_EXPORT (bson_t *) bcon_new (void *unused, ...) BSON_GNUC_NULL_TERMINATED; /** * The bcon_..() functions are all declared with __attribute__((sentinel)). * * From GCC manual for "sentinel": "A valid NULL in this context is defined as * zero with any pointer type. If your system defines the NULL macro with an * integer type then you need to add an explicit cast." * Case in point: GCC on Solaris (at least) */ #define BCON_APPEND(_bson, ...) bcon_append ((_bson), __VA_ARGS__, (void *) NULL) #define BCON_APPEND_CTX(_bson, _ctx, ...) bcon_append_ctx ((_bson), (_ctx), __VA_ARGS__, (void *) NULL) #define BCON_EXTRACT(_bson, ...) bcon_extract ((_bson), __VA_ARGS__, (void *) NULL) #define BCON_EXTRACT_CTX(_bson, _ctx, ...) bcon_extract ((_bson), (_ctx), __VA_ARGS__, (void *) NULL) #define BCON_NEW(...) bcon_new (NULL, __VA_ARGS__, (void *) NULL) BSON_EXPORT (const char *) bson_bcon_magic (void) BSON_GNUC_PURE; BSON_EXPORT (const char *) bson_bcone_magic (void) BSON_GNUC_PURE; BSON_END_DECLS #endif mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-atomic.c0000644000175100001660000001521014760300420021222 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include BEGIN_IGNORE_DEPRECATIONS #ifdef BSON_OS_UNIX /* For sched_yield() */ #include #endif int32_t bson_atomic_int_add (volatile int32_t *p, int32_t n) { return n + bson_atomic_int32_fetch_add ((DECL_ATOMIC_INTEGRAL_INT32 *) p, n, bson_memory_order_seq_cst); } int64_t bson_atomic_int64_add (volatile int64_t *p, int64_t n) { return n + bson_atomic_int64_fetch_add (p, n, bson_memory_order_seq_cst); } void bson_thrd_yield (void) { BSON_IF_WINDOWS (SwitchToThread ();) BSON_IF_POSIX (sched_yield ();) } void bson_memory_barrier (void) { bson_atomic_thread_fence (); } /** * Some platforms do not support compiler intrinsics for atomic operations. * We emulate that here using a spin lock and regular arithmetic operations */ static int8_t gEmulAtomicLock = 0; static void _lock_emul_atomic (void) { int i; if (bson_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, bson_memory_order_acquire) == 0) { /* Successfully took the spinlock */ return; } /* Failed. Try taking ten more times, then begin sleeping. */ for (i = 0; i < 10; ++i) { if (bson_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, bson_memory_order_acquire) == 0) { /* Succeeded in taking the lock */ return; } } /* Still don't have the lock. Spin and yield */ while (bson_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, bson_memory_order_acquire) != 0) { bson_thrd_yield (); } } static void _unlock_emul_atomic (void) { int64_t rv = bson_atomic_int8_exchange (&gEmulAtomicLock, 0, bson_memory_order_release); BSON_ASSERT (rv == 1 && "Released atomic lock while not holding it"); } int64_t _bson_emul_atomic_int64_fetch_add (volatile int64_t *p, int64_t n, enum bson_memory_order _unused) { int64_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p += n; _unlock_emul_atomic (); return ret; } int64_t _bson_emul_atomic_int64_exchange (volatile int64_t *p, int64_t n, enum bson_memory_order _unused) { int64_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p = n; _unlock_emul_atomic (); return ret; } int64_t _bson_emul_atomic_int64_compare_exchange_strong (volatile int64_t *p, int64_t expect_value, int64_t new_value, enum bson_memory_order _unused) { int64_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; if (ret == expect_value) { *p = new_value; } _unlock_emul_atomic (); return ret; } int64_t _bson_emul_atomic_int64_compare_exchange_weak (volatile int64_t *p, int64_t expect_value, int64_t new_value, enum bson_memory_order order) { /* We're emulating. We can't do a weak version. */ return _bson_emul_atomic_int64_compare_exchange_strong (p, expect_value, new_value, order); } int32_t _bson_emul_atomic_int32_fetch_add (volatile int32_t *p, int32_t n, enum bson_memory_order _unused) { int32_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p += n; _unlock_emul_atomic (); return ret; } int32_t _bson_emul_atomic_int32_exchange (volatile int32_t *p, int32_t n, enum bson_memory_order _unused) { int32_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p = n; _unlock_emul_atomic (); return ret; } int32_t _bson_emul_atomic_int32_compare_exchange_strong (volatile int32_t *p, int32_t expect_value, int32_t new_value, enum bson_memory_order _unused) { int32_t ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; if (ret == expect_value) { *p = new_value; } _unlock_emul_atomic (); return ret; } int32_t _bson_emul_atomic_int32_compare_exchange_weak (volatile int32_t *p, int32_t expect_value, int32_t new_value, enum bson_memory_order order) { /* We're emulating. We can't do a weak version. */ return _bson_emul_atomic_int32_compare_exchange_strong (p, expect_value, new_value, order); } int _bson_emul_atomic_int_fetch_add (volatile int *p, int n, enum bson_memory_order _unused) { int ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p += n; _unlock_emul_atomic (); return ret; } int _bson_emul_atomic_int_exchange (volatile int *p, int n, enum bson_memory_order _unused) { int ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p = n; _unlock_emul_atomic (); return ret; } int _bson_emul_atomic_int_compare_exchange_strong (volatile int *p, int expect_value, int new_value, enum bson_memory_order _unused) { int ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; if (ret == expect_value) { *p = new_value; } _unlock_emul_atomic (); return ret; } int _bson_emul_atomic_int_compare_exchange_weak (volatile int *p, int expect_value, int new_value, enum bson_memory_order order) { /* We're emulating. We can't do a weak version. */ return _bson_emul_atomic_int_compare_exchange_strong (p, expect_value, new_value, order); } void * _bson_emul_atomic_ptr_exchange (void *volatile *p, void *n, enum bson_memory_order _unused) { void *ret; BSON_UNUSED (_unused); _lock_emul_atomic (); ret = *p; *p = n; _unlock_emul_atomic (); return ret; } END_IGNORE_DEPRECATIONS mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-atomic.h0000644000175100001660000011431014760300420021230 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_ATOMIC_H #define BSON_ATOMIC_H #include #include #include #ifdef _MSC_VER #include #endif // bson-atomic.h is deprecated. // Ignore deprecation warnings for function calls within this file. #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #define BSON_BEGIN_IGNORE_DEPRECATIONS \ _Pragma ("GCC diagnostic push") _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #define BSON_END_IGNORE_DEPRECATIONS _Pragma ("GCC diagnostic pop") #elif defined(__clang__) #define BSON_BEGIN_IGNORE_DEPRECATIONS \ _Pragma ("clang diagnostic push") _Pragma ("clang diagnostic ignored \"-Wdeprecated-declarations\"") #define BSON_END_IGNORE_DEPRECATIONS _Pragma ("clang diagnostic pop") #else #define BSON_BEGIN_IGNORE_DEPRECATIONS #define BSON_END_IGNORE_DEPRECATIONS #endif BSON_BEGIN_IGNORE_DEPRECATIONS BSON_BEGIN_DECLS enum BSON_GNUC_DEPRECATED bson_memory_order { bson_memory_order_seq_cst, bson_memory_order_acquire, bson_memory_order_release, bson_memory_order_relaxed, bson_memory_order_acq_rel, bson_memory_order_consume, }; #if defined(_M_ARM) /* MSVC memorder atomics are only avail on ARM */ #define MSVC_MEMORDER_SUFFIX(X) X #else #define MSVC_MEMORDER_SUFFIX(X) #endif #if defined(USE_LEGACY_GCC_ATOMICS) || (!defined(__clang__) && __GNUC__ == 4) || defined(__xlC__) #define BSON_USE_LEGACY_GCC_ATOMICS #else #undef BSON_USE_LEGACY_GCC_ATOMICS #endif /* Not all GCC-like compilers support the current __atomic built-ins. Older * GCC (pre-5) used different built-ins named with the __sync prefix. When * compiling with such older GCC versions, it is necessary to use the applicable * functions, which requires redefining BSON_IF_GNU_LIKE and defining the * additional BSON_IF_GNU_LEGACY_ATOMICS macro here. */ #ifdef BSON_USE_LEGACY_GCC_ATOMICS #undef BSON_IF_GNU_LIKE #define BSON_IF_GNU_LIKE(...) #define BSON_IF_GNU_LEGACY_ATOMICS(...) __VA_ARGS__ #else #define BSON_IF_GNU_LEGACY_ATOMICS(...) #endif /* CDRIVER-4229 zSeries with gcc 4.8.4 produces illegal instructions for int and * int32 atomic intrinsics. */ #if defined(__s390__) || defined(__s390x__) || defined(__zarch__) #define BSON_EMULATE_INT32 #define BSON_EMULATE_INT #endif /* CDRIVER-4264 Contrary to documentation, VS 2013 targeting x86 does not * correctly/consistently provide _InterlockedPointerExchange. */ #if defined(_MSC_VER) && _MSC_VER < 1900 && defined(_M_IX86) #define BSON_EMULATE_PTR #endif // Disable the -Wcovered-switch-default warning. #define BSON_DISABLE_COVERED_SWITCH_DEFAULT_BEGIN #define BSON_DISABLE_COVERED_SWITCH_DEFAULT_END #if defined(__clang__) #if __has_warning("-Wcovered-switch-default") #undef BSON_DISABLE_COVERED_SWITCH_DEFAULT_BEGIN #undef BSON_DISABLE_COVERED_SWITCH_DEFAULT_END #define BSON_DISABLE_COVERED_SWITCH_DEFAULT_BEGIN \ _Pragma ("clang diagnostic push") _Pragma ("clang diagnostic ignored \"-Wcovered-switch-default\"") #define BSON_DISABLE_COVERED_SWITCH_DEFAULT_END _Pragma ("clang diagnostic pop") #endif // __has_warning("-Wcovered-switch-default") #endif // defined(__clang__) // Disable the -Watomic-implicit-seq-cst warning. #define BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_BEGIN #define BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_END #if defined(__clang__) #if __has_warning("-Watomic-implicit-seq-cst") #undef BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_BEGIN #undef BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_END #define BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_BEGIN \ _Pragma ("clang diagnostic push") _Pragma ("clang diagnostic ignored \"-Watomic-implicit-seq-cst\"") #define BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_END _Pragma ("clang diagnostic pop") #endif // __has_warning("-Watomic-implicit-seq-cst") #endif // defined(__clang__) BSON_DISABLE_COVERED_SWITCH_DEFAULT_BEGIN #define DEF_ATOMIC_OP(MSVC_Intrinsic, GNU_Intrinsic, GNU_Legacy_Intrinsic, Order, ...) \ do { \ switch (Order) { \ case bson_memory_order_acq_rel: \ BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQ_REL);) \ BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case bson_memory_order_seq_cst: \ BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_SEQ_CST);) \ BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case bson_memory_order_acquire: \ BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQUIRE);) \ BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case bson_memory_order_consume: \ BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_CONSUME);) \ BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case bson_memory_order_release: \ BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_rel)) (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELEASE);) \ BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ case bson_memory_order_relaxed: \ BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_nf)) (__VA_ARGS__);) \ BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELAXED);) \ BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ default: \ BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ } \ } while (0) #define DEF_ATOMIC_CMPEXCH_STRONG(VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue) \ do { \ BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 (_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \ Ptr, NewValue, ExpectActualVar);) \ BSON_IF_GNU_LIKE ((void) __atomic_compare_exchange_n (Ptr, \ &ExpectActualVar, \ NewValue, \ false, /* Not weak */ \ GNU_MemOrder, \ GNU_MemOrder);) \ BSON_IF_GNU_LEGACY_ATOMICS (__typeof__ (ExpectActualVar) _val; \ _val = __sync_val_compare_and_swap (Ptr, ExpectActualVar, NewValue); \ ExpectActualVar = _val;) \ } while (0) #define DEF_ATOMIC_CMPEXCH_WEAK(VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue) \ do { \ BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 (_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \ Ptr, NewValue, ExpectActualVar);) \ BSON_IF_GNU_LIKE ((void) __atomic_compare_exchange_n (Ptr, \ &ExpectActualVar, \ NewValue, \ true, /* Yes weak */ \ GNU_MemOrder, \ GNU_MemOrder);) \ BSON_IF_GNU_LEGACY_ATOMICS (__typeof__ (ExpectActualVar) _val; \ _val = __sync_val_compare_and_swap (Ptr, ExpectActualVar, NewValue); \ ExpectActualVar = _val;) \ } while (0) #define DECL_ATOMIC_INTEGRAL(NamePart, Type, VCIntrinSuffix) \ static BSON_INLINE Type BSON_GNUC_DEPRECATED bson_atomic_##NamePart##_fetch_add ( \ Type volatile *a, Type addend, enum bson_memory_order ord) \ { \ DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchangeAdd, VCIntrinSuffix), \ __atomic_fetch_add, \ __sync_fetch_and_add, \ ord, \ a, \ addend); \ } \ \ static BSON_INLINE Type BSON_GNUC_DEPRECATED bson_atomic_##NamePart##_fetch_sub ( \ Type volatile *a, Type subtrahend, enum bson_memory_order ord) \ { \ /* MSVC doesn't have a subtract intrinsic, so just reuse addition */ \ BSON_IF_MSVC (return bson_atomic_##NamePart##_fetch_add (a, -subtrahend, ord);) \ BSON_IF_GNU_LIKE (DEF_ATOMIC_OP (~, __atomic_fetch_sub, ~, ord, a, subtrahend);) \ BSON_IF_GNU_LEGACY_ATOMICS (DEF_ATOMIC_OP (~, ~, __sync_fetch_and_sub, ord, a, subtrahend);) \ } \ \ static BSON_INLINE Type BSON_GNUC_DEPRECATED bson_atomic_##NamePart##_fetch (Type volatile const *a, \ enum bson_memory_order order) \ { \ /* MSVC doesn't have a load intrinsic, so just add zero */ \ BSON_IF_MSVC (return bson_atomic_##NamePart##_fetch_add ((Type volatile *) a, 0, order);) \ /* GNU doesn't want RELEASE order for the fetch operation, so we can't \ * just use DEF_ATOMIC_OP. */ \ BSON_IF_GNU_LIKE (switch (order) { \ case bson_memory_order_release: /* Fall back to seqcst */ \ case bson_memory_order_acq_rel: /* Fall back to seqcst */ \ case bson_memory_order_seq_cst: \ return __atomic_load_n (a, __ATOMIC_SEQ_CST); \ case bson_memory_order_acquire: \ return __atomic_load_n (a, __ATOMIC_ACQUIRE); \ case bson_memory_order_consume: \ return __atomic_load_n (a, __ATOMIC_CONSUME); \ case bson_memory_order_relaxed: \ return __atomic_load_n (a, __ATOMIC_RELAXED); \ default: \ BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ }) \ BSON_IF_GNU_LEGACY_ATOMICS ({ \ BSON_UNUSED (order); \ __sync_synchronize (); \ return *a; \ }) \ } \ \ static BSON_INLINE Type BSON_GNUC_DEPRECATED bson_atomic_##NamePart##_exchange ( \ Type volatile *a, Type value, enum bson_memory_order ord) \ { \ BSON_IF_MSVC (DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchange, VCIntrinSuffix), ~, ~, ord, a, value);) \ /* GNU doesn't want CONSUME order for the exchange operation, so we \ * cannot use DEF_ATOMIC_OP. */ \ BSON_IF_GNU_LIKE (switch (ord) { \ case bson_memory_order_acq_rel: \ return __atomic_exchange_n (a, value, __ATOMIC_ACQ_REL); \ case bson_memory_order_release: \ return __atomic_exchange_n (a, value, __ATOMIC_RELEASE); \ case bson_memory_order_seq_cst: \ return __atomic_exchange_n (a, value, __ATOMIC_SEQ_CST); \ case bson_memory_order_consume: /* Fall back to acquire */ \ case bson_memory_order_acquire: \ return __atomic_exchange_n (a, value, __ATOMIC_ACQUIRE); \ case bson_memory_order_relaxed: \ return __atomic_exchange_n (a, value, __ATOMIC_RELAXED); \ default: \ BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ }) \ BSON_IF_GNU_LEGACY_ATOMICS (BSON_UNUSED (ord); return __sync_val_compare_and_swap (a, *a, value);) \ } \ \ static BSON_INLINE Type BSON_GNUC_DEPRECATED bson_atomic_##NamePart##_compare_exchange_strong ( \ Type volatile *a, Type expect, Type new_value, enum bson_memory_order ord) \ { \ Type actual = expect; \ switch (ord) { \ case bson_memory_order_release: \ case bson_memory_order_acq_rel: \ case bson_memory_order_seq_cst: \ DEF_ATOMIC_CMPEXCH_STRONG (VCIntrinSuffix, , __ATOMIC_SEQ_CST, a, actual, new_value); \ break; \ case bson_memory_order_acquire: \ DEF_ATOMIC_CMPEXCH_STRONG ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, a, actual, new_value); \ break; \ case bson_memory_order_consume: \ DEF_ATOMIC_CMPEXCH_STRONG ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, a, actual, new_value); \ break; \ case bson_memory_order_relaxed: \ DEF_ATOMIC_CMPEXCH_STRONG ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, a, actual, new_value); \ break; \ default: \ BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ } \ return actual; \ } \ \ static BSON_INLINE Type BSON_GNUC_DEPRECATED bson_atomic_##NamePart##_compare_exchange_weak ( \ Type volatile *a, Type expect, Type new_value, enum bson_memory_order ord) \ { \ Type actual = expect; \ switch (ord) { \ case bson_memory_order_release: \ case bson_memory_order_acq_rel: \ case bson_memory_order_seq_cst: \ DEF_ATOMIC_CMPEXCH_WEAK (VCIntrinSuffix, , __ATOMIC_SEQ_CST, a, actual, new_value); \ break; \ case bson_memory_order_acquire: \ DEF_ATOMIC_CMPEXCH_WEAK ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, a, actual, new_value); \ break; \ case bson_memory_order_consume: \ DEF_ATOMIC_CMPEXCH_WEAK ( \ VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, a, actual, new_value); \ break; \ case bson_memory_order_relaxed: \ DEF_ATOMIC_CMPEXCH_WEAK (VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, a, actual, new_value); \ break; \ default: \ BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ } \ return actual; \ } #define DECL_ATOMIC_STDINT(Name, VCSuffix) DECL_ATOMIC_INTEGRAL (Name, Name##_t, VCSuffix) #if defined(_MSC_VER) || defined(BSON_USE_LEGACY_GCC_ATOMICS) /* MSVC and GCC require built-in types (not typedefs) for their atomic * intrinsics. */ #if defined(_MSC_VER) #define DECL_ATOMIC_INTEGRAL_INT8 char #define DECL_ATOMIC_INTEGRAL_INT32 long #define DECL_ATOMIC_INTEGRAL_INT long #else #define DECL_ATOMIC_INTEGRAL_INT8 signed char #define DECL_ATOMIC_INTEGRAL_INT32 int #define DECL_ATOMIC_INTEGRAL_INT int #endif DECL_ATOMIC_INTEGRAL (int8, DECL_ATOMIC_INTEGRAL_INT8, 8) DECL_ATOMIC_INTEGRAL (int16, short, 16) #if !defined(BSON_EMULATE_INT32) DECL_ATOMIC_INTEGRAL (int32, DECL_ATOMIC_INTEGRAL_INT32, ) #endif #if !defined(BSON_EMULATE_INT) DECL_ATOMIC_INTEGRAL (int, DECL_ATOMIC_INTEGRAL_INT, ) #endif #else /* Other compilers that we support provide generic intrinsics */ DECL_ATOMIC_STDINT (int8, 8) DECL_ATOMIC_STDINT (int16, 16) #if !defined(BSON_EMULATE_INT32) DECL_ATOMIC_STDINT (int32, ) #endif #if !defined(BSON_EMULATE_INT) DECL_ATOMIC_INTEGRAL (int, int, ) #endif #endif #ifndef DECL_ATOMIC_INTEGRAL_INT32 #define DECL_ATOMIC_INTEGRAL_INT32 int32_t #endif BSON_EXPORT (int64_t) _bson_emul_atomic_int64_fetch_add (int64_t volatile *val, int64_t v, enum bson_memory_order); BSON_EXPORT (int64_t) _bson_emul_atomic_int64_exchange (int64_t volatile *val, int64_t v, enum bson_memory_order); BSON_EXPORT (int64_t) _bson_emul_atomic_int64_compare_exchange_strong (int64_t volatile *val, int64_t expect_value, int64_t new_value, enum bson_memory_order); BSON_EXPORT (int64_t) _bson_emul_atomic_int64_compare_exchange_weak (int64_t volatile *val, int64_t expect_value, int64_t new_value, enum bson_memory_order); BSON_EXPORT (int32_t) _bson_emul_atomic_int32_fetch_add (int32_t volatile *val, int32_t v, enum bson_memory_order); BSON_EXPORT (int32_t) _bson_emul_atomic_int32_exchange (int32_t volatile *val, int32_t v, enum bson_memory_order); BSON_EXPORT (int32_t) _bson_emul_atomic_int32_compare_exchange_strong (int32_t volatile *val, int32_t expect_value, int32_t new_value, enum bson_memory_order); BSON_EXPORT (int32_t) _bson_emul_atomic_int32_compare_exchange_weak (int32_t volatile *val, int32_t expect_value, int32_t new_value, enum bson_memory_order); BSON_EXPORT (int) _bson_emul_atomic_int_fetch_add (int volatile *val, int v, enum bson_memory_order); BSON_EXPORT (int) _bson_emul_atomic_int_exchange (int volatile *val, int v, enum bson_memory_order); BSON_EXPORT (int) _bson_emul_atomic_int_compare_exchange_strong (int volatile *val, int expect_value, int new_value, enum bson_memory_order); BSON_EXPORT (int) _bson_emul_atomic_int_compare_exchange_weak (int volatile *val, int expect_value, int new_value, enum bson_memory_order); BSON_EXPORT (void *) _bson_emul_atomic_ptr_exchange (void *volatile *val, void *v, enum bson_memory_order); BSON_EXPORT (void) bson_thrd_yield (void); #if (defined(_MSC_VER) && !defined(_M_IX86)) || (defined(__LP64__) && __LP64__) /* (64-bit intrinsics are only available in x64) */ #ifdef _MSC_VER DECL_ATOMIC_INTEGRAL (int64, __int64, 64) #else DECL_ATOMIC_STDINT (int64, 64) #endif #else static BSON_INLINE int64_t BSON_GNUC_DEPRECATED bson_atomic_int64_fetch (const int64_t volatile *val, enum bson_memory_order order) { return _bson_emul_atomic_int64_fetch_add ((int64_t volatile *) val, 0, order); } static BSON_INLINE int64_t BSON_GNUC_DEPRECATED bson_atomic_int64_fetch_add (int64_t volatile *val, int64_t v, enum bson_memory_order order) { return _bson_emul_atomic_int64_fetch_add (val, v, order); } static BSON_INLINE int64_t BSON_GNUC_DEPRECATED bson_atomic_int64_fetch_sub (int64_t volatile *val, int64_t v, enum bson_memory_order order) { return _bson_emul_atomic_int64_fetch_add (val, -v, order); } static BSON_INLINE int64_t BSON_GNUC_DEPRECATED bson_atomic_int64_exchange (int64_t volatile *val, int64_t v, enum bson_memory_order order) { return _bson_emul_atomic_int64_exchange (val, v, order); } static BSON_INLINE int64_t BSON_GNUC_DEPRECATED bson_atomic_int64_compare_exchange_strong (int64_t volatile *val, int64_t expect_value, int64_t new_value, enum bson_memory_order order) { return _bson_emul_atomic_int64_compare_exchange_strong (val, expect_value, new_value, order); } static BSON_INLINE int64_t BSON_GNUC_DEPRECATED bson_atomic_int64_compare_exchange_weak (int64_t volatile *val, int64_t expect_value, int64_t new_value, enum bson_memory_order order) { return _bson_emul_atomic_int64_compare_exchange_weak (val, expect_value, new_value, order); } #endif #if defined(BSON_EMULATE_INT32) static BSON_INLINE int32_t BSON_GNUC_DEPRECATED bson_atomic_int32_fetch (const int32_t volatile *val, enum bson_memory_order order) { return _bson_emul_atomic_int32_fetch_add ((int32_t volatile *) val, 0, order); } static BSON_INLINE int32_t BSON_GNUC_DEPRECATED bson_atomic_int32_fetch_add (int32_t volatile *val, int32_t v, enum bson_memory_order order) { return _bson_emul_atomic_int32_fetch_add (val, v, order); } static BSON_INLINE int32_t BSON_GNUC_DEPRECATED bson_atomic_int32_fetch_sub (int32_t volatile *val, int32_t v, enum bson_memory_order order) { return _bson_emul_atomic_int32_fetch_add (val, -v, order); } static BSON_INLINE int32_t BSON_GNUC_DEPRECATED bson_atomic_int32_exchange (int32_t volatile *val, int32_t v, enum bson_memory_order order) { return _bson_emul_atomic_int32_exchange (val, v, order); } static BSON_INLINE int32_t BSON_GNUC_DEPRECATED bson_atomic_int32_compare_exchange_strong (int32_t volatile *val, int32_t expect_value, int32_t new_value, enum bson_memory_order order) { return _bson_emul_atomic_int32_compare_exchange_strong (val, expect_value, new_value, order); } static BSON_INLINE int32_t BSON_GNUC_DEPRECATED bson_atomic_int32_compare_exchange_weak (int32_t volatile *val, int32_t expect_value, int32_t new_value, enum bson_memory_order order) { return _bson_emul_atomic_int32_compare_exchange_weak (val, expect_value, new_value, order); } #endif /* BSON_EMULATE_INT32 */ #if defined(BSON_EMULATE_INT) static BSON_INLINE int BSON_GNUC_DEPRECATED bson_atomic_int_fetch (const int volatile *val, enum bson_memory_order order) { return _bson_emul_atomic_int_fetch_add ((int volatile *) val, 0, order); } static BSON_INLINE int BSON_GNUC_DEPRECATED bson_atomic_int_fetch_add (int volatile *val, int v, enum bson_memory_order order) { return _bson_emul_atomic_int_fetch_add (val, v, order); } static BSON_INLINE int BSON_GNUC_DEPRECATED bson_atomic_int_fetch_sub (int volatile *val, int v, enum bson_memory_order order) { return _bson_emul_atomic_int_fetch_add (val, -v, order); } static BSON_INLINE int BSON_GNUC_DEPRECATED bson_atomic_int_exchange (int volatile *val, int v, enum bson_memory_order order) { return _bson_emul_atomic_int_exchange (val, v, order); } static BSON_INLINE int BSON_GNUC_DEPRECATED bson_atomic_int_compare_exchange_strong (int volatile *val, int expect_value, int new_value, enum bson_memory_order order) { return _bson_emul_atomic_int_compare_exchange_strong (val, expect_value, new_value, order); } static BSON_INLINE int BSON_GNUC_DEPRECATED bson_atomic_int_compare_exchange_weak (int volatile *val, int expect_value, int new_value, enum bson_memory_order order) { return _bson_emul_atomic_int_compare_exchange_weak (val, expect_value, new_value, order); } #endif /* BSON_EMULATE_INT */ static BSON_INLINE void *BSON_GNUC_DEPRECATED bson_atomic_ptr_exchange (void *volatile *ptr, void *new_value, enum bson_memory_order ord) { #if defined(BSON_EMULATE_PTR) return _bson_emul_atomic_ptr_exchange (ptr, new_value, ord); #elif defined(BSON_USE_LEGACY_GCC_ATOMICS) /* The older __sync_val_compare_and_swap also takes oldval */ DEF_ATOMIC_OP (_InterlockedExchangePointer, , __sync_val_compare_and_swap, ord, ptr, *ptr, new_value); #else DEF_ATOMIC_OP (_InterlockedExchangePointer, __atomic_exchange_n, , ord, ptr, new_value); #endif } static BSON_INLINE void *BSON_GNUC_DEPRECATED bson_atomic_ptr_compare_exchange_strong (void *volatile *ptr, void *expect, void *new_value, enum bson_memory_order ord) { switch (ord) { case bson_memory_order_release: case bson_memory_order_acq_rel: case bson_memory_order_seq_cst: DEF_ATOMIC_CMPEXCH_STRONG (Pointer, , __ATOMIC_SEQ_CST, ptr, expect, new_value); return expect; case bson_memory_order_relaxed: DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, ptr, expect, new_value); return expect; case bson_memory_order_consume: DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, ptr, expect, new_value); return expect; case bson_memory_order_acquire: DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, ptr, expect, new_value); return expect; default: BSON_UNREACHABLE ("Invalid bson_memory_order value"); } } static BSON_INLINE void *BSON_GNUC_DEPRECATED bson_atomic_ptr_compare_exchange_weak (void *volatile *ptr, void *expect, void *new_value, enum bson_memory_order ord) { switch (ord) { case bson_memory_order_release: case bson_memory_order_acq_rel: case bson_memory_order_seq_cst: DEF_ATOMIC_CMPEXCH_WEAK (Pointer, , __ATOMIC_SEQ_CST, ptr, expect, new_value); return expect; case bson_memory_order_relaxed: DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, ptr, expect, new_value); return expect; case bson_memory_order_consume: DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, ptr, expect, new_value); return expect; case bson_memory_order_acquire: DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, ptr, expect, new_value); return expect; default: BSON_UNREACHABLE ("Invalid bson_memory_order value"); } } static BSON_INLINE void *BSON_GNUC_DEPRECATED bson_atomic_ptr_fetch (void *volatile const *ptr, enum bson_memory_order ord) { // Use a union to address cast-qual compilation warning union { void *volatile const *const_ptr; void *volatile *non_const_ptr; } u; u.const_ptr = ptr; return bson_atomic_ptr_compare_exchange_strong (u.non_const_ptr, NULL, NULL, ord); } #undef DECL_ATOMIC_STDINT #undef DECL_ATOMIC_INTEGRAL #undef DEF_ATOMIC_OP #undef DEF_ATOMIC_CMPEXCH_STRONG #undef DEF_ATOMIC_CMPEXCH_WEAK #undef MSVC_MEMORDER_SUFFIX /** * @brief Generate a full-fence memory barrier at the call site. */ static BSON_INLINE void BSON_GNUC_DEPRECATED bson_atomic_thread_fence (void) { BSON_IF_MSVC (MemoryBarrier ();) BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_BEGIN BSON_IF_GNU_LIKE (__sync_synchronize ();) BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_END BSON_IF_GNU_LEGACY_ATOMICS (__sync_synchronize ();) } static BSON_INLINE void BSON_GNUC_DEPRECATED bson_sync_synchronize (void) { bson_atomic_thread_fence (); } #ifdef BSON_USE_LEGACY_GCC_ATOMICS #undef BSON_IF_GNU_LIKE #define BSON_IF_GNU_LIKE(...) __VA_ARGS__ #endif #undef BSON_IF_GNU_LEGACY_ATOMICS #undef BSON_USE_LEGACY_GCC_ATOMICS BSON_GNUC_DEPRECATED BSON_EXPORT (void) bson_memory_barrier (void); BSON_GNUC_DEPRECATED BSON_EXPORT (int32_t) bson_atomic_int_add (volatile int32_t *p, int32_t n); BSON_GNUC_DEPRECATED BSON_EXPORT (int64_t) bson_atomic_int64_add (volatile int64_t *p, int64_t n); BSON_DISABLE_COVERED_SWITCH_DEFAULT_END #undef BSON_EMULATE_PTR #undef BSON_EMULATE_INT32 #undef BSON_EMULATE_INT #undef BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_BEGIN #undef BSON_DISABLE_ATOMIC_IMPLICIT_SEQ_CST_END #undef BSON_DISABLE_COVERED_SWITCH_DEFAULT_BEGIN #undef BSON_DISABLE_COVERED_SWITCH_DEFAULT_END BSON_END_DECLS BSON_END_IGNORE_DEPRECATIONS #undef BSON_BEGIN_IGNORE_DEPRECATIONS #undef BSON_END_IGNORE_DEPRECATIONS #endif /* BSON_ATOMIC_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-clock.c0000644000175100001660000000661314760300420021050 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #if defined(BSON_HAVE_CLOCK_GETTIME) #include #include #endif #include /* *-------------------------------------------------------------------------- * * bson_gettimeofday -- * * A wrapper around gettimeofday() with fallback support for Windows. * * Returns: * 0 if successful. * * Side effects: * @tv is set. * *-------------------------------------------------------------------------- */ int bson_gettimeofday (struct timeval *tv) /* OUT */ { #if defined(_WIN32) #if defined(_MSC_VER) #define DELTA_EPOCH_IN_MICROSEC 11644473600000000Ui64 #else #define DELTA_EPOCH_IN_MICROSEC 11644473600000000ULL #endif FILETIME ft; uint64_t tmp = 0; /* * The const value is shamelessly stolen from * http://www.boost.org/doc/libs/1_55_0/boost/chrono/detail/inlined/win/chrono.hpp * * File times are the number of 100 nanosecond intervals elapsed since * 12:00 am Jan 1, 1601 UTC. I haven't check the math particularly hard * * ... good luck */ if (tv) { GetSystemTimeAsFileTime (&ft); /* pull out of the filetime into a 64 bit uint */ tmp |= ft.dwHighDateTime; tmp <<= 32; tmp |= ft.dwLowDateTime; /* convert from 100's of nanosecs to microsecs */ tmp /= 10; /* adjust to unix epoch */ tmp -= DELTA_EPOCH_IN_MICROSEC; tv->tv_sec = (long) (tmp / 1000000UL); tv->tv_usec = (long) (tmp % 1000000UL); } return 0; #else return gettimeofday (tv, NULL); #endif } /* *-------------------------------------------------------------------------- * * bson_get_monotonic_time -- * * Returns the monotonic system time, if available. A best effort is * made to use the monotonic clock. However, some systems may not * support such a feature. * * Returns: * The monotonic clock in microseconds. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int64_t bson_get_monotonic_time (void) { #if defined(BSON_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) struct timespec ts; /* ts.tv_sec may be a four-byte integer on 32 bit machines, so cast to * int64_t to avoid truncation. */ clock_gettime (CLOCK_MONOTONIC, &ts); return (((int64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000)); #elif defined(_WIN32) /* Despite it's name, this is in milliseconds! */ int64_t ticks = GetTickCount64 (); return (ticks * 1000); #elif defined(__hpux__) int64_t nanosec = gethrtime (); return (nanosec / 1000UL); #else #pragma message "Monotonic clock is not yet supported on your platform." struct timeval tv; bson_gettimeofday (&tv); return ((int64_t) tv.tv_sec * 1000000) + tv.tv_usec; #endif } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-clock.h0000644000175100001660000000166414760300420021056 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_CLOCK_H #define BSON_CLOCK_H #include #include #include BSON_BEGIN_DECLS BSON_EXPORT (int64_t) bson_get_monotonic_time (void); BSON_EXPORT (int) bson_gettimeofday (struct timeval *tv); BSON_END_DECLS #endif /* BSON_CLOCK_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-cmp.h0000644000175100001660000002273314760300420020542 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_CMP_H #define BSON_CMP_H #include /* ssize_t */ #include /* BSON_CONCAT */ #include #include #include // bson-cmp.h is deprecated. // Ignore deprecation warnings for function calls within this file. #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #define BSON_BEGIN_IGNORE_DEPRECATIONS \ _Pragma ("GCC diagnostic push") _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #define BSON_END_IGNORE_DEPRECATIONS _Pragma ("GCC diagnostic pop") #elif defined(__clang__) #define BSON_BEGIN_IGNORE_DEPRECATIONS \ _Pragma ("clang diagnostic push") _Pragma ("clang diagnostic ignored \"-Wdeprecated-declarations\"") #define BSON_END_IGNORE_DEPRECATIONS _Pragma ("clang diagnostic pop") #else #define BSON_BEGIN_IGNORE_DEPRECATIONS #define BSON_END_IGNORE_DEPRECATIONS #endif BSON_BEGIN_IGNORE_DEPRECATIONS BSON_BEGIN_DECLS /* Based on the "Safe Integral Comparisons" proposal merged in C++20: * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0586r2.html * * Due to lack of type deduction in C, relational comparison functions (e.g. * `cmp_less`) are defined in sets of four "functions" according to the * signedness of each value argument, e.g.: * - bson_cmp_less_ss (signed-value, signed-value) * - bson_cmp_less_uu (unsigned-value, unsigned-value) * - bson_cmp_less_su (signed-value, unsigned-value) * - bson_cmp_less_us (unsigned-value, signed-value) * * Similarly, the `in_range` function is defined as a set of two "functions" * according to the signedness of the value argument: * - bson_in_range_signed (Type, signed-value) * - bson_in_range_unsigned (Type, unsigned-value) * * The user must take care to use the correct signedness for the provided * argument(s). Enabling compiler warnings for implicit sign conversions is * recommended. */ #define BSON_CMP_SET(op, ss, uu, su, us) \ static BSON_INLINE bool BSON_GNUC_DEPRECATED BSON_CONCAT3 (bson_cmp_, op, _ss) (int64_t t, int64_t u) \ { \ return (ss); \ } \ \ static BSON_INLINE bool BSON_GNUC_DEPRECATED BSON_CONCAT3 (bson_cmp_, op, _uu) (uint64_t t, uint64_t u) \ { \ return (uu); \ } \ \ static BSON_INLINE bool BSON_GNUC_DEPRECATED BSON_CONCAT3 (bson_cmp_, op, _su) (int64_t t, uint64_t u) \ { \ return (su); \ } \ \ static BSON_INLINE bool BSON_GNUC_DEPRECATED BSON_CONCAT3 (bson_cmp_, op, _us) (uint64_t t, int64_t u) \ { \ return (us); \ } BSON_CMP_SET (equal, t == u, t == u, t < 0 ? false : (uint64_t) (t) == u, u < 0 ? false : t == (uint64_t) (u)) BSON_CMP_SET (not_equal, !bson_cmp_equal_ss (t, u), !bson_cmp_equal_uu (t, u), !bson_cmp_equal_su (t, u), !bson_cmp_equal_us (t, u)) BSON_CMP_SET (less, t < u, t < u, t < 0 ? true : (uint64_t) (t) < u, u < 0 ? false : t < (uint64_t) (u)) BSON_CMP_SET ( greater, bson_cmp_less_ss (u, t), bson_cmp_less_uu (u, t), bson_cmp_less_us (u, t), bson_cmp_less_su (u, t)) BSON_CMP_SET (less_equal, !bson_cmp_greater_ss (t, u), !bson_cmp_greater_uu (t, u), !bson_cmp_greater_su (t, u), !bson_cmp_greater_us (t, u)) BSON_CMP_SET (greater_equal, !bson_cmp_less_ss (t, u), !bson_cmp_less_uu (t, u), !bson_cmp_less_su (t, u), !bson_cmp_less_us (t, u)) #undef BSON_CMP_SET /* Return true if the given value is within the range of the corresponding * signed type. The suffix must match the signedness of the given value. */ #define BSON_IN_RANGE_SET_SIGNED(Type, min, max) \ static BSON_INLINE bool BSON_GNUC_DEPRECATED BSON_CONCAT3 (bson_in_range, _##Type, _signed) (int64_t value) \ { \ return bson_cmp_greater_equal_ss (value, min) && bson_cmp_less_equal_ss (value, max); \ } \ \ static BSON_INLINE bool BSON_GNUC_DEPRECATED BSON_CONCAT3 (bson_in_range, _##Type, _unsigned) (uint64_t value) \ { \ return bson_cmp_greater_equal_us (value, min) && bson_cmp_less_equal_us (value, max); \ } /* Return true if the given value is within the range of the corresponding * unsigned type. The suffix must match the signedness of the given value. */ #define BSON_IN_RANGE_SET_UNSIGNED(Type, max) \ static BSON_INLINE bool BSON_GNUC_DEPRECATED BSON_CONCAT3 (bson_in_range, _##Type, _signed) (int64_t value) \ { \ return bson_cmp_greater_equal_su (value, 0u) && bson_cmp_less_equal_su (value, max); \ } \ \ static BSON_INLINE bool BSON_GNUC_DEPRECATED BSON_CONCAT3 (bson_in_range, _##Type, _unsigned) (uint64_t value) \ { \ return bson_cmp_less_equal_uu (value, max); \ } BSON_IN_RANGE_SET_SIGNED (signed_char, SCHAR_MIN, SCHAR_MAX) BSON_IN_RANGE_SET_SIGNED (short, SHRT_MIN, SHRT_MAX) BSON_IN_RANGE_SET_SIGNED (int, INT_MIN, INT_MAX) BSON_IN_RANGE_SET_SIGNED (long, LONG_MIN, LONG_MAX) BSON_IN_RANGE_SET_SIGNED (long_long, LLONG_MIN, LLONG_MAX) BSON_IN_RANGE_SET_UNSIGNED (unsigned_char, UCHAR_MAX) BSON_IN_RANGE_SET_UNSIGNED (unsigned_short, USHRT_MAX) BSON_IN_RANGE_SET_UNSIGNED (unsigned_int, UINT_MAX) BSON_IN_RANGE_SET_UNSIGNED (unsigned_long, ULONG_MAX) BSON_IN_RANGE_SET_UNSIGNED (unsigned_long_long, ULLONG_MAX) BSON_IN_RANGE_SET_SIGNED (int8_t, INT8_MIN, INT8_MAX) BSON_IN_RANGE_SET_SIGNED (int16_t, INT16_MIN, INT16_MAX) BSON_IN_RANGE_SET_SIGNED (int32_t, INT32_MIN, INT32_MAX) BSON_IN_RANGE_SET_SIGNED (int64_t, INT64_MIN, INT64_MAX) BSON_IN_RANGE_SET_UNSIGNED (uint8_t, UINT8_MAX) BSON_IN_RANGE_SET_UNSIGNED (uint16_t, UINT16_MAX) BSON_IN_RANGE_SET_UNSIGNED (uint32_t, UINT32_MAX) BSON_IN_RANGE_SET_UNSIGNED (uint64_t, UINT64_MAX) BSON_IN_RANGE_SET_SIGNED (ssize_t, SSIZE_MIN, SSIZE_MAX) BSON_IN_RANGE_SET_UNSIGNED (size_t, SIZE_MAX) #undef BSON_IN_RANGE_SET_SIGNED #undef BSON_IN_RANGE_SET_UNSIGNED /* Return true if the value with *signed* type is in the representable range of * Type and false otherwise. */ #define bson_in_range_signed(Type, value) BSON_CONCAT3 (bson_in_range, _##Type, _signed) (value) /* Return true if the value with *unsigned* type is in the representable range * of Type and false otherwise. */ #define bson_in_range_unsigned(Type, value) BSON_CONCAT3 (bson_in_range, _##Type, _unsigned) (value) BSON_END_DECLS BSON_END_IGNORE_DEPRECATIONS #undef BSON_BEGIN_IGNORE_DEPRECATIONS #undef BSON_END_IGNORE_DEPRECATIONS #endif /* BSON_CMP_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-compat.h0000644000175100001660000001210514760300420021236 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_COMPAT_H #define BSON_COMPAT_H #if defined(__MINGW32__) #if defined(__USE_MINGW_ANSI_STDIO) #if __USE_MINGW_ANSI_STDIO < 1 #error "__USE_MINGW_ANSI_STDIO > 0 is required for correct PRI* macros" #endif #else #define __USE_MINGW_ANSI_STDIO 1 #endif #endif #include #include #ifdef BSON_OS_WIN32 #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0601) #undef _WIN32_WINNT #endif #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0601 #endif #ifndef NOMINMAX #define NOMINMAX #endif #include #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #else #include #endif #include #include #endif #ifdef BSON_OS_UNIX #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include BSON_BEGIN_DECLS #if !defined(_MSC_VER) || (_MSC_VER >= 1800) #include #endif #ifdef _MSC_VER #ifndef __cplusplus /* benign redefinition of type */ #pragma warning(disable : 4142) #ifndef _SSIZE_T_DEFINED #define _SSIZE_T_DEFINED typedef SSIZE_T ssize_t; #endif #ifndef _SIZE_T_DEFINED #define _SIZE_T_DEFINED typedef SIZE_T size_t; #endif #pragma warning(default : 4142) #else /* * MSVC++ does not include ssize_t, just size_t. * So we need to synthesize that as well. */ #pragma warning(disable : 4142) #ifndef _SSIZE_T_DEFINED #define _SSIZE_T_DEFINED typedef SSIZE_T ssize_t; #endif #pragma warning(default : 4142) #endif #ifndef PRIi32 #define PRIi32 "d" #endif #ifndef PRId32 #define PRId32 "d" #endif #ifndef PRIu32 #define PRIu32 "u" #endif #ifndef PRIi64 #define PRIi64 "I64i" #endif #ifndef PRId64 #define PRId64 "I64i" #endif #ifndef PRIu64 #define PRIu64 "I64u" #endif #endif /* Derive the maximum representable value of signed integer type T using the * formula 2^(N - 1) - 1 where N is the number of bits in type T. This assumes * T is represented using two's complement. */ #define BSON_NUMERIC_LIMITS_MAX_SIGNED(T) ((T) ((((size_t) 0x01u) << (sizeof (T) * (size_t) CHAR_BIT - 1u)) - 1u)) /* Derive the minimum representable value of signed integer type T as one less * than the negation of its maximum representable value. This assumes T is * represented using two's complement. */ #define BSON_NUMERIC_LIMITS_MIN_SIGNED(T, max) ((T) ((-(max)) - 1)) /* Derive the maximum representable value of unsigned integer type T by flipping * all its bits to 1. */ #define BSON_NUMERIC_LIMITS_MAX_UNSIGNED(T) ((T) (~((T) 0))) #ifndef SSIZE_MAX #define SSIZE_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (ssize_t) #endif #ifndef SSIZE_MIN #define SSIZE_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (ssize_t, SSIZE_MAX) #endif #if defined(__MINGW32__) && !defined(INIT_ONCE_STATIC_INIT) #define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT typedef RTL_RUN_ONCE INIT_ONCE; #endif #ifdef BSON_HAVE_STDBOOL_H #include #elif !defined(__bool_true_false_are_defined) #ifndef __cplusplus typedef signed char bool; #define false 0 #define true 1 #endif #define __bool_true_false_are_defined 1 #endif #if !defined(va_copy) && defined(__va_copy) #define va_copy(dst, src) __va_copy (dst, src) #endif #if !defined(va_copy) #define va_copy(dst, src) ((dst) = (src)) #endif #ifdef _MSC_VER /** Expands the arguments if compiling with MSVC, otherwise empty */ #define BSON_IF_MSVC(...) __VA_ARGS__ /** Expands the arguments if compiling with GCC or Clang, otherwise empty */ #define BSON_IF_GNU_LIKE(...) #elif defined(__GNUC__) || defined(__clang__) /** Expands the arguments if compiling with MSVC, otherwise empty */ #define BSON_IF_MSVC(...) /** Expands the arguments if compiling with GCC or Clang, otherwise empty */ #define BSON_IF_GNU_LIKE(...) __VA_ARGS__ #else /** Unsupported compiler. **/ #define BSON_IF_MSVC(...) #define BSON_IF_GNU_LIKE(...) #endif #ifdef BSON_OS_WIN32 /** Expands the arguments if compiling for Windows, otherwise empty */ #define BSON_IF_WINDOWS(...) __VA_ARGS__ /** Expands the arguments if compiling for POSIX, otherwise empty */ #define BSON_IF_POSIX(...) #elif defined(BSON_OS_UNIX) /** Expands the arguments if compiling for Windows, otherwise empty */ #define BSON_IF_WINDOWS(...) /** Expands the arguments if compiling for POSIX, otherwise empty */ #define BSON_IF_POSIX(...) __VA_ARGS__ #endif BSON_END_DECLS #endif /* BSON_COMPAT_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-config.h0000644000175100001660000000530614760300420021225 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) #error "Only can be included directly." #endif #ifndef BSON_CONFIG_H #define BSON_CONFIG_H /* * Define to 1234 for Little Endian, 4321 for Big Endian. */ #define BSON_BYTE_ORDER 1234 /* * Define to 1 if you have stdbool.h */ #define BSON_HAVE_STDBOOL_H 1 #if BSON_HAVE_STDBOOL_H != 1 # undef BSON_HAVE_STDBOOL_H #endif /* * Define to 1 for POSIX-like systems, 2 for Windows. */ #define BSON_OS 1 /* * Define to 1 if you have clock_gettime() available. */ #define BSON_HAVE_CLOCK_GETTIME 1 #if BSON_HAVE_CLOCK_GETTIME != 1 # undef BSON_HAVE_CLOCK_GETTIME #endif /* * Define to 1 if you have strings.h available on your platform. */ #define BSON_HAVE_STRINGS_H 1 #if BSON_HAVE_STRINGS_H != 1 # undef BSON_HAVE_STRINGS_H #endif /* * Define to 1 if you have strnlen available on your platform. */ #define BSON_HAVE_STRNLEN 1 #if BSON_HAVE_STRNLEN != 1 # undef BSON_HAVE_STRNLEN #endif /* * Define to 1 if you have snprintf available on your platform. */ #define BSON_HAVE_SNPRINTF 1 #if BSON_HAVE_SNPRINTF != 1 # undef BSON_HAVE_SNPRINTF #endif /* * Define to 1 if you have gmtime_r available on your platform. */ #define BSON_HAVE_GMTIME_R 1 #if BSON_HAVE_GMTIME_R != 1 # undef BSON_HAVE_GMTIME_R #endif /* * Define to 1 if you have struct timespec available on your platform. */ #define BSON_HAVE_TIMESPEC 1 #if BSON_HAVE_TIMESPEC != 1 # undef BSON_HAVE_TIMESPEC #endif /* * Define to 1 if you want extra aligned types in libbson */ #define BSON_EXTRA_ALIGN 0 #if BSON_EXTRA_ALIGN != 1 # undef BSON_EXTRA_ALIGN #endif /* * Define to 1 if you have rand_r available on your platform. */ #define BSON_HAVE_RAND_R 1 #if BSON_HAVE_RAND_R != 1 # undef BSON_HAVE_RAND_R #endif /* * Define to 1 if you have strlcpy available on your platform. */ #define BSON_HAVE_STRLCPY 1 #if BSON_HAVE_STRLCPY != 1 # undef BSON_HAVE_STRLCPY #endif /* * Define to 1 if you have aligned_alloc available on your platform. */ #define BSON_HAVE_ALIGNED_ALLOC 1 #if BSON_HAVE_ALIGNED_ALLOC != 1 # undef BSON_HAVE_ALIGNED_ALLOC #endif #endif /* BSON_CONFIG_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-config.h.in0000644000175100001660000000566214760300420021637 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) #error "Only can be included directly." #endif #ifndef BSON_CONFIG_H #define BSON_CONFIG_H /* * Define to 1234 for Little Endian, 4321 for Big Endian. */ #define BSON_BYTE_ORDER @BSON_BYTE_ORDER@ /* * Define to 1 if you have stdbool.h */ #define BSON_HAVE_STDBOOL_H @BSON_HAVE_STDBOOL_H@ #if BSON_HAVE_STDBOOL_H != 1 # undef BSON_HAVE_STDBOOL_H #endif /* * Define to 1 for POSIX-like systems, 2 for Windows. */ #define BSON_OS @BSON_OS@ /* * Define to 1 if you have clock_gettime() available. */ #define BSON_HAVE_CLOCK_GETTIME @BSON_HAVE_CLOCK_GETTIME@ #if BSON_HAVE_CLOCK_GETTIME != 1 # undef BSON_HAVE_CLOCK_GETTIME #endif /* * Define to 1 if you have strings.h available on your platform. */ #define BSON_HAVE_STRINGS_H @BSON_HAVE_STRINGS_H@ #if BSON_HAVE_STRINGS_H != 1 # undef BSON_HAVE_STRINGS_H #endif /* * Define to 1 if you have strnlen available on your platform. */ #define BSON_HAVE_STRNLEN @BSON_HAVE_STRNLEN@ #if BSON_HAVE_STRNLEN != 1 # undef BSON_HAVE_STRNLEN #endif /* * Define to 1 if you have snprintf available on your platform. */ #define BSON_HAVE_SNPRINTF @BSON_HAVE_SNPRINTF@ #if BSON_HAVE_SNPRINTF != 1 # undef BSON_HAVE_SNPRINTF #endif /* * Define to 1 if you have gmtime_r available on your platform. */ #define BSON_HAVE_GMTIME_R @BSON_HAVE_GMTIME_R@ #if BSON_HAVE_GMTIME_R != 1 # undef BSON_HAVE_GMTIME_R #endif /* * Define to 1 if you have struct timespec available on your platform. */ #define BSON_HAVE_TIMESPEC @BSON_HAVE_TIMESPEC@ #if BSON_HAVE_TIMESPEC != 1 # undef BSON_HAVE_TIMESPEC #endif /* * Define to 1 if you want extra aligned types in libbson */ #define BSON_EXTRA_ALIGN @BSON_EXTRA_ALIGN@ #if BSON_EXTRA_ALIGN != 1 # undef BSON_EXTRA_ALIGN #endif /* * Define to 1 if you have rand_r available on your platform. */ #define BSON_HAVE_RAND_R @BSON_HAVE_RAND_R@ #if BSON_HAVE_RAND_R != 1 # undef BSON_HAVE_RAND_R #endif /* * Define to 1 if you have strlcpy available on your platform. */ #define BSON_HAVE_STRLCPY @BSON_HAVE_STRLCPY@ #if BSON_HAVE_STRLCPY != 1 # undef BSON_HAVE_STRLCPY #endif /* * Define to 1 if you have aligned_alloc available on your platform. */ #define BSON_HAVE_ALIGNED_ALLOC @BSON_HAVE_ALIGNED_ALLOC@ #if BSON_HAVE_ALIGNED_ALLOC != 1 # undef BSON_HAVE_ALIGNED_ALLOC #endif #endif /* BSON_CONFIG_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-context-private.h0000644000175100001660000000412314760300420023110 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_CONTEXT_PRIVATE_H #define BSON_CONTEXT_PRIVATE_H #include #include BSON_BEGIN_DECLS enum { BSON_OID_RANDOMESS_OFFSET = 4, BSON_OID_RANDOMNESS_SIZE = 5, BSON_OID_SEQ32_OFFSET = 9, BSON_OID_SEQ32_SIZE = 3, BSON_OID_SEQ64_OFFSET = 4, BSON_OID_SEQ64_SIZE = 8 }; struct _bson_context_t { /* flags are defined in bson_context_flags_t */ int flags; uint32_t seq32; uint64_t seq64; uint8_t randomness[BSON_OID_RANDOMNESS_SIZE]; uint64_t pid; }; /** * @brief Insert the context's randomness data into the given OID * * @param context A context for some random data * @param oid The OID to update. */ void _bson_context_set_oid_rand (bson_context_t *context, bson_oid_t *oid); /** * @brief Insert the context's sequence counter into the given OID. Increments * the context's sequence counter. * * @param context The context with the counter to get+update * @param oid The OID to modify */ void _bson_context_set_oid_seq32 (bson_context_t *context, bson_oid_t *oid); /** * @brief Write a 64-bit counter from the given context into the OID. Increments * the context's sequence counter. * * @param context The context with the counter to get+update * @param oid The OID to modify * * @note Only used by the deprecated @ref bson_oid_init_sequence */ void _bson_context_set_oid_seq64 (bson_context_t *context, bson_oid_t *oid); BSON_END_DECLS #endif /* BSON_CONTEXT_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-context.c0000644000175100001660000002273414760300420021443 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 256 #endif /* * Globals. */ static bson_context_t gContextDefault; static BSON_INLINE uint64_t _bson_getpid (void) { uint64_t pid; #ifdef BSON_OS_WIN32 DWORD real_pid; real_pid = GetCurrentProcessId (); pid = (real_pid & 0xFFFF) ^ ((real_pid >> 16) & 0xFFFF); #else pid = (uint64_t) getpid (); #endif return pid; } void _bson_context_set_oid_seq32 (bson_context_t *context, /* IN */ bson_oid_t *oid) /* OUT */ { uint32_t seq = (uint32_t) mcommon_atomic_int32_fetch_add ( (DECL_ATOMIC_INTEGRAL_INT32 *) &context->seq32, 1, mcommon_memory_order_seq_cst); seq = BSON_UINT32_TO_BE (seq); memcpy (&oid->bytes[BSON_OID_SEQ32_OFFSET], ((uint8_t *) &seq) + 1, BSON_OID_SEQ32_SIZE); } void _bson_context_set_oid_seq64 (bson_context_t *context, /* IN */ bson_oid_t *oid) /* OUT */ { uint64_t seq = (uint64_t) mcommon_atomic_int64_fetch_add ((int64_t *) &context->seq64, 1, mcommon_memory_order_seq_cst); seq = BSON_UINT64_TO_BE (seq); memcpy (&oid->bytes[BSON_OID_SEQ64_OFFSET], &seq, BSON_OID_SEQ64_SIZE); } /* * -------------------------------------------------------------------------- * * _bson_context_get_hostname * * Gets the hostname of the machine, logs a warning on failure. "out" * must be an array of HOST_NAME_MAX bytes. * * -------------------------------------------------------------------------- */ static void _bson_context_get_hostname (char out[HOST_NAME_MAX]) { if (gethostname (out, HOST_NAME_MAX) != 0) { if (errno == ENAMETOOLONG) { fprintf (stderr, "hostname exceeds %d characters, truncating.", HOST_NAME_MAX); } else { fprintf (stderr, "unable to get hostname: %d", errno); } } out[HOST_NAME_MAX - 1] = '\0'; } /*** ======================================== * The below SipHash implementation is based on the original public-domain * reference implementation from Jean-Philippe Aumasson and DJB * (https://github.com/veorq/SipHash). */ /* in-place rotate a 64bit number */ void _bson_rotl_u64 (uint64_t *p, int nbits) { *p = (*p << nbits) | (*p >> (64 - nbits)); } /* Write the little-endian representation of 'val' into 'out' */ void _u64_into_u8x8_le (uint8_t out[8], uint64_t val) { val = BSON_UINT64_TO_LE (val); memcpy (out, &val, sizeof val); } /* Read a little-endian representation of a 64bit number from 'in' */ uint64_t _u8x8_le_to_u64 (const uint8_t in[8]) { uint64_t r; memcpy (&r, in, sizeof r); return BSON_UINT64_FROM_LE (r); } /* Perform one SipHash round */ void _sip_round (uint64_t *v0, uint64_t *v1, uint64_t *v2, uint64_t *v3) { *v0 += *v1; _bson_rotl_u64 (v1, 13); *v1 ^= *v0; _bson_rotl_u64 (v0, 32); *v2 += *v3; _bson_rotl_u64 (v3, 16); *v3 ^= *v2; *v0 += *v3; _bson_rotl_u64 (v3, 21); *v3 ^= *v0; *v2 += *v1; _bson_rotl_u64 (v1, 17); *v1 ^= *v2; _bson_rotl_u64 (v2, 32); } void _siphash (const void *in, const size_t inlen, const uint64_t key[2], uint64_t digest[2]) { const unsigned char *ni = (const unsigned char *) in; const unsigned char *kk = (const unsigned char *) key; uint8_t digest_buf[16] = {0}; const int C_ROUNDS = 2; const int D_ROUNDS = 4; uint64_t v0 = UINT64_C (0x736f6d6570736575); uint64_t v1 = UINT64_C (0x646f72616e646f6d); uint64_t v2 = UINT64_C (0x6c7967656e657261); uint64_t v3 = UINT64_C (0x7465646279746573); uint64_t k0 = _u8x8_le_to_u64 (kk); uint64_t k1 = _u8x8_le_to_u64 (kk + 8); uint64_t m; int i; const unsigned char *end = ni + inlen - (inlen % sizeof (uint64_t)); const int left = inlen & 7; uint64_t b = ((uint64_t) inlen) << 56; v3 ^= k1; v2 ^= k0; v1 ^= k1; v0 ^= k0; v1 ^= 0xee; for (; ni != end; ni += 8) { m = _u8x8_le_to_u64 (ni); v3 ^= m; for (i = 0; i < C_ROUNDS; ++i) _sip_round (&v0, &v1, &v2, &v3); v0 ^= m; } switch (left) { case 7: b |= ((uint64_t) ni[6]) << 48; /* FALLTHRU */ case 6: b |= ((uint64_t) ni[5]) << 40; /* FALLTHRU */ case 5: b |= ((uint64_t) ni[4]) << 32; /* FALLTHRU */ case 4: b |= ((uint64_t) ni[3]) << 24; /* FALLTHRU */ case 3: b |= ((uint64_t) ni[2]) << 16; /* FALLTHRU */ case 2: b |= ((uint64_t) ni[1]) << 8; /* FALLTHRU */ case 1: b |= ((uint64_t) ni[0]); break; default: BSON_UNREACHABLE ("Invalid remainder during SipHash"); case 0: break; } v3 ^= b; for (i = 0; i < C_ROUNDS; ++i) _sip_round (&v0, &v1, &v2, &v3); v0 ^= b; v2 ^= 0xee; for (i = 0; i < D_ROUNDS; ++i) _sip_round (&v0, &v1, &v2, &v3); b = v0 ^ v1 ^ v2 ^ v3; _u64_into_u8x8_le (digest_buf, b); v1 ^= 0xdd; for (i = 0; i < D_ROUNDS; ++i) _sip_round (&v0, &v1, &v2, &v3); b = v0 ^ v1 ^ v2 ^ v3; _u64_into_u8x8_le (digest_buf + 8, b); memcpy (digest, digest_buf, sizeof digest_buf); } /* * The seed consists of the following hashed together: * - current time (with microsecond resolution) * - current pid * - current hostname * - The init-call counter */ struct _init_rand_params { struct timeval time; uint64_t pid; char hostname[HOST_NAME_MAX]; int64_t rand_call_counter; }; static void _bson_context_init_random (bson_context_t *context, bool init_seq) { /* Keep an atomic counter of this function being called. This is used to add * additional input to the random hash, ensuring no two calls in a single * process will receive identical hash inputs, even occurring at the same * microsecond. */ static int64_t s_rand_call_counter = INT64_MIN; /* The message digest of the random params */ uint64_t digest[2] = {0}; uint64_t key[2] = {0}; /* The randomness parameters */ struct _init_rand_params rand_params; /* Init each part of the randomness source: */ memset (&rand_params, 0, sizeof rand_params); bson_gettimeofday (&rand_params.time); rand_params.pid = _bson_getpid (); _bson_context_get_hostname (rand_params.hostname); rand_params.rand_call_counter = mcommon_atomic_int64_fetch_add (&s_rand_call_counter, 1, mcommon_memory_order_seq_cst); /* Generate a SipHash key. We do not care about secrecy or determinism, only * uniqueness. */ memcpy (key, &rand_params, sizeof key); key[1] = ~key[0]; /* Hash the param struct */ _siphash (&rand_params, sizeof rand_params, key, digest); /** Initialize the rand and sequence counters with our random digest */ memcpy (context->randomness, digest, sizeof context->randomness); if (init_seq) { memcpy (&context->seq32, digest + 1, sizeof context->seq32); memcpy (&context->seq64, digest + 1, sizeof context->seq64); /* Chop off some initial bits for nicer counter behavior. This allows the * low digit to start at a zero, and prevents immediately wrapping the * counter in subsequent calls to set_oid_seq. */ context->seq32 &= ~UINT32_C (0xf0000f); context->seq64 &= ~UINT64_C (0xf0000f); } /* Remember the PID we saw here. This may change in case of fork() */ context->pid = rand_params.pid; } static void _bson_context_init (bson_context_t *context, bson_context_flags_t flags) { context->flags = (int) flags; _bson_context_init_random (context, true /* Init counters */); } void _bson_context_set_oid_rand (bson_context_t *context, bson_oid_t *oid) { BSON_ASSERT (context); BSON_ASSERT (oid); if (context->flags & BSON_CONTEXT_DISABLE_PID_CACHE) { /* User has requested that we check if our PID has changed. This can occur * after a call to fork() */ uint64_t now_pid = _bson_getpid (); if (now_pid != context->pid) { _bson_context_init_random (context, false /* Do not update the sequence counters */); } } /* Copy the stored randomness into the OID */ memcpy (oid->bytes + BSON_OID_RANDOMESS_OFFSET, &context->randomness, BSON_OID_RANDOMNESS_SIZE); } bson_context_t * bson_context_new (bson_context_flags_t flags) { bson_context_t *context; context = bson_malloc0 (sizeof *context); _bson_context_init (context, flags); return context; } void bson_context_destroy (bson_context_t *context) /* IN */ { bson_free (context); } static BSON_ONCE_FUN (_bson_context_init_default) { _bson_context_init (&gContextDefault, BSON_CONTEXT_DISABLE_PID_CACHE); BSON_ONCE_RETURN; } bson_context_t * bson_context_get_default (void) { static bson_once_t once = BSON_ONCE_INIT; bson_once (&once, _bson_context_init_default); return &gContextDefault; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-context.h0000644000175100001660000000323414760300420021442 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_CONTEXT_H #define BSON_CONTEXT_H #include #include BSON_BEGIN_DECLS /** * @brief Initialize a new context with the given flags * * @param flags Flags used to configure the behavior of the context. For most * cases, this should be BSON_CONTEXT_NONE. * * @return A newly allocated context. Must be freed with bson_context_destroy() * * @note If you expect your pid to change without notice, such as from an * unexpected call to fork(), then specify BSON_CONTEXT_DISABLE_PID_CACHE in * `flags`. */ BSON_EXPORT (bson_context_t *) bson_context_new (bson_context_flags_t flags); /** * @brief Destroy and free a bson_context_t created by bson_context_new() */ BSON_EXPORT (void) bson_context_destroy (bson_context_t *context); /** * @brief Obtain a pointer to the application-default bson_context_t * * @note This context_t MUST NOT be passed to bson_context_destroy() */ BSON_EXPORT (bson_context_t *) bson_context_get_default (void); BSON_END_DECLS #endif /* BSON_CONTEXT_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-decimal128.c0000644000175100001660000005713214760300420021610 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #define BSON_DECIMAL128_EXPONENT_MAX 6111 #define BSON_DECIMAL128_EXPONENT_MIN -6176 #define BSON_DECIMAL128_EXPONENT_BIAS 6176 #define BSON_DECIMAL128_MAX_DIGITS 34 #define BSON_DECIMAL128_SET_NAN(dec) \ if (1) { \ (dec).high = 0x7c00000000000000ull; \ (dec).low = 0; \ } else \ (void) 0 #define BSON_DECIMAL128_SET_INF(dec, isneg) \ if (1) { \ (dec).high = 0x7800000000000000ull + 0x8000000000000000ull * (isneg); \ (dec).low = 0; \ } else \ (void) 0 /** * _bson_uint128_t: * * This struct represents a 128 bit integer. */ typedef struct { uint32_t parts[4]; /* 32-bit words stored high to low. */ } _bson_uint128_t; /** *------------------------------------------------------------------------------ * * _bson_uint128_divide1B -- * * This function divides a #_bson_uint128_t by 1000000000 (1 billion) and * computes the quotient and remainder. * * The remainder will contain 9 decimal digits for conversion to string. * * @value The #_bson_uint128_t operand. * @quotient A pointer to store the #_bson_uint128_t quotient. * @rem A pointer to store the #uint64_t remainder. * * Returns: * The quotient at @quotient and the remainder at @rem. * * Side effects: * None. * *------------------------------------------------------------------------------ */ static void _bson_uint128_divide1B (_bson_uint128_t value, /* IN */ _bson_uint128_t *quotient, /* OUT */ uint32_t *rem) /* OUT */ { const uint32_t DIVISOR = 1000 * 1000 * 1000; uint64_t _rem = 0; int i = 0; if (!value.parts[0] && !value.parts[1] && !value.parts[2] && !value.parts[3]) { *quotient = value; *rem = 0; return; } for (i = 0; i <= 3; i++) { _rem <<= 32; /* Adjust remainder to match value of next dividend */ _rem += value.parts[i]; /* Add the divided to _rem */ value.parts[i] = (uint32_t) (_rem / DIVISOR); _rem %= DIVISOR; /* Store the remainder */ } *quotient = value; *rem = (uint32_t) _rem; } /** *------------------------------------------------------------------------------ * * bson_decimal128_to_string -- * * This function converts a BID formatted decimal128 value to string, * accepting a &bson_decimal128_t as @dec. The string is stored at @str. * * @dec : The BID formatted decimal to convert. * @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING *characters. * * Returns: * None. * * Side effects: * None. * *------------------------------------------------------------------------------ */ void bson_decimal128_to_string (const bson_decimal128_t *dec, /* IN */ char *str) /* OUT */ { uint32_t COMBINATION_MASK = 0x1f; /* Extract least significant 5 bits */ uint32_t EXPONENT_MASK = 0x3fff; /* Extract least significant 14 bits */ uint32_t COMBINATION_INFINITY = 30; /* Value of combination field for Inf */ uint32_t COMBINATION_NAN = 31; /* Value of combination field for NaN */ uint32_t EXPONENT_BIAS = 6176; /* decimal128 exponent bias */ char *str_out = str; /* output pointer in string */ char significand_str[35]; /* decoded significand digits */ /* Note: bits in this routine are referred to starting at 0, */ /* from the sign bit, towards the coefficient. */ uint32_t high; /* bits 0 - 31 */ uint32_t midh; /* bits 32 - 63 */ uint32_t midl; /* bits 64 - 95 */ uint32_t low; /* bits 96 - 127 */ uint32_t combination; /* bits 1 - 5 */ uint32_t biased_exponent; /* decoded biased exponent (14 bits) */ uint32_t significand_digits = 0; /* the number of significand digits */ uint32_t significand[36] = {0}; /* the base-10 digits in the significand */ uint32_t *significand_read = significand; /* read pointer into significand */ int32_t exponent; /* unbiased exponent */ int32_t scientific_exponent; /* the exponent if scientific notation is * used */ bool is_zero = false; /* true if the number is zero */ uint8_t significand_msb; /* the most signifcant significand bits (50-46) */ _bson_uint128_t significand128; /* temporary storage for significand decoding */ memset (significand_str, 0, sizeof (significand_str)); if ((int64_t) dec->high < 0) { /* negative */ *(str_out++) = '-'; } low = (uint32_t) dec->low; midl = (uint32_t) (dec->low >> 32); midh = (uint32_t) dec->high; high = (uint32_t) (dec->high >> 32); /* Decode combination field and exponent */ combination = (high >> 26) & COMBINATION_MASK; if (BSON_UNLIKELY ((combination >> 3) == 3)) { /* Check for 'special' values */ if (combination == COMBINATION_INFINITY) { /* Infinity */ strcpy (str_out, BSON_DECIMAL128_INF); return; } else if (combination == COMBINATION_NAN) { /* NaN */ /* str, not str_out, to erase the sign */ strcpy (str, BSON_DECIMAL128_NAN); /* we don't care about the NaN payload. */ return; } else { biased_exponent = (high >> 15) & EXPONENT_MASK; significand_msb = 0x8 + ((high >> 14) & 0x1); } } else { significand_msb = (high >> 14) & 0x7; biased_exponent = (high >> 17) & EXPONENT_MASK; } exponent = biased_exponent - EXPONENT_BIAS; /* Create string of significand digits */ /* Convert the 114-bit binary number represented by */ /* (high, midh, midl, low) to at most 34 decimal */ /* digits through modulo and division. */ significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14); significand128.parts[1] = midh; significand128.parts[2] = midl; significand128.parts[3] = low; if (significand128.parts[0] == 0 && significand128.parts[1] == 0 && significand128.parts[2] == 0 && significand128.parts[3] == 0) { is_zero = true; } else if (significand128.parts[0] >= (1 << 17)) { /* The significand is non-canonical or zero. * In order to preserve compatibility with the densely packed decimal * format, the maximum value for the significand of decimal128 is * 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754 * standard dictates that the significand is interpreted as zero. */ is_zero = true; } else { for (int k = 3; k >= 0; k--) { uint32_t least_digits = 0; _bson_uint128_divide1B (significand128, &significand128, &least_digits); /* We now have the 9 least significant digits (in base 2). */ /* Convert and output to string. */ if (!least_digits) { continue; } for (int j = 8; j >= 0; j--) { significand[k * 9 + j] = least_digits % 10; least_digits /= 10; } } } /* Output format options: */ /* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */ /* Regular - ddd.ddd */ if (is_zero) { significand_digits = 1; *significand_read = 0; } else { significand_digits = 36; while (!(*significand_read)) { significand_digits--; significand_read++; } } scientific_exponent = significand_digits - 1 + exponent; /* The scientific exponent checks are dictated by the string conversion * specification and are somewhat arbitrary cutoffs. * * We must check exponent > 0, because if this is the case, the number * has trailing zeros. However, we *cannot* output these trailing zeros, * because doing so would change the precision of the value, and would * change stored data if the string converted number is round tripped. */ if (scientific_exponent < -6 || exponent > 0) { /* Scientific format */ *(str_out++) = *(significand_read++) + '0'; significand_digits--; if (significand_digits) { *(str_out++) = '.'; } for (uint32_t i = 0; i < significand_digits && (str_out - str) < 36; i++) { *(str_out++) = *(significand_read++) + '0'; } /* Exponent */ *(str_out++) = 'E'; // Truncation is OK. int req = bson_snprintf (str_out, 6, "%+d", scientific_exponent); BSON_ASSERT (req > 0); } else { /* Regular format with no decimal place */ if (exponent >= 0) { for (uint32_t i = 0; i < significand_digits && (str_out - str) < 36; i++) { *(str_out++) = *(significand_read++) + '0'; } *str_out = '\0'; } else { int32_t radix_position = significand_digits + exponent; // Reserve space for null terminator. const int available_bytes = BSON_DECIMAL128_STRING - 1; if (radix_position > 0) { /* non-zero digits before radix */ for (int32_t i = 0; i < radix_position && (str_out - str) < available_bytes; i++) { *(str_out++) = *(significand_read++) + '0'; } } else { /* leading zero before radix point */ *(str_out++) = '0'; } *(str_out++) = '.'; while (radix_position++ < 0) { /* add leading zeros after radix */ *(str_out++) = '0'; } for (uint32_t i = 0; mcommon_cmp_greater_us (significand_digits - i, BSON_MAX (radix_position - 1, 0)) && (str_out - str) < available_bytes; i++) { *(str_out++) = *(significand_read++) + '0'; } *str_out = '\0'; } } } typedef struct { uint64_t high, low; } _bson_uint128_6464_t; /** *------------------------------------------------------------------------- * * mul64x64 -- * * This function multiplies two &uint64_t into a &_bson_uint128_6464_t. * * Returns: * The product of @left and @right. * * Side Effects: * None. * *------------------------------------------------------------------------- */ static void _mul_64x64 (uint64_t left, /* IN */ uint64_t right, /* IN */ _bson_uint128_6464_t *product) /* OUT */ { uint64_t left_high, left_low, right_high, right_low, product_high, product_mid, product_mid2, product_low; _bson_uint128_6464_t rt = {0}; if (!left && !right) { *product = rt; return; } left_high = left >> 32; left_low = (uint32_t) left; right_high = right >> 32; right_low = (uint32_t) right; product_high = left_high * right_high; product_mid = left_high * right_low; product_mid2 = left_low * right_high; product_low = left_low * right_low; product_high += product_mid >> 32; product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32); product_high = product_high + (product_mid >> 32); product_low = (product_mid << 32) + (uint32_t) product_low; rt.high = product_high; rt.low = product_low; *product = rt; } /** *------------------------------------------------------------------------------ * * _dec128_tolower -- * * This function converts the ASCII character @c to lowercase. It is locale * insensitive (unlike the stdlib tolower). * * Returns: * The lowercased character. */ char _dec128_tolower (char c) { if (isupper (c)) { c += 32; } return c; } /** *------------------------------------------------------------------------------ * * _dec128_istreq -- * * This function compares the null-terminated *ASCII* strings @a and @b * for case-insensitive equality. * * Returns: * true if the strings are equal, false otherwise. */ bool _dec128_istreq (const char *a, /* IN */ const char *b /* IN */) { while (*a != '\0' || *b != '\0') { /* strings are different lengths. */ if (*a == '\0' || *b == '\0') { return false; } if (_dec128_tolower (*a) != _dec128_tolower (*b)) { return false; } a++; b++; } return true; } /** *------------------------------------------------------------------------------ * * bson_decimal128_from_string -- * * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to * decimal128. Out of range values are converted to +/-Infinity. Invalid * strings are converted to NaN. * * If more digits are provided than the available precision allows, * round to the nearest expressable decimal128 with ties going to even will * occur. * * Note: @string must be ASCII only! * * Returns: * true on success, or false on failure. @dec will be NaN if @str was invalid * The &bson_decimal128_t converted from @string at @dec. * * Side effects: * None. * *------------------------------------------------------------------------------ */ bool bson_decimal128_from_string (const char *string, /* IN */ bson_decimal128_t *dec) /* OUT */ { return bson_decimal128_from_string_w_len (string, -1, dec); } /** *------------------------------------------------------------------------------ * * bson_decimal128_from_string_w_len -- * * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to * decimal128. Out of range values are converted to +/-Infinity. Invalid * strings are converted to NaN. @len is the length of the string, or -1 * meaning the string is null-terminated. * * If more digits are provided than the available precision allows, * round to the nearest expressable decimal128 with ties going to even will * occur. * * Note: @string must be ASCII only! * * Returns: * true on success, or false on failure. @dec will be NaN if @str was invalid * The &bson_decimal128_t converted from @string at @dec. * * Side effects: * None. * *------------------------------------------------------------------------------ */ bool bson_decimal128_from_string_w_len (const char *string, /* IN */ int len, /* IN */ bson_decimal128_t *dec) /* OUT */ { _bson_uint128_6464_t significand = {0}; const char *str_read = string; /* Read pointer for consuming str. */ /* Parsing state tracking */ bool is_negative = false; bool saw_radix = false; bool includes_sign = false; /* True if the input string contains a sign. */ bool found_nonzero = false; size_t significant_digits = 0; /* Total number of significant digits * (no leading or trailing zero) */ size_t ndigits_read = 0; /* Total number of significand digits read */ size_t ndigits = 0; /* Total number of digits (no leading zeros) */ size_t radix_position = 0; /* The number of the digits after radix */ size_t first_nonzero = 0; /* The index of the first non-zero in *str* */ uint16_t digits[BSON_DECIMAL128_MAX_DIGITS] = {0}; uint16_t ndigits_stored = 0; /* The number of digits in digits */ uint16_t *digits_insert = digits; /* Insertion pointer for digits */ size_t first_digit = 0; /* The index of the first non-zero digit */ size_t last_digit = 0; /* The index of the last digit */ int32_t exponent = 0; uint64_t significand_high = 0; /* The high 17 digits of the significand */ uint64_t significand_low = 0; /* The low 17 digits of the significand */ uint16_t biased_exponent = 0; /* The biased exponent */ BSON_ASSERT (dec); dec->high = 0; dec->low = 0; if (*str_read == '+' || *str_read == '-') { is_negative = *(str_read++) == '-'; includes_sign = true; } /* Check for Infinity or NaN */ if (!isdigit (*str_read) && *str_read != '.') { if (_dec128_istreq (str_read, "inf") || _dec128_istreq (str_read, "infinity")) { BSON_DECIMAL128_SET_INF (*dec, is_negative); return true; } else if (_dec128_istreq (str_read, "nan")) { BSON_DECIMAL128_SET_NAN (*dec); return true; } BSON_DECIMAL128_SET_NAN (*dec); return false; } /* Read digits */ while (((isdigit (*str_read) || *str_read == '.')) && (len == -1 || str_read < string + len)) { if (*str_read == '.') { if (saw_radix) { BSON_DECIMAL128_SET_NAN (*dec); return false; } saw_radix = true; str_read++; continue; } if (ndigits_stored < BSON_DECIMAL128_MAX_DIGITS) { if (*str_read != '0' || found_nonzero) { if (!found_nonzero) { first_nonzero = ndigits_read; } found_nonzero = true; *(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */ ndigits_stored++; } } if (found_nonzero) { ndigits++; } if (saw_radix) { radix_position++; } ndigits_read++; str_read++; } if (saw_radix && !ndigits_read) { BSON_DECIMAL128_SET_NAN (*dec); return false; } /* Read exponent if exists */ if (*str_read == 'e' || *str_read == 'E') { int nread = 0; #ifdef _MSC_VER #define SSCANF sscanf_s #else #define SSCANF sscanf #endif int64_t temp_exponent = 0; int read_exponent = SSCANF (++str_read, "%" SCNd64 "%n", &temp_exponent, &nread); str_read += nread; if (!read_exponent || nread == 0 || !mcommon_in_range_int32_t_signed (temp_exponent)) { BSON_DECIMAL128_SET_NAN (*dec); return false; } exponent = (int32_t) temp_exponent; #undef SSCANF } if ((len == -1 || str_read < string + len) && *str_read) { BSON_DECIMAL128_SET_NAN (*dec); return false; } /* Done reading input. */ /* Find first non-zero digit in digits */ first_digit = 0; if (!ndigits_stored) { /* value is zero */ first_digit = 0; last_digit = 0; digits[0] = 0; ndigits = 1; ndigits_stored = 1; significant_digits = 0; } else { last_digit = ndigits_stored - 1; significant_digits = ndigits; /* Mark trailing zeros as non-significant */ while (string[first_nonzero + significant_digits - 1 + includes_sign + saw_radix] == '0') { significant_digits--; } } /* Normalization of exponent */ /* Correct exponent based on radix position, and shift significand as needed */ /* to represent user input */ /* Overflow prevention */ if (mcommon_cmp_less_equal_su (exponent, radix_position) && mcommon_cmp_greater_us (radix_position, exponent + (1 << 14))) { exponent = BSON_DECIMAL128_EXPONENT_MIN; } else { BSON_ASSERT (mcommon_in_range_unsigned (int32_t, radix_position)); exponent -= (int32_t) radix_position; } /* Attempt to normalize the exponent */ while (exponent > BSON_DECIMAL128_EXPONENT_MAX) { /* Shift exponent to significand and decrease */ last_digit++; if (last_digit - first_digit >= BSON_DECIMAL128_MAX_DIGITS) { /* The exponent is too great to shift into the significand. */ if (significant_digits == 0) { /* Value is zero, we are allowed to clamp the exponent. */ exponent = BSON_DECIMAL128_EXPONENT_MAX; break; } /* Overflow is not permitted, error. */ BSON_DECIMAL128_SET_NAN (*dec); return false; } exponent--; } while (exponent < BSON_DECIMAL128_EXPONENT_MIN || ndigits_stored < ndigits) { /* Shift last digit */ if (last_digit == 0) { /* underflow is not allowed, but zero clamping is */ if (significant_digits == 0) { exponent = BSON_DECIMAL128_EXPONENT_MIN; break; } BSON_DECIMAL128_SET_NAN (*dec); return false; } if (ndigits_stored < ndigits) { if (string[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 && significant_digits != 0) { BSON_DECIMAL128_SET_NAN (*dec); return false; } ndigits--; /* adjust to match digits not stored */ } else { if (digits[last_digit] != 0) { /* Inexact rounding is not allowed. */ BSON_DECIMAL128_SET_NAN (*dec); return false; } last_digit--; /* adjust to round */ } if (exponent < BSON_DECIMAL128_EXPONENT_MAX) { exponent++; } else { BSON_DECIMAL128_SET_NAN (*dec); return false; } } /* Round */ /* We've normalized the exponent, but might still need to round. */ if (last_digit - first_digit + 1 < significant_digits) { uint8_t round_digit; /* There are non-zero digits after last_digit that need rounding. */ /* We round to nearest, ties to even */ round_digit = string[first_nonzero + last_digit + includes_sign + saw_radix + 1] - '0'; if (round_digit != 0) { /* Inexact (non-zero) rounding is not allowed */ BSON_DECIMAL128_SET_NAN (*dec); return false; } } /* Encode significand */ if (significant_digits == 0) { /* read a zero */ significand_high = 0; significand_low = 0; } else if (last_digit - first_digit < 17) { size_t d_idx = first_digit; significand_low = digits[d_idx++]; for (; d_idx <= last_digit; d_idx++) { significand_low *= 10; significand_low += digits[d_idx]; significand_high = 0; } } else { size_t d_idx = first_digit; significand_high = digits[d_idx++]; for (; d_idx <= last_digit - 17; d_idx++) { significand_high *= 10; significand_high += digits[d_idx]; } significand_low = digits[d_idx++]; for (; d_idx <= last_digit; d_idx++) { significand_low *= 10; significand_low += digits[d_idx]; } } _mul_64x64 (significand_high, 100000000000000000ull, &significand); significand.low += significand_low; if (significand.low < significand_low) { significand.high += 1; } biased_exponent = (exponent + (int16_t) BSON_DECIMAL128_EXPONENT_BIAS); /* Encode combination, exponent, and significand. */ if ((significand.high >> 49) & 1) { /* Encode '11' into bits 1 to 3 */ dec->high |= (0x3ull << 61); dec->high |= (biased_exponent & 0x3fffull) << 47; dec->high |= significand.high & 0x7fffffffffffull; } else { dec->high |= (biased_exponent & 0x3fffull) << 49; dec->high |= significand.high & 0x1ffffffffffffull; } dec->low = significand.low; /* Encode sign */ if (is_negative) { dec->high |= 0x8000000000000000ull; } return true; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-decimal128.h0000644000175100001660000000277614760300420021621 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_DECIMAL128_H #define BSON_DECIMAL128_H #include #include #include #include /** * BSON_DECIMAL128_STRING: * * The length of a decimal128 string (with null terminator). * * 1 for the sign * 35 for digits and radix * 2 for exponent indicator and sign * 4 for exponent digits */ #define BSON_DECIMAL128_STRING 43 #define BSON_DECIMAL128_INF "Infinity" #define BSON_DECIMAL128_NAN "NaN" BSON_BEGIN_DECLS BSON_EXPORT (void) bson_decimal128_to_string (const bson_decimal128_t *dec, char *str); /* Note: @string must be ASCII characters only! */ BSON_EXPORT (bool) bson_decimal128_from_string (const char *string, bson_decimal128_t *dec); BSON_EXPORT (bool) bson_decimal128_from_string_w_len (const char *string, int len, bson_decimal128_t *dec); BSON_END_DECLS #endif /* BSON_DECIMAL128_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-endian.h0000644000175100001660000001376214760300420021223 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_ENDIAN_H #define BSON_ENDIAN_H #include #include #include BSON_BEGIN_DECLS #define BSON_BIG_ENDIAN 4321 #define BSON_LITTLE_ENDIAN 1234 #if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && (__clang_major__ >= 3) && \ (__clang_minor__ >= 1) #if __has_builtin(__builtin_bswap16) #define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 (v) #endif #if __has_builtin(__builtin_bswap32) #define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 (v) #endif #if __has_builtin(__builtin_bswap64) #define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 (v) #endif #elif defined(__GNUC__) && (__GNUC__ >= 4) #if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3) #define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 ((uint32_t) v) #define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 ((uint64_t) v) #endif #if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8) #define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 ((uint32_t) v) #endif #endif #ifndef BSON_UINT16_SWAP_LE_BE #define BSON_UINT16_SWAP_LE_BE(v) __bson_uint16_swap_slow ((uint16_t) v) #endif #ifndef BSON_UINT32_SWAP_LE_BE #define BSON_UINT32_SWAP_LE_BE(v) __bson_uint32_swap_slow ((uint32_t) v) #endif #ifndef BSON_UINT64_SWAP_LE_BE #define BSON_UINT64_SWAP_LE_BE(v) __bson_uint64_swap_slow ((uint64_t) v) #endif #if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN #define BSON_UINT16_FROM_LE(v) ((uint16_t) v) #define BSON_UINT16_TO_LE(v) ((uint16_t) v) #define BSON_UINT16_FROM_BE(v) BSON_UINT16_SWAP_LE_BE (v) #define BSON_UINT16_TO_BE(v) BSON_UINT16_SWAP_LE_BE (v) #define BSON_UINT32_FROM_LE(v) ((uint32_t) v) #define BSON_UINT32_TO_LE(v) ((uint32_t) v) #define BSON_UINT32_FROM_BE(v) BSON_UINT32_SWAP_LE_BE (v) #define BSON_UINT32_TO_BE(v) BSON_UINT32_SWAP_LE_BE (v) #define BSON_UINT64_FROM_LE(v) ((uint64_t) v) #define BSON_UINT64_TO_LE(v) ((uint64_t) v) #define BSON_UINT64_FROM_BE(v) BSON_UINT64_SWAP_LE_BE (v) #define BSON_UINT64_TO_BE(v) BSON_UINT64_SWAP_LE_BE (v) #define BSON_DOUBLE_FROM_LE(v) ((double) v) #define BSON_DOUBLE_TO_LE(v) ((double) v) #elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN #define BSON_UINT16_FROM_LE(v) BSON_UINT16_SWAP_LE_BE (v) #define BSON_UINT16_TO_LE(v) BSON_UINT16_SWAP_LE_BE (v) #define BSON_UINT16_FROM_BE(v) ((uint16_t) v) #define BSON_UINT16_TO_BE(v) ((uint16_t) v) #define BSON_UINT32_FROM_LE(v) BSON_UINT32_SWAP_LE_BE (v) #define BSON_UINT32_TO_LE(v) BSON_UINT32_SWAP_LE_BE (v) #define BSON_UINT32_FROM_BE(v) ((uint32_t) v) #define BSON_UINT32_TO_BE(v) ((uint32_t) v) #define BSON_UINT64_FROM_LE(v) BSON_UINT64_SWAP_LE_BE (v) #define BSON_UINT64_TO_LE(v) BSON_UINT64_SWAP_LE_BE (v) #define BSON_UINT64_FROM_BE(v) ((uint64_t) v) #define BSON_UINT64_TO_BE(v) ((uint64_t) v) #define BSON_DOUBLE_FROM_LE(v) (__bson_double_swap_slow (v)) #define BSON_DOUBLE_TO_LE(v) (__bson_double_swap_slow (v)) #else #error "The endianness of target architecture is unknown." #endif /* *-------------------------------------------------------------------------- * * __bson_uint16_swap_slow -- * * Fallback endianness conversion for 16-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static BSON_INLINE uint16_t __bson_uint16_swap_slow (uint16_t v) /* IN */ { return (uint16_t) ((v & 0x00FF) << 8) | (uint16_t) ((v & 0xFF00) >> 8); } /* *-------------------------------------------------------------------------- * * __bson_uint32_swap_slow -- * * Fallback endianness conversion for 32-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static BSON_INLINE uint32_t __bson_uint32_swap_slow (uint32_t v) /* IN */ { return ((v & 0x000000FFU) << 24) | ((v & 0x0000FF00U) << 8) | ((v & 0x00FF0000U) >> 8) | ((v & 0xFF000000U) >> 24); } /* *-------------------------------------------------------------------------- * * __bson_uint64_swap_slow -- * * Fallback endianness conversion for 64-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static BSON_INLINE uint64_t __bson_uint64_swap_slow (uint64_t v) /* IN */ { return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) | ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) | ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) | ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56); } /* *-------------------------------------------------------------------------- * * __bson_double_swap_slow -- * * Fallback endianness conversion for double floating point. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ BSON_STATIC_ASSERT2 (sizeof_uint64_t, sizeof (double) == sizeof (uint64_t)); static BSON_INLINE double __bson_double_swap_slow (double v) /* IN */ { uint64_t uv; memcpy (&uv, &v, sizeof (v)); uv = BSON_UINT64_SWAP_LE_BE (uv); memcpy (&v, &uv, sizeof (v)); return v; } BSON_END_DECLS #endif /* BSON_ENDIAN_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-error.c0000644000175100001660000001371214760300420021104 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include // See `bson_strerror_r()` definition below. #if !defined(_WIN32) && !defined(__APPLE__) #include // uselocale() #endif /* *-------------------------------------------------------------------------- * * bson_set_error -- * * Initializes @error using the parameters specified. * * @domain is an application specific error domain which should * describe which module initiated the error. Think of this as the * exception type. * * @code is the @domain specific error code. * * @format is used to generate the format string. It uses vsnprintf() * internally so the format should match what you would use there. * * Parameters: * @error: A #bson_error_t. * @domain: The error domain. * @code: The error code. * @format: A printf style format string. * * Returns: * None. * * Side effects: * @error is initialized. * *-------------------------------------------------------------------------- */ void bson_set_error (bson_error_t *error, /* OUT */ uint32_t domain, /* IN */ uint32_t code, /* IN */ const char *format, /* IN */ ...) /* IN */ { va_list args; if (error) { error->domain = domain; error->code = code; va_start (args, format); bson_vsnprintf (error->message, sizeof error->message, format, args); va_end (args); error->message[sizeof error->message - 1] = '\0'; } } /* *-------------------------------------------------------------------------- * * bson_strerror_r -- * * This is a reentrant safe macro for strerror. * * The resulting string may be stored in @buf. * * Returns: * A pointer to a static string or @buf. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * bson_strerror_r (int err_code, /* IN */ char *buf BSON_MAYBE_UNUSED, /* IN */ size_t buflen BSON_MAYBE_UNUSED) /* IN */ { static const char *unknown_msg = "Unknown error"; char *ret = NULL; #if defined(_WIN32) // Windows does not provide `strerror_l` or `strerror_r`, but it does // unconditionally provide `strerror_s`. if (strerror_s (buf, buflen, err_code) != 0) { ret = buf; } #elif defined(_AIX) // AIX does not provide strerror_l, and its strerror_r isn't glibc's. // But it does provide a glibc compatible one called __linux_strerror_r ret = __linux_strerror_r (err_code, buf, buflen); #elif defined(__APPLE__) // Apple does not provide `strerror_l`, but it does unconditionally provide // the XSI-compliant `strerror_r`, but only when compiling with Apple Clang. // GNU extensions may still be a problem if we are being compiled with GCC on // Apple. Avoid the compatibility headaches with GNU extensions and the musl // library by assuming the implementation will not cause UB when reading the // error message string even when `strerror_r` fails, as encouraged (but not // required) by the POSIX spec (see: // https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html#tag_16_574_08). (void) strerror_r (err_code, buf, buflen); ret = buf; #elif defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700 // The behavior (of `strerror_l`) is undefined if the locale argument to // `strerror_l()` is the special locale object LC_GLOBAL_LOCALE or is not a // valid locale object handle. locale_t locale = uselocale ((locale_t) 0); // No need to test for error (it can only be [EINVAL]). if (locale == LC_GLOBAL_LOCALE) { // Only use our own locale if a thread-local locale was not already set. // This is just to satisfy `strerror_l`. We do NOT want to unconditionally // set a thread-local locale. locale = newlocale (LC_MESSAGES_MASK, "C", (locale_t) 0); } BSON_ASSERT (locale != LC_GLOBAL_LOCALE); // Avoid `strerror_r` compatibility headaches with GNU extensions and the // musl library by using `strerror_l` instead. Furthermore, `strerror_r` is // scheduled to be marked as obsolete in favor of `strerror_l` in the // upcoming POSIX Issue 8 (see: // https://www.austingroupbugs.net/view.php?id=655). // // POSIX Spec: since strerror_l() is required to return a string for some // errors, an application wishing to check for all error situations should // set errno to 0, then call strerror_l(), then check errno. if (locale != (locale_t) 0) { errno = 0; ret = strerror_l (err_code, locale); if (errno != 0) { ret = NULL; } freelocale (locale); } else { // Could not obtain a valid `locale_t` object to satisfy `strerror_l`. // Fallback to `bson_strncpy` below. } #elif defined(_GNU_SOURCE) // Unlikely, but continue supporting use of GNU extension in cases where the // C Driver is being built without _XOPEN_SOURCE=700. ret = strerror_r (err_code, buf, buflen); #else #error "Unable to find a supported strerror_r candidate" #endif if (!ret) { bson_strncpy (buf, unknown_msg, buflen); ret = buf; } return ret; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-error.h0000644000175100001660000000216214760300420021106 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_ERROR_H #define BSON_ERROR_H #include #include #include BSON_BEGIN_DECLS #define BSON_ERROR_JSON 1 #define BSON_ERROR_READER 2 #define BSON_ERROR_INVALID 3 BSON_EXPORT (void) bson_set_error (bson_error_t *error, uint32_t domain, uint32_t code, const char *format, ...) BSON_GNUC_PRINTF (4, 5); BSON_EXPORT (char *) bson_strerror_r (int err_code, char *buf, size_t buflen); BSON_END_DECLS #endif /* BSON_ERROR_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-iso8601-private.h0000644000175100001660000000170714760300420022542 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_ISO8601_PRIVATE_H #define BSON_ISO8601_PRIVATE_H #include #include #include BSON_BEGIN_DECLS bool _bson_iso8601_date_parse (const char *str, int32_t len, int64_t *out, bson_error_t *error); BSON_END_DECLS #endif /* BSON_ISO8601_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-iso8601.c0000644000175100001660000001725714760300420021074 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include static bool get_tok (const char *terminals, const char **ptr, int32_t *remaining, const char **out, int32_t *out_len) { const char *terminal; bool found_terminal = false; if (!*remaining) { *out = ""; *out_len = 0; } *out = *ptr; *out_len = -1; for (; *remaining && !found_terminal; (*ptr)++, (*remaining)--, (*out_len)++) { for (terminal = terminals; *terminal; terminal++) { if (**ptr == *terminal) { found_terminal = true; break; } } } if (!found_terminal) { (*out_len)++; } return found_terminal; } static bool digits_only (const char *str, int32_t len) { int i; for (i = 0; i < len; i++) { if (!isdigit (str[i])) { return false; } } return true; } static bool parse_num (const char *str, int32_t len, int32_t digits, int32_t min, int32_t max, int32_t *out) { int i; int magnitude = 1; int32_t value = 0; if ((digits >= 0 && len != digits) || !digits_only (str, len)) { return false; } for (i = 1; i <= len; i++, magnitude *= 10) { value += (str[len - i] - '0') * magnitude; } if (value < min || value > max) { return false; } *out = value; return true; } bool _bson_iso8601_date_parse (const char *str, int32_t len, int64_t *out, bson_error_t *error) { const char *ptr; int32_t remaining = len; const char *year_ptr = NULL; const char *month_ptr = NULL; const char *day_ptr = NULL; const char *hour_ptr = NULL; const char *min_ptr = NULL; const char *sec_ptr = NULL; const char *millis_ptr = NULL; const char *tz_ptr = NULL; int32_t year_len = 0; int32_t month_len = 0; int32_t day_len = 0; int32_t hour_len = 0; int32_t min_len = 0; int32_t sec_len = 0; int32_t millis_len = 0; int32_t tz_len = 0; int32_t year; int32_t month; int32_t day; int32_t hour; int32_t min; int32_t sec = 0; int64_t millis = 0; int32_t tz_adjustment = 0; struct bson_tm posix_date = {0}; #define DATE_PARSE_ERR(msg) \ bson_set_error ( \ error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_INVALID_PARAM, "Could not parse \"%s\" as date: " msg, str); \ return false #define DEFAULT_DATE_PARSE_ERR \ DATE_PARSE_ERR ("use ISO8601 format yyyy-mm-ddThh:mm plus timezone, either" \ " \"Z\" or like \"+0500\" or like \"+05:00\"") ptr = str; /* we have to match at least yyyy-mm-ddThh:mm */ if (!(get_tok ("-", &ptr, &remaining, &year_ptr, &year_len) && get_tok ("-", &ptr, &remaining, &month_ptr, &month_len) && get_tok ("T", &ptr, &remaining, &day_ptr, &day_len) && get_tok (":", &ptr, &remaining, &hour_ptr, &hour_len) && get_tok (":+-Z", &ptr, &remaining, &min_ptr, &min_len))) { DEFAULT_DATE_PARSE_ERR; } /* if the minute has a ':' at the end look for seconds */ if (min_ptr[min_len] == ':') { if (remaining < 2) { DATE_PARSE_ERR ("reached end of date while looking for seconds"); } get_tok (".+-Z", &ptr, &remaining, &sec_ptr, &sec_len); if (!sec_len) { DATE_PARSE_ERR ("minute ends in \":\" seconds is required"); } } /* if we had a second and it is followed by a '.' look for milliseconds */ if (sec_len && sec_ptr[sec_len] == '.') { if (remaining < 2) { DATE_PARSE_ERR ("reached end of date while looking for milliseconds"); } get_tok ("+-Z", &ptr, &remaining, &millis_ptr, &millis_len); if (!millis_len) { DATE_PARSE_ERR ("seconds ends in \".\", milliseconds is required"); } } /* backtrack by 1 to put ptr on the timezone */ ptr--; remaining++; get_tok ("", &ptr, &remaining, &tz_ptr, &tz_len); if (!parse_num (year_ptr, year_len, 4, -9999, 9999, &year)) { DATE_PARSE_ERR ("year must be an integer"); } /* values are as in struct tm */ year -= 1900; if (!parse_num (month_ptr, month_len, 2, 1, 12, &month)) { DATE_PARSE_ERR ("month must be an integer"); } /* values are as in struct tm */ month -= 1; if (!parse_num (day_ptr, day_len, 2, 1, 31, &day)) { DATE_PARSE_ERR ("day must be an integer"); } if (!parse_num (hour_ptr, hour_len, 2, 0, 23, &hour)) { DATE_PARSE_ERR ("hour must be an integer"); } if (!parse_num (min_ptr, min_len, 2, 0, 59, &min)) { DATE_PARSE_ERR ("minute must be an integer"); } if (sec_len && !parse_num (sec_ptr, sec_len, 2, 0, 60, &sec)) { DATE_PARSE_ERR ("seconds must be an integer"); } if (tz_len > 0) { if (tz_ptr[0] == 'Z' && tz_len == 1) { /* valid */ } else if (tz_ptr[0] == '+' || tz_ptr[0] == '-') { int32_t tz_hour; int32_t tz_min; if ((tz_len != 5 || !digits_only (tz_ptr + 1, 4)) && (tz_len != 6 || !digits_only (tz_ptr + 1, 2) || tz_ptr[3] != ':' || !digits_only (tz_ptr + 4, 2))) { DATE_PARSE_ERR ("could not parse timezone"); } if (!parse_num (tz_ptr + 1, 2, -1, -23, 23, &tz_hour)) { DATE_PARSE_ERR ("timezone hour must be at most 23"); } int32_t tz_min_offset = tz_ptr[3] == ':' ? 1 : 0; if (!parse_num (tz_ptr + 3 + tz_min_offset, 2, -1, 0, 59, &tz_min)) { DATE_PARSE_ERR ("timezone minute must be at most 59"); } /* we inflect the meaning of a 'positive' timezone. Those are hours * we have to subtract, and vice versa */ tz_adjustment = (tz_ptr[0] == '-' ? 1 : -1) * ((tz_min * 60) + (tz_hour * 60 * 60)); if (!(tz_adjustment > -86400 && tz_adjustment < 86400)) { DATE_PARSE_ERR ("timezone offset must be less than 24 hours"); } } else { DATE_PARSE_ERR ("timezone is required"); } } if (millis_len > 0) { int i; int magnitude; millis = 0; if (millis_len > 3 || !digits_only (millis_ptr, millis_len)) { DATE_PARSE_ERR ("milliseconds must be an integer"); } for (i = 1, magnitude = 1; i <= millis_len; i++, magnitude *= 10) { millis += (millis_ptr[millis_len - i] - '0') * magnitude; } if (millis_len == 1) { millis *= 100; } else if (millis_len == 2) { millis *= 10; } if (millis < 0 || millis > 1000) { DATE_PARSE_ERR ("milliseconds must be at least 0 and less than 1000"); } } posix_date.tm_sec = sec; posix_date.tm_min = min; posix_date.tm_hour = hour; posix_date.tm_mday = day; posix_date.tm_mon = month; posix_date.tm_year = year; posix_date.tm_wday = 0; posix_date.tm_yday = 0; millis = 1000 * _bson_timegm (&posix_date) + millis; millis += tz_adjustment * 1000; *out = millis; return true; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-iter.c0000644000175100001660000017012314760300420020716 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #define ITER_TYPE(i) ((bson_type_t) * ((i)->raw + (i)->type)) /* *-------------------------------------------------------------------------- * * bson_iter_init -- * * Initializes @iter to be used to iterate @bson. * * Returns: * true if bson_iter_t was initialized. otherwise false. * * Side effects: * @iter is initialized. * *-------------------------------------------------------------------------- */ bool bson_iter_init (bson_iter_t *iter, /* OUT */ const bson_t *bson) /* IN */ { BSON_ASSERT (iter); BSON_ASSERT (bson); if (BSON_UNLIKELY (bson->len < 5)) { memset (iter, 0, sizeof *iter); return false; } iter->raw = bson_get_data (bson); iter->len = bson->len; iter->off = 0; iter->type = 0; iter->key = 0; iter->d1 = 0; iter->d2 = 0; iter->d3 = 0; iter->d4 = 0; iter->next_off = 4; iter->err_off = 0; iter->value = (bson_value_t){0}; return true; } /* *-------------------------------------------------------------------------- * * bson_iter_init_from_data -- * * Initializes @iter to be used to iterate @data of length @length * * Returns: * true if bson_iter_t was initialized. otherwise false. * * Side effects: * @iter is initialized. * *-------------------------------------------------------------------------- */ bool bson_iter_init_from_data (bson_iter_t *iter, /* OUT */ const uint8_t *data, /* IN */ size_t length) /* IN */ { uint32_t len_le; BSON_ASSERT (iter); BSON_ASSERT (data); if (BSON_UNLIKELY ((length < 5) || (length > INT_MAX))) { memset (iter, 0, sizeof *iter); return false; } memcpy (&len_le, data, sizeof (len_le)); if (BSON_UNLIKELY ((size_t) BSON_UINT32_FROM_LE (len_le) != length)) { memset (iter, 0, sizeof *iter); return false; } if (BSON_UNLIKELY (data[length - 1])) { memset (iter, 0, sizeof *iter); return false; } if (BSON_UNLIKELY (!mcommon_in_range_unsigned (uint32_t, length))) { memset (iter, 0, sizeof *iter); return false; } iter->raw = (uint8_t *) data; iter->len = (uint32_t) length; iter->off = 0; iter->type = 0; iter->key = 0; iter->d1 = 0; iter->d2 = 0; iter->d3 = 0; iter->d4 = 0; iter->next_off = 4; iter->err_off = 0; return true; } /* *-------------------------------------------------------------------------- * * bson_iter_recurse -- * * Creates a new sub-iter looking at the document or array that @iter * is currently pointing at. * * Returns: * true if successful and @child was initialized. * * Side effects: * @child is initialized. * *-------------------------------------------------------------------------- */ bool bson_iter_recurse (const bson_iter_t *iter, /* IN */ bson_iter_t *child) /* OUT */ { const uint8_t *data = NULL; uint32_t len = 0; BSON_ASSERT (iter); BSON_ASSERT (child); if (ITER_TYPE (iter) == BSON_TYPE_DOCUMENT) { bson_iter_document (iter, &len, &data); } else if (ITER_TYPE (iter) == BSON_TYPE_ARRAY) { bson_iter_array (iter, &len, &data); } else { return false; } child->raw = data; child->len = len; child->off = 0; child->type = 0; child->key = 0; child->d1 = 0; child->d2 = 0; child->d3 = 0; child->d4 = 0; child->next_off = 4; child->err_off = 0; return true; } /* *-------------------------------------------------------------------------- * * bson_iter_init_find -- * * Initializes a #bson_iter_t and moves the iter to the first field * matching @key. * * Returns: * true if the field named @key was found; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_init_find (bson_iter_t *iter, /* INOUT */ const bson_t *bson, /* IN */ const char *key) /* IN */ { BSON_ASSERT (iter); BSON_ASSERT (bson); BSON_ASSERT (key); return bson_iter_init (iter, bson) && bson_iter_find (iter, key); } /* *-------------------------------------------------------------------------- * * bson_iter_init_find_w_len -- * * Initializes a #bson_iter_t and moves the iter to the first field * matching @key. * * Returns: * true if the field named @key was found; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_init_find_w_len (bson_iter_t *iter, /* INOUT */ const bson_t *bson, /* IN */ const char *key, /* IN */ int keylen) /* IN */ { BSON_ASSERT (iter); BSON_ASSERT (bson); BSON_ASSERT (key); return bson_iter_init (iter, bson) && bson_iter_find_w_len (iter, key, keylen); } /* *-------------------------------------------------------------------------- * * bson_iter_init_find_case -- * * A case-insensitive version of bson_iter_init_find(). * * Returns: * true if the field was found and @iter is observing that field. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_init_find_case (bson_iter_t *iter, /* INOUT */ const bson_t *bson, /* IN */ const char *key) /* IN */ { BSON_ASSERT (iter); BSON_ASSERT (bson); BSON_ASSERT (key); return bson_iter_init (iter, bson) && bson_iter_find_case (iter, key); } /* *-------------------------------------------------------------------------- * * bson_iter_find_w_len -- * * Searches through @iter starting from the current position for a key * matching @key. @keylen indicates the length of @key, or -1 to * determine the length with strlen(). * * Returns: * true if the field @key was found. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_find_w_len (bson_iter_t *iter, /* INOUT */ const char *key, /* IN */ int keylen) /* IN */ { const char *ikey; if (keylen < 0) { keylen = (int) strlen (key); } while (bson_iter_next (iter)) { ikey = bson_iter_key (iter); if ((0 == strncmp (key, ikey, keylen)) && (ikey[keylen] == '\0')) { return true; } } return false; } /* *-------------------------------------------------------------------------- * * bson_iter_find -- * * Searches through @iter starting from the current position for a key * matching @key. This is a case-sensitive search meaning "KEY" and * "key" would NOT match. * * Returns: * true if @key is found. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_find (bson_iter_t *iter, /* INOUT */ const char *key) /* IN */ { BSON_ASSERT (iter); BSON_ASSERT (key); return bson_iter_find_w_len (iter, key, -1); } /* *-------------------------------------------------------------------------- * * bson_iter_find_case -- * * Searches through @iter starting from the current position for a key * matching @key. This is a case-insensitive search meaning "KEY" and * "key" would match. * * Returns: * true if @key is found. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_find_case (bson_iter_t *iter, /* INOUT */ const char *key) /* IN */ { BSON_ASSERT (iter); BSON_ASSERT (key); while (bson_iter_next (iter)) { if (!bson_strcasecmp (key, bson_iter_key (iter))) { return true; } } return false; } /* *-------------------------------------------------------------------------- * * bson_iter_find_descendant -- * * Locates a descendant using the "parent.child.key" notation. This * operates similar to bson_iter_find() except that it can recurse * into children documents using the dot notation. * * Returns: * true if the descendant was found and @descendant was initialized. * * Side effects: * @descendant may be initialized. * *-------------------------------------------------------------------------- */ bool bson_iter_find_descendant (bson_iter_t *iter, /* INOUT */ const char *dotkey, /* IN */ bson_iter_t *descendant) /* OUT */ { bson_iter_t tmp; const char *dot; size_t sublen; BSON_ASSERT (iter); BSON_ASSERT (dotkey); BSON_ASSERT (descendant); if ((dot = strchr (dotkey, '.'))) { sublen = dot - dotkey; } else { sublen = strlen (dotkey); } if (bson_iter_find_w_len (iter, dotkey, (int) sublen)) { if (!dot) { *descendant = *iter; return true; } if (BSON_ITER_HOLDS_DOCUMENT (iter) || BSON_ITER_HOLDS_ARRAY (iter)) { if (bson_iter_recurse (iter, &tmp)) { return bson_iter_find_descendant (&tmp, dot + 1, descendant); } } } return false; } /* *-------------------------------------------------------------------------- * * bson_iter_key -- * * Retrieves the key of the current field. The resulting key is valid * while @iter is valid. * * Returns: * A string that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const char * bson_iter_key (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); return bson_iter_key_unsafe (iter); } /* *-------------------------------------------------------------------------- * * bson_iter_type -- * * Retrieves the type of the current field. It may be useful to check * the type using the BSON_ITER_HOLDS_*() macros. * * Returns: * A bson_type_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bson_type_t bson_iter_type (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); BSON_ASSERT (iter->raw); BSON_ASSERT (iter->len); return bson_iter_type_unsafe (iter); } /* *-------------------------------------------------------------------------- * * _bson_iter_next_internal -- * * Internal function to advance @iter to the next field and retrieve * the key and BSON type before error-checking. @next_keylen is * the key length of the next field being iterated or 0 if this is * not known. * * Return: * true if an element was decoded, else false. * * Side effects: * @key and @bson_type are set. * * If the return value is false: * - @iter is invalidated: @iter->raw is NULLed * - @unsupported is set to true if the bson type is unsupported * - otherwise if the BSON is corrupt, @iter->err_off is nonzero * - otherwise @bson_type is set to BSON_TYPE_EOD * *-------------------------------------------------------------------------- */ static bool _bson_iter_next_internal (bson_iter_t *iter, /* INOUT */ uint32_t next_keylen, /* IN */ const char **key, /* OUT */ uint32_t *bson_type, /* OUT */ bool *unsupported) /* OUT */ { const uint8_t *data; uint32_t o; unsigned int len; BSON_ASSERT (iter); *unsupported = false; if (!iter->raw) { *key = NULL; *bson_type = BSON_TYPE_EOD; return false; } data = iter->raw; len = iter->len; iter->off = iter->next_off; iter->type = iter->off; iter->key = iter->off + 1; iter->d1 = 0; iter->d2 = 0; iter->d3 = 0; iter->d4 = 0; if (next_keylen == 0) { /* iterate from start to end of NULL-terminated key string */ for (o = iter->key; o < len; o++) { if (!data[o]) { iter->d1 = ++o; goto fill_data_fields; } } } else { o = iter->key + next_keylen + 1; iter->d1 = o; goto fill_data_fields; } goto mark_invalid; fill_data_fields: *key = bson_iter_key_unsafe (iter); *bson_type = ITER_TYPE (iter); switch (*bson_type) { case BSON_TYPE_DATE_TIME: case BSON_TYPE_DOUBLE: case BSON_TYPE_INT64: case BSON_TYPE_TIMESTAMP: iter->next_off = o + 8; break; case BSON_TYPE_CODE: case BSON_TYPE_SYMBOL: case BSON_TYPE_UTF8: { uint32_t l; if ((o + 4) >= len) { iter->err_off = o; goto mark_invalid; } iter->d2 = o + 4; memcpy (&l, iter->raw + iter->d1, sizeof (l)); l = BSON_UINT32_FROM_LE (l); if (l > (len - (o + 4))) { iter->err_off = o; goto mark_invalid; } iter->next_off = o + 4 + l; /* * Make sure the string length includes the NUL byte. */ if (BSON_UNLIKELY ((l == 0) || (iter->next_off >= len))) { iter->err_off = o; goto mark_invalid; } /* * Make sure the last byte is a NUL byte. */ if (BSON_UNLIKELY ((iter->raw + iter->d2)[l - 1] != '\0')) { iter->err_off = o + 4 + l - 1; goto mark_invalid; } } break; case BSON_TYPE_BINARY: { bson_subtype_t subtype; uint32_t l; if (o >= (len - 4)) { iter->err_off = o; goto mark_invalid; } iter->d2 = o + 4; iter->d3 = o + 5; memcpy (&l, iter->raw + iter->d1, sizeof (l)); l = BSON_UINT32_FROM_LE (l); if (l >= (len - o - 4)) { iter->err_off = o; goto mark_invalid; } subtype = *(iter->raw + iter->d2); if (subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { int32_t binary_len; if (l < 4) { iter->err_off = o; goto mark_invalid; } /* subtype 2 has a redundant length header in the data */ memcpy (&binary_len, (iter->raw + iter->d3), sizeof (binary_len)); binary_len = BSON_UINT32_FROM_LE (binary_len); if (binary_len != l - 4) { iter->err_off = iter->d3; goto mark_invalid; } } iter->next_off = o + 5 + l; } break; case BSON_TYPE_ARRAY: case BSON_TYPE_DOCUMENT: { uint32_t l; if (o >= (len - 4)) { iter->err_off = o; goto mark_invalid; } memcpy (&l, iter->raw + iter->d1, sizeof (l)); l = BSON_UINT32_FROM_LE (l); if ((l > len) || (l > (len - o))) { iter->err_off = o; goto mark_invalid; } iter->next_off = o + l; } break; case BSON_TYPE_OID: iter->next_off = o + 12; break; case BSON_TYPE_BOOL: { char val; if (iter->d1 >= len) { iter->err_off = o; goto mark_invalid; } memcpy (&val, iter->raw + iter->d1, 1); if (val != 0x00 && val != 0x01) { iter->err_off = o; goto mark_invalid; } iter->next_off = o + 1; } break; case BSON_TYPE_REGEX: { bool eor = false; bool eoo = false; for (; o < len; o++) { if (!data[o]) { iter->d2 = ++o; eor = true; break; } } if (!eor) { iter->err_off = iter->next_off; goto mark_invalid; } for (; o < len; o++) { if (!data[o]) { eoo = true; break; } } if (!eoo) { iter->err_off = iter->next_off; goto mark_invalid; } iter->next_off = o + 1; } break; case BSON_TYPE_DBPOINTER: { uint32_t l; if (o >= (len - 4)) { iter->err_off = o; goto mark_invalid; } iter->d2 = o + 4; memcpy (&l, iter->raw + iter->d1, sizeof (l)); l = BSON_UINT32_FROM_LE (l); /* Check valid string length. l counts '\0' but not 4 bytes for itself. */ if (l == 0 || l > (len - o - 4)) { iter->err_off = o; goto mark_invalid; } if (*(iter->raw + o + l + 3)) { /* not null terminated */ iter->err_off = o + l + 3; goto mark_invalid; } iter->d3 = o + 4 + l; iter->next_off = o + 4 + l + 12; } break; case BSON_TYPE_CODEWSCOPE: { uint32_t l; uint32_t doclen; if ((len < 19) || (o >= (len - 14))) { iter->err_off = o; goto mark_invalid; } iter->d2 = o + 4; iter->d3 = o + 8; memcpy (&l, iter->raw + iter->d1, sizeof (l)); l = BSON_UINT32_FROM_LE (l); if ((l < 14) || (l >= (len - o))) { iter->err_off = o; goto mark_invalid; } iter->next_off = o + l; if (iter->next_off >= len) { iter->err_off = o; goto mark_invalid; } memcpy (&l, iter->raw + iter->d2, sizeof (l)); l = BSON_UINT32_FROM_LE (l); if (l == 0 || l >= (len - o - 4 - 4)) { iter->err_off = o; goto mark_invalid; } if ((o + 4 + 4 + l + 4) >= iter->next_off) { iter->err_off = o + 4; goto mark_invalid; } iter->d4 = o + 4 + 4 + l; memcpy (&doclen, iter->raw + iter->d4, sizeof (doclen)); doclen = BSON_UINT32_FROM_LE (doclen); if ((o + 4 + 4 + l + doclen) != iter->next_off) { iter->err_off = o + 4 + 4 + l; goto mark_invalid; } } break; case BSON_TYPE_INT32: iter->next_off = o + 4; break; case BSON_TYPE_DECIMAL128: iter->next_off = o + 16; break; case BSON_TYPE_MAXKEY: case BSON_TYPE_MINKEY: case BSON_TYPE_NULL: case BSON_TYPE_UNDEFINED: iter->next_off = o; break; default: *unsupported = true; /* FALL THROUGH */ case BSON_TYPE_EOD: iter->err_off = o; goto mark_invalid; } /* * Check to see if any of the field locations would overflow the * current BSON buffer. If so, set the error location to the offset * of where the field starts. */ if (iter->next_off >= len) { iter->err_off = o; goto mark_invalid; } iter->err_off = 0; return true; mark_invalid: iter->raw = NULL; iter->len = 0; iter->next_off = 0; return false; } /* *-------------------------------------------------------------------------- * * bson_iter_next -- * * Advances @iter to the next field of the underlying BSON document. * If all fields have been exhausted, then %false is returned. * * It is a programming error to use @iter after this function has * returned false. * * Returns: * true if the iter was advanced to the next record. * otherwise false and @iter should be considered invalid. * * Side effects: * @iter may be invalidated. * *-------------------------------------------------------------------------- */ bool bson_iter_next (bson_iter_t *iter) /* INOUT */ { uint32_t bson_type; const char *key; bool unsupported; return _bson_iter_next_internal (iter, 0, &key, &bson_type, &unsupported); } /* *-------------------------------------------------------------------------- * * bson_iter_binary -- * * Retrieves the BSON_TYPE_BINARY field. The subtype is stored in * @subtype. The length of @binary in bytes is stored in @binary_len. * * @binary should not be modified or freed and is only valid while * @iter's bson_t is valid and unmodified. * * Parameters: * @iter: A bson_iter_t * @subtype: A location for the binary subtype. * @binary_len: A location for the length of @binary. * @binary: A location for a pointer to the binary data. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_iter_binary (const bson_iter_t *iter, /* IN */ bson_subtype_t *subtype, /* OUT */ uint32_t *binary_len, /* OUT */ const uint8_t **binary) /* OUT */ { bson_subtype_t backup; BSON_ASSERT (iter); BSON_ASSERT (!binary || binary_len); if (ITER_TYPE (iter) == BSON_TYPE_BINARY) { if (!subtype) { subtype = &backup; } *subtype = (bson_subtype_t) * (iter->raw + iter->d2); if (binary) { memcpy (binary_len, (iter->raw + iter->d1), sizeof (*binary_len)); *binary_len = BSON_UINT32_FROM_LE (*binary_len); *binary = iter->raw + iter->d3; if (*subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { *binary_len -= sizeof (int32_t); *binary += sizeof (int32_t); } } return; } if (binary) { *binary = NULL; } if (binary_len) { *binary_len = 0; } if (subtype) { *subtype = BSON_SUBTYPE_BINARY; } } /* *-------------------------------------------------------------------------- * * bson_iter_bool -- * * Retrieves the current field of type BSON_TYPE_BOOL. * * Returns: * true or false, dependent on bson document. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_bool (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_BOOL) { return bson_iter_bool_unsafe (iter); } return false; } /* *-------------------------------------------------------------------------- * * bson_iter_as_bool -- * * If @iter is on a boolean field, returns the boolean. If it is on a * non-boolean field such as int32, int64, or double, it will convert * the value to a boolean. * * Zero is false, and non-zero is true. * * Returns: * true or false, dependent on field type. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_as_bool (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); switch ((int) ITER_TYPE (iter)) { case BSON_TYPE_BOOL: return bson_iter_bool (iter); case BSON_TYPE_DOUBLE: return !(bson_iter_double (iter) == 0.0); case BSON_TYPE_INT64: return !(bson_iter_int64 (iter) == 0); case BSON_TYPE_INT32: return !(bson_iter_int32 (iter) == 0); case BSON_TYPE_UTF8: return true; case BSON_TYPE_NULL: case BSON_TYPE_UNDEFINED: return false; default: return true; } } /* *-------------------------------------------------------------------------- * * bson_iter_double -- * * Retrieves the current field of type BSON_TYPE_DOUBLE. * * Returns: * A double. * * Side effects: * None. * *-------------------------------------------------------------------------- */ double bson_iter_double (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_DOUBLE) { return bson_iter_double_unsafe (iter); } return 0; } /* *-------------------------------------------------------------------------- * * bson_iter_as_double -- * * If @iter is on a field of type BSON_TYPE_DOUBLE, * returns the double. If it is on an integer field * such as int32, int64, or bool, it will convert * the value to a double. * * * Returns: * A double. * * Side effects: * None. * *-------------------------------------------------------------------------- */ double bson_iter_as_double (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); switch ((int) ITER_TYPE (iter)) { case BSON_TYPE_BOOL: return (double) bson_iter_bool (iter); case BSON_TYPE_DOUBLE: return bson_iter_double (iter); case BSON_TYPE_INT32: return (double) bson_iter_int32 (iter); case BSON_TYPE_INT64: return (double) bson_iter_int64 (iter); default: return 0; } } /* *-------------------------------------------------------------------------- * * bson_iter_int32 -- * * Retrieves the value of the field of type BSON_TYPE_INT32. * * Returns: * A 32-bit signed integer. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int32_t bson_iter_int32 (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_INT32) { return bson_iter_int32_unsafe (iter); } return 0; } /* *-------------------------------------------------------------------------- * * bson_iter_int64 -- * * Retrieves a 64-bit signed integer for the current BSON_TYPE_INT64 * field. * * Returns: * A 64-bit signed integer. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int64_t bson_iter_int64 (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_INT64) { return bson_iter_int64_unsafe (iter); } return 0; } /* *-------------------------------------------------------------------------- * * bson_iter_as_int64 -- * * If @iter is not an int64 field, it will try to convert the value to * an int64. Such field types include: * * - bool * - double * - int32 * * Returns: * An int64_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int64_t bson_iter_as_int64 (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); switch ((int) ITER_TYPE (iter)) { case BSON_TYPE_BOOL: return (int64_t) bson_iter_bool (iter); case BSON_TYPE_DOUBLE: return (int64_t) bson_iter_double (iter); case BSON_TYPE_INT64: return bson_iter_int64 (iter); case BSON_TYPE_INT32: return (int64_t) bson_iter_int32 (iter); default: return 0; } } /* *-------------------------------------------------------------------------- * * bson_iter_decimal128 -- * * This function retrieves the current field of type *%BSON_TYPE_DECIMAL128. * The result is valid while @iter is valid, and is stored in @dec. * * Returns: * * True on success, false on failure. * * Side Effects: * None. * *-------------------------------------------------------------------------- */ bool bson_iter_decimal128 (const bson_iter_t *iter, /* IN */ bson_decimal128_t *dec) /* OUT */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_DECIMAL128) { bson_iter_decimal128_unsafe (iter, dec); return true; } return false; } /* *-------------------------------------------------------------------------- * * bson_iter_oid -- * * Retrieves the current field of type %BSON_TYPE_OID. The result is * valid while @iter is valid. * * Returns: * A bson_oid_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const bson_oid_t * bson_iter_oid (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_OID) { return bson_iter_oid_unsafe (iter); } return NULL; } /* *-------------------------------------------------------------------------- * * bson_iter_regex -- * * Fetches the current field from the iter which should be of type * BSON_TYPE_REGEX. * * Returns: * Regex from @iter. This should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const char * bson_iter_regex (const bson_iter_t *iter, /* IN */ const char **options) /* IN */ { const char *ret = NULL; const char *ret_options = NULL; BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_REGEX) { ret = (const char *) (iter->raw + iter->d1); ret_options = (const char *) (iter->raw + iter->d2); } if (options) { *options = ret_options; } return ret; } /* *-------------------------------------------------------------------------- * * bson_iter_utf8 -- * * Retrieves the current field of type %BSON_TYPE_UTF8 as a UTF-8 * encoded string. * * Parameters: * @iter: A bson_iter_t. * @length: A location for the length of the string. * * Returns: * A string that should not be modified or freed. * * Side effects: * @length will be set to the result strings length if non-NULL. * *-------------------------------------------------------------------------- */ const char * bson_iter_utf8 (const bson_iter_t *iter, /* IN */ uint32_t *length) /* OUT */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_UTF8) { if (length) { *length = bson_iter_utf8_len_unsafe (iter); } return (const char *) (iter->raw + iter->d2); } if (length) { *length = 0; } return NULL; } /* *-------------------------------------------------------------------------- * * bson_iter_dup_utf8 -- * * Copies the current UTF-8 element into a newly allocated string. The * string should be freed using bson_free() when the caller is * finished with it. * * Returns: * A newly allocated char* that should be freed with bson_free(). * * Side effects: * @length will be set to the result strings length if non-NULL. * *-------------------------------------------------------------------------- */ char * bson_iter_dup_utf8 (const bson_iter_t *iter, /* IN */ uint32_t *length) /* OUT */ { uint32_t local_length = 0; const char *str; char *ret = NULL; BSON_ASSERT (iter); if ((str = bson_iter_utf8 (iter, &local_length))) { ret = bson_malloc0 (local_length + 1); memcpy (ret, str, local_length); ret[local_length] = '\0'; } if (length) { *length = local_length; } return ret; } /* *-------------------------------------------------------------------------- * * bson_iter_code -- * * Retrieves the current field of type %BSON_TYPE_CODE. The length of * the resulting string is stored in @length. * * Parameters: * @iter: A bson_iter_t. * @length: A location for the code length. * * Returns: * A NUL-terminated string containing the code which should not be * modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const char * bson_iter_code (const bson_iter_t *iter, /* IN */ uint32_t *length) /* OUT */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_CODE) { if (length) { *length = bson_iter_utf8_len_unsafe (iter); } return (const char *) (iter->raw + iter->d2); } if (length) { *length = 0; } return NULL; } /* *-------------------------------------------------------------------------- * * bson_iter_codewscope -- * * Similar to bson_iter_code() but with a scope associated encoded as * a BSON document. @scope should not be modified or freed. It is * valid while @iter is valid. * * Parameters: * @iter: A #bson_iter_t. * @length: A location for the length of resulting string. * @scope_len: A location for the length of @scope. * @scope: A location for the scope encoded as BSON. * * Returns: * A NUL-terminated string that should not be modified or freed. * * Side effects: * @length is set to the resulting string length in bytes. * @scope_len is set to the length of @scope in bytes. * @scope is set to the scope documents buffer which can be * turned into a bson document with bson_init_static(). * *-------------------------------------------------------------------------- */ const char * bson_iter_codewscope (const bson_iter_t *iter, /* IN */ uint32_t *length, /* OUT */ uint32_t *scope_len, /* OUT */ const uint8_t **scope) /* OUT */ { uint32_t len; BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_CODEWSCOPE) { if (length) { memcpy (&len, iter->raw + iter->d2, sizeof (len)); /* The string length was checked > 0 in _bson_iter_next_internal. */ len = BSON_UINT32_FROM_LE (len); BSON_ASSERT (len > 0); *length = len - 1; } memcpy (&len, iter->raw + iter->d4, sizeof (len)); *scope_len = BSON_UINT32_FROM_LE (len); *scope = iter->raw + iter->d4; return (const char *) (iter->raw + iter->d3); } if (length) { *length = 0; } if (scope_len) { *scope_len = 0; } if (scope) { *scope = NULL; } return NULL; } /* *-------------------------------------------------------------------------- * * bson_iter_dbpointer -- * * Retrieves a BSON_TYPE_DBPOINTER field. @collection_len will be set * to the length of the collection name. The collection name will be * placed into @collection. The oid will be placed into @oid. * * @collection and @oid should not be modified. * * Parameters: * @iter: A #bson_iter_t. * @collection_len: A location for the length of @collection. * @collection: A location for the collection name. * @oid: A location for the oid. * * Returns: * None. * * Side effects: * @collection_len is set to the length of @collection in bytes * excluding the null byte. * @collection is set to the collection name, including a terminating * null byte. * @oid is initialized with the oid. * *-------------------------------------------------------------------------- */ void bson_iter_dbpointer (const bson_iter_t *iter, /* IN */ uint32_t *collection_len, /* OUT */ const char **collection, /* OUT */ const bson_oid_t **oid) /* OUT */ { BSON_ASSERT (iter); if (collection) { *collection = NULL; } if (oid) { *oid = NULL; } if (ITER_TYPE (iter) == BSON_TYPE_DBPOINTER) { if (collection_len) { memcpy (collection_len, (iter->raw + iter->d1), sizeof (*collection_len)); *collection_len = BSON_UINT32_FROM_LE (*collection_len); if ((*collection_len) > 0) { (*collection_len)--; } } if (collection) { *collection = (const char *) (iter->raw + iter->d2); } if (oid) { *oid = (const bson_oid_t *) (iter->raw + iter->d3); } } } /* *-------------------------------------------------------------------------- * * bson_iter_symbol -- * * Retrieves the symbol of the current field of type BSON_TYPE_SYMBOL. * * Parameters: * @iter: A bson_iter_t. * @length: A location for the length of the symbol. * * Returns: * A string containing the symbol as UTF-8. The value should not be * modified or freed. * * Side effects: * @length is set to the resulting strings length in bytes, * excluding the null byte. * *-------------------------------------------------------------------------- */ const char * bson_iter_symbol (const bson_iter_t *iter, /* IN */ uint32_t *length) /* OUT */ { const char *ret = NULL; uint32_t ret_length = 0; BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_SYMBOL) { ret = (const char *) (iter->raw + iter->d2); ret_length = bson_iter_utf8_len_unsafe (iter); } if (length) { *length = ret_length; } return ret; } /* *-------------------------------------------------------------------------- * * bson_iter_date_time -- * * Fetches the number of milliseconds elapsed since the UNIX epoch. * This value can be negative as times before 1970 are valid. * * Returns: * A signed 64-bit integer containing the number of milliseconds. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int64_t bson_iter_date_time (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { return bson_iter_int64_unsafe (iter); } return 0; } /* *-------------------------------------------------------------------------- * * bson_iter_time_t -- * * Retrieves the current field of type BSON_TYPE_DATE_TIME as a * time_t. * * Returns: * A #time_t of the number of seconds since UNIX epoch in UTC. * * Side effects: * None. * *-------------------------------------------------------------------------- */ time_t bson_iter_time_t (const bson_iter_t *iter) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { return bson_iter_time_t_unsafe (iter); } return 0; } /* *-------------------------------------------------------------------------- * * bson_iter_timestamp -- * * Fetches the current field if it is a BSON_TYPE_TIMESTAMP. * * Parameters: * @iter: A #bson_iter_t. * @timestamp: a location for the timestamp. * @increment: A location for the increment. * * Returns: * None. * * Side effects: * @timestamp is initialized. * @increment is initialized. * *-------------------------------------------------------------------------- */ void bson_iter_timestamp (const bson_iter_t *iter, /* IN */ uint32_t *timestamp, /* OUT */ uint32_t *increment) /* OUT */ { uint64_t encoded; uint32_t ret_timestamp = 0; uint32_t ret_increment = 0; BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_TIMESTAMP) { memcpy (&encoded, iter->raw + iter->d1, sizeof (encoded)); encoded = BSON_UINT64_FROM_LE (encoded); ret_timestamp = (encoded >> 32) & 0xFFFFFFFF; ret_increment = encoded & 0xFFFFFFFF; } if (timestamp) { *timestamp = ret_timestamp; } if (increment) { *increment = ret_increment; } } /* *-------------------------------------------------------------------------- * * bson_iter_timeval -- * * Retrieves the current field of type BSON_TYPE_DATE_TIME and stores * it into the struct timeval provided. tv->tv_sec is set to the * number of seconds since the UNIX epoch in UTC. * * Since BSON_TYPE_DATE_TIME does not support fractions of a second, * tv->tv_usec will always be set to zero. * * Returns: * None. * * Side effects: * @tv is initialized. * *-------------------------------------------------------------------------- */ void bson_iter_timeval (const bson_iter_t *iter, /* IN */ struct timeval *tv) /* OUT */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { bson_iter_timeval_unsafe (iter, tv); return; } memset (tv, 0, sizeof *tv); } /** * bson_iter_document: * @iter: a bson_iter_t. * @document_len: A location for the document length. * @document: A location for a pointer to the document buffer. * */ /* *-------------------------------------------------------------------------- * * bson_iter_document -- * * Retrieves the data to the document BSON structure and stores the * length of the document buffer in @document_len and the document * buffer in @document. * * If you would like to iterate over the child contents, you might * consider creating a bson_t on the stack such as the following. It * allows you to call functions taking a const bson_t* only. * * bson_t b; * uint32_t len; * const uint8_t *data; * * bson_iter_document(iter, &len, &data); * * if (bson_init_static (&b, data, len)) { * ... * } * * There is no need to cleanup the bson_t structure as no data can be * modified in the process of its use (as it is static/const). * * Returns: * None. * * Side effects: * @document_len is initialized. * @document is initialized. * *-------------------------------------------------------------------------- */ void bson_iter_document (const bson_iter_t *iter, /* IN */ uint32_t *document_len, /* OUT */ const uint8_t **document) /* OUT */ { BSON_ASSERT (iter); BSON_ASSERT (document_len); BSON_ASSERT (document); *document = NULL; *document_len = 0; if (ITER_TYPE (iter) == BSON_TYPE_DOCUMENT) { memcpy (document_len, (iter->raw + iter->d1), sizeof (*document_len)); *document_len = BSON_UINT32_FROM_LE (*document_len); *document = (iter->raw + iter->d1); } } /** * bson_iter_array: * @iter: a #bson_iter_t. * @array_len: A location for the array length. * @array: A location for a pointer to the array buffer. */ /* *-------------------------------------------------------------------------- * * bson_iter_array -- * * Retrieves the data to the array BSON structure and stores the * length of the array buffer in @array_len and the array buffer in * @array. * * If you would like to iterate over the child contents, you might * consider creating a bson_t on the stack such as the following. It * allows you to call functions taking a const bson_t* only. * * bson_t b; * uint32_t len; * const uint8_t *data; * * bson_iter_array (iter, &len, &data); * * if (bson_init_static (&b, data, len)) { * ... * } * * There is no need to cleanup the #bson_t structure as no data can be * modified in the process of its use. * * Returns: * None. * * Side effects: * @array_len is initialized. * @array is initialized. * *-------------------------------------------------------------------------- */ void bson_iter_array (const bson_iter_t *iter, /* IN */ uint32_t *array_len, /* OUT */ const uint8_t **array) /* OUT */ { BSON_ASSERT (iter); BSON_ASSERT (array_len); BSON_ASSERT (array); *array = NULL; *array_len = 0; if (ITER_TYPE (iter) == BSON_TYPE_ARRAY) { memcpy (array_len, (iter->raw + iter->d1), sizeof (*array_len)); *array_len = BSON_UINT32_FROM_LE (*array_len); *array = (iter->raw + iter->d1); } } #define VISIT_FIELD(name) visitor->visit_##name && visitor->visit_##name #define VISIT_AFTER VISIT_FIELD (after) #define VISIT_BEFORE VISIT_FIELD (before) #define VISIT_CORRUPT \ if (visitor->visit_corrupt) \ visitor->visit_corrupt #define VISIT_DOUBLE VISIT_FIELD (double) #define VISIT_UTF8 VISIT_FIELD (utf8) #define VISIT_DOCUMENT VISIT_FIELD (document) #define VISIT_ARRAY VISIT_FIELD (array) #define VISIT_BINARY VISIT_FIELD (binary) #define VISIT_UNDEFINED VISIT_FIELD (undefined) #define VISIT_OID VISIT_FIELD (oid) #define VISIT_BOOL VISIT_FIELD (bool) #define VISIT_DATE_TIME VISIT_FIELD (date_time) #define VISIT_NULL VISIT_FIELD (null) #define VISIT_REGEX VISIT_FIELD (regex) #define VISIT_DBPOINTER VISIT_FIELD (dbpointer) #define VISIT_CODE VISIT_FIELD (code) #define VISIT_SYMBOL VISIT_FIELD (symbol) #define VISIT_CODEWSCOPE VISIT_FIELD (codewscope) #define VISIT_INT32 VISIT_FIELD (int32) #define VISIT_TIMESTAMP VISIT_FIELD (timestamp) #define VISIT_INT64 VISIT_FIELD (int64) #define VISIT_DECIMAL128 VISIT_FIELD (decimal128) #define VISIT_MAXKEY VISIT_FIELD (maxkey) #define VISIT_MINKEY VISIT_FIELD (minkey) bool bson_iter_visit_all (bson_iter_t *iter, /* INOUT */ const bson_visitor_t *visitor, /* IN */ void *data) /* IN */ { uint32_t bson_type = 0; const char *key = NULL; bool unsupported; BSON_ASSERT (iter); BSON_ASSERT (visitor); while (_bson_iter_next_internal (iter, 0, &key, &bson_type, &unsupported)) { if (*key && !bson_utf8_validate (key, strlen (key), false)) { iter->err_off = iter->off; break; } if (VISIT_BEFORE (iter, key, data)) { return true; } switch (bson_type) { case BSON_TYPE_DOUBLE: if (VISIT_DOUBLE (iter, key, bson_iter_double (iter), data)) { return true; } break; case BSON_TYPE_UTF8: { uint32_t utf8_len; const char *utf8; utf8 = bson_iter_utf8 (iter, &utf8_len); if (!bson_utf8_validate (utf8, utf8_len, true)) { iter->err_off = iter->off; return true; } if (VISIT_UTF8 (iter, key, utf8_len, utf8, data)) { return true; } } break; case BSON_TYPE_DOCUMENT: { const uint8_t *docbuf = NULL; uint32_t doclen = 0; bson_t b; bson_iter_document (iter, &doclen, &docbuf); if (!bson_init_static (&b, docbuf, doclen)) { iter->err_off = iter->off; break; } if (VISIT_DOCUMENT (iter, key, &b, data)) { return true; } } break; case BSON_TYPE_ARRAY: { const uint8_t *docbuf = NULL; uint32_t doclen = 0; bson_t b; bson_iter_array (iter, &doclen, &docbuf); if (!bson_init_static (&b, docbuf, doclen)) { iter->err_off = iter->off; break; } if (VISIT_ARRAY (iter, key, &b, data)) { return true; } } break; case BSON_TYPE_BINARY: { const uint8_t *binary = NULL; bson_subtype_t subtype = BSON_SUBTYPE_BINARY; uint32_t binary_len = 0; bson_iter_binary (iter, &subtype, &binary_len, &binary); if (VISIT_BINARY (iter, key, subtype, binary_len, binary, data)) { return true; } } break; case BSON_TYPE_UNDEFINED: if (VISIT_UNDEFINED (iter, key, data)) { return true; } break; case BSON_TYPE_OID: if (VISIT_OID (iter, key, bson_iter_oid (iter), data)) { return true; } break; case BSON_TYPE_BOOL: if (VISIT_BOOL (iter, key, bson_iter_bool (iter), data)) { return true; } break; case BSON_TYPE_DATE_TIME: if (VISIT_DATE_TIME (iter, key, bson_iter_date_time (iter), data)) { return true; } break; case BSON_TYPE_NULL: if (VISIT_NULL (iter, key, data)) { return true; } break; case BSON_TYPE_REGEX: { const char *regex = NULL; const char *options = NULL; regex = bson_iter_regex (iter, &options); if (!bson_utf8_validate (regex, strlen (regex), true)) { iter->err_off = iter->off; return true; } if (VISIT_REGEX (iter, key, regex, options, data)) { return true; } } break; case BSON_TYPE_DBPOINTER: { uint32_t collection_len = 0; const char *collection = NULL; const bson_oid_t *oid = NULL; bson_iter_dbpointer (iter, &collection_len, &collection, &oid); if (!bson_utf8_validate (collection, collection_len, true)) { iter->err_off = iter->off; return true; } if (VISIT_DBPOINTER (iter, key, collection_len, collection, oid, data)) { return true; } } break; case BSON_TYPE_CODE: { uint32_t code_len; const char *code; code = bson_iter_code (iter, &code_len); if (!bson_utf8_validate (code, code_len, true)) { iter->err_off = iter->off; return true; } if (VISIT_CODE (iter, key, code_len, code, data)) { return true; } } break; case BSON_TYPE_SYMBOL: { uint32_t symbol_len; const char *symbol; symbol = bson_iter_symbol (iter, &symbol_len); if (!bson_utf8_validate (symbol, symbol_len, true)) { iter->err_off = iter->off; return true; } if (VISIT_SYMBOL (iter, key, symbol_len, symbol, data)) { return true; } } break; case BSON_TYPE_CODEWSCOPE: { uint32_t length = 0; const char *code; const uint8_t *docbuf = NULL; uint32_t doclen = 0; bson_t b; code = bson_iter_codewscope (iter, &length, &doclen, &docbuf); if (!bson_utf8_validate (code, length, true)) { iter->err_off = iter->off; return true; } if (!bson_init_static (&b, docbuf, doclen)) { iter->err_off = iter->off; break; } if (VISIT_CODEWSCOPE (iter, key, length, code, &b, data)) { return true; } } break; case BSON_TYPE_INT32: if (VISIT_INT32 (iter, key, bson_iter_int32 (iter), data)) { return true; } break; case BSON_TYPE_TIMESTAMP: { uint32_t timestamp; uint32_t increment; bson_iter_timestamp (iter, ×tamp, &increment); if (VISIT_TIMESTAMP (iter, key, timestamp, increment, data)) { return true; } } break; case BSON_TYPE_INT64: if (VISIT_INT64 (iter, key, bson_iter_int64 (iter), data)) { return true; } break; case BSON_TYPE_DECIMAL128: { bson_decimal128_t dec; bson_iter_decimal128 (iter, &dec); if (VISIT_DECIMAL128 (iter, key, &dec, data)) { return true; } } break; case BSON_TYPE_MAXKEY: if (VISIT_MAXKEY (iter, bson_iter_key_unsafe (iter), data)) { return true; } break; case BSON_TYPE_MINKEY: if (VISIT_MINKEY (iter, bson_iter_key_unsafe (iter), data)) { return true; } break; case BSON_TYPE_EOD: default: break; } if (VISIT_AFTER (iter, bson_iter_key_unsafe (iter), data)) { return true; } } if (iter->err_off) { if (unsupported && visitor->visit_unsupported_type && bson_utf8_validate (key, strlen (key), false)) { visitor->visit_unsupported_type (iter, key, bson_type, data); return false; } VISIT_CORRUPT (iter, data); } #undef VISIT_FIELD return false; } /* *-------------------------------------------------------------------------- * * bson_iter_overwrite_bool -- * * Overwrites the current BSON_TYPE_BOOLEAN field with a new value. * This is performed in-place and therefore no keys are moved. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_iter_overwrite_bool (bson_iter_t *iter, /* IN */ bool value) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_BOOL) { memcpy ((void *) (iter->raw + iter->d1), &value, 1); } } void bson_iter_overwrite_oid (bson_iter_t *iter, const bson_oid_t *value) { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_OID) { memcpy ((void *) (iter->raw + iter->d1), value->bytes, sizeof (value->bytes)); } } void bson_iter_overwrite_timestamp (bson_iter_t *iter, uint32_t timestamp, uint32_t increment) { uint64_t value; BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_TIMESTAMP) { value = ((((uint64_t) timestamp) << 32U) | ((uint64_t) increment)); value = BSON_UINT64_TO_LE (value); memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); } } void bson_iter_overwrite_date_time (bson_iter_t *iter, int64_t value) { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { value = BSON_UINT64_TO_LE (value); memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); } } /* *-------------------------------------------------------------------------- * * bson_iter_overwrite_int32 -- * * Overwrites the current BSON_TYPE_INT32 field with a new value. * This is performed in-place and therefore no keys are moved. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_iter_overwrite_int32 (bson_iter_t *iter, /* IN */ int32_t value) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_INT32) { #if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN value = BSON_UINT32_TO_LE (value); #endif memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); } } /* *-------------------------------------------------------------------------- * * bson_iter_overwrite_int64 -- * * Overwrites the current BSON_TYPE_INT64 field with a new value. * This is performed in-place and therefore no keys are moved. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_iter_overwrite_int64 (bson_iter_t *iter, /* IN */ int64_t value) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_INT64) { #if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN value = BSON_UINT64_TO_LE (value); #endif memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); } } /* *-------------------------------------------------------------------------- * * bson_iter_overwrite_double -- * * Overwrites the current BSON_TYPE_DOUBLE field with a new value. * This is performed in-place and therefore no keys are moved. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_iter_overwrite_double (bson_iter_t *iter, /* IN */ double value) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_DOUBLE) { value = BSON_DOUBLE_TO_LE (value); memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); } } /* *-------------------------------------------------------------------------- * * bson_iter_overwrite_decimal128 -- * * Overwrites the current BSON_TYPE_DECIMAL128 field with a new value. * This is performed in-place and therefore no keys are moved. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_iter_overwrite_decimal128 (bson_iter_t *iter, /* IN */ const bson_decimal128_t *value) /* IN */ { BSON_ASSERT (iter); if (ITER_TYPE (iter) == BSON_TYPE_DECIMAL128) { #if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN uint64_t data[2]; data[0] = BSON_UINT64_TO_LE (value->low); data[1] = BSON_UINT64_TO_LE (value->high); memcpy ((void *) (iter->raw + iter->d1), data, sizeof (data)); #else memcpy ((void *) (iter->raw + iter->d1), value, sizeof (*value)); #endif } } /* *-------------------------------------------------------------------------- * * bson_iter_value -- * * Retrieves a bson_value_t containing the boxed value of the current * element. The result of this function valid until the state of * iter has been changed (through the use of bson_iter_next()). * * Returns: * A bson_value_t that should not be modified or freed. If you need * to hold on to the value, use bson_value_copy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ const bson_value_t * bson_iter_value (bson_iter_t *iter) /* IN */ { bson_value_t *value; BSON_ASSERT (iter); value = &iter->value; value->value_type = ITER_TYPE (iter); switch (value->value_type) { case BSON_TYPE_DOUBLE: value->value.v_double = bson_iter_double (iter); break; case BSON_TYPE_UTF8: value->value.v_utf8.str = (char *) bson_iter_utf8 (iter, &value->value.v_utf8.len); break; case BSON_TYPE_DOCUMENT: bson_iter_document (iter, &value->value.v_doc.data_len, (const uint8_t **) &value->value.v_doc.data); break; case BSON_TYPE_ARRAY: bson_iter_array (iter, &value->value.v_doc.data_len, (const uint8_t **) &value->value.v_doc.data); break; case BSON_TYPE_BINARY: bson_iter_binary (iter, &value->value.v_binary.subtype, &value->value.v_binary.data_len, (const uint8_t **) &value->value.v_binary.data); break; case BSON_TYPE_OID: bson_oid_copy (bson_iter_oid (iter), &value->value.v_oid); break; case BSON_TYPE_BOOL: value->value.v_bool = bson_iter_bool (iter); break; case BSON_TYPE_DATE_TIME: value->value.v_datetime = bson_iter_date_time (iter); break; case BSON_TYPE_REGEX: value->value.v_regex.regex = (char *) bson_iter_regex (iter, (const char **) &value->value.v_regex.options); break; case BSON_TYPE_DBPOINTER: { const bson_oid_t *oid; bson_iter_dbpointer ( iter, &value->value.v_dbpointer.collection_len, (const char **) &value->value.v_dbpointer.collection, &oid); bson_oid_copy (oid, &value->value.v_dbpointer.oid); break; } case BSON_TYPE_CODE: value->value.v_code.code = (char *) bson_iter_code (iter, &value->value.v_code.code_len); break; case BSON_TYPE_SYMBOL: value->value.v_symbol.symbol = (char *) bson_iter_symbol (iter, &value->value.v_symbol.len); break; case BSON_TYPE_CODEWSCOPE: value->value.v_codewscope.code = (char *) bson_iter_codewscope (iter, &value->value.v_codewscope.code_len, &value->value.v_codewscope.scope_len, (const uint8_t **) &value->value.v_codewscope.scope_data); break; case BSON_TYPE_INT32: value->value.v_int32 = bson_iter_int32 (iter); break; case BSON_TYPE_TIMESTAMP: bson_iter_timestamp (iter, &value->value.v_timestamp.timestamp, &value->value.v_timestamp.increment); break; case BSON_TYPE_INT64: value->value.v_int64 = bson_iter_int64 (iter); break; case BSON_TYPE_DECIMAL128: bson_iter_decimal128 (iter, &(value->value.v_decimal128)); break; case BSON_TYPE_NULL: case BSON_TYPE_UNDEFINED: case BSON_TYPE_MAXKEY: case BSON_TYPE_MINKEY: break; case BSON_TYPE_EOD: default: return NULL; } return value; } uint32_t bson_iter_key_len (const bson_iter_t *iter) { /* * f i e l d n a m e \0 _ * ^ ^ * | | * iter->key iter->d1 * */ BSON_ASSERT (iter->d1 > iter->key); return iter->d1 - iter->key - 1; } bool bson_iter_init_from_data_at_offset ( bson_iter_t *iter, const uint8_t *data, size_t length, uint32_t offset, uint32_t keylen) { const char *key; uint32_t bson_type; bool unsupported; BSON_ASSERT (iter); BSON_ASSERT (data); if (BSON_UNLIKELY ((length < 5) || (length > INT_MAX))) { memset (iter, 0, sizeof *iter); return false; } iter->raw = (uint8_t *) data; iter->len = (uint32_t) length; iter->off = 0; iter->type = 0; iter->key = 0; iter->next_off = offset; iter->err_off = 0; if (!_bson_iter_next_internal (iter, keylen, &key, &bson_type, &unsupported)) { memset (iter, 0, sizeof *iter); return false; } return true; } uint32_t bson_iter_offset (bson_iter_t *iter) { return iter->off; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-iter.h0000644000175100001660000003276214760300420020731 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_ITER_H #define BSON_ITER_H #include #include #include #include BSON_BEGIN_DECLS #define BSON_ITER_HOLDS_DOUBLE(iter) (bson_iter_type ((iter)) == BSON_TYPE_DOUBLE) #define BSON_ITER_HOLDS_UTF8(iter) (bson_iter_type ((iter)) == BSON_TYPE_UTF8) #define BSON_ITER_HOLDS_DOCUMENT(iter) (bson_iter_type ((iter)) == BSON_TYPE_DOCUMENT) #define BSON_ITER_HOLDS_ARRAY(iter) (bson_iter_type ((iter)) == BSON_TYPE_ARRAY) #define BSON_ITER_HOLDS_BINARY(iter) (bson_iter_type ((iter)) == BSON_TYPE_BINARY) #define BSON_ITER_HOLDS_UNDEFINED(iter) (bson_iter_type ((iter)) == BSON_TYPE_UNDEFINED) #define BSON_ITER_HOLDS_OID(iter) (bson_iter_type ((iter)) == BSON_TYPE_OID) #define BSON_ITER_HOLDS_BOOL(iter) (bson_iter_type ((iter)) == BSON_TYPE_BOOL) #define BSON_ITER_HOLDS_DATE_TIME(iter) (bson_iter_type ((iter)) == BSON_TYPE_DATE_TIME) #define BSON_ITER_HOLDS_NULL(iter) (bson_iter_type ((iter)) == BSON_TYPE_NULL) #define BSON_ITER_HOLDS_REGEX(iter) (bson_iter_type ((iter)) == BSON_TYPE_REGEX) #define BSON_ITER_HOLDS_DBPOINTER(iter) (bson_iter_type ((iter)) == BSON_TYPE_DBPOINTER) #define BSON_ITER_HOLDS_CODE(iter) (bson_iter_type ((iter)) == BSON_TYPE_CODE) #define BSON_ITER_HOLDS_SYMBOL(iter) (bson_iter_type ((iter)) == BSON_TYPE_SYMBOL) #define BSON_ITER_HOLDS_CODEWSCOPE(iter) (bson_iter_type ((iter)) == BSON_TYPE_CODEWSCOPE) #define BSON_ITER_HOLDS_INT32(iter) (bson_iter_type ((iter)) == BSON_TYPE_INT32) #define BSON_ITER_HOLDS_TIMESTAMP(iter) (bson_iter_type ((iter)) == BSON_TYPE_TIMESTAMP) #define BSON_ITER_HOLDS_INT64(iter) (bson_iter_type ((iter)) == BSON_TYPE_INT64) #define BSON_ITER_HOLDS_DECIMAL128(iter) (bson_iter_type ((iter)) == BSON_TYPE_DECIMAL128) #define BSON_ITER_HOLDS_MAXKEY(iter) (bson_iter_type ((iter)) == BSON_TYPE_MAXKEY) #define BSON_ITER_HOLDS_MINKEY(iter) (bson_iter_type ((iter)) == BSON_TYPE_MINKEY) #define BSON_ITER_HOLDS_INT(iter) (BSON_ITER_HOLDS_INT32 (iter) || BSON_ITER_HOLDS_INT64 (iter)) #define BSON_ITER_HOLDS_NUMBER(iter) (BSON_ITER_HOLDS_INT (iter) || BSON_ITER_HOLDS_DOUBLE (iter)) #define BSON_ITER_IS_KEY(iter, key) (0 == strcmp ((key), bson_iter_key ((iter)))) BSON_EXPORT (const bson_value_t *) bson_iter_value (bson_iter_t *iter); /** * bson_iter_utf8_len_unsafe: * @iter: a bson_iter_t. * * Returns the length of a string currently pointed to by @iter. This performs * no validation so the is responsible for knowing the BSON is valid. Calling * bson_validate() is one way to do this ahead of time. */ static BSON_INLINE uint32_t bson_iter_utf8_len_unsafe (const bson_iter_t *iter) { uint32_t raw; BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (&raw, iter->raw + iter->d1, sizeof (raw)); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END const uint32_t native = BSON_UINT32_FROM_LE (raw); int32_t len; memcpy (&len, &native, sizeof (len)); return len <= 0 ? 0u : (uint32_t) (len - 1); } BSON_EXPORT (void) bson_iter_array (const bson_iter_t *iter, uint32_t *array_len, const uint8_t **array); BSON_EXPORT (void) bson_iter_binary (const bson_iter_t *iter, bson_subtype_t *subtype, uint32_t *binary_len, const uint8_t **binary); BSON_EXPORT (const char *) bson_iter_code (const bson_iter_t *iter, uint32_t *length); /** * bson_iter_code_unsafe: * @iter: A bson_iter_t. * @length: A location for the length of the resulting string. * * Like bson_iter_code() but performs no integrity checks. * * Returns: A string that should not be modified or freed. */ static BSON_INLINE const char * bson_iter_code_unsafe (const bson_iter_t *iter, uint32_t *length) { *length = bson_iter_utf8_len_unsafe (iter); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN return (const char *) (iter->raw + iter->d2); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } BSON_EXPORT (const char *) bson_iter_codewscope (const bson_iter_t *iter, uint32_t *length, uint32_t *scope_len, const uint8_t **scope); BSON_EXPORT (void) bson_iter_dbpointer (const bson_iter_t *iter, uint32_t *collection_len, const char **collection, const bson_oid_t **oid); BSON_EXPORT (void) bson_iter_document (const bson_iter_t *iter, uint32_t *document_len, const uint8_t **document); BSON_EXPORT (double) bson_iter_double (const bson_iter_t *iter); BSON_EXPORT (double) bson_iter_as_double (const bson_iter_t *iter); /** * bson_iter_double_unsafe: * @iter: A bson_iter_t. * * Similar to bson_iter_double() but does not perform an integrity checking. * * Returns: A double. */ static BSON_INLINE double bson_iter_double_unsafe (const bson_iter_t *iter) { double val; BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (&val, iter->raw + iter->d1, sizeof (val)); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END return BSON_DOUBLE_FROM_LE (val); } BSON_EXPORT (bool) bson_iter_init (bson_iter_t *iter, const bson_t *bson); BSON_EXPORT (bool) bson_iter_init_from_data (bson_iter_t *iter, const uint8_t *data, size_t length); BSON_EXPORT (bool) bson_iter_init_find (bson_iter_t *iter, const bson_t *bson, const char *key); BSON_EXPORT (bool) bson_iter_init_find_w_len (bson_iter_t *iter, const bson_t *bson, const char *key, int keylen); BSON_EXPORT (bool) bson_iter_init_find_case (bson_iter_t *iter, const bson_t *bson, const char *key); BSON_EXPORT (bool) bson_iter_init_from_data_at_offset ( bson_iter_t *iter, const uint8_t *data, size_t length, uint32_t offset, uint32_t keylen); BSON_EXPORT (int32_t) bson_iter_int32 (const bson_iter_t *iter); /** * bson_iter_int32_unsafe: * @iter: A bson_iter_t. * * Similar to bson_iter_int32() but with no integrity checking. * * Returns: A 32-bit signed integer. */ static BSON_INLINE int32_t bson_iter_int32_unsafe (const bson_iter_t *iter) { uint32_t raw; BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (&raw, iter->raw + iter->d1, sizeof (raw)); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END const uint32_t native = BSON_UINT32_FROM_LE (raw); int32_t res; memcpy (&res, &native, sizeof (res)); return res; } BSON_EXPORT (int64_t) bson_iter_int64 (const bson_iter_t *iter); BSON_EXPORT (int64_t) bson_iter_as_int64 (const bson_iter_t *iter); /** * bson_iter_int64_unsafe: * @iter: a bson_iter_t. * * Similar to bson_iter_int64() but without integrity checking. * * Returns: A 64-bit signed integer. */ static BSON_INLINE int64_t bson_iter_int64_unsafe (const bson_iter_t *iter) { uint64_t raw; BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (&raw, iter->raw + iter->d1, sizeof (raw)); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END const uint64_t native = BSON_UINT64_FROM_LE (raw); int64_t res; memcpy (&res, &native, sizeof (res)); return res; } BSON_EXPORT (bool) bson_iter_find (bson_iter_t *iter, const char *key); BSON_EXPORT (bool) bson_iter_find_w_len (bson_iter_t *iter, const char *key, int keylen); BSON_EXPORT (bool) bson_iter_find_case (bson_iter_t *iter, const char *key); BSON_EXPORT (bool) bson_iter_find_descendant (bson_iter_t *iter, const char *dotkey, bson_iter_t *descendant); BSON_EXPORT (bool) bson_iter_next (bson_iter_t *iter); BSON_EXPORT (const bson_oid_t *) bson_iter_oid (const bson_iter_t *iter); /** * bson_iter_oid_unsafe: * @iter: A #bson_iter_t. * * Similar to bson_iter_oid() but performs no integrity checks. * * Returns: A #bson_oid_t that should not be modified or freed. */ static BSON_INLINE const bson_oid_t * bson_iter_oid_unsafe (const bson_iter_t *iter) { BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN return (const bson_oid_t *) (iter->raw + iter->d1); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } BSON_EXPORT (bool) bson_iter_decimal128 (const bson_iter_t *iter, bson_decimal128_t *dec); /** * bson_iter_decimal128_unsafe: * @iter: A #bson_iter_t. * * Similar to bson_iter_decimal128() but performs no integrity checks. * * Returns: A #bson_decimal128_t. */ static BSON_INLINE void bson_iter_decimal128_unsafe (const bson_iter_t *iter, bson_decimal128_t *dec) { uint64_t low_le; uint64_t high_le; BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (&low_le, iter->raw + iter->d1, sizeof (low_le)); memcpy (&high_le, iter->raw + iter->d1 + 8, sizeof (high_le)); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END dec->low = BSON_UINT64_FROM_LE (low_le); dec->high = BSON_UINT64_FROM_LE (high_le); } BSON_EXPORT (const char *) bson_iter_key (const bson_iter_t *iter); BSON_EXPORT (uint32_t) bson_iter_key_len (const bson_iter_t *iter); /** * bson_iter_key_unsafe: * @iter: A bson_iter_t. * * Similar to bson_iter_key() but performs no integrity checking. * * Returns: A string that should not be modified or freed. */ static BSON_INLINE const char * bson_iter_key_unsafe (const bson_iter_t *iter) { BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN return (const char *) (iter->raw + iter->key); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } BSON_EXPORT (const char *) bson_iter_utf8 (const bson_iter_t *iter, uint32_t *length); /** * bson_iter_utf8_unsafe: * * Similar to bson_iter_utf8() but performs no integrity checking. * * Returns: A string that should not be modified or freed. */ static BSON_INLINE const char * bson_iter_utf8_unsafe (const bson_iter_t *iter, size_t *length) { *length = bson_iter_utf8_len_unsafe (iter); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN return (const char *) (iter->raw + iter->d2); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } BSON_EXPORT (char *) bson_iter_dup_utf8 (const bson_iter_t *iter, uint32_t *length); BSON_EXPORT (int64_t) bson_iter_date_time (const bson_iter_t *iter); BSON_EXPORT (time_t) bson_iter_time_t (const bson_iter_t *iter); /** * bson_iter_time_t_unsafe: * @iter: A bson_iter_t. * * Similar to bson_iter_time_t() but performs no integrity checking. * * Returns: A time_t containing the number of seconds since UNIX epoch * in UTC. */ static BSON_INLINE time_t bson_iter_time_t_unsafe (const bson_iter_t *iter) { return (time_t) (bson_iter_int64_unsafe (iter) / 1000); } BSON_EXPORT (void) bson_iter_timeval (const bson_iter_t *iter, struct timeval *tv); /** * bson_iter_timeval_unsafe: * @iter: A bson_iter_t. * @tv: A struct timeval. * * Similar to bson_iter_timeval() but performs no integrity checking. */ static BSON_INLINE void bson_iter_timeval_unsafe (const bson_iter_t *iter, struct timeval *tv) { int64_t value = bson_iter_int64_unsafe (iter); #ifdef BSON_OS_WIN32 tv->tv_sec = (long) (value / 1000); tv->tv_usec = (long) (value % 1000) * 1000; #else tv->tv_sec = (time_t) (value / 1000); tv->tv_usec = (suseconds_t) (value % 1000) * 1000; #endif } BSON_EXPORT (void) bson_iter_timestamp (const bson_iter_t *iter, uint32_t *timestamp, uint32_t *increment); BSON_EXPORT (bool) bson_iter_bool (const bson_iter_t *iter); /** * bson_iter_bool_unsafe: * @iter: A bson_iter_t. * * Similar to bson_iter_bool() but performs no integrity checking. * * Returns: true or false. */ static BSON_INLINE bool bson_iter_bool_unsafe (const bson_iter_t *iter) { char val; BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN memcpy (&val, iter->raw + iter->d1, 1); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END return !!val; } BSON_EXPORT (bool) bson_iter_as_bool (const bson_iter_t *iter); BSON_EXPORT (const char *) bson_iter_regex (const bson_iter_t *iter, const char **options); BSON_EXPORT (const char *) bson_iter_symbol (const bson_iter_t *iter, uint32_t *length); BSON_EXPORT (bson_type_t) bson_iter_type (const bson_iter_t *iter); /** * bson_iter_type_unsafe: * @iter: A bson_iter_t. * * Similar to bson_iter_type() but performs no integrity checking. * * Returns: A bson_type_t. */ static BSON_INLINE bson_type_t bson_iter_type_unsafe (const bson_iter_t *iter) { BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN return (bson_type_t) (iter->raw + iter->type)[0]; BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } BSON_EXPORT (bool) bson_iter_recurse (const bson_iter_t *iter, bson_iter_t *child); BSON_EXPORT (void) bson_iter_overwrite_int32 (bson_iter_t *iter, int32_t value); BSON_EXPORT (void) bson_iter_overwrite_int64 (bson_iter_t *iter, int64_t value); BSON_EXPORT (void) bson_iter_overwrite_double (bson_iter_t *iter, double value); BSON_EXPORT (void) bson_iter_overwrite_decimal128 (bson_iter_t *iter, const bson_decimal128_t *value); BSON_EXPORT (void) bson_iter_overwrite_bool (bson_iter_t *iter, bool value); BSON_EXPORT (void) bson_iter_overwrite_oid (bson_iter_t *iter, const bson_oid_t *value); BSON_EXPORT (void) bson_iter_overwrite_timestamp (bson_iter_t *iter, uint32_t timestamp, uint32_t increment); BSON_EXPORT (void) bson_iter_overwrite_date_time (bson_iter_t *iter, int64_t value); BSON_EXPORT (bool) bson_iter_visit_all (bson_iter_t *iter, const bson_visitor_t *visitor, void *data); BSON_EXPORT (uint32_t) bson_iter_offset (bson_iter_t *iter); BSON_END_DECLS #endif /* BSON_ITER_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-json-private.h0000644000175100001660000000150114760300420022372 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_JSON_PRIVATE_H #define BSON_JSON_PRIVATE_H struct _bson_json_opts_t { bson_json_mode_t mode; int32_t max_len; bool is_outermost_array; }; #endif /* BSON_JSON_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-json.c0000644000175100001660000023001114760300420020715 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #endif #ifndef _MSC_VER #include #endif #ifdef _MSC_VER #define SSCANF sscanf_s #else #define SSCANF sscanf #endif #define STACK_MAX 100 #define BSON_JSON_DEFAULT_BUF_SIZE (1 << 14) #define AT_LEAST_0(x) ((x) >= 0 ? (x) : 0) #define READ_STATE_ENUM(ENUM) BSON_JSON_##ENUM, #define GENERATE_STRING(STRING) #STRING, #define FOREACH_READ_STATE(RS) \ RS (REGULAR) \ RS (DONE) \ RS (ERROR) \ RS (IN_START_MAP) \ RS (IN_BSON_TYPE) \ RS (IN_BSON_TYPE_DATE_NUMBERLONG) \ RS (IN_BSON_TYPE_DATE_ENDMAP) \ RS (IN_BSON_TYPE_TIMESTAMP_STARTMAP) \ RS (IN_BSON_TYPE_TIMESTAMP_VALUES) \ RS (IN_BSON_TYPE_TIMESTAMP_ENDMAP) \ RS (IN_BSON_TYPE_REGEX_STARTMAP) \ RS (IN_BSON_TYPE_REGEX_VALUES) \ RS (IN_BSON_TYPE_REGEX_ENDMAP) \ RS (IN_BSON_TYPE_BINARY_VALUES) \ RS (IN_BSON_TYPE_BINARY_ENDMAP) \ RS (IN_BSON_TYPE_SCOPE_STARTMAP) \ RS (IN_BSON_TYPE_DBPOINTER_STARTMAP) \ RS (IN_SCOPE) \ RS (IN_DBPOINTER) typedef enum { FOREACH_READ_STATE (READ_STATE_ENUM) } bson_json_read_state_t; static const char *read_state_names[] = {FOREACH_READ_STATE (GENERATE_STRING)}; #define BSON_STATE_ENUM(ENUM) BSON_JSON_LF_##ENUM, #define FOREACH_BSON_STATE(BS) \ /* legacy {$regex: "...", $options: "..."} */ \ BS (REGEX) \ BS (OPTIONS) \ /* modern $regularExpression: {pattern: "...", options: "..."} */ \ BS (REGULAR_EXPRESSION_PATTERN) \ BS (REGULAR_EXPRESSION_OPTIONS) \ BS (CODE) \ BS (SCOPE) \ BS (OID) \ BS (BINARY) \ BS (TYPE) \ BS (DATE) \ BS (TIMESTAMP_T) \ BS (TIMESTAMP_I) \ BS (UNDEFINED) \ BS (MINKEY) \ BS (MAXKEY) \ BS (INT32) \ BS (INT64) \ BS (DOUBLE) \ BS (DECIMAL128) \ BS (DBPOINTER) \ BS (SYMBOL) \ BS (UUID) typedef enum { FOREACH_BSON_STATE (BSON_STATE_ENUM) } bson_json_read_bson_state_t; static const char *bson_state_names[] = {FOREACH_BSON_STATE (GENERATE_STRING)}; typedef struct { uint8_t *buf; size_t n_bytes; size_t len; } bson_json_buf_t; typedef enum { BSON_JSON_FRAME_INITIAL = 0, BSON_JSON_FRAME_ARRAY, BSON_JSON_FRAME_DOC, BSON_JSON_FRAME_SCOPE, BSON_JSON_FRAME_DBPOINTER, } bson_json_frame_type_t; typedef struct { int i; bson_json_frame_type_t type; bson_t bson; } bson_json_stack_frame_t; typedef union { struct { bool has_pattern; bool has_options; bool is_legacy; } regex; struct { bool has_oid; bson_oid_t oid; } oid; struct { bool has_binary; bool has_subtype; bson_subtype_t type; bool is_legacy; } binary; struct { bool has_date; int64_t date; } date; struct { bool has_t; bool has_i; uint32_t t; uint32_t i; } timestamp; struct { bool has_undefined; } undefined; struct { bool has_minkey; } minkey; struct { bool has_maxkey; } maxkey; struct { int32_t value; } v_int32; struct { int64_t value; } v_int64; struct { double value; } v_double; struct { bson_decimal128_t value; } v_decimal128; } bson_json_bson_data_t; /* collect info while parsing a {$code: "...", $scope: {...}} object */ typedef struct { bool has_code; bool has_scope; bool in_scope; bson_json_buf_t key_buf; bson_json_buf_t code_buf; } bson_json_code_t; static void _bson_json_code_cleanup (bson_json_code_t *code_data) { bson_free (code_data->key_buf.buf); bson_free (code_data->code_buf.buf); } typedef struct { bson_t *bson; bson_json_stack_frame_t stack[STACK_MAX]; int n; const char *key; bson_json_buf_t key_buf; bson_json_buf_t unescaped; bson_json_read_state_t read_state; bson_json_read_bson_state_t bson_state; bson_type_t bson_type; bson_json_buf_t bson_type_buf[3]; bson_json_bson_data_t bson_type_data; bson_json_code_t code_data; bson_json_buf_t dbpointer_key; } bson_json_reader_bson_t; typedef struct { void *data; bson_json_reader_cb cb; bson_json_destroy_cb dcb; uint8_t *buf; size_t buf_size; size_t bytes_read; size_t bytes_parsed; bool all_whitespace; } bson_json_reader_producer_t; struct _bson_json_reader_t { bson_json_reader_producer_t producer; bson_json_reader_bson_t bson; jsonsl_t json; ssize_t json_text_pos; bool should_reset; ssize_t advance; bson_json_buf_t tok_accumulator; bson_error_t *error; }; typedef struct { int fd; bool do_close; } bson_json_reader_handle_fd_t; /* forward decl */ static void _bson_json_save_map_key (bson_json_reader_bson_t *bson, const uint8_t *val, size_t len); static void _noop (void) { } #define STACK_ELE(_delta, _name) (bson->stack[(_delta) + bson->n]._name) #define STACK_BSON(_delta) (((_delta) + bson->n) == 0 ? bson->bson : &STACK_ELE (_delta, bson)) #define STACK_BSON_PARENT STACK_BSON (-1) #define STACK_BSON_CHILD STACK_BSON (0) #define STACK_I STACK_ELE (0, i) #define STACK_FRAME_TYPE STACK_ELE (0, type) #define STACK_IS_INITIAL (STACK_FRAME_TYPE == BSON_JSON_FRAME_INITIAL) #define STACK_IS_ARRAY (STACK_FRAME_TYPE == BSON_JSON_FRAME_ARRAY) #define STACK_IS_DOC (STACK_FRAME_TYPE == BSON_JSON_FRAME_DOC) #define STACK_IS_SCOPE (STACK_FRAME_TYPE == BSON_JSON_FRAME_SCOPE) #define STACK_IS_DBPOINTER (STACK_FRAME_TYPE == BSON_JSON_FRAME_DBPOINTER) #define FRAME_TYPE_HAS_BSON(_type) ((_type) == BSON_JSON_FRAME_SCOPE || (_type) == BSON_JSON_FRAME_DBPOINTER) #define STACK_HAS_BSON FRAME_TYPE_HAS_BSON (STACK_FRAME_TYPE) #define STACK_PUSH(frame_type) \ do { \ if (bson->n >= (STACK_MAX - 1)) { \ return; \ } \ bson->n++; \ if (STACK_HAS_BSON) { \ if (FRAME_TYPE_HAS_BSON (frame_type)) { \ bson_reinit (STACK_BSON_CHILD); \ } else { \ bson_destroy (STACK_BSON_CHILD); \ } \ } else if (FRAME_TYPE_HAS_BSON (frame_type)) { \ bson_init (STACK_BSON_CHILD); \ } \ STACK_FRAME_TYPE = frame_type; \ } while (0) #define STACK_PUSH_ARRAY(statement) \ do { \ STACK_PUSH (BSON_JSON_FRAME_ARRAY); \ STACK_I = 0; \ if (bson->n != 0) { \ statement; \ } \ } while (0) #define STACK_PUSH_DOC(statement) \ do { \ STACK_PUSH (BSON_JSON_FRAME_DOC); \ if (bson->n != 0) { \ statement; \ } \ } while (0) #define STACK_PUSH_SCOPE \ do { \ STACK_PUSH (BSON_JSON_FRAME_SCOPE); \ bson->code_data.in_scope = true; \ } while (0) #define STACK_PUSH_DBPOINTER \ do { \ STACK_PUSH (BSON_JSON_FRAME_DBPOINTER); \ } while (0) #define STACK_POP_ARRAY(statement) \ do { \ if (!STACK_IS_ARRAY) { \ return; \ } \ if (bson->n < 0) { \ return; \ } \ if (bson->n > 0) { \ statement; \ } \ bson->n--; \ } while (0) #define STACK_POP_DOC(statement) \ do { \ if (STACK_IS_ARRAY) { \ return; \ } \ if (bson->n < 0) { \ return; \ } \ if (bson->n > 0) { \ statement; \ } \ bson->n--; \ } while (0) #define STACK_POP_SCOPE \ do { \ STACK_POP_DOC (_noop ()); \ bson->code_data.in_scope = false; \ } while (0) #define STACK_POP_DBPOINTER STACK_POP_DOC (_noop ()) #define BASIC_CB_PREAMBLE \ const char *key; \ size_t len; \ bson_json_reader_bson_t *bson = &reader->bson; \ _bson_json_read_fixup_key (bson); \ key = bson->key; \ len = bson->key_buf.len; \ (void) 0 #define BASIC_CB_BAIL_IF_NOT_NORMAL(_type) \ if (bson->read_state != BSON_JSON_REGULAR) { \ _bson_json_read_set_error ( \ reader, "Invalid read of %s in state %s", (_type), read_state_names[bson->read_state]); \ return; \ } else if (!key) { \ _bson_json_read_set_error ( \ reader, "Invalid read of %s without key in state %s", (_type), read_state_names[bson->read_state]); \ return; \ } else \ (void) 0 #define HANDLE_OPTION_KEY_COMPARE(_key) (len == strlen (_key) && memcmp (key, (_key), len) == 0) #define HANDLE_OPTION_TYPE_CHECK(_key, _type) \ if (bson->bson_type && bson->bson_type != (_type)) { \ _bson_json_read_set_error (reader, \ "Invalid key \"%s\". Looking for values " \ "for type \"%s\", got \"%s\"", \ (_key), \ _bson_json_type_name (bson->bson_type), \ _bson_json_type_name (_type)); \ return; \ } \ ((void) 0) #define HANDLE_OPTION(_selection_statement, _key, _type, _state) \ _selection_statement (HANDLE_OPTION_KEY_COMPARE (_key)) \ { \ HANDLE_OPTION_TYPE_CHECK (_key, _type); \ bson->bson_type = (_type); \ bson->bson_state = (_state); \ } bson_json_opts_t * bson_json_opts_new (bson_json_mode_t mode, int32_t max_len) { bson_json_opts_t *opts; opts = (bson_json_opts_t *) bson_malloc (sizeof *opts); *opts = (bson_json_opts_t){ .mode = mode, .max_len = max_len, .is_outermost_array = false, }; return opts; } void bson_json_opts_destroy (bson_json_opts_t *opts) { bson_free (opts); } static void _bson_json_read_set_error (bson_json_reader_t *reader, const char *fmt, ...) BSON_GNUC_PRINTF (2, 3); static void _bson_json_read_set_error (bson_json_reader_t *reader, /* IN */ const char *fmt, /* IN */ ...) { va_list ap; if (reader->error) { reader->error->domain = BSON_ERROR_JSON; reader->error->code = BSON_JSON_ERROR_READ_INVALID_PARAM; va_start (ap, fmt); bson_vsnprintf (reader->error->message, sizeof reader->error->message, fmt, ap); va_end (ap); reader->error->message[sizeof reader->error->message - 1] = '\0'; } reader->bson.read_state = BSON_JSON_ERROR; jsonsl_stop (reader->json); } static void _bson_json_read_corrupt (bson_json_reader_t *reader, const char *fmt, ...) BSON_GNUC_PRINTF (2, 3); static void _bson_json_read_corrupt (bson_json_reader_t *reader, /* IN */ const char *fmt, /* IN */ ...) { va_list ap; if (reader->error) { reader->error->domain = BSON_ERROR_JSON; reader->error->code = BSON_JSON_ERROR_READ_CORRUPT_JS; va_start (ap, fmt); bson_vsnprintf (reader->error->message, sizeof reader->error->message, fmt, ap); va_end (ap); reader->error->message[sizeof reader->error->message - 1] = '\0'; } reader->bson.read_state = BSON_JSON_ERROR; jsonsl_stop (reader->json); } static void _bson_json_buf_ensure (bson_json_buf_t *buf, /* IN */ size_t len) /* IN */ { if (buf->n_bytes < len) { bson_free (buf->buf); buf->n_bytes = bson_next_power_of_two (len); buf->buf = bson_malloc (buf->n_bytes); } } static void _bson_json_buf_set (bson_json_buf_t *buf, const void *from, size_t len) { _bson_json_buf_ensure (buf, len + 1); memcpy (buf->buf, from, len); buf->buf[len] = '\0'; buf->len = len; } static void _bson_json_buf_append (bson_json_buf_t *buf, const void *from, size_t len) { size_t len_with_null = len + 1; if (buf->len == 0) { _bson_json_buf_ensure (buf, len_with_null); } else if (buf->n_bytes < buf->len + len_with_null) { buf->n_bytes = bson_next_power_of_two (buf->len + len_with_null); buf->buf = bson_realloc (buf->buf, buf->n_bytes); } memcpy (buf->buf + buf->len, from, len); buf->len += len; buf->buf[buf->len] = '\0'; } static const char * _bson_json_type_name (bson_type_t type) { switch (type) { case BSON_TYPE_EOD: return "end of document"; case BSON_TYPE_DOUBLE: return "double"; case BSON_TYPE_UTF8: return "utf-8"; case BSON_TYPE_DOCUMENT: return "document"; case BSON_TYPE_ARRAY: return "array"; case BSON_TYPE_BINARY: return "binary"; case BSON_TYPE_UNDEFINED: return "undefined"; case BSON_TYPE_OID: return "objectid"; case BSON_TYPE_BOOL: return "bool"; case BSON_TYPE_DATE_TIME: return "datetime"; case BSON_TYPE_NULL: return "null"; case BSON_TYPE_REGEX: return "regex"; case BSON_TYPE_DBPOINTER: return "dbpointer"; case BSON_TYPE_CODE: return "code"; case BSON_TYPE_SYMBOL: return "symbol"; case BSON_TYPE_CODEWSCOPE: return "code with scope"; case BSON_TYPE_INT32: return "int32"; case BSON_TYPE_TIMESTAMP: return "timestamp"; case BSON_TYPE_INT64: return "int64"; case BSON_TYPE_DECIMAL128: return "decimal128"; case BSON_TYPE_MAXKEY: return "maxkey"; case BSON_TYPE_MINKEY: return "minkey"; default: return ""; } } static void _bson_json_read_fixup_key (bson_json_reader_bson_t *bson) /* IN */ { bson_json_read_state_t rs = bson->read_state; if (bson->n >= 0 && STACK_IS_ARRAY && rs == BSON_JSON_REGULAR) { _bson_json_buf_ensure (&bson->key_buf, 12); bson->key_buf.len = bson_uint32_to_string (STACK_I, &bson->key, (char *) bson->key_buf.buf, 12); STACK_I++; } } static void _bson_json_read_null (bson_json_reader_t *reader) { BASIC_CB_PREAMBLE; BASIC_CB_BAIL_IF_NOT_NORMAL ("null"); bson_append_null (STACK_BSON_CHILD, key, (int) len); } static void _bson_json_read_boolean (bson_json_reader_t *reader, /* IN */ int val) /* IN */ { BASIC_CB_PREAMBLE; if (bson->read_state == BSON_JSON_IN_BSON_TYPE && bson->bson_state == BSON_JSON_LF_UNDEFINED) { bson->bson_type_data.undefined.has_undefined = true; return; } BASIC_CB_BAIL_IF_NOT_NORMAL ("boolean"); bson_append_bool (STACK_BSON_CHILD, key, (int) len, val); } /* sign is -1 or 1 */ static void _bson_json_read_integer (bson_json_reader_t *reader, uint64_t val, int64_t sign) { bson_json_read_state_t rs; bson_json_read_bson_state_t bs; BASIC_CB_PREAMBLE; if (sign == 1 && val > INT64_MAX) { _bson_json_read_set_error (reader, "Number \"%" PRIu64 "\" is out of range", val); return; } else if (sign == -1 && val > ((uint64_t) INT64_MAX + 1)) { _bson_json_read_set_error (reader, "Number \"-%" PRIu64 "\" is out of range", val); return; } rs = bson->read_state; bs = bson->bson_state; if (rs == BSON_JSON_REGULAR) { BASIC_CB_BAIL_IF_NOT_NORMAL ("integer"); if (val <= INT32_MAX || (sign == -1 && val <= (uint64_t) INT32_MAX + 1)) { bson_append_int32 (STACK_BSON_CHILD, key, (int) len, (int) (val * sign)); } else if (sign == -1) { #if defined(_WIN32) && !defined(__MINGW32__) // Unary negation of unsigned integer is deliberate. #pragma warning(suppress : 4146) bson_append_int64 (STACK_BSON_CHILD, key, (int) len, (int64_t) -val); #else bson_append_int64 (STACK_BSON_CHILD, key, (int) len, (int64_t) -val); #endif // defined(_WIN32) && !defined(__MINGW32__) } else { bson_append_int64 (STACK_BSON_CHILD, key, (int) len, (int64_t) val); } } else if (rs == BSON_JSON_IN_BSON_TYPE || rs == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { switch (bs) { case BSON_JSON_LF_DATE: bson->bson_type_data.date.has_date = true; bson->bson_type_data.date.date = sign * val; break; case BSON_JSON_LF_TIMESTAMP_T: if (sign == -1) { _bson_json_read_set_error (reader, "Invalid timestamp value: \"-%" PRIu64 "\"", val); return; } bson->bson_type_data.timestamp.has_t = true; bson->bson_type_data.timestamp.t = (uint32_t) val; break; case BSON_JSON_LF_TIMESTAMP_I: if (sign == -1) { _bson_json_read_set_error (reader, "Invalid timestamp value: \"-%" PRIu64 "\"", val); return; } bson->bson_type_data.timestamp.has_i = true; bson->bson_type_data.timestamp.i = (uint32_t) val; break; case BSON_JSON_LF_MINKEY: if (sign == -1) { _bson_json_read_set_error (reader, "Invalid MinKey value: \"-%" PRIu64 "\"", val); return; } else if (val != 1) { _bson_json_read_set_error (reader, "Invalid MinKey value: \"%" PRIu64 "\"", val); } bson->bson_type_data.minkey.has_minkey = true; break; case BSON_JSON_LF_MAXKEY: if (sign == -1) { _bson_json_read_set_error (reader, "Invalid MinKey value: \"-%" PRIu64 "\"", val); return; } else if (val != 1) { _bson_json_read_set_error (reader, "Invalid MinKey value: \"%" PRIu64 "\"", val); } bson->bson_type_data.maxkey.has_maxkey = true; break; case BSON_JSON_LF_INT32: case BSON_JSON_LF_INT64: _bson_json_read_set_error (reader, "Invalid state for integer read: %s, " "expected number as quoted string like \"123\"", bson_state_names[bs]); break; case BSON_JSON_LF_REGEX: case BSON_JSON_LF_OPTIONS: case BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN: case BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS: case BSON_JSON_LF_CODE: case BSON_JSON_LF_SCOPE: case BSON_JSON_LF_OID: case BSON_JSON_LF_BINARY: case BSON_JSON_LF_TYPE: case BSON_JSON_LF_UUID: case BSON_JSON_LF_UNDEFINED: case BSON_JSON_LF_DOUBLE: case BSON_JSON_LF_DECIMAL128: case BSON_JSON_LF_DBPOINTER: case BSON_JSON_LF_SYMBOL: default: _bson_json_read_set_error (reader, "Unexpected integer %s%" PRIu64 " in type \"%s\"", sign == -1 ? "-" : "", val, _bson_json_type_name (bson->bson_type)); } } else { _bson_json_read_set_error ( reader, "Unexpected integer %s%" PRIu64 " in state \"%s\"", sign == -1 ? "-" : "", val, read_state_names[rs]); } } static bool _bson_json_parse_double (bson_json_reader_t *reader, const char *val, size_t vlen, double *d) { errno = 0; *d = strtod (val, NULL); #ifdef _MSC_VER const double pos_inf = INFINITY; const double neg_inf = -pos_inf; /* Microsoft's strtod parses "NaN", "Infinity", "-Infinity" as 0 */ if (*d == 0.0) { if (!_strnicmp (val, "nan", vlen)) { *d = NAN; return true; } else if (!_strnicmp (val, "infinity", vlen)) { *d = pos_inf; return true; } else if (!_strnicmp (val, "-infinity", vlen)) { *d = neg_inf; return true; } } if ((*d == HUGE_VAL || *d == -HUGE_VAL) && errno == ERANGE) { _bson_json_read_set_error (reader, "Number \"%.*s\" is out of range", (int) vlen, val); return false; } #else /* not MSVC - set err on overflow, but avoid err for infinity */ if ((*d == HUGE_VAL || *d == -HUGE_VAL) && errno == ERANGE && strncasecmp (val, "infinity", vlen) && strncasecmp (val, "-infinity", vlen)) { _bson_json_read_set_error (reader, "Number \"%.*s\" is out of range", (int) vlen, val); return false; } #endif /* _MSC_VER */ return true; } static void _bson_json_read_double (bson_json_reader_t *reader, /* IN */ double val) /* IN */ { BASIC_CB_PREAMBLE; BASIC_CB_BAIL_IF_NOT_NORMAL ("double"); if (!bson_append_double (STACK_BSON_CHILD, key, (int) len, val)) { _bson_json_read_set_error (reader, "Cannot append double value %g", val); } } static bool _bson_json_read_int64_or_set_error (bson_json_reader_t *reader, /* IN */ const unsigned char *val, /* IN */ size_t vlen, /* IN */ int64_t *v64) /* OUT */ { bson_json_reader_bson_t *bson = &reader->bson; char *endptr = NULL; _bson_json_read_fixup_key (bson); errno = 0; *v64 = bson_ascii_strtoll ((const char *) val, &endptr, 10); if (((*v64 == INT64_MIN) || (*v64 == INT64_MAX)) && (errno == ERANGE)) { _bson_json_read_set_error (reader, "Number \"%s\" is out of range", val); return false; } if (endptr != ((const char *) val + vlen)) { _bson_json_read_set_error (reader, "Number \"%s\" is invalid", val); return false; } return true; } static bool _unhexlify_uuid (const char *uuid, uint8_t *out, size_t max) { unsigned int byte; size_t x = 0; int i = 0; BSON_ASSERT (strlen (uuid) == 32); while (SSCANF (&uuid[i], "%2x", &byte) == 1) { if (x >= max) { return false; } out[x++] = (uint8_t) byte; i += 2; } return i == 32; } /* parse a value for "base64", "subType", legacy "$binary" or "$type", or * "$uuid" */ static void _bson_json_parse_binary_elem (bson_json_reader_t *reader, const char *val_w_null, size_t vlen) { bson_json_read_bson_state_t bs; bson_json_bson_data_t *data; int binary_len; BASIC_CB_PREAMBLE; bs = bson->bson_state; data = &bson->bson_type_data; if (bs == BSON_JSON_LF_BINARY) { data->binary.has_binary = true; binary_len = mcommon_b64_pton (val_w_null, NULL, 0); if (binary_len < 0) { _bson_json_read_set_error ( reader, "Invalid input string \"%s\", looking for base64-encoded binary", val_w_null); } _bson_json_buf_ensure (&bson->bson_type_buf[0], (size_t) binary_len + 1); if (mcommon_b64_pton (val_w_null, bson->bson_type_buf[0].buf, (size_t) binary_len + 1) < 0) { _bson_json_read_set_error ( reader, "Invalid input string \"%s\", looking for base64-encoded binary", val_w_null); } bson->bson_type_buf[0].len = (size_t) binary_len; } else if (bs == BSON_JSON_LF_TYPE) { data->binary.has_subtype = true; if (SSCANF (val_w_null, "%02x", &data->binary.type) != 1) { if (!data->binary.is_legacy || data->binary.has_binary) { /* misformatted subtype, like {$binary: {base64: "", subType: "x"}}, * or legacy {$binary: "", $type: "x"} */ _bson_json_read_set_error (reader, "Invalid input string \"%s\", looking for binary subtype", val_w_null); } else { /* actually a query operator: {x: {$type: "array"}}*/ bson->read_state = BSON_JSON_REGULAR; STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, key, (int) len, STACK_BSON_CHILD)); bson_append_utf8 (STACK_BSON_CHILD, "$type", 5, (const char *) val_w_null, (int) vlen); } } } else if (bs == BSON_JSON_LF_UUID) { int nread = 0; char uuid[33]; data->binary.has_binary = true; data->binary.has_subtype = true; data->binary.type = BSON_SUBTYPE_UUID; /* Validate the UUID and extract relevant portions */ /* We can't use %x here as it allows +, -, and 0x prefixes */ #ifdef _MSC_VER SSCANF (val_w_null, "%8c-%4c-%4c-%4c-%12c%n", &uuid[0], 8, &uuid[8], 4, &uuid[12], 4, &uuid[16], 4, &uuid[20], 12, &nread); #else SSCANF (val_w_null, "%8c-%4c-%4c-%4c-%12c%n", &uuid[0], &uuid[8], &uuid[12], &uuid[16], &uuid[20], &nread); #endif uuid[32] = '\0'; if (nread != 36 || val_w_null[nread] != '\0') { _bson_json_read_set_error (reader, "Invalid input string \"%s\", looking for " "a dash-separated UUID string", val_w_null); return; } binary_len = 16; _bson_json_buf_ensure (&bson->bson_type_buf[0], (size_t) binary_len + 1); if (!_unhexlify_uuid (&uuid[0], bson->bson_type_buf[0].buf, (size_t) binary_len)) { _bson_json_read_set_error (reader, "Invalid input string \"%s\", looking for " "a dash-separated UUID string", val_w_null); } bson->bson_type_buf[0].len = (size_t) binary_len; } } static bool _bson_json_allow_embedded_nulls (bson_json_reader_t const *reader) { const bson_json_read_state_t read_state = reader->bson.read_state; const bson_json_read_bson_state_t bson_state = reader->bson.bson_state; if (read_state == BSON_JSON_IN_BSON_TYPE_REGEX_VALUES) { if (bson_state == BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN || bson_state == BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS) { /* Prohibit embedded NULL bytes for canonical extended regex: * { $regularExpression: { pattern: "pattern", options: "options" } } */ return false; } } if (read_state == BSON_JSON_IN_BSON_TYPE) { if (bson_state == BSON_JSON_LF_REGEX || bson_state == BSON_JSON_LF_OPTIONS) { /* Prohibit embedded NULL bytes for legacy regex: * { $regex: "pattern", $options: "options" } */ return false; } } /* Embedded nulls are okay in any other context */ return true; } static void _bson_json_read_string (bson_json_reader_t *reader, /* IN */ const unsigned char *val, /* IN */ size_t vlen) /* IN */ { bson_json_read_state_t rs; bson_json_read_bson_state_t bs; const bool allow_null = _bson_json_allow_embedded_nulls (reader); BASIC_CB_PREAMBLE; rs = bson->read_state; bs = bson->bson_state; if (!bson_utf8_validate ((const char *) val, vlen, allow_null)) { _bson_json_read_corrupt (reader, "invalid bytes in UTF8 string"); return; } if (rs == BSON_JSON_REGULAR) { BASIC_CB_BAIL_IF_NOT_NORMAL ("string"); bson_append_utf8 (STACK_BSON_CHILD, key, (int) len, (const char *) val, (int) vlen); } else if (rs == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP || rs == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { _bson_json_read_set_error (reader, "Invalid read of \"%s\" in state \"%s\"", val, read_state_names[rs]); } else if (rs == BSON_JSON_IN_BSON_TYPE_BINARY_VALUES) { const char *val_w_null; _bson_json_buf_set (&bson->bson_type_buf[2], val, vlen); val_w_null = (const char *) bson->bson_type_buf[2].buf; _bson_json_parse_binary_elem (reader, val_w_null, vlen); } else if (rs == BSON_JSON_IN_BSON_TYPE || rs == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES || rs == BSON_JSON_IN_BSON_TYPE_REGEX_VALUES || rs == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { const char *val_w_null; _bson_json_buf_set (&bson->bson_type_buf[2], val, vlen); val_w_null = (const char *) bson->bson_type_buf[2].buf; switch (bs) { case BSON_JSON_LF_REGEX: bson->bson_type_data.regex.is_legacy = true; /* FALL THROUGH */ case BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN: bson->bson_type_data.regex.has_pattern = true; _bson_json_buf_set (&bson->bson_type_buf[0], val, vlen); break; case BSON_JSON_LF_OPTIONS: bson->bson_type_data.regex.is_legacy = true; /* FALL THROUGH */ case BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS: bson->bson_type_data.regex.has_options = true; _bson_json_buf_set (&bson->bson_type_buf[1], val, vlen); break; case BSON_JSON_LF_OID: if (vlen != 24) { goto BAD_PARSE; } bson->bson_type_data.oid.has_oid = true; bson_oid_init_from_string (&bson->bson_type_data.oid.oid, val_w_null); break; case BSON_JSON_LF_BINARY: case BSON_JSON_LF_TYPE: bson->bson_type_data.binary.is_legacy = true; /* FALL THROUGH */ case BSON_JSON_LF_UUID: _bson_json_parse_binary_elem (reader, val_w_null, vlen); break; case BSON_JSON_LF_INT32: { int64_t v64; if (!_bson_json_read_int64_or_set_error (reader, val, vlen, &v64)) { /* the error is set, return and let the reader exit */ return; } if (v64 < INT32_MIN || v64 > INT32_MAX) { goto BAD_PARSE; } if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { bson->bson_type_data.v_int32.value = (int32_t) v64; } else { goto BAD_PARSE; } } break; case BSON_JSON_LF_INT64: { int64_t v64; if (!_bson_json_read_int64_or_set_error (reader, val, vlen, &v64)) { /* the error is set, return and let the reader exit */ return; } if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { bson->bson_type_data.v_int64.value = v64; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { bson->bson_type_data.date.has_date = true; bson->bson_type_data.date.date = v64; } else { goto BAD_PARSE; } } break; case BSON_JSON_LF_DOUBLE: { if (!_bson_json_parse_double (reader, (const char *) val, vlen, &bson->bson_type_data.v_double.value)) { /* the error is set, return and let the reader exit */ return; } } break; case BSON_JSON_LF_DATE: { int64_t v64; if (!_bson_iso8601_date_parse ((char *) val, (int) vlen, &v64, reader->error)) { jsonsl_stop (reader->json); } else { bson->bson_type_data.date.has_date = true; bson->bson_type_data.date.date = v64; } } break; case BSON_JSON_LF_DECIMAL128: { bson_decimal128_t decimal128; if (bson_decimal128_from_string (val_w_null, &decimal128) && bson->read_state == BSON_JSON_IN_BSON_TYPE) { bson->bson_type_data.v_decimal128.value = decimal128; } else { goto BAD_PARSE; } } break; case BSON_JSON_LF_CODE: _bson_json_buf_set (&bson->code_data.code_buf, val, vlen); break; case BSON_JSON_LF_SYMBOL: bson_append_symbol (STACK_BSON_CHILD, key, (int) len, (const char *) val, (int) vlen); break; case BSON_JSON_LF_SCOPE: case BSON_JSON_LF_TIMESTAMP_T: case BSON_JSON_LF_TIMESTAMP_I: case BSON_JSON_LF_UNDEFINED: case BSON_JSON_LF_MINKEY: case BSON_JSON_LF_MAXKEY: case BSON_JSON_LF_DBPOINTER: default: goto BAD_PARSE; } return; BAD_PARSE: _bson_json_read_set_error ( reader, "Invalid input string \"%s\", looking for %s", val_w_null, bson_state_names[bs]); } else { _bson_json_read_set_error (reader, "Invalid state to look for string: %s", read_state_names[rs]); } } static void _bson_json_read_start_map (bson_json_reader_t *reader) /* IN */ { BASIC_CB_PREAMBLE; if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { switch (bson->bson_state) { case BSON_JSON_LF_DATE: bson->read_state = BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG; break; case BSON_JSON_LF_BINARY: bson->read_state = BSON_JSON_IN_BSON_TYPE_BINARY_VALUES; break; case BSON_JSON_LF_TYPE: /* special case, we started parsing {$type: {$numberInt: "2"}} and we * expected a legacy Binary format. now we see the second "{", so * backtrack and parse $type query operator. */ bson->read_state = BSON_JSON_IN_START_MAP; BSON_ASSERT (mcommon_in_range_unsigned (int, len)); STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, key, (int) len, STACK_BSON_CHILD)); _bson_json_save_map_key (bson, (const uint8_t *) "$type", 5); break; case BSON_JSON_LF_CODE: case BSON_JSON_LF_DECIMAL128: case BSON_JSON_LF_DOUBLE: case BSON_JSON_LF_INT32: case BSON_JSON_LF_INT64: case BSON_JSON_LF_MAXKEY: case BSON_JSON_LF_MINKEY: case BSON_JSON_LF_OID: case BSON_JSON_LF_OPTIONS: case BSON_JSON_LF_REGEX: /** * NOTE: A read_state of BSON_JSON_IN_BSON_TYPE is used when "$regex" is * found, but BSON_JSON_IN_BSON_TYPE_REGEX_STARTMAP is used for * "$regularExpression", which will instead go to a below 'if else' branch * instead of this switch statement. They're both called "regex" in their * respective enumerators, but they behave differently when parsing. */ // fallthrough case BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS: case BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN: case BSON_JSON_LF_SYMBOL: case BSON_JSON_LF_UNDEFINED: case BSON_JSON_LF_UUID: // These special keys do not expect objects as their values. Fail. _bson_json_read_set_error ( reader, "Unexpected nested object value for \"%s\" key", reader->bson.unescaped.buf); break; case BSON_JSON_LF_DBPOINTER: case BSON_JSON_LF_SCOPE: case BSON_JSON_LF_TIMESTAMP_I: case BSON_JSON_LF_TIMESTAMP_T: default: // These special LF keys aren't handled with BSON_JSON_IN_BSON_TYPE BSON_UNREACHABLE ("These LF values are handled with a different read_state"); } } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP) { bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP) { bson->read_state = BSON_JSON_IN_SCOPE; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { bson->read_state = BSON_JSON_IN_DBPOINTER; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_REGEX_STARTMAP) { bson->read_state = BSON_JSON_IN_BSON_TYPE_REGEX_VALUES; } else { bson->read_state = BSON_JSON_IN_START_MAP; } /* silence some warnings */ (void) len; (void) key; } #define BSON_PRIVATE_SPECIAL_KEYS_XMACRO(X) \ X (binary) \ X (code) \ X (date) \ X (dbPointer) \ X (maxKey) \ X (minKey) \ X (numberDecimal) \ X (numberDouble) \ X (numberInt) \ X (numberLong) \ X (oid) \ X (options) \ X (regex) \ X (regularExpression) \ X (scope) \ X (symbol) \ X (timestamp) \ X (type) \ X (undefined) \ X (uuid) static bool _is_known_key (const char *key, size_t len) { #define IS_KEY(k) \ if (len == strlen ("$" #k) && (0 == memcmp ("$" #k, key, len))) { \ return true; \ } BSON_PRIVATE_SPECIAL_KEYS_XMACRO (IS_KEY) #undef IS_KEY return false; } static void _bson_json_save_map_key (bson_json_reader_bson_t *bson, const uint8_t *val, size_t len) { _bson_json_buf_set (&bson->key_buf, val, len); bson->key = (const char *) bson->key_buf.buf; } static void _bson_json_read_code_or_scope_key (bson_json_reader_bson_t *bson, bool is_scope, const uint8_t *val, size_t len) { bson_json_code_t *code = &bson->code_data; if (code->in_scope) { /* we're reading something weirdly nested, e.g. we just read "$code" in * "$scope: {x: {$code: {}}}". just create the subdoc within the scope. */ bson->read_state = BSON_JSON_REGULAR; STACK_PUSH_DOC ( bson_append_document_begin (STACK_BSON_PARENT, bson->key, (int) bson->key_buf.len, STACK_BSON_CHILD)); _bson_json_save_map_key (bson, val, len); } else { if (!bson->code_data.key_buf.len) { /* save the key, e.g. {"key": {"$code": "return x", "$scope":{"x":1}}}, * in case it is overwritten while parsing scope sub-object */ _bson_json_buf_set (&bson->code_data.key_buf, bson->key, bson->key_buf.len); } if (is_scope) { bson->bson_type = BSON_TYPE_CODEWSCOPE; bson->read_state = BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP; bson->bson_state = BSON_JSON_LF_SCOPE; bson->code_data.has_scope = true; } else { bson->bson_type = BSON_TYPE_CODE; bson->bson_state = BSON_JSON_LF_CODE; bson->code_data.has_code = true; } } } static void _bson_json_bad_key_in_type (bson_json_reader_t *reader, /* IN */ const uint8_t *val) /* IN */ { bson_json_reader_bson_t *bson = &reader->bson; _bson_json_read_set_error ( reader, "Invalid key \"%s\". Looking for values for type \"%s\"", val, _bson_json_type_name (bson->bson_type)); } static void _bson_json_read_map_key (bson_json_reader_t *reader, /* IN */ const uint8_t *val, /* IN */ size_t len) /* IN */ { bson_json_reader_bson_t *bson = &reader->bson; if (!bson_utf8_validate ((const char *) val, len, false /* allow null */)) { _bson_json_read_corrupt (reader, "invalid bytes in UTF8 string"); return; } const char *const key = (const char *) val; if (bson->read_state == BSON_JSON_IN_START_MAP) { if (len > 0 && key[0] == '$' && _is_known_key (key, len) && bson->n >= 0 /* key is in subdocument */) { bson->read_state = BSON_JSON_IN_BSON_TYPE; bson->bson_type = (bson_type_t) 0; memset (&bson->bson_type_data, 0, sizeof bson->bson_type_data); } else { bson->read_state = BSON_JSON_REGULAR; STACK_PUSH_DOC ( bson_append_document_begin (STACK_BSON_PARENT, bson->key, (int) bson->key_buf.len, STACK_BSON_CHILD)); } } else if (bson->read_state == BSON_JSON_IN_SCOPE) { /* we've read "key" in {$code: "", $scope: {key: ""}}*/ bson->read_state = BSON_JSON_REGULAR; STACK_PUSH_SCOPE; _bson_json_save_map_key (bson, val, len); } else if (bson->read_state == BSON_JSON_IN_DBPOINTER) { /* we've read "$ref" or "$id" in {$dbPointer: {$ref: ..., $id: ...}} */ bson->read_state = BSON_JSON_REGULAR; STACK_PUSH_DBPOINTER; _bson_json_save_map_key (bson, val, len); } if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { HANDLE_OPTION (if, "$regex", BSON_TYPE_REGEX, BSON_JSON_LF_REGEX) HANDLE_OPTION (else if, "$options", BSON_TYPE_REGEX, BSON_JSON_LF_OPTIONS) HANDLE_OPTION (else if, "$oid", BSON_TYPE_OID, BSON_JSON_LF_OID) HANDLE_OPTION (else if, "$binary", BSON_TYPE_BINARY, BSON_JSON_LF_BINARY) HANDLE_OPTION (else if, "$type", BSON_TYPE_BINARY, BSON_JSON_LF_TYPE) HANDLE_OPTION (else if, "$uuid", BSON_TYPE_BINARY, BSON_JSON_LF_UUID) HANDLE_OPTION (else if, "$date", BSON_TYPE_DATE_TIME, BSON_JSON_LF_DATE) HANDLE_OPTION (else if, "$undefined", BSON_TYPE_UNDEFINED, BSON_JSON_LF_UNDEFINED) HANDLE_OPTION (else if, "$minKey", BSON_TYPE_MINKEY, BSON_JSON_LF_MINKEY) HANDLE_OPTION (else if, "$maxKey", BSON_TYPE_MAXKEY, BSON_JSON_LF_MAXKEY) HANDLE_OPTION (else if, "$numberInt", BSON_TYPE_INT32, BSON_JSON_LF_INT32) HANDLE_OPTION (else if, "$numberLong", BSON_TYPE_INT64, BSON_JSON_LF_INT64) HANDLE_OPTION (else if, "$numberDouble", BSON_TYPE_DOUBLE, BSON_JSON_LF_DOUBLE) HANDLE_OPTION (else if, "$symbol", BSON_TYPE_SYMBOL, BSON_JSON_LF_SYMBOL) HANDLE_OPTION (else if, "$numberDecimal", BSON_TYPE_DECIMAL128, BSON_JSON_LF_DECIMAL128) else if (HANDLE_OPTION_KEY_COMPARE ("$timestamp")) { HANDLE_OPTION_TYPE_CHECK ("$timestamp", BSON_TYPE_TIMESTAMP); bson->bson_type = BSON_TYPE_TIMESTAMP; bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP; } else if (HANDLE_OPTION_KEY_COMPARE ("$regularExpression")) { HANDLE_OPTION_TYPE_CHECK ("$regularExpression", BSON_TYPE_REGEX); bson->bson_type = BSON_TYPE_REGEX; bson->read_state = BSON_JSON_IN_BSON_TYPE_REGEX_STARTMAP; } else if (HANDLE_OPTION_KEY_COMPARE ("$dbPointer")) { HANDLE_OPTION_TYPE_CHECK ("$dbPointer", BSON_TYPE_DBPOINTER); /* start parsing "key": {"$dbPointer": {...}}, save "key" for later */ _bson_json_buf_set (&bson->dbpointer_key, bson->key, bson->key_buf.len); bson->bson_type = BSON_TYPE_DBPOINTER; bson->read_state = BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP; } else if (HANDLE_OPTION_KEY_COMPARE ("$code")) { // "$code" may come after "$scope". if (bson->bson_type != BSON_TYPE_CODEWSCOPE) { HANDLE_OPTION_TYPE_CHECK ("$code", BSON_TYPE_CODE); } _bson_json_read_code_or_scope_key (bson, false /* is_scope */, val, len); } else if (HANDLE_OPTION_KEY_COMPARE ("$scope")) { // "$scope" may come after "$code". if (bson->bson_type != BSON_TYPE_CODE) { HANDLE_OPTION_TYPE_CHECK ("$scope", BSON_TYPE_CODEWSCOPE); } _bson_json_read_code_or_scope_key (bson, true /* is_scope */, val, len); } else { _bson_json_bad_key_in_type (reader, val); } } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { HANDLE_OPTION (if, "$numberLong", BSON_TYPE_DATE_TIME, BSON_JSON_LF_INT64) else { _bson_json_bad_key_in_type (reader, val); } } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { HANDLE_OPTION (if, "t", BSON_TYPE_TIMESTAMP, BSON_JSON_LF_TIMESTAMP_T) HANDLE_OPTION (else if, "i", BSON_TYPE_TIMESTAMP, BSON_JSON_LF_TIMESTAMP_I) else { _bson_json_bad_key_in_type (reader, val); } } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_REGEX_VALUES) { HANDLE_OPTION (if, "pattern", BSON_TYPE_REGEX, BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN) HANDLE_OPTION (else if, "options", BSON_TYPE_REGEX, BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS) else { _bson_json_bad_key_in_type (reader, val); } } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_BINARY_VALUES) { HANDLE_OPTION (if, "base64", BSON_TYPE_BINARY, BSON_JSON_LF_BINARY) HANDLE_OPTION (else if, "subType", BSON_TYPE_BINARY, BSON_JSON_LF_TYPE) else { _bson_json_bad_key_in_type (reader, val); } } else { _bson_json_save_map_key (bson, val, len); } } static void _bson_json_read_append_binary (bson_json_reader_t *reader, /* IN */ bson_json_reader_bson_t *bson) /* IN */ { bson_json_bson_data_t *data = &bson->bson_type_data; if (data->binary.is_legacy) { if (!data->binary.has_binary) { _bson_json_read_set_error (reader, "Missing \"$binary\" after \"$type\" reading type \"binary\""); return; } else if (!data->binary.has_subtype) { _bson_json_read_set_error (reader, "Missing \"$type\" after \"$binary\" reading type \"binary\""); return; } } else { if (!data->binary.has_binary) { _bson_json_read_set_error (reader, "Missing \"base64\" after \"subType\" reading type \"binary\""); return; } else if (!data->binary.has_subtype) { _bson_json_read_set_error (reader, "Missing \"subType\" after \"base64\" reading type \"binary\""); return; } } if (!bson_append_binary (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, data->binary.type, bson->bson_type_buf[0].buf, (uint32_t) bson->bson_type_buf[0].len)) { _bson_json_read_set_error (reader, "Error storing binary data"); } } static void _bson_json_read_append_regex (bson_json_reader_t *reader, /* IN */ bson_json_reader_bson_t *bson) /* IN */ { bson_json_bson_data_t *data = &bson->bson_type_data; if (data->regex.is_legacy) { if (!data->regex.has_pattern) { _bson_json_read_set_error (reader, "Missing \"$regex\" after \"$options\""); return; } } else if (!data->regex.has_pattern) { _bson_json_read_set_error (reader, "Missing \"pattern\" after \"options\" in regular expression"); return; } else if (!data->regex.has_options) { _bson_json_read_set_error (reader, "Missing \"options\" after \"pattern\" in regular expression"); return; } if (!bson_append_regex (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, (char *) bson->bson_type_buf[0].buf, (char *) bson->bson_type_buf[1].buf)) { _bson_json_read_set_error (reader, "Error storing regex"); } } static void _bson_json_read_append_code (bson_json_reader_t *reader, /* IN */ bson_json_reader_bson_t *bson) /* IN */ { bson_json_code_t *code_data; char *code = NULL; bson_t *scope = NULL; bool r; code_data = &bson->code_data; BSON_ASSERT (!code_data->in_scope); if (!code_data->has_code) { _bson_json_read_set_error (reader, "Missing $code after $scope"); return; } code = (char *) code_data->code_buf.buf; if (code_data->has_scope) { scope = STACK_BSON (1); } /* creates BSON "code" elem, or "code with scope" if scope is not NULL */ r = bson_append_code_with_scope ( STACK_BSON_CHILD, (const char *) code_data->key_buf.buf, (int) code_data->key_buf.len, code, scope); if (!r) { _bson_json_read_set_error (reader, "Error storing Javascript code"); } /* keep the buffer but truncate it */ code_data->key_buf.len = 0; code_data->has_code = code_data->has_scope = false; } static void _bson_json_read_append_dbpointer (bson_json_reader_t *reader, /* IN */ bson_json_reader_bson_t *bson) /* IN */ { bson_t *db_pointer; bson_iter_t iter; const char *ns = NULL; const bson_oid_t *oid = NULL; bool r; BSON_ASSERT (reader->bson.dbpointer_key.buf); db_pointer = STACK_BSON (1); if (!bson_iter_init (&iter, db_pointer)) { _bson_json_read_set_error (reader, "Error storing DBPointer"); return; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "$id")) { if (!BSON_ITER_HOLDS_OID (&iter)) { _bson_json_read_set_error (reader, "$dbPointer.$id must be like {\"$oid\": ...\"}"); return; } oid = bson_iter_oid (&iter); } else if (!strcmp (bson_iter_key (&iter), "$ref")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { _bson_json_read_set_error (reader, "$dbPointer.$ref must be a string like \"db.collection\""); return; } ns = bson_iter_utf8 (&iter, NULL); } else { _bson_json_read_set_error (reader, "$dbPointer contains invalid key: \"%s\"", bson_iter_key (&iter)); return; } } if (!oid || !ns) { _bson_json_read_set_error (reader, "$dbPointer requires both $id and $ref"); return; } r = bson_append_dbpointer ( STACK_BSON_CHILD, (char *) reader->bson.dbpointer_key.buf, (int) reader->bson.dbpointer_key.len, ns, oid); if (!r) { _bson_json_read_set_error (reader, "Error storing DBPointer"); } } static void _bson_json_read_append_oid (bson_json_reader_t *reader, /* IN */ bson_json_reader_bson_t *bson) /* IN */ { if (!bson_append_oid (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, &bson->bson_type_data.oid.oid)) { _bson_json_read_set_error (reader, "Error storing ObjectId"); } } static void _bson_json_read_append_date_time (bson_json_reader_t *reader, /* IN */ bson_json_reader_bson_t *bson) /* IN */ { if (!bson_append_date_time (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.date.date)) { _bson_json_read_set_error (reader, "Error storing datetime"); } } static void _bson_json_read_append_timestamp (bson_json_reader_t *reader, /* IN */ bson_json_reader_bson_t *bson) /* IN */ { if (!bson->bson_type_data.timestamp.has_t) { _bson_json_read_set_error (reader, "Missing t after $timestamp in BSON_TYPE_TIMESTAMP"); return; } else if (!bson->bson_type_data.timestamp.has_i) { _bson_json_read_set_error (reader, "Missing i after $timestamp in BSON_TYPE_TIMESTAMP"); return; } bson_append_timestamp (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.timestamp.t, bson->bson_type_data.timestamp.i); } static void _bad_extended_json (bson_json_reader_t *reader) { _bson_json_read_corrupt (reader, "Invalid MongoDB extended JSON"); } static void _bson_json_read_end_map (bson_json_reader_t *reader) /* IN */ { bson_json_reader_bson_t *bson = &reader->bson; bool r = true; if (bson->read_state == BSON_JSON_IN_START_MAP) { bson->read_state = BSON_JSON_REGULAR; STACK_PUSH_DOC ( bson_append_document_begin (STACK_BSON_PARENT, bson->key, (int) bson->key_buf.len, STACK_BSON_CHILD)); } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP) { bson->read_state = BSON_JSON_REGULAR; STACK_PUSH_SCOPE; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { /* we've read last "}" in "{$dbPointer: {$id: ..., $ref: ...}}" */ _bson_json_read_append_dbpointer (reader, bson); bson->read_state = BSON_JSON_REGULAR; return; } if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { if (!bson->key) { /* invalid, like {$numberLong: "1"} at the document top level */ _bad_extended_json (reader); return; } bson->read_state = BSON_JSON_REGULAR; switch (bson->bson_type) { case BSON_TYPE_REGEX: _bson_json_read_append_regex (reader, bson); break; case BSON_TYPE_CODE: case BSON_TYPE_CODEWSCOPE: /* we've read the closing "}" in "{$code: ..., $scope: ...}" */ _bson_json_read_append_code (reader, bson); break; case BSON_TYPE_OID: _bson_json_read_append_oid (reader, bson); break; case BSON_TYPE_BINARY: _bson_json_read_append_binary (reader, bson); break; case BSON_TYPE_DATE_TIME: _bson_json_read_append_date_time (reader, bson); break; case BSON_TYPE_UNDEFINED: r = bson_append_undefined (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); break; case BSON_TYPE_MINKEY: r = bson_append_minkey (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); break; case BSON_TYPE_MAXKEY: r = bson_append_maxkey (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); break; case BSON_TYPE_INT32: r = bson_append_int32 ( STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.v_int32.value); break; case BSON_TYPE_INT64: r = bson_append_int64 ( STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.v_int64.value); break; case BSON_TYPE_DOUBLE: r = bson_append_double ( STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.v_double.value); break; case BSON_TYPE_DECIMAL128: r = bson_append_decimal128 ( STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, &bson->bson_type_data.v_decimal128.value); break; case BSON_TYPE_DBPOINTER: /* shouldn't set type to DBPointer unless inside $dbPointer: {...} */ _bson_json_read_set_error (reader, "Internal error: shouldn't be in state BSON_TYPE_DBPOINTER"); break; case BSON_TYPE_SYMBOL: break; case BSON_TYPE_EOD: case BSON_TYPE_UTF8: case BSON_TYPE_DOCUMENT: case BSON_TYPE_ARRAY: case BSON_TYPE_BOOL: case BSON_TYPE_NULL: case BSON_TYPE_TIMESTAMP: default: _bson_json_read_set_error ( reader, "Internal error: can't parse JSON wrapper for type \"%s\"", _bson_json_type_name (bson->bson_type)); break; } if (!r) { _bson_json_read_set_error (reader, "Cannot append value at end of JSON object for key %s", bson->key); } } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { if (!bson->key) { _bad_extended_json (reader); return; } bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_ENDMAP; _bson_json_read_append_timestamp (reader, bson); return; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_REGEX_VALUES) { if (!bson->key) { _bad_extended_json (reader); return; } bson->read_state = BSON_JSON_IN_BSON_TYPE_REGEX_ENDMAP; _bson_json_read_append_regex (reader, bson); return; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_BINARY_VALUES) { if (!bson->key) { _bad_extended_json (reader); return; } bson->read_state = BSON_JSON_IN_BSON_TYPE_BINARY_ENDMAP; _bson_json_read_append_binary (reader, bson); return; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_ENDMAP) { bson->read_state = BSON_JSON_REGULAR; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_REGEX_ENDMAP) { bson->read_state = BSON_JSON_REGULAR; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_BINARY_ENDMAP) { bson->read_state = BSON_JSON_REGULAR; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { if (!bson->key) { _bad_extended_json (reader); return; } bson->read_state = BSON_JSON_IN_BSON_TYPE_DATE_ENDMAP; _bson_json_read_append_date_time (reader, bson); return; } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_ENDMAP) { bson->read_state = BSON_JSON_REGULAR; } else if (bson->read_state == BSON_JSON_REGULAR) { if (STACK_IS_SCOPE) { bson->read_state = BSON_JSON_IN_BSON_TYPE; bson->bson_type = BSON_TYPE_CODE; STACK_POP_SCOPE; } else if (STACK_IS_DBPOINTER) { bson->read_state = BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP; STACK_POP_DBPOINTER; } else { STACK_POP_DOC (bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); } if (bson->n == -1) { bson->read_state = BSON_JSON_DONE; } } else if (bson->read_state == BSON_JSON_IN_SCOPE) { /* empty $scope */ BSON_ASSERT (bson->code_data.has_scope); STACK_PUSH_SCOPE; STACK_POP_SCOPE; bson->read_state = BSON_JSON_IN_BSON_TYPE; bson->bson_type = BSON_TYPE_CODE; } else if (bson->read_state == BSON_JSON_IN_DBPOINTER) { /* empty $dbPointer??? */ _bson_json_read_set_error (reader, "Empty $dbPointer"); } else { _bson_json_read_set_error (reader, "Invalid state \"%s\"", read_state_names[bson->read_state]); } } static void _bson_json_read_start_array (bson_json_reader_t *reader) /* IN */ { const char *key; size_t len; bson_json_reader_bson_t *bson = &reader->bson; if (bson->read_state != BSON_JSON_REGULAR) { _bson_json_read_set_error (reader, "Invalid read of \"[\" in state \"%s\"", read_state_names[bson->read_state]); return; } if (bson->n == -1) { STACK_PUSH_ARRAY (_noop ()); } else { _bson_json_read_fixup_key (bson); key = bson->key; len = bson->key_buf.len; STACK_PUSH_ARRAY (bson_append_array_begin (STACK_BSON_PARENT, key, (int) len, STACK_BSON_CHILD)); } } static void _bson_json_read_end_array (bson_json_reader_t *reader) /* IN */ { bson_json_reader_bson_t *bson = &reader->bson; if (bson->read_state != BSON_JSON_REGULAR) { _bson_json_read_set_error (reader, "Invalid read of \"]\" in state \"%s\"", read_state_names[bson->read_state]); return; } STACK_POP_ARRAY (bson_append_array_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); if (bson->n == -1) { bson->read_state = BSON_JSON_DONE; } } /* put unescaped text in reader->bson.unescaped, or set reader->error. * json_text has length len and it is not null-terminated. */ static bool _bson_json_unescape (bson_json_reader_t *reader, struct jsonsl_state_st *state, const char *json_text, ssize_t len) { bson_json_reader_bson_t *reader_bson; jsonsl_error_t err; reader_bson = &reader->bson; /* add 1 for NULL */ _bson_json_buf_ensure (&reader_bson->unescaped, (size_t) len + 1); /* length of unescaped str is always <= len */ reader_bson->unescaped.len = jsonsl_util_unescape (json_text, (char *) reader_bson->unescaped.buf, (size_t) len, NULL, &err); if (err != JSONSL_ERROR_SUCCESS) { bson_set_error (reader->error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_CORRUPT_JS, "error near position %d: \"%s\"", (int) state->pos_begin, jsonsl_strerror (err)); return false; } reader_bson->unescaped.buf[reader_bson->unescaped.len] = '\0'; return true; } /* read the buffered JSON plus new data, and fill out @len with its length */ static const char * _get_json_text (jsonsl_t json, /* IN */ struct jsonsl_state_st *state, /* IN */ const char *buf /* IN */, ssize_t *len /* OUT */) { bson_json_reader_t *reader; ssize_t bytes_available; reader = (bson_json_reader_t *) json->data; BSON_ASSERT (state->pos_cur > state->pos_begin); *len = (ssize_t) (state->pos_cur - state->pos_begin); bytes_available = buf - json->base; if (*len <= bytes_available) { /* read directly from stream, not from saved JSON */ return buf - (size_t) *len; } else { /* combine saved text with new data from the jsonsl_t */ ssize_t append = buf - json->base; if (append > 0) { _bson_json_buf_append (&reader->tok_accumulator, buf - append, (size_t) append); } return (const char *) reader->tok_accumulator.buf; } } static void _push_callback (jsonsl_t json, jsonsl_action_t action, struct jsonsl_state_st *state, const char *buf) { bson_json_reader_t *reader = (bson_json_reader_t *) json->data; BSON_UNUSED (action); BSON_UNUSED (buf); switch (state->type) { case JSONSL_T_STRING: case JSONSL_T_HKEY: case JSONSL_T_SPECIAL: case JSONSL_T_UESCAPE: reader->json_text_pos = state->pos_begin; break; case JSONSL_T_OBJECT: _bson_json_read_start_map (reader); break; case JSONSL_T_LIST: _bson_json_read_start_array (reader); break; default: break; } } static void _pop_callback (jsonsl_t json, jsonsl_action_t action, struct jsonsl_state_st *state, const char *buf) { bson_json_reader_t *reader; bson_json_reader_bson_t *reader_bson; ssize_t len; double d; const char *obj_text; BSON_UNUSED (action); reader = (bson_json_reader_t *) json->data; reader_bson = &reader->bson; switch (state->type) { case JSONSL_T_HKEY: case JSONSL_T_STRING: obj_text = _get_json_text (json, state, buf, &len); BSON_ASSERT (obj_text[0] == '"'); /* remove start/end quotes, replace backslash-escapes, null-terminate */ /* you'd think it would be faster to check if state->nescapes > 0 first, * but tests show no improvement */ if (!_bson_json_unescape (reader, state, obj_text + 1, len - 1)) { /* reader->error is set */ jsonsl_stop (json); break; } if (state->type == JSONSL_T_HKEY) { _bson_json_read_map_key (reader, reader_bson->unescaped.buf, reader_bson->unescaped.len); } else { _bson_json_read_string (reader, reader_bson->unescaped.buf, reader_bson->unescaped.len); } break; case JSONSL_T_OBJECT: _bson_json_read_end_map (reader); break; case JSONSL_T_LIST: _bson_json_read_end_array (reader); break; case JSONSL_T_SPECIAL: obj_text = _get_json_text (json, state, buf, &len); if (state->special_flags & JSONSL_SPECIALf_NUMNOINT) { if (_bson_json_parse_double (reader, obj_text, (size_t) len, &d)) { _bson_json_read_double (reader, d); } } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) { /* jsonsl puts the unsigned value in state->nelem */ _bson_json_read_integer (reader, state->nelem, state->special_flags & JSONSL_SPECIALf_SIGNED ? -1 : 1); } else if (state->special_flags & JSONSL_SPECIALf_BOOLEAN) { _bson_json_read_boolean (reader, obj_text[0] == 't' ? 1 : 0); } else if (state->special_flags & JSONSL_SPECIALf_NULL) { _bson_json_read_null (reader); } break; default: break; } reader->json_text_pos = -1; reader->tok_accumulator.len = 0; } static int _error_callback (jsonsl_t json, jsonsl_error_t err, struct jsonsl_state_st *state, char *errat) { bson_json_reader_t *reader = (bson_json_reader_t *) json->data; BSON_UNUSED (state); if (err == JSONSL_ERROR_CANT_INSERT && *errat == '{') { /* start the next document */ reader->should_reset = true; reader->advance = errat - json->base; return 0; } bson_set_error (reader->error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_CORRUPT_JS, "Got parse error at \"%c\", position %d: \"%s\"", *errat, (int) json->pos, jsonsl_strerror (err)); return 0; } /* *-------------------------------------------------------------------------- * * bson_json_reader_read -- * * Read the next json document from @reader and write its value * into @bson. @bson will be allocated as part of this process. * * @bson MUST be initialized before calling this function as it * will not be initialized automatically. The reasoning for this * is so that you can chain together bson_json_reader_t with * other components like bson_writer_t. * * Returns: * 1 if successful and data was read. * 0 if successful and no data was read. * -1 if there was an error and @error is set. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ int bson_json_reader_read (bson_json_reader_t *reader, /* IN */ bson_t *bson, /* IN */ bson_error_t *error) /* OUT */ { bson_json_reader_producer_t *p; ssize_t start_pos; ssize_t r; ssize_t buf_offset; ssize_t accum; bson_error_t error_tmp; int ret = 0; BSON_ASSERT (reader); BSON_ASSERT (bson); p = &reader->producer; reader->bson.bson = bson; reader->bson.n = -1; reader->bson.read_state = BSON_JSON_REGULAR; reader->error = error ? error : &error_tmp; memset (reader->error, 0, sizeof (bson_error_t)); for (;;) { start_pos = reader->json->pos; if (p->bytes_read > 0) { /* leftover data from previous JSON doc in the stream */ r = p->bytes_read; } else { /* read a chunk of bytes by executing the callback */ r = p->cb (p->data, p->buf, p->buf_size); } if (r < 0) { if (error) { bson_set_error (error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_CB_FAILURE, "reader cb failed"); } ret = -1; goto cleanup; } else if (r == 0) { break; } else { ret = 1; p->bytes_read = (size_t) r; jsonsl_feed (reader->json, (const jsonsl_char_t *) p->buf, (size_t) r); if (reader->should_reset) { /* end of a document */ jsonsl_reset (reader->json); reader->should_reset = false; /* advance past already-parsed data */ memmove (p->buf, p->buf + reader->advance, r - reader->advance); p->bytes_read -= reader->advance; ret = 1; goto cleanup; } if (reader->error->domain) { ret = -1; goto cleanup; } /* accumulate a key or string value */ if (reader->json_text_pos != -1) { if (mcommon_cmp_less_su (reader->json_text_pos, reader->json->pos)) { BSON_ASSERT (mcommon_in_range_unsigned (ssize_t, reader->json->pos)); accum = BSON_MIN ((ssize_t) reader->json->pos - reader->json_text_pos, r); /* if this chunk stopped mid-token, buf_offset is how far into * our current chunk the token begins. */ buf_offset = AT_LEAST_0 (reader->json_text_pos - start_pos); _bson_json_buf_append (&reader->tok_accumulator, p->buf + buf_offset, (size_t) accum); } } p->bytes_read = 0; } } cleanup: if (ret == 1 && reader->bson.read_state != BSON_JSON_DONE) { /* data ended in the middle */ _bson_json_read_corrupt (reader, "%s", "Incomplete JSON"); return -1; } return ret; } bson_json_reader_t * bson_json_reader_new (void *data, /* IN */ bson_json_reader_cb cb, /* IN */ bson_json_destroy_cb dcb, /* IN */ bool allow_multiple, /* unused */ size_t buf_size) /* IN */ { bson_json_reader_t *r; bson_json_reader_producer_t *p; BSON_UNUSED (allow_multiple); r = BSON_ALIGNED_ALLOC0 (bson_json_reader_t); r->json = jsonsl_new (STACK_MAX); r->json->error_callback = _error_callback; r->json->action_callback_PUSH = _push_callback; r->json->action_callback_POP = _pop_callback; r->json->data = r; r->json_text_pos = -1; jsonsl_enable_all_callbacks (r->json); p = &r->producer; p->data = data; p->cb = cb; p->dcb = dcb; p->buf_size = buf_size ? buf_size : BSON_JSON_DEFAULT_BUF_SIZE; p->buf = bson_malloc (p->buf_size); return r; } void bson_json_reader_destroy (bson_json_reader_t *reader) /* IN */ { int i; bson_json_reader_producer_t *p; bson_json_reader_bson_t *b; if (!reader) { return; } p = &reader->producer; b = &reader->bson; if (reader->producer.dcb) { reader->producer.dcb (reader->producer.data); } bson_free (p->buf); bson_free (b->key_buf.buf); bson_free (b->unescaped.buf); bson_free (b->dbpointer_key.buf); /* destroy each bson_t initialized in parser stack frames */ for (i = 1; i < STACK_MAX; i++) { if (b->stack[i].type == BSON_JSON_FRAME_INITIAL) { /* highest the stack grew */ break; } if (FRAME_TYPE_HAS_BSON (b->stack[i].type)) { bson_destroy (&b->stack[i].bson); } } for (i = 0; i < 3; i++) { bson_free (b->bson_type_buf[i].buf); } _bson_json_code_cleanup (&b->code_data); jsonsl_destroy (reader->json); bson_free (reader->tok_accumulator.buf); bson_free (reader); } void bson_json_opts_set_outermost_array (bson_json_opts_t *opts, bool is_outermost_array) { opts->is_outermost_array = is_outermost_array; } typedef struct { const uint8_t *data; size_t len; size_t bytes_parsed; } bson_json_data_reader_t; static ssize_t _bson_json_data_reader_cb (void *_ctx, uint8_t *buf, size_t len) { size_t bytes; bson_json_data_reader_t *ctx = (bson_json_data_reader_t *) _ctx; if (!ctx->data) { return -1; } bytes = BSON_MIN (len, ctx->len - ctx->bytes_parsed); memcpy (buf, ctx->data + ctx->bytes_parsed, bytes); ctx->bytes_parsed += bytes; return bytes; } bson_json_reader_t * bson_json_data_reader_new (bool allow_multiple, /* IN */ size_t size) /* IN */ { bson_json_data_reader_t *dr = bson_malloc0 (sizeof *dr); return bson_json_reader_new (dr, &_bson_json_data_reader_cb, &bson_free, allow_multiple, size); } void bson_json_data_reader_ingest (bson_json_reader_t *reader, /* IN */ const uint8_t *data, /* IN */ size_t len) /* IN */ { bson_json_data_reader_t *ctx = (bson_json_data_reader_t *) reader->producer.data; ctx->data = data; ctx->len = len; ctx->bytes_parsed = 0; } bson_t * bson_new_from_json (const uint8_t *data, /* IN */ ssize_t len, /* IN */ bson_error_t *error) /* OUT */ { bson_json_reader_t *reader; bson_t *bson; int r; BSON_ASSERT (data); if (len < 0) { len = (ssize_t) strlen ((const char *) data); } bson = bson_new (); reader = bson_json_data_reader_new (false, BSON_JSON_DEFAULT_BUF_SIZE); bson_json_data_reader_ingest (reader, data, len); r = bson_json_reader_read (reader, bson, error); bson_json_reader_destroy (reader); if (r == 0) { bson_set_error (error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_INVALID_PARAM, "Empty JSON string"); } if (r != 1) { bson_destroy (bson); return NULL; } return bson; } bool bson_init_from_json (bson_t *bson, /* OUT */ const char *data, /* IN */ ssize_t len, /* IN */ bson_error_t *error) /* OUT */ { bson_json_reader_t *reader; int r; BSON_ASSERT (bson); BSON_ASSERT (data); if (len < 0) { len = strlen (data); } bson_init (bson); reader = bson_json_data_reader_new (false, BSON_JSON_DEFAULT_BUF_SIZE); bson_json_data_reader_ingest (reader, (const uint8_t *) data, len); r = bson_json_reader_read (reader, bson, error); bson_json_reader_destroy (reader); if (r == 0) { bson_set_error (error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_INVALID_PARAM, "Empty JSON string"); } if (r != 1) { bson_destroy (bson); return false; } return true; } static void _bson_json_reader_handle_fd_destroy (void *handle) /* IN */ { bson_json_reader_handle_fd_t *fd = handle; if (fd) { if ((fd->fd != -1) && fd->do_close) { #ifdef _WIN32 _close (fd->fd); #else close (fd->fd); #endif } bson_free (fd); } } static ssize_t _bson_json_reader_handle_fd_read (void *handle, /* IN */ uint8_t *buf, /* IN */ size_t len) /* IN */ { bson_json_reader_handle_fd_t *fd = handle; ssize_t ret = -1; if (fd && (fd->fd != -1)) { again: #ifdef BSON_OS_WIN32 ret = _read (fd->fd, buf, (unsigned int) len); #else ret = read (fd->fd, buf, len); #endif if ((ret == -1) && (errno == EAGAIN)) { goto again; } } return ret; } bson_json_reader_t * bson_json_reader_new_from_fd (int fd, /* IN */ bool close_on_destroy) /* IN */ { bson_json_reader_handle_fd_t *handle; BSON_ASSERT (fd != -1); handle = bson_malloc0 (sizeof *handle); handle->fd = fd; handle->do_close = close_on_destroy; return bson_json_reader_new ( handle, _bson_json_reader_handle_fd_read, _bson_json_reader_handle_fd_destroy, true, BSON_JSON_DEFAULT_BUF_SIZE); } bson_json_reader_t * bson_json_reader_new_from_file (const char *path, /* IN */ bson_error_t *error) /* OUT */ { char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; char *errmsg; int fd = -1; BSON_ASSERT (path); #ifdef BSON_OS_WIN32 _sopen_s (&fd, path, (_O_RDONLY | _O_BINARY), _SH_DENYNO, _S_IREAD); #else fd = open (path, O_RDONLY); #endif if (fd == -1) { errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf); bson_set_error (error, BSON_ERROR_READER, BSON_ERROR_READER_BADFD, "%s", errmsg); return NULL; } return bson_json_reader_new_from_fd (fd, true); } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-json.h0000644000175100001660000000473214760300420020733 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_JSON_H #define BSON_JSON_H #include BSON_BEGIN_DECLS typedef struct _bson_json_reader_t bson_json_reader_t; typedef enum { BSON_JSON_ERROR_READ_CORRUPT_JS = 1, BSON_JSON_ERROR_READ_INVALID_PARAM, BSON_JSON_ERROR_READ_CB_FAILURE, } bson_json_error_code_t; /** * BSON_MAX_LEN_UNLIMITED * * Denotes unlimited length limit when converting BSON to JSON. */ #define BSON_MAX_LEN_UNLIMITED -1 /** * bson_json_mode_t: * * This enumeration contains the different modes to serialize BSON into extended * JSON. */ typedef enum { BSON_JSON_MODE_LEGACY, BSON_JSON_MODE_CANONICAL, BSON_JSON_MODE_RELAXED, } bson_json_mode_t; BSON_EXPORT (bson_json_opts_t *) bson_json_opts_new (bson_json_mode_t mode, int32_t max_len); BSON_EXPORT (void) bson_json_opts_destroy (bson_json_opts_t *opts); BSON_EXPORT (void) bson_json_opts_set_outermost_array (bson_json_opts_t *opts, bool is_outermost_array); typedef ssize_t (*bson_json_reader_cb) (void *handle, uint8_t *buf, size_t count); typedef void (*bson_json_destroy_cb) (void *handle); BSON_EXPORT (bson_json_reader_t *) bson_json_reader_new ( void *data, bson_json_reader_cb cb, bson_json_destroy_cb dcb, bool allow_multiple, size_t buf_size); BSON_EXPORT (bson_json_reader_t *) bson_json_reader_new_from_fd (int fd, bool close_on_destroy); BSON_EXPORT (bson_json_reader_t *) bson_json_reader_new_from_file (const char *filename, bson_error_t *error); BSON_EXPORT (void) bson_json_reader_destroy (bson_json_reader_t *reader); BSON_EXPORT (int) bson_json_reader_read (bson_json_reader_t *reader, bson_t *bson, bson_error_t *error); BSON_EXPORT (bson_json_reader_t *) bson_json_data_reader_new (bool allow_multiple, size_t size); BSON_EXPORT (void) bson_json_data_reader_ingest (bson_json_reader_t *reader, const uint8_t *data, size_t len); BSON_END_DECLS #endif /* BSON_JSON_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-keys.c0000644000175100001660000002303514760300420020725 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include static const char *gUint32Strs[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", "270", "271", "272", "273", "274", "275", "276", "277", "278", "279", "280", "281", "282", "283", "284", "285", "286", "287", "288", "289", "290", "291", "292", "293", "294", "295", "296", "297", "298", "299", "300", "301", "302", "303", "304", "305", "306", "307", "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318", "319", "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", "340", "341", "342", "343", "344", "345", "346", "347", "348", "349", "350", "351", "352", "353", "354", "355", "356", "357", "358", "359", "360", "361", "362", "363", "364", "365", "366", "367", "368", "369", "370", "371", "372", "373", "374", "375", "376", "377", "378", "379", "380", "381", "382", "383", "384", "385", "386", "387", "388", "389", "390", "391", "392", "393", "394", "395", "396", "397", "398", "399", "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", "410", "411", "412", "413", "414", "415", "416", "417", "418", "419", "420", "421", "422", "423", "424", "425", "426", "427", "428", "429", "430", "431", "432", "433", "434", "435", "436", "437", "438", "439", "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", "450", "451", "452", "453", "454", "455", "456", "457", "458", "459", "460", "461", "462", "463", "464", "465", "466", "467", "468", "469", "470", "471", "472", "473", "474", "475", "476", "477", "478", "479", "480", "481", "482", "483", "484", "485", "486", "487", "488", "489", "490", "491", "492", "493", "494", "495", "496", "497", "498", "499", "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", "510", "511", "512", "513", "514", "515", "516", "517", "518", "519", "520", "521", "522", "523", "524", "525", "526", "527", "528", "529", "530", "531", "532", "533", "534", "535", "536", "537", "538", "539", "540", "541", "542", "543", "544", "545", "546", "547", "548", "549", "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", "560", "561", "562", "563", "564", "565", "566", "567", "568", "569", "570", "571", "572", "573", "574", "575", "576", "577", "578", "579", "580", "581", "582", "583", "584", "585", "586", "587", "588", "589", "590", "591", "592", "593", "594", "595", "596", "597", "598", "599", "600", "601", "602", "603", "604", "605", "606", "607", "608", "609", "610", "611", "612", "613", "614", "615", "616", "617", "618", "619", "620", "621", "622", "623", "624", "625", "626", "627", "628", "629", "630", "631", "632", "633", "634", "635", "636", "637", "638", "639", "640", "641", "642", "643", "644", "645", "646", "647", "648", "649", "650", "651", "652", "653", "654", "655", "656", "657", "658", "659", "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", "670", "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681", "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692", "693", "694", "695", "696", "697", "698", "699", "700", "701", "702", "703", "704", "705", "706", "707", "708", "709", "710", "711", "712", "713", "714", "715", "716", "717", "718", "719", "720", "721", "722", "723", "724", "725", "726", "727", "728", "729", "730", "731", "732", "733", "734", "735", "736", "737", "738", "739", "740", "741", "742", "743", "744", "745", "746", "747", "748", "749", "750", "751", "752", "753", "754", "755", "756", "757", "758", "759", "760", "761", "762", "763", "764", "765", "766", "767", "768", "769", "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", "780", "781", "782", "783", "784", "785", "786", "787", "788", "789", "790", "791", "792", "793", "794", "795", "796", "797", "798", "799", "800", "801", "802", "803", "804", "805", "806", "807", "808", "809", "810", "811", "812", "813", "814", "815", "816", "817", "818", "819", "820", "821", "822", "823", "824", "825", "826", "827", "828", "829", "830", "831", "832", "833", "834", "835", "836", "837", "838", "839", "840", "841", "842", "843", "844", "845", "846", "847", "848", "849", "850", "851", "852", "853", "854", "855", "856", "857", "858", "859", "860", "861", "862", "863", "864", "865", "866", "867", "868", "869", "870", "871", "872", "873", "874", "875", "876", "877", "878", "879", "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", "890", "891", "892", "893", "894", "895", "896", "897", "898", "899", "900", "901", "902", "903", "904", "905", "906", "907", "908", "909", "910", "911", "912", "913", "914", "915", "916", "917", "918", "919", "920", "921", "922", "923", "924", "925", "926", "927", "928", "929", "930", "931", "932", "933", "934", "935", "936", "937", "938", "939", "940", "941", "942", "943", "944", "945", "946", "947", "948", "949", "950", "951", "952", "953", "954", "955", "956", "957", "958", "959", "960", "961", "962", "963", "964", "965", "966", "967", "968", "969", "970", "971", "972", "973", "974", "975", "976", "977", "978", "979", "980", "981", "982", "983", "984", "985", "986", "987", "988", "989", "990", "991", "992", "993", "994", "995", "996", "997", "998", "999"}; /* *-------------------------------------------------------------------------- * * bson_uint32_to_string -- * * Converts @value to a string. * * If @value is from 0 to 1000, it will use a constant string in the * data section of the library. * * If not, a string will be formatted using @str and snprintf(). This * is much slower, of course and therefore we try to optimize it out. * * @strptr will always be set. It will either point to @str or a * constant string. You will want to use this as your key. * * Parameters: * @value: A #uint32_t to convert to string. * @strptr: (out): A pointer to the resulting string. * @str: (out): Storage for a string made with snprintf. * @size: Size of @str. * * Returns: * The number of bytes in the resulting string excluding the NULL * terminator. If the output requires more than @size bytes, then @size * bytes are written and the result is the number of bytes required * (excluding the NULL terminator) * * Side effects: * None. * *-------------------------------------------------------------------------- */ size_t bson_uint32_to_string (uint32_t value, /* IN */ const char **strptr, /* OUT */ char *str, /* OUT */ size_t size) /* IN */ { if (value < 1000) { *strptr = gUint32Strs[value]; if (value < 10) { return 1; } else if (value < 100) { return 2; } else { return 3; } } *strptr = str; int ret = bson_snprintf (str, size, "%u", value); // Truncation is OK. BSON_ASSERT (ret > 0); BSON_ASSERT (mcommon_in_range_size_t_signed (ret)); return (size_t) ret; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-keys.h0000644000175100001660000000161514760300420020732 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_KEYS_H #define BSON_KEYS_H #include #include BSON_BEGIN_DECLS BSON_EXPORT (size_t) bson_uint32_to_string (uint32_t value, const char **strptr, char *str, size_t size); BSON_END_DECLS #endif /* BSON_KEYS_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-macros.h0000644000175100001660000002643314760300420021250 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_MACROS_H #define BSON_MACROS_H #include #include #ifdef __cplusplus #include #endif #include #if BSON_OS == 1 #define BSON_OS_UNIX #elif BSON_OS == 2 #define BSON_OS_WIN32 #else #error "Unknown operating system." #endif #ifdef __cplusplus #define BSON_BEGIN_DECLS extern "C" { #define BSON_END_DECLS } #else #define BSON_BEGIN_DECLS #define BSON_END_DECLS #endif #if defined(__GNUC__) #define BSON_GNUC_CHECK_VERSION(major, minor) \ ((__GNUC__ > (major)) || ((__GNUC__ == (major)) && (__GNUC_MINOR__ >= (minor)))) #else #define BSON_GNUC_CHECK_VERSION(major, minor) 0 #endif #if defined(__GNUC__) #define BSON_GNUC_IS_VERSION(major, minor) ((__GNUC__ == (major)) && (__GNUC_MINOR__ == (minor))) #else #define BSON_GNUC_IS_VERSION(major, minor) 0 #endif /* Decorate public functions: * - if BSON_STATIC, we're compiling a static libbson or a program * that uses libbson as a static library. Don't decorate functions. * - else if BSON_COMPILATION, we're compiling a shared libbson, mark * public functions for export from the shared lib * - else, we're compiling a program that uses libbson as a shared library, * mark public functions as DLL imports for Microsoft Visual C */ #ifdef _MSC_VER /* * Microsoft Visual C */ #ifdef BSON_STATIC #define BSON_API #elif defined(BSON_COMPILATION) #define BSON_API __declspec (dllexport) #else #define BSON_API __declspec (dllimport) #endif #define BSON_CALL __cdecl #elif defined(__GNUC__) /* * GCC */ #ifdef BSON_STATIC #define BSON_API #elif defined(BSON_COMPILATION) #define BSON_API __attribute__ ((visibility ("default"))) #else #define BSON_API #endif #define BSON_CALL #else /* * Other compilers */ #define BSON_API #define BSON_CALL #endif #define BSON_EXPORT(type) BSON_API type BSON_CALL #ifdef MIN #define BSON_MIN MIN #elif defined(__cplusplus) #define BSON_MIN(a, b) ((std::min) (a, b)) #elif defined(_MSC_VER) #define BSON_MIN(a, b) ((a) < (b) ? (a) : (b)) #else #define BSON_MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifdef MAX #define BSON_MAX MAX #elif defined(__cplusplus) #define BSON_MAX(a, b) ((std::max) (a, b)) #elif defined(_MSC_VER) #define BSON_MAX(a, b) ((a) > (b) ? (a) : (b)) #else #define BSON_MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifdef ABS #define BSON_ABS ABS #else #define BSON_ABS(a) (((a) < 0) ? ((a) * -1) : (a)) #endif #if defined(__cplusplus) && (__cplusplus >= 201103L || defined(_MSVC_LANG)) #define BSON_ALIGNOF(expr) alignof (expr) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define BSON_ALIGNOF(expr) _Alignof (expr) #else #if defined(_MSC_VER) #define BSON_ALIGNOF(expr) __alignof (expr) #else #define BSON_ALIGNOF(expr) __alignof__ (expr) #endif #endif // __STDC_VERSION__ >= 201112L #ifdef _MSC_VER // __declspec (align (_N)) only permits integer literals as _N. #ifdef _WIN64 #define BSON_ALIGN_OF_PTR 8 #else #define BSON_ALIGN_OF_PTR 4 #endif #else #define BSON_ALIGN_OF_PTR (BSON_ALIGNOF (void *)) #endif #ifdef BSON_EXTRA_ALIGN #if defined(_MSC_VER) #define BSON_ALIGNED_BEGIN(_N) __declspec (align (_N)) #define BSON_ALIGNED_END(_N) #else #define BSON_ALIGNED_BEGIN(_N) #define BSON_ALIGNED_END(_N) __attribute__ ((aligned (_N))) #endif #else #if defined(_MSC_VER) #define BSON_ALIGNED_BEGIN(_N) __declspec (align (BSON_ALIGN_OF_PTR)) #define BSON_ALIGNED_END(_N) #else #define BSON_ALIGNED_BEGIN(_N) #define BSON_ALIGNED_END(_N) __attribute__ ((aligned ((_N) > BSON_ALIGN_OF_PTR ? BSON_ALIGN_OF_PTR : (_N)))) #endif #endif #define bson_str_empty(s) (!s[0]) #define bson_str_empty0(s) (!s || !s[0]) #if defined(_MSC_VER) #define BSON_FUNC __FUNCTION__ #else #define BSON_FUNC __func__ #endif #if defined(_MSC_VER) #define BSON_INLINE __inline #else #define BSON_INLINE __inline__ #endif #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L #define BSON_NORETURN [[noreturn]] #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define BSON_NORETURN _Noreturn #elif defined(__GNUC__) && 2 < __GNUC__ + (8 <= __GNUC_MINOR__) #define BSON_NORETURN __attribute__ ((__noreturn__)) #else #define BSON_NORETURN #endif BSON_NORETURN static BSON_INLINE void _bson_assert_failed_on_line (const char *file, int line, const char *func, const char *test) { fprintf (stderr, "%s:%d %s(): assertion failed: %s\n", file, line, func, test); abort (); } BSON_NORETURN static BSON_INLINE void _bson_assert_failed_on_param (const char *param, const char *func) { fprintf (stderr, "The parameter: %s, in function %s, cannot be NULL\n", param, func); abort (); } #define BSON_ASSERT(test) \ do { \ if (!(BSON_LIKELY (test))) { \ _bson_assert_failed_on_line (__FILE__, (int) (__LINE__), BSON_FUNC, #test); \ } \ } while (0) /** * @brief Assert the expression `Assertion`, and evaluates to `Value` on * success. */ #define BSON_ASSERT_INLINE(Assertion, Value) \ ((void) ((Assertion) ? (0) : (_bson_assert_failed_on_line (__FILE__, (int) (__LINE__), BSON_FUNC, #Assertion), 0)), \ Value) /** * @brief Assert that the given pointer is non-NULL, while also evaluating to * that pointer. * * Can be used to inline assertions with a pointer dereference: * * ``` * foo* f = get_foo(); * bar* b = BSON_ASSERT_PTR_INLINE(f)->bar_value; * ``` */ #define BSON_ASSERT_PTR_INLINE(Pointer) BSON_ASSERT_INLINE ((Pointer) != NULL, (Pointer)) /* Used for asserting parameters to provide a more precise error message */ #define BSON_ASSERT_PARAM(param) \ do { \ if ((BSON_UNLIKELY (param == NULL))) { \ _bson_assert_failed_on_param (#param, BSON_FUNC); \ } \ } while (0) // `BSON_OPTIONAL_PARAM` is a documentation-only macro to document X may be NULL. // Useful in combination with `BSON_ASSERT_PARAM` to document and assert pointer parameters. #define BSON_OPTIONAL_PARAM(param) (void) 0 /* obsolete macros, preserved for compatibility */ #define BSON_STATIC_ASSERT(s) BSON_STATIC_ASSERT_ (s, __LINE__) #define BSON_STATIC_ASSERT_JOIN(a, b) BSON_STATIC_ASSERT_JOIN2 (a, b) #define BSON_STATIC_ASSERT_JOIN2(a, b) a##b #define BSON_STATIC_ASSERT_(s, l) typedef char BSON_STATIC_ASSERT_JOIN (static_assert_test_, __LINE__)[(s) ? 1 : -1] /* modern macros */ #define BSON_STATIC_ASSERT2(_name, _s) BSON_STATIC_ASSERT2_ (_s, __LINE__, _name) #define BSON_STATIC_ASSERT_JOIN3(_a, _b, _name) BSON_STATIC_ASSERT_JOIN4 (_a, _b, _name) #define BSON_STATIC_ASSERT_JOIN4(_a, _b, _name) _a##_b##_name #define BSON_STATIC_ASSERT2_(_s, _l, _name) \ typedef char BSON_STATIC_ASSERT_JOIN3 (static_assert_test_, __LINE__, _name)[(_s) ? 1 : -1] #if defined(__GNUC__) #define BSON_GNUC_PURE __attribute__ ((pure)) #define BSON_GNUC_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) #else #define BSON_GNUC_PURE #define BSON_GNUC_WARN_UNUSED_RESULT #endif #if BSON_GNUC_CHECK_VERSION(4, 0) && !defined(_WIN32) #define BSON_GNUC_NULL_TERMINATED __attribute__ ((sentinel)) #define BSON_GNUC_INTERNAL __attribute__ ((visibility ("hidden"))) #else #define BSON_GNUC_NULL_TERMINATED #define BSON_GNUC_INTERNAL #endif #if defined(__GNUC__) #define BSON_LIKELY(x) __builtin_expect (!!(x), 1) #define BSON_UNLIKELY(x) __builtin_expect (!!(x), 0) #else #define BSON_LIKELY(v) v #define BSON_UNLIKELY(v) v #endif #if defined(__clang__) #define BSON_GNUC_PRINTF(f, v) __attribute__ ((format (printf, f, v))) #elif BSON_GNUC_CHECK_VERSION(4, 4) #define BSON_GNUC_PRINTF(f, v) __attribute__ ((format (gnu_printf, f, v))) #else #define BSON_GNUC_PRINTF(f, v) #endif #if defined(__LP64__) || defined(_LP64) #define BSON_WORD_SIZE 64 #else #define BSON_WORD_SIZE 32 #endif #ifdef _MSC_VER #define BSON_ENSURE_ARRAY_PARAM_SIZE(_n) #define BSON_TYPEOF decltype #else #define BSON_ENSURE_ARRAY_PARAM_SIZE(_n) static (_n) #define BSON_TYPEOF typeof #endif #if BSON_GNUC_CHECK_VERSION(3, 1) #define BSON_GNUC_DEPRECATED __attribute__ ((__deprecated__)) #else #define BSON_GNUC_DEPRECATED #endif #define BSON_CONCAT_IMPL(a, ...) a##__VA_ARGS__ #define BSON_CONCAT(a, ...) BSON_CONCAT_IMPL (a, __VA_ARGS__) #define BSON_CONCAT3(a, b, c) BSON_CONCAT (a, BSON_CONCAT (b, c)) #define BSON_CONCAT4(a, b, c, d) BSON_CONCAT (BSON_CONCAT (a, b), BSON_CONCAT (c, d)) #if BSON_GNUC_CHECK_VERSION(4, 5) #define BSON_GNUC_DEPRECATED_FOR(f) __attribute__ ((deprecated ("Use " #f " instead"))) #else #define BSON_GNUC_DEPRECATED_FOR(f) BSON_GNUC_DEPRECATED #endif /** * @brief String-ify the given argument */ #define BSON_STR(...) #__VA_ARGS__ /** * @brief Mark the attached declared entity as "possibly-unused." * * Does nothing on MSVC. */ #if defined(__GNUC__) || defined(__clang__) #define BSON_MAYBE_UNUSED __attribute__ ((unused)) #else #define BSON_MAYBE_UNUSED /* Nothing for other compilers */ #endif /** * @brief Mark a point in the code as unreachable. If the point is reached, the * program will abort with an error message. * * @param What A string to include in the error message if this point is ever * executed. */ #define BSON_UNREACHABLE(What) \ do { \ fprintf (stderr, "%s:%d %s(): Unreachable code reached: %s\n", __FILE__, (int) (__LINE__), BSON_FUNC, What); \ abort (); \ } while (0) /** * @brief Silence warnings for deliberately unused variables or parameters. * * @param expr An unused variable or parameter. * */ #define BSON_UNUSED(expr) \ do { \ (void) (expr); \ } while (0) // Disable the -Wunsafe-buffer-usage warning. #define BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN #define BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END #if defined(__clang__) #if __has_warning("-Wunsafe-buffer-usage") #undef BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN #undef BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END #define BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN \ _Pragma ("clang diagnostic push") _Pragma ("clang diagnostic ignored \"-Wunsafe-buffer-usage\"") #define BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END _Pragma ("clang diagnostic pop") #endif // __has_warning("-Wunsafe-buffer-usage") #endif // defined(__clang__) #endif /* BSON_MACROS_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-md5.c0000644000175100001660000000060314760300420020433 0ustar #include #include #include void bson_md5_init (bson_md5_t *pms) { mcommon_md5_init (pms); } void bson_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes) { mcommon_md5_append (pms, data, nbytes); } void bson_md5_finish (bson_md5_t *pms, uint8_t digest[16]) { mcommon_md5_finish (pms, digest); } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-md5.h0000644000175100001660000000541014760300420020441 0ustar /* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgement in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ /* * The following MD5 implementation has been modified to use types as * specified in libbson. */ #include #ifndef BSON_MD5_H #define BSON_MD5_H #include BSON_BEGIN_DECLS typedef struct { uint32_t count[2]; /* message length in bits, lsw first */ uint32_t abcd[4]; /* digest buffer */ uint8_t buf[64]; /* accumulate block */ } bson_md5_t; BSON_EXPORT (void) bson_md5_init (bson_md5_t *pms) BSON_GNUC_DEPRECATED; BSON_EXPORT (void) bson_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes) BSON_GNUC_DEPRECATED; BSON_EXPORT (void) bson_md5_finish (bson_md5_t *pms, uint8_t digest[16]) BSON_GNUC_DEPRECATED; BSON_END_DECLS #endif /* BSON_MD5_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-memory.c0000644000175100001660000002560014760300420021262 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include // Ensure size of exported structs are stable. BSON_STATIC_ASSERT2 (bson_mem_vtable_t, sizeof (bson_mem_vtable_t) == sizeof (void *) * 8u); // For compatibility with C standards prior to C11. static void * _aligned_alloc_impl (size_t alignment, size_t num_bytes) #if defined(BSON_HAVE_ALIGNED_ALLOC) { MC_DISABLE_IMPLICIT_WARNING_BEGIN return aligned_alloc (alignment, num_bytes); MC_DISABLE_IMPLICIT_WARNING_END } #elif defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L { void *mem = NULL; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425. BSON_MAYBE_UNUSED int ret = posix_memalign (&mem, alignment, num_bytes); return mem; } #else { // Fallback to simple malloc even if it does not satisfy alignment // requirements. Note: Visual C++ _aligned_malloc requires using // _aligned_free instead of free and modifies errno on failure, both of which // breaks symmetry with C11 aligned_alloc, so it is deliberately not used. BSON_UNUSED (alignment); return malloc (num_bytes); } #endif static bson_mem_vtable_t gMemVtable = {.malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free, .aligned_alloc = _aligned_alloc_impl, .padding = {0}}; /* *-------------------------------------------------------------------------- * * bson_malloc -- * * Allocates @num_bytes of memory and returns a pointer to it. If * malloc failed to allocate the memory, abort() is called. * * Libbson does not try to handle OOM conditions as it is beyond the * scope of this library to handle so appropriately. * * Parameters: * @num_bytes: The number of bytes to allocate. * * Returns: * A pointer if successful; otherwise abort() is called and this * function will never return. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void * bson_malloc (size_t num_bytes) /* IN */ { void *mem = NULL; if (BSON_LIKELY (num_bytes)) { if (BSON_UNLIKELY (!(mem = gMemVtable.malloc (num_bytes)))) { fprintf (stderr, "Failure to allocate memory in bson_malloc(). errno: %d.\n", errno); abort (); } } return mem; } /* *-------------------------------------------------------------------------- * * bson_malloc0 -- * * Like bson_malloc() except the memory is zeroed first. This is * similar to calloc() except that abort() is called in case of * failure to allocate memory. * * Parameters: * @num_bytes: The number of bytes to allocate. * * Returns: * A pointer if successful; otherwise abort() is called and this * function will never return. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void * bson_malloc0 (size_t num_bytes) /* IN */ { void *mem = NULL; if (BSON_LIKELY (num_bytes)) { if (BSON_UNLIKELY (!(mem = gMemVtable.calloc (1, num_bytes)))) { fprintf (stderr, "Failure to allocate memory in bson_malloc0(). errno: %d.\n", errno); abort (); } } return mem; } /* *-------------------------------------------------------------------------- * * bson_aligned_alloc -- * * Allocates @num_bytes of memory with an alignment of @alignment and * returns a pointer to it. If malloc failed to allocate the memory, * abort() is called. * * Libbson does not try to handle OOM conditions as it is beyond the * scope of this library to handle so appropriately. * * Parameters: * @alignment: The alignment of the allocated bytes of memory. * @num_bytes: The number of bytes to allocate. * * Returns: * A pointer if successful; otherwise abort() is called and this * function will never return. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void * bson_aligned_alloc (size_t alignment /* IN */, size_t num_bytes /* IN */) { void *mem = NULL; if (BSON_LIKELY (num_bytes)) { if (BSON_UNLIKELY (!(mem = gMemVtable.aligned_alloc (alignment, num_bytes)))) { fprintf (stderr, "Failure to allocate memory in bson_aligned_alloc()\n"); abort (); } } return mem; } /* *-------------------------------------------------------------------------- * * bson_aligned_alloc0 -- * * Like bson_aligned_alloc() except the memory is zeroed after allocation * for convenience. * * Parameters: * @alignment: The alignment of the allocated bytes of memory. * @num_bytes: The number of bytes to allocate. * * Returns: * A pointer if successful; otherwise abort() is called and this * function will never return. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void * bson_aligned_alloc0 (size_t alignment /* IN */, size_t num_bytes /* IN */) { void *mem = NULL; if (BSON_LIKELY (num_bytes)) { if (BSON_UNLIKELY (!(mem = gMemVtable.aligned_alloc (alignment, num_bytes)))) { fprintf (stderr, "Failure to allocate memory in bson_aligned_alloc0()\n"); abort (); } memset (mem, 0, num_bytes); } return mem; } /* *-------------------------------------------------------------------------- * * bson_realloc -- * * This function behaves similar to realloc() except that if there is * a failure abort() is called. * * Parameters: * @mem: The memory to realloc, or NULL. * @num_bytes: The size of the new allocation or 0 to free. * * Returns: * The new allocation if successful; otherwise abort() is called and * this function never returns. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void * bson_realloc (void *mem, /* IN */ size_t num_bytes) /* IN */ { /* * Not all platforms are guaranteed to free() the memory if a call to * realloc() with a size of zero occurs. Windows, Linux, and FreeBSD do, * however, OS X does not. */ if (BSON_UNLIKELY (num_bytes == 0)) { gMemVtable.free (mem); return NULL; } mem = gMemVtable.realloc (mem, num_bytes); if (BSON_UNLIKELY (!mem)) { fprintf (stderr, "Failure to re-allocate memory in bson_realloc(). errno: %d.\n", errno); abort (); } return mem; } /* *-------------------------------------------------------------------------- * * bson_realloc_ctx -- * * This wraps bson_realloc and provides a compatible api for similar * functions with a context * * Parameters: * @mem: The memory to realloc, or NULL. * @num_bytes: The size of the new allocation or 0 to free. * @ctx: Ignored * * Returns: * The new allocation if successful; otherwise abort() is called and * this function never returns. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void * bson_realloc_ctx (void *mem, /* IN */ size_t num_bytes, /* IN */ void *ctx) /* IN */ { BSON_UNUSED (ctx); return bson_realloc (mem, num_bytes); } /* *-------------------------------------------------------------------------- * * bson_free -- * * Frees @mem using the underlying allocator. * * Currently, this only calls free() directly, but that is subject to * change. * * Parameters: * @mem: An allocation to free. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_free (void *mem) /* IN */ { gMemVtable.free (mem); } /* *-------------------------------------------------------------------------- * * bson_zero_free -- * * Frees @mem using the underlying allocator. @size bytes of @mem will * be zeroed before freeing the memory. This is useful in scenarios * where @mem contains passwords or other sensitive information. * * Parameters: * @mem: An allocation to free. * @size: The number of bytes in @mem. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_zero_free (void *mem, /* IN */ size_t size) /* IN */ { if (BSON_LIKELY (mem)) { memset (mem, 0, size); gMemVtable.free (mem); } } static void * _aligned_alloc_as_malloc (size_t alignment, size_t num_bytes) { BSON_UNUSED (alignment); return gMemVtable.malloc (num_bytes); } /* *-------------------------------------------------------------------------- * * bson_mem_set_vtable -- * * This function will change our allocation vtable. * * It is imperative that this is called at the beginning of the * process before any memory has been allocated by the default * allocator. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_mem_set_vtable (const bson_mem_vtable_t *vtable) { BSON_ASSERT (vtable); if (!vtable->malloc || !vtable->calloc || !vtable->realloc || !vtable->free) { fprintf (stderr, "Failure to install BSON vtable, " "missing functions.\n"); return; } gMemVtable = *vtable; // Backwards compatibility with code prior to addition of aligned_alloc. if (!gMemVtable.aligned_alloc) { gMemVtable.aligned_alloc = _aligned_alloc_as_malloc; } } void bson_mem_restore_vtable (void) { bson_mem_vtable_t vtable = {.malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free, .aligned_alloc = _aligned_alloc_impl, .padding = {0}}; bson_mem_set_vtable (&vtable); } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-memory.h0000644000175100001660000000375414760300420021275 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_MEMORY_H #define BSON_MEMORY_H #include #include BSON_BEGIN_DECLS typedef void *(*bson_realloc_func) (void *mem, size_t num_bytes, void *ctx); typedef struct _bson_mem_vtable_t { void *(*malloc) (size_t num_bytes); void *(*calloc) (size_t n_members, size_t num_bytes); void *(*realloc) (void *mem, size_t num_bytes); void (*free) (void *mem); void *(*aligned_alloc) (size_t alignment, size_t num_bytes); void *padding[3]; } bson_mem_vtable_t; BSON_EXPORT (void) bson_mem_set_vtable (const bson_mem_vtable_t *vtable); BSON_EXPORT (void) bson_mem_restore_vtable (void); BSON_EXPORT (void *) bson_malloc (size_t num_bytes); BSON_EXPORT (void *) bson_malloc0 (size_t num_bytes); BSON_EXPORT (void *) bson_aligned_alloc (size_t alignment, size_t num_bytes); BSON_EXPORT (void *) bson_aligned_alloc0 (size_t alignment, size_t num_bytes); BSON_EXPORT (void *) bson_realloc (void *mem, size_t num_bytes); BSON_EXPORT (void *) bson_realloc_ctx (void *mem, size_t num_bytes, void *ctx); BSON_EXPORT (void) bson_free (void *mem); BSON_EXPORT (void) bson_zero_free (void *mem, size_t size); #define BSON_ALIGNED_ALLOC(T) ((T *) (bson_aligned_alloc (BSON_ALIGNOF (T), sizeof (T)))) #define BSON_ALIGNED_ALLOC0(T) ((T *) (bson_aligned_alloc0 (BSON_ALIGNOF (T), sizeof (T)))) BSON_END_DECLS #endif /* BSON_MEMORY_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-oid.c0000644000175100001660000002241214760300420020523 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include /* * This table contains an array of two character pairs for every possible * uint8_t. It is used as a lookup table when encoding a bson_oid_t * to hex formatted ASCII. Performing two characters at a time roughly * reduces the number of operations by one-half. */ BSON_MAYBE_UNUSED static const uint16_t gHexCharPairs[] = { #if BSON_BYTE_ORDER == BSON_BIG_ENDIAN 12336, 12337, 12338, 12339, 12340, 12341, 12342, 12343, 12344, 12345, 12385, 12386, 12387, 12388, 12389, 12390, 12592, 12593, 12594, 12595, 12596, 12597, 12598, 12599, 12600, 12601, 12641, 12642, 12643, 12644, 12645, 12646, 12848, 12849, 12850, 12851, 12852, 12853, 12854, 12855, 12856, 12857, 12897, 12898, 12899, 12900, 12901, 12902, 13104, 13105, 13106, 13107, 13108, 13109, 13110, 13111, 13112, 13113, 13153, 13154, 13155, 13156, 13157, 13158, 13360, 13361, 13362, 13363, 13364, 13365, 13366, 13367, 13368, 13369, 13409, 13410, 13411, 13412, 13413, 13414, 13616, 13617, 13618, 13619, 13620, 13621, 13622, 13623, 13624, 13625, 13665, 13666, 13667, 13668, 13669, 13670, 13872, 13873, 13874, 13875, 13876, 13877, 13878, 13879, 13880, 13881, 13921, 13922, 13923, 13924, 13925, 13926, 14128, 14129, 14130, 14131, 14132, 14133, 14134, 14135, 14136, 14137, 14177, 14178, 14179, 14180, 14181, 14182, 14384, 14385, 14386, 14387, 14388, 14389, 14390, 14391, 14392, 14393, 14433, 14434, 14435, 14436, 14437, 14438, 14640, 14641, 14642, 14643, 14644, 14645, 14646, 14647, 14648, 14649, 14689, 14690, 14691, 14692, 14693, 14694, 24880, 24881, 24882, 24883, 24884, 24885, 24886, 24887, 24888, 24889, 24929, 24930, 24931, 24932, 24933, 24934, 25136, 25137, 25138, 25139, 25140, 25141, 25142, 25143, 25144, 25145, 25185, 25186, 25187, 25188, 25189, 25190, 25392, 25393, 25394, 25395, 25396, 25397, 25398, 25399, 25400, 25401, 25441, 25442, 25443, 25444, 25445, 25446, 25648, 25649, 25650, 25651, 25652, 25653, 25654, 25655, 25656, 25657, 25697, 25698, 25699, 25700, 25701, 25702, 25904, 25905, 25906, 25907, 25908, 25909, 25910, 25911, 25912, 25913, 25953, 25954, 25955, 25956, 25957, 25958, 26160, 26161, 26162, 26163, 26164, 26165, 26166, 26167, 26168, 26169, 26209, 26210, 26211, 26212, 26213, 26214 #else 12336, 12592, 12848, 13104, 13360, 13616, 13872, 14128, 14384, 14640, 24880, 25136, 25392, 25648, 25904, 26160, 12337, 12593, 12849, 13105, 13361, 13617, 13873, 14129, 14385, 14641, 24881, 25137, 25393, 25649, 25905, 26161, 12338, 12594, 12850, 13106, 13362, 13618, 13874, 14130, 14386, 14642, 24882, 25138, 25394, 25650, 25906, 26162, 12339, 12595, 12851, 13107, 13363, 13619, 13875, 14131, 14387, 14643, 24883, 25139, 25395, 25651, 25907, 26163, 12340, 12596, 12852, 13108, 13364, 13620, 13876, 14132, 14388, 14644, 24884, 25140, 25396, 25652, 25908, 26164, 12341, 12597, 12853, 13109, 13365, 13621, 13877, 14133, 14389, 14645, 24885, 25141, 25397, 25653, 25909, 26165, 12342, 12598, 12854, 13110, 13366, 13622, 13878, 14134, 14390, 14646, 24886, 25142, 25398, 25654, 25910, 26166, 12343, 12599, 12855, 13111, 13367, 13623, 13879, 14135, 14391, 14647, 24887, 25143, 25399, 25655, 25911, 26167, 12344, 12600, 12856, 13112, 13368, 13624, 13880, 14136, 14392, 14648, 24888, 25144, 25400, 25656, 25912, 26168, 12345, 12601, 12857, 13113, 13369, 13625, 13881, 14137, 14393, 14649, 24889, 25145, 25401, 25657, 25913, 26169, 12385, 12641, 12897, 13153, 13409, 13665, 13921, 14177, 14433, 14689, 24929, 25185, 25441, 25697, 25953, 26209, 12386, 12642, 12898, 13154, 13410, 13666, 13922, 14178, 14434, 14690, 24930, 25186, 25442, 25698, 25954, 26210, 12387, 12643, 12899, 13155, 13411, 13667, 13923, 14179, 14435, 14691, 24931, 25187, 25443, 25699, 25955, 26211, 12388, 12644, 12900, 13156, 13412, 13668, 13924, 14180, 14436, 14692, 24932, 25188, 25444, 25700, 25956, 26212, 12389, 12645, 12901, 13157, 13413, 13669, 13925, 14181, 14437, 14693, 24933, 25189, 25445, 25701, 25957, 26213, 12390, 12646, 12902, 13158, 13414, 13670, 13926, 14182, 14438, 14694, 24934, 25190, 25446, 25702, 25958, 26214 #endif }; static BSON_INLINE void _oid_init (bson_oid_t *oid, bson_context_t *context, bool add_random) { BSON_ASSERT (oid); if (!context) { context = bson_context_get_default (); } const time_t now = time (NULL); // Big-endian encode the low 32 bits of the time as the leading 32 bits of the new OID oid->bytes[0] = (uint8_t) (now >> 24); oid->bytes[1] = (uint8_t) (now >> 16); oid->bytes[2] = (uint8_t) (now >> 8); oid->bytes[3] = (uint8_t) (now >> 0); // Maybe add randomness if the caller wants it if (add_random) { _bson_context_set_oid_rand (context, oid); _bson_context_set_oid_seq32 (context, oid); } else { _bson_context_set_oid_seq64 (context, oid); } } void bson_oid_init_sequence (bson_oid_t *oid, /* OUT */ bson_context_t *context) /* IN */ { _oid_init (oid, context, false /* no randomness */); } void bson_oid_init (bson_oid_t *oid, /* OUT */ bson_context_t *context) /* IN */ { _oid_init (oid, context, true /* add randomness */); } void bson_oid_init_from_data (bson_oid_t *oid, /* OUT */ const uint8_t *data) /* IN */ { BSON_ASSERT (oid); BSON_ASSERT (data); memcpy (oid, data, 12); } void bson_oid_init_from_string (bson_oid_t *oid, /* OUT */ const char *str) /* IN */ { BSON_ASSERT (oid); BSON_ASSERT (str); bson_oid_init_from_string_unsafe (oid, str); } time_t bson_oid_get_time_t (const bson_oid_t *oid) /* IN */ { BSON_ASSERT (oid); return bson_oid_get_time_t_unsafe (oid); } void bson_oid_to_string (const bson_oid_t *oid, /* IN */ char str[BSON_ENSURE_ARRAY_PARAM_SIZE (25)]) /* OUT */ { #if !defined(__i386__) && !defined(__x86_64__) && !defined(_M_IX86) && !defined(_M_X64) BSON_ASSERT (oid); BSON_ASSERT (str); bson_snprintf (str, 25, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", oid->bytes[0], oid->bytes[1], oid->bytes[2], oid->bytes[3], oid->bytes[4], oid->bytes[5], oid->bytes[6], oid->bytes[7], oid->bytes[8], oid->bytes[9], oid->bytes[10], oid->bytes[11]); #else uint16_t *dst; uint8_t *id = (uint8_t *) oid; BSON_ASSERT (oid); BSON_ASSERT (str); dst = (uint16_t *) (void *) str; dst[0] = gHexCharPairs[id[0]]; dst[1] = gHexCharPairs[id[1]]; dst[2] = gHexCharPairs[id[2]]; dst[3] = gHexCharPairs[id[3]]; dst[4] = gHexCharPairs[id[4]]; dst[5] = gHexCharPairs[id[5]]; dst[6] = gHexCharPairs[id[6]]; dst[7] = gHexCharPairs[id[7]]; dst[8] = gHexCharPairs[id[8]]; dst[9] = gHexCharPairs[id[9]]; dst[10] = gHexCharPairs[id[10]]; dst[11] = gHexCharPairs[id[11]]; str[24] = '\0'; #endif } uint32_t bson_oid_hash (const bson_oid_t *oid) /* IN */ { BSON_ASSERT (oid); return bson_oid_hash_unsafe (oid); } int bson_oid_compare (const bson_oid_t *oid1, /* IN */ const bson_oid_t *oid2) /* IN */ { BSON_ASSERT (oid1); BSON_ASSERT (oid2); return bson_oid_compare_unsafe (oid1, oid2); } bool bson_oid_equal (const bson_oid_t *oid1, /* IN */ const bson_oid_t *oid2) /* IN */ { BSON_ASSERT (oid1); BSON_ASSERT (oid2); return bson_oid_equal_unsafe (oid1, oid2); } void bson_oid_copy (const bson_oid_t *src, /* IN */ bson_oid_t *dst) /* OUT */ { BSON_ASSERT (src); BSON_ASSERT (dst); bson_oid_copy_unsafe (src, dst); } bool bson_oid_is_valid (const char *str, /* IN */ size_t length) /* IN */ { size_t i; BSON_ASSERT (str); if ((length == 25) && (str[24] == '\0')) { length = 24; } if (length == 24) { for (i = 0; i < length; i++) { switch (str[i]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': break; default: return false; } } return true; } return false; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-oid.h0000644000175100001660000001423214760300420020531 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_OID_H #define BSON_OID_H #include #include #include #include #include BSON_BEGIN_DECLS BSON_EXPORT (int) bson_oid_compare (const bson_oid_t *oid1, const bson_oid_t *oid2); BSON_EXPORT (void) bson_oid_copy (const bson_oid_t *src, bson_oid_t *dst); BSON_EXPORT (bool) bson_oid_equal (const bson_oid_t *oid1, const bson_oid_t *oid2); BSON_EXPORT (bool) bson_oid_is_valid (const char *str, size_t length); BSON_EXPORT (time_t) bson_oid_get_time_t (const bson_oid_t *oid); BSON_EXPORT (uint32_t) bson_oid_hash (const bson_oid_t *oid); BSON_EXPORT (void) bson_oid_init (bson_oid_t *oid, bson_context_t *context); BSON_EXPORT (void) bson_oid_init_from_data (bson_oid_t *oid, const uint8_t *data); BSON_EXPORT (void) bson_oid_init_from_string (bson_oid_t *oid, const char *str); BSON_EXPORT (void) bson_oid_init_sequence (bson_oid_t *oid, bson_context_t *context) BSON_GNUC_DEPRECATED_FOR (bson_oid_init); BSON_EXPORT (void) bson_oid_to_string (const bson_oid_t *oid, char str[25]); /** * bson_oid_compare_unsafe: * @oid1: A bson_oid_t. * @oid2: A bson_oid_t. * * Performs a qsort() style comparison between @oid1 and @oid2. * * This function is meant to be as fast as possible and therefore performs * no argument validation. That is the callers responsibility. * * Returns: An integer < 0 if @oid1 is less than @oid2. Zero if they are equal. * An integer > 0 if @oid1 is greater than @oid2. */ static BSON_INLINE int bson_oid_compare_unsafe (const bson_oid_t *oid1, const bson_oid_t *oid2) { return memcmp (oid1, oid2, sizeof *oid1); } /** * bson_oid_equal_unsafe: * @oid1: A bson_oid_t. * @oid2: A bson_oid_t. * * Checks the equality of @oid1 and @oid2. * * This function is meant to be as fast as possible and therefore performs * no checks for argument validity. That is the callers responsibility. * * Returns: true if @oid1 and @oid2 are equal; otherwise false. */ static BSON_INLINE bool bson_oid_equal_unsafe (const bson_oid_t *oid1, const bson_oid_t *oid2) { return !memcmp (oid1, oid2, sizeof *oid1); } /** * bson_oid_hash_unsafe: * @oid: A bson_oid_t. * * This function performs a DJB style hash upon the bytes contained in @oid. * The result is a hash key suitable for use in a hashtable. * * This function is meant to be as fast as possible and therefore performs no * validation of arguments. The caller is responsible to ensure they are * passing valid arguments. * * Returns: A uint32_t containing a hash code. */ static BSON_INLINE uint32_t bson_oid_hash_unsafe (const bson_oid_t *oid) { uint32_t hash = 5381; uint32_t i; for (i = 0; i < sizeof oid->bytes; i++) { BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN hash = ((hash << 5) + hash) + oid->bytes[i]; BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } return hash; } /** * bson_oid_copy_unsafe: * @src: A bson_oid_t to copy from. * @dst: A bson_oid_t to copy into. * * Copies the contents of @src into @dst. This function is meant to be as * fast as possible and therefore performs no argument checking. It is the * callers responsibility to ensure they are passing valid data into the * function. */ static BSON_INLINE void bson_oid_copy_unsafe (const bson_oid_t *src, bson_oid_t *dst) { memcpy (dst, src, sizeof *src); } /** * bson_oid_parse_hex_char: * @hex: A character to parse to its integer value. * * This function contains a jump table to return the integer value for a * character containing a hexadecimal value (0-9, a-f, A-F). If the character * is not a hexadecimal character then zero is returned. * * Returns: An integer between 0 and 15. */ static BSON_INLINE uint8_t bson_oid_parse_hex_char (char hex) { switch (hex) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 0xa; case 'b': case 'B': return 0xb; case 'c': case 'C': return 0xc; case 'd': case 'D': return 0xd; case 'e': case 'E': return 0xe; case 'f': case 'F': return 0xf; default: return 0; } } /** * bson_oid_init_from_string_unsafe: * @oid: A bson_oid_t to store the result. * @str: A 24-character hexadecimal encoded string. * * Parses a string containing 24 hexadecimal encoded bytes into a bson_oid_t. * This function is meant to be as fast as possible and inlined into your * code. For that purpose, the function does not perform any sort of bounds * checking and it is the callers responsibility to ensure they are passing * valid input to the function. */ static BSON_INLINE void bson_oid_init_from_string_unsafe (bson_oid_t *oid, const char *str) { int i; for (i = 0; i < 12; i++) { BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_BEGIN oid->bytes[i] = (uint8_t) ((bson_oid_parse_hex_char (str[2 * i]) << 4) | (bson_oid_parse_hex_char (str[2 * i + 1]))); BSON_DISABLE_UNSAFE_BUFFER_USAGE_WARNING_END } } /** * bson_oid_get_time_t_unsafe: * @oid: A bson_oid_t. * * Fetches the time @oid was generated. * * Returns: A time_t containing the UNIX timestamp of generation. */ static BSON_INLINE time_t bson_oid_get_time_t_unsafe (const bson_oid_t *oid) { uint32_t t; memcpy (&t, oid, sizeof (t)); return BSON_UINT32_FROM_BE (t); } BSON_END_DECLS #endif /* BSON_OID_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-prelude.h0000644000175100001660000000132114760300420021411 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) #error "Only can be included directly." #endif mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-private.h0000644000175100001660000000477314760300420021441 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_PRIVATE_H #define BSON_PRIVATE_H #include #include #include BSON_BEGIN_DECLS typedef enum { BSON_FLAG_NONE = 0, BSON_FLAG_INLINE = (1 << 0), BSON_FLAG_STATIC = (1 << 1), BSON_FLAG_RDONLY = (1 << 2), BSON_FLAG_CHILD = (1 << 3), BSON_FLAG_IN_CHILD = (1 << 4), BSON_FLAG_NO_FREE = (1 << 5), } bson_flags_t; #ifdef BSON_MEMCHECK #define BSON_INLINE_DATA_SIZE (120 - sizeof (char *)) #else #define BSON_INLINE_DATA_SIZE 120 #endif BSON_ALIGNED_BEGIN (128) typedef struct { bson_flags_t flags; uint32_t len; #ifdef BSON_MEMCHECK char *canary; #endif uint8_t data[BSON_INLINE_DATA_SIZE]; } bson_impl_inline_t BSON_ALIGNED_END (128); BSON_STATIC_ASSERT2 (impl_inline_t, sizeof (bson_impl_inline_t) == 128); BSON_ALIGNED_BEGIN (128) typedef struct { bson_flags_t flags; /* flags describing the bson_t */ /* len is part of the public bson_t declaration. It is not * exposed through an accessor function. Plus, it's redundant since * BSON self describes the length in the first four bytes of the * buffer. */ uint32_t len; /* length of bson document in bytes */ bson_t *parent; /* parent bson if a child */ uint32_t depth; /* Subdocument depth. */ uint8_t **buf; /* pointer to buffer pointer */ size_t *buflen; /* pointer to buffer length */ size_t offset; /* our offset inside *buf */ uint8_t *alloc; /* buffer that we own. */ size_t alloclen; /* length of buffer that we own. */ bson_realloc_func realloc; /* our realloc implementation */ void *realloc_func_ctx; /* context for our realloc func */ } bson_impl_alloc_t BSON_ALIGNED_END (128); BSON_STATIC_ASSERT2 (impl_alloc_t, sizeof (bson_impl_alloc_t) <= 128); BSON_END_DECLS #endif /* BSON_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-reader.c0000644000175100001660000004542214760300420021220 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #ifdef BSON_OS_WIN32 #include #include #endif #include #include #include #include #include #include typedef enum { BSON_READER_HANDLE = 1, BSON_READER_DATA = 2, } bson_reader_type_t; typedef struct { bson_reader_type_t type; void *handle; bool done : 1; bool failed : 1; size_t end; size_t len; size_t offset; size_t bytes_read; bson_t inline_bson; uint8_t *data; bson_reader_read_func_t read_func; bson_reader_destroy_func_t destroy_func; } bson_reader_handle_t; typedef struct { int fd; bool do_close; } bson_reader_handle_fd_t; typedef struct { bson_reader_type_t type; const uint8_t *data; size_t length; size_t offset; bson_t inline_bson; } bson_reader_data_t; /* *-------------------------------------------------------------------------- * * _bson_reader_handle_fill_buffer -- * * Attempt to read as much as possible until the underlying buffer * in @reader is filled or we have reached end-of-stream or * read failure. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _bson_reader_handle_fill_buffer (bson_reader_handle_t *reader) /* IN */ { ssize_t ret; /* * Handle first read specially. */ if ((!reader->done) && (!reader->offset) && (!reader->end)) { ret = reader->read_func (reader->handle, &reader->data[0], reader->len); if (ret <= 0) { reader->done = true; return; } reader->bytes_read += ret; reader->end = ret; return; } /* * Move valid data to head. */ memmove (&reader->data[0], &reader->data[reader->offset], reader->end - reader->offset); reader->end = reader->end - reader->offset; reader->offset = 0; /* * Read in data to fill the buffer. */ ret = reader->read_func (reader->handle, &reader->data[reader->end], reader->len - reader->end); if (ret <= 0) { reader->done = true; reader->failed = (ret < 0); } else { reader->bytes_read += ret; reader->end += ret; } BSON_ASSERT (reader->offset == 0); BSON_ASSERT (reader->end <= reader->len); } /* *-------------------------------------------------------------------------- * * bson_reader_new_from_handle -- * * Allocates and initializes a new bson_reader_t using the opaque * handle provided. * * Parameters: * @handle: an opaque handle to use to read data. * @rf: a function to perform reads on @handle. * @df: a function to release @handle, or NULL. * * Returns: * A newly allocated bson_reader_t if successful, otherwise NULL. * Free the successful result with bson_reader_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ bson_reader_t * bson_reader_new_from_handle (void *handle, bson_reader_read_func_t rf, bson_reader_destroy_func_t df) { bson_reader_handle_t *real; BSON_ASSERT (handle); BSON_ASSERT (rf); real = BSON_ALIGNED_ALLOC0 (bson_reader_handle_t); real->type = BSON_READER_HANDLE; real->data = bson_malloc0 (1024); real->handle = handle; real->len = 1024; real->offset = 0; bson_reader_set_read_func ((bson_reader_t *) real, rf); if (df) { bson_reader_set_destroy_func ((bson_reader_t *) real, df); } _bson_reader_handle_fill_buffer (real); return (bson_reader_t *) real; } /* *-------------------------------------------------------------------------- * * _bson_reader_handle_fd_destroy -- * * Cleanup allocations associated with state created in * bson_reader_new_from_fd(). * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _bson_reader_handle_fd_destroy (void *handle) /* IN */ { bson_reader_handle_fd_t *fd = handle; if (fd) { if ((fd->fd != -1) && fd->do_close) { #ifdef _WIN32 _close (fd->fd); #else close (fd->fd); #endif } bson_free (fd); } } /* *-------------------------------------------------------------------------- * * _bson_reader_handle_fd_read -- * * Perform read on opaque handle created in * bson_reader_new_from_fd(). * * The underlying file descriptor is read from the current position * using the bson_reader_handle_fd_t allocated. * * Returns: * -1 on failure. * 0 on end of stream. * Greater than zero on success. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static ssize_t _bson_reader_handle_fd_read (void *handle, /* IN */ void *buf, /* IN */ size_t len) /* IN */ { bson_reader_handle_fd_t *fd = handle; ssize_t ret = -1; if (fd && (fd->fd != -1)) { again: #ifdef BSON_OS_WIN32 ret = _read (fd->fd, buf, (unsigned int) len); #else ret = read (fd->fd, buf, len); #endif if ((ret == -1) && (errno == EAGAIN)) { goto again; } } return ret; } /* *-------------------------------------------------------------------------- * * bson_reader_new_from_fd -- * * Create a new bson_reader_t using the file-descriptor provided. * * Parameters: * @fd: a libc style file-descriptor. * @close_on_destroy: if close() should be called on @fd when * bson_reader_destroy() is called. * * Returns: * A newly allocated bson_reader_t on success; otherwise NULL. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bson_reader_t * bson_reader_new_from_fd (int fd, /* IN */ bool close_on_destroy) /* IN */ { bson_reader_handle_fd_t *handle; BSON_ASSERT (fd != -1); handle = bson_malloc0 (sizeof *handle); handle->fd = fd; handle->do_close = close_on_destroy; return bson_reader_new_from_handle (handle, _bson_reader_handle_fd_read, _bson_reader_handle_fd_destroy); } /** * bson_reader_set_read_func: * @reader: A bson_reader_t. * * Note that @reader must be initialized by bson_reader_init_from_handle(), or * data * will be destroyed. */ /* *-------------------------------------------------------------------------- * * bson_reader_set_read_func -- * * Set the read func to be provided for @reader. * * You probably want to use bson_reader_new_from_handle() or * bson_reader_new_from_fd() instead. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_reader_set_read_func (bson_reader_t *reader, /* IN */ bson_reader_read_func_t func) /* IN */ { bson_reader_handle_t *real = (bson_reader_handle_t *) reader; BSON_ASSERT (reader->type == BSON_READER_HANDLE); real->read_func = func; } /* *-------------------------------------------------------------------------- * * bson_reader_set_destroy_func -- * * Set the function to cleanup state when @reader is destroyed. * * You probably want bson_reader_new_from_fd() or * bson_reader_new_from_handle() instead. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_reader_set_destroy_func (bson_reader_t *reader, /* IN */ bson_reader_destroy_func_t func) /* IN */ { bson_reader_handle_t *real = (bson_reader_handle_t *) reader; BSON_ASSERT (reader->type == BSON_READER_HANDLE); real->destroy_func = func; } /* *-------------------------------------------------------------------------- * * _bson_reader_handle_grow_buffer -- * * Grow the buffer to the next power of two. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _bson_reader_handle_grow_buffer (bson_reader_handle_t *reader) /* IN */ { size_t size; size = reader->len * 2; reader->data = bson_realloc (reader->data, size); reader->len = size; } /* *-------------------------------------------------------------------------- * * _bson_reader_handle_tell -- * * Tell the current position within the underlying file-descriptor. * * Returns: * An off_t containing the current offset. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static off_t _bson_reader_handle_tell (bson_reader_handle_t *reader) /* IN */ { off_t off; off = (off_t) reader->bytes_read; off -= (off_t) reader->end; off += (off_t) reader->offset; return off; } /* *-------------------------------------------------------------------------- * * _bson_reader_handle_read -- * * Read the next chunk of data from the underlying file descriptor * and return a bson_t which should not be modified. * * There was a failure if NULL is returned and @reached_eof is * not set to true. * * Returns: * NULL on failure or end of stream. * * Side effects: * @reached_eof is set if non-NULL. * *-------------------------------------------------------------------------- */ static const bson_t * _bson_reader_handle_read (bson_reader_handle_t *reader, /* IN */ bool *reached_eof) /* IN */ { int32_t blen; if (reached_eof) { *reached_eof = false; } while (!reader->done) { if ((reader->end - reader->offset) < 4) { _bson_reader_handle_fill_buffer (reader); continue; } memcpy (&blen, &reader->data[reader->offset], sizeof blen); blen = BSON_UINT32_FROM_LE (blen); if (blen < 5) { return NULL; } if (blen > (int32_t) (reader->end - reader->offset)) { if (blen > (int32_t) reader->len) { _bson_reader_handle_grow_buffer (reader); } _bson_reader_handle_fill_buffer (reader); continue; } if (!bson_init_static (&reader->inline_bson, &reader->data[reader->offset], (uint32_t) blen)) { return NULL; } reader->offset += blen; return &reader->inline_bson; } if (reached_eof) { *reached_eof = reader->done && !reader->failed; } return NULL; } /* *-------------------------------------------------------------------------- * * bson_reader_new_from_data -- * * Allocates and initializes a new bson_reader_t that reads the memory * provided as a stream of BSON documents. * * Parameters: * @data: A buffer to read BSON documents from. * @length: The length of @data. * * Returns: * A newly allocated bson_reader_t that should be freed with * bson_reader_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ bson_reader_t * bson_reader_new_from_data (const uint8_t *data, /* IN */ size_t length) /* IN */ { bson_reader_data_t *real; BSON_ASSERT (data); real = BSON_ALIGNED_ALLOC0 (bson_reader_data_t); real->type = BSON_READER_DATA; real->data = data; real->length = length; real->offset = 0; return (bson_reader_t *) real; } /* *-------------------------------------------------------------------------- * * _bson_reader_data_read -- * * Read the next document from the underlying buffer. * * Returns: * NULL on failure or end of stream. * a bson_t which should not be modified. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static const bson_t * _bson_reader_data_read (bson_reader_data_t *reader, /* IN */ bool *reached_eof) /* IN */ { int32_t blen; if (reached_eof) { *reached_eof = false; } if ((reader->offset + 4) < reader->length) { memcpy (&blen, &reader->data[reader->offset], sizeof blen); blen = BSON_UINT32_FROM_LE (blen); if (blen < 5) { return NULL; } if (blen > (int32_t) (reader->length - reader->offset)) { return NULL; } if (!bson_init_static (&reader->inline_bson, &reader->data[reader->offset], (uint32_t) blen)) { return NULL; } reader->offset += blen; return &reader->inline_bson; } if (reached_eof) { *reached_eof = (reader->offset == reader->length); } return NULL; } /* *-------------------------------------------------------------------------- * * _bson_reader_data_tell -- * * Tell the current position in the underlying buffer. * * Returns: * An off_t of the current offset. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static off_t _bson_reader_data_tell (bson_reader_data_t *reader) /* IN */ { return (off_t) reader->offset; } /* *-------------------------------------------------------------------------- * * bson_reader_destroy -- * * Release a bson_reader_t created with bson_reader_new_from_data(), * bson_reader_new_from_fd(), or bson_reader_new_from_handle(). * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_reader_destroy (bson_reader_t *reader) /* IN */ { if (!reader) { return; } switch (reader->type) { case 0: break; case BSON_READER_HANDLE: { bson_reader_handle_t *handle = (bson_reader_handle_t *) reader; if (handle->destroy_func) { handle->destroy_func (handle->handle); } bson_free (handle->data); } break; case BSON_READER_DATA: break; default: fprintf (stderr, "No such reader type: %02x\n", reader->type); break; } reader->type = 0; bson_free (reader); } /* *-------------------------------------------------------------------------- * * bson_reader_read -- * * Reads the next bson_t in the underlying memory or storage. The * resulting bson_t should not be modified or freed. You may copy it * and iterate over it. Functions that take a const bson_t* are safe * to use. * * This structure does not survive calls to bson_reader_read() or * bson_reader_destroy() as it uses memory allocated by the reader or * underlying storage/memory. * * If NULL is returned then @reached_eof will be set to true if the * end of the file or buffer was reached. This indicates if there was * an error parsing the document stream. * * Returns: * A const bson_t that should not be modified or freed. * NULL on failure or end of stream. * * Side effects: * @reached_eof is set if non-NULL. * *-------------------------------------------------------------------------- */ const bson_t * bson_reader_read (bson_reader_t *reader, /* IN */ bool *reached_eof) /* OUT */ { BSON_ASSERT (reader); switch (reader->type) { case BSON_READER_HANDLE: return _bson_reader_handle_read ((bson_reader_handle_t *) reader, reached_eof); case BSON_READER_DATA: return _bson_reader_data_read ((bson_reader_data_t *) reader, reached_eof); default: fprintf (stderr, "No such reader type: %02x\n", reader->type); break; } return NULL; } /* *-------------------------------------------------------------------------- * * bson_reader_tell -- * * Return the current position in the underlying reader. This will * always be at the beginning of a bson document or end of file. * * Returns: * An off_t containing the current offset. * * Side effects: * None. * *-------------------------------------------------------------------------- */ off_t bson_reader_tell (bson_reader_t *reader) /* IN */ { BSON_ASSERT (reader); switch (reader->type) { case BSON_READER_HANDLE: return _bson_reader_handle_tell ((bson_reader_handle_t *) reader); case BSON_READER_DATA: return _bson_reader_data_tell ((bson_reader_data_t *) reader); default: fprintf (stderr, "No such reader type: %02x\n", reader->type); return -1; } } /* *-------------------------------------------------------------------------- * * bson_reader_new_from_file -- * * A convenience function to open a file containing sequential * bson documents and read them using bson_reader_t. * * Returns: * A new bson_reader_t if successful, otherwise NULL and * @error is set. Free the non-NULL result with * bson_reader_destroy(). * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ bson_reader_t * bson_reader_new_from_file (const char *path, /* IN */ bson_error_t *error) /* OUT */ { char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; char *errmsg; int fd; BSON_ASSERT (path); #ifdef BSON_OS_WIN32 if (_sopen_s (&fd, path, (_O_RDONLY | _O_BINARY), _SH_DENYNO, 0) != 0) { fd = -1; } #else fd = open (path, O_RDONLY); #endif if (fd == -1) { errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf); bson_set_error (error, BSON_ERROR_READER, BSON_ERROR_READER_BADFD, "%s", errmsg); return NULL; } return bson_reader_new_from_fd (fd, true); } /* *-------------------------------------------------------------------------- * * bson_reader_reset -- * * Restore the reader to its initial state. Valid only for readers * created with bson_reader_new_from_data. * *-------------------------------------------------------------------------- */ void bson_reader_reset (bson_reader_t *reader) { bson_reader_data_t *real = (bson_reader_data_t *) reader; if (real->type != BSON_READER_DATA) { fprintf (stderr, "Reader type cannot be reset\n"); return; } real->offset = 0; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-reader.h0000644000175100001660000000632414760300420021223 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_READER_H #define BSON_READER_H #include #include #include BSON_BEGIN_DECLS #define BSON_ERROR_READER_BADFD 1 /* *-------------------------------------------------------------------------- * * bson_reader_read_func_t -- * * This function is a callback used by bson_reader_t to read the * next chunk of data from the underlying opaque file descriptor. * * This function is meant to operate similar to the read() function * as part of libc on UNIX-like systems. * * Parameters: * @handle: The handle to read from. * @buf: The buffer to read into. * @count: The number of bytes to read. * * Returns: * 0 for end of stream. * -1 for read failure. * Greater than zero for number of bytes read into @buf. * * Side effects: * None. * *-------------------------------------------------------------------------- */ typedef ssize_t (*bson_reader_read_func_t) (void *handle, /* IN */ void *buf, /* IN */ size_t count); /* IN */ /* *-------------------------------------------------------------------------- * * bson_reader_destroy_func_t -- * * Destroy callback to release any resources associated with the * opaque handle. * * Parameters: * @handle: the handle provided to bson_reader_new_from_handle(). * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ typedef void (*bson_reader_destroy_func_t) (void *handle); /* IN */ BSON_EXPORT (bson_reader_t *) bson_reader_new_from_handle (void *handle, bson_reader_read_func_t rf, bson_reader_destroy_func_t df); BSON_EXPORT (bson_reader_t *) bson_reader_new_from_fd (int fd, bool close_on_destroy); BSON_EXPORT (bson_reader_t *) bson_reader_new_from_file (const char *path, bson_error_t *error); BSON_EXPORT (bson_reader_t *) bson_reader_new_from_data (const uint8_t *data, size_t length); BSON_EXPORT (void) bson_reader_destroy (bson_reader_t *reader); BSON_EXPORT (void) bson_reader_set_read_func (bson_reader_t *reader, bson_reader_read_func_t func); BSON_EXPORT (void) bson_reader_set_destroy_func (bson_reader_t *reader, bson_reader_destroy_func_t func); BSON_EXPORT (const bson_t *) bson_reader_read (bson_reader_t *reader, bool *reached_eof); BSON_EXPORT (off_t) bson_reader_tell (bson_reader_t *reader); BSON_EXPORT (void) bson_reader_reset (bson_reader_t *reader); BSON_END_DECLS #endif /* BSON_READER_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-string.c0000644000175100001660000003554214760300420021266 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #ifdef BSON_HAVE_STRINGS_H #include #else #include #endif bson_string_t * bson_string_new (const char *str) /* IN */ { /* Compatibility wrapper; deprecated. * New mcommon_string behavior is to use power of two rounding for resize but not for initial allocation unless * extra capacity is explicitly requested. This emulates the old behavior, padding the allocation of all new strings. */ size_t len = str ? strlen (str) : 0; BSON_ASSERT (mcommon_in_range_unsigned (uint32_t, len) && (uint32_t) len < UINT32_MAX); uint32_t alloc = mcommon_next_power_of_two_u32 ((uint32_t) len + 1); return (bson_string_t *) mcommon_string_new_with_capacity (str ? str : "", (uint32_t) len, alloc - 1); } char * bson_string_free (bson_string_t *string, /* IN */ bool free_segment) /* IN */ { // Compatibility wrapper; deprecated. if (free_segment) { mcommon_string_destroy ((mcommon_string_t *) string); return NULL; } else { return mcommon_string_destroy_with_steal ((mcommon_string_t *) string); } } void bson_string_append (bson_string_t *string, /* IN */ const char *str) /* IN */ { // Compatibility wrapper; deprecated. BSON_ASSERT_PARAM (string); BSON_ASSERT_PARAM (str); mcommon_string_append_t append; mcommon_string_set_append ((mcommon_string_t *) string, &append); (void) mcommon_string_append (&append, str); } void bson_string_append_unichar (bson_string_t *string, /* IN */ bson_unichar_t unichar) /* IN */ { // Compatibility wrapper; deprecated. BSON_ASSERT_PARAM (string); mcommon_string_append_t append; mcommon_string_set_append ((mcommon_string_t *) string, &append); (void) mcommon_string_append_unichar (&append, unichar); } void bson_string_append_c (bson_string_t *string, /* IN */ char c) /* IN */ { // Compatibility wrapper; deprecated. BSON_ASSERT_PARAM (string); mcommon_string_append_t append; mcommon_string_set_append ((mcommon_string_t *) string, &append); (void) mcommon_string_append_bytes (&append, &c, 1); } void bson_string_append_printf (bson_string_t *string, const char *format, ...) { // Compatibility wrapper; deprecated. BSON_ASSERT_PARAM (string); BSON_ASSERT_PARAM (format); va_list args; mcommon_string_append_t append; mcommon_string_set_append ((mcommon_string_t *) string, &append); va_start (args, format); (void) mcommon_string_append_vprintf (&append, format, args); va_end (args); } void bson_string_truncate (bson_string_t *string, /* IN */ uint32_t len) /* IN */ { /* Does not preserve UTF-8 validity; deprecated. * Although the documentation only describes truncation as decreasing the length, we have undocumented requirements: * the string may grow or shrink, and the buffer is expected to be allocated using the same power-of-two scheme as * when growing to append. No effect if 'string' already has the requested length, regardless of the allocation size. * When extending string length, this implementation is guaranteed to fill with NUL bytes. Previous versions left the * new buffer contents undefined. */ BSON_ASSERT_PARAM (string); BSON_ASSERT (len < UINT32_MAX); uint32_t old_len = string->len; if (len != old_len) { uint32_t alloc = mcommon_next_power_of_two_u32 (len + 1u); char *buffer = bson_realloc (string->str, alloc); string->str = buffer; string->alloc = alloc; string->len = len; if (len < old_len) { buffer[len] = '\0'; } else { memset (buffer + old_len, 0, len + 1 - old_len); } } } /* *-------------------------------------------------------------------------- * * bson_strdup -- * * Portable strdup(). * * Returns: * A newly allocated string that should be freed with bson_free(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * bson_strdup (const char *str) /* IN */ { long len; char *out; if (!str) { return NULL; } len = (long) strlen (str); out = bson_malloc (len + 1); if (!out) { return NULL; } memcpy (out, str, len + 1); return out; } /* *-------------------------------------------------------------------------- * * bson_strdupv_printf -- * * Like bson_strdup_printf() but takes a va_list. * * Returns: * A newly allocated string that should be freed with bson_free(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * bson_strdupv_printf (const char *format, /* IN */ va_list args) /* IN */ { va_list my_args; char *buf; int len = 32; int n; BSON_ASSERT (format); buf = bson_malloc0 (len); while (true) { va_copy (my_args, args); n = bson_vsnprintf (buf, len, format, my_args); va_end (my_args); if (n > -1 && n < len) { return buf; } if (n > -1) { len = n + 1; } else { len *= 2; } buf = bson_realloc (buf, len); } } /* *-------------------------------------------------------------------------- * * bson_strdup_printf -- * * Convenience function that formats a string according to @format * and returns a copy of it. * * Returns: * A newly created string that should be freed with bson_free(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * bson_strdup_printf (const char *format, /* IN */ ...) /* IN */ { va_list args; char *ret; BSON_ASSERT (format); va_start (args, format); ret = bson_strdupv_printf (format, args); va_end (args); return ret; } /* *-------------------------------------------------------------------------- * * bson_strndup -- * * A portable strndup(). * * Returns: * A newly allocated string that should be freed with bson_free(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * bson_strndup (const char *str, /* IN */ size_t n_bytes) /* IN */ { char *ret; BSON_ASSERT (str); ret = bson_malloc (n_bytes + 1); bson_strncpy (ret, str, n_bytes + 1); return ret; } /* *-------------------------------------------------------------------------- * * bson_strfreev -- * * Frees each string in a NULL terminated array of strings. * This also frees the underlying array. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_strfreev (char **str) /* IN */ { if (str) { for (char **ptr = str; *ptr != NULL; ++ptr) { bson_free (*ptr); } bson_free (str); } } /* *-------------------------------------------------------------------------- * * bson_strnlen -- * * A portable strnlen(). * * Returns: * The length of @s up to @maxlen. * * Side effects: * None. * *-------------------------------------------------------------------------- */ size_t bson_strnlen (const char *s, /* IN */ size_t maxlen) /* IN */ { #ifdef BSON_HAVE_STRNLEN return strnlen (s, maxlen); #else size_t i; for (i = 0; i < maxlen; i++) { if (s[i] == '\0') { return i; } } return maxlen; #endif } /* *-------------------------------------------------------------------------- * * bson_strncpy -- * * A portable strncpy. * * Copies @src into @dst, which must be @size bytes or larger. * The result is guaranteed to be \0 terminated. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_strncpy (char *dst, /* IN */ const char *src, /* IN */ size_t size) /* IN */ { if (size == 0) { return; } /* Prefer strncpy_s for MSVC, or strlcpy, which has additional checks and only * adds one trailing \0 */ #ifdef _MSC_VER strncpy_s (dst, size, src, _TRUNCATE); #elif defined(BSON_HAVE_STRLCPY) strlcpy (dst, src, size); #else strncpy (dst, src, size); dst[size - 1] = '\0'; #endif } /* *-------------------------------------------------------------------------- * * bson_vsnprintf -- * * A portable vsnprintf. * * If more than @size bytes are required (exluding the null byte), * then @size bytes will be written to @string and the return value * is the number of bytes required. * * This function will always return a NULL terminated string. * * Returns: * The number of bytes required for @format excluding the null byte. * * Side effects: * @str is initialized with the formatted string. * *-------------------------------------------------------------------------- */ int bson_vsnprintf (char *str, /* IN */ size_t size, /* IN */ const char *format, /* IN */ va_list ap) /* IN */ { #ifdef _MSC_VER int r = -1; BSON_ASSERT (str); if (size == 0) { return 0; } r = _vsnprintf_s (str, size, _TRUNCATE, format, ap); if (r == -1) { r = _vscprintf (format, ap); } str[size - 1] = '\0'; return r; #else int r; BSON_ASSERT (str); if (size == 0) { return 0; } r = vsnprintf (str, size, format, ap); str[size - 1] = '\0'; return r; #endif } /* *-------------------------------------------------------------------------- * * bson_snprintf -- * * A portable snprintf. * * If @format requires more than @size bytes, then @size bytes are * written and the result is the number of bytes required (excluding * the null byte). * * This function will always return a NULL terminated string. * * Returns: * The number of bytes required for @format. * * Side effects: * @str is initialized. * *-------------------------------------------------------------------------- */ int bson_snprintf (char *str, /* IN */ size_t size, /* IN */ const char *format, /* IN */ ...) { int r; va_list ap; BSON_ASSERT (str); va_start (ap, format); r = bson_vsnprintf (str, size, format, ap); va_end (ap); return r; } /* *-------------------------------------------------------------------------- * * bson_ascii_strtoll -- * * A portable strtoll. * * Convert a string to a 64-bit signed integer according to the given * @base, which must be 16, 10, or 8. Leading whitespace will be ignored. * * If base is 0 is passed in, the base is inferred from the string's * leading characters. Base-16 numbers start with "0x" or "0X", base-8 * numbers start with "0", base-10 numbers start with a digit from 1 to 9. * * If @e is not NULL, it will be assigned the address of the first invalid * character of @s, or its null terminating byte if the entire string was * valid. * * If an invalid value is encountered, errno will be set to EINVAL and * zero will be returned. If the number is out of range, errno is set to * ERANGE and LLONG_MAX or LLONG_MIN is returned. * * Returns: * The result of the conversion. * * Side effects: * errno will be set on error. * *-------------------------------------------------------------------------- */ int64_t bson_ascii_strtoll (const char *s, char **e, int base) { char *tok = (char *) s; char *digits_start; char c; int64_t number = 0; int64_t sign = 1; int64_t cutoff; int64_t cutlim; errno = 0; if (!s) { errno = EINVAL; return 0; } c = *tok; while (bson_isspace (c)) { c = *++tok; } if (c == '-') { sign = -1; c = *++tok; } else if (c == '+') { c = *++tok; } else if (!isdigit (c)) { errno = EINVAL; return 0; } /* from here down, inspired by NetBSD's strtoll */ if ((base == 0 || base == 16) && c == '0' && (tok[1] == 'x' || tok[1] == 'X')) { tok += 2; c = *tok; base = 16; } if (base == 0) { base = c == '0' ? 8 : 10; } /* Cutoff is the greatest magnitude we'll be able to multiply by base without * range error. If the current number is past cutoff and we see valid digit, * fail. If the number is *equal* to cutoff, then the next digit must be less * than cutlim, otherwise fail. */ cutoff = sign == -1 ? INT64_MIN : INT64_MAX; cutlim = (int) (cutoff % base); cutoff /= base; if (sign == -1) { if (cutlim > 0) { cutlim -= base; cutoff += 1; } cutlim = -cutlim; } digits_start = tok; while ((c = *tok)) { if (isdigit (c)) { c -= '0'; } else if (isalpha (c)) { c -= isupper (c) ? 'A' - 10 : 'a' - 10; } else { /* end of number string */ break; } if (c >= base) { break; } if (sign == -1) { if (number < cutoff || (number == cutoff && c > cutlim)) { number = INT64_MIN; errno = ERANGE; break; } else { number *= base; number -= c; } } else { if (number > cutoff || (number == cutoff && c > cutlim)) { number = INT64_MAX; errno = ERANGE; break; } else { number *= base; number += c; } } tok++; } /* did we parse any digits at all? */ if (e != NULL && tok > digits_start) { *e = tok; } return number; } int bson_strcasecmp (const char *s1, const char *s2) { #ifdef BSON_OS_WIN32 return _stricmp (s1, s2); #else return strcasecmp (s1, s2); #endif } bool bson_isspace (int c) { return c >= -1 && c <= 255 && isspace (c); } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-string.h0000644000175100001660000000502014760300420021257 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_STRING_H #define BSON_STRING_H #include #include #include BSON_BEGIN_DECLS typedef struct { char *str; uint32_t len; uint32_t alloc; } bson_string_t; BSON_EXPORT (bson_string_t *) bson_string_new (const char *str) BSON_GNUC_DEPRECATED; BSON_EXPORT (char *) bson_string_free (bson_string_t *string, bool free_segment) BSON_GNUC_DEPRECATED; BSON_EXPORT (void) bson_string_append (bson_string_t *string, const char *str) BSON_GNUC_DEPRECATED; BSON_EXPORT (void) bson_string_append_c (bson_string_t *string, char str) BSON_GNUC_DEPRECATED; BSON_EXPORT (void) bson_string_append_unichar (bson_string_t *string, bson_unichar_t unichar) BSON_GNUC_DEPRECATED; BSON_EXPORT (void) bson_string_append_printf (bson_string_t *string, const char *format, ...) BSON_GNUC_PRINTF (2, 3) BSON_GNUC_DEPRECATED; BSON_EXPORT (void) bson_string_truncate (bson_string_t *string, uint32_t len) BSON_GNUC_DEPRECATED; BSON_EXPORT (char *) bson_strdup (const char *str); BSON_EXPORT (char *) bson_strdup_printf (const char *format, ...) BSON_GNUC_PRINTF (1, 2); BSON_EXPORT (char *) bson_strdupv_printf (const char *format, va_list args) BSON_GNUC_PRINTF (1, 0); BSON_EXPORT (char *) bson_strndup (const char *str, size_t n_bytes); BSON_EXPORT (void) bson_strncpy (char *dst, const char *src, size_t size); BSON_EXPORT (int) bson_vsnprintf (char *str, size_t size, const char *format, va_list ap) BSON_GNUC_PRINTF (3, 0); BSON_EXPORT (int) bson_snprintf (char *str, size_t size, const char *format, ...) BSON_GNUC_PRINTF (3, 4); BSON_EXPORT (void) bson_strfreev (char **strv); BSON_EXPORT (size_t) bson_strnlen (const char *s, size_t maxlen); BSON_EXPORT (int64_t) bson_ascii_strtoll (const char *str, char **endptr, int base); BSON_EXPORT (int) bson_strcasecmp (const char *s1, const char *s2); BSON_EXPORT (bool) bson_isspace (int c); BSON_END_DECLS #endif /* BSON_STRING_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-timegm-private.h0000644000175100001660000000304414760300420022707 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_TIMEGM_PRIVATE_H #define BSON_TIMEGM_PRIVATE_H #include #include BSON_BEGIN_DECLS /* avoid system-dependent struct tm definitions */ struct bson_tm { int64_t tm_sec; /* seconds after the minute [0-60] */ int64_t tm_min; /* minutes after the hour [0-59] */ int64_t tm_hour; /* hours since midnight [0-23] */ int64_t tm_mday; /* day of the month [1-31] */ int64_t tm_mon; /* months since January [0-11] */ int64_t tm_year; /* years since 1900 */ int64_t tm_wday; /* days since Sunday [0-6] */ int64_t tm_yday; /* days since January 1 [0-365] */ int64_t tm_isdst; /* Daylight Savings Time flag */ int64_t tm_gmtoff; /* offset from CUT in seconds */ const char *tm_zone; /* timezone abbreviation */ }; int64_t _bson_timegm (struct bson_tm *const tmp); BSON_END_DECLS #endif /* BSON_TIMEGM_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-timegm.c0000644000175100001660000005446514760300420021247 0ustar /* ** The original version of this file is in the public domain, so clarified as of ** 1996-06-05 by Arthur David Olson. */ /* ** Leap second handling from Bradley White. ** POSIX-style TZ environment variable handling from Guy Harris. ** Updated to use int64_t's instead of system-dependent definitions of int64_t ** and struct tm by A. Jesse Jiryu Davis for MongoDB, Inc. */ #include #include #include #include #include #include /* for INT64_MAX and INT64_MIN */ /* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */ #define is_digit(c) ((unsigned) (c) - '0' <= 9) #if 2 < __GNUC__ + (96 <= __GNUC_MINOR__) #define ATTRIBUTE_CONST __attribute__ ((const)) #define ATTRIBUTE_PURE __attribute__ ((__pure__)) #define ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) #else #define ATTRIBUTE_CONST /* empty */ #define ATTRIBUTE_PURE /* empty */ #define ATTRIBUTE_FORMAT(spec) /* empty */ #endif #if !defined(__STDC_VERSION__) && !defined restrict #define restrict /* empty */ #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-pragmas" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wshift-negative-value" #endif /* The minimum and maximum finite time values. */ static int64_t const time_t_min = INT64_MIN; static int64_t const time_t_max = INT64_MAX; #ifdef __clang__ #pragma clang diagnostic pop #pragma clang diagnostic pop #endif #ifndef TZ_MAX_TIMES #define TZ_MAX_TIMES 2000 #endif /* !defined TZ_MAX_TIMES */ #ifndef TZ_MAX_TYPES /* This must be at least 17 for Europe/Samara and Europe/Vilnius. */ #define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ #endif /* !defined TZ_MAX_TYPES */ #ifndef TZ_MAX_CHARS #define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ /* (limited by what unsigned chars can hold) */ #endif /* !defined TZ_MAX_CHARS */ #ifndef TZ_MAX_LEAPS #define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ #endif /* !defined TZ_MAX_LEAPS */ #define SECSPERMIN 60 #define MINSPERHOUR 60 #define HOURSPERDAY 24 #define DAYSPERWEEK 7 #define DAYSPERNYEAR 365 #define DAYSPERLYEAR 366 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) #define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) #define MONSPERYEAR 12 #define TM_SUNDAY 0 #define TM_MONDAY 1 #define TM_TUESDAY 2 #define TM_WEDNESDAY 3 #define TM_THURSDAY 4 #define TM_FRIDAY 5 #define TM_SATURDAY 6 #define TM_JANUARY 0 #define TM_FEBRUARY 1 #define TM_MARCH 2 #define TM_APRIL 3 #define TM_MAY 4 #define TM_JUNE 5 #define TM_JULY 6 #define TM_AUGUST 7 #define TM_SEPTEMBER 8 #define TM_OCTOBER 9 #define TM_NOVEMBER 10 #define TM_DECEMBER 11 #define TM_YEAR_BASE 1900 #define EPOCH_YEAR 1970 #define EPOCH_WDAY TM_THURSDAY #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) /* ** Since everything in isleap is modulo 400 (or a factor of 400), we know that ** isleap(y) == isleap(y % 400) ** and so ** isleap(a + b) == isleap((a + b) % 400) ** or ** isleap(a + b) == isleap(a % 400 + b % 400) ** This is true even if % means modulo rather than Fortran remainder ** (which is allowed by C89 but not C99). ** We use this to avoid addition overflow problems. */ #define isleap_sum(a, b) isleap ((a) % 400 + (b) % 400) #ifndef TZ_ABBR_MAX_LEN #define TZ_ABBR_MAX_LEN 16 #endif /* !defined TZ_ABBR_MAX_LEN */ #ifndef TZ_ABBR_CHAR_SET #define TZ_ABBR_CHAR_SET "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" #endif /* !defined TZ_ABBR_CHAR_SET */ #ifndef TZ_ABBR_ERR_CHAR #define TZ_ABBR_ERR_CHAR '_' #endif /* !defined TZ_ABBR_ERR_CHAR */ #ifndef WILDABBR /* ** Someone might make incorrect use of a time zone abbreviation: ** 1. They might reference tzname[0] before calling tzset (explicitly ** or implicitly). ** 2. They might reference tzname[1] before calling tzset (explicitly ** or implicitly). ** 3. They might reference tzname[1] after setting to a time zone ** in which Daylight Saving Time is never observed. ** 4. They might reference tzname[0] after setting to a time zone ** in which Standard Time is never observed. ** 5. They might reference tm.TM_ZONE after calling offtime. ** What's best to do in the above cases is open to debate; ** for now, we just set things up so that in any of the five cases ** WILDABBR is used. Another possibility: initialize tzname[0] to the ** string "tzname[0] used before set", and similarly for the other cases. ** And another: initialize tzname[0] to "ERA", with an explanation in the ** manual page of what this "time zone abbreviation" means (doing this so ** that tzname[0] has the "normal" length of three characters). */ #define WILDABBR " " #endif /* !defined WILDABBR */ #ifdef TM_ZONE static const char wildabbr[] = WILDABBR; static const char gmt[] = "GMT"; #endif struct ttinfo { /* time type information */ int_fast32_t tt_gmtoff; /* UT offset in seconds */ int tt_isdst; /* used to set tm_isdst */ int tt_abbrind; /* abbreviation list index */ int tt_ttisstd; /* true if transition is std time */ int tt_ttisgmt; /* true if transition is UT */ }; struct lsinfo { /* leap second information */ int64_t ls_trans; /* transition time */ int_fast64_t ls_corr; /* correction to apply */ }; #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) #ifdef TZNAME_MAX #define MY_TZNAME_MAX TZNAME_MAX #endif /* defined TZNAME_MAX */ #ifndef TZNAME_MAX #define MY_TZNAME_MAX 255 #endif /* !defined TZNAME_MAX */ struct state { int leapcnt; int timecnt; int typecnt; int charcnt; int goback; int goahead; int64_t ats[TZ_MAX_TIMES]; unsigned char types[TZ_MAX_TIMES]; struct ttinfo ttis[TZ_MAX_TYPES]; char chars[BIGGEST (TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))]; struct lsinfo lsis[TZ_MAX_LEAPS]; int defaulttype; /* for early times or if no transitions */ }; struct rule { int r_type; /* type of rule--see below */ int r_day; /* day number of rule */ int r_week; /* week number of rule */ int r_mon; /* month number of rule */ int_fast32_t r_time; /* transition time of rule */ }; #define JULIAN_DAY 0 /* Jn - Julian day */ #define DAY_OF_YEAR 1 /* n - day of year */ #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ /* ** Prototypes for static functions. */ static void gmtload (struct state *const sp); static struct bson_tm * gmtsub (const int64_t *const timep, const int_fast32_t offset, struct bson_tm *const tmp); static int64_t increment_overflow (int64_t *const ip, int64_t j); static int64_t leaps_thru_end_of (const int64_t y) ATTRIBUTE_PURE; static int64_t increment_overflow32 (int_fast32_t *const lp, int64_t const m); static int64_t normalize_overflow32 (int_fast32_t *const tensptr, int64_t *const unitsptr, const int64_t base); static int64_t normalize_overflow (int64_t *const tensptr, int64_t *const unitsptr, const int64_t base); static int64_t time1 (struct bson_tm *const tmp, struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), const int_fast32_t offset); static int64_t time2 (struct bson_tm *const tmp, struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), const int_fast32_t offset, int64_t *const okayp); static int64_t time2sub (struct bson_tm *const tmp, struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), const int_fast32_t offset, int64_t *const okayp, const int64_t do_norm_secs); static struct bson_tm * timesub (const int64_t *const timep, const int_fast32_t offset, const struct state *const sp, struct bson_tm *const tmp); static int64_t tmcomp (const struct bson_tm *const atmp, const struct bson_tm *const btmp); static struct state gmtmem; #define gmtptr (&gmtmem) static int gmt_is_set; static const int mon_lengths[2][MONSPERYEAR] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; static const int year_lengths[2] = {DAYSPERNYEAR, DAYSPERLYEAR}; static void gmtload (struct state *const sp) { memset (sp, 0, sizeof (struct state)); sp->typecnt = 1; sp->charcnt = 4; sp->chars[0] = 'G'; sp->chars[1] = 'M'; sp->chars[2] = 'T'; } /* ** gmtsub is to gmtime as localsub is to localtime. */ static struct bson_tm * gmtsub (const int64_t *const timep, const int_fast32_t offset, struct bson_tm *const tmp) { struct bson_tm *result; if (!gmt_is_set) { gmt_is_set = true; gmtload (gmtptr); } result = timesub (timep, offset, gmtptr, tmp); #ifdef TM_ZONE /* ** Could get fancy here and deliver something such as ** "UT+xxxx" or "UT-xxxx" if offset is non-zero, ** but this is no time for a treasure hunt. */ tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt; #endif /* defined TM_ZONE */ return result; } /* ** Return the number of leap years through the end of the given year ** where, to make the math easy, the answer for year zero is defined as zero. */ static int64_t leaps_thru_end_of (const int64_t y) { return (y >= 0) ? (y / 4 - y / 100 + y / 400) : -(leaps_thru_end_of (-(y + 1)) + 1); } static struct bson_tm * timesub (const int64_t *const timep, const int_fast32_t offset, const struct state *const sp, struct bson_tm *const tmp) { const struct lsinfo *lp; int64_t tdays; int64_t idays; /* unsigned would be so 2003 */ int_fast64_t rem; int64_t y; const int (*ip)[MONSPERYEAR]; int_fast64_t corr; int64_t hit; int64_t i; corr = 0; hit = 0; i = (sp == NULL) ? 0 : sp->leapcnt; while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) { if (*timep == lp->ls_trans) { hit = ((i == 0 && lp->ls_corr > 0) || lp->ls_corr > sp->lsis[i - 1].ls_corr); if (hit) while (i > 0 && sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 && sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1) { ++hit; --i; } } corr = lp->ls_corr; break; } } y = EPOCH_YEAR; tdays = *timep / SECSPERDAY; rem = *timep - tdays * SECSPERDAY; while (tdays < 0 || tdays >= year_lengths[isleap (y)]) { int64_t newy; int64_t tdelta; int64_t idelta; int64_t leapdays; tdelta = tdays / DAYSPERLYEAR; idelta = tdelta; if (idelta == 0) idelta = (tdays < 0) ? -1 : 1; newy = y; if (increment_overflow (&newy, idelta)) return NULL; leapdays = leaps_thru_end_of (newy - 1) - leaps_thru_end_of (y - 1); tdays -= ((int64_t) newy - y) * DAYSPERNYEAR; tdays -= leapdays; y = newy; } { int_fast32_t seconds; seconds = (int_fast32_t) (tdays * SECSPERDAY); tdays = seconds / SECSPERDAY; rem += seconds - tdays * SECSPERDAY; } /* ** Given the range, we can now fearlessly cast... */ idays = (int64_t) tdays; rem += offset - corr; while (rem < 0) { rem += SECSPERDAY; --idays; } while (rem >= SECSPERDAY) { rem -= SECSPERDAY; ++idays; } while (idays < 0) { if (increment_overflow (&y, -1)) return NULL; idays += year_lengths[isleap (y)]; } while (idays >= year_lengths[isleap (y)]) { idays -= year_lengths[isleap (y)]; if (increment_overflow (&y, 1)) return NULL; } tmp->tm_year = y; if (increment_overflow (&tmp->tm_year, -TM_YEAR_BASE)) return NULL; tmp->tm_yday = idays; /* ** The "extra" mods below avoid overflow problems. */ tmp->tm_wday = EPOCH_WDAY + ((y - EPOCH_YEAR) % DAYSPERWEEK) * (DAYSPERNYEAR % DAYSPERWEEK) + leaps_thru_end_of (y - 1) - leaps_thru_end_of (EPOCH_YEAR - 1) + idays; tmp->tm_wday %= DAYSPERWEEK; if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; tmp->tm_hour = (int64_t) (rem / SECSPERHOUR); rem %= SECSPERHOUR; tmp->tm_min = (int64_t) (rem / SECSPERMIN); /* ** A positive leap second requires a special ** representation. This uses "... ??:59:60" et seq. */ tmp->tm_sec = (int64_t) (rem % SECSPERMIN) + hit; ip = mon_lengths + (isleap (y) ? 1 : 0); tmp->tm_mon = 0; while (idays >= (*ip)[tmp->tm_mon]) { idays -= (*ip)[tmp->tm_mon++]; BSON_ASSERT (tmp->tm_mon < MONSPERYEAR); } tmp->tm_mday = (int64_t) (idays + 1); tmp->tm_isdst = 0; #ifdef TM_GMTOFF tmp->TM_GMTOFF = offset; #endif /* defined TM_GMTOFF */ return tmp; } /* ** Adapted from code provided by Robert Elz, who writes: ** The "best" way to do mktime I think is based on an idea of Bob ** Kridle's (so its said...) from a long time ago. ** It does a binary search of the int64_t space. Since int64_t's are ** just 32 bits, its a max of 32 iterations (even at 64 bits it ** would still be very reasonable). */ #ifndef WRONG #define WRONG (-1) #endif /* !defined WRONG */ /* ** Normalize logic courtesy Paul Eggert. */ static int64_t increment_overflow (int64_t *const ip, int64_t j) { int64_t const i = *ip; /* ** If i >= 0 there can only be overflow if i + j > INT_MAX ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow. ** If i < 0 there can only be overflow if i + j < INT_MIN ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow. */ if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i)) return true; *ip += j; return false; } static int64_t increment_overflow32 (int_fast32_t *const lp, int64_t const m) { int_fast32_t const l = *lp; if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) return true; *lp += (int_fast32_t) m; return false; } static int64_t normalize_overflow (int64_t *const tensptr, int64_t *const unitsptr, const int64_t base) { int64_t tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); *unitsptr -= tensdelta * base; return increment_overflow (tensptr, tensdelta); } static int64_t normalize_overflow32 (int_fast32_t *const tensptr, int64_t *const unitsptr, const int64_t base) { int64_t tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); *unitsptr -= tensdelta * base; return increment_overflow32 (tensptr, tensdelta); } static int64_t tmcomp (const struct bson_tm *const atmp, const struct bson_tm *const btmp) { int64_t result; if (atmp->tm_year != btmp->tm_year) return atmp->tm_year < btmp->tm_year ? -1 : 1; if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 && (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && (result = (atmp->tm_min - btmp->tm_min)) == 0) result = atmp->tm_sec - btmp->tm_sec; return result; } static int64_t time2sub (struct bson_tm *const tmp, struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), const int_fast32_t offset, int64_t *const okayp, const int64_t do_norm_secs) { const struct state *sp; int64_t dir; int64_t i, j; int64_t saved_seconds; int_fast32_t li; int64_t lo; int64_t hi; int_fast32_t y; int64_t newt; int64_t t; struct bson_tm yourtm, mytm; *okayp = false; yourtm = *tmp; if (do_norm_secs) { if (normalize_overflow (&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) return WRONG; } if (normalize_overflow (&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) return WRONG; if (normalize_overflow (&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) return WRONG; y = (int_fast32_t) yourtm.tm_year; if (normalize_overflow32 (&y, &yourtm.tm_mon, MONSPERYEAR)) return WRONG; /* ** Turn y into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ if (increment_overflow32 (&y, TM_YEAR_BASE)) return WRONG; while (yourtm.tm_mday <= 0) { if (increment_overflow32 (&y, -1)) return WRONG; li = y + (1 < yourtm.tm_mon); yourtm.tm_mday += year_lengths[isleap (li)]; } while (yourtm.tm_mday > DAYSPERLYEAR) { li = y + (1 < yourtm.tm_mon); yourtm.tm_mday -= year_lengths[isleap (li)]; if (increment_overflow32 (&y, 1)) return WRONG; } for (;;) { i = mon_lengths[isleap (y)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) break; yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; if (increment_overflow32 (&y, 1)) return WRONG; } } if (increment_overflow32 (&y, -TM_YEAR_BASE)) return WRONG; yourtm.tm_year = y; if (yourtm.tm_year != y) return WRONG; if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) saved_seconds = 0; else if (y + TM_YEAR_BASE < EPOCH_YEAR) { /* ** We can't set tm_sec to 0, because that might push the ** time below the minimum representable time. ** Set tm_sec to 59 instead. ** This assumes that the minimum representable time is ** not in the same minute that a leap second was deleted from, ** which is a safer assumption than using 58 would be. */ if (increment_overflow (&yourtm.tm_sec, 1 - SECSPERMIN)) return WRONG; saved_seconds = yourtm.tm_sec; yourtm.tm_sec = SECSPERMIN - 1; } else { saved_seconds = yourtm.tm_sec; yourtm.tm_sec = 0; } /* ** Do a binary search. */ lo = INT64_MIN; hi = INT64_MAX; for (;;) { t = lo / 2 + hi / 2; if (t < lo) t = lo; else if (t > hi) t = hi; if ((*funcp) (&t, offset, &mytm) == NULL) { /* ** Assume that t is too extreme to be represented in ** a struct bson_tm; arrange things so that it is less ** extreme on the next pass. */ dir = (t > 0) ? 1 : -1; } else dir = tmcomp (&mytm, &yourtm); if (dir != 0) { if (t == lo) { if (t == time_t_max) return WRONG; ++t; ++lo; } else if (t == hi) { if (t == time_t_min) return WRONG; --t; --hi; } if (lo > hi) return WRONG; if (dir > 0) hi = t; else lo = t; continue; } if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) break; /* ** Right time, wrong type. ** Hunt for right time, right type. ** It's okay to guess wrong since the guess ** gets checked. */ sp = (const struct state *) gmtptr; if (sp == NULL) return WRONG; for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; for (j = sp->typecnt - 1; j >= 0; --j) { if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) continue; newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; if ((*funcp) (&newt, offset, &mytm) == NULL) continue; if (tmcomp (&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) continue; /* ** We have a match. */ t = newt; goto label; } } return WRONG; } label: newt = t + saved_seconds; if ((newt < t) != (saved_seconds < 0)) return WRONG; t = newt; if ((*funcp) (&t, offset, tmp)) *okayp = true; return t; } static int64_t time2 (struct bson_tm *const tmp, struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), const int_fast32_t offset, int64_t *const okayp) { int64_t t; /* ** First try without normalization of seconds ** (in case tm_sec contains a value associated with a leap second). ** If that fails, try with normalization of seconds. */ t = time2sub (tmp, funcp, offset, okayp, false); return *okayp ? t : time2sub (tmp, funcp, offset, okayp, true); } static int64_t time1 (struct bson_tm *const tmp, struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), const int_fast32_t offset) { int64_t t; const struct state *sp; int64_t samei, otheri; int64_t sameind, otherind; int64_t i; int64_t nseen; int64_t seen[TZ_MAX_TYPES]; int64_t types[TZ_MAX_TYPES]; int64_t okay; if (tmp == NULL) { errno = EINVAL; return WRONG; } if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2 (tmp, funcp, offset, &okay); if (okay) return t; if (tmp->tm_isdst < 0) #ifdef PCTS /* ** POSIX Conformance Test Suite code courtesy Grant Sullivan. */ tmp->tm_isdst = 0; /* reset to std and try again */ #else return t; #endif /* !defined PCTS */ /* ** We're supposed to assume that somebody took a time of one type ** and did some math on it that yielded a "struct tm" that's bad. ** We try to divine the type they started from and adjust to the ** type they need. */ sp = (const struct state *) gmtptr; if (sp == NULL) return WRONG; for (i = 0; i < sp->typecnt; ++i) seen[i] = false; nseen = 0; for (i = sp->timecnt - 1; i >= 0; --i) if (!seen[sp->types[i]]) { seen[sp->types[i]] = true; types[nseen++] = sp->types[i]; } for (sameind = 0; sameind < nseen; ++sameind) { samei = types[sameind]; if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; for (otherind = 0; otherind < nseen; ++otherind) { otheri = types[otherind]; if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) continue; tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; t = time2 (tmp, funcp, offset, &okay); if (okay) return t; tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; } } return WRONG; } int64_t _bson_timegm (struct bson_tm *const tmp) { if (tmp != NULL) tmp->tm_isdst = 0; return time1 (tmp, gmtsub, 0L); } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-types.h0000644000175100001660000004034214760300420021123 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_TYPES_H #define BSON_TYPES_H #include #include #include #include #include #include BSON_BEGIN_DECLS /* *-------------------------------------------------------------------------- * * bson_unichar_t -- * * bson_unichar_t provides an unsigned 32-bit type for containing * unicode characters. When iterating UTF-8 sequences, this should * be used to avoid losing the high-bits of non-ascii characters. * * See also: * bson_string_append_unichar() * *-------------------------------------------------------------------------- */ typedef uint32_t bson_unichar_t; /** * @brief Flags configuring the creation of a bson_context_t */ typedef enum { /** Use default options */ BSON_CONTEXT_NONE = 0, /* Deprecated: Generating new OIDs from a bson_context_t is always thread-safe */ BSON_CONTEXT_THREAD_SAFE = (1 << 0), /* Deprecated: Does nothing and is ignored */ BSON_CONTEXT_DISABLE_HOST_CACHE = (1 << 1), /* Call getpid() instead of remembering the result of getpid() when using the context */ BSON_CONTEXT_DISABLE_PID_CACHE = (1 << 2), /* Deprecated: Does nothing */ BSON_CONTEXT_USE_TASK_ID = (1 << 3), } bson_context_flags_t; /** * bson_context_t: * * This structure manages context for the bson library. It handles * configuration for thread-safety and other performance related requirements. * Consumers will create a context and may use multiple under a variety of * situations. * * If your program calls fork(), you should initialize a new bson_context_t * using bson_context_init(). * * If you are using threading, it is suggested that you use a bson_context_t * per thread for best performance. Alternatively, you can initialize the * bson_context_t with BSON_CONTEXT_THREAD_SAFE, although a performance penalty * will be incurred. * * Many functions will require that you provide a bson_context_t such as OID * generation. * * This structure is opaque in that you cannot see the contents of the * structure. However, it is stack allocatable in that enough padding is * provided in _bson_context_t to hold the structure. */ typedef struct _bson_context_t bson_context_t; /** * bson_json_opts_t: * * This structure is used to pass options for serializing BSON into extended * JSON to the respective serialization methods. * * max_len can be either a non-negative integer, or BSON_MAX_LEN_UNLIMITED to * set no limit for serialization length. */ typedef struct _bson_json_opts_t bson_json_opts_t; /** * bson_t: * * This structure manages a buffer whose contents are a properly formatted * BSON document. You may perform various transforms on the BSON documents. * Additionally, it can be iterated over using bson_iter_t. * * See bson_iter_init() for iterating the contents of a bson_t. * * When building a bson_t structure using the various append functions, * memory allocations may occur. That is performed using power of two * allocations and realloc(). * * See http://bsonspec.org for the BSON document spec. * * This structure is meant to fit in two sequential 64-byte cachelines. */ #ifdef BSON_MEMCHECK BSON_ALIGNED_BEGIN (128) typedef struct _bson_t { uint32_t flags; /* Internal flags for the bson_t. */ uint32_t len; /* Length of BSON data. */ char *canary; /* For leak checks. */ uint8_t padding[120 - sizeof (char *)]; } bson_t BSON_ALIGNED_END (128); #else BSON_ALIGNED_BEGIN (128) typedef struct _bson_t { uint32_t flags; /* Internal flags for the bson_t. */ uint32_t len; /* Length of BSON data. */ uint8_t padding[120]; /* Padding for stack allocation. */ } bson_t BSON_ALIGNED_END (128); #endif /** * BSON_INITIALIZER: * * This macro can be used to initialize a #bson_t structure on the stack * without calling bson_init(). * * |[ * bson_t b = BSON_INITIALIZER; * ]| */ #ifdef BSON_MEMCHECK #define BSON_INITIALIZER \ { \ 3, 5, bson_malloc (1), {5}, \ } #else #define BSON_INITIALIZER \ { \ 3, 5, \ { \ 5 \ } \ } #endif BSON_STATIC_ASSERT2 (bson_t, sizeof (bson_t) == 128); /** * bson_oid_t: * * This structure contains the binary form of a BSON Object Id as specified * on http://bsonspec.org. If you would like the bson_oid_t in string form * see bson_oid_to_string() or bson_oid_to_string_r(). */ typedef struct { uint8_t bytes[12]; } bson_oid_t; BSON_STATIC_ASSERT2 (oid_t, sizeof (bson_oid_t) == 12); /** * bson_decimal128_t: * * @high The high-order bytes of the decimal128. This field contains sign, * combination bits, exponent, and part of the coefficient continuation. * @low The low-order bytes of the decimal128. This field contains the second * part of the coefficient continuation. * * This structure is a boxed type containing the value for the BSON decimal128 * type. The structure stores the 128 bits such that they correspond to the * native format for the IEEE decimal128 type, if it is implemented. **/ typedef struct { #if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN uint64_t low; uint64_t high; #elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN uint64_t high; uint64_t low; #endif } bson_decimal128_t; /** * bson_validate_flags_t: * * This enumeration is used for validation of BSON documents. It allows * selective control on what you wish to validate. * * %BSON_VALIDATE_NONE: No additional validation occurs. * %BSON_VALIDATE_UTF8: Check that strings are valid UTF-8. * %BSON_VALIDATE_DOLLAR_KEYS: Check that keys do not start with $. * %BSON_VALIDATE_DOT_KEYS: Check that keys do not contain a period. * %BSON_VALIDATE_UTF8_ALLOW_NULL: Allow NUL bytes in UTF-8 text. * %BSON_VALIDATE_EMPTY_KEYS: Prohibit zero-length field names */ typedef enum { BSON_VALIDATE_NONE = 0, BSON_VALIDATE_UTF8 = (1 << 0), BSON_VALIDATE_DOLLAR_KEYS = (1 << 1), BSON_VALIDATE_DOT_KEYS = (1 << 2), BSON_VALIDATE_UTF8_ALLOW_NULL = (1 << 3), BSON_VALIDATE_EMPTY_KEYS = (1 << 4), } bson_validate_flags_t; /** * bson_type_t: * * This enumeration contains all of the possible types within a BSON document. * Use bson_iter_type() to fetch the type of a field while iterating over it. */ typedef enum { BSON_TYPE_EOD = 0x00, BSON_TYPE_DOUBLE = 0x01, BSON_TYPE_UTF8 = 0x02, BSON_TYPE_DOCUMENT = 0x03, BSON_TYPE_ARRAY = 0x04, BSON_TYPE_BINARY = 0x05, BSON_TYPE_UNDEFINED = 0x06, BSON_TYPE_OID = 0x07, BSON_TYPE_BOOL = 0x08, BSON_TYPE_DATE_TIME = 0x09, BSON_TYPE_NULL = 0x0A, BSON_TYPE_REGEX = 0x0B, BSON_TYPE_DBPOINTER = 0x0C, BSON_TYPE_CODE = 0x0D, BSON_TYPE_SYMBOL = 0x0E, BSON_TYPE_CODEWSCOPE = 0x0F, BSON_TYPE_INT32 = 0x10, BSON_TYPE_TIMESTAMP = 0x11, BSON_TYPE_INT64 = 0x12, BSON_TYPE_DECIMAL128 = 0x13, BSON_TYPE_MAXKEY = 0x7F, BSON_TYPE_MINKEY = 0xFF, } bson_type_t; /** * bson_subtype_t: * * This enumeration contains the various subtypes that may be used in a binary * field. See http://bsonspec.org for more information. */ typedef enum { BSON_SUBTYPE_BINARY = 0x00, BSON_SUBTYPE_FUNCTION = 0x01, BSON_SUBTYPE_BINARY_DEPRECATED = 0x02, BSON_SUBTYPE_UUID_DEPRECATED = 0x03, BSON_SUBTYPE_UUID = 0x04, BSON_SUBTYPE_MD5 = 0x05, BSON_SUBTYPE_ENCRYPTED = 0x06, BSON_SUBTYPE_COLUMN = 0x07, BSON_SUBTYPE_SENSITIVE = 0x08, BSON_SUBTYPE_USER = 0x80, } bson_subtype_t; /* *-------------------------------------------------------------------------- * * bson_value_t -- * * A boxed type to contain various bson_type_t types. * * See also: * bson_value_copy() * bson_value_destroy() * *-------------------------------------------------------------------------- */ BSON_ALIGNED_BEGIN (8) typedef struct _bson_value_t { bson_type_t value_type; int32_t padding; union { bson_oid_t v_oid; int64_t v_int64; int32_t v_int32; int8_t v_int8; double v_double; bool v_bool; int64_t v_datetime; struct { uint32_t timestamp; uint32_t increment; } v_timestamp; struct { char *str; uint32_t len; } v_utf8; struct { uint8_t *data; uint32_t data_len; } v_doc; struct { uint8_t *data; uint32_t data_len; bson_subtype_t subtype; } v_binary; struct { char *regex; char *options; } v_regex; struct { char *collection; uint32_t collection_len; bson_oid_t oid; } v_dbpointer; struct { char *code; uint32_t code_len; } v_code; struct { char *code; uint8_t *scope_data; uint32_t code_len; uint32_t scope_len; } v_codewscope; struct { char *symbol; uint32_t len; } v_symbol; bson_decimal128_t v_decimal128; } value; } bson_value_t BSON_ALIGNED_END (8); /** * bson_iter_t: * * This structure manages iteration over a bson_t structure. It keeps track * of the location of the current key and value within the buffer. Using the * various functions to get the value of the iter will read from these * locations. * * This structure is safe to discard on the stack. No cleanup is necessary * after using it. */ BSON_ALIGNED_BEGIN (128) typedef struct { const uint8_t *raw; /* The raw buffer being iterated. */ uint32_t len; /* The length of raw. */ uint32_t off; /* The offset within the buffer. */ uint32_t type; /* The offset of the type byte. */ uint32_t key; /* The offset of the key byte. */ uint32_t d1; /* The offset of the first data byte. */ uint32_t d2; /* The offset of the second data byte. */ uint32_t d3; /* The offset of the third data byte. */ uint32_t d4; /* The offset of the fourth data byte. */ uint32_t next_off; /* The offset of the next field. */ uint32_t err_off; /* The offset of the error. */ bson_value_t value; /* Internal value for various state. */ } bson_iter_t BSON_ALIGNED_END (128); /** * bson_reader_t: * * This structure is used to iterate over a sequence of BSON documents. It * allows for them to be iterated with the possibility of no additional * memory allocations under certain circumstances such as reading from an * incoming mongo packet. */ BSON_ALIGNED_BEGIN (BSON_ALIGN_OF_PTR) typedef struct { uint32_t type; /**< private >**/ } bson_reader_t BSON_ALIGNED_END (BSON_ALIGN_OF_PTR); /** * bson_visitor_t: * * This structure contains a series of pointers that can be executed for * each field of a BSON document based on the field type. * * For example, if an int32 field is found, visit_int32 will be called. * * When visiting each field using bson_iter_visit_all(), you may provide a * data pointer that will be provided with each callback. This might be useful * if you are marshaling to another language. * * You may pre-maturely stop the visitation of fields by returning true in your * visitor. Returning false will continue visitation to further fields. */ BSON_ALIGNED_BEGIN (8) typedef struct { /* run before / after descending into a document */ bool (*visit_before) (const bson_iter_t *iter, const char *key, void *data); bool (*visit_after) (const bson_iter_t *iter, const char *key, void *data); /* corrupt BSON, or unsupported type and visit_unsupported_type not set */ void (*visit_corrupt) (const bson_iter_t *iter, void *data); /* normal bson field callbacks */ bool (*visit_double) (const bson_iter_t *iter, const char *key, double v_double, void *data); bool (*visit_utf8) (const bson_iter_t *iter, const char *key, size_t v_utf8_len, const char *v_utf8, void *data); bool (*visit_document) (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data); bool (*visit_array) (const bson_iter_t *iter, const char *key, const bson_t *v_array, void *data); bool (*visit_binary) (const bson_iter_t *iter, const char *key, bson_subtype_t v_subtype, size_t v_binary_len, const uint8_t *v_binary, void *data); /* normal field with deprecated "Undefined" BSON type */ bool (*visit_undefined) (const bson_iter_t *iter, const char *key, void *data); bool (*visit_oid) (const bson_iter_t *iter, const char *key, const bson_oid_t *v_oid, void *data); bool (*visit_bool) (const bson_iter_t *iter, const char *key, bool v_bool, void *data); bool (*visit_date_time) (const bson_iter_t *iter, const char *key, int64_t msec_since_epoch, void *data); bool (*visit_null) (const bson_iter_t *iter, const char *key, void *data); bool (*visit_regex) ( const bson_iter_t *iter, const char *key, const char *v_regex, const char *v_options, void *data); bool (*visit_dbpointer) (const bson_iter_t *iter, const char *key, size_t v_collection_len, const char *v_collection, const bson_oid_t *v_oid, void *data); bool (*visit_code) (const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, void *data); bool (*visit_symbol) ( const bson_iter_t *iter, const char *key, size_t v_symbol_len, const char *v_symbol, void *data); bool (*visit_codewscope) (const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, const bson_t *v_scope, void *data); bool (*visit_int32) (const bson_iter_t *iter, const char *key, int32_t v_int32, void *data); bool (*visit_timestamp) ( const bson_iter_t *iter, const char *key, uint32_t v_timestamp, uint32_t v_increment, void *data); bool (*visit_int64) (const bson_iter_t *iter, const char *key, int64_t v_int64, void *data); bool (*visit_maxkey) (const bson_iter_t *iter, const char *key, void *data); bool (*visit_minkey) (const bson_iter_t *iter, const char *key, void *data); /* if set, called instead of visit_corrupt when an apparently valid BSON * includes an unrecognized field type (reading future version of BSON) */ void (*visit_unsupported_type) (const bson_iter_t *iter, const char *key, uint32_t type_code, void *data); bool (*visit_decimal128) (const bson_iter_t *iter, const char *key, const bson_decimal128_t *v_decimal128, void *data); void *padding[7]; } bson_visitor_t BSON_ALIGNED_END (8); #define BSON_ERROR_BUFFER_SIZE 504 BSON_ALIGNED_BEGIN (8) typedef struct _bson_error_t { uint32_t domain; uint32_t code; char message[BSON_ERROR_BUFFER_SIZE]; } bson_error_t BSON_ALIGNED_END (8); BSON_STATIC_ASSERT2 (error_t, sizeof (bson_error_t) == 512); /** * bson_next_power_of_two: * @v: A 32-bit unsigned integer of required bytes. * * Determines the next larger power of two for the value of @v * in a constant number of operations. * * It is up to the caller to guarantee this will not overflow. * * Returns: The next power of 2 from @v. */ static BSON_INLINE size_t bson_next_power_of_two (size_t v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; #if BSON_WORD_SIZE == 64 v |= v >> 32; #endif v++; return v; } static BSON_INLINE bool bson_is_power_of_two (uint32_t v) { return ((v != 0) && ((v & (v - 1)) == 0)); } BSON_END_DECLS #endif /* BSON_TYPES_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-utf8.c0000644000175100001660000002272614760300420020646 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include /* *-------------------------------------------------------------------------- * * bson_utf8_validate -- * * Validates that @utf8 is a valid UTF-8 string. Note that we only * support UTF-8 characters which have sequence length less than or equal * to 4 bytes (RFC 3629). * * If @allow_null is true, then \0 is allowed within @utf8_len bytes * of @utf8. Generally, this is bad practice since the main point of * UTF-8 strings is that they can be used with strlen() and friends. * However, some languages such as Python can send UTF-8 encoded * strings with NUL's in them. * * Note that the two-byte sequence "C0 80" is also interpreted as an * internal NUL, for historical reasons. This sequence is considered * invalid according to RFC3629. * * Parameters: * @utf8: A UTF-8 encoded string. * @utf8_len: The length of @utf8 in bytes. * @allow_null: If the single "00" byte or two-byte sequence "C0 80" are allowed internally within @utf8. * * Returns: * true if @utf8 is valid UTF-8. otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_utf8_validate (const char *utf8, /* IN */ size_t utf8_len, /* IN */ bool allow_null) /* IN */ { bson_unichar_t c; uint8_t first_mask; uint8_t seq_length; size_t i; size_t j; BSON_ASSERT (utf8); for (i = 0; i < utf8_len; i += seq_length) { mcommon_utf8_get_sequence (&utf8[i], &seq_length, &first_mask); /* * Ensure we have a valid multi-byte sequence length. */ if (!seq_length) { return false; } /* * Ensure we have enough bytes left. */ if ((utf8_len - i) < seq_length) { return false; } /* * Also calculate the next char as a unichar so we can * check code ranges for non-shortest form. */ c = utf8[i] & first_mask; /* * Check the high-bits for each additional sequence byte. */ for (j = i + 1; j < (i + seq_length); j++) { c = (c << 6) | (utf8[j] & 0x3F); if ((utf8[j] & 0xC0) != 0x80) { return false; } } /* * Check for NULL bytes afterwards. * * Hint: if you want to optimize this function, starting here to do * this in the same pass as the data above would probably be a good * idea. You would add a branch into the inner loop, but save possibly * on cache-line bouncing on larger strings. Just a thought. */ if (!allow_null) { for (j = 0; j < seq_length; j++) { if (((i + j) > utf8_len) || !utf8[i + j]) { return false; } } } /* * Code point won't fit in utf-16, not allowed. */ if (c > 0x0010FFFF) { return false; } /* * Byte is in reserved range for UTF-16 high-marks * for surrogate pairs. */ if ((c & 0xFFFFF800) == 0xD800) { return false; } /* * Check non-shortest form unicode. */ switch (seq_length) { case 1: if (c <= 0x007F) { continue; } return false; case 2: if ((c >= 0x0080) && (c <= 0x07FF)) { continue; } else if (c == 0) { /* Two-byte representation for NULL. */ if (!allow_null) { return false; } continue; } return false; case 3: if (((c >= 0x0800) && (c <= 0x0FFF)) || ((c >= 0x1000) && (c <= 0xFFFF))) { continue; } return false; case 4: if (((c >= 0x10000) && (c <= 0x3FFFF)) || ((c >= 0x40000) && (c <= 0xFFFFF)) || ((c >= 0x100000) && (c <= 0x10FFFF))) { continue; } return false; default: return false; } } return true; } /* *-------------------------------------------------------------------------- * * bson_utf8_escape_for_json -- * * Allocates a new string matching @utf8 except that special * characters in JSON will be escaped. The resulting string is also * UTF-8 encoded. * * Both " and \ characters will be escaped. Additionally, if a NUL * byte is found before @utf8_len bytes, it will be converted to the * two byte UTF-8 sequence. * * The two-byte sequence "C0 80" is also interpreted as an internal NUL, * for historical reasons. This sequence is considered invalid according * to RFC3629. * * Parameters: * @utf8: A UTF-8 encoded string. * @utf8_len: The length of @utf8 in bytes or -1 if NUL terminated. * * Returns: * A newly allocated string that should be freed with bson_free(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * bson_utf8_escape_for_json (const char *utf8, /* IN */ ssize_t utf8_len) /* IN */ { uint32_t len32; bool allow_nul; if (utf8_len < 0) { size_t sizet_len = strlen (utf8); if (sizet_len < UINT32_MAX) { len32 = (uint32_t) sizet_len; allow_nul = false; } else { return NULL; } } else { if (mcommon_in_range_signed (uint32_t, utf8_len) && (uint32_t) utf8_len < UINT32_MAX) { len32 = utf8_len; allow_nul = true; } else { return NULL; } } /* The new private implementation of mcommon_json_append_escaped() avoids * parsing UTF-8 sequences at all in most cases. It preserves the validity * of valid sequences, but it will not catch most UTF-8 errors. For compatibility * at the expense of performance, we emulate the old behavior in this wrapper. */ if (!bson_utf8_validate (utf8, (size_t) len32, allow_nul)) { return NULL; } mcommon_string_append_t append; mcommon_string_new_with_capacity_as_append (&append, len32); if (mcommon_json_append_escaped (&append, utf8, len32, allow_nul)) { return mcommon_string_from_append_destroy_with_steal (&append); } else { mcommon_string_from_append_destroy (&append); return NULL; } } /* *-------------------------------------------------------------------------- * * bson_utf8_get_char -- * * Fetches the next UTF-8 character from the UTF-8 sequence. * * Parameters: * @utf8: A string containing validated UTF-8. * * Returns: * A 32-bit bson_unichar_t reprsenting the multi-byte sequence. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bson_unichar_t bson_utf8_get_char (const char *utf8) /* IN */ { bson_unichar_t c; uint8_t mask; uint8_t num; int i; BSON_ASSERT (utf8); mcommon_utf8_get_sequence (utf8, &num, &mask); c = (*utf8) & mask; for (i = 1; i < num; i++) { c = (c << 6) | (utf8[i] & 0x3F); } return c; } /* *-------------------------------------------------------------------------- * * bson_utf8_next_char -- * * Returns an incremented pointer to the beginning of the next * multi-byte sequence in @utf8. * * Parameters: * @utf8: A string containing validated UTF-8. * * Returns: * An incremented pointer in @utf8. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const char * bson_utf8_next_char (const char *utf8) /* IN */ { uint8_t mask; uint8_t num; BSON_ASSERT (utf8); mcommon_utf8_get_sequence (utf8, &num, &mask); return utf8 + num; } /* *-------------------------------------------------------------------------- * * bson_utf8_from_unichar -- * * Converts the unichar to a sequence of utf8 bytes and stores those * in @utf8. The number of bytes in the sequence are stored in @len. * * Parameters: * @unichar: A bson_unichar_t. * @utf8: A location for the multi-byte sequence. * @len: A location for number of bytes stored in @utf8. * * Returns: * None. * * Side effects: * @utf8 is set. * @len is set. * *-------------------------------------------------------------------------- */ void bson_utf8_from_unichar (bson_unichar_t unichar, /* IN */ char utf8[BSON_ENSURE_ARRAY_PARAM_SIZE (6)], /* OUT */ uint32_t *len) /* OUT */ { // Inlined implementation from common-utf8-private mcommon_utf8_from_unichar (unichar, utf8, len); } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-utf8.h0000644000175100001660000000227414760300420020647 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_UTF8_H #define BSON_UTF8_H #include #include BSON_BEGIN_DECLS BSON_EXPORT (bool) bson_utf8_validate (const char *utf8, size_t utf8_len, bool allow_null); BSON_EXPORT (char *) bson_utf8_escape_for_json (const char *utf8, ssize_t utf8_len); BSON_EXPORT (bson_unichar_t) bson_utf8_get_char (const char *utf8); BSON_EXPORT (const char *) bson_utf8_next_char (const char *utf8); BSON_EXPORT (void) bson_utf8_from_unichar (bson_unichar_t unichar, char utf8[6], uint32_t *len); BSON_END_DECLS #endif /* BSON_UTF8_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-value.c0000644000175100001660000001707514760300420021075 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include void bson_value_copy (const bson_value_t *src, /* IN */ bson_value_t *dst) /* OUT */ { BSON_ASSERT (src); BSON_ASSERT (dst); dst->value_type = src->value_type; switch (src->value_type) { case BSON_TYPE_DOUBLE: dst->value.v_double = src->value.v_double; break; case BSON_TYPE_UTF8: BSON_ASSERT (mcommon_in_range_size_t_unsigned (src->value.v_utf8.len)); size_t utf8_len_sz = (size_t) src->value.v_utf8.len; if (utf8_len_sz == SIZE_MAX) { // If the string is at maximum length, do not NULL terminate. The source necessarily cannot fit it. dst->value.v_utf8.len = src->value.v_utf8.len; dst->value.v_utf8.str = bson_malloc (utf8_len_sz); memcpy (dst->value.v_utf8.str, src->value.v_utf8.str, dst->value.v_utf8.len); } else { // There is room in destination to NULL terminate. dst->value.v_utf8.len = src->value.v_utf8.len; dst->value.v_utf8.str = bson_malloc (utf8_len_sz + 1); memcpy (dst->value.v_utf8.str, src->value.v_utf8.str, dst->value.v_utf8.len); dst->value.v_utf8.str[dst->value.v_utf8.len] = '\0'; } break; case BSON_TYPE_DOCUMENT: case BSON_TYPE_ARRAY: dst->value.v_doc.data_len = src->value.v_doc.data_len; dst->value.v_doc.data = bson_malloc (src->value.v_doc.data_len); memcpy (dst->value.v_doc.data, src->value.v_doc.data, dst->value.v_doc.data_len); break; case BSON_TYPE_BINARY: dst->value.v_binary.subtype = src->value.v_binary.subtype; dst->value.v_binary.data_len = src->value.v_binary.data_len; dst->value.v_binary.data = bson_malloc (src->value.v_binary.data_len); if (dst->value.v_binary.data_len) { memcpy (dst->value.v_binary.data, src->value.v_binary.data, dst->value.v_binary.data_len); } break; case BSON_TYPE_OID: bson_oid_copy (&src->value.v_oid, &dst->value.v_oid); break; case BSON_TYPE_BOOL: dst->value.v_bool = src->value.v_bool; break; case BSON_TYPE_DATE_TIME: dst->value.v_datetime = src->value.v_datetime; break; case BSON_TYPE_REGEX: dst->value.v_regex.regex = bson_strdup (src->value.v_regex.regex); dst->value.v_regex.options = bson_strdup (src->value.v_regex.options); break; case BSON_TYPE_DBPOINTER: BSON_ASSERT (mcommon_in_range_size_t_unsigned (src->value.v_dbpointer.collection_len)); size_t dbpointer_len_sz = (size_t) src->value.v_dbpointer.collection_len; BSON_ASSERT (dbpointer_len_sz <= SIZE_MAX - 1); dst->value.v_dbpointer.collection_len = src->value.v_dbpointer.collection_len; dst->value.v_dbpointer.collection = bson_malloc (dbpointer_len_sz + 1); memcpy ( dst->value.v_dbpointer.collection, src->value.v_dbpointer.collection, dst->value.v_dbpointer.collection_len); dst->value.v_dbpointer.collection[dst->value.v_dbpointer.collection_len] = '\0'; bson_oid_copy (&src->value.v_dbpointer.oid, &dst->value.v_dbpointer.oid); break; case BSON_TYPE_CODE: BSON_ASSERT (mcommon_in_range_size_t_unsigned (src->value.v_code.code_len)); size_t code_len_sz = (size_t) src->value.v_code.code_len; BSON_ASSERT (code_len_sz <= SIZE_MAX - 1); dst->value.v_code.code_len = src->value.v_code.code_len; dst->value.v_code.code = bson_malloc (code_len_sz + 1); memcpy (dst->value.v_code.code, src->value.v_code.code, dst->value.v_code.code_len); dst->value.v_code.code[dst->value.v_code.code_len] = '\0'; break; case BSON_TYPE_SYMBOL: BSON_ASSERT (mcommon_in_range_size_t_unsigned (src->value.v_symbol.len)); size_t symbol_len_sz = (size_t) src->value.v_symbol.len; BSON_ASSERT (symbol_len_sz <= SIZE_MAX - 1); dst->value.v_symbol.len = src->value.v_symbol.len; dst->value.v_symbol.symbol = bson_malloc (symbol_len_sz + 1); memcpy (dst->value.v_symbol.symbol, src->value.v_symbol.symbol, dst->value.v_symbol.len); dst->value.v_symbol.symbol[dst->value.v_symbol.len] = '\0'; break; case BSON_TYPE_CODEWSCOPE: BSON_ASSERT (mcommon_in_range_size_t_unsigned (src->value.v_codewscope.code_len)); size_t codewscope_len_sz = (size_t) src->value.v_codewscope.code_len; BSON_ASSERT (codewscope_len_sz <= SIZE_MAX - 1); dst->value.v_codewscope.code_len = src->value.v_codewscope.code_len; dst->value.v_codewscope.code = bson_malloc (codewscope_len_sz + 1); memcpy (dst->value.v_codewscope.code, src->value.v_codewscope.code, dst->value.v_codewscope.code_len); dst->value.v_codewscope.code[dst->value.v_codewscope.code_len] = '\0'; dst->value.v_codewscope.scope_len = src->value.v_codewscope.scope_len; dst->value.v_codewscope.scope_data = bson_malloc (src->value.v_codewscope.scope_len); memcpy ( dst->value.v_codewscope.scope_data, src->value.v_codewscope.scope_data, dst->value.v_codewscope.scope_len); break; case BSON_TYPE_INT32: dst->value.v_int32 = src->value.v_int32; break; case BSON_TYPE_TIMESTAMP: dst->value.v_timestamp.timestamp = src->value.v_timestamp.timestamp; dst->value.v_timestamp.increment = src->value.v_timestamp.increment; break; case BSON_TYPE_INT64: dst->value.v_int64 = src->value.v_int64; break; case BSON_TYPE_DECIMAL128: dst->value.v_decimal128 = src->value.v_decimal128; break; case BSON_TYPE_UNDEFINED: case BSON_TYPE_NULL: case BSON_TYPE_MAXKEY: case BSON_TYPE_MINKEY: break; case BSON_TYPE_EOD: default: BSON_ASSERT (false); return; } } void bson_value_destroy (bson_value_t *value) /* IN */ { if (!value) { return; } switch (value->value_type) { case BSON_TYPE_UTF8: bson_free (value->value.v_utf8.str); break; case BSON_TYPE_DOCUMENT: case BSON_TYPE_ARRAY: bson_free (value->value.v_doc.data); break; case BSON_TYPE_BINARY: bson_free (value->value.v_binary.data); break; case BSON_TYPE_REGEX: bson_free (value->value.v_regex.regex); bson_free (value->value.v_regex.options); break; case BSON_TYPE_DBPOINTER: bson_free (value->value.v_dbpointer.collection); break; case BSON_TYPE_CODE: bson_free (value->value.v_code.code); break; case BSON_TYPE_SYMBOL: bson_free (value->value.v_symbol.symbol); break; case BSON_TYPE_CODEWSCOPE: bson_free (value->value.v_codewscope.code); bson_free (value->value.v_codewscope.scope_data); break; case BSON_TYPE_DOUBLE: case BSON_TYPE_UNDEFINED: case BSON_TYPE_OID: case BSON_TYPE_BOOL: case BSON_TYPE_DATE_TIME: case BSON_TYPE_NULL: case BSON_TYPE_INT32: case BSON_TYPE_TIMESTAMP: case BSON_TYPE_INT64: case BSON_TYPE_DECIMAL128: case BSON_TYPE_MAXKEY: case BSON_TYPE_MINKEY: case BSON_TYPE_EOD: default: break; } } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-value.h0000644000175100001660000000166414760300420021077 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_VALUE_H #define BSON_VALUE_H #include #include BSON_BEGIN_DECLS BSON_EXPORT (void) bson_value_copy (const bson_value_t *src, bson_value_t *dst); BSON_EXPORT (void) bson_value_destroy (bson_value_t *value); BSON_END_DECLS #endif /* BSON_VALUE_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-version-functions.c0000644000175100001660000000321014760300420023436 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include /** * bson_get_major_version: * * Helper function to return the runtime major version of the library. */ int bson_get_major_version (void) { return BSON_MAJOR_VERSION; } /** * bson_get_minor_version: * * Helper function to return the runtime minor version of the library. */ int bson_get_minor_version (void) { return BSON_MINOR_VERSION; } /** * bson_get_micro_version: * * Helper function to return the runtime micro version of the library. */ int bson_get_micro_version (void) { return BSON_MICRO_VERSION; } /** * bson_get_version: * * Helper function to return the runtime string version of the library. */ const char * bson_get_version (void) { return BSON_VERSION_S; } /** * bson_check_version: * * True if libmongoc's version is greater than or equal to the required * version. */ bool bson_check_version (int required_major, int required_minor, int required_micro) { return BSON_CHECK_VERSION (required_major, required_minor, required_micro); } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-version-functions.h0000644000175100001660000000212314760300420023445 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_VERSION_FUNCTIONS_H #define BSON_VERSION_FUNCTIONS_H #include BSON_BEGIN_DECLS BSON_EXPORT (int) bson_get_major_version (void); BSON_EXPORT (int) bson_get_minor_version (void); BSON_EXPORT (int) bson_get_micro_version (void); BSON_EXPORT (const char *) bson_get_version (void); BSON_EXPORT (bool) bson_check_version (int required_major, int required_minor, int required_micro); BSON_END_DECLS #endif /* BSON_VERSION_FUNCTIONS_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-version.h0000644000175100001660000000457714760300420021456 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) #error "Only can be included directly." #endif // clang-format off #ifndef BSON_VERSION_H #define BSON_VERSION_H /** * BSON_MAJOR_VERSION: * * BSON major version component (e.g. 1 if %BSON_VERSION is 1.2.3) */ #define BSON_MAJOR_VERSION (1) /** * BSON_MINOR_VERSION: * * BSON minor version component (e.g. 2 if %BSON_VERSION is 1.2.3) */ #define BSON_MINOR_VERSION (30) /** * BSON_MICRO_VERSION: * * BSON micro version component (e.g. 3 if %BSON_VERSION is 1.2.3) */ #define BSON_MICRO_VERSION (1) /** * BSON_PRERELEASE_VERSION: * * BSON prerelease version component (e.g. pre if %BSON_VERSION is 1.2.3-pre) */ #define BSON_PRERELEASE_VERSION () /** * BSON_VERSION: * * BSON version. */ #define BSON_VERSION (1.30.1) /** * BSON_VERSION_S: * * BSON version, encoded as a string, useful for printing and * concatenation. */ #define BSON_VERSION_S "1.30.1" /** * BSON_VERSION_HEX: * * BSON version, encoded as an hexadecimal number, useful for * integer comparisons. */ #define BSON_VERSION_HEX (BSON_MAJOR_VERSION << 24 | \ BSON_MINOR_VERSION << 16 | \ BSON_MICRO_VERSION << 8) /** * BSON_CHECK_VERSION: * @major: required major version * @minor: required minor version * @micro: required micro version * * Compile-time version checking. Evaluates to %TRUE if the version * of BSON is greater than or equal to the required one. */ #define BSON_CHECK_VERSION(major,minor,micro) \ (BSON_MAJOR_VERSION > (major) || \ (BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION > (minor)) || \ (BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION == (minor) && \ BSON_MICRO_VERSION >= (micro))) #endif /* BSON_VERSION_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-version.h.in0000644000175100001660000000477414760300420022062 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) #error "Only can be included directly." #endif // clang-format off #ifndef BSON_VERSION_H #define BSON_VERSION_H /** * BSON_MAJOR_VERSION: * * BSON major version component (e.g. 1 if %BSON_VERSION is 1.2.3) */ #define BSON_MAJOR_VERSION (@libbson_VERSION_MAJOR@) /** * BSON_MINOR_VERSION: * * BSON minor version component (e.g. 2 if %BSON_VERSION is 1.2.3) */ #define BSON_MINOR_VERSION (@libbson_VERSION_MINOR@) /** * BSON_MICRO_VERSION: * * BSON micro version component (e.g. 3 if %BSON_VERSION is 1.2.3) */ #define BSON_MICRO_VERSION (@libbson_VERSION_PATCH@) /** * BSON_PRERELEASE_VERSION: * * BSON prerelease version component (e.g. pre if %BSON_VERSION is 1.2.3-pre) */ #define BSON_PRERELEASE_VERSION (@libbson_VERSION_PRERELEASE@) /** * BSON_VERSION: * * BSON version. */ #define BSON_VERSION (@libbson_VERSION_FULL@) /** * BSON_VERSION_S: * * BSON version, encoded as a string, useful for printing and * concatenation. */ #define BSON_VERSION_S "@libbson_VERSION_FULL@" /** * BSON_VERSION_HEX: * * BSON version, encoded as an hexadecimal number, useful for * integer comparisons. */ #define BSON_VERSION_HEX (BSON_MAJOR_VERSION << 24 | \ BSON_MINOR_VERSION << 16 | \ BSON_MICRO_VERSION << 8) /** * BSON_CHECK_VERSION: * @major: required major version * @minor: required minor version * @micro: required micro version * * Compile-time version checking. Evaluates to %TRUE if the version * of BSON is greater than or equal to the required one. */ #define BSON_CHECK_VERSION(major,minor,micro) \ (BSON_MAJOR_VERSION > (major) || \ (BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION > (minor)) || \ (BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION == (minor) && \ BSON_MICRO_VERSION >= (micro))) #endif /* BSON_VERSION_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-writer.c0000644000175100001660000001531514760300420021270 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include struct _bson_writer_t { bool ready; uint8_t **buf; size_t *buflen; size_t offset; bson_realloc_func realloc_func; void *realloc_func_ctx; bson_t b; }; /* *-------------------------------------------------------------------------- * * bson_writer_new -- * * Creates a new instance of bson_writer_t using the buffer, length, * offset, and realloc() function supplied. * * The caller is expected to clean up the structure when finished * using bson_writer_destroy(). * * Parameters: * @buf: (inout): A pointer to a target buffer. * @buflen: (inout): A pointer to the buffer length. * @offset: The offset in the target buffer to start from. * @realloc_func: A realloc() style function or NULL. * * Returns: * A newly allocated bson_writer_t that should be freed with * bson_writer_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ bson_writer_t * bson_writer_new (uint8_t **buf, /* IN */ size_t *buflen, /* IN */ size_t offset, /* IN */ bson_realloc_func realloc_func, /* IN */ void *realloc_func_ctx) /* IN */ { bson_writer_t *writer; writer = BSON_ALIGNED_ALLOC0 (bson_writer_t); writer->buf = buf; writer->buflen = buflen; writer->offset = offset; writer->realloc_func = realloc_func; writer->realloc_func_ctx = realloc_func_ctx; writer->ready = true; return writer; } /* *-------------------------------------------------------------------------- * * bson_writer_destroy -- * * Cleanup after @writer and release any allocated memory. Note that * the buffer supplied to bson_writer_new() is NOT freed from this * method. The caller is responsible for that. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_writer_destroy (bson_writer_t *writer) /* IN */ { bson_free (writer); } /* *-------------------------------------------------------------------------- * * bson_writer_get_length -- * * Fetches the current length of the content written by the buffer * (including the initial offset). This includes a partly written * document currently being written. * * This is useful if you want to check to see if you've passed a given * memory boundary that cannot be sent in a packet. See * bson_writer_rollback() to abort the current document being written. * * Returns: * The number of bytes written plus initial offset. * * Side effects: * None. * *-------------------------------------------------------------------------- */ size_t bson_writer_get_length (bson_writer_t *writer) /* IN */ { return writer->offset + writer->b.len; } /* *-------------------------------------------------------------------------- * * bson_writer_begin -- * * Begins writing a new document. The caller may use the bson * structure to write out a new BSON document. When completed, the * caller must call either bson_writer_end() or * bson_writer_rollback(). * * Parameters: * @writer: A bson_writer_t. * @bson: (out): A location for a bson_t*. * * Returns: * true if the underlying realloc was successful; otherwise false. * * Side effects: * @bson is initialized if true is returned. * *-------------------------------------------------------------------------- */ bool bson_writer_begin (bson_writer_t *writer, /* IN */ bson_t **bson) /* OUT */ { bson_impl_alloc_t *b; bool grown = false; BSON_ASSERT (writer); BSON_ASSERT (writer->ready); BSON_ASSERT (bson); writer->ready = false; memset (&writer->b, 0, sizeof (bson_t)); b = (bson_impl_alloc_t *) &writer->b; b->flags = BSON_FLAG_STATIC | BSON_FLAG_NO_FREE; b->len = 5; b->parent = NULL; b->buf = writer->buf; b->buflen = writer->buflen; b->offset = writer->offset; b->alloc = NULL; b->alloclen = 0; b->realloc = writer->realloc_func; b->realloc_func_ctx = writer->realloc_func_ctx; while ((writer->offset + writer->b.len) > *writer->buflen) { if (!writer->realloc_func) { memset (&writer->b, 0, sizeof (bson_t)); writer->ready = true; return false; } grown = true; if (!*writer->buflen) { *writer->buflen = 64; } else { (*writer->buflen) *= 2; } } if (grown) { *writer->buf = writer->realloc_func (*writer->buf, *writer->buflen, writer->realloc_func_ctx); } memset ((*writer->buf) + writer->offset + 1, 0, 5); (*writer->buf)[writer->offset] = 5; *bson = &writer->b; return true; } /* *-------------------------------------------------------------------------- * * bson_writer_end -- * * Complete writing of a bson_writer_t to the buffer supplied. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_writer_end (bson_writer_t *writer) /* IN */ { BSON_ASSERT (writer); BSON_ASSERT (!writer->ready); writer->offset += writer->b.len; memset (&writer->b, 0, sizeof (bson_t)); writer->ready = true; } /* *-------------------------------------------------------------------------- * * bson_writer_rollback -- * * Abort the appending of the current bson_t to the memory region * managed by @writer. This is useful if you detected that you went * past a particular memory limit. For example, MongoDB has 48MB * message limits. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void bson_writer_rollback (bson_writer_t *writer) /* IN */ { BSON_ASSERT (writer); if (writer->b.len) { memset (&writer->b, 0, sizeof (bson_t)); } writer->ready = true; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson-writer.h0000644000175100001660000000330014760300420021264 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef BSON_WRITER_H #define BSON_WRITER_H #include BSON_BEGIN_DECLS /** * bson_writer_t: * * The bson_writer_t structure is a helper for writing a series of BSON * documents to a single malloc() buffer. You can provide a realloc() style * function to grow the buffer as you go. * * This is useful if you want to build a series of BSON documents right into * the target buffer for an outgoing packet. The offset parameter allows you to * start at an offset of the target buffer. */ typedef struct _bson_writer_t bson_writer_t; BSON_EXPORT (bson_writer_t *) bson_writer_new (uint8_t **buf, size_t *buflen, size_t offset, bson_realloc_func realloc_func, void *realloc_func_ctx); BSON_EXPORT (void) bson_writer_destroy (bson_writer_t *writer); BSON_EXPORT (size_t) bson_writer_get_length (bson_writer_t *writer); BSON_EXPORT (bool) bson_writer_begin (bson_writer_t *writer, bson_t **bson); BSON_EXPORT (void) bson_writer_end (bson_writer_t *writer); BSON_EXPORT (void) bson_writer_rollback (bson_writer_t *writer); BSON_END_DECLS #endif /* BSON_WRITER_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson.c0000644000175100001660000024040114760300420017752 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #ifdef BSON_MEMCHECK #pragma message( \ "Do not define BSON_MEMCHECK. BSON_MEMCHECK changes the data layout of bson_t. BSON_MEMCHECK is deprecated may be removed in a future major release") #endif typedef enum { BSON_VALIDATE_PHASE_START, BSON_VALIDATE_PHASE_TOP, BSON_VALIDATE_PHASE_LF_REF_KEY, BSON_VALIDATE_PHASE_LF_REF_UTF8, BSON_VALIDATE_PHASE_LF_ID_KEY, BSON_VALIDATE_PHASE_LF_DB_KEY, BSON_VALIDATE_PHASE_LF_DB_UTF8, BSON_VALIDATE_PHASE_NOT_DBREF, } bson_validate_phase_t; /* * Structures. */ typedef struct { bson_validate_flags_t flags; ssize_t err_offset; bson_validate_phase_t phase; bson_error_t error; } bson_validate_state_t; /* * Globals. */ static const uint8_t gZero; /* *-------------------------------------------------------------------------- * * _bson_impl_inline_grow -- * * Document growth implementation for documents that currently * contain stack based buffers. The document may be switched to * a malloc based buffer. * * Returns: * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ size_t size) /* IN */ { bson_impl_alloc_t *alloc = (bson_impl_alloc_t *) impl; uint8_t *data; size_t req; if (((size_t) impl->len + size) <= sizeof impl->data) { return true; } req = bson_next_power_of_two (impl->len + size); if (req <= BSON_MAX_SIZE) { data = bson_malloc (req); memcpy (data, impl->data, impl->len); #ifdef BSON_MEMCHECK bson_free (impl->canary); #endif alloc->flags &= ~BSON_FLAG_INLINE; alloc->parent = NULL; alloc->depth = 0; alloc->buf = &alloc->alloc; alloc->buflen = &alloc->alloclen; alloc->offset = 0; alloc->alloc = data; alloc->alloclen = req; alloc->realloc = bson_realloc_ctx; alloc->realloc_func_ctx = NULL; return true; } return false; } /* *-------------------------------------------------------------------------- * * _bson_impl_alloc_grow -- * * Document growth implementation for documents containing malloc * based buffers. * * Returns: * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ size_t size) /* IN */ { size_t req; /* * Determine how many bytes we need for this document in the buffer * including necessary trailing bytes for parent documents. */ req = (impl->offset + impl->len + size + impl->depth); if (req <= *impl->buflen) { return true; } req = bson_next_power_of_two (req); if ((req <= BSON_MAX_SIZE) && impl->realloc) { *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); *impl->buflen = req; return true; } return false; } /* *-------------------------------------------------------------------------- * * _bson_grow -- * * Grows the bson_t structure to be large enough to contain @size * bytes. * * Returns: * true if successful, false if the size would overflow. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _bson_grow (bson_t *bson, /* IN */ uint32_t size) /* IN */ { if ((bson->flags & BSON_FLAG_INLINE)) { return _bson_impl_inline_grow ((bson_impl_inline_t *) bson, size); } return _bson_impl_alloc_grow ((bson_impl_alloc_t *) bson, size); } /* *-------------------------------------------------------------------------- * * _bson_data -- * * A helper function to return the contents of the bson document * taking into account the polymorphic nature of bson_t. * * Returns: * A buffer which should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static BSON_INLINE uint8_t * _bson_data (const bson_t *bson) /* IN */ { if ((bson->flags & BSON_FLAG_INLINE)) { return ((bson_impl_inline_t *) bson)->data; } else { bson_impl_alloc_t *impl = (bson_impl_alloc_t *) bson; return (*impl->buf) + impl->offset; } } /* *-------------------------------------------------------------------------- * * _bson_encode_length -- * * Helper to encode the length of the bson_t in the first 4 bytes * of the bson document. Little endian format is used as specified * by bsonspec. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static BSON_INLINE void _bson_encode_length (bson_t *bson) /* IN */ { #if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN memcpy (_bson_data (bson), &bson->len, sizeof (bson->len)); #else uint32_t length_le = BSON_UINT32_TO_LE (bson->len); memcpy (_bson_data (bson), &length_le, sizeof (length_le)); #endif } typedef struct _bson_append_bytes_arg { const uint8_t *bytes; // Not null. uint32_t length; // > 0. } _bson_append_bytes_arg; typedef struct _bson_append_bytes_list { _bson_append_bytes_arg args[8]; // Arbitrary length: just needs to be large enough. _bson_append_bytes_arg *current; // "Insert"/"End" pointer. uint32_t n_bytes; // Total bytes to be appended. } _bson_append_bytes_list; // To support unchecked cast from non-negative `int` to `size_t`. BSON_STATIC_ASSERT2 (size_t_gte_int, SIZE_MAX >= INT_MAX); // To support unchecked cast from `uint32_t` to `size_t`. BSON_STATIC_ASSERT2 (size_t_gte_uint32_t, SIZE_MAX >= UINT32_MAX); // Declare local state with the identifier `ident`. #define BSON_APPEND_BYTES_LIST_DECLARE(ident) \ _bson_append_bytes_list ident = {.current = (ident).args, .n_bytes = 0u}; \ ((void) 0) // Add a bytes+length pair only if `_length > 0`. // Append failure if `n_bytes` will exceed BSON max size. #define BSON_APPEND_BYTES_ADD_ARGUMENT(_list, _bytes, _length) \ if (BSON_UNLIKELY ((_length) > BSON_MAX_SIZE - (_list).n_bytes)) { \ goto append_failure; \ } else if ((_length) > 0) { \ *(_list).current++ = (_bson_append_bytes_arg){ \ .bytes = (const uint8_t *) (_bytes), \ .length = (_length), \ }; \ (_list).n_bytes += (_length); \ } else \ ((void) 0) // Add a UTF-8 string only if no embedded null bytes are present. // Uses `strlen (_key)` when `_key_len < 0`, otherwise uses `_key_len`. #define BSON_APPEND_BYTES_ADD_CHECKED_STRING(_list, _key, _key_len) \ uint32_t BSON_CONCAT (key_ulen_, __LINE__); \ if ((_key_len) < 0) { \ const size_t key_zulen = strlen ((_key)); \ if (BSON_UNLIKELY (key_zulen > UINT32_MAX)) { \ goto append_failure; \ } \ BSON_CONCAT (key_ulen_, __LINE__) = (uint32_t) key_zulen; \ } else { \ const size_t key_zulen = (size_t) (_key_len); \ if (BSON_UNLIKELY (key_zulen > UINT32_MAX)) { \ goto append_failure; \ } /* Necessary to validate embedded NULL is not present in key. */ \ else if (memchr ((_key), '\0', key_zulen) != NULL) { \ goto append_failure; \ } else { \ BSON_CONCAT (key_ulen_, __LINE__) = (uint32_t) key_zulen; \ } \ } \ BSON_APPEND_BYTES_ADD_ARGUMENT ((_list), (_key), BSON_CONCAT (key_ulen_, __LINE__)) // Apply the list of arguments to be appended to `_bson`. // Append failure if adding `_list.n_bytes` will exceed BSON max size. #define BSON_APPEND_BYTES_APPLY_ARGUMENTS(_bson, _list) \ if (BSON_UNLIKELY ((_list).n_bytes > BSON_MAX_SIZE - (_bson)->len)) { \ goto append_failure; \ } else if (BSON_UNLIKELY (!_bson_grow ((_bson), (_list).n_bytes))) { \ goto append_failure; \ } else { \ uint8_t *data = _bson_data ((_bson)) + ((_bson)->len - 1u); \ for (const _bson_append_bytes_arg *arg = (_list).args; arg != (_list).current; ++arg) { \ memcpy (data, arg->bytes, arg->length); \ (_bson)->len += arg->length; \ data += arg->length; \ } \ _bson_encode_length ((_bson)); \ data[0] = '\0'; \ } \ ((void) 0) /* *-------------------------------------------------------------------------- * * _bson_append_bson_begin -- * * Begin appending a subdocument or subarray to the document using * the key provided by @key. * * If @key_length is < 0, then strlen() will be called on @key * to determine the length. * * @key_type MUST be either BSON_TYPE_DOCUMENT or BSON_TYPE_ARRAY. * * Returns: * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. * * Side effects: * @child is initialized if true is returned. * *-------------------------------------------------------------------------- */ static bool _bson_append_bson_begin (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ bson_type_t child_type, /* IN */ bson_t *child) /* OUT */ { BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (child); BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY)); BSON_ASSERT (!(bson->flags & BSON_FLAG_IN_CHILD)); BSON_ASSERT ((child_type == BSON_TYPE_DOCUMENT) || (child_type == BSON_TYPE_ARRAY)); { BSON_APPEND_BYTES_LIST_DECLARE (args); const uint8_t type = (uint8_t) child_type; BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); /* * If the parent is an inline bson_t, then we need to convert * it to a heap allocated buffer. This makes extending buffers * of child bson documents much simpler logic, as they can just * realloc the *buf pointer. */ if ((bson->flags & BSON_FLAG_INLINE)) { BSON_ASSERT (bson->len <= 120); if (!_bson_grow (bson, 128 - bson->len)) { return false; } BSON_ASSERT (!(bson->flags & BSON_FLAG_INLINE)); } const uint8_t empty[5] = {5}; BSON_APPEND_BYTES_ADD_ARGUMENT (args, &empty, sizeof (empty)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); goto append_success; append_failure: return false; } append_success: ((void) 0); bson_impl_alloc_t *aparent = (bson_impl_alloc_t *) bson; bson_impl_alloc_t *achild = (bson_impl_alloc_t *) child; /* * Mark the document as working on a child document so that no * further modifications can happen until the caller has called * bson_append_{document,array}_end(). */ bson->flags |= BSON_FLAG_IN_CHILD; /* * Initialize the child bson_t structure and point it at the parents * buffers. This allows us to realloc directly from the child without * walking up to the parent bson_t. */ achild->flags = (BSON_FLAG_CHILD | BSON_FLAG_NO_FREE | BSON_FLAG_STATIC); if ((bson->flags & BSON_FLAG_CHILD)) { achild->depth = ((bson_impl_alloc_t *) bson)->depth + 1; } else { achild->depth = 1; } achild->parent = bson; achild->buf = aparent->buf; achild->buflen = aparent->buflen; achild->offset = aparent->offset + aparent->len - 1 - 5; achild->len = 5; achild->alloc = NULL; achild->alloclen = 0; achild->realloc = aparent->realloc; achild->realloc_func_ctx = aparent->realloc_func_ctx; return true; } /* *-------------------------------------------------------------------------- * * _bson_append_bson_end -- * * Complete a call to _bson_append_bson_begin. * * Returns: * true if successful. * * Side effects: * @child is destroyed and no longer valid after calling this * function. * *-------------------------------------------------------------------------- */ static bool _bson_append_bson_end (bson_t *bson, /* IN */ bson_t *child) /* IN */ { BSON_ASSERT (bson); BSON_ASSERT ((bson->flags & BSON_FLAG_IN_CHILD)); BSON_ASSERT (!(child->flags & BSON_FLAG_IN_CHILD)); /* * Unmark the IN_CHILD flag. */ bson->flags &= ~BSON_FLAG_IN_CHILD; /* * Now that we are done building the sub-document, add the size to the * parent, not including the default 5 byte empty document already added. */ bson->len = (bson->len + child->len - 5); /* * Ensure we have a \0 byte at the end and proper length encoded at * the beginning of the document. */ _bson_data (bson)[bson->len - 1] = '\0'; _bson_encode_length (bson); return true; } /* *-------------------------------------------------------------------------- * * bson_append_array_begin -- * * Start appending a new array. * * Use @child to append to the data area for the given field. * * It is a programming error to call any other bson function on * @bson until bson_append_array_end() has been called. It is * valid to call bson_append*() functions on @child. * * This function is useful to allow building nested documents using * a single buffer owned by the top-level bson document. * * Returns: * true if successful; otherwise false and @child is invalid. * * Side effects: * @child is initialized if true is returned. * *-------------------------------------------------------------------------- */ bool bson_append_array_begin (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ bson_t *child) /* IN */ { BSON_ASSERT (bson); BSON_ASSERT (key); BSON_ASSERT (child); return _bson_append_bson_begin (bson, key, key_length, BSON_TYPE_ARRAY, child); } /* *-------------------------------------------------------------------------- * * bson_append_array_end -- * * Complete a call to bson_append_array_begin(). * * It is safe to append other fields to @bson after calling this * function. * * Returns: * true if successful. * * Side effects: * @child is invalid after calling this function. * *-------------------------------------------------------------------------- */ bool bson_append_array_end (bson_t *bson, /* IN */ bson_t *child) /* IN */ { BSON_ASSERT (bson); BSON_ASSERT (child); return _bson_append_bson_end (bson, child); } /* *-------------------------------------------------------------------------- * * bson_append_document_begin -- * * Start appending a new document. * * Use @child to append to the data area for the given field. * * It is a programming error to call any other bson function on * @bson until bson_append_document_end() has been called. It is * valid to call bson_append*() functions on @child. * * This function is useful to allow building nested documents using * a single buffer owned by the top-level bson document. * * Returns: * true if successful; otherwise false and @child is invalid. * * Side effects: * @child is initialized if true is returned. * *-------------------------------------------------------------------------- */ bool bson_append_document_begin (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ bson_t *child) /* IN */ { BSON_ASSERT (bson); BSON_ASSERT (key); BSON_ASSERT (child); return _bson_append_bson_begin (bson, key, key_length, BSON_TYPE_DOCUMENT, child); } /* *-------------------------------------------------------------------------- * * bson_append_document_end -- * * Complete a call to bson_append_document_begin(). * * It is safe to append new fields to @bson after calling this * function, if true is returned. * * Returns: * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. * * Side effects: * @child is destroyed and invalid after calling this function. * *-------------------------------------------------------------------------- */ bool bson_append_document_end (bson_t *bson, /* IN */ bson_t *child) /* IN */ { BSON_ASSERT (bson); BSON_ASSERT (child); return _bson_append_bson_end (bson, child); } /* *-------------------------------------------------------------------------- * * bson_append_array -- * * Append an array to @bson. * * Generally, bson_append_array_begin() will result in faster code * since few buffers need to be malloced. * * Returns: * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_append_array (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ const bson_t *array) /* IN */ { static const uint8_t type = BSON_TYPE_ARRAY; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (array); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); /* * Let's be a bit pedantic and ensure the array has properly formatted key * names. We will verify this simply by checking the first element for "0" * if the array is non-empty. */ if (array && !bson_empty (array)) { bson_iter_t iter; if (bson_iter_init (&iter, array) && bson_iter_next (&iter)) { if (0 != strcmp ("0", bson_iter_key (&iter))) { fprintf (stderr, "%s(): invalid array detected. first element of array " "parameter is not \"0\".\n", BSON_FUNC); } } } BSON_APPEND_BYTES_ADD_ARGUMENT (args, _bson_data (array), array->len); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } /* *-------------------------------------------------------------------------- * * bson_append_binary -- * * Append binary data to @bson. The field will have the * BSON_TYPE_BINARY type. * * Parameters: * @subtype: the BSON Binary Subtype. See bsonspec.org for more * information. * @binary: a pointer to the raw binary data. * @length: the size of @binary in bytes. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_append_binary (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ bson_subtype_t subtype, /* IN */ const uint8_t *binary, /* IN */ uint32_t length) /* IN */ { static const uint8_t type = BSON_TYPE_BINARY; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); if (!binary && length > 0u) { return false; } BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); const uint8_t subtype_arg = (uint8_t) subtype; if (subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { if (length > UINT32_MAX - 4u) { return false; } const uint32_t length_le = BSON_UINT32_TO_LE (length + 4u); const uint32_t length_arg = BSON_UINT32_TO_LE (length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &length_le, sizeof (length_le)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &subtype_arg, sizeof (subtype_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &length_arg, sizeof (length_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, binary, length); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); } else { const uint32_t length_arg = BSON_UINT32_TO_LE (length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &length_arg, sizeof (length_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &subtype_arg, sizeof (subtype_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, binary, length); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); } return true; append_failure: return false; } /* *-------------------------------------------------------------------------- * * bson_append_bool -- * * Append a new field to @bson with the name @key. The value is * a boolean indicated by @value. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_append_bool (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ bool value) /* IN */ { static const uint8_t type = BSON_TYPE_BOOL; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); const uint8_t byte_arg = value ? 1u : 0u; BSON_APPEND_BYTES_ADD_ARGUMENT (args, &byte_arg, sizeof (byte_arg)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } /* *-------------------------------------------------------------------------- * * bson_append_code -- * * Append a new field to @bson containing javascript code. * * @javascript MUST be a zero terminated UTF-8 string. It MUST NOT * containing embedded \0 characters. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * * See also: * bson_append_code_with_scope(). * *-------------------------------------------------------------------------- */ bool bson_append_code (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ const char *javascript) /* IN */ { static const uint8_t type = BSON_TYPE_CODE; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (javascript); const size_t zulength = strlen (javascript); if (zulength > UINT32_MAX - 1u) { return false; } const uint32_t length = (uint32_t) zulength + 1u; const uint32_t length_arg = BSON_UINT32_TO_LE (length); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &length_arg, sizeof (length_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, javascript, length); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } /* *-------------------------------------------------------------------------- * * bson_append_code_with_scope -- * * Append a new field to @bson containing javascript code with * supplied scope. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_append_code_with_scope (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ const char *javascript, /* IN */ const bson_t *scope) /* IN */ { static const uint8_t type = BSON_TYPE_CODEWSCOPE; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (javascript); if (!scope) { return bson_append_code (bson, key, key_length, javascript); } const size_t zulength = strlen (javascript); if (zulength > UINT32_MAX - 1u) { return false; } const uint32_t js_length = (uint32_t) zulength + 1u; const uint32_t js_length_arg = BSON_UINT32_TO_LE (js_length); if (js_length > UINT32_MAX - scope->len) { return false; } if (js_length + scope->len > UINT32_MAX - (2u * sizeof (uint32_t))) { return false; } const uint32_t total_length = (uint32_t) (2u * sizeof (uint32_t)) + js_length + scope->len; const uint32_t total_length_arg = BSON_UINT32_TO_LE (total_length); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &total_length_arg, sizeof (total_length_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &js_length_arg, sizeof (js_length_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, javascript, js_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, _bson_data (scope), scope->len); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } /* *-------------------------------------------------------------------------- * * bson_append_dbpointer -- * * This BSON data type is DEPRECATED. * * Append a BSON dbpointer field to @bson. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool bson_append_dbpointer (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ const char *collection, /* IN */ const bson_oid_t *oid) { static const uint8_t type = BSON_TYPE_DBPOINTER; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (oid); const size_t zulength = strlen (collection); if (zulength > UINT32_MAX - 1u) { return false; } const uint32_t length = (uint32_t) zulength + 1u; const uint32_t length_arg = BSON_UINT32_TO_LE (length); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &length_arg, sizeof (length_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, collection, length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, oid->bytes, sizeof (oid->bytes)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } /* *-------------------------------------------------------------------------- * * bson_append_document -- * * Append a new field to @bson containing a BSON document. * * In general, using bson_append_document_begin() results in faster * code and less memory fragmentation. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * * See also: * bson_append_document_begin(). * *-------------------------------------------------------------------------- */ bool bson_append_document (bson_t *bson, /* IN */ const char *key, /* IN */ int key_length, /* IN */ const bson_t *value) /* IN */ { static const uint8_t type = BSON_TYPE_DOCUMENT; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (value); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, _bson_data (value), value->len); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_double (bson_t *bson, const char *key, int key_length, double value) { static const uint8_t type = BSON_TYPE_DOUBLE; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); const double value_arg = BSON_DOUBLE_TO_LE (value); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &value_arg, sizeof (value_arg)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_int32 (bson_t *bson, const char *key, int key_length, int32_t value) { static const uint8_t type = BSON_TYPE_INT32; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); const uint32_t value_arg = BSON_UINT32_TO_LE (value); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &value_arg, sizeof (value_arg)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_int64 (bson_t *bson, const char *key, int key_length, int64_t value) { static const uint8_t type = BSON_TYPE_INT64; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); const uint64_t value_arg = BSON_UINT64_TO_LE (value); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &value_arg, sizeof (value_arg)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_decimal128 (bson_t *bson, const char *key, int key_length, const bson_decimal128_t *value) { static const uint8_t type = BSON_TYPE_DECIMAL128; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); const uint64_t value_arg[] = { BSON_UINT64_TO_LE (value->low), BSON_UINT64_TO_LE (value->high), }; BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &value_arg, sizeof (value_arg)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_iter (bson_t *bson, const char *key, int key_length, const bson_iter_t *iter) { bool ret = false; BSON_ASSERT (bson); BSON_ASSERT (iter); if (!key) { key = bson_iter_key (iter); key_length = -1; } switch (bson_iter_type_unsafe (iter)) { case BSON_TYPE_EOD: return false; case BSON_TYPE_DOUBLE: ret = bson_append_double (bson, key, key_length, bson_iter_double (iter)); break; case BSON_TYPE_UTF8: { uint32_t len = 0; const char *str; str = bson_iter_utf8 (iter, &len); ret = bson_append_utf8 (bson, key, key_length, str, len); } break; case BSON_TYPE_DOCUMENT: { const uint8_t *buf = NULL; uint32_t len = 0; bson_t doc; bson_iter_document (iter, &len, &buf); if (bson_init_static (&doc, buf, len)) { ret = bson_append_document (bson, key, key_length, &doc); bson_destroy (&doc); } } break; case BSON_TYPE_ARRAY: { const uint8_t *buf = NULL; uint32_t len = 0; bson_t doc; bson_iter_array (iter, &len, &buf); if (bson_init_static (&doc, buf, len)) { ret = bson_append_array (bson, key, key_length, &doc); bson_destroy (&doc); } } break; case BSON_TYPE_BINARY: { const uint8_t *binary = NULL; bson_subtype_t subtype = BSON_SUBTYPE_BINARY; uint32_t len = 0; bson_iter_binary (iter, &subtype, &len, &binary); ret = bson_append_binary (bson, key, key_length, subtype, binary, len); } break; case BSON_TYPE_UNDEFINED: ret = bson_append_undefined (bson, key, key_length); break; case BSON_TYPE_OID: ret = bson_append_oid (bson, key, key_length, bson_iter_oid (iter)); break; case BSON_TYPE_BOOL: ret = bson_append_bool (bson, key, key_length, bson_iter_bool (iter)); break; case BSON_TYPE_DATE_TIME: ret = bson_append_date_time (bson, key, key_length, bson_iter_date_time (iter)); break; case BSON_TYPE_NULL: ret = bson_append_null (bson, key, key_length); break; case BSON_TYPE_REGEX: { const char *regex; const char *options; regex = bson_iter_regex (iter, &options); ret = bson_append_regex (bson, key, key_length, regex, options); } break; case BSON_TYPE_DBPOINTER: { const bson_oid_t *oid; uint32_t len; const char *collection; bson_iter_dbpointer (iter, &len, &collection, &oid); ret = bson_append_dbpointer (bson, key, key_length, collection, oid); } break; case BSON_TYPE_CODE: { uint32_t len; const char *code; code = bson_iter_code (iter, &len); ret = bson_append_code (bson, key, key_length, code); } break; case BSON_TYPE_SYMBOL: { uint32_t len; const char *symbol; symbol = bson_iter_symbol (iter, &len); ret = bson_append_symbol (bson, key, key_length, symbol, len); } break; case BSON_TYPE_CODEWSCOPE: { const uint8_t *scope = NULL; uint32_t scope_len = 0; uint32_t len = 0; const char *javascript = NULL; bson_t doc; javascript = bson_iter_codewscope (iter, &len, &scope_len, &scope); if (bson_init_static (&doc, scope, scope_len)) { ret = bson_append_code_with_scope (bson, key, key_length, javascript, &doc); bson_destroy (&doc); } } break; case BSON_TYPE_INT32: ret = bson_append_int32 (bson, key, key_length, bson_iter_int32 (iter)); break; case BSON_TYPE_TIMESTAMP: { uint32_t ts; uint32_t inc; bson_iter_timestamp (iter, &ts, &inc); ret = bson_append_timestamp (bson, key, key_length, ts, inc); } break; case BSON_TYPE_INT64: ret = bson_append_int64 (bson, key, key_length, bson_iter_int64 (iter)); break; case BSON_TYPE_DECIMAL128: { bson_decimal128_t dec; if (!bson_iter_decimal128 (iter, &dec)) { return false; } ret = bson_append_decimal128 (bson, key, key_length, &dec); } break; case BSON_TYPE_MAXKEY: ret = bson_append_maxkey (bson, key, key_length); break; case BSON_TYPE_MINKEY: ret = bson_append_minkey (bson, key, key_length); break; default: break; } return ret; } bool bson_append_maxkey (bson_t *bson, const char *key, int key_length) { static const uint8_t type = BSON_TYPE_MAXKEY; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_minkey (bson_t *bson, const char *key, int key_length) { static const uint8_t type = BSON_TYPE_MINKEY; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_null (bson_t *bson, const char *key, int key_length) { static const uint8_t type = BSON_TYPE_NULL; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_oid (bson_t *bson, const char *key, int key_length, const bson_oid_t *value) { static const uint8_t type = BSON_TYPE_OID; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (value); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, value->bytes, sizeof (value->bytes)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_regex (bson_t *bson, const char *key, int key_length, const char *regex, const char *options) { return bson_append_regex_w_len (bson, key, key_length, regex, -1, options); } bool bson_append_regex_w_len ( bson_t *bson, const char *key, int key_length, const char *regex, int regex_length, const char *options) { static const uint8_t type = BSON_TYPE_REGEX; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); bool ret = false; if (!regex) { regex = ""; } if (!options) { options = ""; } size_t options_len = strlen (options); mcommon_string_append_t options_sorted; mcommon_string_new_with_capacity_as_append (&options_sorted, (uint32_t) options_len); if (!mcommon_string_append_selected_chars (&options_sorted, BSON_REGEX_OPTIONS_SORTED, options, options_len)) { goto append_failure; } BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, regex, regex_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT ( args, mcommon_str_from_append (&options_sorted), 1u + mcommon_strlen_from_append (&options_sorted)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); ret = true; append_failure: mcommon_string_from_append_destroy (&options_sorted); return ret; } bool bson_append_utf8 (bson_t *bson, const char *key, int key_length, const char *value, int length) { static const uint8_t type = BSON_TYPE_UTF8; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); if (BSON_UNLIKELY (!value)) { return bson_append_null (bson, key, key_length); } size_t zulength; if (BSON_UNLIKELY (length < 0)) { zulength = strlen (value); } else { zulength = (size_t) length; } if (zulength > UINT32_MAX - 1u) { return false; } const uint32_t ulength = (uint32_t) zulength; const uint32_t ulength_arg = BSON_UINT32_TO_LE (ulength + 1u); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &ulength_arg, sizeof (ulength_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, value, ulength); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_symbol (bson_t *bson, const char *key, int key_length, const char *value, int length) { static const uint8_t type = BSON_TYPE_SYMBOL; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); if (!value) { return bson_append_null (bson, key, key_length); } size_t zulength; if (BSON_UNLIKELY (length < 0)) { zulength = strlen (value); } else { zulength = (size_t) length; } if (zulength > UINT32_MAX - 1u) { return false; } const uint32_t ulength = (uint32_t) zulength; const uint32_t ulength_arg = BSON_UINT32_TO_LE (ulength + 1u); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &ulength_arg, sizeof (ulength_arg)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, value, ulength); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_time_t (bson_t *bson, const char *key, int key_length, time_t value) { #ifdef BSON_OS_WIN32 struct timeval tv = {(long) value, 0}; #else struct timeval tv = {value, 0}; #endif BSON_ASSERT (bson); BSON_ASSERT (key); return bson_append_timeval (bson, key, key_length, &tv); } bool bson_append_timestamp (bson_t *bson, const char *key, int key_length, uint32_t timestamp, uint32_t increment) { static const uint8_t type = BSON_TYPE_TIMESTAMP; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); const uint64_t value = BSON_UINT64_TO_LE (((((uint64_t) timestamp) << 32) | ((uint64_t) increment))); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &value, sizeof (value)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_now_utc (bson_t *bson, const char *key, int key_length) { BSON_ASSERT (bson); BSON_ASSERT (key); BSON_ASSERT (key_length >= -1); return bson_append_time_t (bson, key, key_length, time (NULL)); } bool bson_append_date_time (bson_t *bson, const char *key, int key_length, int64_t value) { static const uint8_t type = BSON_TYPE_DATE_TIME; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); const uint64_t value_arg = BSON_UINT64_TO_LE (value); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &value_arg, sizeof (value_arg)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_timeval (bson_t *bson, const char *key, int key_length, struct timeval *value) { uint64_t unix_msec; BSON_ASSERT (bson); BSON_ASSERT (key); BSON_ASSERT (value); unix_msec = (((uint64_t) value->tv_sec) * 1000UL) + (value->tv_usec / 1000UL); return bson_append_date_time (bson, key, key_length, unix_msec); } bool bson_append_undefined (bson_t *bson, const char *key, int key_length) { static const uint8_t type = BSON_TYPE_UNDEFINED; BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &type, sizeof (type)); BSON_APPEND_BYTES_ADD_CHECKED_STRING (args, key, key_length); BSON_APPEND_BYTES_ADD_ARGUMENT (args, &gZero, sizeof (gZero)); BSON_APPEND_BYTES_APPLY_ARGUMENTS (bson, args); return true; append_failure: return false; } bool bson_append_value (bson_t *bson, const char *key, int key_length, const bson_value_t *value) { bson_t local; bool ret = false; BSON_ASSERT (bson); BSON_ASSERT (key); BSON_ASSERT (value); switch (value->value_type) { case BSON_TYPE_DOUBLE: ret = bson_append_double (bson, key, key_length, value->value.v_double); break; case BSON_TYPE_UTF8: ret = bson_append_utf8 (bson, key, key_length, value->value.v_utf8.str, value->value.v_utf8.len); break; case BSON_TYPE_DOCUMENT: if (bson_init_static (&local, value->value.v_doc.data, value->value.v_doc.data_len)) { ret = bson_append_document (bson, key, key_length, &local); bson_destroy (&local); } break; case BSON_TYPE_ARRAY: if (bson_init_static (&local, value->value.v_doc.data, value->value.v_doc.data_len)) { ret = bson_append_array (bson, key, key_length, &local); bson_destroy (&local); } break; case BSON_TYPE_BINARY: ret = bson_append_binary (bson, key, key_length, value->value.v_binary.subtype, value->value.v_binary.data, value->value.v_binary.data_len); break; case BSON_TYPE_UNDEFINED: ret = bson_append_undefined (bson, key, key_length); break; case BSON_TYPE_OID: ret = bson_append_oid (bson, key, key_length, &value->value.v_oid); break; case BSON_TYPE_BOOL: ret = bson_append_bool (bson, key, key_length, value->value.v_bool); break; case BSON_TYPE_DATE_TIME: ret = bson_append_date_time (bson, key, key_length, value->value.v_datetime); break; case BSON_TYPE_NULL: ret = bson_append_null (bson, key, key_length); break; case BSON_TYPE_REGEX: ret = bson_append_regex (bson, key, key_length, value->value.v_regex.regex, value->value.v_regex.options); break; case BSON_TYPE_DBPOINTER: ret = bson_append_dbpointer ( bson, key, key_length, value->value.v_dbpointer.collection, &value->value.v_dbpointer.oid); break; case BSON_TYPE_CODE: ret = bson_append_code (bson, key, key_length, value->value.v_code.code); break; case BSON_TYPE_SYMBOL: ret = bson_append_symbol (bson, key, key_length, value->value.v_symbol.symbol, value->value.v_symbol.len); break; case BSON_TYPE_CODEWSCOPE: if (bson_init_static (&local, value->value.v_codewscope.scope_data, value->value.v_codewscope.scope_len)) { ret = bson_append_code_with_scope (bson, key, key_length, value->value.v_codewscope.code, &local); bson_destroy (&local); } break; case BSON_TYPE_INT32: ret = bson_append_int32 (bson, key, key_length, value->value.v_int32); break; case BSON_TYPE_TIMESTAMP: ret = bson_append_timestamp ( bson, key, key_length, value->value.v_timestamp.timestamp, value->value.v_timestamp.increment); break; case BSON_TYPE_INT64: ret = bson_append_int64 (bson, key, key_length, value->value.v_int64); break; case BSON_TYPE_DECIMAL128: ret = bson_append_decimal128 (bson, key, key_length, &(value->value.v_decimal128)); break; case BSON_TYPE_MAXKEY: ret = bson_append_maxkey (bson, key, key_length); break; case BSON_TYPE_MINKEY: ret = bson_append_minkey (bson, key, key_length); break; case BSON_TYPE_EOD: default: break; } return ret; } void bson_init (bson_t *bson) { bson_impl_inline_t *impl = (bson_impl_inline_t *) bson; BSON_ASSERT (bson); #ifdef BSON_MEMCHECK impl->canary = bson_malloc (1); #endif impl->flags = BSON_FLAG_INLINE | BSON_FLAG_STATIC; impl->len = 5; impl->data[0] = 5; impl->data[1] = 0; impl->data[2] = 0; impl->data[3] = 0; impl->data[4] = 0; } void bson_reinit (bson_t *bson) { uint8_t *data; BSON_ASSERT (bson); data = _bson_data (bson); bson->len = 5; data[0] = 5; data[1] = 0; data[2] = 0; data[3] = 0; data[4] = 0; } bool bson_init_static (bson_t *bson, const uint8_t *data, size_t length) { bson_impl_alloc_t *impl = (bson_impl_alloc_t *) bson; uint32_t len_le; BSON_ASSERT (bson); BSON_ASSERT (data); if ((length < 5) || (length > BSON_MAX_SIZE)) { return false; } memcpy (&len_le, data, sizeof (len_le)); if ((size_t) BSON_UINT32_FROM_LE (len_le) != length) { return false; } if (data[length - 1]) { return false; } impl->flags = BSON_FLAG_STATIC | BSON_FLAG_RDONLY; impl->len = (uint32_t) length; impl->parent = NULL; impl->depth = 0; impl->buf = &impl->alloc; impl->buflen = &impl->alloclen; impl->offset = 0; impl->alloc = (uint8_t *) data; impl->alloclen = length; impl->realloc = NULL; impl->realloc_func_ctx = NULL; return true; } bson_t * bson_new (void) { bson_impl_inline_t *impl; bson_t *bson; bson = BSON_ALIGNED_ALLOC (bson_t); impl = (bson_impl_inline_t *) bson; impl->flags = BSON_FLAG_INLINE; impl->len = 5; #ifdef BSON_MEMCHECK impl->canary = bson_malloc (1); #endif impl->data[0] = 5; impl->data[1] = 0; impl->data[2] = 0; impl->data[3] = 0; impl->data[4] = 0; return bson; } bson_t * bson_sized_new (size_t size) { bson_impl_alloc_t *impl_a; bson_t *b; BSON_ASSERT (size <= BSON_MAX_SIZE); { b = BSON_ALIGNED_ALLOC (bson_t); impl_a = (bson_impl_alloc_t *) b; } if (size <= BSON_INLINE_DATA_SIZE) { bson_init (b); b->flags &= ~BSON_FLAG_STATIC; } else { impl_a->flags = BSON_FLAG_NONE; impl_a->len = 5; impl_a->parent = NULL; impl_a->depth = 0; impl_a->buf = &impl_a->alloc; impl_a->buflen = &impl_a->alloclen; impl_a->offset = 0; impl_a->alloclen = BSON_MAX (5, size); impl_a->alloc = bson_malloc (impl_a->alloclen); impl_a->alloc[0] = 5; impl_a->alloc[1] = 0; impl_a->alloc[2] = 0; impl_a->alloc[3] = 0; impl_a->alloc[4] = 0; impl_a->realloc = bson_realloc_ctx; impl_a->realloc_func_ctx = NULL; } return b; } bson_t * bson_new_from_data (const uint8_t *data, size_t length) { uint32_t len_le; bson_t *bson; BSON_ASSERT (data); if ((length < 5) || (length > BSON_MAX_SIZE) || data[length - 1]) { return NULL; } memcpy (&len_le, data, sizeof (len_le)); if (length != (size_t) BSON_UINT32_FROM_LE (len_le)) { return NULL; } bson = bson_sized_new (length); memcpy (_bson_data (bson), data, length); bson->len = (uint32_t) length; return bson; } bson_t * bson_new_from_buffer (uint8_t **buf, size_t *buf_len, bson_realloc_func realloc_func, void *realloc_func_ctx) { bson_impl_alloc_t *impl; uint32_t len_le; uint32_t length; bson_t *bson; BSON_ASSERT (buf); BSON_ASSERT (buf_len); if (!realloc_func) { realloc_func = bson_realloc_ctx; } bson = BSON_ALIGNED_ALLOC0 (bson_t); impl = (bson_impl_alloc_t *) bson; if (!*buf) { length = 5; len_le = BSON_UINT32_TO_LE (length); *buf_len = 5; *buf = realloc_func (*buf, *buf_len, realloc_func_ctx); memcpy (*buf, &len_le, sizeof (len_le)); (*buf)[4] = '\0'; } else { if ((*buf_len < 5) || (*buf_len > BSON_MAX_SIZE)) { bson_free (bson); return NULL; } memcpy (&len_le, *buf, sizeof (len_le)); length = BSON_UINT32_FROM_LE (len_le); } if ((*buf)[length - 1]) { bson_free (bson); return NULL; } impl->flags = BSON_FLAG_NO_FREE; impl->len = length; impl->buf = buf; impl->buflen = buf_len; impl->realloc = realloc_func; impl->realloc_func_ctx = realloc_func_ctx; return bson; } bson_t * bson_copy (const bson_t *bson) { const uint8_t *data; BSON_ASSERT (bson); data = _bson_data (bson); return bson_new_from_data (data, bson->len); } void bson_copy_to (const bson_t *src, bson_t *dst) { const uint8_t *data; bson_impl_alloc_t *adst; size_t len; BSON_ASSERT (src); BSON_ASSERT (dst); if ((src->flags & BSON_FLAG_INLINE)) { #ifdef BSON_MEMCHECK dst->len = src->len; dst->canary = bson_malloc (1); memcpy (dst->padding, src->padding, sizeof dst->padding); #else memcpy (dst, src, sizeof *dst); #endif dst->flags = (BSON_FLAG_STATIC | BSON_FLAG_INLINE); return; } data = _bson_data (src); len = bson_next_power_of_two ((size_t) src->len); adst = (bson_impl_alloc_t *) dst; adst->flags = BSON_FLAG_STATIC; adst->len = src->len; adst->parent = NULL; adst->depth = 0; adst->buf = &adst->alloc; adst->buflen = &adst->alloclen; adst->offset = 0; adst->alloc = bson_malloc (len); adst->alloclen = len; adst->realloc = bson_realloc_ctx; adst->realloc_func_ctx = NULL; memcpy (adst->alloc, data, src->len); } static bool should_ignore (const char *first_exclude, va_list args, const char *name) { bool ret = false; const char *exclude = first_exclude; va_list args_copy; va_copy (args_copy, args); do { if (!strcmp (name, exclude)) { ret = true; break; } } while ((exclude = va_arg (args_copy, const char *))); va_end (args_copy); return ret; } void bson_copy_to_excluding_noinit_va (const bson_t *src, bson_t *dst, const char *first_exclude, va_list args) { bson_iter_t iter; if (bson_iter_init (&iter, src)) { while (bson_iter_next (&iter)) { if (!should_ignore (first_exclude, args, bson_iter_key (&iter))) { if (!bson_append_iter (dst, NULL, 0, &iter)) { /* * This should not be able to happen since we are copying * from within a valid bson_t. */ BSON_ASSERT (false); return; } } } } } void bson_copy_to_excluding (const bson_t *src, bson_t *dst, const char *first_exclude, ...) { va_list args; BSON_ASSERT (src); BSON_ASSERT (dst); BSON_ASSERT (first_exclude); bson_init (dst); va_start (args, first_exclude); bson_copy_to_excluding_noinit_va (src, dst, first_exclude, args); va_end (args); } void bson_copy_to_excluding_noinit (const bson_t *src, bson_t *dst, const char *first_exclude, ...) { va_list args; BSON_ASSERT (src); BSON_ASSERT (dst); BSON_ASSERT (first_exclude); va_start (args, first_exclude); bson_copy_to_excluding_noinit_va (src, dst, first_exclude, args); va_end (args); } void bson_destroy (bson_t *bson) { if (!bson) { return; } if (!(bson->flags & (BSON_FLAG_RDONLY | BSON_FLAG_INLINE | BSON_FLAG_NO_FREE))) { bson_free (*((bson_impl_alloc_t *) bson)->buf); } #ifdef BSON_MEMCHECK if (bson->flags & BSON_FLAG_INLINE) { bson_free (bson->canary); } #endif if (!(bson->flags & BSON_FLAG_STATIC)) { bson_free (bson); } } uint8_t * bson_reserve_buffer (bson_t *bson, uint32_t size) { if (bson->flags & (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY)) { return NULL; } if (!_bson_grow (bson, size)) { return NULL; } if (bson->flags & BSON_FLAG_INLINE) { /* bson_grow didn't spill over */ ((bson_impl_inline_t *) bson)->len = size; } else { ((bson_impl_alloc_t *) bson)->len = size; } return _bson_data (bson); } bool bson_steal (bson_t *dst, bson_t *src) { bson_impl_inline_t *src_inline; bson_impl_inline_t *dst_inline; bson_impl_alloc_t *alloc; BSON_ASSERT (dst); BSON_ASSERT (src); bson_init (dst); if (src->flags & (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY)) { return false; } if (src->flags & BSON_FLAG_INLINE) { src_inline = (bson_impl_inline_t *) src; dst_inline = (bson_impl_inline_t *) dst; dst_inline->len = src_inline->len; memcpy (dst_inline->data, src_inline->data, sizeof src_inline->data); /* for consistency, src is always invalid after steal, even if inline */ src->len = 0; #ifdef BSON_MEMCHECK bson_free (src->canary); #endif } else { #ifdef BSON_MEMCHECK bson_free (dst->canary); #endif memcpy (dst, src, sizeof (bson_t)); alloc = (bson_impl_alloc_t *) dst; alloc->flags |= BSON_FLAG_STATIC; alloc->buf = &alloc->alloc; alloc->buflen = &alloc->alloclen; } if (!(src->flags & BSON_FLAG_STATIC)) { bson_free (src); } else { /* src is invalid after steal */ src->len = 0; } return true; } uint8_t * bson_destroy_with_steal (bson_t *bson, bool steal, uint32_t *length) { uint8_t *ret = NULL; BSON_ASSERT (bson); if (length) { *length = bson->len; } if (!steal) { bson_destroy (bson); return NULL; } if ((bson->flags & (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY))) { /* Do nothing */ } else if ((bson->flags & BSON_FLAG_INLINE)) { bson_impl_inline_t *inl; inl = (bson_impl_inline_t *) bson; ret = bson_malloc (bson->len); memcpy (ret, inl->data, bson->len); } else { bson_impl_alloc_t *alloc; alloc = (bson_impl_alloc_t *) bson; ret = *alloc->buf; *alloc->buf = NULL; } bson_destroy (bson); return ret; } const uint8_t * bson_get_data (const bson_t *bson) { BSON_ASSERT (bson); return _bson_data (bson); } uint32_t bson_count_keys (const bson_t *bson) { uint32_t count = 0; bson_iter_t iter; BSON_ASSERT (bson); if (bson_iter_init (&iter, bson)) { while (bson_iter_next (&iter)) { count++; } } return count; } bool bson_has_field (const bson_t *bson, const char *key) { bson_iter_t iter; bson_iter_t child; BSON_ASSERT (bson); BSON_ASSERT (key); if (NULL != strchr (key, '.')) { return (bson_iter_init (&iter, bson) && bson_iter_find_descendant (&iter, key, &child)); } return bson_iter_init_find (&iter, bson, key); } int bson_compare (const bson_t *bson, const bson_t *other) { const uint8_t *data1; const uint8_t *data2; size_t len1; size_t len2; int64_t ret; data1 = _bson_data (bson) + 4; len1 = bson->len - 4; data2 = _bson_data (other) + 4; len2 = other->len - 4; if (len1 == len2) { return memcmp (data1, data2, len1); } ret = memcmp (data1, data2, BSON_MIN (len1, len2)); if (ret == 0) { ret = (int64_t) len1 - (int64_t) len2; } return (ret < 0) ? -1 : (ret > 0); } bool bson_equal (const bson_t *bson, const bson_t *other) { return !bson_compare (bson, other); } char * bson_as_json_with_opts (const bson_t *bson, size_t *length, const bson_json_opts_t *opts) { BSON_ASSERT_PARAM (bson); BSON_OPTIONAL_PARAM (length); BSON_ASSERT_PARAM (opts); // Convert the API-specified max length into a literal byte count; max length is transformed from a special value // (-1) to the maximum representable size. int32_t limit_i32 = opts->max_len; uint32_t limit_u32 = 0; if (limit_i32 == BSON_MAX_LEN_UNLIMITED) { limit_u32 = UINT32_MAX - 1u; } else if (limit_i32 > 0) { limit_u32 = (uint32_t) limit_i32; } // Use the bson length as an initial buffer capacity guess mcommon_string_append_t append; mcommon_string_set_append_with_limit (mcommon_string_new_with_capacity ("", 0, bson->len), &append, limit_u32); if (opts->is_outermost_array ? mcommon_json_append_bson_array (&append, bson, opts->mode, BSON_MAX_RECURSION) : mcommon_json_append_bson_document (&append, bson, opts->mode, BSON_MAX_RECURSION)) { if (length) { *length = (size_t) mcommon_strlen_from_append (&append); } return mcommon_string_from_append_destroy_with_steal (&append); } else { if (length) { *length = 0; } mcommon_string_from_append_destroy (&append); return NULL; } } char * bson_as_canonical_extended_json (const bson_t *bson, size_t *length) { const bson_json_opts_t opts = {BSON_JSON_MODE_CANONICAL, BSON_MAX_LEN_UNLIMITED, false}; return bson_as_json_with_opts (bson, length, &opts); } char * bson_as_json (const bson_t *bson, size_t *length) { return bson_as_legacy_extended_json (bson, length); } char * bson_as_legacy_extended_json (const bson_t *bson, size_t *length) { const bson_json_opts_t opts = {BSON_JSON_MODE_LEGACY, BSON_MAX_LEN_UNLIMITED, false}; return bson_as_json_with_opts (bson, length, &opts); } char * bson_as_relaxed_extended_json (const bson_t *bson, size_t *length) { const bson_json_opts_t opts = {BSON_JSON_MODE_RELAXED, BSON_MAX_LEN_UNLIMITED, false}; return bson_as_json_with_opts (bson, length, &opts); } char * bson_array_as_json (const bson_t *bson, size_t *length) { return bson_array_as_legacy_extended_json (bson, length); } char * bson_array_as_legacy_extended_json (const bson_t *bson, size_t *length) { const bson_json_opts_t opts = {BSON_JSON_MODE_LEGACY, BSON_MAX_LEN_UNLIMITED, true}; return bson_as_json_with_opts (bson, length, &opts); } char * bson_array_as_relaxed_extended_json (const bson_t *bson, size_t *length) { const bson_json_opts_t opts = {BSON_JSON_MODE_RELAXED, BSON_MAX_LEN_UNLIMITED, true}; return bson_as_json_with_opts (bson, length, &opts); } char * bson_array_as_canonical_extended_json (const bson_t *bson, size_t *length) { const bson_json_opts_t opts = {BSON_JSON_MODE_CANONICAL, BSON_MAX_LEN_UNLIMITED, true}; return bson_as_json_with_opts (bson, length, &opts); } #define VALIDATION_ERR(_flag, _msg, ...) bson_set_error (&state->error, BSON_ERROR_INVALID, _flag, _msg, __VA_ARGS__) static bool _bson_iter_validate_utf8 (const bson_iter_t *iter, const char *key, size_t v_utf8_len, const char *v_utf8, void *data) { bson_validate_state_t *state = data; bool allow_null; if ((state->flags & BSON_VALIDATE_UTF8)) { allow_null = !!(state->flags & BSON_VALIDATE_UTF8_ALLOW_NULL); if (!bson_utf8_validate (v_utf8, v_utf8_len, allow_null)) { state->err_offset = iter->off; VALIDATION_ERR (BSON_VALIDATE_UTF8, "invalid utf8 string for key \"%s\"", key); return true; } } if ((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) { if (state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8) { state->phase = BSON_VALIDATE_PHASE_LF_ID_KEY; } else if (state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { state->phase = BSON_VALIDATE_PHASE_NOT_DBREF; } } return false; } static void _bson_iter_validate_corrupt (const bson_iter_t *iter, void *data) { bson_validate_state_t *state = data; state->err_offset = iter->err_off; VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt BSON"); } static bool _bson_iter_validate_before (const bson_iter_t *iter, const char *key, void *data) { bson_validate_state_t *state = data; if ((state->flags & BSON_VALIDATE_EMPTY_KEYS)) { if (key[0] == '\0') { state->err_offset = iter->off; VALIDATION_ERR (BSON_VALIDATE_EMPTY_KEYS, "%s", "empty key"); return true; } } if ((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) { if (key[0] == '$') { if (state->phase == BSON_VALIDATE_PHASE_LF_REF_KEY && strcmp (key, "$ref") == 0) { state->phase = BSON_VALIDATE_PHASE_LF_REF_UTF8; } else if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY && strcmp (key, "$id") == 0) { state->phase = BSON_VALIDATE_PHASE_LF_DB_KEY; } else if (state->phase == BSON_VALIDATE_PHASE_LF_DB_KEY && strcmp (key, "$db") == 0) { state->phase = BSON_VALIDATE_PHASE_LF_DB_UTF8; } else { state->err_offset = iter->off; VALIDATION_ERR (BSON_VALIDATE_DOLLAR_KEYS, "keys cannot begin with \"$\": \"%s\"", key); return true; } } else if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY || state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 || state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { state->err_offset = iter->off; VALIDATION_ERR (BSON_VALIDATE_DOLLAR_KEYS, "invalid key within DBRef subdocument: \"%s\"", key); return true; } else { state->phase = BSON_VALIDATE_PHASE_NOT_DBREF; } } if ((state->flags & BSON_VALIDATE_DOT_KEYS)) { if (strstr (key, ".")) { state->err_offset = iter->off; VALIDATION_ERR (BSON_VALIDATE_DOT_KEYS, "keys cannot contain \".\": \"%s\"", key); return true; } } return false; } static bool _bson_iter_validate_codewscope ( const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, const bson_t *v_scope, void *data) { bson_validate_state_t *state = data; size_t offset = 0; BSON_UNUSED (key); BSON_UNUSED (v_code_len); BSON_UNUSED (v_code); if (!bson_validate (v_scope, state->flags, &offset)) { state->err_offset = iter->off + offset; VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt code-with-scope"); return false; } return true; } static bool _bson_iter_validate_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data); static const bson_visitor_t bson_validate_funcs = { _bson_iter_validate_before, NULL, /* visit_after */ _bson_iter_validate_corrupt, NULL, /* visit_double */ _bson_iter_validate_utf8, _bson_iter_validate_document, _bson_iter_validate_document, /* visit_array */ NULL, /* visit_binary */ NULL, /* visit_undefined */ NULL, /* visit_oid */ NULL, /* visit_bool */ NULL, /* visit_date_time */ NULL, /* visit_null */ NULL, /* visit_regex */ NULL, /* visit_dbpoint */ NULL, /* visit_code */ NULL, /* visit_symbol */ _bson_iter_validate_codewscope, }; static bool _bson_iter_validate_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data) { bson_validate_state_t *state = data; bson_iter_t child; bson_validate_phase_t phase = state->phase; BSON_UNUSED (key); if (!bson_iter_init (&child, v_document)) { state->err_offset = iter->off; return true; } if (state->phase == BSON_VALIDATE_PHASE_START) { state->phase = BSON_VALIDATE_PHASE_TOP; } else { state->phase = BSON_VALIDATE_PHASE_LF_REF_KEY; } (void) bson_iter_visit_all (&child, &bson_validate_funcs, state); if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY || state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 || state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { if (state->err_offset <= 0) { state->err_offset = iter->off; } return true; } state->phase = phase; return false; } static void _bson_validate_internal (const bson_t *bson, bson_validate_state_t *state) { bson_iter_t iter; state->err_offset = -1; state->phase = BSON_VALIDATE_PHASE_START; memset (&state->error, 0, sizeof state->error); if (!bson_iter_init (&iter, bson)) { state->err_offset = 0; VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt BSON"); } else { _bson_iter_validate_document (&iter, NULL, bson, state); } } bool bson_validate (const bson_t *bson, bson_validate_flags_t flags, size_t *offset) { return bson_validate_with_error_and_offset (bson, flags, offset, NULL); } bool bson_validate_with_error (const bson_t *bson, bson_validate_flags_t flags, bson_error_t *error) { return bson_validate_with_error_and_offset (bson, flags, NULL, error); } bool bson_validate_with_error_and_offset (const bson_t *bson, bson_validate_flags_t flags, size_t *offset, bson_error_t *error) { bson_validate_state_t state; state.flags = flags; _bson_validate_internal (bson, &state); if (state.err_offset >= 0) { if (offset) { *offset = (size_t) state.err_offset; } if (error) { memcpy (error, &state.error, sizeof *error); } return false; } return true; } bool bson_concat (bson_t *dst, const bson_t *src) { BSON_ASSERT (dst); BSON_ASSERT (src); if (!bson_empty (src)) { BSON_APPEND_BYTES_LIST_DECLARE (args); BSON_APPEND_BYTES_ADD_ARGUMENT (args, _bson_data (src) + 4, src->len - 5u); BSON_APPEND_BYTES_APPLY_ARGUMENTS (dst, args); } return true; append_failure: return false; } struct _bson_array_builder_t { uint32_t index; bson_t bson; }; bson_array_builder_t * bson_array_builder_new (void) { bson_array_builder_t *bab = BSON_ALIGNED_ALLOC0 (bson_array_builder_t); bson_init (&bab->bson); return bab; } // `bson_array_builder_append_impl` generates the next key index, calls // `append_fn`, and may update the tracked next index. #define bson_array_builder_append_impl(append_fn, ...) \ if (1) { \ BSON_ASSERT_PARAM (bab); \ const char *key; \ char buf[16]; \ size_t key_length = bson_uint32_to_string (bab->index, &key, buf, sizeof buf); \ /* Expect enough room in `buf` for key string. UINT32_MAX is 10 digits. \ * With the NULL terminator, 11 is expected maximum number of \ * characters. */ \ BSON_ASSERT (key_length < sizeof buf); \ bool ok = append_fn (&bab->bson, key, (int) key_length, __VA_ARGS__); \ if (ok) { \ bab->index += 1; \ } \ return ok; \ } else \ (void) 0 #define bson_array_builder_append_impl_noargs(append_fn) \ if (1) { \ BSON_ASSERT_PARAM (bab); \ const char *key; \ char buf[16]; \ size_t key_length = bson_uint32_to_string (bab->index, &key, buf, sizeof buf); \ /* Expect enough room in `buf` for key string. UINT32_MAX is 10 digits. \ * With the NULL terminator, 11 is expected maximum number of \ * characters. */ \ BSON_ASSERT (key_length < sizeof buf); \ bool ok = append_fn (&bab->bson, key, (int) key_length); \ if (ok) { \ bab->index += 1; \ } \ return ok; \ } else \ (void) 0 bool bson_array_builder_append_value (bson_array_builder_t *bab, const bson_value_t *value) { bson_array_builder_append_impl (bson_append_value, value); } bool bson_array_builder_append_array (bson_array_builder_t *bab, const bson_t *array) { bson_array_builder_append_impl (bson_append_array, array); } bool bson_array_builder_append_binary (bson_array_builder_t *bab, bson_subtype_t subtype, const uint8_t *binary, uint32_t length) { bson_array_builder_append_impl (bson_append_binary, subtype, binary, length); } bool bson_array_builder_append_bool (bson_array_builder_t *bab, bool value) { bson_array_builder_append_impl (bson_append_bool, value); } bool bson_array_builder_append_code (bson_array_builder_t *bab, const char *javascript) { bson_array_builder_append_impl (bson_append_code, javascript); } bool bson_array_builder_append_code_with_scope (bson_array_builder_t *bab, const char *javascript, const bson_t *scope) { bson_array_builder_append_impl (bson_append_code_with_scope, javascript, scope); } bool bson_array_builder_append_dbpointer (bson_array_builder_t *bab, const char *collection, const bson_oid_t *oid) { bson_array_builder_append_impl (bson_append_dbpointer, collection, oid); } bool bson_array_builder_append_double (bson_array_builder_t *bab, double value) { bson_array_builder_append_impl (bson_append_double, value); } bool bson_array_builder_append_document (bson_array_builder_t *bab, const bson_t *value) { bson_array_builder_append_impl (bson_append_document, value); } bool bson_array_builder_append_document_begin (bson_array_builder_t *bab, bson_t *child) { bson_array_builder_append_impl (bson_append_document_begin, child); } bool bson_array_builder_append_document_end (bson_array_builder_t *bab, bson_t *child) { return bson_append_document_end (&bab->bson, child); } bool bson_array_builder_append_int32 (bson_array_builder_t *bab, int32_t value) { bson_array_builder_append_impl (bson_append_int32, value); } bool bson_array_builder_append_int64 (bson_array_builder_t *bab, int64_t value) { bson_array_builder_append_impl (bson_append_int64, value); } bool bson_array_builder_append_decimal128 (bson_array_builder_t *bab, const bson_decimal128_t *value) { bson_array_builder_append_impl (bson_append_decimal128, value); } bool bson_array_builder_append_iter (bson_array_builder_t *bab, const bson_iter_t *iter) { bson_array_builder_append_impl (bson_append_iter, iter); } bool bson_array_builder_append_minkey (bson_array_builder_t *bab) { bson_array_builder_append_impl_noargs (bson_append_minkey); } bool bson_array_builder_append_maxkey (bson_array_builder_t *bab) { bson_array_builder_append_impl_noargs (bson_append_maxkey); } bool bson_array_builder_append_null (bson_array_builder_t *bab) { bson_array_builder_append_impl_noargs (bson_append_null); } bool bson_array_builder_append_oid (bson_array_builder_t *bab, const bson_oid_t *oid) { bson_array_builder_append_impl (bson_append_oid, oid); } bool bson_array_builder_append_regex (bson_array_builder_t *bab, const char *regex, const char *options) { bson_array_builder_append_impl (bson_append_regex, regex, options); } bool bson_array_builder_append_regex_w_len (bson_array_builder_t *bab, const char *regex, int regex_length, const char *options) { bson_array_builder_append_impl (bson_append_regex_w_len, regex, regex_length, options); } bool bson_array_builder_append_utf8 (bson_array_builder_t *bab, const char *value, int length) { bson_array_builder_append_impl (bson_append_utf8, value, length); } bool bson_array_builder_append_symbol (bson_array_builder_t *bab, const char *value, int length) { bson_array_builder_append_impl (bson_append_symbol, value, length); } bool bson_array_builder_append_time_t (bson_array_builder_t *bab, time_t value) { bson_array_builder_append_impl (bson_append_time_t, value); } bool bson_array_builder_append_timeval (bson_array_builder_t *bab, struct timeval *value) { bson_array_builder_append_impl (bson_append_timeval, value); } bool bson_array_builder_append_date_time (bson_array_builder_t *bab, int64_t value) { bson_array_builder_append_impl (bson_append_date_time, value); } bool bson_array_builder_append_now_utc (bson_array_builder_t *bab) { bson_array_builder_append_impl_noargs (bson_append_now_utc); } bool bson_array_builder_append_timestamp (bson_array_builder_t *bab, uint32_t timestamp, uint32_t increment) { bson_array_builder_append_impl (bson_append_timestamp, timestamp, increment); } bool bson_array_builder_append_undefined (bson_array_builder_t *bab) { bson_array_builder_append_impl_noargs (bson_append_undefined); } bool bson_array_builder_append_array_builder_begin (bson_array_builder_t *bab, bson_array_builder_t **child) { bson_array_builder_append_impl (bson_append_array_builder_begin, child); } bool bson_array_builder_append_array_builder_end (bson_array_builder_t *bab, bson_array_builder_t *child) { return bson_append_array_builder_end (&bab->bson, child); } bool bson_array_builder_build (bson_array_builder_t *bab, bson_t *out) { BSON_ASSERT_PARAM (bab); BSON_ASSERT_PARAM (out); if (!bson_steal (out, &bab->bson)) { return false; } bson_init (&bab->bson); bab->index = 0; return true; } void bson_array_builder_destroy (bson_array_builder_t *bab) { if (!bab) { return; } bson_destroy (&bab->bson); bson_free (bab); } bool bson_append_array_builder_begin (bson_t *bson, const char *key, int key_length, bson_array_builder_t **child) { BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (child); *child = bson_array_builder_new (); bool ok = bson_append_array_begin (bson, key, key_length, &(*child)->bson); if (!ok) { bson_array_builder_destroy (*child); *child = NULL; } return ok; } bool bson_append_array_builder_end (bson_t *bson, bson_array_builder_t *child) { bool ok = bson_append_array_end (bson, &child->bson); bson_array_builder_destroy (child); return ok; } mongodb-1.21.0/src/libmongoc/src/libbson/src/bson/bson.h0000644000175100001660000012043014760300420017756 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifndef BSON_H #define BSON_H #define BSON_INSIDE #include #include #include #include #include #include // Deprecated. #include // Deprecated. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef BSON_INSIDE BSON_BEGIN_DECLS /** * bson_empty: * @b: a bson_t. * * Checks to see if @b is an empty BSON document. An empty BSON document is * a 5 byte document which contains the length (4 bytes) and a single NUL * byte indicating end of fields. */ #define bson_empty(b) (((b)->len == 5) || !bson_get_data ((b))[4]) /** * bson_empty0: * * Like bson_empty() but treats NULL the same as an empty bson_t document. */ #define bson_empty0(b) (!(b) || bson_empty (b)) /** * bson_clear: * * Easily free a bson document and set it to NULL. Use like: * * bson_t *doc = bson_new(); * bson_clear (&doc); * BSON_ASSERT (doc == NULL); */ #define bson_clear(bptr) \ do { \ if (*(bptr)) { \ bson_destroy (*(bptr)); \ *(bptr) = NULL; \ } \ } while (0) /** * BSON_MAX_SIZE: * * The maximum size in bytes of a BSON document. */ #define BSON_MAX_SIZE ((size_t) ((1U << 31) - 1)) #define BSON_APPEND_ARRAY(b, key, val) bson_append_array (b, key, (int) strlen (key), val) #define BSON_APPEND_ARRAY_BEGIN(b, key, child) bson_append_array_begin (b, key, (int) strlen (key), child) #define BSON_APPEND_BINARY(b, key, subtype, val, len) bson_append_binary (b, key, (int) strlen (key), subtype, val, len) #define BSON_APPEND_BOOL(b, key, val) bson_append_bool (b, key, (int) strlen (key), val) #define BSON_APPEND_CODE(b, key, val) bson_append_code (b, key, (int) strlen (key), val) #define BSON_APPEND_CODE_WITH_SCOPE(b, key, val, scope) \ bson_append_code_with_scope (b, key, (int) strlen (key), val, scope) #define BSON_APPEND_DBPOINTER(b, key, coll, oid) bson_append_dbpointer (b, key, (int) strlen (key), coll, oid) #define BSON_APPEND_DOCUMENT_BEGIN(b, key, child) bson_append_document_begin (b, key, (int) strlen (key), child) #define BSON_APPEND_DOUBLE(b, key, val) bson_append_double (b, key, (int) strlen (key), val) #define BSON_APPEND_DOCUMENT(b, key, val) bson_append_document (b, key, (int) strlen (key), val) #define BSON_APPEND_INT32(b, key, val) bson_append_int32 (b, key, (int) strlen (key), val) #define BSON_APPEND_INT64(b, key, val) bson_append_int64 (b, key, (int) strlen (key), val) #define BSON_APPEND_MINKEY(b, key) bson_append_minkey (b, key, (int) strlen (key)) #define BSON_APPEND_DECIMAL128(b, key, val) bson_append_decimal128 (b, key, (int) strlen (key), val) #define BSON_APPEND_MAXKEY(b, key) bson_append_maxkey (b, key, (int) strlen (key)) #define BSON_APPEND_NULL(b, key) bson_append_null (b, key, (int) strlen (key)) #define BSON_APPEND_OID(b, key, val) bson_append_oid (b, key, (int) strlen (key), val) #define BSON_APPEND_REGEX(b, key, val, opt) bson_append_regex (b, key, (int) strlen (key), val, opt) #define BSON_APPEND_UTF8(b, key, val) bson_append_utf8 (b, key, (int) strlen (key), val, (int) strlen (val)) #define BSON_APPEND_SYMBOL(b, key, val) bson_append_symbol (b, key, (int) strlen (key), val, (int) strlen (val)) #define BSON_APPEND_TIME_T(b, key, val) bson_append_time_t (b, key, (int) strlen (key), val) #define BSON_APPEND_TIMEVAL(b, key, val) bson_append_timeval (b, key, (int) strlen (key), val) #define BSON_APPEND_DATE_TIME(b, key, val) bson_append_date_time (b, key, (int) strlen (key), val) #define BSON_APPEND_TIMESTAMP(b, key, val, inc) bson_append_timestamp (b, key, (int) strlen (key), val, inc) #define BSON_APPEND_UNDEFINED(b, key) bson_append_undefined (b, key, (int) strlen (key)) #define BSON_APPEND_VALUE(b, key, val) bson_append_value (b, key, (int) strlen (key), (val)) /** * bson_new: * * Allocates a new bson_t structure. Call the various bson_append_*() * functions to add fields to the bson. You can iterate the bson_t at any * time using a bson_iter_t and bson_iter_init(). * * Returns: A newly allocated bson_t that should be freed with bson_destroy(). */ BSON_EXPORT (bson_t *) bson_new (void); BSON_EXPORT (bson_t *) bson_new_from_json (const uint8_t *data, ssize_t len, bson_error_t *error); BSON_EXPORT (bool) bson_init_from_json (bson_t *bson, const char *data, ssize_t len, bson_error_t *error); /** * bson_init_static: * @b: A pointer to a bson_t. * @data: The data buffer to use. * @length: The length of @data. * * Initializes a bson_t using @data and @length. This is ideal if you would * like to use a stack allocation for your bson and do not need to grow the * buffer. @data must be valid for the life of @b. * * Returns: true if initialized successfully; otherwise false. */ BSON_EXPORT (bool) bson_init_static (bson_t *b, const uint8_t *data, size_t length); /** * bson_init: * @b: A pointer to a bson_t. * * Initializes a bson_t for use. This function is useful to those that want a * stack allocated bson_t. The usefulness of a stack allocated bson_t is * marginal as the target buffer for content will still require heap * allocations. It can help reduce heap fragmentation on allocators that do * not employ SLAB/magazine semantics. * * You must call bson_destroy() with @b to release resources when you are done * using @b. */ BSON_EXPORT (void) bson_init (bson_t *b); /** * bson_reinit: * @b: (inout): A bson_t. * * This is equivalent to calling bson_destroy() and bson_init() on a #bson_t. * However, it will try to persist the existing malloc'd buffer if one exists. * This is useful in cases where you want to reduce malloc overhead while * building many documents. */ BSON_EXPORT (void) bson_reinit (bson_t *b); /** * bson_new_from_data: * @data: A buffer containing a serialized bson document. * @length: The length of the document in bytes. * * Creates a new bson_t structure using the data provided. @data should contain * at least @length bytes that can be copied into the new bson_t structure. * * Returns: A newly allocated bson_t that should be freed with bson_destroy(). * If the first four bytes (little-endian) of data do not match @length, * then NULL will be returned. */ BSON_EXPORT (bson_t *) bson_new_from_data (const uint8_t *data, size_t length); /** * bson_new_from_buffer: * @buf: A pointer to a buffer containing a serialized bson document. * @buf_len: The length of the buffer in bytes. * @realloc_fun: a realloc like function * @realloc_fun_ctx: a context for the realloc function * * Creates a new bson_t structure using the data provided. @buf should contain * a bson document, or null pointer should be passed for new allocations. * * Returns: A newly allocated bson_t that should be freed with bson_destroy(). * The underlying buffer will be used and not be freed in destroy. */ BSON_EXPORT (bson_t *) bson_new_from_buffer (uint8_t **buf, size_t *buf_len, bson_realloc_func realloc_func, void *realloc_func_ctx); /** * bson_sized_new: * @size: A size_t containing the number of bytes to allocate. * * This will allocate a new bson_t with enough bytes to hold a buffer * sized @size. @size must be smaller than INT_MAX bytes. * * Returns: A newly allocated bson_t that should be freed with bson_destroy(). */ BSON_EXPORT (bson_t *) bson_sized_new (size_t size); /** * bson_copy: * @bson: A bson_t. * * Copies @bson into a newly allocated bson_t. You must call bson_destroy() * when you are done with the resulting value to free its resources. * * Returns: A newly allocated bson_t that should be free'd with bson_destroy() */ BSON_EXPORT (bson_t *) bson_copy (const bson_t *bson); /** * bson_copy_to: * @src: The source bson_t. * @dst: The destination bson_t. * * Initializes @dst and copies the content from @src into @dst. */ BSON_EXPORT (void) bson_copy_to (const bson_t *src, bson_t *dst); /** * bson_copy_to_excluding: * @src: A bson_t. * @dst: A bson_t to initialize and copy into. * @first_exclude: First field name to exclude. * * Copies @src into @dst excluding any field that is provided. * This is handy for situations when you need to remove one or * more fields in a bson_t. Note that bson_init() will be called * on dst. */ BSON_EXPORT (void) bson_copy_to_excluding (const bson_t *src, bson_t *dst, const char *first_exclude, ...) BSON_GNUC_NULL_TERMINATED BSON_GNUC_DEPRECATED_FOR (bson_copy_to_excluding_noinit); /** * bson_copy_to_excluding_noinit: * @src: A bson_t. * @dst: A bson_t to initialize and copy into. * @first_exclude: First field name to exclude. * * The same as bson_copy_to_excluding, but does not call bson_init() * on the dst. This version should be preferred in new code, but the * old function is left for backwards compatibility. */ BSON_EXPORT (void) bson_copy_to_excluding_noinit (const bson_t *src, bson_t *dst, const char *first_exclude, ...) BSON_GNUC_NULL_TERMINATED; BSON_EXPORT (void) bson_copy_to_excluding_noinit_va (const bson_t *src, bson_t *dst, const char *first_exclude, va_list args); /** * bson_destroy: * @bson: A bson_t. * * Frees the resources associated with @bson. */ BSON_EXPORT (void) bson_destroy (bson_t *bson); BSON_EXPORT (uint8_t *) bson_reserve_buffer (bson_t *bson, uint32_t size); BSON_EXPORT (bool) bson_steal (bson_t *dst, bson_t *src); /** * bson_destroy_with_steal: * @bson: A #bson_t. * @steal: If ownership of the data buffer should be transferred to caller. * @length: (out): location for the length of the buffer. * * Destroys @bson similar to calling bson_destroy() except that the underlying * buffer will be returned and ownership transferred to the caller if @steal * is non-zero. * * If length is non-NULL, the length of @bson will be stored in @length. * * It is a programming error to call this function with any bson that has * been initialized static, or is being used to create a subdocument with * functions such as bson_append_document_begin() or bson_append_array_begin(). * * Returns: a buffer owned by the caller if @steal is true. Otherwise NULL. * If there was an error, NULL is returned. */ BSON_EXPORT (uint8_t *) bson_destroy_with_steal (bson_t *bson, bool steal, uint32_t *length); /** * bson_get_data: * @bson: A bson_t. * * Fetched the data buffer for @bson of @bson->len bytes in length. * * Returns: A buffer that should not be modified or freed. */ BSON_EXPORT (const uint8_t *) bson_get_data (const bson_t *bson); /** * bson_count_keys: * @bson: A bson_t. * * Counts the number of elements found in @bson. */ BSON_EXPORT (uint32_t) bson_count_keys (const bson_t *bson); /** * bson_has_field: * @bson: A bson_t. * @key: The key to lookup. * * Checks to see if @bson contains a field named @key. * * This function is case-sensitive. * * Returns: true if @key exists in @bson; otherwise false. */ BSON_EXPORT (bool) bson_has_field (const bson_t *bson, const char *key); /** * bson_compare: * @bson: A bson_t. * @other: A bson_t. * * Compares @bson to @other in a qsort() style comparison. * See qsort() for information on how this function works. * * Returns: Less than zero, zero, or greater than zero. */ BSON_EXPORT (int) bson_compare (const bson_t *bson, const bson_t *other); /* * bson_equal: * @bson: A bson_t. * @other: A bson_t. * * Checks to see if @bson and @other are equal. * * Returns: true if equal; otherwise false. */ BSON_EXPORT (bool) bson_equal (const bson_t *bson, const bson_t *other); /** * bson_validate: * @bson: A bson_t. * @offset: A location for the error offset. * * Validates a BSON document by walking through the document and inspecting * the fields for valid content. * * Returns: true if @bson is valid; otherwise false and @offset is set. */ BSON_EXPORT (bool) bson_validate (const bson_t *bson, bson_validate_flags_t flags, size_t *offset); /** * bson_validate_with_error: * @bson: A bson_t. * @error: A location for the error info. * * Validates a BSON document by walking through the document and inspecting * the fields for valid content. * * Returns: true if @bson is valid; otherwise false and @error is filled out. */ BSON_EXPORT (bool) bson_validate_with_error (const bson_t *bson, bson_validate_flags_t flags, bson_error_t *error); /** * bson_validate_with_error_and_offset: * @bson: A bson_t. * @offset: A location for the error offset. * @error: A location for the error info. * * Validates a BSON document by walking through the document and inspecting * the fields for valid content. * * Returns: true if @bson is valid; otherwise false, @offset is set * and @error is filled out. */ BSON_EXPORT (bool) bson_validate_with_error_and_offset (const bson_t *bson, bson_validate_flags_t flags, size_t *offset, bson_error_t *error); /** * bson_as_json_with_opts: * @bson: A bson_t. * @length: A location for the string length, or NULL. * @opts: A bson_t_json_opts_t defining options for the conversion * * Creates a new string containing @bson in the selected JSON format, * conforming to the MongoDB Extended JSON Spec: * * github.com/mongodb/specifications/blob/master/source/extended-json.rst * * The caller is responsible for freeing the resulting string. If @length is * non-NULL, then the length of the resulting string will be placed in @length. * * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for * more information on extended JSON. * * Returns: A newly allocated string that should be freed with bson_free(). */ BSON_EXPORT (char *) bson_as_json_with_opts (const bson_t *bson, size_t *length, const bson_json_opts_t *opts); /** * bson_as_canonical_extended_json: * @bson: A bson_t. * @length: A location for the string length, or NULL. * * Creates a new string containing @bson in canonical extended JSON format, * conforming to the MongoDB Extended JSON Spec: * * github.com/mongodb/specifications/blob/master/source/extended-json.rst * * The caller is responsible for freeing the resulting string. If @length is * non-NULL, then the length of the resulting string will be placed in @length. * * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for * more information on extended JSON. * * Returns: A newly allocated string that should be freed with bson_free(). */ BSON_EXPORT (char *) bson_as_canonical_extended_json (const bson_t *bson, size_t *length); /** * bson_as_json: * @bson: A bson_t. * @length: A location for the string length, or NULL. * * Creates a new string containing @bson in libbson's legacy JSON format. * Superseded by bson_as_canonical_extended_json and * bson_as_relaxed_extended_json. The caller is * responsible for freeing the resulting string. If @length is non-NULL, then * the length of the resulting string will be placed in @length. * * Returns: A newly allocated string that should be freed with bson_free(). */ BSON_EXPORT (char *) bson_as_json (const bson_t *bson, size_t *length) BSON_GNUC_DEPRECATED_FOR (bson_as_legacy_extended_json); // `bson_as_legacy_extended_json` is a non-deprecated form of `bson_as_json`. BSON_EXPORT (char *) bson_as_legacy_extended_json (const bson_t *bson, size_t *length); /** * bson_as_relaxed_extended_json: * @bson: A bson_t. * @length: A location for the string length, or NULL. * * Creates a new string containing @bson in relaxed extended JSON format, * conforming to the MongoDB Extended JSON Spec: * * github.com/mongodb/specifications/blob/master/source/extended-json.rst * * The caller is responsible for freeing the resulting string. If @length is * non-NULL, then the length of the resulting string will be placed in @length. * * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for * more information on extended JSON. * * Returns: A newly allocated string that should be freed with bson_free(). */ BSON_EXPORT (char *) bson_as_relaxed_extended_json (const bson_t *bson, size_t *length); /* like bson_as_json() but for outermost arrays. */ BSON_EXPORT (char *) bson_array_as_json (const bson_t *bson, size_t *length) BSON_GNUC_DEPRECATED_FOR (bson_array_as_legacy_extended_json); // `bson_array_as_legacy_extended_json` is a non-deprecated form of `bson_array_as_json`. BSON_EXPORT (char *) bson_array_as_legacy_extended_json (const bson_t *bson, size_t *length); /* like bson_as_relaxed_extended_json() but for outermost arrays. */ BSON_EXPORT (char *) bson_array_as_relaxed_extended_json (const bson_t *bson, size_t *length); /* like bson_as_canonical_extended_json() but for outermost arrays. */ BSON_EXPORT (char *) bson_array_as_canonical_extended_json (const bson_t *bson, size_t *length); // bson_array_builder_t defines an API for building arrays. // BSON arrays require sequential numeric keys "0", "1", "2", ... typedef struct _bson_array_builder_t bson_array_builder_t; // bson_array_builder_new may be used to build a top-level BSON array. Example: // `[1,2,3]`. // To append an array field to a document (Example: `{ "field": [1,2,3] }`), use // `bson_append_array_builder_begin`. BSON_EXPORT (bson_array_builder_t *) bson_array_builder_new (void); // bson_array_builder_build initializes and moves BSON data to `out`. // `bab` may be reused and will start appending a new array at index "0". BSON_EXPORT (bool) bson_array_builder_build (bson_array_builder_t *bab, bson_t *out); BSON_EXPORT (void) bson_array_builder_destroy (bson_array_builder_t *bab); BSON_EXPORT (bool) bson_append_value (bson_t *bson, const char *key, int key_length, const bson_value_t *value); #define BSON_APPEND_VALUE(b, key, val) bson_append_value (b, key, (int) strlen (key), (val)) BSON_EXPORT (bool) bson_array_builder_append_value (bson_array_builder_t *bab, const bson_value_t *value); /** * bson_append_array: * @bson: A bson_t. * @key: The key for the field. * @array: A bson_t containing the array. * * Appends a BSON array to @bson. BSON arrays are like documents where the * key is the string version of the index. For example, the first item of the * array would have the key "0". The second item would have the index "1". * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_array (bson_t *bson, const char *key, int key_length, const bson_t *array); #define BSON_APPEND_ARRAY(b, key, val) bson_append_array (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_array (bson_array_builder_t *bab, const bson_t *array); /** * bson_append_binary: * @bson: A bson_t to append. * @key: The key for the field. * @subtype: The bson_subtype_t of the binary. * @binary: The binary buffer to append. * @length: The length of @binary. * * Appends a binary buffer to the BSON document. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_binary ( bson_t *bson, const char *key, int key_length, bson_subtype_t subtype, const uint8_t *binary, uint32_t length); #define BSON_APPEND_BINARY(b, key, subtype, val, len) bson_append_binary (b, key, (int) strlen (key), subtype, val, len) BSON_EXPORT (bool) bson_array_builder_append_binary (bson_array_builder_t *bab, bson_subtype_t subtype, const uint8_t *binary, uint32_t length); /** * bson_append_bool: * @bson: A bson_t. * @key: The key for the field. * @value: The boolean value. * * Appends a new field to @bson of type BSON_TYPE_BOOL. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_bool (bson_t *bson, const char *key, int key_length, bool value); #define BSON_APPEND_BOOL(b, key, val) bson_append_bool (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_bool (bson_array_builder_t *bab, bool value); /** * bson_append_code: * @bson: A bson_t. * @key: The key for the document. * @javascript: JavaScript code to be executed. * * Appends a field of type BSON_TYPE_CODE to the BSON document. @javascript * should contain a script in javascript to be executed. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_code (bson_t *bson, const char *key, int key_length, const char *javascript); #define BSON_APPEND_CODE(b, key, val) bson_append_code (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_code (bson_array_builder_t *bab, const char *javascript); /** * bson_append_code_with_scope: * @bson: A bson_t. * @key: The key for the document. * @javascript: JavaScript code to be executed. * @scope: A bson_t containing the scope for @javascript. * * Appends a field of type BSON_TYPE_CODEWSCOPE to the BSON document. * @javascript should contain a script in javascript to be executed. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_code_with_scope ( bson_t *bson, const char *key, int key_length, const char *javascript, const bson_t *scope); #define BSON_APPEND_CODE_WITH_SCOPE(b, key, val, scope) \ bson_append_code_with_scope (b, key, (int) strlen (key), val, scope) BSON_EXPORT (bool) bson_array_builder_append_code_with_scope (bson_array_builder_t *bab, const char *javascript, const bson_t *scope); /** * bson_append_dbpointer: * @bson: A bson_t. * @key: The key for the field. * @collection: The collection name. * @oid: The oid to the reference. * * Appends a new field of type BSON_TYPE_DBPOINTER. This datum type is * deprecated in the BSON spec and should not be used in new code. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_dbpointer (bson_t *bson, const char *key, int key_length, const char *collection, const bson_oid_t *oid); #define BSON_APPEND_DBPOINTER(b, key, coll, oid) bson_append_dbpointer (b, key, (int) strlen (key), coll, oid) BSON_EXPORT (bool) bson_array_builder_append_dbpointer (bson_array_builder_t *bab, const char *collection, const bson_oid_t *oid); /** * bson_append_double: * @bson: A bson_t. * @key: The key for the field. * * Appends a new field to @bson of the type BSON_TYPE_DOUBLE. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_double (bson_t *bson, const char *key, int key_length, double value); #define BSON_APPEND_DOUBLE(b, key, val) bson_append_double (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_double (bson_array_builder_t *bab, double value); /** * bson_append_document: * @bson: A bson_t. * @key: The key for the field. * @value: A bson_t containing the subdocument. * * Appends a new field to @bson of the type BSON_TYPE_DOCUMENT. * The documents contents will be copied into @bson. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_document (bson_t *bson, const char *key, int key_length, const bson_t *value); #define BSON_APPEND_DOCUMENT(b, key, val) bson_append_document (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_document (bson_array_builder_t *bab, const bson_t *value); /** * bson_append_document_begin: * @bson: A bson_t. * @key: The key for the field. * @key_length: The length of @key in bytes not including NUL or -1 * if @key_length is NUL terminated. * @child: A location to an uninitialized bson_t. * * Appends a new field named @key to @bson. The field is, however, * incomplete. @child will be initialized so that you may add fields to the * child document. Child will use a memory buffer owned by @bson and * therefore grow the parent buffer as additional space is used. This allows * a single malloc'd buffer to be used when building documents which can help * reduce memory fragmentation. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_document_begin (bson_t *bson, const char *key, int key_length, bson_t *child); #define BSON_APPEND_DOCUMENT_BEGIN(b, key, child) bson_append_document_begin (b, key, (int) strlen (key), child) BSON_EXPORT (bool) bson_array_builder_append_document_begin (bson_array_builder_t *bab, bson_t *child); /** * bson_append_document_end: * @bson: A bson_t. * @child: A bson_t supplied to bson_append_document_begin(). * * Finishes the appending of a document to a @bson. @child is considered * disposed after this call and should not be used any further. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_document_end (bson_t *bson, bson_t *child); BSON_EXPORT (bool) bson_array_builder_append_document_end (bson_array_builder_t *bab, bson_t *child); /** * bson_append_array_begin: * @bson: A bson_t. * @key: The key for the field. * @key_length: The length of @key in bytes not including NUL or -1 * if @key_length is NUL terminated. * @child: A location to an uninitialized bson_t. * * Appends a new field named @key to @bson. The field is, however, * incomplete. @child will be initialized so that you may add fields to the * child array. Child will use a memory buffer owned by @bson and * therefore grow the parent buffer as additional space is used. This allows * a single malloc'd buffer to be used when building arrays which can help * reduce memory fragmentation. * * The type of @child will be BSON_TYPE_ARRAY and therefore the keys inside * of it MUST be "0", "1", etc. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_array_begin (bson_t *bson, const char *key, int key_length, bson_t *child); #define BSON_APPEND_ARRAY_BEGIN(b, key, child) bson_append_array_begin (b, key, (int) strlen (key), child) /** * bson_append_array_end: * @bson: A bson_t. * @child: A bson_t supplied to bson_append_array_begin(). * * Finishes the appending of a array to a @bson. @child is considered * disposed after this call and should not be used any further. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_array_end (bson_t *bson, bson_t *child); /** * bson_append_int32: * @bson: A bson_t. * @key: The key for the field. * @value: The int32_t 32-bit integer value. * * Appends a new field of type BSON_TYPE_INT32 to @bson. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_int32 (bson_t *bson, const char *key, int key_length, int32_t value); #define BSON_APPEND_INT32(b, key, val) bson_append_int32 (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_int32 (bson_array_builder_t *bab, int32_t value); /** * bson_append_int64: * @bson: A bson_t. * @key: The key for the field. * @value: The int64_t 64-bit integer value. * * Appends a new field of type BSON_TYPE_INT64 to @bson. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_int64 (bson_t *bson, const char *key, int key_length, int64_t value); #define BSON_APPEND_INT64(b, key, val) bson_append_int64 (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_int64 (bson_array_builder_t *bab, int64_t value); /** * bson_append_decimal128: * @bson: A bson_t. * @key: The key for the field. * @value: The bson_decimal128_t decimal128 value. * * Appends a new field of type BSON_TYPE_DECIMAL128 to @bson. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_decimal128 (bson_t *bson, const char *key, int key_length, const bson_decimal128_t *value); #define BSON_APPEND_DECIMAL128(b, key, val) bson_append_decimal128 (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_decimal128 (bson_array_builder_t *bab, const bson_decimal128_t *value); /** * bson_append_iter: * @bson: A bson_t to append to. * @key: The key name or %NULL to take current key from @iter. * @key_length: The key length or -1 to use strlen(). * @iter: The iter located on the position of the element to append. * * Appends a new field to @bson that is equivalent to the field currently * pointed to by @iter. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_iter (bson_t *bson, const char *key, int key_length, const bson_iter_t *iter); #define BSON_APPEND_ITER(b, key, val) bson_append_iter (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_iter (bson_array_builder_t *bab, const bson_iter_t *iter); /** * bson_append_minkey: * @bson: A bson_t. * @key: The key for the field. * * Appends a new field of type BSON_TYPE_MINKEY to @bson. This is a special * type that compares lower than all other possible BSON element values. * * See http://bsonspec.org for more information on this type. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_minkey (bson_t *bson, const char *key, int key_length); #define BSON_APPEND_MINKEY(b, key) bson_append_minkey (b, key, (int) strlen (key)) BSON_EXPORT (bool) bson_array_builder_append_minkey (bson_array_builder_t *bab); /** * bson_append_maxkey: * @bson: A bson_t. * @key: The key for the field. * * Appends a new field of type BSON_TYPE_MAXKEY to @bson. This is a special * type that compares higher than all other possible BSON element values. * * See http://bsonspec.org for more information on this type. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_maxkey (bson_t *bson, const char *key, int key_length); #define BSON_APPEND_MAXKEY(b, key) bson_append_maxkey (b, key, (int) strlen (key)) BSON_EXPORT (bool) bson_array_builder_append_maxkey (bson_array_builder_t *bab); /** * bson_append_null: * @bson: A bson_t. * @key: The key for the field. * * Appends a new field to @bson with NULL for the value. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_null (bson_t *bson, const char *key, int key_length); #define BSON_APPEND_NULL(b, key) bson_append_null (b, key, (int) strlen (key)) BSON_EXPORT (bool) bson_array_builder_append_null (bson_array_builder_t *bab); /** * bson_append_oid: * @bson: A bson_t. * @key: The key for the field. * @oid: bson_oid_t. * * Appends a new field to the @bson of type BSON_TYPE_OID using the contents of * @oid. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_oid (bson_t *bson, const char *key, int key_length, const bson_oid_t *oid); #define BSON_APPEND_OID(b, key, val) bson_append_oid (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_oid (bson_array_builder_t *bab, const bson_oid_t *oid); /** * bson_append_regex: * @bson: A bson_t. * @key: The key of the field. * @regex: The regex to append to the bson. * @options: Options for @regex. * * Appends a new field to @bson of type BSON_TYPE_REGEX. @regex should * be the regex string. @options should contain the options for the regex. * * Valid options for @options are: * * 'i' for case-insensitive. * 'm' for multiple matching. * 'x' for verbose mode. * 'l' to make \w and \W locale dependent. * 's' for dotall mode ('.' matches everything) * 'u' to make \w and \W match unicode. * * For more detailed information about BSON regex elements, see bsonspec.org. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_regex (bson_t *bson, const char *key, int key_length, const char *regex, const char *options); #define BSON_APPEND_REGEX(b, key, val, opt) bson_append_regex (b, key, (int) strlen (key), val, opt) BSON_EXPORT (bool) bson_array_builder_append_regex (bson_array_builder_t *bab, const char *regex, const char *options); /** * bson_append_regex: * @bson: A bson_t. * @key: The key of the field. * @key_length: The length of the key string. * @regex: The regex to append to the bson. * @regex_length: The length of the regex string. * @options: Options for @regex. * * Appends a new field to @bson of type BSON_TYPE_REGEX. @regex should * be the regex string. @options should contain the options for the regex. * * Valid options for @options are: * * 'i' for case-insensitive. * 'm' for multiple matching. * 'x' for verbose mode. * 'l' to make \w and \W locale dependent. * 's' for dotall mode ('.' matches everything) * 'u' to make \w and \W match unicode. * * For more detailed information about BSON regex elements, see bsonspec.org. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_regex_w_len ( bson_t *bson, const char *key, int key_length, const char *regex, int regex_length, const char *options); BSON_EXPORT (bool) bson_array_builder_append_regex_w_len (bson_array_builder_t *bab, const char *regex, int regex_length, const char *options); /** * bson_append_utf8: * @bson: A bson_t. * @key: The key for the field. * @value: A UTF-8 encoded string. * @length: The length of @value or -1 if it is NUL terminated. * * Appends a new field to @bson using @key as the key and @value as the UTF-8 * encoded value. * * It is the callers responsibility to ensure @value is valid UTF-8. You can * use bson_utf8_validate() to perform this check. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_utf8 (bson_t *bson, const char *key, int key_length, const char *value, int length); #define BSON_APPEND_UTF8(b, key, val) bson_append_utf8 (b, key, (int) strlen (key), val, (int) strlen (val)) BSON_EXPORT (bool) bson_array_builder_append_utf8 (bson_array_builder_t *bab, const char *value, int length); /** * bson_append_symbol: * @bson: A bson_t. * @key: The key for the field. * @value: The symbol as a string. * @length: The length of @value or -1 if NUL-terminated. * * Appends a new field to @bson of type BSON_TYPE_SYMBOL. This BSON type is * deprecated and should not be used in new code. * * See http://bsonspec.org for more information on this type. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_symbol (bson_t *bson, const char *key, int key_length, const char *value, int length); #define BSON_APPEND_SYMBOL(b, key, val) bson_append_symbol (b, key, (int) strlen (key), val, (int) strlen (val)) BSON_EXPORT (bool) bson_array_builder_append_symbol (bson_array_builder_t *bab, const char *value, int length); /** * bson_append_time_t: * @bson: A bson_t. * @key: The key for the field. * @value: A time_t. * * Appends a BSON_TYPE_DATE_TIME field to @bson using the time_t @value for the * number of seconds since UNIX epoch in UTC. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_time_t (bson_t *bson, const char *key, int key_length, time_t value); #define BSON_APPEND_TIME_T(b, key, val) bson_append_time_t (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_time_t (bson_array_builder_t *bab, time_t value); /** * bson_append_timeval: * @bson: A bson_t. * @key: The key for the field. * @value: A struct timeval containing the date and time. * * Appends a BSON_TYPE_DATE_TIME field to @bson using the struct timeval * provided. The time is persisted in milliseconds since the UNIX epoch in UTC. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_timeval (bson_t *bson, const char *key, int key_length, struct timeval *value); #define BSON_APPEND_TIMEVAL(b, key, val) bson_append_timeval (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_timeval (bson_array_builder_t *bab, struct timeval *value); /** * bson_append_date_time: * @bson: A bson_t. * @key: The key for the field. * @key_length: The length of @key in bytes or -1 if \0 terminated. * @value: The number of milliseconds elapsed since UNIX epoch. * * Appends a new field to @bson of type BSON_TYPE_DATE_TIME. * * Returns: true if successful; otherwise false. */ BSON_EXPORT (bool) bson_append_date_time (bson_t *bson, const char *key, int key_length, int64_t value); #define BSON_APPEND_DATE_TIME(b, key, val) bson_append_date_time (b, key, (int) strlen (key), val) BSON_EXPORT (bool) bson_array_builder_append_date_time (bson_array_builder_t *bab, int64_t value); /** * bson_append_now_utc: * @bson: A bson_t. * @key: The key for the field. * @key_length: The length of @key or -1 if it is NULL terminated. * * Appends a BSON_TYPE_DATE_TIME field to @bson using the current time in UTC * as the field value. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_now_utc (bson_t *bson, const char *key, int key_length); #define BSON_APPEND_NOW_UTC(b, key) bson_append_now_utc (b, key, (int) strlen (key)) BSON_EXPORT (bool) bson_array_builder_append_now_utc (bson_array_builder_t *bab); /** * bson_append_timestamp: * @bson: A bson_t. * @key: The key for the field. * @timestamp: 4 byte timestamp. * @increment: 4 byte increment for timestamp. * * Appends a field of type BSON_TYPE_TIMESTAMP to @bson. This is a special type * used by MongoDB replication and sharding. If you need generic time and date * fields use bson_append_time_t() or bson_append_timeval(). * * Setting @increment and @timestamp to zero has special semantics. See * http://bsonspec.org for more information on this field type. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_timestamp (bson_t *bson, const char *key, int key_length, uint32_t timestamp, uint32_t increment); #define BSON_APPEND_TIMESTAMP(b, key, val, inc) bson_append_timestamp (b, key, (int) strlen (key), val, inc) BSON_EXPORT (bool) bson_array_builder_append_timestamp (bson_array_builder_t *bab, uint32_t timestamp, uint32_t increment); /** * bson_append_undefined: * @bson: A bson_t. * @key: The key for the field. * * Appends a field of type BSON_TYPE_UNDEFINED. This type is deprecated in the * spec and should not be used for new code. However, it is provided for those * needing to interact with legacy systems. * * Returns: true if successful; false if append would overflow max size. */ BSON_EXPORT (bool) bson_append_undefined (bson_t *bson, const char *key, int key_length); #define BSON_APPEND_UNDEFINED(b, key) bson_append_undefined (b, key, (int) strlen (key)) BSON_EXPORT (bool) bson_array_builder_append_undefined (bson_array_builder_t *bab); BSON_EXPORT (bool) bson_concat (bson_t *dst, const bson_t *src); BSON_EXPORT (bool) bson_append_array_builder_begin (bson_t *bson, const char *key, int key_length, bson_array_builder_t **child); #define BSON_APPEND_ARRAY_BUILDER_BEGIN(b, key, child) \ bson_append_array_builder_begin (b, key, (int) strlen (key), child) BSON_EXPORT (bool) bson_array_builder_append_array_builder_begin (bson_array_builder_t *bab, bson_array_builder_t **child); BSON_EXPORT (bool) bson_append_array_builder_end (bson_t *bson, bson_array_builder_t *child); BSON_EXPORT (bool) bson_array_builder_append_array_builder_end (bson_array_builder_t *bab, bson_array_builder_t *child); BSON_END_DECLS #endif /* BSON_H */ mongodb-1.21.0/src/libmongoc/src/libbson/src/jsonsl/jsonsl.c0000644000175100001660000015205014760300420020672 0ustar /* Copyright (C) 2012-2015 Mark Nunberg. * * See included LICENSE file for license details. */ #include #include #include #include #ifdef JSONSL_USE_METRICS #define XMETRICS \ X(STRINGY_INSIGNIFICANT) \ X(STRINGY_SLOWPATH) \ X(ALLOWED_WHITESPACE) \ X(QUOTE_FASTPATH) \ X(SPECIAL_FASTPATH) \ X(SPECIAL_WSPOP) \ X(SPECIAL_SLOWPATH) \ X(GENERIC) \ X(STRUCTURAL_TOKEN) \ X(SPECIAL_SWITCHFIRST) \ X(STRINGY_CATCH) \ X(NUMBER_FASTPATH) \ X(ESCAPES) \ X(TOTAL) \ struct jsonsl_metrics_st { #define X(m) \ unsigned long metric_##m; XMETRICS #undef X }; static struct jsonsl_metrics_st GlobalMetrics = { 0 }; static unsigned long GenericCounter[0x100] = { 0 }; static unsigned long StringyCatchCounter[0x100] = { 0 }; #define INCR_METRIC(m) \ GlobalMetrics.metric_##m++; #define INCR_GENERIC(c) \ INCR_METRIC(GENERIC); \ GenericCounter[c]++; \ #define INCR_STRINGY_CATCH(c) \ INCR_METRIC(STRINGY_CATCH); \ StringyCatchCounter[c]++; JSONSL_API void jsonsl_dump_global_metrics(void) { int ii; printf("JSONSL Metrics:\n"); #define X(m) \ printf("\t%-30s %20lu (%0.2f%%)\n", #m, GlobalMetrics.metric_##m, \ (float)((float)(GlobalMetrics.metric_##m/(float)GlobalMetrics.metric_TOTAL)) * 100); XMETRICS #undef X printf("Generic Characters:\n"); for (ii = 0; ii < 0xff; ii++) { if (GenericCounter[ii]) { printf("\t[ %c ] %lu\n", ii, GenericCounter[ii]); } } printf("Weird string loop\n"); for (ii = 0; ii < 0xff; ii++) { if (StringyCatchCounter[ii]) { printf("\t[ %c ] %lu\n", ii, StringyCatchCounter[ii]); } } } #else #define INCR_METRIC(m) #define INCR_GENERIC(c) #define INCR_STRINGY_CATCH(c) JSONSL_API void jsonsl_dump_global_metrics(void) { } #endif /* JSONSL_USE_METRICS */ #define CASE_DIGITS \ case '1': \ case '2': \ case '3': \ case '4': \ case '5': \ case '6': \ case '7': \ case '8': \ case '9': \ case '0': static unsigned extract_special(unsigned); static int is_special_end(unsigned); static int is_allowed_whitespace(unsigned); static int is_allowed_escape(unsigned); static int is_simple_char(unsigned); static char get_escape_equiv(unsigned); JSONSL_API jsonsl_t jsonsl_new(int nlevels) { unsigned int ii; struct jsonsl_st * jsn; if (nlevels < 2) { return NULL; } jsn = (struct jsonsl_st *) bson_malloc0(sizeof (*jsn) + ( (nlevels-1) * sizeof (struct jsonsl_state_st) ) ); jsn->levels_max = (unsigned int) nlevels; jsn->max_callback_level = UINT_MAX; jsonsl_reset(jsn); for (ii = 0; ii < jsn->levels_max; ii++) { jsn->stack[ii].level = ii; } return jsn; } JSONSL_API void jsonsl_reset(jsonsl_t jsn) { jsn->tok_last = 0; jsn->can_insert = 1; jsn->pos = 0; jsn->level = 0; jsn->stopfl = 0; jsn->in_escape = 0; jsn->expecting = 0; } JSONSL_API void jsonsl_destroy(jsonsl_t jsn) { if (jsn) { bson_free(jsn); } } #define FASTPARSE_EXHAUSTED 1 #define FASTPARSE_BREAK 0 /* * This function is meant to accelerate string parsing, reducing the main loop's * check if we are indeed a string. * * @param jsn the parser * @param[in,out] bytes_p A pointer to the current buffer (i.e. current position) * @param[in,out] nbytes_p A pointer to the current size of the buffer * @return true if all bytes have been exhausted (and thus the main loop can * return), false if a special character was examined which requires greater * examination. */ static int jsonsl__str_fastparse(jsonsl_t jsn, const jsonsl_uchar_t **bytes_p, size_t *nbytes_p) { const jsonsl_uchar_t *bytes = *bytes_p; const jsonsl_uchar_t *end; for (end = bytes + *nbytes_p; bytes != end; bytes++) { if ( #ifdef JSONSL_USE_WCHAR *bytes >= 0x100 || #endif /* JSONSL_USE_WCHAR */ (is_simple_char(*bytes))) { INCR_METRIC(TOTAL); INCR_METRIC(STRINGY_INSIGNIFICANT); } else { /* Once we're done here, re-calculate the position variables */ jsn->pos += (bytes - *bytes_p); *nbytes_p -= (bytes - *bytes_p); *bytes_p = bytes; return FASTPARSE_BREAK; } } /* Once we're done here, re-calculate the position variables */ jsn->pos += (bytes - *bytes_p); return FASTPARSE_EXHAUSTED; } /* Functions exactly like str_fastparse, except it also accepts a 'state' * argument, since the number's value is updated in the state. */ static int jsonsl__num_fastparse(jsonsl_t jsn, const jsonsl_uchar_t **bytes_p, size_t *nbytes_p, struct jsonsl_state_st *state) { int exhausted = 1; size_t nbytes = *nbytes_p; const jsonsl_uchar_t *bytes = *bytes_p; for (; nbytes; nbytes--, bytes++) { jsonsl_uchar_t c = *bytes; if (isdigit(c)) { INCR_METRIC(TOTAL); INCR_METRIC(NUMBER_FASTPATH); state->nelem = (state->nelem * 10) + (c - 0x30); } else { exhausted = 0; break; } } jsn->pos += (*nbytes_p - nbytes); if (exhausted) { return FASTPARSE_EXHAUSTED; } *nbytes_p = nbytes; *bytes_p = bytes; return FASTPARSE_BREAK; } JSONSL_API void jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes) { #define INVOKE_ERROR(eb) \ if (jsn->error_callback(jsn, JSONSL_ERROR_##eb, state, (char*)c)) { \ goto GT_AGAIN; \ } \ return; #define STACK_PUSH \ if (jsn->level >= (levels_max-1)) { \ jsn->error_callback(jsn, JSONSL_ERROR_LEVELS_EXCEEDED, state, (char*)c); \ return; \ } \ state = jsn->stack + (++jsn->level); \ state->ignore_callback = jsn->stack[jsn->level-1].ignore_callback; \ state->pos_begin = jsn->pos; #define STACK_POP_NOPOS \ state->pos_cur = jsn->pos; \ state = jsn->stack + (--jsn->level); #define STACK_POP \ STACK_POP_NOPOS; \ state->pos_cur = jsn->pos; #define CALLBACK_AND_POP_NOPOS(T) \ state->pos_cur = jsn->pos; \ DO_CALLBACK(T, POP); \ state->nescapes = 0; \ state = jsn->stack + (--jsn->level); #define CALLBACK_AND_POP(T) \ CALLBACK_AND_POP_NOPOS(T); \ state->pos_cur = jsn->pos; #define SPECIAL_POP \ CALLBACK_AND_POP(SPECIAL); \ jsn->expecting = 0; \ jsn->tok_last = 0; \ #define CUR_CHAR (*(jsonsl_uchar_t*)c) #define DO_CALLBACK(T, action) \ if (jsn->call_##T && \ jsn->max_callback_level > state->level && \ state->ignore_callback == 0) { \ \ if (jsn->action_callback_##action) { \ jsn->action_callback_##action(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \ } else if (jsn->action_callback) { \ jsn->action_callback(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \ } \ if (jsn->stopfl) { return; } \ } /** * Verifies that we are able to insert the (non-string) item into a hash. */ #define ENSURE_HVAL \ if (state->nelem % 2 == 0 && state->type == JSONSL_T_OBJECT) { \ INVOKE_ERROR(HKEY_EXPECTED); \ } #define VERIFY_SPECIAL(lit, lit_len) \ if ((jsn->pos - state->pos_begin) > lit_len \ || CUR_CHAR != (lit)[jsn->pos - state->pos_begin]) { \ INVOKE_ERROR(SPECIAL_EXPECTED); \ } #define VERIFY_SPECIAL_CI(lit, lit_len) \ if ((jsn->pos - state->pos_begin) > lit_len \ || tolower(CUR_CHAR) != (lit)[jsn->pos - state->pos_begin]) { \ INVOKE_ERROR(SPECIAL_EXPECTED); \ } #define STATE_SPECIAL_LENGTH \ (state)->nescapes #define IS_NORMAL_NUMBER \ ((state)->special_flags == JSONSL_SPECIALf_UNSIGNED || \ (state)->special_flags == JSONSL_SPECIALf_SIGNED) #define STATE_NUM_LAST jsn->tok_last #define CONTINUE_NEXT_CHAR() continue const jsonsl_uchar_t *c = (jsonsl_uchar_t*)bytes; size_t levels_max = jsn->levels_max; struct jsonsl_state_st *state = jsn->stack + jsn->level; jsn->base = bytes; for (; nbytes; nbytes--, jsn->pos++, c++) { unsigned state_type; INCR_METRIC(TOTAL); GT_AGAIN: state_type = state->type; /* Most common type is typically a string: */ if (state_type & JSONSL_Tf_STRINGY) { /* Special escape handling for some stuff */ if (jsn->in_escape) { jsn->in_escape = 0; if (!is_allowed_escape(CUR_CHAR)) { INVOKE_ERROR(ESCAPE_INVALID); } else if (CUR_CHAR == 'u') { DO_CALLBACK(UESCAPE, UESCAPE); if (jsn->return_UESCAPE) { return; } } CONTINUE_NEXT_CHAR(); } if (jsonsl__str_fastparse(jsn, &c, &nbytes) == FASTPARSE_EXHAUSTED) { /* No need to readjust variables as we've exhausted the iterator */ return; } else { if (CUR_CHAR == '"') { goto GT_QUOTE; } else if (CUR_CHAR == '\\') { goto GT_ESCAPE; } else { INVOKE_ERROR(WEIRD_WHITESPACE); } } INCR_METRIC(STRINGY_SLOWPATH); } else if (state_type == JSONSL_T_SPECIAL) { /* Fast track for signed/unsigned */ if (IS_NORMAL_NUMBER) { if (jsonsl__num_fastparse(jsn, &c, &nbytes, state) == FASTPARSE_EXHAUSTED) { return; } else { goto GT_SPECIAL_NUMERIC; } } else if (state->special_flags == JSONSL_SPECIALf_DASH) { #ifdef JSONSL_PARSE_NAN if (CUR_CHAR == 'I' || CUR_CHAR == 'i') { /* parsing -Infinity? */ state->special_flags = JSONSL_SPECIALf_NEG_INF; CONTINUE_NEXT_CHAR(); } #endif if (!isdigit(CUR_CHAR)) { INVOKE_ERROR(INVALID_NUMBER); } if (CUR_CHAR == '0') { state->special_flags = JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED; } else if (isdigit(CUR_CHAR)) { state->special_flags = JSONSL_SPECIALf_SIGNED; state->nelem = CUR_CHAR - 0x30; } else { INVOKE_ERROR(INVALID_NUMBER); } CONTINUE_NEXT_CHAR(); } else if (state->special_flags == JSONSL_SPECIALf_ZERO) { if (isdigit(CUR_CHAR)) { /* Following a zero! */ INVOKE_ERROR(INVALID_NUMBER); } /* Unset the 'zero' flag: */ if (state->special_flags & JSONSL_SPECIALf_SIGNED) { state->special_flags = JSONSL_SPECIALf_SIGNED; } else { state->special_flags = JSONSL_SPECIALf_UNSIGNED; } goto GT_SPECIAL_NUMERIC; } if ((state->special_flags & JSONSL_SPECIALf_NUMERIC) && !(state->special_flags & JSONSL_SPECIALf_INF)) { GT_SPECIAL_NUMERIC: switch (CUR_CHAR) { CASE_DIGITS STATE_NUM_LAST = '1'; CONTINUE_NEXT_CHAR(); case '.': if (state->special_flags & JSONSL_SPECIALf_FLOAT) { INVOKE_ERROR(INVALID_NUMBER); } state->special_flags |= JSONSL_SPECIALf_FLOAT; STATE_NUM_LAST = '.'; CONTINUE_NEXT_CHAR(); case 'e': case 'E': if (state->special_flags & JSONSL_SPECIALf_EXPONENT) { INVOKE_ERROR(INVALID_NUMBER); } state->special_flags |= JSONSL_SPECIALf_EXPONENT; STATE_NUM_LAST = 'e'; CONTINUE_NEXT_CHAR(); case '-': case '+': if (STATE_NUM_LAST != 'e') { INVOKE_ERROR(INVALID_NUMBER); } STATE_NUM_LAST = '-'; CONTINUE_NEXT_CHAR(); default: if (is_special_end(CUR_CHAR)) { goto GT_SPECIAL_POP; } INVOKE_ERROR(INVALID_NUMBER); break; } } /* else if (!NUMERIC) */ if (!is_special_end(CUR_CHAR)) { STATE_SPECIAL_LENGTH++; /* Verify TRUE, FALSE, NULL */ if (state->special_flags == JSONSL_SPECIALf_TRUE) { VERIFY_SPECIAL("true", 4 /* strlen("true") */); } else if (state->special_flags == JSONSL_SPECIALf_FALSE) { VERIFY_SPECIAL("false", 5 /* strlen("false") */); } else if (state->special_flags == JSONSL_SPECIALf_NULL) { VERIFY_SPECIAL("null", 4 /* strlen("null") */); #ifdef JSONSL_PARSE_NAN } else if (state->special_flags == JSONSL_SPECIALf_POS_INF) { VERIFY_SPECIAL_CI("infinity", 8 /* strlen("infinity") */); } else if (state->special_flags == JSONSL_SPECIALf_NEG_INF) { VERIFY_SPECIAL_CI("-infinity", 9 /* strlen("-infinity") */); } else if (state->special_flags == JSONSL_SPECIALf_NAN) { VERIFY_SPECIAL_CI("nan", 3 /* strlen("nan") */); } else if (state->special_flags & JSONSL_SPECIALf_NULL || state->special_flags & JSONSL_SPECIALf_NAN) { /* previous char was "n", are we parsing null or nan? */ const bool not_u = CUR_CHAR != 'u'; const bool not_a = tolower (CUR_CHAR) != 'a'; if (not_u) { state->special_flags &= ~JSONSL_SPECIALf_NULL; } if (not_a) { state->special_flags &= ~JSONSL_SPECIALf_NAN; } if (not_u && not_a) { /* This verify will always fail, as we have an 'n' * followed by a character that is neither 'a' nor 'u' * (and hence cannot be "null"). The purpose of this * VERIFY_SPECIAL is to generate an error in tokenization * that stops if a bare 'n' cannot possibly be a "nan" or * a "null". */ VERIFY_SPECIAL ("null", 4); } #endif } INCR_METRIC(SPECIAL_FASTPATH); CONTINUE_NEXT_CHAR(); } GT_SPECIAL_POP: jsn->can_insert = 0; if (IS_NORMAL_NUMBER) { /* Nothing */ } else if (state->special_flags == JSONSL_SPECIALf_ZERO || state->special_flags == (JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED)) { /* 0 is unsigned! */ state->special_flags = JSONSL_SPECIALf_UNSIGNED; } else if (state->special_flags == JSONSL_SPECIALf_DASH) { /* Still in dash! */ INVOKE_ERROR(INVALID_NUMBER); } else if (state->special_flags & JSONSL_SPECIALf_INF) { if (STATE_SPECIAL_LENGTH != 8) { INVOKE_ERROR(SPECIAL_INCOMPLETE); } state->nelem = 1; } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) { /* Check that we're not at the end of a token */ if (STATE_NUM_LAST != '1') { INVOKE_ERROR(INVALID_NUMBER); } } else if (state->special_flags == JSONSL_SPECIALf_TRUE) { if (STATE_SPECIAL_LENGTH != 4) { INVOKE_ERROR(SPECIAL_INCOMPLETE); } state->nelem = 1; } else if (state->special_flags == JSONSL_SPECIALf_FALSE) { if (STATE_SPECIAL_LENGTH != 5) { INVOKE_ERROR(SPECIAL_INCOMPLETE); } } else if (state->special_flags == JSONSL_SPECIALf_NULL) { if (STATE_SPECIAL_LENGTH != 4) { INVOKE_ERROR(SPECIAL_INCOMPLETE); } } SPECIAL_POP; jsn->expecting = ','; if (is_allowed_whitespace(CUR_CHAR)) { CONTINUE_NEXT_CHAR(); } /** * This works because we have a non-whitespace token * which is not a special token. If this is a structural * character then it will be gracefully handled by the * switch statement. Otherwise it will default to the 'special' * state again, */ goto GT_STRUCTURAL_TOKEN; } else if (is_allowed_whitespace(CUR_CHAR)) { INCR_METRIC(ALLOWED_WHITESPACE); /* So we're not special. Harmless insignificant whitespace * passthrough */ CONTINUE_NEXT_CHAR(); } else if (extract_special(CUR_CHAR)) { /* not a string, whitespace, or structural token. must be special */ goto GT_SPECIAL_BEGIN; } INCR_GENERIC(CUR_CHAR); if (CUR_CHAR == '"') { GT_QUOTE: jsn->can_insert = 0; switch (state_type) { /* the end of a string or hash key */ case JSONSL_T_STRING: CALLBACK_AND_POP(STRING); CONTINUE_NEXT_CHAR(); case JSONSL_T_HKEY: CALLBACK_AND_POP(HKEY); CONTINUE_NEXT_CHAR(); case JSONSL_T_OBJECT: state->nelem++; if ( (state->nelem-1) % 2 ) { /* Odd, this must be a hash value */ if (jsn->tok_last != ':') { INVOKE_ERROR(MISSING_TOKEN); } jsn->expecting = ','; /* Can't figure out what to expect next */ jsn->tok_last = 0; STACK_PUSH; state->type = JSONSL_T_STRING; DO_CALLBACK(STRING, PUSH); } else { /* hash key */ if (jsn->expecting != '"') { INVOKE_ERROR(STRAY_TOKEN); } jsn->tok_last = 0; jsn->expecting = ':'; STACK_PUSH; state->type = JSONSL_T_HKEY; DO_CALLBACK(HKEY, PUSH); } CONTINUE_NEXT_CHAR(); case JSONSL_T_LIST: state->nelem++; STACK_PUSH; state->type = JSONSL_T_STRING; jsn->expecting = ','; jsn->tok_last = 0; DO_CALLBACK(STRING, PUSH); CONTINUE_NEXT_CHAR(); case JSONSL_T_SPECIAL: INVOKE_ERROR(STRAY_TOKEN); break; default: INVOKE_ERROR(STRING_OUTSIDE_CONTAINER); break; } /* switch(state->type) */ } else if (CUR_CHAR == '\\') { GT_ESCAPE: INCR_METRIC(ESCAPES); /* Escape */ if ( (state->type & JSONSL_Tf_STRINGY) == 0 ) { INVOKE_ERROR(ESCAPE_OUTSIDE_STRING); } state->nescapes++; jsn->in_escape = 1; CONTINUE_NEXT_CHAR(); } /* " or \ */ GT_STRUCTURAL_TOKEN: switch (CUR_CHAR) { case ':': INCR_METRIC(STRUCTURAL_TOKEN); if (jsn->expecting != CUR_CHAR) { INVOKE_ERROR(STRAY_TOKEN); } jsn->tok_last = ':'; jsn->can_insert = 1; jsn->expecting = '"'; CONTINUE_NEXT_CHAR(); case ',': INCR_METRIC(STRUCTURAL_TOKEN); /** * The comma is one of the more generic tokens. * In the context of an OBJECT, the can_insert flag * should never be set, and no other action is * necessary. */ if (jsn->expecting != CUR_CHAR) { /* make this branch execute only when we haven't manually * just placed the ',' in the expecting register. */ INVOKE_ERROR(STRAY_TOKEN); } if (state->type == JSONSL_T_OBJECT) { /* end of hash value, expect a string as a hash key */ jsn->expecting = '"'; } else { jsn->can_insert = 1; } jsn->tok_last = ','; jsn->expecting = '"'; CONTINUE_NEXT_CHAR(); /* new list or object */ /* hashes are more common */ case '{': case '[': INCR_METRIC(STRUCTURAL_TOKEN); if (!jsn->can_insert) { INVOKE_ERROR(CANT_INSERT); } ENSURE_HVAL; state->nelem++; STACK_PUSH; /* because the constants match the opening delimiters, we can do this: */ state->type = CUR_CHAR; state->nelem = 0; jsn->can_insert = 1; if (CUR_CHAR == '{') { /* If we're a hash, we expect a key first, which is quouted */ jsn->expecting = '"'; } if (CUR_CHAR == JSONSL_T_OBJECT) { DO_CALLBACK(OBJECT, PUSH); } else { DO_CALLBACK(LIST, PUSH); } jsn->tok_last = 0; CONTINUE_NEXT_CHAR(); /* closing of list or object */ case '}': case ']': INCR_METRIC(STRUCTURAL_TOKEN); if (jsn->tok_last == ',' && jsn->options.allow_trailing_comma == 0) { INVOKE_ERROR(TRAILING_COMMA); } jsn->can_insert = 0; jsn->level--; jsn->expecting = ','; jsn->tok_last = 0; if (CUR_CHAR == ']') { if (state->type != '[') { INVOKE_ERROR(BRACKET_MISMATCH); } DO_CALLBACK(LIST, POP); } else { if (state->type != '{') { INVOKE_ERROR(BRACKET_MISMATCH); } else if (state->nelem && state->nelem % 2 != 0) { INVOKE_ERROR(VALUE_EXPECTED); } DO_CALLBACK(OBJECT, POP); } state = jsn->stack + jsn->level; state->pos_cur = jsn->pos; CONTINUE_NEXT_CHAR(); default: GT_SPECIAL_BEGIN: /** * Not a string, not a structural token, and not benign whitespace. * Technically we should iterate over the character always, but since * we are not doing full numerical/value decoding anyway (but only hinting), * we only check upon entry. */ if (state->type != JSONSL_T_SPECIAL) { int special_flags = extract_special(CUR_CHAR); if (!special_flags) { /** * Try to do some heuristics here anyway to figure out what kind of * error this is. The 'special' case is a fallback scenario anyway. */ if (CUR_CHAR == '\0') { INVOKE_ERROR(FOUND_NULL_BYTE); } else if (CUR_CHAR < 0x20) { INVOKE_ERROR(WEIRD_WHITESPACE); } else { INVOKE_ERROR(SPECIAL_EXPECTED); } } ENSURE_HVAL; state->nelem++; if (!jsn->can_insert) { INVOKE_ERROR(CANT_INSERT); } STACK_PUSH; state->type = JSONSL_T_SPECIAL; state->special_flags = special_flags; STATE_SPECIAL_LENGTH = 1; if (special_flags == JSONSL_SPECIALf_UNSIGNED) { state->nelem = CUR_CHAR - 0x30; STATE_NUM_LAST = '1'; } else { STATE_NUM_LAST = '-'; state->nelem = 0; } DO_CALLBACK(SPECIAL, PUSH); } CONTINUE_NEXT_CHAR(); } } } JSONSL_API const char* jsonsl_strerror(jsonsl_error_t err) { if (err == JSONSL_ERROR_SUCCESS) { return "SUCCESS"; } #define X(t) \ if (err == JSONSL_ERROR_##t) \ return #t; JSONSL_XERR; #undef X return ""; } JSONSL_API const char *jsonsl_strtype(jsonsl_type_t type) { #define X(o,c) \ if (type == JSONSL_T_##o) \ return #o; JSONSL_XTYPE #undef X return "UNKNOWN TYPE"; } /* * * JPR/JSONPointer functions * * */ #ifndef JSONSL_NO_JPR static jsonsl_jpr_type_t populate_component(char *in, struct jsonsl_jpr_component_st *component, char **next, jsonsl_error_t *errp) { unsigned long pctval; char *c = NULL, *outp = NULL, *end = NULL; size_t input_len; jsonsl_jpr_type_t ret = JSONSL_PATH_NONE; if (*next == NULL || *(*next) == '\0') { return JSONSL_PATH_NONE; } /* Replace the next / with a NULL */ *next = strstr(in, "/"); if (*next != NULL) { *(*next) = '\0'; /* drop the forward slash */ input_len = *next - in; end = *next; *next += 1; /* next character after the '/' */ } else { input_len = strlen(in); end = in + input_len + 1; } component->pstr = in; /* Check for special components of interest */ if (*in == JSONSL_PATH_WILDCARD_CHAR && input_len == 1) { /* Lone wildcard */ ret = JSONSL_PATH_WILDCARD; goto GT_RET; } else if (isdigit(*in)) { /* ASCII Numeric */ char *endptr; component->idx = strtoul(in, &endptr, 10); if (endptr && *endptr == '\0') { ret = JSONSL_PATH_NUMERIC; goto GT_RET; } } /* Default, it's a string */ ret = JSONSL_PATH_STRING; for (c = outp = in; c < end; c++, outp++) { char origc; if (*c != '%') { goto GT_ASSIGN; } /* * c = { [+0] = '%', [+1] = 'b', [+2] = 'e', [+3] = '\0' } */ /* Need %XX */ if (c+2 >= end) { *errp = JSONSL_ERROR_PERCENT_BADHEX; return JSONSL_PATH_INVALID; } if (! (isxdigit(*(c+1)) && isxdigit(*(c+2))) ) { *errp = JSONSL_ERROR_PERCENT_BADHEX; return JSONSL_PATH_INVALID; } /* Temporarily null-terminate the characters */ origc = *(c+3); *(c+3) = '\0'; pctval = strtoul(c+1, NULL, 16); *(c+3) = origc; *outp = (char) pctval; c += 2; continue; GT_ASSIGN: *outp = *c; } /* Null-terminate the string */ for (; outp < c; outp++) { *outp = '\0'; } GT_RET: component->ptype = ret; if (ret != JSONSL_PATH_WILDCARD) { component->len = strlen(component->pstr); } return ret; } JSONSL_API jsonsl_jpr_t jsonsl_jpr_new(const char *path, jsonsl_error_t *errp) { char *my_copy = NULL; int count, curidx; struct jsonsl_jpr_st *ret = NULL; struct jsonsl_jpr_component_st *components = NULL; size_t origlen; jsonsl_error_t errstacked; #define JPR_BAIL(err) *errp = err; goto GT_ERROR; if (errp == NULL) { errp = &errstacked; } if (path == NULL || *path != '/') { JPR_BAIL(JSONSL_ERROR_JPR_NOROOT); } count = 1; path++; { const char *c = path; for (; *c; c++) { if (*c == '/') { count++; if (*(c+1) == '/') { JPR_BAIL(JSONSL_ERROR_JPR_DUPSLASH); } } } } if(*path) { count++; } components = (struct jsonsl_jpr_component_st *) malloc(sizeof(*components) * count); if (!components) { JPR_BAIL(JSONSL_ERROR_ENOMEM); } my_copy = (char *)malloc(strlen(path) + 1); if (!my_copy) { JPR_BAIL(JSONSL_ERROR_ENOMEM); } strcpy(my_copy, path); components[0].ptype = JSONSL_PATH_ROOT; if (*my_copy) { char *cur = my_copy; int pathret = JSONSL_PATH_STRING; curidx = 1; while (curidx < count) { pathret = populate_component(cur, components + curidx, &cur, errp); if (pathret > 0) { curidx++; } else { break; } } if (pathret == JSONSL_PATH_INVALID) { JPR_BAIL(JSONSL_ERROR_JPR_BADPATH); } } else { curidx = 1; } path--; /*revert path to leading '/' */ origlen = strlen(path) + 1; ret = (struct jsonsl_jpr_st *)malloc(sizeof(*ret)); if (!ret) { JPR_BAIL(JSONSL_ERROR_ENOMEM); } ret->orig = (char *)malloc(origlen); if (!ret->orig) { JPR_BAIL(JSONSL_ERROR_ENOMEM); } ret->components = components; ret->ncomponents = curidx; ret->basestr = my_copy; ret->norig = origlen-1; strcpy(ret->orig, path); return ret; GT_ERROR: free(my_copy); free(components); if (ret) { free(ret->orig); } free(ret); return NULL; #undef JPR_BAIL } void jsonsl_jpr_destroy(jsonsl_jpr_t jpr) { free(jpr->components); free(jpr->basestr); free(jpr->orig); free(jpr); } /** * Call when there is a possibility of a match, either as a final match or * as a path within a match * @param jpr The JPR path * @param component Component corresponding to the current element * @param prlevel The level of the *parent* * @param chtype The type of the child * @return Match status */ static jsonsl_jpr_match_t jsonsl__match_continue(jsonsl_jpr_t jpr, const struct jsonsl_jpr_component_st *component, unsigned prlevel, unsigned chtype) { const struct jsonsl_jpr_component_st *next_comp = component + 1; if (prlevel == jpr->ncomponents - 1) { /* This is the match. Check the expected type of the match against * the child */ if (jpr->match_type == 0 || jpr->match_type == chtype) { return JSONSL_MATCH_COMPLETE; } else { return JSONSL_MATCH_TYPE_MISMATCH; } } if (chtype == JSONSL_T_LIST) { if (next_comp->ptype == JSONSL_PATH_NUMERIC) { return JSONSL_MATCH_POSSIBLE; } else { return JSONSL_MATCH_TYPE_MISMATCH; } } else if (chtype == JSONSL_T_OBJECT) { if (next_comp->ptype == JSONSL_PATH_NUMERIC) { return JSONSL_MATCH_TYPE_MISMATCH; } else { return JSONSL_MATCH_POSSIBLE; } } else { return JSONSL_MATCH_TYPE_MISMATCH; } } JSONSL_API jsonsl_jpr_match_t jsonsl_path_match(jsonsl_jpr_t jpr, const struct jsonsl_state_st *parent, const struct jsonsl_state_st *child, const char *key, size_t nkey) { const struct jsonsl_jpr_component_st *comp; if (!parent) { /* No parent. Return immediately since it's always a match */ return jsonsl__match_continue(jpr, jpr->components, 0, child->type); } comp = jpr->components + parent->level; /* note that we don't need to verify the type of the match, this is * always done through the previous call to jsonsl__match_continue. * If we are in a POSSIBLE tree then we can be certain the types (at * least at this level) are correct */ if (parent->type == JSONSL_T_OBJECT) { if (comp->len != nkey || strncmp(key, comp->pstr, nkey) != 0) { return JSONSL_MATCH_NOMATCH; } } else { if (comp->idx != parent->nelem - 1) { return JSONSL_MATCH_NOMATCH; } } return jsonsl__match_continue(jpr, comp, parent->level, child->type); } JSONSL_API jsonsl_jpr_match_t jsonsl_jpr_match(jsonsl_jpr_t jpr, unsigned int parent_type, unsigned int parent_level, const char *key, size_t nkey) { /* find our current component. This is the child level */ int cmpret; struct jsonsl_jpr_component_st *p_component; p_component = jpr->components + parent_level; if (parent_level >= jpr->ncomponents) { return JSONSL_MATCH_NOMATCH; } /* Lone query for 'root' element. Always matches */ if (parent_level == 0) { if (jpr->ncomponents == 1) { return JSONSL_MATCH_COMPLETE; } else { return JSONSL_MATCH_POSSIBLE; } } /* Wildcard, always matches */ if (p_component->ptype == JSONSL_PATH_WILDCARD) { if (parent_level == jpr->ncomponents-1) { return JSONSL_MATCH_COMPLETE; } else { return JSONSL_MATCH_POSSIBLE; } } /* Check numeric array index. This gets its special block so we can avoid * string comparisons */ if (p_component->ptype == JSONSL_PATH_NUMERIC) { if (parent_type == JSONSL_T_LIST) { if (p_component->idx != nkey) { /* Wrong index */ return JSONSL_MATCH_NOMATCH; } else { if (parent_level == jpr->ncomponents-1) { /* This is the last element of the path */ return JSONSL_MATCH_COMPLETE; } else { /* Intermediate element */ return JSONSL_MATCH_POSSIBLE; } } } else if (p_component->is_arridx) { /* Numeric and an array index (set explicitly by user). But not * a list for a parent */ return JSONSL_MATCH_TYPE_MISMATCH; } } else if (parent_type == JSONSL_T_LIST) { return JSONSL_MATCH_TYPE_MISMATCH; } /* Check lengths */ if (p_component->len != nkey) { return JSONSL_MATCH_NOMATCH; } /* Check string comparison */ cmpret = strncmp(p_component->pstr, key, nkey); if (cmpret == 0) { if (parent_level == jpr->ncomponents-1) { return JSONSL_MATCH_COMPLETE; } else { return JSONSL_MATCH_POSSIBLE; } } return JSONSL_MATCH_NOMATCH; } JSONSL_API void jsonsl_jpr_match_state_init(jsonsl_t jsn, jsonsl_jpr_t *jprs, size_t njprs) { size_t ii, *firstjmp; if (njprs == 0) { return; } jsn->jprs = (jsonsl_jpr_t *)malloc(sizeof(jsonsl_jpr_t) * njprs); jsn->jpr_count = njprs; jsn->jpr_root = (size_t*)calloc(1, sizeof(size_t) * njprs * jsn->levels_max); memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs); /* Set the initial jump table values */ firstjmp = jsn->jpr_root; for (ii = 0; ii < njprs; ii++) { firstjmp[ii] = ii+1; } } JSONSL_API void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn) { if (jsn->jpr_count == 0) { return; } free(jsn->jpr_root); free(jsn->jprs); jsn->jprs = NULL; jsn->jpr_root = NULL; jsn->jpr_count = 0; } /** * This function should be called exactly once on each element... * This should also be called in recursive order, since we rely * on the parent having been initialized for a match. * * Since the parent is checked for a match as well, we maintain a 'serial' counter. * Whenever we traverse an element, we expect the serial to be the same as a global * integer. If they do not match, we re-initialize the context, and set the serial. * * This ensures a type of consistency without having a proactive reset by the * main lexer itself. * */ JSONSL_API jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn, struct jsonsl_state_st *state, const char *key, size_t nkey, jsonsl_jpr_match_t *out) { struct jsonsl_state_st *parent_state; jsonsl_jpr_t ret = NULL; /* Jump and JPR tables for our own state and the parent state */ size_t *jmptable, *pjmptable; size_t jmp_cur, ii, ourjmpidx; if (!jsn->jpr_root) { *out = JSONSL_MATCH_NOMATCH; return NULL; } pjmptable = jsn->jpr_root + (jsn->jpr_count * (state->level-1)); jmptable = pjmptable + jsn->jpr_count; /* If the parent cannot match, then invalidate it */ if (*pjmptable == 0) { *jmptable = 0; *out = JSONSL_MATCH_NOMATCH; return NULL; } parent_state = jsn->stack + state->level - 1; if (parent_state->type == JSONSL_T_LIST) { nkey = (size_t) parent_state->nelem; } *jmptable = 0; ourjmpidx = 0; memset(jmptable, 0, sizeof(int) * jsn->jpr_count); for (ii = 0; ii < jsn->jpr_count; ii++) { jmp_cur = pjmptable[ii]; if (jmp_cur) { jsonsl_jpr_t jpr = jsn->jprs[jmp_cur-1]; *out = jsonsl_jpr_match(jpr, parent_state->type, parent_state->level, key, nkey); if (*out == JSONSL_MATCH_COMPLETE) { ret = jpr; *jmptable = 0; return ret; } else if (*out == JSONSL_MATCH_POSSIBLE) { jmptable[ourjmpidx] = ii+1; ourjmpidx++; } } else { break; } } if (!*jmptable) { *out = JSONSL_MATCH_NOMATCH; } return NULL; } JSONSL_API const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match) { #define X(T,v) \ if ( match == JSONSL_MATCH_##T ) \ return #T; JSONSL_XMATCH #undef X return ""; } #endif /* JSONSL_WITH_JPR */ static char * jsonsl__writeutf8(uint32_t pt, char *out) { #define ADD_OUTPUT(c) *out = (char)(c); out++; if (pt < 0x80) { ADD_OUTPUT(pt); } else if (pt < 0x800) { ADD_OUTPUT((pt >> 6) | 0xC0); ADD_OUTPUT((pt & 0x3F) | 0x80); } else if (pt < 0x10000) { ADD_OUTPUT((pt >> 12) | 0xE0); ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80); ADD_OUTPUT((pt & 0x3F) | 0x80); } else { ADD_OUTPUT((pt >> 18) | 0xF0); ADD_OUTPUT(((pt >> 12) & 0x3F) | 0x80); ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80); ADD_OUTPUT((pt & 0x3F) | 0x80); } return out; #undef ADD_OUTPUT } /* Thanks snej (https://github.com/mnunberg/jsonsl/issues/9) */ static int jsonsl__digit2int(char ch) { int d = ch - '0'; if ((unsigned) d < 10) { return d; } d = ch - 'a'; if ((unsigned) d < 6) { return d + 10; } d = ch - 'A'; if ((unsigned) d < 6) { return d + 10; } return -1; } /* Assume 's' is at least 4 bytes long */ static int jsonsl__get_uescape_16(const char *s) { int ret = 0; int cur; #define GET_DIGIT(off) \ cur = jsonsl__digit2int(s[off]); \ if (cur == -1) { return -1; } \ ret |= (cur << (12 - (off * 4))); GET_DIGIT(0); GET_DIGIT(1); GET_DIGIT(2); GET_DIGIT(3); #undef GET_DIGIT return ret; } /** * Utility function to convert escape sequences */ JSONSL_API size_t jsonsl_util_unescape_ex(const char *in, char *out, size_t len, const int toEscape[128], unsigned *oflags, jsonsl_error_t *err, const char **errat) { const unsigned char *c = (const unsigned char*)in; char *begin_p = out; unsigned oflags_s; uint16_t last_codepoint = 0; if (!oflags) { oflags = &oflags_s; } *oflags = 0; #define UNESCAPE_BAIL(e,offset) \ *err = JSONSL_ERROR_##e; \ if (errat) { \ *errat = (const char*)(c+ (ptrdiff_t)(offset)); \ } \ return 0; for (; len; len--, c++, out++) { int uescval; if (*c != '\\') { /* Not an escape, so we don't care about this */ goto GT_ASSIGN; } if (len < 2) { UNESCAPE_BAIL(ESCAPE_INVALID, 0); } if (!is_allowed_escape(c[1])) { UNESCAPE_BAIL(ESCAPE_INVALID, 1) } if ((toEscape && toEscape[(unsigned char)c[1] & 0x7f] == 0 && c[1] != '\\' && c[1] != '"')) { /* if we don't want to unescape this string, write the escape sequence to the output */ *out++ = *c++; --len; goto GT_ASSIGN; } if (c[1] != 'u') { /* simple skip-and-replace using pre-defined maps. * TODO: should the maps actually reflect the desired * replacement character in toEscape? */ char esctmp = get_escape_equiv(c[1]); if (esctmp) { /* Check if there is a corresponding replacement */ *out = esctmp; } else { /* Just gobble up the 'reverse-solidus' */ *out = c[1]; } len--; c++; /* do not assign, just continue */ continue; } /* next == 'u' */ if (len < 6) { /* Need at least six characters.. */ UNESCAPE_BAIL(UESCAPE_TOOSHORT, 2); } uescval = jsonsl__get_uescape_16((const char *)c + 2); if (uescval == -1) { UNESCAPE_BAIL(PERCENT_BADHEX, -1); } if (last_codepoint) { uint16_t w1 = last_codepoint, w2 = (uint16_t)uescval; uint32_t cp; if (uescval < 0xDC00 || uescval > 0xDFFF) { UNESCAPE_BAIL(INVALID_CODEPOINT, -1); } cp = (w1 & 0x3FF) << 10; cp |= (w2 & 0x3FF); cp += 0x10000; out = jsonsl__writeutf8(cp, out) - 1; last_codepoint = 0; } else if (uescval < 0xD800 || uescval > 0xDFFF) { *oflags |= JSONSL_SPECIALf_NONASCII; out = jsonsl__writeutf8(uescval, out) - 1; } else if (uescval < 0xDC00) { *oflags |= JSONSL_SPECIALf_NONASCII; last_codepoint = (uint16_t)uescval; out--; } else { UNESCAPE_BAIL(INVALID_CODEPOINT, 2); } /* Post uescape cleanup */ len -= 5; /* Gobble up 5 chars after 'u' */ c += 5; continue; /* Only reached by previous branches */ GT_ASSIGN: *out = *c; } if (last_codepoint) { *err = JSONSL_ERROR_INVALID_CODEPOINT; return 0; } *err = JSONSL_ERROR_SUCCESS; return out - begin_p; } /** * Character Table definitions. * These were all generated via srcutil/genchartables.pl */ /** * This table contains the beginnings of non-string * allowable (bareword) values. */ static unsigned short Special_Table[0x100] = { /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2c */ /* 0x2d */ JSONSL_SPECIALf_DASH /* <-> */, /* 0x2d */ /* 0x2e */ 0,0, /* 0x2f */ /* 0x30 */ JSONSL_SPECIALf_ZERO /* <0> */, /* 0x30 */ /* 0x31 */ JSONSL_SPECIALf_UNSIGNED /* <1> */, /* 0x31 */ /* 0x32 */ JSONSL_SPECIALf_UNSIGNED /* <2> */, /* 0x32 */ /* 0x33 */ JSONSL_SPECIALf_UNSIGNED /* <3> */, /* 0x33 */ /* 0x34 */ JSONSL_SPECIALf_UNSIGNED /* <4> */, /* 0x34 */ /* 0x35 */ JSONSL_SPECIALf_UNSIGNED /* <5> */, /* 0x35 */ /* 0x36 */ JSONSL_SPECIALf_UNSIGNED /* <6> */, /* 0x36 */ /* 0x37 */ JSONSL_SPECIALf_UNSIGNED /* <7> */, /* 0x37 */ /* 0x38 */ JSONSL_SPECIALf_UNSIGNED /* <8> */, /* 0x38 */ /* 0x39 */ JSONSL_SPECIALf_UNSIGNED /* <9> */, /* 0x39 */ /* 0x3a */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x48 */ /* 0x49 */ JSONSL__INF_PROXY /* */, /* 0x49 */ /* 0x4a */ 0,0,0,0, /* 0x4d */ /* 0x4e */ JSONSL__NAN_PROXY /* */, /* 0x4e */ /* 0x4f */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x65 */ /* 0x66 */ JSONSL_SPECIALf_FALSE /* */, /* 0x66 */ /* 0x67 */ 0,0, /* 0x68 */ /* 0x69 */ JSONSL__INF_PROXY /* */, /* 0x69 */ /* 0x6a */ 0,0,0,0, /* 0x6d */ /* 0x6e */ JSONSL_SPECIALf_NULL|JSONSL__NAN_PROXY /* */, /* 0x6e */ /* 0x6f */ 0,0,0,0,0, /* 0x73 */ /* 0x74 */ JSONSL_SPECIALf_TRUE /* */, /* 0x74 */ /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */ /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */ /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */ /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */ /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0, /* 0xfe */ }; /** * Contains characters which signal the termination of any of the 'special' bareword * values. */ static int Special_Endings[0x100] = { /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */ /* 0x09 */ 1 /* */, /* 0x09 */ /* 0x0a */ 1 /* */, /* 0x0a */ /* 0x0b */ 0,0, /* 0x0c */ /* 0x0d */ 1 /* */, /* 0x0d */ /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ /* 0x20 */ 1 /* */, /* 0x20 */ /* 0x21 */ 0, /* 0x21 */ /* 0x22 */ 1 /* " */, /* 0x22 */ /* 0x23 */ 0,0,0,0,0,0,0,0,0, /* 0x2b */ /* 0x2c */ 1 /* , */, /* 0x2c */ /* 0x2d */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x39 */ /* 0x3a */ 1 /* : */, /* 0x3a */ /* 0x3b */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5a */ /* 0x5b */ 1 /* [ */, /* 0x5b */ /* 0x5c */ 1 /* \ */, /* 0x5c */ /* 0x5d */ 1 /* ] */, /* 0x5d */ /* 0x5e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7a */ /* 0x7b */ 1 /* { */, /* 0x7b */ /* 0x7c */ 0, /* 0x7c */ /* 0x7d */ 1 /* } */, /* 0x7d */ /* 0x7e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9d */ /* 0x9e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbd */ /* 0xbe */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdd */ /* 0xde */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfd */ /* 0xfe */ 0 /* 0xfe */ }; /** * This table contains entries for the allowed whitespace as per RFC 4627 */ static int Allowed_Whitespace[0x100] = { /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */ /* 0x09 */ 1 /* */, /* 0x09 */ /* 0x0a */ 1 /* */, /* 0x0a */ /* 0x0b */ 0,0, /* 0x0c */ /* 0x0d */ 1 /* */, /* 0x0d */ /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ /* 0x20 */ 1 /* */, /* 0x20 */ /* 0x21 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 */ /* 0x41 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 */ /* 0x61 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 */ /* 0x81 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0 */ /* 0xa1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xc0 */ /* 0xc1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xe0 */ /* 0xe1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xfe */ }; static const int String_No_Passthrough[0x100] = { /* 0x00 */ 1 /* */, /* 0x00 */ /* 0x01 */ 1 /* */, /* 0x01 */ /* 0x02 */ 1 /* */, /* 0x02 */ /* 0x03 */ 1 /* */, /* 0x03 */ /* 0x04 */ 1 /* */, /* 0x04 */ /* 0x05 */ 1 /* */, /* 0x05 */ /* 0x06 */ 1 /* */, /* 0x06 */ /* 0x07 */ 1 /* */, /* 0x07 */ /* 0x08 */ 1 /* */, /* 0x08 */ /* 0x09 */ 1 /* */, /* 0x09 */ /* 0x0a */ 1 /* */, /* 0x0a */ /* 0x0b */ 1 /* */, /* 0x0b */ /* 0x0c */ 1 /* */, /* 0x0c */ /* 0x0d */ 1 /* */, /* 0x0d */ /* 0x0e */ 1 /* */, /* 0x0e */ /* 0x0f */ 1 /* */, /* 0x0f */ /* 0x10 */ 1 /* */, /* 0x10 */ /* 0x11 */ 1 /* */, /* 0x11 */ /* 0x12 */ 1 /* */, /* 0x12 */ /* 0x13 */ 1 /* */, /* 0x13 */ /* 0x14 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x21 */ /* 0x22 */ 1 /* <"> */, /* 0x22 */ /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x42 */ /* 0x43 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */ /* 0x5c */ 1 /* <\> */, /* 0x5c */ /* 0x5d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7c */ /* 0x7d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9c */ /* 0x9d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbc */ /* 0xbd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdc */ /* 0xdd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfc */ /* 0xfd */ 0,0, /* 0xfe */ }; /** * Allowable two-character 'common' escapes: */ static int Allowed_Escapes[0x100] = { /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ /* 0x20 */ 0,0, /* 0x21 */ /* 0x22 */ 1 /* <"> */, /* 0x22 */ /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2e */ /* 0x2f */ 1 /* */, /* 0x2f */ /* 0x30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4f */ /* 0x50 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */ /* 0x5c */ 1 /* <\> */, /* 0x5c */ /* 0x5d */ 0,0,0,0,0, /* 0x61 */ /* 0x62 */ 1 /* */, /* 0x62 */ /* 0x63 */ 0,0,0, /* 0x65 */ /* 0x66 */ 1 /* */, /* 0x66 */ /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */ /* 0x6e */ 1 /* */, /* 0x6e */ /* 0x6f */ 0,0,0, /* 0x71 */ /* 0x72 */ 1 /* */, /* 0x72 */ /* 0x73 */ 0, /* 0x73 */ /* 0x74 */ 1 /* */, /* 0x74 */ /* 0x75 */ 1 /* */, /* 0x75 */ /* 0x76 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x95 */ /* 0x96 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb5 */ /* 0xb6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd5 */ /* 0xd6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf5 */ /* 0xf6 */ 0,0,0,0,0,0,0,0,0, /* 0xfe */ }; /** * This table contains the _values_ for a given (single) escaped character. */ static unsigned char Escape_Equivs[0x100] = { /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x3f */ /* 0x40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5f */ /* 0x60 */ 0,0, /* 0x61 */ /* 0x62 */ 8 /* */, /* 0x62 */ /* 0x63 */ 0,0,0, /* 0x65 */ /* 0x66 */ 12 /* */, /* 0x66 */ /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */ /* 0x6e */ 10 /* */, /* 0x6e */ /* 0x6f */ 0,0,0, /* 0x71 */ /* 0x72 */ 13 /* */, /* 0x72 */ /* 0x73 */ 0, /* 0x73 */ /* 0x74 */ 9 /* */, /* 0x74 */ /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */ /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */ /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */ /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */ /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0 /* 0xfe */ }; /* Definitions of above-declared static functions */ static char get_escape_equiv(unsigned c) { return Escape_Equivs[c & 0xff]; } static unsigned extract_special(unsigned c) { return Special_Table[c & 0xff]; } static int is_special_end(unsigned c) { return Special_Endings[c & 0xff]; } static int is_allowed_whitespace(unsigned c) { return c == ' ' || Allowed_Whitespace[c & 0xff]; } static int is_allowed_escape(unsigned c) { return Allowed_Escapes[c & 0xff]; } static int is_simple_char(unsigned c) { return !String_No_Passthrough[c & 0xff]; } /* Clean up all our macros! */ #undef INCR_METRIC #undef INCR_GENERIC #undef INCR_STRINGY_CATCH #undef CASE_DIGITS #undef INVOKE_ERROR #undef STACK_PUSH #undef STACK_POP_NOPOS #undef STACK_POP #undef CALLBACK_AND_POP_NOPOS #undef CALLBACK_AND_POP #undef SPECIAL_POP #undef CUR_CHAR #undef DO_CALLBACK #undef ENSURE_HVAL #undef VERIFY_SPECIAL #undef STATE_SPECIAL_LENGTH #undef IS_NORMAL_NUMBER #undef STATE_NUM_LAST #undef FASTPARSE_EXHAUSTED #undef FASTPARSE_BREAK mongodb-1.21.0/src/libmongoc/src/libbson/src/jsonsl/jsonsl.h0000644000175100001660000007444614760300420020713 0ustar /** * JSON Simple/Stacked/Stateful Lexer. * - Does not buffer data * - Maintains state * - Callback oriented * - Lightweight and fast. One source file and one header file * * Copyright (C) 2012-2015 Mark Nunberg * See included LICENSE file for license details. */ #include #ifndef JSONSL_H_ #define JSONSL_H_ #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifdef JSONSL_USE_WCHAR typedef jsonsl_char_t wchar_t; typedef jsonsl_uchar_t unsigned wchar_t; #else typedef char jsonsl_char_t; typedef unsigned char jsonsl_uchar_t; #endif /* JSONSL_USE_WCHAR */ #ifdef JSONSL_PARSE_NAN #define JSONSL__NAN_PROXY JSONSL_SPECIALf_NAN #define JSONSL__INF_PROXY JSONSL_SPECIALf_INF #else #define JSONSL__NAN_PROXY 0 #define JSONSL__INF_PROXY 0 #endif /* Stolen from http-parser.h, and possibly others */ #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #if !defined(_MSC_VER) || _MSC_VER<1400 typedef unsigned int size_t; typedef int ssize_t; #endif #else #include #endif #if (!defined(JSONSL_STATE_GENERIC)) && (!defined(JSONSL_STATE_USER_FIELDS)) #define JSONSL_STATE_GENERIC #endif /* !defined JSONSL_STATE_GENERIC */ #ifdef JSONSL_STATE_GENERIC #define JSONSL_STATE_USER_FIELDS #endif /* JSONSL_STATE_GENERIC */ /* Additional fields for component object */ #ifndef JSONSL_JPR_COMPONENT_USER_FIELDS #define JSONSL_JPR_COMPONENT_USER_FIELDS #endif #ifndef JSONSL_API /** * We require a /DJSONSL_DLL so that users already using this as a static * or embedded library don't get confused */ #if defined(_WIN32) && defined(JSONSL_DLL) #define JSONSL_API __declspec(dllexport) #else #define JSONSL_API #endif /* _WIN32 */ #endif /* !JSONSL_API */ #ifndef JSONSL_INLINE #if defined(_MSC_VER) #define JSONSL_INLINE __inline #elif defined(__GNUC__) #define JSONSL_INLINE __inline__ #else #define JSONSL_INLINE inline #endif /* _MSC_VER or __GNUC__ */ #endif /* JSONSL_INLINE */ #define JSONSL_MAX_LEVELS 512 struct jsonsl_st; typedef struct jsonsl_st *jsonsl_t; typedef struct jsonsl_jpr_st* jsonsl_jpr_t; /** * This flag is true when AND'd against a type whose value * must be in "quoutes" i.e. T_HKEY and T_STRING */ #define JSONSL_Tf_STRINGY 0xffff00 /** * Constant representing the special JSON types. * The values are special and aid in speed (the OBJECT and LIST * values are the char literals of their openings). * * Their actual value is a character which attempts to resemble * some mnemonic reference to the actual type. * * If new types are added, they must fit into the ASCII printable * range (so they should be AND'd with 0x7f and yield something * meaningful) */ #define JSONSL_XTYPE \ X(STRING, '"'|JSONSL_Tf_STRINGY) \ X(HKEY, '#'|JSONSL_Tf_STRINGY) \ X(OBJECT, '{') \ X(LIST, '[') \ X(SPECIAL, '^') \ X(UESCAPE, 'u') typedef enum { #define X(o, c) \ JSONSL_T_##o = c, JSONSL_XTYPE JSONSL_T_UNKNOWN = '?', /* Abstract 'root' object */ JSONSL_T_ROOT = 0 #undef X } jsonsl_type_t; /** * Subtypes for T_SPECIAL. We define them as flags * because more than one type can be applied to a * given object. */ #define JSONSL_XSPECIAL \ X(NONE, 0) \ X(SIGNED, 1<<0) \ X(UNSIGNED, 1<<1) \ X(TRUE, 1<<2) \ X(FALSE, 1<<3) \ X(NULL, 1<<4) \ X(FLOAT, 1<<5) \ X(EXPONENT, 1<<6) \ X(NONASCII, 1<<7) \ X(NAN, 1<<8) \ X(INF, 1<<9) typedef enum { #define X(o,b) \ JSONSL_SPECIALf_##o = b, JSONSL_XSPECIAL #undef X /* Handy flags for checking */ JSONSL_SPECIALf_UNKNOWN = 1 << 10, /** @private Private */ JSONSL_SPECIALf_ZERO = 1 << 11 | JSONSL_SPECIALf_UNSIGNED, /** @private */ JSONSL_SPECIALf_DASH = 1 << 12, /** @private */ JSONSL_SPECIALf_POS_INF = (JSONSL_SPECIALf_INF), JSONSL_SPECIALf_NEG_INF = (JSONSL_SPECIALf_INF|JSONSL_SPECIALf_SIGNED), /** Type is numeric */ JSONSL_SPECIALf_NUMERIC = (JSONSL_SPECIALf_SIGNED| JSONSL_SPECIALf_UNSIGNED), /** Type is a boolean */ JSONSL_SPECIALf_BOOLEAN = (JSONSL_SPECIALf_TRUE|JSONSL_SPECIALf_FALSE), /** Type is an "extended", not integral type (but numeric) */ JSONSL_SPECIALf_NUMNOINT = (JSONSL_SPECIALf_FLOAT|JSONSL_SPECIALf_EXPONENT|JSONSL_SPECIALf_NAN |JSONSL_SPECIALf_INF) } jsonsl_special_t; /** * These are the various types of stack (or other) events * which will trigger a callback. * Like the type constants, this are also mnemonic */ #define JSONSL_XACTION \ X(PUSH, '+') \ X(POP, '-') \ X(UESCAPE, 'U') \ X(ERROR, '!') typedef enum { #define X(a,c) \ JSONSL_ACTION_##a = c, JSONSL_XACTION JSONSL_ACTION_UNKNOWN = '?' #undef X } jsonsl_action_t; /** * Various errors which may be thrown while parsing JSON */ #define JSONSL_XERR \ /* Trailing garbage characters */ \ X(GARBAGE_TRAILING) \ /* We were expecting a 'special' (numeric, true, false, null) */ \ X(SPECIAL_EXPECTED) \ /* The 'special' value was incomplete */ \ X(SPECIAL_INCOMPLETE) \ /* Found a stray token */ \ X(STRAY_TOKEN) \ /* We were expecting a token before this one */ \ X(MISSING_TOKEN) \ /* Cannot insert because the container is not ready */ \ X(CANT_INSERT) \ /* Found a '\' outside a string */ \ X(ESCAPE_OUTSIDE_STRING) \ /* Found a ':' outside of a hash */ \ X(KEY_OUTSIDE_OBJECT) \ /* found a string outside of a container */ \ X(STRING_OUTSIDE_CONTAINER) \ /* Found a null byte in middle of string */ \ X(FOUND_NULL_BYTE) \ /* Current level exceeds limit specified in constructor */ \ X(LEVELS_EXCEEDED) \ /* Got a } as a result of an opening [ or vice versa */ \ X(BRACKET_MISMATCH) \ /* We expected a key, but got something else instead */ \ X(HKEY_EXPECTED) \ /* We got an illegal control character (bad whitespace or something) */ \ X(WEIRD_WHITESPACE) \ /* Found a \u-escape, but there were less than 4 following hex digits */ \ X(UESCAPE_TOOSHORT) \ /* Invalid two-character escape */ \ X(ESCAPE_INVALID) \ /* Trailing comma */ \ X(TRAILING_COMMA) \ /* An invalid number was passed in a numeric field */ \ X(INVALID_NUMBER) \ /* Value is missing for object */ \ X(VALUE_EXPECTED) \ /* The following are for JPR Stuff */ \ \ /* Found a literal '%' but it was only followed by a single valid hex digit */ \ X(PERCENT_BADHEX) \ /* jsonpointer URI is malformed '/' */ \ X(JPR_BADPATH) \ /* Duplicate slash */ \ X(JPR_DUPSLASH) \ /* No leading root */ \ X(JPR_NOROOT) \ /* Allocation failure */ \ X(ENOMEM) \ /* Invalid unicode codepoint detected (in case of escapes) */ \ X(INVALID_CODEPOINT) typedef enum { JSONSL_ERROR_SUCCESS = 0, #define X(e) \ JSONSL_ERROR_##e, JSONSL_XERR #undef X JSONSL_ERROR_GENERIC } jsonsl_error_t; /** * A state is a single level of the stack. * Non-private data (i.e. the 'data' field, see the STATE_GENERIC section) * will remain in tact until the item is popped. * * As a result, it means a parent state object may be accessed from a child * object, (the parents fields will all be valid). This allows a user to create * an ad-hoc hierarchy on top of the JSON one. * */ struct jsonsl_state_st { /** * The JSON object type */ unsigned type; /** If this element is special, then its extended type is here */ unsigned special_flags; /** * The position (in terms of number of bytes since the first call to * jsonsl_feed()) at which the state was first pushed. This includes * opening tokens, if applicable. * * @note For strings (i.e. type & JSONSL_Tf_STRINGY is nonzero) this will * be the position of the first quote. * * @see jsonsl_st::pos which contains the _current_ position and can be * used during a POP callback to get the length of the element. */ size_t pos_begin; /**FIXME: This is redundant as the same information can be derived from * jsonsl_st::pos at pop-time */ size_t pos_cur; /** * Level of recursion into nesting. This is mainly a convenience * variable, as this can technically be deduced from the lexer's * level parameter (though the logic is not that simple) */ unsigned int level; /** * how many elements in the object/list. * For objects (hashes), an element is either * a key or a value. Thus for one complete pair, * nelem will be 2. * * For special types, this will hold the sum of the digits. * This only holds true for values which are simple signed/unsigned * numbers. Otherwise a special flag is set, and extra handling is not * performed. */ uint64_t nelem; /*TODO: merge this and special_flags into a union */ /** * Useful for an opening nest, this will prevent a callback from being * invoked on this item or any of its children */ int ignore_callback; /** * Counter which is incremented each time an escape ('\') is encountered. * This is used internally for non-string types and should only be * inspected by the user if the state actually represents a string * type. */ unsigned int nescapes; /** * Put anything you want here. if JSONSL_STATE_USER_FIELDS is here, then * the macro expansion happens here. * * You can use these fields to store hierarchical or 'tagging' information * for specific objects. * * See the documentation above for the lifetime of the state object (i.e. * if the private data points to allocated memory, it should be freed * when the object is popped, as the state object will be re-used) */ #ifndef JSONSL_STATE_GENERIC JSONSL_STATE_USER_FIELDS #else /** * Otherwise, this is a simple void * pointer for anything you want */ void *data; #endif /* JSONSL_STATE_USER_FIELDS */ }; /**Gets the number of elements in the list. * @param st The state. Must be of type JSONSL_T_LIST * @return number of elements in the list */ #define JSONSL_LIST_SIZE(st) ((st)->nelem) /**Gets the number of key-value pairs in an object * @param st The state. Must be of type JSONSL_T_OBJECT * @return the number of key-value pairs in the object */ #define JSONSL_OBJECT_SIZE(st) ((st)->nelem / 2) /**Gets the numeric value. * @param st The state. Must be of type JSONSL_T_SPECIAL and * special_flags must have the JSONSL_SPECIALf_NUMERIC flag * set. * @return the numeric value of the state. */ #define JSONSL_NUMERIC_VALUE(st) ((st)->nelem) /* * So now we need some special structure for keeping the * JPR info in sync. Preferably all in a single block * of memory (there's no need for separate allocations. * So we will define a 'table' with the following layout * * Level nPosbl JPR1_last JPR2_last JPR3_last * * 0 1 NOMATCH POSSIBLE POSSIBLE * 1 0 NOMATCH NOMATCH COMPLETE * [ table ends here because no further path is possible] * * Where the JPR..n corresponds to the number of JPRs * requested, and nPosble is a quick flag to determine * * the number of possibilities. In the future this might * be made into a proper 'jump' table, * * Since we always mark JPRs from the higher levels descending * into the lower ones, a prospective child match would first * look at the parent table to check the possibilities, and then * see which ones were possible.. * * Thus, the size of this blob would be (and these are all ints here) * nLevels * nJPR * 2. * * the 'Width' of the table would be nJPR*2, and the 'height' would be * nlevels */ /** * This is called when a stack change ocurs. * * @param jsn The lexer * @param action The type of action, this can be PUSH or POP * @param state A pointer to the stack currently affected by the action * @param at A pointer to the position of the input buffer which triggered * this action. */ typedef void (*jsonsl_stack_callback)( jsonsl_t jsn, jsonsl_action_t action, struct jsonsl_state_st* state, const jsonsl_char_t *at); /** * This is called when an error is encountered. * Sometimes it's possible to 'erase' characters (by replacing them * with whitespace). If you think you have corrected the error, you * can return a true value, in which case the parser will backtrack * and try again. * * @param jsn The lexer * @param error The error which was thrown * @param state the current state * @param a pointer to the position of the input buffer which triggered * the error. Note that this is not const, this is because you have the * possibility of modifying the character in an attempt to correct the * error * * @return zero to bail, nonzero to try again (this only makes sense if * the input buffer has been modified by this callback) */ typedef int (*jsonsl_error_callback)( jsonsl_t jsn, jsonsl_error_t error, struct jsonsl_state_st* state, jsonsl_char_t *at); struct jsonsl_st { /** Public, read-only */ /** This is the current level of the stack */ unsigned int level; /** Flag set to indicate we should stop processing */ unsigned int stopfl; /** * This is the current position, relative to the beginning * of the stream. */ size_t pos; /** This is the 'bytes' variable passed to feed() */ const jsonsl_char_t *base; /** Callback invoked for PUSH actions */ jsonsl_stack_callback action_callback_PUSH; /** Callback invoked for POP actions */ jsonsl_stack_callback action_callback_POP; /** Default callback for any action, if neither PUSH or POP callbacks are defined */ jsonsl_stack_callback action_callback; /** * Do not invoke callbacks for objects deeper than this level. * NOTE: This field establishes the lower bound for ignored callbacks, * and is thus misnamed. `min_ignore_level` would actually make more * sense, but we don't want to break API. */ unsigned int max_callback_level; /** The error callback. Invoked when an error happens. Should not be NULL */ jsonsl_error_callback error_callback; /* these are boolean flags you can modify. You will be called * about notification for each of these types if the corresponding * variable is true. */ /** * @name Callback Booleans. * These determine whether a callback is to be invoked for certain types of objects * @{*/ /** Boolean flag to enable or disable the invokcation for events on this type*/ int call_SPECIAL; int call_OBJECT; int call_LIST; int call_STRING; int call_HKEY; /*@}*/ /** * @name u-Escape handling * Special handling for the \\u-f00d type sequences. These are meant * to be translated back into the corresponding octet(s). * A special callback (if set) is invoked with *at=='u'. An application * may wish to temporarily suspend parsing and handle the 'u-' sequence * internally (or not). */ /*@{*/ /** Callback to be invoked for a u-escape */ jsonsl_stack_callback action_callback_UESCAPE; /** Boolean flag, whether to invoke the callback */ int call_UESCAPE; /** Boolean flag, whether we should return after encountering a u-escape: * the callback is invoked and then we return if this is true */ int return_UESCAPE; /*@}*/ struct { int allow_trailing_comma; } options; /** Put anything here */ void *data; /*@{*/ /** Private */ int in_escape; char expecting; char tok_last; int can_insert; unsigned int levels_max; #ifndef JSONSL_NO_JPR size_t jpr_count; jsonsl_jpr_t *jprs; /* Root pointer for JPR matching information */ size_t *jpr_root; #endif /* JSONSL_NO_JPR */ /*@}*/ /** * This is the stack. Its upper bound is levels_max, or the * nlevels argument passed to jsonsl_new. If you modify this structure, * make sure that this member is last. */ struct jsonsl_state_st stack[1]; }; /** * Creates a new lexer object, with capacity for recursion up to nlevels * * @param nlevels maximum recursion depth */ JSONSL_API jsonsl_t jsonsl_new(int nlevels); /** * Feeds data into the lexer. * * @param jsn the lexer object * @param bytes new data to be fed * @param nbytes size of new data */ JSONSL_API void jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes); /** * Resets the internal parser state. This does not free the parser * but does clean it internally, so that the next time feed() is called, * it will be treated as a new stream * * @param jsn the lexer */ JSONSL_API void jsonsl_reset(jsonsl_t jsn); /** * Frees the lexer, cleaning any allocated memory taken * * @param jsn the lexer */ JSONSL_API void jsonsl_destroy(jsonsl_t jsn); /** * Gets the 'parent' element, given the current one * * @param jsn the lexer * @param cur the current nest, which should be a struct jsonsl_nest_st */ static JSONSL_INLINE struct jsonsl_state_st *jsonsl_last_state(const jsonsl_t jsn, const struct jsonsl_state_st *state) { /* Don't complain about overriding array bounds */ if (state->level > 1) { return jsn->stack + state->level - 1; } else { return NULL; } } /** * Gets the state of the last fully consumed child of this parent. This is * only valid in the parent's POP callback. * * @param the lexer * @return A pointer to the child. */ static JSONSL_INLINE struct jsonsl_state_st *jsonsl_last_child(const jsonsl_t jsn, const struct jsonsl_state_st *parent) { return jsn->stack + (parent->level + 1); } /**Call to instruct the parser to stop parsing and return. This is valid * only from within a callback */ static JSONSL_INLINE void jsonsl_stop(jsonsl_t jsn) { jsn->stopfl = 1; } /** * This enables receiving callbacks on all events. Doesn't do * anything special but helps avoid some boilerplate. * This does not touch the UESCAPE callbacks or flags. */ static JSONSL_INLINE void jsonsl_enable_all_callbacks(jsonsl_t jsn) { jsn->call_HKEY = 1; jsn->call_STRING = 1; jsn->call_OBJECT = 1; jsn->call_SPECIAL = 1; jsn->call_LIST = 1; } /** * A macro which returns true if the current state object can * have children. This means a list type or an object type. */ #define JSONSL_STATE_IS_CONTAINER(state) \ (state->type == JSONSL_T_OBJECT || state->type == JSONSL_T_LIST) /** * These two functions, dump a string representation * of the error or type, respectively. They will never * return NULL */ JSONSL_API const char* jsonsl_strerror(jsonsl_error_t err); JSONSL_API const char* jsonsl_strtype(jsonsl_type_t jt); /** * Dumps global metrics to the screen. This is a noop unless * jsonsl was compiled with JSONSL_USE_METRICS */ JSONSL_API void jsonsl_dump_global_metrics(void); /* This macro just here for editors to do code folding */ #ifndef JSONSL_NO_JPR /** * @name JSON Pointer API * * JSONPointer API. This isn't really related to the lexer (at least not yet) * JSONPointer provides an extremely simple specification for providing * locations within JSON objects. We will extend it a bit and allow for * providing 'wildcard' characters by which to be able to 'query' the stream. * * See http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00 * * Currently I'm implementing the 'single query' API which can only use a single * query component. In the future I will integrate my yet-to-be-published * Boyer-Moore-esque prefix searching implementation, in order to allow * multiple paths to be merged into one for quick and efficient searching. * * * JPR (as we'll refer to it within the source) can be used by splitting * the components into multiple sections, and incrementally 'track' each * component. When JSONSL delivers a 'pop' callback for a string, or a 'push' * callback for an object, we will check to see whether the index matching * the component corresponding to the current level contains a match * for our path. * * In order to do this properly, a structure must be maintained within the * parent indicating whether its children are possible matches. This flag * will be 'inherited' by call children which may conform to the match * specification, and discarded by all which do not (thereby eliminating * their children from inheriting it). * * A successful match is a complete one. One can provide multiple paths with * multiple levels of matches e.g. * /foo/bar/baz/^/blah * * @{ */ /** The wildcard character */ #ifndef JSONSL_PATH_WILDCARD_CHAR #define JSONSL_PATH_WILDCARD_CHAR '^' #endif /* WILDCARD_CHAR */ #define JSONSL_XMATCH \ X(COMPLETE,1) \ X(POSSIBLE,0) \ X(NOMATCH,-1) \ X(TYPE_MISMATCH, -2) typedef enum { #define X(T,v) \ JSONSL_MATCH_##T = v, JSONSL_XMATCH #undef X JSONSL_MATCH_UNKNOWN } jsonsl_jpr_match_t; typedef enum { JSONSL_PATH_STRING = 1, JSONSL_PATH_WILDCARD, JSONSL_PATH_NUMERIC, JSONSL_PATH_ROOT, /* Special */ JSONSL_PATH_INVALID = -1, JSONSL_PATH_NONE = 0 } jsonsl_jpr_type_t; struct jsonsl_jpr_component_st { /** The string the component points to */ char *pstr; /** if this is a numeric type, the number is 'cached' here */ unsigned long idx; /** The length of the string */ size_t len; /** The type of component (NUMERIC or STRING) */ jsonsl_jpr_type_t ptype; /** Set this to true to enforce type checking between dict keys and array * indices. jsonsl_jpr_match() will return TYPE_MISMATCH if it detects * that an array index is actually a child of a dictionary. */ short is_arridx; /* Extra fields (for more advanced searches. Default is empty) */ JSONSL_JPR_COMPONENT_USER_FIELDS }; struct jsonsl_jpr_st { /** Path components */ struct jsonsl_jpr_component_st *components; size_t ncomponents; /**Type of the match to be expected. If nonzero, will be compared against * the actual type */ unsigned match_type; /** Base of allocated string for components */ char *basestr; /** The original match string. Useful for returning to the user */ char *orig; size_t norig; }; /** * Create a new JPR object. * * @param path the JSONPointer path specification. * @param errp a pointer to a jsonsl_error_t. If this function returns NULL, * then more details will be in this variable. * * @return a new jsonsl_jpr_t object, or NULL on error. */ JSONSL_API jsonsl_jpr_t jsonsl_jpr_new(const char *path, jsonsl_error_t *errp); /** * Destroy a JPR object */ JSONSL_API void jsonsl_jpr_destroy(jsonsl_jpr_t jpr); /** * Match a JSON object against a type and specific level * * @param jpr the JPR object * @param parent_type the type of the parent (should be T_LIST or T_OBJECT) * @param parent_level the level of the parent * @param key the 'key' of the child. If the parent is an array, this should be * empty. * @param nkey - the length of the key. If the parent is an array (T_LIST), then * this should be the current index. * * NOTE: The key of the child means any kind of associative data related to the * element. Thus: <<< { "foo" : [ >>, * the opening array's key is "foo". * * @return a status constant. This indicates whether a match was excluded, possible, * or successful. */ JSONSL_API jsonsl_jpr_match_t jsonsl_jpr_match(jsonsl_jpr_t jpr, unsigned int parent_type, unsigned int parent_level, const char *key, size_t nkey); /** * Alternate matching algorithm. This matching algorithm does not use * JSONPointer but relies on a more structured searching mechanism. It * assumes that there is a clear distinction between array indices and * object keys. In this case, the jsonsl_path_component_st::ptype should * be set to @ref JSONSL_PATH_NUMERIC for an array index (the * jsonsl_path_comonent_st::is_arridx field will be removed in a future * version). * * @param jpr The path * @param parent The parent structure. Can be NULL if this is the root object * @param child The child structure. Should not be NULL * @param key Object key, if an object * @param nkey Length of object key * @return Status constant if successful * * @note * For successful matching, both the key and the path itself should be normalized * to contain 'proper' utf8 sequences rather than utf16 '\uXXXX' escapes. This * should currently be done in the application. Another version of this function * may use a temporary buffer in such circumstances (allocated by the application). * * Since this function also checks the state of the child, it should only * be called on PUSH callbacks, and not POP callbacks */ JSONSL_API jsonsl_jpr_match_t jsonsl_path_match(jsonsl_jpr_t jpr, const struct jsonsl_state_st *parent, const struct jsonsl_state_st *child, const char *key, size_t nkey); /** * Associate a set of JPR objects with a lexer instance. * This should be called before the lexer has been fed any data (and * behavior is undefined if you don't adhere to this). * * After using this function, you may subsequently call match_state() on * given states (presumably from within the callbacks). * * Note that currently the first JPR is the quickest and comes * pre-allocated with the state structure. Further JPR objects * are chained. * * @param jsn The lexer * @param jprs An array of jsonsl_jpr_t objects * @param njprs How many elements in the jprs array. */ JSONSL_API void jsonsl_jpr_match_state_init(jsonsl_t jsn, jsonsl_jpr_t *jprs, size_t njprs); /** * This follows the same semantics as the normal match, * except we infer parent and type information from the relevant state objects. * The match status (for all possible JPR objects) is set in the *out parameter. * * If a match has succeeded, then its JPR object will be returned. In all other * instances, NULL is returned; * * @param jpr The jsonsl_jpr_t handle * @param state The jsonsl_state_st which is a candidate * @param key The hash key (if applicable, can be NULL if parent is list) * @param nkey Length of hash key (if applicable, can be zero if parent is list) * @param out A pointer to a jsonsl_jpr_match_t. This will be populated with * the match result * * @return If a match was completed in full, then the JPR object containing * the matching path will be returned. Otherwise, the return is NULL (note, this * does not mean matching has failed, it can still be part of the match: check * the out parameter). */ JSONSL_API jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn, struct jsonsl_state_st *state, const char *key, size_t nkey, jsonsl_jpr_match_t *out); /** * Cleanup any memory allocated and any states set by * match_state_init() and match_state() * @param jsn The lexer */ JSONSL_API void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn); /** * Return a string representation of the match result returned by match() */ JSONSL_API const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match); /* @}*/ /** * Utility function to convert escape sequences into their original form. * * The decoders I've sampled do not seem to specify a standard behavior of what * to escape/unescape. * * RFC 4627 Mandates only that the quoute, backslash, and ASCII control * characters (0x00-0x1f) be escaped. It is often common for applications * to escape a '/' - however this may also be desired behavior. the JSON * spec is not clear on this, and therefore jsonsl leaves it up to you. * * Additionally, sometimes you may wish to _normalize_ JSON. This is specifically * true when dealing with 'u-escapes' which can be expressed perfectly fine * as utf8. One use case for normalization is JPR string comparison, in which * case two effectively equivalent strings may not match because one is using * u-escapes and the other proper utf8. To normalize u-escapes only, pass in * an empty `toEscape` table, enabling only the `u` index. * * @param in The input string. * @param out An allocated output (should be the same size as in) * @param len the size of the buffer * @param toEscape - A sparse array of characters to unescape. Characters * which are not present in this array, e.g. toEscape['c'] == 0 will be * ignored and passed to the output in their original form. * @param oflags If not null, and a \uXXXX escape expands to a non-ascii byte, * then this variable will have the SPECIALf_NONASCII flag on. * * @param err A pointer to an error variable. If an error ocurrs, it will be * set in this variable * @param errat If not null and an error occurs, this will be set to point * to the position within the string at which the offending character was * encountered. * * @return The effective size of the output buffer. * * @note * This function now encodes the UTF8 equivalents of utf16 escapes (i.e. * 'u-escapes'). Previously this would encode the escapes as utf16 literals, * which while still correct in some sense was confusing for many (especially * considering that the inputs were variations of char). * * @note * The output buffer will never be larger than the input buffer, since * standard escape sequences (i.e. '\t') occupy two bytes in the source * but only one byte (when unescaped) in the output. Likewise u-escapes * (i.e. \uXXXX) will occupy six bytes in the source, but at the most * two bytes when escaped. */ JSONSL_API size_t jsonsl_util_unescape_ex(const char *in, char *out, size_t len, const int toEscape[128], unsigned *oflags, jsonsl_error_t *err, const char **errat); /** * Convenience macro to avoid passing too many parameters */ #define jsonsl_util_unescape(in, out, len, toEscape, err) \ jsonsl_util_unescape_ex(in, out, len, toEscape, NULL, err, NULL) #endif /* JSONSL_NO_JPR */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JSONSL_H_ */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mcd-azure.c0000644000175100001660000001532214760300420021544 0ustar /** * Copyright 2009-present MongoDB, 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. */ #include #include #include #define AZURE_API_VERSION "2018-02-01" static const char *const DEFAULT_METADATA_PATH = "/metadata/identity/oauth2/" "token?api-version=" AZURE_API_VERSION "&resource=https%3A%2F%2Fvault.azure.net"; void mcd_azure_imds_request_init (mcd_azure_imds_request *req, const char *const opt_imds_host, int opt_port, const char *const opt_extra_headers) { BSON_ASSERT_PARAM (req); _mongoc_http_request_init (&req->req); // The HTTP host of the IMDS server req->req.host = req->_owned_host = bson_strdup (opt_imds_host ? opt_imds_host : "169.254.169.254"); if (opt_port) { req->req.port = opt_port; } else { req->req.port = 80; } // No body req->req.body = ""; // We GET req->req.method = "GET"; // 'Metadata: true' is required req->req.extra_headers = req->_owned_headers = bson_strdup_printf ("Metadata: true\r\n" "Accept: application/json\r\n%s", opt_extra_headers ? opt_extra_headers : ""); // The default path is suitable. In the future, we may want to add query // parameters to disambiguate a managed identity. req->req.path = req->_owned_path = bson_strdup (DEFAULT_METADATA_PATH); } void mcd_azure_imds_request_destroy (mcd_azure_imds_request *req) { BSON_ASSERT_PARAM (req); bson_free (req->_owned_path); bson_free (req->_owned_host); bson_free (req->_owned_headers); *req = MCD_AZURE_IMDS_REQUEST_INIT; } bool mcd_azure_access_token_try_init_from_json_str (mcd_azure_access_token *out, const char *json, int len, bson_error_t *error) { BSON_ASSERT_PARAM (out); BSON_ASSERT_PARAM (json); bool okay = false; if (len < 0) { // Detect from a null-terminated string len = (int) strlen (json); } // Zero the output *out = (mcd_azure_access_token){0}; // Parse the JSON data bson_t bson; if (!bson_init_from_json (&bson, json, len, error)) { return false; } bson_iter_t iter; // access_token bool found = bson_iter_init_find (&iter, &bson, "access_token"); const char *const access_token = !found ? NULL : bson_iter_utf8 (&iter, NULL); // resource found = bson_iter_init_find (&iter, &bson, "resource"); const char *const resource = !found ? NULL : bson_iter_utf8 (&iter, NULL); // token_type found = bson_iter_init_find (&iter, &bson, "token_type"); const char *const token_type = !found ? NULL : bson_iter_utf8 (&iter, NULL); // expires_in found = bson_iter_init_find (&iter, &bson, "expires_in"); uint32_t expires_in_len = 0; const char *const expires_in_str = !found ? NULL : bson_iter_utf8 (&iter, &expires_in_len); if (!(access_token && resource && token_type && expires_in_str)) { bson_set_error (error, MONGOC_ERROR_AZURE, MONGOC_ERROR_KMS_SERVER_BAD_JSON, "One or more required JSON properties are missing/invalid: data: %.*s", len, json); } else { // Set the output, duplicate each string *out = (mcd_azure_access_token){ .access_token = bson_strdup (access_token), .resource = bson_strdup (resource), .token_type = bson_strdup (token_type), }; // "expires_in" encodes the number of seconds since the issue time for // which the token will be valid. strtoll() will saturate on range errors // and return zero on parse errors. char *parse_end; long long s = strtoll (expires_in_str, &parse_end, 0); if (parse_end != expires_in_str + expires_in_len) { // Did not parse the entire string. Bad bson_set_error (error, MONGOC_ERROR_AZURE, MONGOC_ERROR_KMS_SERVER_BAD_JSON, "Invalid 'expires_in' string \"%.*s\" from IMDS server", mcommon_in_range_unsigned (int, expires_in_len) ? (int) expires_in_len : INT_MAX, expires_in_str); } else { out->expires_in = mcd_seconds (s); okay = true; } } bson_destroy (&bson); return okay; } void mcd_azure_access_token_destroy (mcd_azure_access_token *c) { bson_free (c->access_token); bson_free (c->resource); bson_free (c->token_type); c->access_token = NULL; c->resource = NULL; c->token_type = NULL; } bool mcd_azure_access_token_from_imds (mcd_azure_access_token *const out, const char *const opt_imds_host, int opt_port, const char *opt_extra_headers, bson_error_t *error) { BSON_ASSERT_PARAM (out); bool okay = false; // Clear the output *out = (mcd_azure_access_token){0}; mongoc_http_response_t resp; _mongoc_http_response_init (&resp); mcd_azure_imds_request req = MCD_AZURE_IMDS_REQUEST_INIT; mcd_azure_imds_request_init (&req, opt_imds_host, opt_port, opt_extra_headers); if (!_mongoc_http_send (&req.req, 3 * 1000, false, NULL, &resp, error)) { goto fail; } // We only accept an HTTP 200 as a success if (resp.status != 200) { bson_set_error (error, MONGOC_ERROR_AZURE, MONGOC_ERROR_KMS_SERVER_HTTP, "Error from Azure IMDS server while looking for " "Managed Identity access token: %.*s", resp.body_len, resp.body); goto fail; } // Parse the token from the response JSON if (!mcd_azure_access_token_try_init_from_json_str (out, resp.body, resp.body_len, error)) { goto fail; } okay = true; fail: mcd_azure_imds_request_destroy (&req); _mongoc_http_response_cleanup (&resp); return okay; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mcd-azure.h0000644000175100001660000001114714760300420021552 0ustar /** * Copyright 2009-present MongoDB, 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. */ #ifndef MCD_AZURE_H_INCLUDED #define MCD_AZURE_H_INCLUDED #include #include #include #include /** * @brief An Azure OAuth2 access token obtained from the Azure API */ typedef struct mcd_azure_access_token { /// The access token string char *access_token; /// The resource of the token (the Azure resource for which it is valid) char *resource; /// The HTTP type of the token char *token_type; /// The duration after which it will the token will expires. This is relative /// to the "issue time" of the token. mcd_duration expires_in; } mcd_azure_access_token; /** * @brief Try to parse an Azure access token from an IMDS metadata JSON response * * @param out The token to initialize. Should be uninitialized. Must later be * destroyed by the caller. * @param json The JSON string body * @param len The length of 'body' * @param error An output parameter for errors * @retval true If 'out' was successfully initialized to a token. * @retval false Otherwise * * @note The 'out' token must later be given to @ref * mcd_azure_access_token_destroy */ bool mcd_azure_access_token_try_init_from_json_str (mcd_azure_access_token *out, const char *json, int len, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; /** * @brief Destroy and zero-fill an access token object * * @param token The access token to destroy */ void mcd_azure_access_token_destroy (mcd_azure_access_token *token); /** * @brief An Azure IMDS HTTP request */ typedef struct mcd_azure_imds_request { /// The underlying HTTP request object to be sent mongoc_http_request_t req; char *_owned_path; char *_owned_host; char *_owned_headers; } mcd_azure_imds_request; #define MCD_AZURE_IMDS_REQUEST_INIT \ (mcd_azure_imds_request) \ { \ .req = {0}, ._owned_path = NULL, ._owned_host = NULL, ._owned_headers = NULL, \ } /** * @brief Initialize a new IMDS HTTP request * * @param out The object to initialize * @param opt_imds_host (Optional) the IP host of the IMDS server * @param opt_port (Optional) The port of the IMDS HTTP server (default is 80) * @param opt_extra_headers (Optional) Set extra HTTP headers for the request * * @note the request must later be destroyed with mcd_azure_imds_request_destroy * @note Currently only supports the vault.azure.net resource */ void mcd_azure_imds_request_init (mcd_azure_imds_request *req, const char *const opt_imds_host, int opt_port, const char *const opt_extra_headers); /** * @brief Destroy an IMDS request created with mcd_azure_imds_request_init() * * @param req */ void mcd_azure_imds_request_destroy (mcd_azure_imds_request *req); /** * @brief Attempt to obtain a new OAuth2 access token from an Azure IMDS HTTP * server. * * @param out The output parameter for the obtained token. Must later be * destroyed * @param opt_imds_host (Optional) Override the IP host of the IMDS server * @param opt_port (Optional) The port of the IMDS HTTP server (default is 80) * @param opt_extra_headers (Optional) Set extra HTTP headers for the request * @param error Output parameter for errors * @retval true Upon success * @retval false Otherwise. Sets an error via `error` * * @note Currently only supports the vault.azure.net resource */ bool mcd_azure_access_token_from_imds (mcd_azure_access_token *const out, const char *const opt_imds_host, int opt_port, const char *opt_extra_headers, bson_error_t *error); #endif // MCD_AZURE_H_INCLUDED mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mcd-integer.h0000644000175100001660000002610014760300420022054 0ustar /** * Copyright 2009-present MongoDB, 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. */ #ifndef MCD_INTEGER_H_INCLUDED #define MCD_INTEGER_H_INCLUDED #include #include #include #include /// Return 'true' iff (left * right) would overflow with int64 static BSON_INLINE bool _mcd_i64_mul_would_overflow (int64_t left, int64_t right) { if (right == -1) { // We will perform an integer division, and only (MIN / -1) is undefined // for integer division. return left == INT64_MIN; } if (right == 0) { // Multiplication by zero never overflows, and we cannot divide by zero return false; } // From here on, all integer division by 'right' is well-defined if (left > 0) { if (right > 0) { /** Given: left > 0 and: right > 0 then: left * right > 0 THEN: left * right > MIN Define: max_fac = MAX / right then: max_fac * right = (MAX / right) * right then: max_fac * right = MAX */ const int64_t max_fac = INT64_MAX / right; if (left > max_fac) { /** Given: left > max_fac then: left * right > max_fac * right with: MAX = max_fac * right then: left * right > MAX */ return true; } else { /** Given: left <= max_fac then: left * right <= max_fac * right with: MAX = max_fac * right THEN: left * right <= MAX */ return false; } } else { /** Given: left > 0 and: right <= 0 then: left * right < 0 THEN: left * right < MAX Define: min_fac = MIN / left then: min_Fac * left = (MIN / left) * left then: min_Fac * left = MIN */ const int64_t min_fac = INT64_MIN / left; if (right < min_fac) { /** Given: right < min_fac then: right * left < min_fac * left with: min_fac * left = MIN then: right * left < MIN */ return true; } else { /** Given: right >= min_fac then: right * left >= min_fac * left with: min_fac * left = MIN then: right * left >= MIN */ return false; } } } else { if (right > 0) { /** Given: left <= 0 and: right > 0 then: left * right <= 0 THEN: left * right < MAX Define: min_fac = MIN / right then: min_fac * right = (MIN / right) * right then: min_fac * right = MIN */ const int64_t min_fac = INT64_MIN / right; if (left < min_fac) { /** Given: left < min_fac then: left * right < min_fac * right with: MIN = min_fac * right then: left * right < MIN */ return true; } else { /** Given: left >= min_fac then: left * right >= min_fac * right with: MIN = min_fac * right then: left * right >= MIN */ return false; } } else { /** Given: left <= 0 and: right <= 0 then: left * right >= 0 THEN: left * right > MIN */ if (left == 0) { // Multiplication by zero will never overflow return false; } else { /** Given: left <= 0 and: left != 0 then: left < 0 Define: max_fac = MAX / left then: max_fac * left = (MAX / left) * left then: max_fac * left = MAX Given: left < 0 and: MAX > 0 and: max_fac = MAX / left then: max_fac < 0 [pos/neg -> neg] */ const int64_t max_fac = INT64_MAX / left; if (right < max_fac) { /* Given: right < max_fac and: left < 0 then: left * right > max_fac * left then: left * right > (MAX / left) * left then: left * right > MAX */ return true; } else { /* Given: right >= max_fac and: left < 0 then: left * right <= max_fac * left then: left * right <= (MAX / left) * left then: left * right <= MAX */ return false; } } } } } /// Return 'true' iff (left + right) would overflow with int64 static BSON_INLINE bool _mcd_i64_add_would_overflow (int64_t left, int64_t right) { /** * Context: * * - MAX, MIN, left: right: ℤ * - left >= MIN * - left <= MAX * - right >= MIN * - right <= MAX * - forall (N, M, Q : ℤ) . * if N = M then * M = N (Symmetry) * N + 0 = N (Zero is neutral) * N + M = M + N (Addition is commutative) * if N < M then * 0 - N > 0 - M (Order inversion) * M > N (Symmetry inversion) * 0 - M < 0 - N (order+symmetry inversion) * if M < Q or M = Q then * N < Q (Order transitivity) * 0 - M = -M (Negation is subtraction) * N - M = N + (-M) * Ord(N, M) = Ord(N+Q, M+Q) (Addition preserves ordering) */ // MAX, MIN, left, right: ℤ //* Given: right <= MAX //* Given: left <= MAX if (right < 0) { /** Given: right < 0 then: left + right < left + 0 then: left + right < left then: left + right <= left [Weakening] Given: left <= MAX and: left + right <= left then: left + right <= MAX THEN: left + right CANNOT overflow MAX */ /** Given: right >= MIN then: 0 - right <= 0 - MIN then: -right <= -MIN Given: -right <= -MIN then: MIN + -right <= MIN + -MIN then: MIN + -right <= 0 then: MIN - right <= 0 then: MIN - right <= MAX THEN: MIN - right CANNOT overflow MAX Given: right < 0 then: 0 - right > 0 - 0 then: 0 - right > 0 then: -right > 0 Given: -right > 0 then: MIN + (-right) > MIN + 0 then: MIN - right > MIN + 0 then: MIN - right > MIN THEN: MIN - right CANNOT overflow MIN Define: legroom = MIN - right Given: legroom = MIN - right then: legroom + right = MIN - right + right then: legroom + right = MIN */ const int64_t legroom = INT64_MIN - right; if (left < legroom) { /** Given: left < legroom then: left + right < legroom + right Given: legroom + right = MIN and: left + right < legroom + right then: left + right < MIN THEN: left + right WILL overflow MIN! */ return true; } else { /** Given: left >= legroom then: left + right >= legroom + right Given: legroom + right = MIN and: left + right >= legroom + right THEN: left + right >= MIN Given: left + right <= MAX and: left + right >= MIN THEN: left + right is in [MIN, MAX] */ return false; } } else if (right > 0) { /** Given: right > 0 then: left + right > left + 0 then: left + right > left then: left + right >= left [Weakening] Given: left >= MIN and: left + right >= left then: left + right >= MIN THEN: left + right cannot overflow MIN */ /** Given: right <= MAX then: 0 - right >= 0 - MAX then: -right >= -MAX Given: -right >= -MAX then: MAX + -right >= MAX + -MAX then: MAX + -right >= 0 then: MAX - right >= 0 then: MAX - right >= MIN THEN: MAX - right CANNOT overflow MIN Given: right > 0 then: 0 - right < 0 - 0 then: -right < 0 then: MAX + (-right) < MAX + 0 then: MAX + (-right) < MAX then: MAX - right < MAX THEN: MAX - right CANNOT overflow MAX Define: headroom = MAX - right Given: headroom = MAX - right; then: headroom + right = MAX - right + right then: headroom + right = MAX */ int64_t headroom = INT64_MAX - right; if (left > headroom) { /** Given: left > headroom then: left + right > headroom + right Given: left + right > headroom + right and: headroom + right = MAX then: left + right > MAX THEN: left + right WILL overflow MAX! */ return true; } else { /** Given: left <= headroom then: left + rigth <= headroom + right Given: left + right <= headroom + right and: headroom + right = MAX then: left + right <= MAX THEN: left + right CANNOT overflow MAX */ return false; } } else { /** Given: right = 0 and: left + right = left + 0 then: left + right = left Given: left <= MAX and: left >= MIN and: left + right = left then: left + right <= MAX and: left + right >= MIN THEN: left + right is in [MIN, MAX] */ return false; } } /// Return 'true' iff (left - right) would overflow with int64 static BSON_INLINE bool _mcd_i64_sub_would_overflow (int64_t left, int64_t right) { // Lemma: N - M = N + (-M), therefore (N - M) is bounded iff (N + -M) // is bounded. if (right > 0) { return _mcd_i64_add_would_overflow (left, -right); } else if (right < 0) { if (left > 0) { return _mcd_i64_add_would_overflow (-left, right); } else { // Both negative. Subtracting two negatives will never overflow return false; } } else { // Given: right = 0 // then: left - right = left - 0 // then: left - right = left //? THEN: left - right is bounded return false; } } #endif // MCD_INTEGER_H_INCLUDED mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mcd-nsinfo.c0000644000175100001660000000634114760300420021713 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include typedef struct { char *ns; // Hash key. int32_t index; UT_hash_handle hh; } ns_to_index_t; struct _mcd_nsinfo_t { ns_to_index_t *n2i; int32_t count; mongoc_buffer_t payload; }; mcd_nsinfo_t * mcd_nsinfo_new (void) { mcd_nsinfo_t *self = bson_malloc0 (sizeof (*self)); _mongoc_buffer_init (&self->payload, NULL, 0, NULL, NULL); return self; } void mcd_nsinfo_destroy (mcd_nsinfo_t *self) { if (!self) { return; } // Delete hash table. ns_to_index_t *entry, *tmp; HASH_ITER (hh, self->n2i, entry, tmp) { HASH_DEL (self->n2i, entry); bson_free (entry->ns); bson_free (entry); } _mongoc_buffer_destroy (&self->payload); bson_free (self); } int32_t mcd_nsinfo_append (mcd_nsinfo_t *self, const char *ns, bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (ns); BSON_OPTIONAL_PARAM (error); const int32_t ns_index = self->count; if (self->count == INT32_MAX) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Only %" PRId32 " distinct collections may be used", INT32_MAX); return -1; } self->count++; // Add to hash table. ns_to_index_t *entry = bson_malloc (sizeof (*entry)); *entry = (ns_to_index_t){.index = ns_index, .ns = bson_strdup (ns), .hh = {0}}; HASH_ADD_KEYPTR (hh, self->n2i, entry->ns, strlen (entry->ns), entry); // Append to buffer. bson_t mcd_nsinfo_bson = BSON_INITIALIZER; BSON_ASSERT (bson_append_utf8 (&mcd_nsinfo_bson, "ns", 2, ns, -1)); BSON_ASSERT (_mongoc_buffer_append (&self->payload, bson_get_data (&mcd_nsinfo_bson), mcd_nsinfo_bson.len)); bson_destroy (&mcd_nsinfo_bson); return ns_index; } int32_t mcd_nsinfo_find (const mcd_nsinfo_t *self, const char *ns) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (ns); ns_to_index_t *found; HASH_FIND_STR (self->n2i, ns, found); if (found == NULL) { return -1; } return found->index; } uint32_t mcd_nsinfo_get_bson_size (const char *ns) { BSON_ASSERT_PARAM (ns); // Calculate overhead of the BSON document { "ns": "" }. See BSON specification. bson_t as_bson = BSON_INITIALIZER; BSON_ASSERT (bson_append_utf8 (&as_bson, "ns", 2, ns, -1)); uint32_t size = as_bson.len; bson_destroy (&as_bson); return size; } const mongoc_buffer_t * mcd_nsinfo_as_document_sequence (const mcd_nsinfo_t *self) { BSON_ASSERT_PARAM (self); return &self->payload; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mcd-nsinfo.h0000644000175100001660000000354414760300420021722 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifndef MCD_NSINFO_H #define MCD_NSINFO_H #include #include // `mcd_nsinfo_t` builds the `nsInfo` payload for a `bulkWrite` command. typedef struct _mcd_nsinfo_t mcd_nsinfo_t; mcd_nsinfo_t * mcd_nsinfo_new (void); void mcd_nsinfo_destroy (mcd_nsinfo_t *self); // `mcd_nsinfo_append` adds `ns`. It is the callers responsibility to ensure duplicates are not inserted. // Namespaces are assigned indexes in order of insertion, starting at 0. // Returns the resulting non-negative index on success. Returns -1 on error. int32_t mcd_nsinfo_append (mcd_nsinfo_t *self, const char *ns, bson_error_t *error); // `mcd_nsinfo_find` returns the non-negative index if found. Returns -1 if not found. int32_t mcd_nsinfo_find (const mcd_nsinfo_t *self, const char *ns); // `mcd_nsinfo_get_bson_size` returns the size of the BSON document { "ns": "" } // Useful for checking whether a namespace can be added without exceeding a size limit. uint32_t mcd_nsinfo_get_bson_size (const char *ns); // `mcd_nsinfo_as_document_sequence` returns a document sequence. // Useful for constructing an OP_MSG Section with payloadType=1. const mongoc_buffer_t * mcd_nsinfo_as_document_sequence (const mcd_nsinfo_t *self); #endif // MCD_NSINFO_H mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mcd-rpc.c0000644000175100001660000022631714760300420021212 0ustar #include // Header-only dependency. Does NOT require linking with libmongoc. #define MONGOC_INSIDE #include #undef MONGOC_INSIDE #include #include typedef struct _mcd_rpc_message_header mcd_rpc_message_header; typedef struct _mcd_rpc_op_compressed mcd_rpc_op_compressed; typedef struct _mcd_rpc_op_msg_section mcd_rpc_op_msg_section; typedef struct _mcd_rpc_op_msg mcd_rpc_op_msg; typedef struct _mcd_rpc_op_reply mcd_rpc_op_reply; typedef struct _mcd_rpc_op_update mcd_rpc_op_update; typedef struct _mcd_rpc_op_insert mcd_rpc_op_insert; typedef struct _mcd_rpc_op_query mcd_rpc_op_query; typedef struct _mcd_rpc_op_get_more mcd_rpc_op_get_more; typedef struct _mcd_rpc_op_delete mcd_rpc_op_delete; typedef struct _mcd_rpc_op_kill_cursors mcd_rpc_op_kill_cursors; // See: https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol struct _mcd_rpc_message_header { int32_t message_length; int32_t request_id; int32_t response_to; int32_t op_code; bool is_in_iovecs_state; // Not part of actual message. }; struct _mcd_rpc_op_compressed { mcd_rpc_message_header header; int32_t original_opcode; int32_t uncompressed_size; uint8_t compressor_id; const void *compressed_message; // Non-owning. size_t compressed_message_len; // Not part of actual message. }; struct _mcd_rpc_op_msg_section { uint8_t kind; union payload { // Kind 0. struct body { int32_t section_len; // Not part of actual message. const void *bson; // bson_t data, non-owning. } body; // Kind 1. struct document_sequence { int32_t section_len; const char *identifier; // Non-owning. size_t identifier_len; // Not part of actual message. const void *bson_objects; // Array of bson_t data, non-owning. size_t bson_objects_len; // Not part of actual message. } document_sequence; } payload; }; struct _mcd_rpc_op_msg { mcd_rpc_message_header header; uint32_t flag_bits; mcd_rpc_op_msg_section *sections; // Owning. size_t sections_count; // Not part of actual message. uint32_t checksum; // Optional, ignored by Drivers. bool checksum_set; // Not part of actual message. }; struct _mcd_rpc_op_reply { mcd_rpc_message_header header; int32_t response_flags; int64_t cursor_id; int32_t starting_from; int32_t number_returned; const void *documents; // Array of bson_t data, non-owning. size_t documents_len; // Not part of actual message. }; struct _mcd_rpc_op_update { mcd_rpc_message_header header; const char *full_collection_name; // Non-owning. size_t full_collection_name_len; // Not part of actual message. int32_t flags; const void *selector; // bson_t data, non-owning. const void *update; // bson_t data, non-owning. }; struct _mcd_rpc_op_insert { mcd_rpc_message_header header; int32_t flags; const char *full_collection_name; // Non-owning. size_t full_collection_name_len; // Not part of actual message. const void *documents; // Array of bson_t data, non-owning. size_t documents_len; // Not part of actual message. }; struct _mcd_rpc_op_query { mcd_rpc_message_header header; int32_t flags; const char *full_collection_name; // Non-owning. size_t full_collection_name_len; // Not part of actual message. int32_t number_to_skip; int32_t number_to_return; const void *query; // bson_t, non-owning. const void *return_fields_selector; // Optional bson_t, non-owning. }; struct _mcd_rpc_op_get_more { mcd_rpc_message_header header; const char *full_collection_name; // Non-owning. size_t full_collection_name_len; // Not part of actual message. int32_t number_to_return; int64_t cursor_id; }; struct _mcd_rpc_op_delete { mcd_rpc_message_header header; const char *full_collection_name; size_t full_collection_name_len; // Not part of actual message. int32_t flags; const void *selector; // bson_t data, non-owning. }; struct _mcd_rpc_op_kill_cursors { mcd_rpc_message_header header; int32_t zero; // Reserved. int32_t number_of_cursor_ids; int64_t *cursor_ids; // Array of int64_t, owning. }; union _mcd_rpc_message { mcd_rpc_message_header msg_header; // Common initial sequence. mcd_rpc_op_compressed op_compressed; mcd_rpc_op_msg op_msg; mcd_rpc_op_reply op_reply; mcd_rpc_op_update op_update; mcd_rpc_op_insert op_insert; mcd_rpc_op_query op_query; mcd_rpc_op_get_more op_get_more; mcd_rpc_op_delete op_delete; mcd_rpc_op_kill_cursors op_kill_cursors; }; // The minimum byte length of a valid RPC message is 16 bytes (messageHeader is // the common initial sequence for all opcodes). RPC message lengths less than // 16 may be encountered parsing due to invalid or malformed input. #define MONGOC_RPC_MINIMUM_MESSAGE_LENGTH INT32_C (16) // The minimum byte length of a valid BSON document is 5 bytes (empty document): // - length (int32): total document length (including itself). // - "\x00": document terminator. // BSON document lengths less than 5 may be encountered during parsing due to // invalid or malformed input. #define MONGOC_RPC_MINIMUM_BSON_LENGTH INT32_C (5) // To avoid unexpected behavior on big endian targets after // `mcd_rpc_message_to_iovecs` due to fields being converted to little endian, // forbid use of accessors unless the RPC message has been reset to an // initialized state by asserting `!is_in_iovecs_state` even on little endian // targets. #define ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS \ if (1) { \ BSON_ASSERT_PARAM (rpc); \ BSON_ASSERT (!rpc->msg_header.is_in_iovecs_state); \ } else \ (void) 0 static int32_t _int32_from_le (const void *data) { BSON_ASSERT_PARAM (data); return bson_iter_int32_unsafe (&(bson_iter_t){.raw = data}); } // In addition to validating expected size against remaining bytes, ensure // proper conversion from little endian format. #define MONGOC_RPC_CONSUME(type, raw_type, from_le) \ static bool _consume_##type (type *target, const uint8_t **ptr, size_t *remaining_bytes) \ { \ BSON_ASSERT_PARAM (target); \ BSON_ASSERT_PARAM (ptr); \ BSON_ASSERT_PARAM (remaining_bytes); \ \ if (*remaining_bytes < sizeof (type)) { \ return false; \ } \ \ raw_type raw; \ memcpy (&raw, *ptr, sizeof (type)); \ \ const raw_type native = from_le (raw); \ memcpy (target, &native, sizeof (type)); \ \ *ptr += sizeof (type); \ *remaining_bytes -= sizeof (type); \ \ return true; \ } MONGOC_RPC_CONSUME (uint8_t, uint8_t, (uint8_t)) MONGOC_RPC_CONSUME (int32_t, uint32_t, BSON_UINT32_FROM_LE) MONGOC_RPC_CONSUME (uint32_t, uint32_t, BSON_UINT32_FROM_LE) MONGOC_RPC_CONSUME (int64_t, uint64_t, BSON_UINT64_FROM_LE) static bool _consume_utf8 (const char **target, size_t *length, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (target); BSON_ASSERT_PARAM (length); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); *target = (const char *) *ptr; const uint8_t *iter = *ptr; size_t rem = *remaining_bytes; while (rem > 0u && *iter != '\0') { iter += 1u; rem -= 1u; } if (rem == 0u) { return false; } // Consume string including the null terminator. iter += 1u; rem -= 1u; *length = *remaining_bytes - rem; *ptr = iter; *remaining_bytes = rem; return true; } static bool _consume_reserved_zero (const uint8_t **ptr, size_t *remaining_bytes) { int32_t zero; if (!_consume_int32_t (&zero, ptr, remaining_bytes)) { return false; } if (zero != 0) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // ZERO as invalid input. return false; } return true; } static bool _consume_bson_objects (const uint8_t **ptr, size_t *remaining_bytes, int32_t *num_parsed, int32_t limit) { BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); BSON_OPTIONAL_PARAM (num_parsed); int32_t count = 0; // Validate document count and lengths. while ((count < limit) && (*remaining_bytes > 0u)) { int32_t doc_len; if (!_consume_int32_t (&doc_len, ptr, remaining_bytes)) { return false; } if (doc_len < MONGOC_RPC_MINIMUM_BSON_LENGTH || mcommon_cmp_greater_su (doc_len, *remaining_bytes + sizeof (int32_t))) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // document as invalid input. return false; } // Consume rest of document without validation. *ptr += (size_t) doc_len - sizeof (int32_t); *remaining_bytes -= (size_t) doc_len - sizeof (int32_t); count += 1; } if (num_parsed) { *num_parsed = count; } return true; } static bool _consume_op_compressed (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_compressed *const op_compressed = &rpc->op_compressed; if (!_consume_int32_t (&op_compressed->original_opcode, ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_compressed->uncompressed_size, ptr, remaining_bytes)) { return false; } if (!_consume_uint8_t (&op_compressed->compressor_id, ptr, remaining_bytes)) { return false; } // Consume compressedMessage without validation. op_compressed->compressed_message = *ptr; op_compressed->compressed_message_len = *remaining_bytes; *ptr += *remaining_bytes; *remaining_bytes = 0u; return true; } static bool _consume_op_msg_section ( mcd_rpc_op_msg *op_msg, const uint8_t **ptr, size_t *remaining_bytes, size_t *capacity, bool *found_kind_0) { BSON_ASSERT_PARAM (op_msg); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (found_kind_0); mcd_rpc_op_msg_section section; if (!_consume_uint8_t (§ion.kind, ptr, remaining_bytes)) { return false; } // There is no ordering implied by payload types. A section with payload type // 1 can be serialized before payload type 0. if (section.kind == 0) { if (*found_kind_0) { *ptr -= sizeof (uint8_t); // Revert so *data_end points to start of // section as invalid input. return false; } *found_kind_0 = true; } switch (section.kind) { case 0: { // Body section.payload.body.section_len = _int32_from_le (*ptr); section.payload.body.bson = *ptr; int32_t num_parsed = 0; if (!_consume_bson_objects (ptr, remaining_bytes, &num_parsed, 1) || num_parsed != 1) { return false; } break; } case 1: { // Document Sequence if (!_consume_int32_t (§ion.payload.document_sequence.section_len, ptr, remaining_bytes)) { return false; } // Minimum byte length of a valid document sequence section is 4 bytes // (section length). Actual minimum length would also account for the // identifier field, but 4 bytes is sufficient to avoid unsigned integer // overflow when computing `remaining_section_bytes` and to encourage as // much progress is made parsing input data as able. if (mcommon_cmp_less_su (section.payload.document_sequence.section_len, sizeof (int32_t))) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // document sequence as invalid input. return false; } size_t remaining_section_bytes = (size_t) section.payload.document_sequence.section_len - sizeof (int32_t); // Section length exceeds remaining data. if (remaining_section_bytes > *remaining_bytes) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // document sequence as invalid input. return false; } // Consume identifier without validating uniqueness. { const uint8_t *const identifier_begin = *ptr; if (!_consume_utf8 (§ion.payload.document_sequence.identifier, §ion.payload.document_sequence.identifier_len, ptr, &remaining_section_bytes)) { return false; } *remaining_bytes -= (size_t) (*ptr - identifier_begin); } section.payload.document_sequence.bson_objects = *ptr; section.payload.document_sequence.bson_objects_len = remaining_section_bytes; _consume_bson_objects (ptr, &remaining_section_bytes, NULL, INT32_MAX); // Should have exhausted all bytes in the section. if (remaining_section_bytes != 0u) { return false; } *remaining_bytes -= (size_t) (*ptr - (const uint8_t *) section.payload.document_sequence.bson_objects); break; } default: *ptr -= sizeof (uint8_t); // Revert so *data_end points to start of kind // as invalid input. return false; } // Expand sections capacity if required. if (op_msg->sections_count >= *capacity) { *capacity *= 2u; op_msg->sections = bson_realloc (op_msg->sections, *capacity * sizeof (mcd_rpc_op_msg_section)); } // Append the valid section. op_msg->sections[op_msg->sections_count++] = section; return true; } static bool _consume_op_msg (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_msg *const op_msg = &rpc->op_msg; if (!_consume_uint32_t (&op_msg->flag_bits, ptr, remaining_bytes)) { return false; } { const uint32_t defined_bits = MONGOC_OP_MSG_FLAG_CHECKSUM_PRESENT | MONGOC_OP_MSG_FLAG_MORE_TO_COME | MONGOC_OP_MSG_FLAG_EXHAUST_ALLOWED; // Clients MUST error if any unsupported or undefined required bits are // set to 1 and MUST ignore all undefined optional bits. if (((op_msg->flag_bits & UINT32_C (0x0000FFFF)) & ~defined_bits) != 0u) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // flagBits as invalid input. return false; } } // Each message contains one or more sections. Preallocate space for two // sections, which should cover the most frequent cases. size_t capacity = 2u; op_msg->sections = bson_malloc (capacity * sizeof (mcd_rpc_op_msg_section)); op_msg->sections_count = 0u; // A fully constructed OP_MSG MUST contain exactly one Payload Type 0, and // optionally any number of Payload Type 1 where each identifier MUST be // unique per message. { bool found_kind_0 = false; // A section requires at least 5 bytes for kind (1) + length (4). while (*remaining_bytes > 4u) { if (!_consume_op_msg_section (op_msg, ptr, remaining_bytes, &capacity, &found_kind_0)) { return false; } } if (!found_kind_0) { return false; } } if ((op_msg->flag_bits & MONGOC_OP_MSG_FLAG_CHECKSUM_PRESENT) != 0u) { if (!_consume_uint32_t (&op_msg->checksum, ptr, remaining_bytes)) { return false; } op_msg->checksum_set = true; } return true; } static bool _consume_op_reply (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_reply *const op_reply = &rpc->op_reply; if (!_consume_int32_t (&op_reply->response_flags, ptr, remaining_bytes)) { return false; } if (!_consume_int64_t (&op_reply->cursor_id, ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_reply->starting_from, ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_reply->number_returned, ptr, remaining_bytes)) { return false; } if (op_reply->number_returned < 0) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // numberReturned as invalid input. return false; } if (op_reply->number_returned > 0) { op_reply->documents = *ptr; op_reply->documents_len = *remaining_bytes; } else { op_reply->documents = NULL; op_reply->documents_len = 0u; } int32_t num_parsed = 0; if (!_consume_bson_objects (ptr, remaining_bytes, &num_parsed, op_reply->number_returned) || num_parsed != op_reply->number_returned) { return false; } return true; } static bool _consume_op_update (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_update *const op_update = &rpc->op_update; if (!_consume_reserved_zero (ptr, remaining_bytes)) { return false; } if (!_consume_utf8 (&op_update->full_collection_name, &op_update->full_collection_name_len, ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_update->flags, ptr, remaining_bytes)) { return false; } // Bits 2-31 are reserved. Must be set to 0. if ((op_update->flags & ~(0x00000003)) != 0) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // flags as invalid input. return false; } int32_t num_parsed = 0; op_update->selector = *ptr; if (!_consume_bson_objects (ptr, remaining_bytes, &num_parsed, 1) || num_parsed != 1) { return false; } op_update->update = *ptr; if (!_consume_bson_objects (ptr, remaining_bytes, &num_parsed, 1) || num_parsed != 1) { return false; } return true; } static bool _consume_op_insert (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_insert *const op_insert = &rpc->op_insert; if (!_consume_int32_t (&op_insert->flags, ptr, remaining_bytes)) { return false; } // Bits 1-31 are reserved. Must be set to 0. if ((op_insert->flags & ~(0x00000001)) != 0) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // flags as invalid input. return false; } if (!_consume_utf8 (&op_insert->full_collection_name, &op_insert->full_collection_name_len, ptr, remaining_bytes)) { return false; } op_insert->documents = *ptr; op_insert->documents_len = *remaining_bytes; int32_t num_parsed = 0; if (!_consume_bson_objects (ptr, remaining_bytes, &num_parsed, INT32_MAX) || num_parsed == 0) { return false; } return true; } static bool _consume_op_query (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_query *const op_query = &rpc->op_query; if (!_consume_int32_t (&op_query->flags, ptr, remaining_bytes)) { return false; } // Bit 0 is reserved. Must be set to 0. if ((op_query->flags & 0x01) != 0) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // flags as invalid input. return false; } // Bits 8-31 are reserved. Must be set to 0. if ((op_query->flags & ~(0x0000007F)) != 0) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // flags as invalid input. return false; } if (!_consume_utf8 (&op_query->full_collection_name, &op_query->full_collection_name_len, ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_query->number_to_skip, ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_query->number_to_return, ptr, remaining_bytes)) { return false; } int32_t num_parsed = 0; op_query->query = *ptr; if (!_consume_bson_objects (ptr, remaining_bytes, &num_parsed, 1) || num_parsed != 1) { return false; } op_query->return_fields_selector = *ptr; if (!_consume_bson_objects (ptr, remaining_bytes, &num_parsed, 1)) { return false; } // returnFieldsSelector is optional. if (num_parsed == 0) { op_query->return_fields_selector = NULL; } return true; } static bool _consume_op_get_more (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_get_more *const op_get_more = &rpc->op_get_more; if (!_consume_reserved_zero (ptr, remaining_bytes)) { return false; } if (!_consume_utf8 ( &op_get_more->full_collection_name, &op_get_more->full_collection_name_len, ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_get_more->number_to_return, ptr, remaining_bytes)) { return false; } if (!_consume_int64_t (&op_get_more->cursor_id, ptr, remaining_bytes)) { return false; } return true; } static bool _consume_op_delete (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_delete *const op_delete = &rpc->op_delete; if (!_consume_reserved_zero (ptr, remaining_bytes)) { return false; } if (!_consume_utf8 (&op_delete->full_collection_name, &op_delete->full_collection_name_len, ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_delete->flags, ptr, remaining_bytes)) { return false; } // Bits 1-31 are reserved. Must be set to 0. if ((op_delete->flags & ~(0x00000001)) != 0) { *ptr -= sizeof (int32_t); // Revert so *data_end points to start of // flags as invalid input. return false; } op_delete->selector = *ptr; int32_t num_parsed = 0; if (!_consume_bson_objects (ptr, remaining_bytes, &num_parsed, 1) || num_parsed != 1) { return false; } return true; } static bool _consume_op_kill_cursors (mcd_rpc_message *rpc, const uint8_t **ptr, size_t *remaining_bytes) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (ptr); BSON_ASSERT_PARAM (remaining_bytes); mcd_rpc_op_kill_cursors *op_kill_cursors = &rpc->op_kill_cursors; if (!_consume_reserved_zero (ptr, remaining_bytes)) { return false; } if (!_consume_int32_t (&op_kill_cursors->number_of_cursor_ids, ptr, remaining_bytes)) { return false; } if (op_kill_cursors->number_of_cursor_ids < 0 || // Truncation may (deliberately) leave unparsed bytes that will later // trigger validation failure due to unexpected remaining bytes. mcommon_cmp_greater_su (op_kill_cursors->number_of_cursor_ids, *remaining_bytes / sizeof (int64_t))) { *ptr -= sizeof (int32_t); // Revert so *data_len points to start of // numberOfCursorIds as invalid input. return false; } const size_t cursor_ids_length = (size_t) op_kill_cursors->number_of_cursor_ids * sizeof (int64_t); bson_free (op_kill_cursors->cursor_ids); if (op_kill_cursors->number_of_cursor_ids > 0) { op_kill_cursors->cursor_ids = bson_malloc (cursor_ids_length); for (int32_t i = 0; i < op_kill_cursors->number_of_cursor_ids; ++i) { if (!_consume_int64_t (op_kill_cursors->cursor_ids + i, ptr, remaining_bytes)) { return false; } } } else { op_kill_cursors->cursor_ids = NULL; } return true; } mcd_rpc_message * mcd_rpc_message_from_data (const void *data, size_t length, const void **data_end) { BSON_ASSERT_PARAM (data); BSON_OPTIONAL_PARAM (data_end); mcd_rpc_message *rpc = bson_malloc (sizeof (mcd_rpc_message)); mcd_rpc_message *ret = NULL; *rpc = (mcd_rpc_message){.msg_header = {0}}; if (!mcd_rpc_message_from_data_in_place (rpc, data, length, data_end)) { goto fail; } ret = rpc; rpc = NULL; fail: mcd_rpc_message_destroy (rpc); return ret; } bool mcd_rpc_message_from_data_in_place (mcd_rpc_message *rpc, const void *data, size_t length, const void **data_end) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT_PARAM (data); BSON_OPTIONAL_PARAM (data_end); bool ret = false; size_t remaining_bytes = length; const uint8_t *ptr = data; if (!_consume_int32_t (&rpc->msg_header.message_length, &ptr, &remaining_bytes)) { goto fail; } if (rpc->msg_header.message_length < MONGOC_RPC_MINIMUM_MESSAGE_LENGTH || mcommon_cmp_greater_su (rpc->msg_header.message_length, remaining_bytes + sizeof (int32_t))) { ptr -= sizeof (int32_t); // Revert so *data_end points to start of // messageLength as invalid input. goto fail; } // Use reported message length as upper bound. remaining_bytes = (size_t) rpc->msg_header.message_length - sizeof (int32_t); if (!_consume_int32_t (&rpc->msg_header.request_id, &ptr, &remaining_bytes)) { goto fail; } if (!_consume_int32_t (&rpc->msg_header.response_to, &ptr, &remaining_bytes)) { goto fail; } if (!_consume_int32_t (&rpc->msg_header.op_code, &ptr, &remaining_bytes)) { goto fail; } switch (rpc->msg_header.op_code) { case MONGOC_OP_CODE_COMPRESSED: if (!_consume_op_compressed (rpc, &ptr, &remaining_bytes)) { goto fail; } break; case MONGOC_OP_CODE_MSG: if (!_consume_op_msg (rpc, &ptr, &remaining_bytes)) { goto fail; } break; case MONGOC_OP_CODE_REPLY: if (!_consume_op_reply (rpc, &ptr, &remaining_bytes)) { goto fail; } break; case MONGOC_OP_CODE_UPDATE: if (!_consume_op_update (rpc, &ptr, &remaining_bytes)) { goto fail; } break; case MONGOC_OP_CODE_INSERT: if (!_consume_op_insert (rpc, &ptr, &remaining_bytes)) { goto fail; } break; case MONGOC_OP_CODE_QUERY: if (!_consume_op_query (rpc, &ptr, &remaining_bytes)) { goto fail; } break; case MONGOC_OP_CODE_GET_MORE: if (!_consume_op_get_more (rpc, &ptr, &remaining_bytes)) { goto fail; } break; case MONGOC_OP_CODE_DELETE: if (!_consume_op_delete (rpc, &ptr, &remaining_bytes)) { goto fail; } break; case MONGOC_OP_CODE_KILL_CURSORS: if (!_consume_op_kill_cursors (rpc, &ptr, &remaining_bytes)) { goto fail; } break; default: ptr -= sizeof (int32_t); // Revert so *data_end points to start of opCode // as invalid input. goto fail; } // Number of bytes parsed do not match the reported message length. if (remaining_bytes > 0) { goto fail; } ret = true; fail: if (data_end) { *data_end = ptr; } return ret; } static void _append_iovec_reserve_space_for (mongoc_iovec_t **iovecs, size_t *capacity, const mongoc_iovec_t *header_iovecs, size_t additional_capacity) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (header_iovecs); // Expect this function to be invoked only once after initializing the // `header_iovecs` array. BSON_ASSERT (*capacity == 4u); *capacity += additional_capacity; *iovecs = bson_malloc (*capacity * sizeof (mongoc_iovec_t)); memcpy (*iovecs, header_iovecs, 4u * sizeof (mongoc_iovec_t)); } static bool _append_iovec (mongoc_iovec_t *iovecs, size_t *capacity, size_t *count, mongoc_iovec_t iovec) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); if (!iovec.iov_base || iovec.iov_len == 0u) { return false; } // Expect iovecs array capacity to have been reserved upfront according to // the upper bound of potential iovec objects required for the opcode being // converted. This is to minimize (re)allocations. BSON_ASSERT (*count < *capacity); iovecs[*count] = iovec; *count += 1u; return true; } #define MONGOC_RPC_APPEND_IOVEC(type, raw_type, to_le) \ static bool _append_iovec_##type (mongoc_iovec_t *iovecs, size_t *capacity, size_t *count, type *value) \ { \ raw_type storage; \ memcpy (&storage, value, sizeof (raw_type)); \ storage = to_le (storage); \ memcpy (value, &storage, sizeof (raw_type)); \ return _append_iovec (iovecs, \ capacity, \ count, \ (mongoc_iovec_t){ \ .iov_base = (void *) value, \ .iov_len = sizeof (type), \ }); \ } MONGOC_RPC_APPEND_IOVEC (uint8_t, uint8_t, (uint8_t)) MONGOC_RPC_APPEND_IOVEC (int32_t, uint32_t, BSON_UINT32_TO_LE) MONGOC_RPC_APPEND_IOVEC (uint32_t, uint32_t, BSON_UINT32_TO_LE) MONGOC_RPC_APPEND_IOVEC (int64_t, uint64_t, BSON_UINT64_TO_LE) static bool _append_iovec_data (mongoc_iovec_t *iovecs, size_t *capacity, size_t *count, const void *data, size_t length) { return _append_iovec (iovecs, capacity, count, (mongoc_iovec_t){ .iov_base = (void *) data, .iov_len = length, }); } static bool _append_iovec_reserved_zero (mongoc_iovec_t *iovecs, size_t *capacity, size_t *count) { static int32_t zero = 0u; return _append_iovec (iovecs, capacity, count, (mongoc_iovec_t){ .iov_base = (void *) &zero, .iov_len = sizeof (zero), }); } static bool _append_iovec_op_compressed (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_compressed *op_compressed, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (op_compressed); BSON_ASSERT_PARAM (header_iovecs); _append_iovec_reserve_space_for (iovecs, capacity, header_iovecs, 4u); if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_compressed->original_opcode)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_compressed->uncompressed_size)) { return false; } if (!_append_iovec_uint8_t (*iovecs, capacity, count, &op_compressed->compressor_id)) { return false; } if (!_append_iovec_data ( *iovecs, capacity, count, op_compressed->compressed_message, op_compressed->compressed_message_len)) { return false; } return true; } static bool _count_section_iovecs (const mcd_rpc_op_msg *op_msg, size_t *section_iovecs) { BSON_ASSERT_PARAM (op_msg); BSON_ASSERT_PARAM (section_iovecs); for (size_t i = 0u; i < op_msg->sections_count; ++i) { *section_iovecs += 1u; switch (op_msg->sections[i].kind) { case 0: // Body. *section_iovecs += 1u; break; case 1: // Document Sequence. *section_iovecs += 3u; break; default: return false; } } return true; } static bool _append_iovec_op_msg (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_msg *op_msg, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (op_msg); BSON_ASSERT_PARAM (header_iovecs); size_t section_iovecs = 0u; if (!_count_section_iovecs (op_msg, §ion_iovecs)) { return false; } _append_iovec_reserve_space_for (iovecs, capacity, header_iovecs, 2u + section_iovecs); if (!_append_iovec_uint32_t (*iovecs, capacity, count, &op_msg->flag_bits)) { return false; } for (size_t i = 0u; i < op_msg->sections_count; ++i) { mcd_rpc_op_msg_section *section = &op_msg->sections[i]; if (!section) { return false; } if (!_append_iovec_uint8_t (*iovecs, capacity, count, §ion->kind)) { return false; } switch (section->kind) { case 0: // Body if (!_append_iovec_data ( *iovecs, capacity, count, section->payload.body.bson, (size_t) section->payload.body.section_len)) { return false; } break; case 1: // Document Sequence if (!_append_iovec_int32_t (*iovecs, capacity, count, §ion->payload.document_sequence.section_len)) { return false; } if (!_append_iovec_data (*iovecs, capacity, count, section->payload.document_sequence.identifier, section->payload.document_sequence.identifier_len)) { return false; } if (!_append_iovec_data (*iovecs, capacity, count, section->payload.document_sequence.bson_objects, section->payload.document_sequence.bson_objects_len)) { return false; } break; default: return false; } } if (op_msg->checksum_set) { if (!_append_iovec_uint32_t (*iovecs, capacity, count, &op_msg->checksum)) { return false; } } return true; } static bool _append_iovec_op_reply (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_reply *op_reply, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (op_reply); BSON_ASSERT_PARAM (header_iovecs); _append_iovec_reserve_space_for (iovecs, capacity, header_iovecs, 5u); if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_reply->response_flags)) { return false; } if (!_append_iovec_int64_t (*iovecs, capacity, count, &op_reply->cursor_id)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_reply->starting_from)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_reply->number_returned)) { return false; } if (op_reply->number_returned > 0 && !_append_iovec_data (*iovecs, capacity, count, op_reply->documents, op_reply->documents_len)) { return false; } return true; } static bool _append_iovec_op_update (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_update *op_update, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (op_update); BSON_ASSERT_PARAM (header_iovecs); _append_iovec_reserve_space_for (iovecs, capacity, header_iovecs, 5u); if (!_append_iovec_reserved_zero (*iovecs, capacity, count)) { return false; } if (!_append_iovec_data ( *iovecs, capacity, count, op_update->full_collection_name, op_update->full_collection_name_len)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_update->flags)) { return false; } if (!_append_iovec_data ( *iovecs, capacity, count, op_update->selector, (size_t) _int32_from_le (op_update->selector))) { return false; } if (!_append_iovec_data (*iovecs, capacity, count, op_update->update, (size_t) _int32_from_le (op_update->update))) { return false; } return true; } static bool _append_iovec_op_insert (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_insert *op_insert, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (op_insert); BSON_ASSERT_PARAM (header_iovecs); _append_iovec_reserve_space_for (iovecs, capacity, header_iovecs, 3u); if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_insert->flags)) { return false; } if (!_append_iovec_data ( *iovecs, capacity, count, op_insert->full_collection_name, op_insert->full_collection_name_len)) { return false; } if (!_append_iovec_data (*iovecs, capacity, count, op_insert->documents, op_insert->documents_len)) { return false; } return true; } static bool _append_iovec_op_query (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_query *op_query, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (op_query); BSON_ASSERT_PARAM (header_iovecs); _append_iovec_reserve_space_for ( iovecs, capacity, header_iovecs, 5u + (size_t) (!!op_query->return_fields_selector)); if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_query->flags)) { return false; } if (!_append_iovec_data ( *iovecs, capacity, count, op_query->full_collection_name, op_query->full_collection_name_len)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_query->number_to_skip)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_query->number_to_return)) { return false; } if (!_append_iovec_data (*iovecs, capacity, count, op_query->query, (size_t) _int32_from_le (op_query->query))) { return false; } if (op_query->return_fields_selector) { if (!_append_iovec_data (*iovecs, capacity, count, op_query->return_fields_selector, (size_t) _int32_from_le (op_query->return_fields_selector))) { return false; } } return true; } static bool _append_iovec_op_get_more (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_get_more *op_get_more, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (op_get_more); BSON_ASSERT_PARAM (header_iovecs); _append_iovec_reserve_space_for (iovecs, capacity, header_iovecs, 4u); if (!_append_iovec_reserved_zero (*iovecs, capacity, count)) { return false; } if (!_append_iovec_data ( *iovecs, capacity, count, op_get_more->full_collection_name, op_get_more->full_collection_name_len)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_get_more->number_to_return)) { return false; } if (!_append_iovec_int64_t (*iovecs, capacity, count, &op_get_more->cursor_id)) { return false; } return true; } static bool _append_iovec_op_delete (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_delete *op_delete, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (op_delete); BSON_ASSERT_PARAM (header_iovecs); _append_iovec_reserve_space_for (iovecs, capacity, header_iovecs, 4u); if (!_append_iovec_reserved_zero (*iovecs, capacity, count)) { return false; } if (!_append_iovec_data ( *iovecs, capacity, count, op_delete->full_collection_name, op_delete->full_collection_name_len)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_delete->flags)) { return false; } if (!_append_iovec_data ( *iovecs, capacity, count, op_delete->selector, (size_t) _int32_from_le (op_delete->selector))) { return false; } return true; } static bool _append_iovec_op_kill_cursors (mongoc_iovec_t **iovecs, size_t *capacity, size_t *count, mcd_rpc_op_kill_cursors *op_kill_cursors, const mongoc_iovec_t *header_iovecs) { BSON_ASSERT_PARAM (iovecs); BSON_ASSERT_PARAM (capacity); BSON_ASSERT_PARAM (count); BSON_ASSERT_PARAM (op_kill_cursors); BSON_ASSERT_PARAM (header_iovecs); // Store value before conversion to little endian. const int32_t number_of_cursor_ids = op_kill_cursors->number_of_cursor_ids; _append_iovec_reserve_space_for (iovecs, capacity, header_iovecs, 3u); if (!_append_iovec_reserved_zero (*iovecs, capacity, count)) { return false; } if (!_append_iovec_int32_t (*iovecs, capacity, count, &op_kill_cursors->number_of_cursor_ids)) { return false; } // Each cursorID must be converted to little endian. for (int32_t i = 0; i < number_of_cursor_ids; ++i) { int64_t *const cursor_id = op_kill_cursors->cursor_ids + i; uint64_t storage; memcpy (&storage, cursor_id, sizeof (int64_t)); storage = BSON_UINT64_TO_LE (storage); memcpy (cursor_id, &storage, sizeof (int64_t)); } if (number_of_cursor_ids > 0 && !_append_iovec_data ( *iovecs, capacity, count, op_kill_cursors->cursor_ids, (size_t) number_of_cursor_ids * sizeof (int64_t))) { return false; } return true; } void * mcd_rpc_message_to_iovecs (mcd_rpc_message *rpc, size_t *count) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT_PARAM (count); const int32_t op_code = rpc->msg_header.op_code; // Preallocated space for msgHeader fields. mongoc_iovec_t header_iovecs[4]; size_t capacity = 4u; *count = 0u; (void) _append_iovec_int32_t (header_iovecs, &capacity, count, &rpc->msg_header.message_length); (void) _append_iovec_int32_t (header_iovecs, &capacity, count, &rpc->msg_header.request_id); (void) _append_iovec_int32_t (header_iovecs, &capacity, count, &rpc->msg_header.response_to); (void) _append_iovec_int32_t (header_iovecs, &capacity, count, &rpc->msg_header.op_code); mongoc_iovec_t *iovecs = NULL; mongoc_iovec_t *ret = NULL; // Fields may be converted to little endian even on failure, so consider the // RPC object to be in an iovecs state from this point forward regardless of // success or failure. rpc->msg_header.is_in_iovecs_state = true; switch (op_code) { case MONGOC_OP_CODE_COMPRESSED: if (!_append_iovec_op_compressed (&iovecs, &capacity, count, &rpc->op_compressed, header_iovecs)) { goto fail; } break; case MONGOC_OP_CODE_MSG: { if (!_append_iovec_op_msg (&iovecs, &capacity, count, &rpc->op_msg, header_iovecs)) { goto fail; } break; } case MONGOC_OP_CODE_REPLY: if (!_append_iovec_op_reply (&iovecs, &capacity, count, &rpc->op_reply, header_iovecs)) { goto fail; } break; case MONGOC_OP_CODE_UPDATE: if (!_append_iovec_op_update (&iovecs, &capacity, count, &rpc->op_update, header_iovecs)) { goto fail; } break; case MONGOC_OP_CODE_INSERT: if (!_append_iovec_op_insert (&iovecs, &capacity, count, &rpc->op_insert, header_iovecs)) { goto fail; } break; case MONGOC_OP_CODE_QUERY: if (!_append_iovec_op_query (&iovecs, &capacity, count, &rpc->op_query, header_iovecs)) { goto fail; } break; case MONGOC_OP_CODE_GET_MORE: if (!_append_iovec_op_get_more (&iovecs, &capacity, count, &rpc->op_get_more, header_iovecs)) { goto fail; } break; case MONGOC_OP_CODE_DELETE: if (!_append_iovec_op_delete (&iovecs, &capacity, count, &rpc->op_delete, header_iovecs)) { goto fail; } break; case MONGOC_OP_CODE_KILL_CURSORS: if (!_append_iovec_op_kill_cursors (&iovecs, &capacity, count, &rpc->op_kill_cursors, header_iovecs)) { goto fail; } break; default: goto fail; } ret = iovecs; iovecs = NULL; fail: bson_free (iovecs); return ret; } mcd_rpc_message * mcd_rpc_message_new (void) { mcd_rpc_message *const rpc = bson_malloc (sizeof (mcd_rpc_message)); *rpc = (mcd_rpc_message){.msg_header = {0}}; return rpc; } static int32_t _mcd_rpc_header_get_op_code_maybe_le (const mcd_rpc_message *rpc) { BSON_ASSERT_PARAM (rpc); int32_t op_code = rpc->msg_header.op_code; // May already be in native endian. switch (op_code) { case MONGOC_OP_CODE_COMPRESSED: case MONGOC_OP_CODE_MSG: case MONGOC_OP_CODE_REPLY: case MONGOC_OP_CODE_UPDATE: case MONGOC_OP_CODE_INSERT: case MONGOC_OP_CODE_QUERY: case MONGOC_OP_CODE_GET_MORE: case MONGOC_OP_CODE_DELETE: case MONGOC_OP_CODE_KILL_CURSORS: return op_code; default: // May be in little endian. op_code = _int32_from_le (&op_code); switch (op_code) { case MONGOC_OP_CODE_COMPRESSED: case MONGOC_OP_CODE_MSG: case MONGOC_OP_CODE_REPLY: case MONGOC_OP_CODE_UPDATE: case MONGOC_OP_CODE_INSERT: case MONGOC_OP_CODE_QUERY: case MONGOC_OP_CODE_GET_MORE: case MONGOC_OP_CODE_DELETE: case MONGOC_OP_CODE_KILL_CURSORS: return op_code; default: // Doesn't seem to have been a valid opCode. return rpc->msg_header.op_code; } } } static void _mcd_rpc_message_free_owners (mcd_rpc_message *rpc) { BSON_ASSERT_PARAM (rpc); switch (_mcd_rpc_header_get_op_code_maybe_le (rpc)) { case MONGOC_OP_CODE_MSG: bson_free (rpc->op_msg.sections); rpc->op_msg.sections = NULL; return; case MONGOC_OP_CODE_KILL_CURSORS: bson_free (rpc->op_kill_cursors.cursor_ids); rpc->op_kill_cursors.cursor_ids = NULL; return; case MONGOC_OP_CODE_COMPRESSED: case MONGOC_OP_CODE_REPLY: case MONGOC_OP_CODE_UPDATE: case MONGOC_OP_CODE_INSERT: case MONGOC_OP_CODE_QUERY: case MONGOC_OP_CODE_GET_MORE: case MONGOC_OP_CODE_DELETE: return; default: return; } } void mcd_rpc_message_destroy (mcd_rpc_message *rpc) { if (!rpc) { return; } _mcd_rpc_message_free_owners (rpc); bson_free ((void *) rpc); } void mcd_rpc_message_reset (mcd_rpc_message *rpc) { BSON_ASSERT_PARAM (rpc); _mcd_rpc_message_free_owners (rpc); *rpc = (mcd_rpc_message){.msg_header = {0}}; } void mcd_rpc_message_set_length (mcd_rpc_message *rpc, int32_t value) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->msg_header.message_length = value; } int32_t mcd_rpc_header_get_message_length (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; return rpc->msg_header.message_length; } int32_t mcd_rpc_header_get_request_id (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; return rpc->msg_header.request_id; } int32_t mcd_rpc_header_get_response_to (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; return rpc->msg_header.response_to; } int32_t mcd_rpc_header_get_op_code (const mcd_rpc_message *rpc) { BSON_ASSERT_PARAM (rpc); // Permit read access even if the RPC message object // is in an iovecs state. return rpc->msg_header.op_code; } int32_t mcd_rpc_header_set_message_length (mcd_rpc_message *rpc, int32_t message_length) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->msg_header.message_length = message_length; return sizeof (message_length); } int32_t mcd_rpc_header_set_request_id (mcd_rpc_message *rpc, int32_t request_id) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->msg_header.request_id = request_id; return sizeof (request_id); } int32_t mcd_rpc_header_set_response_to (mcd_rpc_message *rpc, int32_t response_to) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->msg_header.response_to = response_to; return sizeof (response_to); } int32_t mcd_rpc_header_set_op_code (mcd_rpc_message *rpc, int32_t op_code) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; _mcd_rpc_message_free_owners (rpc); rpc->msg_header.op_code = op_code; return sizeof (op_code); } int32_t mcd_rpc_op_compressed_get_original_opcode (const mcd_rpc_message *rpc) { BSON_ASSERT_PARAM (rpc); // Permit read access even if the RPC message object // is in an iovecs state. BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); return rpc->op_compressed.original_opcode; } int32_t mcd_rpc_op_compressed_get_uncompressed_size (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); return rpc->op_compressed.uncompressed_size; } uint8_t mcd_rpc_op_compressed_get_compressor_id (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); return rpc->op_compressed.compressor_id; } const void * mcd_rpc_op_compressed_get_compressed_message (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); return rpc->op_compressed.compressed_message; } size_t mcd_rpc_op_compressed_get_compressed_message_length (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); return rpc->op_compressed.compressed_message_len; } int32_t mcd_rpc_op_compressed_set_original_opcode (mcd_rpc_message *rpc, int32_t original_opcode) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); rpc->op_compressed.original_opcode = original_opcode; return sizeof (original_opcode); } int32_t mcd_rpc_op_compressed_set_uncompressed_size (mcd_rpc_message *rpc, int32_t uncompressed_size) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); rpc->op_compressed.uncompressed_size = uncompressed_size; return sizeof (uncompressed_size); } int32_t mcd_rpc_op_compressed_set_compressor_id (mcd_rpc_message *rpc, uint8_t compressor_id) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); rpc->op_compressed.compressor_id = compressor_id; return sizeof (compressor_id); } int32_t mcd_rpc_op_compressed_set_compressed_message (mcd_rpc_message *rpc, const void *compressed_message, size_t compressed_message_length) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_COMPRESSED); BSON_ASSERT (mcommon_in_range_unsigned (int32_t, compressed_message_length)); rpc->op_compressed.compressed_message = compressed_message; rpc->op_compressed.compressed_message_len = compressed_message_length; return (int32_t) compressed_message_length; } uint8_t mcd_rpc_op_msg_section_get_kind (const mcd_rpc_message *rpc, size_t index) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); return rpc->op_msg.sections[index].kind; } int32_t mcd_rpc_op_msg_section_get_length (const mcd_rpc_message *rpc, size_t index) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); const mcd_rpc_op_msg_section *const section = &rpc->op_msg.sections[index]; switch (section->kind) { case 0: { // Body return _int32_from_le (section->payload.body.bson); } case 1: { // Document Sequence return section->payload.document_sequence.section_len; } default: BSON_UNREACHABLE ("invalid section kind"); } } const char * mcd_rpc_op_msg_section_get_identifier (const mcd_rpc_message *rpc, size_t index) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); const mcd_rpc_op_msg_section *const section = &rpc->op_msg.sections[index]; BSON_ASSERT (section->kind == 1); return section->payload.document_sequence.identifier; } const void * mcd_rpc_op_msg_section_get_body (const mcd_rpc_message *rpc, size_t index) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); const mcd_rpc_op_msg_section *const section = &rpc->op_msg.sections[index]; BSON_ASSERT (section->kind == 0); return section->payload.body.bson; } const void * mcd_rpc_op_msg_section_get_document_sequence (const mcd_rpc_message *rpc, size_t index) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); const mcd_rpc_op_msg_section *const section = &rpc->op_msg.sections[index]; BSON_ASSERT (section->kind == 1); return section->payload.document_sequence.bson_objects; } size_t mcd_rpc_op_msg_section_get_document_sequence_length (const mcd_rpc_message *rpc, size_t index) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); const mcd_rpc_op_msg_section *const section = &rpc->op_msg.sections[index]; BSON_ASSERT (section->kind == 1); return section->payload.document_sequence.bson_objects_len; } int32_t mcd_rpc_op_msg_section_set_kind (mcd_rpc_message *rpc, size_t index, uint8_t kind) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); rpc->op_msg.sections[index].kind = kind; return sizeof (kind); } int32_t mcd_rpc_op_msg_section_set_length (mcd_rpc_message *rpc, size_t index, int32_t length) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); BSON_ASSERT (rpc->op_msg.sections[index].kind == 1); rpc->op_msg.sections[index].payload.document_sequence.section_len = length; return sizeof (length); } int32_t mcd_rpc_op_msg_section_set_identifier (mcd_rpc_message *rpc, size_t index, const char *identifier) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); BSON_ASSERT (rpc->op_msg.sections[index].kind == 1); const size_t identifier_len = identifier ? strlen (identifier) + 1u : 0u; rpc->op_msg.sections[index].payload.document_sequence.identifier = identifier; rpc->op_msg.sections[index].payload.document_sequence.identifier_len = identifier_len; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, identifier_len)); return (int32_t) identifier_len; } int32_t mcd_rpc_op_msg_section_set_body (mcd_rpc_message *rpc, size_t index, const void *body) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); BSON_ASSERT (rpc->op_msg.sections[index].kind == 0); const int32_t section_len = body ? _int32_from_le (body) : 0; rpc->op_msg.sections[index].payload.body.bson = body; rpc->op_msg.sections[index].payload.body.section_len = section_len; return section_len; } int32_t mcd_rpc_op_msg_section_set_document_sequence (mcd_rpc_message *rpc, size_t index, const void *document_sequence, size_t document_sequence_length) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); BSON_ASSERT (index < rpc->op_msg.sections_count); BSON_ASSERT (rpc->op_msg.sections[index].kind == 1); const size_t bson_objects_len = document_sequence ? document_sequence_length : 0u; rpc->op_msg.sections[index].payload.document_sequence.bson_objects = document_sequence; rpc->op_msg.sections[index].payload.document_sequence.bson_objects_len = bson_objects_len; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, document_sequence_length)); return (int32_t) bson_objects_len; } uint32_t mcd_rpc_op_msg_get_flag_bits (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); return rpc->op_msg.flag_bits; } size_t mcd_rpc_op_msg_get_sections_count (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); return rpc->op_msg.sections_count; } const uint32_t * mcd_rpc_op_msg_get_checksum (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); return rpc->op_msg.checksum_set ? &rpc->op_msg.checksum : NULL; } int32_t mcd_rpc_op_msg_set_flag_bits (mcd_rpc_message *rpc, uint32_t flag_bits) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); rpc->op_msg.flag_bits = flag_bits; return sizeof (flag_bits); } void mcd_rpc_op_msg_set_sections_count (mcd_rpc_message *rpc, size_t section_count) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); rpc->op_msg.sections = bson_realloc (rpc->op_msg.sections, section_count * sizeof (mcd_rpc_op_msg_section)); rpc->op_msg.sections_count = section_count; } int32_t mcd_rpc_op_msg_set_checksum (mcd_rpc_message *rpc, uint32_t checksum) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_MSG); rpc->op_msg.checksum = checksum; rpc->op_msg.checksum_set = true; return sizeof (checksum); } int32_t mcd_rpc_op_reply_get_response_flags (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_REPLY); return rpc->op_reply.response_flags; } int64_t mcd_rpc_op_reply_get_cursor_id (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_REPLY); return rpc->op_reply.cursor_id; } int32_t mcd_rpc_op_reply_get_starting_from (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_REPLY); return rpc->op_reply.starting_from; } int32_t mcd_rpc_op_reply_get_number_returned (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_REPLY); return rpc->op_reply.number_returned; } const void * mcd_rpc_op_reply_get_documents (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_REPLY); return rpc->op_reply.documents_len > 0 ? rpc->op_reply.documents : NULL; } size_t mcd_rpc_op_reply_get_documents_len (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_REPLY); return rpc->op_reply.documents_len; } int32_t mcd_rpc_op_reply_set_response_flags (mcd_rpc_message *rpc, int32_t response_flags) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->op_reply.response_flags = response_flags; return sizeof (response_flags); } int32_t mcd_rpc_op_reply_set_cursor_id (mcd_rpc_message *rpc, int64_t cursor_id) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->op_reply.cursor_id = cursor_id; return sizeof (cursor_id); } int32_t mcd_rpc_op_reply_set_starting_from (mcd_rpc_message *rpc, int32_t starting_from) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->op_reply.starting_from = starting_from; return sizeof (starting_from); } int32_t mcd_rpc_op_reply_set_number_returned (mcd_rpc_message *rpc, int32_t number_returned) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->op_reply.number_returned = number_returned; return sizeof (number_returned); } int32_t mcd_rpc_op_reply_set_documents (mcd_rpc_message *rpc, const void *documents, size_t documents_len) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->op_reply.documents = documents; rpc->op_reply.documents_len = documents_len; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, documents_len)); return (int32_t) documents_len; } const char * mcd_rpc_op_update_get_full_collection_name (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_UPDATE); return rpc->op_update.full_collection_name; } int32_t mcd_rpc_op_update_get_flags (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_UPDATE); return rpc->op_update.flags; } const void * mcd_rpc_op_update_get_selector (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_UPDATE); return rpc->op_update.selector; } const void * mcd_rpc_op_update_get_update (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_UPDATE); return rpc->op_update.update; } int32_t mcd_rpc_op_update_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; const size_t length = full_collection_name ? strlen (full_collection_name) + 1u : 0u; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_UPDATE); rpc->op_update.full_collection_name = full_collection_name; rpc->op_update.full_collection_name_len = length; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, length)); return (int32_t) length; } int32_t mcd_rpc_op_update_set_flags (mcd_rpc_message *rpc, int32_t flags) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->op_update.flags = flags; return sizeof (flags); } int32_t mcd_rpc_op_update_set_selector (mcd_rpc_message *rpc, const void *selector) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->op_update.selector = selector; return selector ? _int32_from_le (selector) : 0; } int32_t mcd_rpc_op_update_set_update (mcd_rpc_message *rpc, const void *update) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; rpc->op_update.update = update; return update ? _int32_from_le (update) : 0; } int32_t mcd_rpc_op_insert_get_flags (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_INSERT); return rpc->op_insert.flags; } const char * mcd_rpc_op_insert_get_full_collection_name (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_INSERT); return rpc->op_insert.full_collection_name; } const void * mcd_rpc_op_insert_get_documents (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_INSERT); return rpc->op_insert.documents; } size_t mcd_rpc_op_insert_get_documents_len (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_INSERT); return rpc->op_insert.documents_len; } int32_t mcd_rpc_op_insert_set_flags (mcd_rpc_message *rpc, int32_t flags) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_INSERT); rpc->op_insert.flags = flags; return sizeof (flags); } int32_t mcd_rpc_op_insert_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_INSERT); const size_t length = full_collection_name ? strlen (full_collection_name) + 1u : 0u; rpc->op_insert.full_collection_name = full_collection_name; rpc->op_insert.full_collection_name_len = length; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, length)); return (int32_t) length; } int32_t mcd_rpc_op_insert_set_documents (mcd_rpc_message *rpc, const void *documents, size_t documents_len) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_INSERT); rpc->op_insert.documents = documents; rpc->op_insert.documents_len = documents_len; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, documents_len)); return (int32_t) documents_len; } int32_t mcd_rpc_op_query_get_flags (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); return rpc->op_query.flags; } const char * mcd_rpc_op_query_get_full_collection_name (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); return rpc->op_query.full_collection_name; } int32_t mcd_rpc_op_query_get_number_to_skip (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); return rpc->op_query.number_to_skip; } int32_t mcd_rpc_op_query_get_number_to_return (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); return rpc->op_query.number_to_return; } const void * mcd_rpc_op_query_get_query (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); return rpc->op_query.query; } const void * mcd_rpc_op_query_get_return_fields_selector (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); return rpc->op_query.return_fields_selector; } int32_t mcd_rpc_op_query_set_flags (mcd_rpc_message *rpc, int32_t flags) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); rpc->op_query.flags = flags; return sizeof (flags); } int32_t mcd_rpc_op_query_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); const size_t length = full_collection_name ? strlen (full_collection_name) + 1u : 0u; rpc->op_query.full_collection_name = full_collection_name; rpc->op_query.full_collection_name_len = length; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, length)); return (int32_t) length; } int32_t mcd_rpc_op_query_set_number_to_skip (mcd_rpc_message *rpc, int32_t number_to_skip) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); rpc->op_query.number_to_skip = number_to_skip; return sizeof (number_to_skip); } int32_t mcd_rpc_op_query_set_number_to_return (mcd_rpc_message *rpc, int32_t number_to_return) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); rpc->op_query.number_to_return = number_to_return; return sizeof (number_to_return); } int32_t mcd_rpc_op_query_set_query (mcd_rpc_message *rpc, const void *query) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); rpc->op_query.query = query; return _int32_from_le (query); } int32_t mcd_rpc_op_query_set_return_fields_selector (mcd_rpc_message *rpc, const void *return_fields_selector) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_QUERY); rpc->op_query.return_fields_selector = return_fields_selector; return return_fields_selector ? _int32_from_le (return_fields_selector) : 0; } const char * mcd_rpc_op_get_more_get_full_collection_name (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_GET_MORE); return rpc->op_get_more.full_collection_name; } int32_t mcd_rpc_op_get_more_get_number_to_return (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_GET_MORE); return rpc->op_get_more.number_to_return; } int64_t mcd_rpc_op_get_more_get_cursor_id (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_GET_MORE); return rpc->op_get_more.cursor_id; } int32_t mcd_rpc_op_get_more_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_GET_MORE); const size_t length = full_collection_name ? strlen (full_collection_name) + 1u : 0u; rpc->op_get_more.full_collection_name = full_collection_name; rpc->op_get_more.full_collection_name_len = length; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, length)); return (int32_t) length; } int32_t mcd_rpc_op_get_more_set_number_to_return (mcd_rpc_message *rpc, int32_t number_to_return) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_GET_MORE); rpc->op_get_more.number_to_return = number_to_return; return sizeof (number_to_return); } int32_t mcd_rpc_op_get_more_set_cursor_id (mcd_rpc_message *rpc, int64_t cursor_id) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_GET_MORE); rpc->op_get_more.cursor_id = cursor_id; return sizeof (cursor_id); } const char * mcd_rpc_op_delete_get_full_collection_name (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_DELETE); return rpc->op_delete.full_collection_name; } int32_t mcd_rpc_op_delete_get_flags (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; return rpc->op_delete.flags; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_DELETE); } const void * mcd_rpc_op_delete_get_selector (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_DELETE); return rpc->op_delete.selector; } int32_t mcd_rpc_op_delete_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_DELETE); const size_t length = full_collection_name ? strlen (full_collection_name) + 1u : 0u; rpc->op_delete.full_collection_name = full_collection_name; rpc->op_delete.full_collection_name_len = length; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, length)); return (int32_t) length; } int32_t mcd_rpc_op_delete_set_flags (mcd_rpc_message *rpc, int32_t flags) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_DELETE); rpc->op_delete.flags = flags; return sizeof (flags); } int32_t mcd_rpc_op_delete_set_selector (mcd_rpc_message *rpc, const void *selector) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_DELETE); rpc->op_delete.selector = selector; return selector ? _int32_from_le (selector) : 0; } int32_t mcd_rpc_op_kill_cursors_get_number_of_cursor_ids (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_KILL_CURSORS); return rpc->op_kill_cursors.number_of_cursor_ids; } const int64_t * mcd_rpc_op_kill_cursors_get_cursor_ids (const mcd_rpc_message *rpc) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_KILL_CURSORS); return rpc->op_kill_cursors.number_of_cursor_ids > 0 ? rpc->op_kill_cursors.cursor_ids : NULL; } int32_t mcd_rpc_op_kill_cursors_set_cursor_ids (mcd_rpc_message *rpc, const int64_t *cursor_ids, int32_t number_of_cursor_ids) { ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS; BSON_ASSERT (rpc->msg_header.op_code == MONGOC_OP_CODE_KILL_CURSORS); BSON_ASSERT (mcommon_cmp_less_su (number_of_cursor_ids, (size_t) INT32_MAX / sizeof (int64_t))); const size_t cursor_ids_length = (size_t) number_of_cursor_ids * sizeof (int64_t); rpc->op_kill_cursors.number_of_cursor_ids = number_of_cursor_ids; bson_free (rpc->op_kill_cursors.cursor_ids); if (number_of_cursor_ids > 0) { rpc->op_kill_cursors.cursor_ids = bson_malloc (cursor_ids_length); memcpy (rpc->op_kill_cursors.cursor_ids, cursor_ids, cursor_ids_length); } else { rpc->op_kill_cursors.cursor_ids = NULL; } return (int32_t) sizeof (int32_t) + (int32_t) cursor_ids_length; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mcd-rpc.h0000644000175100001660000006254514760300420021220 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(MCD_RPC_H_INCLUDED) #define MCD_RPC_H_INCLUDED #include #include #include #ifdef __cplusplus extern "C" { #endif typedef union _mcd_rpc_message mcd_rpc_message; // See: https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol #define MONGOC_OP_CODE_NONE INT32_C (0) #define MONGOC_OP_CODE_COMPRESSED INT32_C (2012) #define MONGOC_OP_CODE_MSG INT32_C (2013) #define MONGOC_OP_COMPRESSED_COMPRESSOR_ID_NOOP UINT8_C (0) #define MONGOC_OP_COMPRESSED_COMPRESSOR_ID_SNAPPY UINT8_C (1) #define MONGOC_OP_COMPRESSED_COMPRESSOR_ID_ZLIB UINT8_C (2) #define MONGOC_OP_COMPRESSED_COMPRESSOR_ID_ZSTD UINT8_C (3) #define MONGOC_OP_MSG_FLAG_NONE UINT32_C (0) #define MONGOC_OP_MSG_FLAG_CHECKSUM_PRESENT (UINT32_C (0x01) << 0) #define MONGOC_OP_MSG_FLAG_MORE_TO_COME (UINT32_C (0x01) << 1) #define MONGOC_OP_MSG_FLAG_EXHAUST_ALLOWED (UINT32_C (0x01) << 16) // See: https://www.mongodb.com/docs/manual/legacy-opcodes/ #define MONGOC_OP_CODE_REPLY INT32_C (1) #define MONGOC_OP_CODE_UPDATE INT32_C (2001) #define MONGOC_OP_CODE_INSERT INT32_C (2002) #define MONGOC_OP_CODE_QUERY INT32_C (2004) #define MONGOC_OP_CODE_GET_MORE INT32_C (2005) #define MONGOC_OP_CODE_DELETE INT32_C (2006) #define MONGOC_OP_CODE_KILL_CURSORS INT32_C (2007) #define MONGOC_OP_REPLY_RESPONSE_FLAG_NONE INT32_C (0) #define MONGOC_OP_REPLY_RESPONSE_FLAG_CURSOR_NOT_FOUND (INT32_C (0x01) << 0) #define MONGOC_OP_REPLY_RESPONSE_FLAG_QUERY_FAILURE (INT32_C (0x01) << 1) #define MONGOC_OP_REPLY_RESPONSE_FLAG_SHARD_CONFIG_STALE (INT32_C (0x01) << 2) #define MONGOC_OP_REPLY_RESPONSE_FLAG_AWAIT_CAPABLE (INT32_C (0x01) << 3) #define MONGOC_OP_UPDATE_FLAG_NONE INT32_C (0) #define MONGOC_OP_UPDATE_FLAG_UPSERT (INT32_C (0x01) << 0) #define MONGOC_OP_UPDATE_FLAG_MULTI_UPDATE (INT32_C (0x01) << 1) #define MONGOC_OP_INSERT_FLAG_NONE INT32_C (0) #define MONGOC_OP_INSERT_FLAG_CONTINUE_ON_ERROR (INT32_C (0x01) << 0) #define MONGOC_OP_QUERY_FLAG_NONE INT32_C (0) #define MONGOC_OP_QUERY_FLAG_TAILABLE_CURSOR (INT32_C (0x01) << 1) #define MONGOC_OP_QUERY_FLAG_SECONDARY_OK (INT32_C (0x01) << 2) #define MONGOC_OP_QUERY_FLAG_OPLOG_REPLAY (INT32_C (0x01) << 3) #define MONGOC_OP_QUERY_FLAG_NO_CURSOR_TIMEOUT (INT32_C (0x01) << 4) #define MONGOC_OP_QUERY_FLAG_AWAIT_DATA (INT32_C (0x01) << 5) #define MONGOC_OP_QUERY_FLAG_EXHAUST (INT32_C (0x01) << 6) #define MONGOC_OP_QUERY_FLAG_PARTIAL (INT32_C (0x01) << 7) #define MONGOC_OP_DELETE_FLAG_NONE INT32_C (0) #define MONGOC_OP_DELETE_FLAG_SINGLE_REMOVE (INT32_C (0x01) << 0) // Convert the given array of bytes into an RPC message object. The RPC message // object must be freed by `mcd_rpc_message_destroy`. // // data: an array of `length` bytes. // data_end: if not `NULL`, `*data_end` is set to one past the last byte of // valid input data. Useful for diagnosing failures. // // Note: the fields of the RPC message object are automatically converted from // little endian to native endian. // // Returns the new RPC message object on success. Returns `NULL` on failure. mcd_rpc_message * mcd_rpc_message_from_data (const void *data, size_t length, const void **data_end); // The in-place version of `mcd_rpc_message_from_data`. // // rpc: an RPC message object in an initialized state. // // Returns `true` on success. Returns `false` on failure. bool mcd_rpc_message_from_data_in_place (mcd_rpc_message *rpc, const void *data, size_t length, const void **data_end); // Convert the given RPC message object into an array of iovec structures, // putting the RPC message object in an iovecs state. The return value must be // freed by `bson_free`. // // Unless otherwise specified, it is undefined behavior to access any RPC // message field when the object is in an iovecs state. Use // `mcd_rpc_message_reset` to return the object to an initialized state before // further reuse. // // The data layout of the iovec structures is consistent with the definition of // `mongoc_iovec_t` as defined in ``. // // rpc: a valid RPC message object whose fields are in native endian. // length: if not `NULL`, `*length` is set to the number of iovec structures in // the array. // // Returns the array of iovec structures on success. Returns `NULL` on failure. void * mcd_rpc_message_to_iovecs (mcd_rpc_message *rpc, size_t *count); // Return an RPC message object in an initialized state whose fields will be set // manually. The return value must be freed by `mcd_rpc_message_destroy`. mcd_rpc_message * mcd_rpc_message_new (void); // Destroy the given RPC message object. void mcd_rpc_message_destroy (mcd_rpc_message *rpc); // Restore the given RPC message object to an initialized state. void mcd_rpc_message_reset (mcd_rpc_message *rpc); // Set the message length for the given RPC message object. Expected to be used // in conjunction with the return values of setters. void mcd_rpc_message_set_length (mcd_rpc_message *rpc, int32_t value); // Get the msgHeader.messageLength field. int32_t mcd_rpc_header_get_message_length (const mcd_rpc_message *rpc); // Get the msgHeader.requestId field. int32_t mcd_rpc_header_get_request_id (const mcd_rpc_message *rpc); // Get the msgHeader.responseTo field. int32_t mcd_rpc_header_get_response_to (const mcd_rpc_message *rpc); // Get the msgHeader.opCode field. // // This function may be called even if the RPC message is in an iovecs state. int32_t mcd_rpc_header_get_op_code (const mcd_rpc_message *rpc); // Set the msgHeader.messageLength field. // // Returns the length of the field as part of msgHeader.messageLength. int32_t mcd_rpc_header_set_message_length (mcd_rpc_message *rpc, int32_t message_length); // Set the msgHeader.requestId field. // // Returns the length of the field as part of msgHeader.messageLength. int32_t mcd_rpc_header_set_request_id (mcd_rpc_message *rpc, int32_t request_id); // Set the msgHeader.responseTo field. // // Returns the length of the field as part of msgHeader.messageLength. int32_t mcd_rpc_header_set_response_to (mcd_rpc_message *rpc, int32_t response_to); // Set the msgHeader.opCode field. // // Note: the msgHeader.opCode field may be set more than once. // // Returns the length of the field as part of msgHeader.messageLength. int32_t mcd_rpc_header_set_op_code (mcd_rpc_message *rpc, int32_t op_code); // Get the OP_COMPRESSED originalOpcode field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. // // This function may be called even if the RPC message is in an iovecs state. int32_t mcd_rpc_op_compressed_get_original_opcode (const mcd_rpc_message *rpc); // Get the OP_COMPRESSED uncompressedSize field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. int32_t mcd_rpc_op_compressed_get_uncompressed_size (const mcd_rpc_message *rpc); // Get the OP_COMPRESSED compressorId field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. uint8_t mcd_rpc_op_compressed_get_compressor_id (const mcd_rpc_message *rpc); // Get the OP_COMPRESSED compressedMessage field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. const void * mcd_rpc_op_compressed_get_compressed_message (const mcd_rpc_message *rpc); // Get the length of the OP_COMPRESSED compressedMessage field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. size_t mcd_rpc_op_compressed_get_compressed_message_length (const mcd_rpc_message *rpc); // Set the OP_COMPRESSED originalOpcode field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. int32_t mcd_rpc_op_compressed_set_original_opcode (mcd_rpc_message *rpc, int32_t original_opcode); // Set the OP_COMPRESSED uncompressedSize field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. int32_t mcd_rpc_op_compressed_set_uncompressed_size (mcd_rpc_message *rpc, int32_t uncompressed_size); // Set the OP_COMPRESSED compressorId field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. int32_t mcd_rpc_op_compressed_set_compressor_id (mcd_rpc_message *rpc, uint8_t compressor_id); // Set the OP_COMPRESSED compressedMessage field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_COMPRESSED. int32_t mcd_rpc_op_compressed_set_compressed_message (mcd_rpc_message *rpc, const void *compressed_message, size_t compressed_message_length); // Get the kind byte for the OP_MSG section at the given index. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. uint8_t mcd_rpc_op_msg_section_get_kind (const mcd_rpc_message *rpc, size_t index); // Get the length of the OP_MSG section at the given index. // // If the section kind is 0, returns the length of the single BSON object. // If the section kind is 1, returns the total length of the section. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. int32_t mcd_rpc_op_msg_section_get_length (const mcd_rpc_message *rpc, size_t index); // Get the document sequence identifier of the OP_MSG document sequence section // at the given index. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. // The section kind at the given index MUST equal 1. const char * mcd_rpc_op_msg_section_get_identifier (const mcd_rpc_message *rpc, size_t index); // Get a pointer to the beginning of the single BSON object of the OP_MSG body // section at the given index. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. // The section kind at the given index MUST equal 0. const void * mcd_rpc_op_msg_section_get_body (const mcd_rpc_message *rpc, size_t index); // Get a pointer to the beginning of the document sequence of the OP_MSG // document sequence section at the given index. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. // The section kind at the given index MUST equal 1. const void * mcd_rpc_op_msg_section_get_document_sequence (const mcd_rpc_message *rpc, size_t index); // Get the length of the document sequence of the OP_MSG document sequence // section at the given index. // // Note: the length is the number of bytes, NOT the number of documents. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. // The section kind at the given index MUST equal 1. size_t mcd_rpc_op_msg_section_get_document_sequence_length (const mcd_rpc_message *rpc, size_t index); // Set the kind byte for the OP_MSG section at the given index. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. int32_t mcd_rpc_op_msg_section_set_kind (mcd_rpc_message *rpc, size_t index, uint8_t kind); // Set the length of the OP_MSG document sequence section at the given index. // // Note: the section length of an OP_MSG body section is equal to the length // of the single BSON object, thus does not require a seperate setter. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. // The section kind at the given index MUST equal 1. int32_t mcd_rpc_op_msg_section_set_length (mcd_rpc_message *rpc, size_t index, int32_t length); // Set the document sequence identifier of the OP_MSG document sequence section // at the given index. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. // The section kind at the given index MUST equal 1. int32_t mcd_rpc_op_msg_section_set_identifier (mcd_rpc_message *rpc, size_t index, const char *identifier); // Set the BSON object for the OP_MSG body section at the given index. // // Note: the section length of an OP_MSG body section is equal to the length // of the single BSON object, thus does not require a seperate setter. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. // The section kind at the given index MUST equal 0. int32_t mcd_rpc_op_msg_section_set_body (mcd_rpc_message *rpc, size_t index, const void *body); // Set the document sequence for the OP_MSG document sequence section at the // given index. // // `document_sequence_length` MUST equal the length in bytes of the document // sequence. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. // The given index MUST be a valid index into the OP_MSG sections array. // The section kind at the given index MUST equal 1. int32_t mcd_rpc_op_msg_section_set_document_sequence (mcd_rpc_message *rpc, size_t index, const void *document_sequence, size_t document_sequence_length); // Get the OP_MSG flagBits field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. uint32_t mcd_rpc_op_msg_get_flag_bits (const mcd_rpc_message *rpc); // Get the number of sections in the OP_MSG sections array. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. size_t mcd_rpc_op_msg_get_sections_count (const mcd_rpc_message *rpc); // Get the OP_MSG checksum field. // // Returns `NULL` if the field is not set. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. const uint32_t * mcd_rpc_op_msg_get_checksum (const mcd_rpc_message *rpc); // Set the OP_MSG flagBits field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. int32_t mcd_rpc_op_msg_set_flag_bits (mcd_rpc_message *rpc, uint32_t flag_bits); // Set the number of sections in the OP_MSG section array. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. void mcd_rpc_op_msg_set_sections_count (mcd_rpc_message *rpc, size_t section_count); // Set the OP_MSG checksum field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_MSG. int32_t mcd_rpc_op_msg_set_checksum (mcd_rpc_message *rpc, uint32_t checksum); // Get the OP_REPLY responseFlags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int32_t mcd_rpc_op_reply_get_response_flags (const mcd_rpc_message *rpc); // Get the OP_REPLY cursorID field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int64_t mcd_rpc_op_reply_get_cursor_id (const mcd_rpc_message *rpc); // Get the OP_REPLY startingFrom field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int32_t mcd_rpc_op_reply_get_starting_from (const mcd_rpc_message *rpc); // Get the OP_REPLY numberReturned field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int32_t mcd_rpc_op_reply_get_number_returned (const mcd_rpc_message *rpc); // Get a pointer to the beginning of the OP_REPLY documents array. // // Returns `NULL` if the OP_REPLY numberReturned field equals 0. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. const void * mcd_rpc_op_reply_get_documents (const mcd_rpc_message *rpc); // Get the length of the OP_REPLY documents array. // // Note: the length is the number of bytes, NOT the number of documents. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. size_t mcd_rpc_op_reply_get_documents_len (const mcd_rpc_message *rpc); // Set the OP_REPLY responseFlags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int32_t mcd_rpc_op_reply_set_response_flags (mcd_rpc_message *rpc, int32_t response_flags); // Set the OP_REPLY cursorID field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int32_t mcd_rpc_op_reply_set_cursor_id (mcd_rpc_message *rpc, int64_t cursor_id); // Set the OP_REPLY startingFrom field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int32_t mcd_rpc_op_reply_set_starting_from (mcd_rpc_message *rpc, int32_t starting_from); // Set the OP_REPLY numberReturned field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int32_t mcd_rpc_op_reply_set_number_returned (mcd_rpc_message *rpc, int32_t number_returned); // Set the OP_REPLY documents field. // // `documents_len` MUST equal the length in bytes of the documents array. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_REPLY. int32_t mcd_rpc_op_reply_set_documents (mcd_rpc_message *rpc, const void *documents, size_t documents_len); // Get the OP_UPDATE fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_UPDATE. const char * mcd_rpc_op_update_get_full_collection_name (const mcd_rpc_message *rpc); // Get the OP_UPDATE flags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_UPDATE. int32_t mcd_rpc_op_update_get_flags (const mcd_rpc_message *rpc); // Get the OP_UPDATE selector field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_UPDATE. const void * mcd_rpc_op_update_get_selector (const mcd_rpc_message *rpc); // Get the OP_UPDATE update field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_UPDATE. const void * mcd_rpc_op_update_get_update (const mcd_rpc_message *rpc); // Set the OP_UPDATE fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_UPDATE. int32_t mcd_rpc_op_update_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name); // Set the OP_UPDATE flags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_UPDATE. int32_t mcd_rpc_op_update_set_flags (mcd_rpc_message *rpc, int32_t flags); // Set the OP_UPDATE selector field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_UPDATE. int32_t mcd_rpc_op_update_set_selector (mcd_rpc_message *rpc, const void *selector); // Set the OP_UPDATE update field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_UPDATE. int32_t mcd_rpc_op_update_set_update (mcd_rpc_message *rpc, const void *update); // Get the OP_INSERT flags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_INSERT. int32_t mcd_rpc_op_insert_get_flags (const mcd_rpc_message *rpc); // Get the OP_INSERT fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_INSERT. const char * mcd_rpc_op_insert_get_full_collection_name (const mcd_rpc_message *rpc); // Get a pointer to the beginning of the OP_INSERT documents array. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_INSERT. const void * mcd_rpc_op_insert_get_documents (const mcd_rpc_message *rpc); // Get the length of the OP_INSERT documents array. // // Note: the length is the number of bytes, NOT the number of documents. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_INSERT. size_t mcd_rpc_op_insert_get_documents_len (const mcd_rpc_message *rpc); // Set the OP_INSERT flags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_INSERT. int32_t mcd_rpc_op_insert_set_flags (mcd_rpc_message *rpc, int32_t flags); // Set the OP_INSERT fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_INSERT. int32_t mcd_rpc_op_insert_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name); // Set the OP_INSERT documents array. // // `documents_len` MUST equal the length in bytes of the documents array. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_INSERT. int32_t mcd_rpc_op_insert_set_documents (mcd_rpc_message *rpc, const void *documents, size_t documents_len); // Get the OP_QUERY flags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_get_flags (const mcd_rpc_message *rpc); // Get the OP_QUERY fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. const char * mcd_rpc_op_query_get_full_collection_name (const mcd_rpc_message *rpc); // Get the OP_QUERY numberToSkip field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_get_number_to_skip (const mcd_rpc_message *rpc); // Get the OP_QUERY numberToReturn field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_get_number_to_return (const mcd_rpc_message *rpc); // Get the OP_QUERY query field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. const void * mcd_rpc_op_query_get_query (const mcd_rpc_message *rpc); // Get the OP_QUERY returnFieldsSelector field. // // Returns `NULL` if the field is not set. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. const void * mcd_rpc_op_query_get_return_fields_selector (const mcd_rpc_message *rpc); // Set the OP_QUERY flags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_set_flags (mcd_rpc_message *rpc, int32_t flags); // Set the OP_QUERY fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name); // Set the OP_QUERY numberToSkip field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_set_number_to_skip (mcd_rpc_message *rpc, int32_t number_to_skip); // Set the OP_QUERY numberToReturn field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_set_number_to_return (mcd_rpc_message *rpc, int32_t number_to_return); // Set the OP_QUERY query field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_set_query (mcd_rpc_message *rpc, const void *query); // Set the OP_QUERY returnFieldsSelector field. // // Note: `return_fields_selector` may be `NULL` to unset the field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_QUERY. int32_t mcd_rpc_op_query_set_return_fields_selector (mcd_rpc_message *rpc, const void *return_fields_selector); // Get the OP_GET_MORE fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_GET_MORE. const char * mcd_rpc_op_get_more_get_full_collection_name (const mcd_rpc_message *rpc); // Get the OP_GET_MORE numberToReturn field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_GET_MORE. int32_t mcd_rpc_op_get_more_get_number_to_return (const mcd_rpc_message *rpc); // Get the OP_GET_MORE cursorID field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_GET_MORE. int64_t mcd_rpc_op_get_more_get_cursor_id (const mcd_rpc_message *rpc); // Set the OP_GET_MORE fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_GET_MORE. int32_t mcd_rpc_op_get_more_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name); // Set the OP_GET_MORE numberToReturn field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_GET_MORE. int32_t mcd_rpc_op_get_more_set_number_to_return (mcd_rpc_message *rpc, int32_t number_to_return); // Set the OP_GET_MORE cursorID field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_GET_MORE. int32_t mcd_rpc_op_get_more_set_cursor_id (mcd_rpc_message *rpc, int64_t cursor_id); // Get the OP_DELETE fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_DELETE. const char * mcd_rpc_op_delete_get_full_collection_name (const mcd_rpc_message *rpc); // Get the OP_DELETE flags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_DELETE. int32_t mcd_rpc_op_delete_get_flags (const mcd_rpc_message *rpc); // Get the OP_DELETE selector field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_DELETE. const void * mcd_rpc_op_delete_get_selector (const mcd_rpc_message *rpc); // Set the OP_DELETE fullCollectionName field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_DELETE. int32_t mcd_rpc_op_delete_set_full_collection_name (mcd_rpc_message *rpc, const char *full_collection_name); // Set the OP_DELETE flags field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_DELETE. int32_t mcd_rpc_op_delete_set_flags (mcd_rpc_message *rpc, int32_t flags); // Set the OP_DELETE selector field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_DELETE. int32_t mcd_rpc_op_delete_set_selector (mcd_rpc_message *rpc, const void *selector); // Get the OP_KILL_CURSORS numberOfCursorIDs field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_KILL_CURSORS. int32_t mcd_rpc_op_kill_cursors_get_number_of_cursor_ids (const mcd_rpc_message *rpc); // Get the OP_KILL_CURSORS cursorIDs field. // // Returns `NULL` if the OP_KILL_CURSORS numberOfCursorIDs field equals 0. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_KILL_CURSORS. const int64_t * mcd_rpc_op_kill_cursors_get_cursor_ids (const mcd_rpc_message *rpc); // Set the OP_KILL_CURSORS cursorIDs field. // // The msgHeader.opCode field MUST equal MONGOC_OP_CODE_KILL_CURSORS. int32_t mcd_rpc_op_kill_cursors_set_cursor_ids (mcd_rpc_message *rpc, const int64_t *cursor_ids, int32_t number_of_cursor_ids); #ifdef __cplusplus } #endif #endif // !defined(MCD_RPC_H_INCLUDED) mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mcd-time.h0000644000175100001660000002466414760300420021372 0ustar /** * Copyright 2009-present MongoDB, 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. */ #ifndef MCD_TIME_H_INCLUDED #define MCD_TIME_H_INCLUDED #include #include #include /** * @brief Represents an abstract point-in-time. * * @note This is an *abstract* time point, with the only guarantee that it * is strictly ordered with every other time point and that the difference * between any two times will roughly encode actual wall-clock durations. */ typedef struct mcd_time_point { /// The internal representation of the time. int64_t _rep; } mcd_time_point; /// The latest representable future point-in-time #define MCD_TIME_POINT_MAX ((mcd_time_point){._rep = INT64_MAX}) /// The oldest representable past point-in-time #define MCD_TIME_POINT_MIN ((mcd_time_point){._rep = INT64_MIN}) /** * @brief Represents a (possibly negative) duration of time. * * Construct this using one of the duration constructor functions. * * @note This encodes real wall-time durations, and may include negative * durations. It can be compared with other durations and used to offset * time points. */ typedef struct mcd_duration { /// An internal representation of the duration int64_t _rep; } mcd_duration; /// The maximum representable duration #define MCD_DURATION_MAX ((mcd_duration){._rep = INT64_MAX}) /// The minimal representable (negative) duration #define MCD_DURATION_MIN ((mcd_duration){._rep = INT64_MIN}) /// A duration representing zero amount of time #define MCD_DURATION_ZERO ((mcd_duration){._rep = 0}) /** * @brief Obtain the current time point. This is only an abstract * monotonically increasing time, and does not necessarily correlate with * any real-world clock. */ static BSON_INLINE mcd_time_point mcd_now (void) { // Create a time point representing the current time. return (mcd_time_point){._rep = bson_get_monotonic_time ()}; } /** * @brief Create a duration from a number of microseconds. * * @param s A number of microseconds * @return mcd_duration A duration corresponding to 's' microseconds. * * @note Saturates to the min/max duration if the duration is too great in * magnitude. */ static BSON_INLINE mcd_duration mcd_microseconds (int64_t s) { // 'mcd_duration' is encoded in a number of microseconds, so we don't need to // do bounds checking here. return (mcd_duration){._rep = s}; } /** * @brief Create a duration from a number of milliseconds. * * @param s A number of milliseconds * @return mcd_duration A duration corresponding to 's' milliseconds. * * @note Saturates to the min/max duration if the duration is too great in * magnitude. */ static BSON_INLINE mcd_duration mcd_milliseconds (int64_t s) { // 1'000 microseconds per millisecond: if (_mcd_i64_mul_would_overflow (s, 1000)) { return s < 0 ? MCD_DURATION_MIN : MCD_DURATION_MAX; } return mcd_microseconds (s * 1000); } /** * @brief Create a duration from a number of seconds. * * @param s A number of seconds * @return mcd_duration A duration corresponding to 's' seconds. * * @note Saturates to the min/max duration if the duration is too great in * magnitude. */ static BSON_INLINE mcd_duration mcd_seconds (int64_t s) { // 1'000 milliseconds per second: if (_mcd_i64_mul_would_overflow (s, 1000)) { return s < 0 ? MCD_DURATION_MIN : MCD_DURATION_MAX; } return mcd_milliseconds (s * 1000); } /** * @brief Create a duration from a number of minutes. * * @param m A number of minutes * @return mcd_duration A duration corresponding to 's' minutes. * * @note Saturates to the min/max duration if the duration is too great in * magnitude. */ static BSON_INLINE mcd_duration mcd_minutes (int64_t m) { // Sixty seconds per minute: if (_mcd_i64_mul_would_overflow (m, 60)) { return m < 0 ? MCD_DURATION_MIN : MCD_DURATION_MAX; } return mcd_seconds (m * 60); } /** * @brief Obtain the count of full milliseconds encoded in the given duration * * @param d An abstract duration * @return int64_t The number of milliseconds in 'd' * * @note Does not round-trip with `mcd_milliseconds(N)` if N-milliseconds is * unrepresentable in the duration type. This only occurs in extreme durations */ static BSON_INLINE int64_t mcd_get_milliseconds (mcd_duration d) { return d._rep / 1000; } /** * @brief Obtain a point-in-time relative to a base time offset by the given * duration (which may be negative). * * @param from The basis of the time offset * @param delta The amount of time to shift the resulting time point * @return mcd_time_point If 'delta' is a positive duration, the result is a * point-in-time *after* 'from'. If 'delta' is a negative duration, the result * is a point-in-time *before* 'from'. * * @note If the resulting point-in-time is unrepresentable, the return value * will be clamped to MCD_TIME_POINT_MIN or MCD_TIME_POINT_MAX. */ static BSON_INLINE mcd_time_point mcd_later (mcd_time_point from, mcd_duration delta) { if (_mcd_i64_add_would_overflow (from._rep, delta._rep)) { return delta._rep < 0 ? MCD_TIME_POINT_MIN : MCD_TIME_POINT_MAX; } else { from._rep += delta._rep; return from; } } /** * @brief Obtain the duration between two points in time. * * @param then The target time * @param from The base time * @return mcd_duration The amount of time you would need to wait starting * at 'from' for the time to become 'then' (the result may be a negative * duration). * * Intuition: If "then" is "in the future" relative to "from", you will * receive a positive duration, indicating an amount of time to wait * beginning at 'from' to reach 'then'. If "then" is actually *before* * "from", you will receive a paradoxical *negative* duration, indicating * the amount of time needed to time-travel backwards to reach "then." */ static BSON_INLINE mcd_duration mcd_time_difference (mcd_time_point then, mcd_time_point from) { if (_mcd_i64_sub_would_overflow (then._rep, from._rep)) { if (from._rep < 0) { // Would overflow past the max return MCD_DURATION_MAX; } else { // Would overflow past the min return MCD_DURATION_MIN; } } else { int64_t diff = then._rep - from._rep; // Our time_point encodes the time using a microsecond counter. return mcd_microseconds (diff); } } /** * @brief Compare two time points to create an ordering. * * A time point "in the past" is "less than" a time point "in the future". * * @retval <0 If 'left' is before 'right' * @retval >0 If 'right' is before 'left' * @retval 0 If 'left' and 'right' are equivalent */ static BSON_INLINE int mcd_time_compare (mcd_time_point left, mcd_time_point right) { // Obtain the amount of time needed to wait from 'right' to reach // 'left' int64_t diff = mcd_time_difference (left, right)._rep; if (diff < 0) { // A negative duration indicates that 'left' is "before" 'right' return -1; } else if (diff > 0) { // A positive duration indicates that 'left' is "after" 'right' return 1; } else { // These time points are equivalent return 0; } } /** * @brief Compare two durations * * A duration D1 is "less than" a duration D2 if time-travelling/waiting for D1 * duration would end in the past relative to time-travelling/waiting for D2. * * @retval <0 If left is "less than" right * @retval >0 If left is "greater than" right * @retval 0 If left and right are equivalent */ static BSON_INLINE int mcd_duration_compare (mcd_duration left, mcd_duration right) { if (left._rep < right._rep) { return -1; } else if (left._rep > right._rep) { return 1; } else { return 0; } } /** * @brief Clamp a duration between two other durations * * @param dur The duration to transform * @param min The minimum duration * @param max The maximum duration * @retval min If `dur` < `min` * @retval max If `dur` > `max` * @retval dur Otherwise */ static BSON_INLINE mcd_duration mcd_duration_clamp (mcd_duration dur, mcd_duration min, mcd_duration max) { BSON_ASSERT (mcd_duration_compare (min, max) <= 0 && "Invalid min-max range given to mcd_duration_clamp()"); if (mcd_duration_compare (dur, min) < 0) { // The duration is less than the minimum return min; } else if (mcd_duration_compare (dur, max) > 0) { // The duration is greater than the maximum return max; } else { // The duration is in-bounds return dur; } } /// Represents a timer that can be expired typedef struct mcd_timer { /// The point in time after which the time will become expired. mcd_time_point expire_at; } mcd_timer; /// Create a time that will expire at the given time static BSON_INLINE mcd_timer mcd_timer_expire_at (mcd_time_point time) { return (mcd_timer){time}; } /** * @brief Create a timer that will expire after waiting for the given duration * relative to now * * @note If the duration is less-than or equal-to zero, the timer will already * have expired */ static BSON_INLINE mcd_timer mcd_timer_expire_after (mcd_duration after) { return mcd_timer_expire_at (mcd_later (mcd_now (), after)); } /** * @brief Obtain the amount of time that one will need to WAIT before the timer * will be an expired state. * * @return mcd_duration A non-negative duration. * * @note If the timer is already expired, returns a zero duration. Will never * return a negative duration. */ static BSON_INLINE mcd_duration mcd_timer_remaining (mcd_timer timer) { // Compute the distance until the expiry time relative to now mcd_duration remain = mcd_time_difference (timer.expire_at, mcd_now ()); // Compare that duration with a zero duration if (mcd_duration_compare (remain, mcd_microseconds (0)) < 0) { // The "remaining" time is less-than zero, which means the timer is // already expired, so we only need to wait for zero time: return mcd_microseconds (0); } // There is a positive amount of time remaining return remain; } #endif // MCD_TIME_H_INCLUDED mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-aggregate-private.h0000644000175100001660000000273714760300420024546 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_AGGREGATE_PRIVATE_H #define MONGOC_AGGREGATE_PRIVATE_H #include #include #include #include #include #include BSON_BEGIN_DECLS mongoc_cursor_t * _mongoc_aggregate (mongoc_client_t *client, const char *ns, mongoc_query_flags_t flags, const bson_t *pipeline, const bson_t *opts, const mongoc_read_prefs_t *user_rp, const mongoc_read_prefs_t *default_rp, const mongoc_read_concern_t *default_rc, const mongoc_write_concern_t *default_wc); bool _has_write_key (bson_iter_t *iter); BSON_END_DECLS #endif /* MONGOC_AGGREGATE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-aggregate.c0000644000175100001660000002520214760300420023061 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include /*-------------------------------------------------------------------------- * * _has_write_key -- * * Returns true if the aggregation pipeline's last stage is "$out" * or "$merge"; otherwise returns false. * * Side effects: * Advances @iter to the last element. * *-------------------------------------------------------------------------- */ bool _has_write_key (bson_iter_t *iter) { bson_iter_t stage; bson_iter_t next; memcpy (&next, iter, sizeof (bson_iter_t)); if (!bson_iter_next (&next)) { /* default to false when iter is emtpy */ return false; } while (bson_iter_next (iter)) { if (!bson_iter_next (&next) && BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_iter_recurse (iter, &stage); if (bson_iter_find (&stage, "$out")) { return true; } bson_iter_recurse (iter, &stage); if (bson_iter_find (&stage, "$merge")) { return true; } } } return false; } /*-------------------------------------------------------------------------- * * _make_agg_cmd -- * * Constructs an aggregate command. If @ns does not include a collection * name, 1 will be used in its place for the value of "aggregate" in the * command document. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @command is always initialized. * @error is set if there is a failure. * *-------------------------------------------------------------------------- */ static bool _make_agg_cmd ( const char *ns, const bson_t *pipeline, mongoc_aggregate_opts_t *opts, bson_t *command, bson_error_t *err) { const char *const dot = strstr (ns, "."); const char *error = NULL; const char *error_hint = NULL; bsonBuild (*command, kv ("aggregate", if (dot, /* Note: we're not validating that the collection name's length is one or more characters, as functions such as mongoc_client_get_collection also do not validate. */ // If 'ns' contains a dot, insert the string after the dot: then (cstr (dot + 1)), // Otherwise just an integer 1: else (int32 (1))))); if ((error = bsonBuildError)) { error_hint = "append-aggregate"; goto fail; } /* * The following will allow @pipeline to be either an array of * items for the pipeline, or {"pipeline": [...]}. */ bsonParse (*pipeline, find (keyWithType ("pipeline", array), // There is a "pipeline" array in the document append (*command, kv ("pipeline", iterValue (bsonVisitIter)))), else ( // We did not find a "pipeline" array. copy the pipeline as // an array into the command append (*command, kv ("pipeline", array (insert (*pipeline, true)))))); if ((error = bsonParseError)) { error_hint = "append-pipeline"; goto fail; } // Check if there is a $merge or $out in the pipeline for the command bool has_write_key = false; bsonParse (*command, find ( // Find the "pipeline" array keyWithType ("pipeline", array), parse ( // Find the last element of the pipeline array find (lastElement, // If it has an "$out" or "$merge" key, it is a // writing aggregate command. parse (find (key ("$out", "$merge"), do (has_write_key = true))))))); if ((error = bsonParseError)) { error_hint = "parse-pipeline"; goto fail; } bsonBuildAppend (*command, kv ("cursor", // If batchSize is set, and if we are not a writing command with zero // batchSize, append 'batchSize' to the cursor, otherwise leave the // 'cursor' as an empty subdocument. doc (if (opts->batchSize_is_set && !(has_write_key && opts->batchSize == 0), then (kv ("batchSize", int32 (opts->batchSize))))))); if ((error = bsonBuildError)) { error_hint = "build-cursor"; goto fail; } return true; fail: bson_set_error (err, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Error while building aggregate command [%s]: %s", error_hint, error); return false; } /* *-------------------------------------------------------------------------- * * _mongoc_aggregate -- * * Constructs a mongoc_cursor_t for an "aggregate" command. * * This function will always return a new mongoc_cursor_t that should * be freed with mongoc_cursor_destroy(). * * The cursor may fail once iterated upon, so check * mongoc_cursor_error() if mongoc_cursor_next() returns false. * * See https://www.mongodb.com/docs/manual/aggregation/ for more * information on how to build aggregation pipelines. * * Parameters: * @ns: Namespace (or database name for database-level aggregation). * @flags: Bitwise or of mongoc_query_flags_t or 0. * @pipeline: A bson_t containing the pipeline request. @pipeline * will be sent as an array type in the request. * @opts: A bson_t containing aggregation options, such as * bypassDocumentValidation (used with $out and $merge), maxTimeMS * (declaring maximum server execution time) and explain (return * information on the processing of the pipeline). * @user_rp: Optional read preferences for the command. * @default_rp: Default read preferences from the collection or database. * @default_rc: Default read concern from the collection or database. * @default_wc: Default write concern from the collection or database. * * Returns: * A newly allocated mongoc_cursor_t that should be freed with * mongoc_cursor_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_cursor_t * _mongoc_aggregate (mongoc_client_t *client, const char *ns, mongoc_query_flags_t flags, const bson_t *pipeline, const bson_t *opts, const mongoc_read_prefs_t *user_rp, const mongoc_read_prefs_t *default_rp, const mongoc_read_concern_t *default_rc, const mongoc_write_concern_t *default_wc) { mongoc_server_stream_t *server_stream = NULL; bool has_write_key; bson_iter_t ar; mongoc_cursor_t *cursor; bson_iter_t iter; bson_t command = BSON_INITIALIZER; bson_t cursor_opts; bool created_command; bson_error_t create_cmd_err = {0}; mongoc_aggregate_opts_t aggregate_opts; bson_error_t opts_err = {0}; bool parsed_opts; ENTRY; BSON_ASSERT (client); BSON_ASSERT (ns); BSON_ASSERT (pipeline); bson_init (&cursor_opts); _mongoc_cursor_flags_to_opts (flags, &cursor_opts, NULL); if (opts) { bson_concat (&cursor_opts /* destination */, opts /* source */); } parsed_opts = _mongoc_aggregate_opts_parse (client, opts, &aggregate_opts, &opts_err); if (parsed_opts) { created_command = _make_agg_cmd (ns, pipeline, &aggregate_opts, &command, &create_cmd_err); } else { created_command = false; } cursor = _mongoc_cursor_cmd_new ( client, ns, created_command ? &command : NULL, &cursor_opts, user_rp, default_rp, default_rc); bson_destroy (&command); bson_destroy (&cursor_opts); if (!parsed_opts) { memcpy (&cursor->error, &opts_err, sizeof (bson_error_t)); GOTO (done); } if (!created_command) { /* copy error back to cursor. */ memcpy (&cursor->error, &create_cmd_err, sizeof (bson_error_t)); GOTO (done); } if (mongoc_cursor_error (cursor, NULL)) { GOTO (done); } if (!_mongoc_read_prefs_validate (cursor->read_prefs, &cursor->error)) { GOTO (done); } /* pipeline could be like {pipeline: [{$out: 'test'}]} or [{$out: 'test'}] */ if (bson_iter_init_find (&iter, pipeline, "pipeline") && BSON_ITER_HOLDS_ARRAY (&iter) && bson_iter_recurse (&iter, &ar)) { has_write_key = _has_write_key (&ar); } else { if (!bson_iter_init (&iter, pipeline)) { bson_set_error (&cursor->error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Pipeline is invalid BSON"); GOTO (done); } has_write_key = _has_write_key (&iter); } /* This has an important effect on server selection when * readPreferences=secondary. Keep track of this fact for later use. */ cursor->is_aggr_with_write_stage = has_write_key; /* server id isn't enough. ensure we're connected & know wire version */ const mongoc_ss_log_context_t ss_log_context = {.operation = "aggregate"}; server_stream = _mongoc_cursor_fetch_stream (cursor, &ss_log_context); if (!server_stream) { GOTO (done); } /* Only inherit WriteConcern when aggregate has $out or $merge */ if (!aggregate_opts.write_concern_owned && has_write_key) { mongoc_write_concern_destroy (cursor->write_concern); cursor->write_concern = mongoc_write_concern_copy (default_wc); } done: _mongoc_aggregate_opts_cleanup (&aggregate_opts); mongoc_server_stream_cleanup (server_stream); /* null ok */ /* we always return the cursor, even if it fails; users can detect the * failure on performing a cursor operation. see CDRIVER-880. */ RETURN (cursor); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-apm-private.h0000644000175100001660000001606714760300420023376 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_APM_PRIVATE_H #define MONGOC_APM_PRIVATE_H #include #include BSON_BEGIN_DECLS /* forward decl */ struct _mongoc_cmd_t; struct _mongoc_apm_callbacks_t { mongoc_apm_command_started_cb_t started; mongoc_apm_command_succeeded_cb_t succeeded; mongoc_apm_command_failed_cb_t failed; mongoc_apm_server_changed_cb_t server_changed; mongoc_apm_server_opening_cb_t server_opening; mongoc_apm_server_closed_cb_t server_closed; mongoc_apm_topology_changed_cb_t topology_changed; mongoc_apm_topology_opening_cb_t topology_opening; mongoc_apm_topology_closed_cb_t topology_closed; mongoc_apm_server_heartbeat_started_cb_t server_heartbeat_started; mongoc_apm_server_heartbeat_succeeded_cb_t server_heartbeat_succeeded; mongoc_apm_server_heartbeat_failed_cb_t server_heartbeat_failed; }; /* * command monitoring events */ struct _mongoc_apm_command_started_t { bson_t *command; bool command_owned; const char *database_name; const char *command_name; int64_t request_id; int64_t operation_id; const mongoc_host_list_t *host; uint32_t server_id; bson_oid_t service_id; int64_t server_connection_id; void *context; }; struct _mongoc_apm_command_succeeded_t { int64_t duration; bson_t *reply; bool reply_owned; const char *command_name; const char *database_name; int64_t request_id; int64_t operation_id; const mongoc_host_list_t *host; uint32_t server_id; bson_oid_t service_id; int64_t server_connection_id; void *context; }; struct _mongoc_apm_command_failed_t { int64_t duration; const char *command_name; const char *database_name; const bson_error_t *error; bson_t *reply; bool reply_owned; int64_t request_id; int64_t operation_id; const mongoc_host_list_t *host; uint32_t server_id; bson_oid_t service_id; int64_t server_connection_id; void *context; }; /* * SDAM monitoring events */ struct _mongoc_apm_server_changed_t { const mongoc_host_list_t *host; bson_oid_t topology_id; const mongoc_server_description_t *previous_description; const mongoc_server_description_t *new_description; void *context; }; struct _mongoc_apm_server_opening_t { const mongoc_host_list_t *host; bson_oid_t topology_id; void *context; }; struct _mongoc_apm_server_closed_t { const mongoc_host_list_t *host; bson_oid_t topology_id; void *context; }; struct _mongoc_apm_topology_changed_t { bson_oid_t topology_id; const mongoc_topology_description_t *previous_description; const mongoc_topology_description_t *new_description; void *context; }; struct _mongoc_apm_topology_opening_t { bson_oid_t topology_id; void *context; }; struct _mongoc_apm_topology_closed_t { bson_oid_t topology_id; void *context; }; struct _mongoc_apm_server_heartbeat_started_t { const mongoc_host_list_t *host; void *context; bool awaited; }; struct _mongoc_apm_server_heartbeat_succeeded_t { int64_t duration_usec; const bson_t *reply; const mongoc_host_list_t *host; void *context; bool awaited; }; struct _mongoc_apm_server_heartbeat_failed_t { int64_t duration_usec; const bson_error_t *error; const mongoc_host_list_t *host; void *context; bool awaited; }; void mongoc_apm_command_started_init (mongoc_apm_command_started_t *event, const bson_t *command, const char *database_name, const char *command_name, int64_t request_id, int64_t operation_id, const mongoc_host_list_t *host, uint32_t server_id, const bson_oid_t *service_id, int64_t server_connection_id, bool *is_redacted, /* out */ void *context); void mongoc_apm_command_started_init_with_cmd (mongoc_apm_command_started_t *event, struct _mongoc_cmd_t *cmd, int64_t request_id, bool *is_redacted, /* out */ void *context); void mongoc_apm_command_started_cleanup (mongoc_apm_command_started_t *event); void mongoc_apm_command_succeeded_init (mongoc_apm_command_succeeded_t *event, int64_t duration, const bson_t *reply, const char *command_name, const char *database_name, int64_t request_id, int64_t operation_id, const mongoc_host_list_t *host, uint32_t server_id, const bson_oid_t *service_id, int64_t server_connection_id, bool force_redaction, void *context); void mongoc_apm_command_succeeded_cleanup (mongoc_apm_command_succeeded_t *event); void mongoc_apm_command_failed_init (mongoc_apm_command_failed_t *event, int64_t duration, const char *command_name, const char *database_name, const bson_error_t *error, const bson_t *reply, int64_t request_id, int64_t operation_id, const mongoc_host_list_t *host, uint32_t server_id, const bson_oid_t *service_id, int64_t server_connection_id, bool force_redaction, void *context); void mongoc_apm_command_failed_cleanup (mongoc_apm_command_failed_t *event); /** * @brief Determine whether the given command-related message is a "sensitive * command." * * @param command_name The name of the command being checked * @param body The body of the command request, reply, or failure. */ bool mongoc_apm_is_sensitive_command_message (const char *command_name, const bson_t *body); BSON_END_DECLS #endif /* MONGOC_APM_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-apm.c0000644000175100001660000006361714760300420021724 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include /* * An Application Performance Management (APM) implementation, complying with * MongoDB's Command Logging and Monitoring Spec: * * https://github.com/mongodb/specifications/tree/master/source/command-logging-and-monitoring */ static void append_documents_from_cmd (const mongoc_cmd_t *cmd, mongoc_apm_command_started_t *event) { // If there are no document sequences (OP_MSG Section with payloadType=1), return the command unchanged. if (cmd->payloads_count == 0) { return; } if (!event->command_owned) { event->command = bson_copy (event->command); event->command_owned = true; } _mongoc_cmd_append_payload_as_array (cmd, event->command); } /* * Private initializer / cleanup functions. */ static void mongoc_apm_redact_command (bson_t *command); static void mongoc_apm_redact_reply (bson_t *reply); /*-------------------------------------------------------------------------- * * mongoc_apm_command_started_init -- * * Initialises the command started event. * * Side effects: * If provided, is_redacted indicates whether the command document was * redacted to hide sensitive information. * *-------------------------------------------------------------------------- */ void mongoc_apm_command_started_init (mongoc_apm_command_started_t *event, const bson_t *command, const char *database_name, const char *command_name, int64_t request_id, int64_t operation_id, const mongoc_host_list_t *host, uint32_t server_id, const bson_oid_t *service_id, int64_t server_connection_id, bool *is_redacted, /* out */ void *context) { bson_iter_t iter; uint32_t len; const uint8_t *data; /* Command Monitoring Spec: * * In cases where queries or commands are embedded in a $query parameter * when a read preference is provided, they MUST be unwrapped and the value * of the $query attribute becomes the filter or the command in the started * event. The read preference will subsequently be dropped as it is * considered metadata and metadata is not currently provided in the command * events. */ if (bson_has_field (command, "$readPreference")) { if (bson_iter_init_find (&iter, command, "$query") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_iter_document (&iter, &len, &data); event->command = bson_new_from_data (data, len); event->command_owned = true; } else { /* Got $readPreference without $query, probably OP_MSG */ event->command = (bson_t *) command; event->command_owned = false; } } else { /* discard "const", we promise not to modify "command" */ event->command = (bson_t *) command; event->command_owned = false; } if (mongoc_apm_is_sensitive_command_message (command_name, command)) { if (!event->command_owned) { event->command = bson_copy (event->command); event->command_owned = true; } if (is_redacted) { *is_redacted = true; } mongoc_apm_redact_command (event->command); } else if (is_redacted) { *is_redacted = false; } event->database_name = database_name; event->command_name = command_name; event->request_id = request_id; event->operation_id = operation_id; event->host = host; event->server_id = server_id; event->context = context; event->server_connection_id = server_connection_id; bson_oid_copy_unsafe (service_id, &event->service_id); } /*-------------------------------------------------------------------------- * * mongoc_apm_command_started_init_with_cmd -- * * Initialises the command started event from a mongoc_cmd_t. * * Side effects: * If provided, is_redacted indicates whether the command document was * redacted to hide sensitive information. * *-------------------------------------------------------------------------- */ void mongoc_apm_command_started_init_with_cmd (mongoc_apm_command_started_t *event, mongoc_cmd_t *cmd, int64_t request_id, bool *is_redacted, /* out */ void *context) { mongoc_apm_command_started_init (event, cmd->command, cmd->db_name, cmd->command_name, request_id, cmd->operation_id, &cmd->server_stream->sd->host, cmd->server_stream->sd->id, &cmd->server_stream->sd->service_id, cmd->server_stream->sd->server_connection_id, is_redacted, context); /* OP_MSG document sequence for insert, update, or delete? */ append_documents_from_cmd (cmd, event); } void mongoc_apm_command_started_cleanup (mongoc_apm_command_started_t *event) { if (event->command_owned) { bson_destroy (event->command); } } /*-------------------------------------------------------------------------- * * mongoc_apm_command_succeeded_init -- * * Initialises the command succeeded event. * * Parameters: * @force_redaction: If true, the reply document is always redacted, * regardless of whether the command contains sensitive information. * *-------------------------------------------------------------------------- */ void mongoc_apm_command_succeeded_init (mongoc_apm_command_succeeded_t *event, int64_t duration, const bson_t *reply, const char *command_name, const char *database_name, int64_t request_id, int64_t operation_id, const mongoc_host_list_t *host, uint32_t server_id, const bson_oid_t *service_id, int64_t server_connection_id, bool force_redaction, void *context) { BSON_ASSERT (reply); if (force_redaction || mongoc_apm_is_sensitive_command_message (command_name, reply)) { event->reply = bson_copy (reply); event->reply_owned = true; mongoc_apm_redact_reply (event->reply); } else { /* discard "const", we promise not to modify "reply" */ event->reply = (bson_t *) reply; event->reply_owned = false; } event->duration = duration; event->command_name = command_name; event->database_name = database_name; event->request_id = request_id; event->operation_id = operation_id; event->host = host; event->server_id = server_id; event->server_connection_id = server_connection_id; event->context = context; bson_oid_copy_unsafe (service_id, &event->service_id); } void mongoc_apm_command_succeeded_cleanup (mongoc_apm_command_succeeded_t *event) { if (event->reply_owned) { bson_destroy (event->reply); } } /*-------------------------------------------------------------------------- * * mongoc_apm_command_failed_init -- * * Initialises the command failed event. * * Parameters: * @force_redaction: If true, the reply document is always redacted, * regardless of whether the command contains sensitive information. * *-------------------------------------------------------------------------- */ void mongoc_apm_command_failed_init (mongoc_apm_command_failed_t *event, int64_t duration, const char *command_name, const char *database_name, const bson_error_t *error, const bson_t *reply, int64_t request_id, int64_t operation_id, const mongoc_host_list_t *host, uint32_t server_id, const bson_oid_t *service_id, int64_t server_connection_id, bool force_redaction, void *context) { BSON_ASSERT (reply); if (force_redaction || mongoc_apm_is_sensitive_command_message (command_name, reply)) { event->reply = bson_copy (reply); event->reply_owned = true; mongoc_apm_redact_reply (event->reply); } else { /* discard "const", we promise not to modify "reply" */ event->reply = (bson_t *) reply; event->reply_owned = false; } event->duration = duration; event->command_name = command_name; event->database_name = database_name; event->error = error; event->request_id = request_id; event->operation_id = operation_id; event->host = host; event->server_id = server_id; event->server_connection_id = server_connection_id; event->context = context; bson_oid_copy_unsafe (service_id, &event->service_id); } void mongoc_apm_command_failed_cleanup (mongoc_apm_command_failed_t *event) { if (event->reply_owned) { bson_destroy (event->reply); } } /* * event field accessors */ /* command-started event fields */ const bson_t * mongoc_apm_command_started_get_command (const mongoc_apm_command_started_t *event) { return event->command; } const char * mongoc_apm_command_started_get_database_name (const mongoc_apm_command_started_t *event) { return event->database_name; } const char * mongoc_apm_command_started_get_command_name (const mongoc_apm_command_started_t *event) { return event->command_name; } int64_t mongoc_apm_command_started_get_request_id (const mongoc_apm_command_started_t *event) { return event->request_id; } int64_t mongoc_apm_command_started_get_operation_id (const mongoc_apm_command_started_t *event) { return event->operation_id; } const mongoc_host_list_t * mongoc_apm_command_started_get_host (const mongoc_apm_command_started_t *event) { return event->host; } uint32_t mongoc_apm_command_started_get_server_id (const mongoc_apm_command_started_t *event) { return event->server_id; } const bson_oid_t * mongoc_apm_command_started_get_service_id (const mongoc_apm_command_started_t *event) { if (mcommon_oid_is_zero (&event->service_id)) { /* serviceId is unset. */ return NULL; } return &event->service_id; } int32_t mongoc_apm_command_started_get_server_connection_id (const mongoc_apm_command_started_t *event) { if (event->server_connection_id > INT32_MAX || event->server_connection_id < INT32_MIN) { MONGOC_WARNING ("Server connection ID %" PRId64 " is outside of int32 range. Returning -1. Use " "mongoc_apm_command_started_get_server_connection_id_int64.", event->server_connection_id); return MONGOC_NO_SERVER_CONNECTION_ID; } return (int32_t) event->server_connection_id; } int64_t mongoc_apm_command_started_get_server_connection_id_int64 (const mongoc_apm_command_started_t *event) { return event->server_connection_id; } void * mongoc_apm_command_started_get_context (const mongoc_apm_command_started_t *event) { return event->context; } /* command-succeeded event fields */ int64_t mongoc_apm_command_succeeded_get_duration (const mongoc_apm_command_succeeded_t *event) { return event->duration; } const bson_t * mongoc_apm_command_succeeded_get_reply (const mongoc_apm_command_succeeded_t *event) { return event->reply; } const char * mongoc_apm_command_succeeded_get_command_name (const mongoc_apm_command_succeeded_t *event) { return event->command_name; } const char * mongoc_apm_command_succeeded_get_database_name (const mongoc_apm_command_succeeded_t *event) { return event->database_name; } int64_t mongoc_apm_command_succeeded_get_request_id (const mongoc_apm_command_succeeded_t *event) { return event->request_id; } int64_t mongoc_apm_command_succeeded_get_operation_id (const mongoc_apm_command_succeeded_t *event) { return event->operation_id; } const mongoc_host_list_t * mongoc_apm_command_succeeded_get_host (const mongoc_apm_command_succeeded_t *event) { return event->host; } uint32_t mongoc_apm_command_succeeded_get_server_id (const mongoc_apm_command_succeeded_t *event) { return event->server_id; } const bson_oid_t * mongoc_apm_command_succeeded_get_service_id (const mongoc_apm_command_succeeded_t *event) { if (mcommon_oid_is_zero (&event->service_id)) { /* serviceId is unset. */ return NULL; } return &event->service_id; } int32_t mongoc_apm_command_succeeded_get_server_connection_id (const mongoc_apm_command_succeeded_t *event) { if (event->server_connection_id > INT32_MAX || event->server_connection_id < INT32_MIN) { MONGOC_WARNING ("Server connection ID %" PRId64 " is outside of int32 range. Returning -1. Use " "mongoc_apm_command_succeeded_get_server_connection_id_int64.", event->server_connection_id); return MONGOC_NO_SERVER_CONNECTION_ID; } return (int32_t) event->server_connection_id; } int64_t mongoc_apm_command_succeeded_get_server_connection_id_int64 (const mongoc_apm_command_succeeded_t *event) { return event->server_connection_id; } void * mongoc_apm_command_succeeded_get_context (const mongoc_apm_command_succeeded_t *event) { return event->context; } /* command-failed event fields */ int64_t mongoc_apm_command_failed_get_duration (const mongoc_apm_command_failed_t *event) { return event->duration; } const char * mongoc_apm_command_failed_get_command_name (const mongoc_apm_command_failed_t *event) { return event->command_name; } void mongoc_apm_command_failed_get_error (const mongoc_apm_command_failed_t *event, bson_error_t *error) { memcpy (error, event->error, sizeof *event->error); } const bson_t * mongoc_apm_command_failed_get_reply (const mongoc_apm_command_failed_t *event) { return event->reply; } int64_t mongoc_apm_command_failed_get_request_id (const mongoc_apm_command_failed_t *event) { return event->request_id; } int64_t mongoc_apm_command_failed_get_operation_id (const mongoc_apm_command_failed_t *event) { return event->operation_id; } const mongoc_host_list_t * mongoc_apm_command_failed_get_host (const mongoc_apm_command_failed_t *event) { return event->host; } uint32_t mongoc_apm_command_failed_get_server_id (const mongoc_apm_command_failed_t *event) { return event->server_id; } const bson_oid_t * mongoc_apm_command_failed_get_service_id (const mongoc_apm_command_failed_t *event) { if (mcommon_oid_is_zero (&event->service_id)) { /* serviceId is unset. */ return NULL; } return &event->service_id; } int32_t mongoc_apm_command_failed_get_server_connection_id (const mongoc_apm_command_failed_t *event) { if (event->server_connection_id > INT32_MAX || event->server_connection_id < INT32_MIN) { MONGOC_WARNING ("Server connection ID %" PRId64 " is outside of int32 range. Returning -1. Use " "mongoc_apm_command_failed_get_server_connection_id_int64.", event->server_connection_id); return MONGOC_NO_SERVER_CONNECTION_ID; } return (int32_t) event->server_connection_id; } int64_t mongoc_apm_command_failed_get_server_connection_id_int64 (const mongoc_apm_command_failed_t *event) { return event->server_connection_id; } void * mongoc_apm_command_failed_get_context (const mongoc_apm_command_failed_t *event) { return event->context; } const char * mongoc_apm_command_failed_get_database_name (const mongoc_apm_command_failed_t *event) { return event->database_name; } /* server-changed event fields */ const mongoc_host_list_t * mongoc_apm_server_changed_get_host (const mongoc_apm_server_changed_t *event) { return event->host; } void mongoc_apm_server_changed_get_topology_id (const mongoc_apm_server_changed_t *event, bson_oid_t *topology_id) { bson_oid_copy (&event->topology_id, topology_id); } const mongoc_server_description_t * mongoc_apm_server_changed_get_previous_description (const mongoc_apm_server_changed_t *event) { return event->previous_description; } const mongoc_server_description_t * mongoc_apm_server_changed_get_new_description (const mongoc_apm_server_changed_t *event) { return event->new_description; } void * mongoc_apm_server_changed_get_context (const mongoc_apm_server_changed_t *event) { return event->context; } /* server-opening event fields */ const mongoc_host_list_t * mongoc_apm_server_opening_get_host (const mongoc_apm_server_opening_t *event) { return event->host; } void mongoc_apm_server_opening_get_topology_id (const mongoc_apm_server_opening_t *event, bson_oid_t *topology_id) { bson_oid_copy (&event->topology_id, topology_id); } void * mongoc_apm_server_opening_get_context (const mongoc_apm_server_opening_t *event) { return event->context; } /* server-closed event fields */ const mongoc_host_list_t * mongoc_apm_server_closed_get_host (const mongoc_apm_server_closed_t *event) { return event->host; } void mongoc_apm_server_closed_get_topology_id (const mongoc_apm_server_closed_t *event, bson_oid_t *topology_id) { bson_oid_copy (&event->topology_id, topology_id); } void * mongoc_apm_server_closed_get_context (const mongoc_apm_server_closed_t *event) { return event->context; } /* topology-changed event fields */ void mongoc_apm_topology_changed_get_topology_id (const mongoc_apm_topology_changed_t *event, bson_oid_t *topology_id) { bson_oid_copy (&event->topology_id, topology_id); } const mongoc_topology_description_t * mongoc_apm_topology_changed_get_previous_description (const mongoc_apm_topology_changed_t *event) { return event->previous_description; } const mongoc_topology_description_t * mongoc_apm_topology_changed_get_new_description (const mongoc_apm_topology_changed_t *event) { return event->new_description; } void * mongoc_apm_topology_changed_get_context (const mongoc_apm_topology_changed_t *event) { return event->context; } /* topology-opening event field */ void mongoc_apm_topology_opening_get_topology_id (const mongoc_apm_topology_opening_t *event, bson_oid_t *topology_id) { bson_oid_copy (&event->topology_id, topology_id); } void * mongoc_apm_topology_opening_get_context (const mongoc_apm_topology_opening_t *event) { return event->context; } /* topology-closed event field */ void mongoc_apm_topology_closed_get_topology_id (const mongoc_apm_topology_closed_t *event, bson_oid_t *topology_id) { bson_oid_copy (&event->topology_id, topology_id); } void * mongoc_apm_topology_closed_get_context (const mongoc_apm_topology_closed_t *event) { return event->context; } /* heartbeat-started event field */ const mongoc_host_list_t * mongoc_apm_server_heartbeat_started_get_host (const mongoc_apm_server_heartbeat_started_t *event) { return event->host; } void * mongoc_apm_server_heartbeat_started_get_context (const mongoc_apm_server_heartbeat_started_t *event) { return event->context; } bool mongoc_apm_server_heartbeat_started_get_awaited (const mongoc_apm_server_heartbeat_started_t *event) { return event->awaited; } /* heartbeat-succeeded event fields */ int64_t mongoc_apm_server_heartbeat_succeeded_get_duration (const mongoc_apm_server_heartbeat_succeeded_t *event) { return event->duration_usec; } const bson_t * mongoc_apm_server_heartbeat_succeeded_get_reply (const mongoc_apm_server_heartbeat_succeeded_t *event) { return event->reply; } const mongoc_host_list_t * mongoc_apm_server_heartbeat_succeeded_get_host (const mongoc_apm_server_heartbeat_succeeded_t *event) { return event->host; } void * mongoc_apm_server_heartbeat_succeeded_get_context (const mongoc_apm_server_heartbeat_succeeded_t *event) { return event->context; } bool mongoc_apm_server_heartbeat_succeeded_get_awaited (const mongoc_apm_server_heartbeat_succeeded_t *event) { return event->awaited; } /* heartbeat-failed event fields */ int64_t mongoc_apm_server_heartbeat_failed_get_duration (const mongoc_apm_server_heartbeat_failed_t *event) { return event->duration_usec; } void mongoc_apm_server_heartbeat_failed_get_error (const mongoc_apm_server_heartbeat_failed_t *event, bson_error_t *error) { memcpy (error, event->error, sizeof *event->error); } const mongoc_host_list_t * mongoc_apm_server_heartbeat_failed_get_host (const mongoc_apm_server_heartbeat_failed_t *event) { return event->host; } void * mongoc_apm_server_heartbeat_failed_get_context (const mongoc_apm_server_heartbeat_failed_t *event) { return event->context; } bool mongoc_apm_server_heartbeat_failed_get_awaited (const mongoc_apm_server_heartbeat_failed_t *event) { return event->awaited; } /* * registering callbacks */ mongoc_apm_callbacks_t * mongoc_apm_callbacks_new (void) { size_t s = sizeof (mongoc_apm_callbacks_t); return (mongoc_apm_callbacks_t *) bson_malloc0 (s); } void mongoc_apm_callbacks_destroy (mongoc_apm_callbacks_t *callbacks) { bson_free (callbacks); } void mongoc_apm_set_command_started_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_command_started_cb_t cb) { callbacks->started = cb; } void mongoc_apm_set_command_succeeded_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_command_succeeded_cb_t cb) { callbacks->succeeded = cb; } void mongoc_apm_set_command_failed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_command_failed_cb_t cb) { callbacks->failed = cb; } void mongoc_apm_set_server_changed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_changed_cb_t cb) { callbacks->server_changed = cb; } void mongoc_apm_set_server_opening_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_opening_cb_t cb) { callbacks->server_opening = cb; } void mongoc_apm_set_server_closed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_closed_cb_t cb) { callbacks->server_closed = cb; } void mongoc_apm_set_topology_changed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_topology_changed_cb_t cb) { callbacks->topology_changed = cb; } void mongoc_apm_set_topology_opening_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_topology_opening_cb_t cb) { callbacks->topology_opening = cb; } void mongoc_apm_set_topology_closed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_topology_closed_cb_t cb) { callbacks->topology_closed = cb; } void mongoc_apm_set_server_heartbeat_started_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_heartbeat_started_cb_t cb) { callbacks->server_heartbeat_started = cb; } void mongoc_apm_set_server_heartbeat_succeeded_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_heartbeat_succeeded_cb_t cb) { callbacks->server_heartbeat_succeeded = cb; } void mongoc_apm_set_server_heartbeat_failed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_heartbeat_failed_cb_t cb) { callbacks->server_heartbeat_failed = cb; } static bool _mongoc_apm_is_sensitive_command_name (const char *command_name) { return 0 == strcasecmp (command_name, "authenticate") || 0 == strcasecmp (command_name, "saslStart") || 0 == strcasecmp (command_name, "saslContinue") || 0 == strcasecmp (command_name, "getnonce") || 0 == strcasecmp (command_name, "createUser") || 0 == strcasecmp (command_name, "updateUser") || 0 == strcasecmp (command_name, "copydbgetnonce") || 0 == strcasecmp (command_name, "copydbsaslstart") || 0 == strcasecmp (command_name, "copydb"); } static bool _mongoc_apm_is_sensitive_hello_message (const char *command_name, const bson_t *body) { const bool is_hello = (0 == strcasecmp (command_name, "hello") || 0 == strcasecmp (command_name, HANDSHAKE_CMD_LEGACY_HELLO)); if (!is_hello) { return false; } if (bson_empty (body)) { /* An empty message body means that it has been redacted */ return true; } else if (bson_has_field (body, "speculativeAuthenticate")) { /* "hello" messages are only sensitive if they contain * 'speculativeAuthenticate' */ return true; } else { /* Other "hello" messages are okay */ return false; } } bool mongoc_apm_is_sensitive_command_message (const char *command_name, const bson_t *body) { BSON_ASSERT (body); return _mongoc_apm_is_sensitive_command_name (command_name) || _mongoc_apm_is_sensitive_hello_message (command_name, body); } void mongoc_apm_redact_command (bson_t *command) { BSON_ASSERT (command); /* Reinit the command to have an empty document */ bson_reinit (command); } void mongoc_apm_redact_reply (bson_t *reply) { BSON_ASSERT (reply); /* Reinit the reply to have an empty document */ bson_reinit (reply); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-apm.h0000644000175100001660000003466414760300420021731 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_APM_H #define MONGOC_APM_H #include #include #include #include #include BSON_BEGIN_DECLS /* * Application Performance Management (APM) interface, complies with two specs. * MongoDB's Command Logging and Monitoring Spec: * * https://github.com/mongodb/specifications/tree/master/source/command-logging-and-monitoring * * MongoDB's Spec for Monitoring Server Discovery and Monitoring (SDAM) events: * * https://github.com/mongodb/specifications/tree/master/source/server-discovery-and-monitoring * */ /* * callbacks to receive APM events */ typedef struct _mongoc_apm_callbacks_t mongoc_apm_callbacks_t; /* * command monitoring events */ typedef struct _mongoc_apm_command_started_t mongoc_apm_command_started_t; typedef struct _mongoc_apm_command_succeeded_t mongoc_apm_command_succeeded_t; typedef struct _mongoc_apm_command_failed_t mongoc_apm_command_failed_t; /* * SDAM monitoring events */ typedef struct _mongoc_apm_server_changed_t mongoc_apm_server_changed_t; typedef struct _mongoc_apm_server_opening_t mongoc_apm_server_opening_t; typedef struct _mongoc_apm_server_closed_t mongoc_apm_server_closed_t; typedef struct _mongoc_apm_topology_changed_t mongoc_apm_topology_changed_t; typedef struct _mongoc_apm_topology_opening_t mongoc_apm_topology_opening_t; typedef struct _mongoc_apm_topology_closed_t mongoc_apm_topology_closed_t; typedef struct _mongoc_apm_server_heartbeat_started_t mongoc_apm_server_heartbeat_started_t; typedef struct _mongoc_apm_server_heartbeat_succeeded_t mongoc_apm_server_heartbeat_succeeded_t; typedef struct _mongoc_apm_server_heartbeat_failed_t mongoc_apm_server_heartbeat_failed_t; /* * event field accessors */ /* command-started event fields */ MONGOC_EXPORT (const bson_t *) mongoc_apm_command_started_get_command (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (const char *) mongoc_apm_command_started_get_database_name (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (const char *) mongoc_apm_command_started_get_command_name (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (int64_t) mongoc_apm_command_started_get_request_id (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (int64_t) mongoc_apm_command_started_get_operation_id (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_command_started_get_host (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (uint32_t) mongoc_apm_command_started_get_server_id (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (const bson_oid_t *) mongoc_apm_command_started_get_service_id (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (int32_t) mongoc_apm_command_started_get_server_connection_id (const mongoc_apm_command_started_t *event) BSON_GNUC_DEPRECATED_FOR ("mongoc_apm_command_started_get_server_connection_id_int64"); MONGOC_EXPORT (int64_t) mongoc_apm_command_started_get_server_connection_id_int64 (const mongoc_apm_command_started_t *event); MONGOC_EXPORT (void *) mongoc_apm_command_started_get_context (const mongoc_apm_command_started_t *event); /* command-succeeded event fields */ MONGOC_EXPORT (int64_t) mongoc_apm_command_succeeded_get_duration (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (const bson_t *) mongoc_apm_command_succeeded_get_reply (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (const char *) mongoc_apm_command_succeeded_get_command_name (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (const char *) mongoc_apm_command_succeeded_get_database_name (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (int64_t) mongoc_apm_command_succeeded_get_request_id (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (int64_t) mongoc_apm_command_succeeded_get_operation_id (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_command_succeeded_get_host (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (uint32_t) mongoc_apm_command_succeeded_get_server_id (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (const bson_oid_t *) mongoc_apm_command_succeeded_get_service_id (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (int32_t) mongoc_apm_command_succeeded_get_server_connection_id (const mongoc_apm_command_succeeded_t *event) BSON_GNUC_DEPRECATED_FOR ("mongoc_apm_command_succeeded_get_server_connection_id_int64"); MONGOC_EXPORT (int64_t) mongoc_apm_command_succeeded_get_server_connection_id_int64 (const mongoc_apm_command_succeeded_t *event); MONGOC_EXPORT (void *) mongoc_apm_command_succeeded_get_context (const mongoc_apm_command_succeeded_t *event); /* command-failed event fields */ MONGOC_EXPORT (int64_t) mongoc_apm_command_failed_get_duration (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (const char *) mongoc_apm_command_failed_get_command_name (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (const char *) mongoc_apm_command_failed_get_database_name (const mongoc_apm_command_failed_t *event); /* retrieve the error by filling out the passed-in "error" struct */ MONGOC_EXPORT (void) mongoc_apm_command_failed_get_error (const mongoc_apm_command_failed_t *event, bson_error_t *error); MONGOC_EXPORT (const bson_t *) mongoc_apm_command_failed_get_reply (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (int64_t) mongoc_apm_command_failed_get_request_id (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (int64_t) mongoc_apm_command_failed_get_operation_id (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_command_failed_get_host (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (uint32_t) mongoc_apm_command_failed_get_server_id (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (const bson_oid_t *) mongoc_apm_command_failed_get_service_id (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (int32_t) mongoc_apm_command_failed_get_server_connection_id (const mongoc_apm_command_failed_t *event) BSON_GNUC_DEPRECATED_FOR ("mongoc_apm_command_failed_get_server_connection_id_int64"); MONGOC_EXPORT (int64_t) mongoc_apm_command_failed_get_server_connection_id_int64 (const mongoc_apm_command_failed_t *event); MONGOC_EXPORT (void *) mongoc_apm_command_failed_get_context (const mongoc_apm_command_failed_t *event); /* server-changed event fields */ MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_server_changed_get_host (const mongoc_apm_server_changed_t *event); MONGOC_EXPORT (void) mongoc_apm_server_changed_get_topology_id (const mongoc_apm_server_changed_t *event, bson_oid_t *topology_id); MONGOC_EXPORT (const mongoc_server_description_t *) mongoc_apm_server_changed_get_previous_description (const mongoc_apm_server_changed_t *event); MONGOC_EXPORT (const mongoc_server_description_t *) mongoc_apm_server_changed_get_new_description (const mongoc_apm_server_changed_t *event); MONGOC_EXPORT (void *) mongoc_apm_server_changed_get_context (const mongoc_apm_server_changed_t *event); /* server-opening event fields */ MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_server_opening_get_host (const mongoc_apm_server_opening_t *event); MONGOC_EXPORT (void) mongoc_apm_server_opening_get_topology_id (const mongoc_apm_server_opening_t *event, bson_oid_t *topology_id); MONGOC_EXPORT (void *) mongoc_apm_server_opening_get_context (const mongoc_apm_server_opening_t *event); /* server-closed event fields */ MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_server_closed_get_host (const mongoc_apm_server_closed_t *event); MONGOC_EXPORT (void) mongoc_apm_server_closed_get_topology_id (const mongoc_apm_server_closed_t *event, bson_oid_t *topology_id); MONGOC_EXPORT (void *) mongoc_apm_server_closed_get_context (const mongoc_apm_server_closed_t *event); /* topology-changed event fields */ MONGOC_EXPORT (void) mongoc_apm_topology_changed_get_topology_id (const mongoc_apm_topology_changed_t *event, bson_oid_t *topology_id); MONGOC_EXPORT (const mongoc_topology_description_t *) mongoc_apm_topology_changed_get_previous_description (const mongoc_apm_topology_changed_t *event); MONGOC_EXPORT (const mongoc_topology_description_t *) mongoc_apm_topology_changed_get_new_description (const mongoc_apm_topology_changed_t *event); MONGOC_EXPORT (void *) mongoc_apm_topology_changed_get_context (const mongoc_apm_topology_changed_t *event); /* topology-opening event field */ MONGOC_EXPORT (void) mongoc_apm_topology_opening_get_topology_id (const mongoc_apm_topology_opening_t *event, bson_oid_t *topology_id); MONGOC_EXPORT (void *) mongoc_apm_topology_opening_get_context (const mongoc_apm_topology_opening_t *event); /* topology-closed event field */ MONGOC_EXPORT (void) mongoc_apm_topology_closed_get_topology_id (const mongoc_apm_topology_closed_t *event, bson_oid_t *topology_id); MONGOC_EXPORT (void *) mongoc_apm_topology_closed_get_context (const mongoc_apm_topology_closed_t *event); /* heartbeat-started event field */ MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_server_heartbeat_started_get_host (const mongoc_apm_server_heartbeat_started_t *event); MONGOC_EXPORT (void *) mongoc_apm_server_heartbeat_started_get_context (const mongoc_apm_server_heartbeat_started_t *event); MONGOC_EXPORT (bool) mongoc_apm_server_heartbeat_started_get_awaited (const mongoc_apm_server_heartbeat_started_t *event); /* heartbeat-succeeded event fields */ MONGOC_EXPORT (int64_t) mongoc_apm_server_heartbeat_succeeded_get_duration (const mongoc_apm_server_heartbeat_succeeded_t *event); MONGOC_EXPORT (const bson_t *) mongoc_apm_server_heartbeat_succeeded_get_reply (const mongoc_apm_server_heartbeat_succeeded_t *event); MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_server_heartbeat_succeeded_get_host (const mongoc_apm_server_heartbeat_succeeded_t *event); MONGOC_EXPORT (void *) mongoc_apm_server_heartbeat_succeeded_get_context (const mongoc_apm_server_heartbeat_succeeded_t *event); MONGOC_EXPORT (bool) mongoc_apm_server_heartbeat_succeeded_get_awaited (const mongoc_apm_server_heartbeat_succeeded_t *event); /* heartbeat-failed event fields */ MONGOC_EXPORT (int64_t) mongoc_apm_server_heartbeat_failed_get_duration (const mongoc_apm_server_heartbeat_failed_t *event); MONGOC_EXPORT (void) mongoc_apm_server_heartbeat_failed_get_error (const mongoc_apm_server_heartbeat_failed_t *event, bson_error_t *error); MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_apm_server_heartbeat_failed_get_host (const mongoc_apm_server_heartbeat_failed_t *event); MONGOC_EXPORT (void *) mongoc_apm_server_heartbeat_failed_get_context (const mongoc_apm_server_heartbeat_failed_t *event); MONGOC_EXPORT (bool) mongoc_apm_server_heartbeat_failed_get_awaited (const mongoc_apm_server_heartbeat_failed_t *event); /* * callbacks */ typedef void (*mongoc_apm_command_started_cb_t) (const mongoc_apm_command_started_t *event); typedef void (*mongoc_apm_command_succeeded_cb_t) (const mongoc_apm_command_succeeded_t *event); typedef void (*mongoc_apm_command_failed_cb_t) (const mongoc_apm_command_failed_t *event); typedef void (*mongoc_apm_server_changed_cb_t) (const mongoc_apm_server_changed_t *event); typedef void (*mongoc_apm_server_opening_cb_t) (const mongoc_apm_server_opening_t *event); typedef void (*mongoc_apm_server_closed_cb_t) (const mongoc_apm_server_closed_t *event); typedef void (*mongoc_apm_topology_changed_cb_t) (const mongoc_apm_topology_changed_t *event); typedef void (*mongoc_apm_topology_opening_cb_t) (const mongoc_apm_topology_opening_t *event); typedef void (*mongoc_apm_topology_closed_cb_t) (const mongoc_apm_topology_closed_t *event); typedef void (*mongoc_apm_server_heartbeat_started_cb_t) (const mongoc_apm_server_heartbeat_started_t *event); typedef void (*mongoc_apm_server_heartbeat_succeeded_cb_t) (const mongoc_apm_server_heartbeat_succeeded_t *event); typedef void (*mongoc_apm_server_heartbeat_failed_cb_t) (const mongoc_apm_server_heartbeat_failed_t *event); /* * registering callbacks */ MONGOC_EXPORT (mongoc_apm_callbacks_t *) mongoc_apm_callbacks_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_apm_callbacks_destroy (mongoc_apm_callbacks_t *callbacks); MONGOC_EXPORT (void) mongoc_apm_set_command_started_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_command_started_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_command_succeeded_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_command_succeeded_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_command_failed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_command_failed_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_server_changed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_changed_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_server_opening_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_opening_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_server_closed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_closed_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_topology_changed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_topology_changed_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_topology_opening_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_topology_opening_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_topology_closed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_topology_closed_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_server_heartbeat_started_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_heartbeat_started_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_server_heartbeat_succeeded_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_heartbeat_succeeded_cb_t cb); MONGOC_EXPORT (void) mongoc_apm_set_server_heartbeat_failed_cb (mongoc_apm_callbacks_t *callbacks, mongoc_apm_server_heartbeat_failed_cb_t cb); BSON_END_DECLS #endif /* MONGOC_APM_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-array-private.h0000644000175100001660000000321014760300420023721 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_ARRAY_PRIVATE_H #define MONGOC_ARRAY_PRIVATE_H #include BSON_BEGIN_DECLS typedef struct _mongoc_array_t mongoc_array_t; struct _mongoc_array_t { size_t len; size_t element_alignment; size_t element_size; size_t allocated; void *data; }; #define mongoc_array_aligned_init(a, Type) _mongoc_array_aligned_init (a, BSON_ALIGNOF (Type), sizeof (Type)) #define _mongoc_array_append_val(a, v) _mongoc_array_append_vals (a, &v, 1) #define _mongoc_array_index(a, t, i) (((t *) (a)->data)[i]) #define _mongoc_array_clear(a) (a)->len = 0 void _mongoc_array_aligned_init (mongoc_array_t *array, size_t element_alignment, size_t element_size); void _mongoc_array_init (mongoc_array_t *array, size_t element_size); void _mongoc_array_copy (mongoc_array_t *dst, const mongoc_array_t *src); void _mongoc_array_append_vals (mongoc_array_t *array, const void *data, uint32_t n_elements); void _mongoc_array_destroy (mongoc_array_t *array); BSON_END_DECLS #endif /* MONGOC_ARRAY_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-array.c0000644000175100001660000000626614760300420022262 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include void _mongoc_array_init (mongoc_array_t *array, size_t element_size) { BSON_ASSERT_PARAM (array); BSON_ASSERT (element_size > 0); array->len = 0; array->element_alignment = 0; array->element_size = element_size; array->allocated = 128; array->data = (void *) bson_malloc0 (array->allocated); } void _mongoc_array_aligned_init (mongoc_array_t *array, size_t element_alignment, size_t element_size) { BSON_ASSERT_PARAM (array); BSON_ASSERT (element_alignment > 0); BSON_ASSERT (element_size > 0); array->len = 0; array->element_alignment = element_alignment; array->element_size = element_size; array->allocated = 128; array->data = bson_aligned_alloc0 (element_alignment, array->allocated); } /* *-------------------------------------------------------------------------- * * _mongoc_array_copy -- * * Destroy dst and copy src into it. Both arrays must be initialized. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void _mongoc_array_copy (mongoc_array_t *dst, const mongoc_array_t *src) { _mongoc_array_destroy (dst); dst->len = src->len; dst->element_alignment = src->element_alignment; dst->element_size = src->element_size; dst->allocated = src->allocated; if (dst->element_alignment == 0) { dst->data = bson_malloc (dst->allocated); } else { dst->data = bson_aligned_alloc (dst->element_alignment, dst->allocated); } memcpy (dst->data, src->data, dst->allocated); } void _mongoc_array_destroy (mongoc_array_t *array) { if (array && array->data) { bson_free (array->data); } } void _mongoc_array_append_vals (mongoc_array_t *array, const void *data, uint32_t n_elements) { size_t len; size_t off; size_t next_size; BSON_ASSERT (array); BSON_ASSERT (data); off = array->element_size * array->len; len = (size_t) n_elements * array->element_size; if ((off + len) > array->allocated) { next_size = bson_next_power_of_two (off + len); if (array->element_alignment == 0) { array->data = bson_realloc (array->data, next_size); array->allocated = next_size; } else { void *const old_data = array->data; array->data = bson_aligned_alloc (array->element_alignment, next_size); memmove (array->data, old_data, array->allocated); array->allocated = next_size; bson_free (old_data); } } memcpy ((uint8_t *) array->data + off, data, len); array->len += n_elements; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-async-cmd-private.h0000644000175100001660000000572214760300420024473 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_ASYNC_CMD_PRIVATE_H #define MONGOC_ASYNC_CMD_PRIVATE_H #include #include #include #include #include #include #include #include BSON_BEGIN_DECLS typedef enum { MONGOC_ASYNC_CMD_INITIATE, MONGOC_ASYNC_CMD_SETUP, MONGOC_ASYNC_CMD_SEND, MONGOC_ASYNC_CMD_RECV_LEN, MONGOC_ASYNC_CMD_RECV_RPC, MONGOC_ASYNC_CMD_ERROR_STATE, MONGOC_ASYNC_CMD_CANCELED_STATE, } mongoc_async_cmd_state_t; typedef struct _mongoc_async_cmd { mongoc_stream_t *stream; mongoc_async_t *async; mongoc_async_cmd_state_t state; int events; mongoc_async_cmd_initiate_t initiator; mongoc_async_cmd_setup_t setup; void *setup_ctx; mongoc_async_cmd_cb_t cb; void *data; bson_error_t error; int64_t initiate_delay_ms; int64_t connect_started; int64_t cmd_started; int64_t timeout_msec; bson_t cmd; mongoc_buffer_t buffer; mongoc_iovec_t *iovec; size_t niovec; size_t bytes_written; size_t bytes_to_read; mcd_rpc_message *rpc; bson_t reply; bool reply_needs_cleanup; char *ns; struct addrinfo *dns_result; struct _mongoc_async_cmd *next; struct _mongoc_async_cmd *prev; } mongoc_async_cmd_t; mongoc_async_cmd_t * mongoc_async_cmd_new (mongoc_async_t *async, mongoc_stream_t *stream, bool is_setup_done, struct addrinfo *dns_result, mongoc_async_cmd_initiate_t initiator, int64_t initiate_delay_ms, mongoc_async_cmd_setup_t setup, void *setup_ctx, const char *dbname, const bson_t *cmd, const int32_t cmd_opcode, mongoc_async_cmd_cb_t cb, void *cb_data, int64_t timeout_msec); void mongoc_async_cmd_destroy (mongoc_async_cmd_t *acmd); bool mongoc_async_cmd_run (mongoc_async_cmd_t *acmd); #ifdef MONGOC_ENABLE_SSL int mongoc_async_cmd_tls_setup (mongoc_stream_t *stream, int *events, void *ctx, int32_t timeout_msec, bson_error_t *error); #endif BSON_END_DECLS #endif /* MONGOC_ASYNC_CMD_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-async-cmd.c0000644000175100001660000003470114760300420023015 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #endif #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "async" typedef mongoc_async_cmd_result_t (*_mongoc_async_cmd_phase_t) (mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_initiate (mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_setup (mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_send (mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_len (mongoc_async_cmd_t *cmd); mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_rpc (mongoc_async_cmd_t *cmd); static const _mongoc_async_cmd_phase_t gMongocCMDPhases[] = { _mongoc_async_cmd_phase_initiate, _mongoc_async_cmd_phase_setup, _mongoc_async_cmd_phase_send, _mongoc_async_cmd_phase_recv_len, _mongoc_async_cmd_phase_recv_rpc, NULL, /* no callback for MONGOC_ASYNC_CMD_ERROR_STATE */ NULL, /* no callback for MONGOC_ASYNC_CMD_CANCELED_STATE */ }; #ifdef MONGOC_ENABLE_SSL int mongoc_async_cmd_tls_setup (mongoc_stream_t *stream, int *events, void *ctx, int32_t timeout_msec, bson_error_t *error) { mongoc_stream_t *tls_stream; const char *host = (const char *) ctx; int retry_events = 0; for (tls_stream = stream; tls_stream->type != MONGOC_STREAM_TLS; tls_stream = mongoc_stream_get_base_stream (tls_stream)) { } #if defined(MONGOC_ENABLE_SSL_OPENSSL) || defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL) /* pass 0 for the timeout to begin / continue non-blocking handshake */ timeout_msec = 0; #endif if (mongoc_stream_tls_handshake (tls_stream, host, timeout_msec, &retry_events, error)) { return 1; } if (retry_events) { *events = retry_events; return 0; } return -1; } #endif bool mongoc_async_cmd_run (mongoc_async_cmd_t *acmd) { mongoc_async_cmd_result_t result; int64_t duration_usec; _mongoc_async_cmd_phase_t phase_callback; BSON_ASSERT (acmd); /* if we have successfully connected to the node, call the callback. */ if (acmd->state == MONGOC_ASYNC_CMD_SEND) { acmd->cb (acmd, MONGOC_ASYNC_CMD_CONNECTED, NULL, 0); } phase_callback = gMongocCMDPhases[acmd->state]; if (phase_callback) { result = phase_callback (acmd); } else { result = MONGOC_ASYNC_CMD_ERROR; } if (result == MONGOC_ASYNC_CMD_IN_PROGRESS) { return true; } duration_usec = bson_get_monotonic_time () - acmd->cmd_started; if (result == MONGOC_ASYNC_CMD_SUCCESS) { acmd->cb (acmd, result, &acmd->reply, duration_usec); } else { /* we're in ERROR, TIMEOUT, or CANCELED */ acmd->cb (acmd, result, NULL, duration_usec); } mongoc_async_cmd_destroy (acmd); return false; } static void _mongoc_async_cmd_init_send (const int32_t cmd_opcode, mongoc_async_cmd_t *acmd, const char *dbname) { BSON_ASSERT (cmd_opcode == MONGOC_OP_CODE_QUERY || cmd_opcode == MONGOC_OP_CODE_MSG); int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (acmd->rpc, 0); message_length += mcd_rpc_header_set_request_id (acmd->rpc, ++acmd->async->request_id); message_length += mcd_rpc_header_set_response_to (acmd->rpc, 0); message_length += mcd_rpc_header_set_op_code (acmd->rpc, cmd_opcode); if (cmd_opcode == MONGOC_OP_CODE_QUERY) { acmd->ns = bson_strdup_printf ("%s.$cmd", dbname); message_length += mcd_rpc_op_query_set_flags (acmd->rpc, MONGOC_OP_QUERY_FLAG_SECONDARY_OK); message_length += mcd_rpc_op_query_set_full_collection_name (acmd->rpc, acmd->ns); message_length += mcd_rpc_op_query_set_number_to_skip (acmd->rpc, 0); message_length += mcd_rpc_op_query_set_number_to_return (acmd->rpc, -1); message_length += mcd_rpc_op_query_set_query (acmd->rpc, bson_get_data (&acmd->cmd)); } else { mcd_rpc_op_msg_set_sections_count (acmd->rpc, 1u); message_length += mcd_rpc_op_msg_set_flag_bits (acmd->rpc, MONGOC_OP_MSG_FLAG_NONE); message_length += mcd_rpc_op_msg_section_set_kind (acmd->rpc, 0u, 0); message_length += mcd_rpc_op_msg_section_set_body (acmd->rpc, 0u, bson_get_data (&acmd->cmd)); } mcd_rpc_message_set_length (acmd->rpc, message_length); /* This will always be hello, which are not allowed to be compressed */ acmd->iovec = mcd_rpc_message_to_iovecs (acmd->rpc, &acmd->niovec); BSON_ASSERT (acmd->iovec); acmd->bytes_written = 0; } void _mongoc_async_cmd_state_start (mongoc_async_cmd_t *acmd, bool is_setup_done) { if (!acmd->stream) { acmd->state = MONGOC_ASYNC_CMD_INITIATE; } else if (acmd->setup && !is_setup_done) { acmd->state = MONGOC_ASYNC_CMD_SETUP; } else { acmd->state = MONGOC_ASYNC_CMD_SEND; } acmd->events = POLLOUT; } mongoc_async_cmd_t * mongoc_async_cmd_new (mongoc_async_t *async, mongoc_stream_t *stream, bool is_setup_done, struct addrinfo *dns_result, mongoc_async_cmd_initiate_t initiator, int64_t initiate_delay_ms, mongoc_async_cmd_setup_t setup, void *setup_ctx, const char *dbname, const bson_t *cmd, const int32_t cmd_opcode, /* OP_QUERY or OP_MSG */ mongoc_async_cmd_cb_t cb, void *cb_data, int64_t timeout_msec) { BSON_ASSERT_PARAM (cmd); BSON_ASSERT_PARAM (dbname); mongoc_async_cmd_t *const acmd = BSON_ALIGNED_ALLOC0 (mongoc_async_cmd_t); acmd->async = async; acmd->dns_result = dns_result; acmd->timeout_msec = timeout_msec; acmd->stream = stream; acmd->initiator = initiator; acmd->initiate_delay_ms = initiate_delay_ms; acmd->setup = setup; acmd->setup_ctx = setup_ctx; acmd->cb = cb; acmd->data = cb_data; acmd->connect_started = bson_get_monotonic_time (); bson_copy_to (cmd, &acmd->cmd); if (MONGOC_OP_CODE_MSG == cmd_opcode) { /* If we're sending an OP_MSG, we need to add the "db" field: */ bson_append_utf8 (&acmd->cmd, "$db", 3, "admin", 5); } acmd->rpc = mcd_rpc_message_new (); acmd->iovec = NULL; _mongoc_buffer_init (&acmd->buffer, NULL, 0, NULL, NULL); _mongoc_async_cmd_init_send (cmd_opcode, acmd, dbname); _mongoc_async_cmd_state_start (acmd, is_setup_done); async->ncmds++; DL_APPEND (async->cmds, acmd); return acmd; } void mongoc_async_cmd_destroy (mongoc_async_cmd_t *acmd) { BSON_ASSERT (acmd); DL_DELETE (acmd->async->cmds, acmd); acmd->async->ncmds--; bson_destroy (&acmd->cmd); if (acmd->reply_needs_cleanup) { bson_destroy (&acmd->reply); } bson_free (acmd->iovec); _mongoc_buffer_destroy (&acmd->buffer); mcd_rpc_message_destroy (acmd->rpc); bson_free (acmd->ns); bson_free (acmd); } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_initiate (mongoc_async_cmd_t *acmd) { acmd->stream = acmd->initiator (acmd); if (!acmd->stream) { return MONGOC_ASYNC_CMD_ERROR; } /* reset the connect started time after connection starts. */ acmd->connect_started = bson_get_monotonic_time (); if (acmd->setup) { acmd->state = MONGOC_ASYNC_CMD_SETUP; } else { acmd->state = MONGOC_ASYNC_CMD_SEND; } return MONGOC_ASYNC_CMD_IN_PROGRESS; } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_setup (mongoc_async_cmd_t *acmd) { int retval; BSON_ASSERT (acmd->timeout_msec < INT32_MAX); retval = acmd->setup (acmd->stream, &acmd->events, acmd->setup_ctx, (int32_t) acmd->timeout_msec, &acmd->error); switch (retval) { case -1: return MONGOC_ASYNC_CMD_ERROR; case 0: break; case 1: acmd->state = MONGOC_ASYNC_CMD_SEND; acmd->events = POLLOUT; break; default: abort (); } return MONGOC_ASYNC_CMD_IN_PROGRESS; } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_send (mongoc_async_cmd_t *acmd) { size_t total_bytes = 0; size_t offset; ssize_t bytes; /* if a continued write, then iovec will be set to a temporary copy */ bool used_temp_iovec = false; mongoc_iovec_t *iovec = acmd->iovec; size_t niovec = acmd->niovec; for (size_t i = 0u; i < acmd->niovec; i++) { total_bytes += acmd->iovec[i].iov_len; } if (acmd->bytes_written > 0) { BSON_ASSERT (acmd->bytes_written < total_bytes); /* if bytes have been written before, compute the offset in the next * iovec entry to be written. */ offset = acmd->bytes_written; size_t i = 0u; /* subtract the lengths of all iovec entries written so far. */ for (i = 0u; i < acmd->niovec; i++) { if (offset < acmd->iovec[i].iov_len) { break; } offset -= acmd->iovec[i].iov_len; } BSON_ASSERT (i < acmd->niovec); /* create a new iovec with the remaining data to be written. */ niovec = acmd->niovec - i; iovec = bson_malloc (niovec * sizeof (mongoc_iovec_t)); memcpy (iovec, acmd->iovec + i, niovec * sizeof (mongoc_iovec_t)); iovec[0].iov_base = (char *) iovec[0].iov_base + offset; iovec[0].iov_len -= offset; used_temp_iovec = true; } mcd_rpc_message_egress (acmd->rpc); bytes = mongoc_stream_writev (acmd->stream, iovec, niovec, 0); if (used_temp_iovec) { bson_free (iovec); } if (bytes <= 0 && mongoc_stream_should_retry (acmd->stream)) { return MONGOC_ASYNC_CMD_IN_PROGRESS; } if (bytes < 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to write rpc bytes."); return MONGOC_ASYNC_CMD_ERROR; } acmd->bytes_written += bytes; if (acmd->bytes_written < total_bytes) { return MONGOC_ASYNC_CMD_IN_PROGRESS; } acmd->state = MONGOC_ASYNC_CMD_RECV_LEN; acmd->bytes_to_read = 4; acmd->events = POLLIN; acmd->cmd_started = bson_get_monotonic_time (); return MONGOC_ASYNC_CMD_IN_PROGRESS; } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_len (mongoc_async_cmd_t *acmd) { ssize_t bytes = _mongoc_buffer_try_append_from_stream (&acmd->buffer, acmd->stream, acmd->bytes_to_read, 0); uint32_t msg_len; if (bytes <= 0 && mongoc_stream_should_retry (acmd->stream)) { return MONGOC_ASYNC_CMD_IN_PROGRESS; } if (bytes < 0) { bson_set_error ( &acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to receive length header from server."); return MONGOC_ASYNC_CMD_ERROR; } if (bytes == 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Server closed connection."); return MONGOC_ASYNC_CMD_ERROR; } acmd->bytes_to_read = (size_t) (acmd->bytes_to_read - bytes); if (!acmd->bytes_to_read) { memcpy (&msg_len, acmd->buffer.data, 4); msg_len = BSON_UINT32_FROM_LE (msg_len); if (msg_len < 16 || msg_len > MONGOC_DEFAULT_MAX_MSG_SIZE || msg_len < acmd->buffer.len) { bson_set_error ( &acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server."); return MONGOC_ASYNC_CMD_ERROR; } acmd->bytes_to_read = msg_len - acmd->buffer.len; acmd->state = MONGOC_ASYNC_CMD_RECV_RPC; return _mongoc_async_cmd_phase_recv_rpc (acmd); } return MONGOC_ASYNC_CMD_IN_PROGRESS; } mongoc_async_cmd_result_t _mongoc_async_cmd_phase_recv_rpc (mongoc_async_cmd_t *acmd) { ssize_t bytes = _mongoc_buffer_try_append_from_stream (&acmd->buffer, acmd->stream, acmd->bytes_to_read, 0); if (bytes <= 0 && mongoc_stream_should_retry (acmd->stream)) { return MONGOC_ASYNC_CMD_IN_PROGRESS; } if (bytes < 0) { bson_set_error ( &acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to receive rpc bytes from server."); return MONGOC_ASYNC_CMD_ERROR; } if (bytes == 0) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Server closed connection."); return MONGOC_ASYNC_CMD_ERROR; } acmd->bytes_to_read = (size_t) (acmd->bytes_to_read - bytes); if (!acmd->bytes_to_read) { mcd_rpc_message_reset (acmd->rpc); if (!mcd_rpc_message_from_data_in_place (acmd->rpc, acmd->buffer.data, acmd->buffer.len, NULL)) { bson_set_error ( &acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server."); return MONGOC_ASYNC_CMD_ERROR; } mcd_rpc_message_ingress (acmd->rpc); void *decompressed_data; size_t decompressed_data_len; if (!mcd_rpc_message_decompress_if_necessary (acmd->rpc, &decompressed_data, &decompressed_data_len)) { bson_set_error (&acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Could not decompress server reply"); return MONGOC_ASYNC_CMD_ERROR; } if (decompressed_data) { _mongoc_buffer_destroy (&acmd->buffer); _mongoc_buffer_init (&acmd->buffer, decompressed_data, decompressed_data_len, NULL, NULL); } if (!mcd_rpc_message_get_body (acmd->rpc, &acmd->reply)) { bson_set_error ( &acmd->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply from server"); return MONGOC_ASYNC_CMD_ERROR; } acmd->reply_needs_cleanup = true; return MONGOC_ASYNC_CMD_SUCCESS; } return MONGOC_ASYNC_CMD_IN_PROGRESS; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-async-private.h0000644000175100001660000000342714760300420023732 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_ASYNC_PRIVATE_H #define MONGOC_ASYNC_PRIVATE_H #include #include BSON_BEGIN_DECLS struct _mongoc_async_cmd; typedef struct _mongoc_async { struct _mongoc_async_cmd *cmds; size_t ncmds; uint32_t request_id; } mongoc_async_t; typedef enum { MONGOC_ASYNC_CMD_CONNECTED, MONGOC_ASYNC_CMD_IN_PROGRESS, MONGOC_ASYNC_CMD_SUCCESS, MONGOC_ASYNC_CMD_ERROR, MONGOC_ASYNC_CMD_TIMEOUT, } mongoc_async_cmd_result_t; typedef void (*mongoc_async_cmd_cb_t) (struct _mongoc_async_cmd *acmd, mongoc_async_cmd_result_t result, const bson_t *bson, int64_t duration_usec); typedef mongoc_stream_t *(*mongoc_async_cmd_initiate_t) (struct _mongoc_async_cmd *); typedef int (*mongoc_async_cmd_setup_t) ( mongoc_stream_t *stream, int *events, void *ctx, int32_t timeout_msec, bson_error_t *error); mongoc_async_t * mongoc_async_new (void); void mongoc_async_destroy (mongoc_async_t *async); void mongoc_async_run (mongoc_async_t *async); BSON_END_DECLS #endif /* MONGOC_ASYNC_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-async.c0000644000175100001660000001421214760300420022247 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "async" mongoc_async_t * mongoc_async_new (void) { mongoc_async_t *async = (mongoc_async_t *) bson_malloc0 (sizeof (*async)); return async; } void mongoc_async_destroy (mongoc_async_t *async) { mongoc_async_cmd_t *acmd, *tmp; DL_FOREACH_SAFE (async->cmds, acmd, tmp) { mongoc_async_cmd_destroy (acmd); } bson_free (async); } void mongoc_async_run (mongoc_async_t *async) { mongoc_async_cmd_t *acmd, *tmp; mongoc_async_cmd_t **acmds_polled = NULL; mongoc_stream_poll_t *poller = NULL; int nstreams, i; ssize_t nactive = 0; int64_t now; int64_t expire_at; int64_t poll_timeout_msec; size_t poll_size; now = bson_get_monotonic_time (); poll_size = 0; /* CDRIVER-1571 reset start times in case a stream initiator was slow */ DL_FOREACH (async->cmds, acmd) { acmd->connect_started = now; } while (async->ncmds) { /* ncmds grows if we discover a replica & start calling hello on it */ if (poll_size < async->ncmds) { poller = (mongoc_stream_poll_t *) bson_realloc (poller, sizeof (*poller) * async->ncmds); acmds_polled = (mongoc_async_cmd_t **) bson_realloc (acmds_polled, sizeof (*acmds_polled) * async->ncmds); poll_size = async->ncmds; } expire_at = INT64_MAX; nstreams = 0; /* check if any cmds are ready to be initiated. */ DL_FOREACH_SAFE (async->cmds, acmd, tmp) { if (acmd->state == MONGOC_ASYNC_CMD_INITIATE) { BSON_ASSERT (!acmd->stream); if (now >= acmd->initiate_delay_ms * 1000 + acmd->connect_started) { /* time to initiate. */ if (mongoc_async_cmd_run (acmd)) { BSON_ASSERT (acmd->stream); } else { /* this command was removed. */ continue; } } else { /* don't poll longer than the earliest cmd ready to init. */ expire_at = BSON_MIN (expire_at, acmd->connect_started + acmd->initiate_delay_ms); } } if (acmd->stream) { acmds_polled[nstreams] = acmd; poller[nstreams].stream = acmd->stream; poller[nstreams].events = acmd->events; poller[nstreams].revents = 0; expire_at = BSON_MIN (expire_at, acmd->connect_started + acmd->timeout_msec * 1000); ++nstreams; } } if (async->ncmds == 0) { /* all cmds failed to initiate and removed themselves. */ break; } poll_timeout_msec = BSON_MAX (0, (expire_at - now) / 1000); BSON_ASSERT (poll_timeout_msec < INT32_MAX); if (nstreams > 0) { /* we need at least one stream to poll. */ nactive = mongoc_stream_poll (poller, nstreams, (int32_t) poll_timeout_msec); } else { /* currently this does not get hit. we always have at least one command * initialized with a stream. */ _mongoc_usleep (poll_timeout_msec * 1000); } if (nactive > 0) { for (i = 0; i < nstreams; i++) { mongoc_async_cmd_t *iter = acmds_polled[i]; if (poller[i].revents & (POLLERR | POLLHUP)) { int hup = poller[i].revents & POLLHUP; if (iter->state == MONGOC_ASYNC_CMD_SEND) { bson_set_error (&iter->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, hup ? "connection refused" : "unknown connection error"); } else { bson_set_error (&iter->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, hup ? "connection closed" : "unknown socket error"); } iter->state = MONGOC_ASYNC_CMD_ERROR_STATE; } if ((poller[i].revents & poller[i].events) || iter->state == MONGOC_ASYNC_CMD_ERROR_STATE) { (void) mongoc_async_cmd_run (iter); nactive--; } if (!nactive) { break; } } } DL_FOREACH_SAFE (async->cmds, acmd, tmp) { /* check if an initiated cmd has passed the connection timeout. */ if (acmd->state != MONGOC_ASYNC_CMD_INITIATE && now > acmd->connect_started + acmd->timeout_msec * 1000) { bson_set_error (&acmd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, acmd->state == MONGOC_ASYNC_CMD_SEND ? "connection timeout" : "socket timeout"); acmd->cb (acmd, MONGOC_ASYNC_CMD_TIMEOUT, NULL, (now - acmd->connect_started) / 1000); /* Remove acmd from the async->cmds doubly-linked list */ mongoc_async_cmd_destroy (acmd); } else if (acmd->state == MONGOC_ASYNC_CMD_CANCELED_STATE) { acmd->cb (acmd, MONGOC_ASYNC_CMD_ERROR, NULL, (now - acmd->connect_started) / 1000); /* Remove acmd from the async->cmds doubly-linked list */ mongoc_async_cmd_destroy (acmd); } } now = bson_get_monotonic_time (); } bson_free (poller); bson_free (acmds_polled); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-buffer-private.h0000644000175100001660000000361514760300420024065 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_BUFFER_PRIVATE_H #define MONGOC_BUFFER_PRIVATE_H #include #include BSON_BEGIN_DECLS typedef struct _mongoc_buffer_t mongoc_buffer_t; struct _mongoc_buffer_t { uint8_t *data; size_t datalen; size_t len; bson_realloc_func realloc_func; void *realloc_data; }; void _mongoc_buffer_init ( mongoc_buffer_t *buffer, uint8_t *buf, size_t buflen, bson_realloc_func realloc_func, void *realloc_data); bool _mongoc_buffer_append (mongoc_buffer_t *buffer, const uint8_t *data, size_t data_size); bool _mongoc_buffer_append_from_stream ( mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t size, int64_t timeout_msec, bson_error_t *error); ssize_t _mongoc_buffer_try_append_from_stream (mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t size, int64_t timeout_msec); ssize_t _mongoc_buffer_fill ( mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t min_bytes, int64_t timeout_msec, bson_error_t *error); void _mongoc_buffer_destroy (mongoc_buffer_t *buffer); void _mongoc_buffer_clear (mongoc_buffer_t *buffer, bool zero); BSON_END_DECLS #endif /* MONGOC_BUFFER_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-buffer.c0000644000175100001660000002133314760300420022405 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "buffer" #ifndef MONGOC_BUFFER_DEFAULT_SIZE #define MONGOC_BUFFER_DEFAULT_SIZE 1024 #endif static void make_space_for (mongoc_buffer_t *buffer, size_t data_size) { if (buffer->len + data_size > buffer->datalen) { buffer->datalen = bson_next_power_of_two (buffer->len + data_size); buffer->data = (uint8_t *) buffer->realloc_func (buffer->data, buffer->datalen, buffer->realloc_data); } } /** * _mongoc_buffer_init: * @buffer: A mongoc_buffer_t to initialize. * @buf: A data buffer to attach to @buffer. * @buflen: The size of @buflen. * @realloc_func: A function to resize @buf. * * Initializes @buffer for use. If additional space is needed by @buffer, then * @realloc_func will be called to resize @buf. * * @buffer takes ownership of @buf and will realloc it to zero bytes when * cleaning up the data structure. */ void _mongoc_buffer_init ( mongoc_buffer_t *buffer, uint8_t *buf, size_t buflen, bson_realloc_func realloc_func, void *realloc_data) { BSON_ASSERT_PARAM (buffer); BSON_ASSERT (buflen || !buf); if (!realloc_func) { realloc_func = bson_realloc_ctx; } if (!buflen) { buflen = MONGOC_BUFFER_DEFAULT_SIZE; } if (!buf) { buf = (uint8_t *) realloc_func (NULL, buflen, NULL); } memset (buffer, 0, sizeof *buffer); buffer->data = buf; buffer->datalen = buflen; buffer->len = 0; buffer->realloc_func = realloc_func; buffer->realloc_data = realloc_data; } /** * _mongoc_buffer_destroy: * @buffer: A mongoc_buffer_t. * * Cleanup after @buffer and release any allocated resources. */ void _mongoc_buffer_destroy (mongoc_buffer_t *buffer) { BSON_ASSERT_PARAM (buffer); if (buffer->data && buffer->realloc_func) { buffer->realloc_func (buffer->data, 0, buffer->realloc_data); } memset (buffer, 0, sizeof *buffer); } /** * _mongoc_buffer_clear: * @buffer: A mongoc_buffer_t. * @zero: If the memory should be zeroed. * * Clears a buffers contents and resets it to initial state. You can request * that the memory is zeroed, which might be useful if you know the contents * contain security related information. */ void _mongoc_buffer_clear (mongoc_buffer_t *buffer, bool zero) { BSON_ASSERT_PARAM (buffer); if (zero) { memset (buffer->data, 0, buffer->datalen); } buffer->len = 0; } bool _mongoc_buffer_append (mongoc_buffer_t *buffer, const uint8_t *data, size_t data_size) { uint8_t *buf; ENTRY; BSON_ASSERT_PARAM (buffer); BSON_ASSERT (data_size); BSON_ASSERT (buffer->datalen); make_space_for (buffer, data_size); buf = &buffer->data[buffer->len]; BSON_ASSERT ((buffer->len + data_size) <= buffer->datalen); memcpy (buf, data, data_size); buffer->len += data_size; RETURN (true); } /** * mongoc_buffer_append_from_stream: * @buffer; A mongoc_buffer_t. * @stream: The stream to read from. * @size: The number of bytes to read. * @timeout_msec: The number of milliseconds to wait or -1 for the default * @error: A location for a bson_error_t, or NULL. * * Reads from stream @size bytes and stores them in @buffer. This can be used * in conjunction with reading RPCs from a stream. You read from the stream * into this buffer and then scatter the buffer into the RPC. * * Returns: true if successful; otherwise false and @error is set. */ bool _mongoc_buffer_append_from_stream ( mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t size, int64_t timeout_msec, bson_error_t *error) { uint8_t *buf; ssize_t ret; ENTRY; BSON_ASSERT_PARAM (buffer); BSON_ASSERT_PARAM (stream); BSON_ASSERT (size); BSON_ASSERT (buffer->datalen); make_space_for (buffer, size); buf = &buffer->data[buffer->len]; BSON_ASSERT ((buffer->len + size) <= buffer->datalen); if (BSON_UNLIKELY (!mcommon_in_range_signed (int32_t, timeout_msec))) { // CDRIVER-4589 bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "timeout_msec value %" PRId64 " exceeds supported 32-bit range", timeout_msec); RETURN (false); } ret = mongoc_stream_read (stream, buf, size, size, (int32_t) timeout_msec); if (mcommon_cmp_not_equal_su (ret, size)) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to read %zu bytes: socket error or timeout", size); RETURN (false); } buffer->len += (size_t) ret; RETURN (true); } /** * _mongoc_buffer_fill: * @buffer: A mongoc_buffer_t. * @stream: A stream to read from. * @min_bytes: The minimum number of bytes to read. * @error: A location for a bson_error_t or NULL. * * Attempts to fill the entire buffer, or at least @min_bytes. * * Returns: The number of buffered bytes, or -1 on failure. */ ssize_t _mongoc_buffer_fill ( mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t min_bytes, int64_t timeout_msec, bson_error_t *error) { ssize_t ret; size_t avail_bytes; ENTRY; BSON_ASSERT_PARAM (buffer); BSON_ASSERT_PARAM (stream); BSON_ASSERT (buffer->data); BSON_ASSERT (buffer->datalen); if (min_bytes <= buffer->len) { BSON_ASSERT (mcommon_in_range_unsigned (ssize_t, buffer->len)); RETURN ((ssize_t) buffer->len); } min_bytes -= buffer->len; make_space_for (buffer, min_bytes); avail_bytes = buffer->datalen - buffer->len; if (BSON_UNLIKELY (!mcommon_in_range_signed (int32_t, timeout_msec))) { // CDRIVER-4589 bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "timeout_msec value %" PRId64 " exceeds supported 32-bit range", timeout_msec); RETURN (false); } ret = mongoc_stream_read (stream, &buffer->data[buffer->len], avail_bytes, min_bytes, (int32_t) timeout_msec); if (ret < 0) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to buffer %zu bytes", min_bytes); RETURN (-1); } buffer->len += (size_t) ret; if (buffer->len < min_bytes) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Could only buffer %zu of %zu bytes", buffer->len, min_bytes); RETURN (-1); } BSON_ASSERT (mcommon_in_range_unsigned (ssize_t, buffer->len)); RETURN ((ssize_t) buffer->len); } /** * mongoc_buffer_try_append_from_stream: * @buffer; A mongoc_buffer_t. * @stream: The stream to read from. * @size: The number of bytes to read. * @timeout_msec: The number of milliseconds to wait or -1 for the default * * Reads from stream @size bytes and stores them in @buffer. This can be used * in conjunction with reading RPCs from a stream. You read from the stream * into this buffer and then scatter the buffer into the RPC. * * Returns: bytes read if successful; otherwise 0 or -1. */ ssize_t _mongoc_buffer_try_append_from_stream (mongoc_buffer_t *buffer, mongoc_stream_t *stream, size_t size, int64_t timeout_msec) { uint8_t *buf; ssize_t ret; ENTRY; BSON_ASSERT_PARAM (buffer); BSON_ASSERT_PARAM (stream); BSON_ASSERT (size); BSON_ASSERT (buffer->datalen); make_space_for (buffer, size); buf = &buffer->data[buffer->len]; BSON_ASSERT ((buffer->len + size) <= buffer->datalen); if (BSON_UNLIKELY (!mcommon_in_range_signed (int32_t, timeout_msec))) { // CDRIVER-4589 MONGOC_ERROR ("timeout_msec value %" PRId64 " exceeds supported 32-bit range", timeout_msec); RETURN (-1); } ret = mongoc_stream_read (stream, buf, size, 0, (int32_t) timeout_msec); if (ret > 0) { buffer->len += (size_t) ret; } RETURN (ret); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-bulk-operation-private.h0000644000175100001660000000314214760300420025542 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_BULK_OPERATION_PRIVATE_H #define MONGOC_BULK_OPERATION_PRIVATE_H #include #include #include BSON_BEGIN_DECLS struct _mongoc_bulk_operation_t { char *database; char *collection; mongoc_client_t *client; mongoc_client_session_t *session; mongoc_write_concern_t *write_concern; mongoc_bulk_write_flags_t flags; bson_value_t comment; bson_t let; uint32_t server_id; mongoc_array_t commands; mongoc_write_result_t result; bool executed; int64_t operation_id; }; mongoc_bulk_operation_t * _mongoc_bulk_operation_new (mongoc_client_t *client, const char *database, const char *collection, mongoc_bulk_write_flags_t flags, const mongoc_write_concern_t *write_concern); BSON_END_DECLS #endif /* MONGOC_BULK_OPERATION_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-bulk-operation.c0000644000175100001660000007414714760300420024102 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include /* * This is the implementation of both write commands and bulk write commands. * They are all implemented as one contiguous set since we'd like to cut down * on code duplication here. * * This implementation is currently naive. * * Some interesting optimizations might be: * * - If unordered mode, send operations as we get them instead of waiting * for execute() to be called. This could save us memcpy()'s too. * - If there is no acknowledgement desired, keep a count of how many * replies we need and ask the socket layer to skip that many bytes * when reading. * - Try to use iovec to send write commands with subdocuments rather than * copying them into the write command document. */ mongoc_bulk_operation_t * mongoc_bulk_operation_new (bool ordered) { mongoc_bulk_operation_t *bulk; bulk = BSON_ALIGNED_ALLOC0 (mongoc_bulk_operation_t); bulk->flags.bypass_document_validation = false; bulk->flags.ordered = ordered; bulk->server_id = 0; bson_init (&bulk->let); mongoc_array_aligned_init (&bulk->commands, mongoc_write_command_t); _mongoc_write_result_init (&bulk->result); return bulk; } mongoc_bulk_operation_t * _mongoc_bulk_operation_new (mongoc_client_t *client, /* IN */ const char *database, /* IN */ const char *collection, /* IN */ mongoc_bulk_write_flags_t flags, /* IN */ const mongoc_write_concern_t *write_concern) /* IN */ { mongoc_bulk_operation_t *bulk; BSON_ASSERT_PARAM (client); BSON_ASSERT_PARAM (collection); bulk = mongoc_bulk_operation_new (flags.ordered); bulk->client = client; bulk->database = bson_strdup (database); bulk->collection = bson_strdup (collection); bulk->write_concern = mongoc_write_concern_copy (write_concern); bulk->executed = false; bulk->flags = flags; bulk->operation_id = ++client->cluster.operation_id; return bulk; } void mongoc_bulk_operation_destroy (mongoc_bulk_operation_t *bulk) /* IN */ { mongoc_write_command_t *command; if (bulk) { for (size_t i = 0; i < bulk->commands.len; i++) { command = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, i); _mongoc_write_command_destroy (command); } bson_free (bulk->database); bson_free (bulk->collection); bson_value_destroy (&bulk->comment); bson_destroy (&bulk->let); mongoc_write_concern_destroy (bulk->write_concern); _mongoc_array_destroy (&bulk->commands); _mongoc_write_result_destroy (&bulk->result); bson_free (bulk); } } /* already failed, e.g. a bad call to mongoc_bulk_operation_insert? */ #define BULK_EXIT_IF_PRIOR_ERROR \ do { \ if (bulk->result.error.domain) { \ EXIT; \ } \ } while (0) #define BULK_RETURN_IF_PRIOR_ERROR \ do { \ if (bulk->result.error.domain) { \ if (error != &bulk->result.error) { \ bson_set_error (error, \ MONGOC_ERROR_COMMAND, \ MONGOC_ERROR_COMMAND_INVALID_ARG, \ "Bulk operation is invalid from prior error: %s", \ bulk->result.error.message); \ }; \ return false; \ }; \ } while (0) static bool _mongoc_bulk_operation_remove_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const mongoc_bulk_remove_opts_t *remove_opts, int32_t limit, bson_error_t *error) /* OUT */ { mongoc_write_command_t command = {0}; mongoc_write_command_t *last; bson_t cmd_opts = BSON_INITIALIZER; bson_t opts; bool has_collation; bool ret = false; bool has_delete_hint; ENTRY; BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (selector); bson_init (&opts); /* allow "limit" in opts, but it must be the correct limit */ if (remove_opts->limit != limit) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid \"limit\" in opts: %" PRId32 "." " The value must be %" PRId32 ", or omitted.", remove_opts->limit, limit); GOTO (done); } bson_append_int32 (&opts, "limit", 5, limit); has_collation = !bson_empty (&remove_opts->collation); if (has_collation) { bson_append_document (&opts, "collation", 9, &remove_opts->collation); } has_delete_hint = !!(remove_opts->hint.value_type); if (has_delete_hint) { bson_append_value (&opts, "hint", 4, &remove_opts->hint); } if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if (last->type == MONGOC_WRITE_COMMAND_DELETE) { last->flags.has_collation |= has_collation; last->flags.has_delete_hint |= has_delete_hint; last->flags.has_multi_write |= (remove_opts->limit == 0); _mongoc_write_command_delete_append (last, selector, &opts); ret = true; GOTO (done); } } if (bulk->comment.value_type != BSON_TYPE_EOD) { bson_append_value (&cmd_opts, "comment", 7, &bulk->comment); } if (!bson_empty (&bulk->let)) { bson_append_document (&cmd_opts, "let", 3, &bulk->let); } _mongoc_write_command_init_delete (&command, selector, &cmd_opts, &opts, bulk->flags, bulk->operation_id); command.flags.has_collation = has_collation; command.flags.has_delete_hint = has_delete_hint; command.flags.has_multi_write = (remove_opts->limit == 0); _mongoc_array_append_val (&bulk->commands, command); ret = true; done: bson_destroy (&cmd_opts); bson_destroy (&opts); RETURN (ret); } bool mongoc_bulk_operation_remove_one_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *opts, bson_error_t *error) /* OUT */ { mongoc_bulk_remove_one_opts_t remove_opts; bool ret; ENTRY; BULK_RETURN_IF_PRIOR_ERROR; if (!_mongoc_bulk_remove_one_opts_parse (bulk->client, opts, &remove_opts, error)) { _mongoc_bulk_remove_one_opts_cleanup (&remove_opts); RETURN (false); } ret = _mongoc_bulk_operation_remove_with_opts (bulk, selector, &remove_opts.remove, 1, error); _mongoc_bulk_remove_one_opts_cleanup (&remove_opts); RETURN (ret); } bool mongoc_bulk_operation_remove_many_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *opts, bson_error_t *error) /* OUT */ { mongoc_bulk_remove_many_opts_t remove_opts; bool ret; ENTRY; BULK_RETURN_IF_PRIOR_ERROR; if (!_mongoc_bulk_remove_many_opts_parse (bulk->client, opts, &remove_opts, error)) { _mongoc_bulk_remove_many_opts_cleanup (&remove_opts); RETURN (false); } ret = _mongoc_bulk_operation_remove_with_opts (bulk, selector, &remove_opts.remove, 0, error); _mongoc_bulk_remove_many_opts_cleanup (&remove_opts); RETURN (ret); } void mongoc_bulk_operation_remove (mongoc_bulk_operation_t *bulk, /* IN */ const bson_t *selector) /* IN */ { bson_error_t *error = &bulk->result.error; ENTRY; BULK_EXIT_IF_PRIOR_ERROR; if (!mongoc_bulk_operation_remove_many_with_opts (bulk, selector, NULL, error)) { MONGOC_WARNING ("%s", error->message); } if (error->domain) { MONGOC_WARNING ("%s", error->message); } EXIT; } void mongoc_bulk_operation_remove_one (mongoc_bulk_operation_t *bulk, /* IN */ const bson_t *selector) /* IN */ { bson_error_t *error = &bulk->result.error; ENTRY; BULK_EXIT_IF_PRIOR_ERROR; if (!mongoc_bulk_operation_remove_one_with_opts (bulk, selector, NULL, error)) { MONGOC_WARNING ("%s", error->message); } if (error->domain) { MONGOC_WARNING ("%s", error->message); } EXIT; } void mongoc_bulk_operation_delete (mongoc_bulk_operation_t *bulk, const bson_t *selector) { ENTRY; mongoc_bulk_operation_remove (bulk, selector); EXIT; } void mongoc_bulk_operation_delete_one (mongoc_bulk_operation_t *bulk, const bson_t *selector) { ENTRY; mongoc_bulk_operation_remove_one (bulk, selector); EXIT; } void mongoc_bulk_operation_insert (mongoc_bulk_operation_t *bulk, const bson_t *document) { ENTRY; BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (document); if (!mongoc_bulk_operation_insert_with_opts (bulk, document, NULL /* opts */, &bulk->result.error)) { MONGOC_WARNING ("%s", bulk->result.error.message); } EXIT; } bool mongoc_bulk_operation_insert_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *document, const bson_t *opts, bson_error_t *error) { mongoc_bulk_insert_opts_t insert_opts; mongoc_write_command_t command = {0}; mongoc_write_command_t *last; bson_t cmd_opts = BSON_INITIALIZER; bool ret = false; ENTRY; BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (document); BULK_RETURN_IF_PRIOR_ERROR; if (!_mongoc_bulk_insert_opts_parse (bulk->client, opts, &insert_opts, error)) { GOTO (done); } if (!_mongoc_validate_new_document (document, insert_opts.validate, error)) { GOTO (done); } /* Note: mongoc_bulk_insert_opts_t specifies allow_extra=False, so there is * no reason to concatenate cmd_opts with &insert_opts.extra. */ if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if (last->type == MONGOC_WRITE_COMMAND_INSERT) { _mongoc_write_command_insert_append (last, document); ret = true; GOTO (done); } } if (bulk->comment.value_type != BSON_TYPE_EOD) { bson_append_value (&cmd_opts, "comment", 7, &bulk->comment); } _mongoc_write_command_init_insert (&command, document, &cmd_opts, bulk->flags, bulk->operation_id); _mongoc_array_append_val (&bulk->commands, command); ret = true; done: _mongoc_bulk_insert_opts_cleanup (&insert_opts); bson_destroy (&cmd_opts); RETURN (ret); } static void _mongoc_bulk_operation_update_append (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, const mongoc_bulk_update_opts_t *update_opts, const bson_t *array_filters, const bson_t *extra_opts, const bson_t *sort) { mongoc_write_command_t command = {0}; mongoc_write_command_t *last; bson_t cmd_opts = BSON_INITIALIZER; bson_t opts; bool has_collation; bool has_array_filters; bool has_update_hint; bson_init (&opts); bson_append_bool (&opts, "upsert", 6, update_opts->upsert); bson_append_bool (&opts, "multi", 5, update_opts->multi); has_array_filters = !bson_empty0 (array_filters); if (has_array_filters) { bson_append_array (&opts, "arrayFilters", 12, array_filters); } has_collation = !bson_empty (&update_opts->collation); if (has_collation) { bson_append_document (&opts, "collation", 9, &update_opts->collation); } has_update_hint = !!(update_opts->hint.value_type); if (has_update_hint) { bson_append_value (&opts, "hint", 4, &update_opts->hint); } if (!bson_empty0 (sort)) { bson_append_document (&opts, "sort", 4, sort); } if (extra_opts) { bson_concat (&opts, extra_opts); } if (bulk->commands.len) { last = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, bulk->commands.len - 1); if (last->type == MONGOC_WRITE_COMMAND_UPDATE) { last->flags.has_array_filters |= has_array_filters; last->flags.has_collation |= has_collation; last->flags.has_update_hint |= has_update_hint; last->flags.has_multi_write |= update_opts->multi; _mongoc_write_command_update_append (last, selector, document, &opts); GOTO (done); } } if (bulk->comment.value_type != BSON_TYPE_EOD) { bson_append_value (&cmd_opts, "comment", 7, &bulk->comment); } if (!bson_empty (&bulk->let)) { bson_append_document (&cmd_opts, "let", 3, &bulk->let); } _mongoc_write_command_init_update (&command, selector, document, &cmd_opts, &opts, bulk->flags, bulk->operation_id); command.flags.has_array_filters = has_array_filters; command.flags.has_collation = has_collation; command.flags.has_update_hint = has_update_hint; command.flags.has_multi_write = update_opts->multi; _mongoc_array_append_val (&bulk->commands, command); done: bson_destroy (&cmd_opts); bson_destroy (&opts); } static bool _mongoc_bulk_operation_update_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, const mongoc_bulk_update_opts_t *update_opts, const bson_t *array_filters, const bson_t *extra_opts, bool multi, const bson_t *sort, bson_error_t *error) /* OUT */ { ENTRY; BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (selector); BSON_ASSERT_PARAM (document); if (!_mongoc_validate_update (document, update_opts->validate, error)) { RETURN (false); } /* allow "multi" in opts, but it must be the correct multi */ if (update_opts->multi != multi) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid \"multi\" in opts: %s." " The value must be %s, or omitted.", update_opts->multi ? "true" : "false", multi ? "true" : "false"); RETURN (false); } _mongoc_bulk_operation_update_append (bulk, selector, document, update_opts, array_filters, extra_opts, sort); RETURN (true); } bool mongoc_bulk_operation_update_one_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, const bson_t *opts, bson_error_t *error) /* OUT */ { mongoc_bulk_update_one_opts_t update_opts; bool ret; ENTRY; BULK_RETURN_IF_PRIOR_ERROR; if (!_mongoc_bulk_update_one_opts_parse (bulk->client, opts, &update_opts, error)) { _mongoc_bulk_update_one_opts_cleanup (&update_opts); RETURN (false); } ret = _mongoc_bulk_operation_update_with_opts (bulk, selector, document, &update_opts.update, &update_opts.arrayFilters, &update_opts.extra, false /* multi */, &update_opts.sort, error); _mongoc_bulk_update_one_opts_cleanup (&update_opts); RETURN (ret); } bool mongoc_bulk_operation_update_many_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, const bson_t *opts, bson_error_t *error) /* OUT */ { mongoc_bulk_update_many_opts_t update_opts; bool ret; ENTRY; BULK_RETURN_IF_PRIOR_ERROR; if (!_mongoc_bulk_update_many_opts_parse (bulk->client, opts, &update_opts, error)) { _mongoc_bulk_update_many_opts_cleanup (&update_opts); RETURN (false); } ret = _mongoc_bulk_operation_update_with_opts (bulk, selector, document, &update_opts.update, &update_opts.arrayFilters, &update_opts.extra, true /* multi */, NULL /* sort */, error); _mongoc_bulk_update_many_opts_cleanup (&update_opts); RETURN (ret); } void mongoc_bulk_operation_update (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert) { bson_t opts; bson_error_t *error = &bulk->result.error; ENTRY; BULK_EXIT_IF_PRIOR_ERROR; bson_init (&opts); if (upsert) { BSON_APPEND_BOOL (&opts, "upsert", upsert); } if (!mongoc_bulk_operation_update_many_with_opts (bulk, selector, document, &opts, error)) { MONGOC_WARNING ("%s", error->message); } bson_destroy (&opts); if (error->domain) { MONGOC_WARNING ("%s", error->message); } EXIT; } void mongoc_bulk_operation_update_one (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert) { bson_t opts; bson_error_t *error = &bulk->result.error; ENTRY; BULK_EXIT_IF_PRIOR_ERROR; bson_init (&opts); BSON_APPEND_BOOL (&opts, "upsert", upsert); if (!mongoc_bulk_operation_update_one_with_opts (bulk, selector, document, &opts, error)) { MONGOC_WARNING ("%s", error->message); } bson_destroy (&opts); if (error->domain) { MONGOC_WARNING ("%s", error->message); } EXIT; } bool mongoc_bulk_operation_replace_one_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, const bson_t *opts, bson_error_t *error) /* OUT */ { mongoc_bulk_replace_one_opts_t repl_opts; mongoc_bulk_update_opts_t *update_opts = &repl_opts.update; bool ret = false; ENTRY; BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (selector); BSON_ASSERT_PARAM (document); BULK_RETURN_IF_PRIOR_ERROR; if (!_mongoc_bulk_replace_one_opts_parse (bulk->client, opts, &repl_opts, error)) { GOTO (done); } if (!_mongoc_validate_replace (document, update_opts->validate, error)) { GOTO (done); } /* allow "multi" in opts, but it must be the correct multi */ if (update_opts->multi) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid \"multi\": true in opts for" " mongoc_bulk_operation_replace_one_with_opts." " The value must be true, or omitted."); GOTO (done); } _mongoc_bulk_operation_update_append ( bulk, selector, document, update_opts, NULL, &repl_opts.extra, &repl_opts.sort); ret = true; done: _mongoc_bulk_replace_one_opts_cleanup (&repl_opts); RETURN (ret); } void mongoc_bulk_operation_replace_one (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert) { bson_t opts = BSON_INITIALIZER; bson_error_t *error = &bulk->result.error; ENTRY; BSON_APPEND_BOOL (&opts, "upsert", upsert); if (!mongoc_bulk_operation_replace_one_with_opts (bulk, selector, document, &opts, error)) { MONGOC_WARNING ("%s", error->message); } bson_destroy (&opts); EXIT; } uint32_t mongoc_bulk_operation_execute (mongoc_bulk_operation_t *bulk, /* IN */ bson_t *reply, /* OUT */ bson_error_t *error) /* OUT */ { mongoc_cluster_t *cluster; mongoc_write_command_t *command; mongoc_server_stream_t *server_stream; bool ret; uint32_t offset = 0; ENTRY; BSON_ASSERT_PARAM (bulk); if (!bulk->client) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "mongoc_bulk_operation_execute() requires a client " "and one has not been set."); GOTO (err); } cluster = &bulk->client->cluster; if (bulk->executed) { _mongoc_write_result_destroy (&bulk->result); _mongoc_write_result_init (&bulk->result); } bulk->executed = true; if (!bulk->database) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "mongoc_bulk_operation_execute() requires a database " "and one has not been set."); GOTO (err); } else if (!bulk->collection) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "mongoc_bulk_operation_execute() requires a collection " "and one has not been set."); GOTO (err); } /* error stored by functions like mongoc_bulk_operation_insert that * can't report errors immediately */ if (bulk->result.error.domain) { if (error) { memcpy (error, &bulk->result.error, sizeof (bson_error_t)); } GOTO (err); } if (!bulk->commands.len) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot do an empty bulk write"); GOTO (err); } for (size_t i = 0u; i < bulk->commands.len; i++) { command = &_mongoc_array_index (&bulk->commands, mongoc_write_command_t, i); if (bulk->server_id) { server_stream = mongoc_cluster_stream_for_server ( cluster, bulk->server_id, true /* reconnect_ok */, bulk->session, reply, error); } else { const mongoc_ss_log_context_t ss_log_context = {.operation = _mongoc_write_command_get_name (command), .has_operation_id = true, .operation_id = command->operation_id}; server_stream = mongoc_cluster_stream_for_writes (cluster, &ss_log_context, bulk->session, NULL, reply, error); } if (!server_stream) { /* stream_for_server and stream_for_writes initialize reply on error */ RETURN (false); } _mongoc_write_command_execute (command, bulk->client, server_stream, bulk->database, bulk->collection, bulk->write_concern, offset, bulk->session, &bulk->result); bulk->server_id = server_stream->sd->id; /* If a retryable error occurred and a new primary was selected, use it in * subsequent commands. */ if (bulk->result.retry_server_id) { bulk->server_id = bulk->result.retry_server_id; } if (bulk->result.failed && (bulk->flags.ordered || bulk->result.must_stop)) { mongoc_server_stream_cleanup (server_stream); GOTO (cleanup); } offset += command->n_documents; mongoc_server_stream_cleanup (server_stream); } cleanup: _mongoc_bson_init_if_set (reply); ret = MONGOC_WRITE_RESULT_COMPLETE (&bulk->result, bulk->client->error_api_version, bulk->write_concern, MONGOC_ERROR_COMMAND /* err domain */, reply, error); RETURN (ret ? bulk->server_id : 0); err: _mongoc_bson_init_if_set (reply); RETURN (false); } void mongoc_bulk_operation_set_write_concern (mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern) { BSON_ASSERT_PARAM (bulk); if (bulk->write_concern) { mongoc_write_concern_destroy (bulk->write_concern); } if (write_concern) { bulk->write_concern = mongoc_write_concern_copy (write_concern); } else { bulk->write_concern = mongoc_write_concern_new (); } } const mongoc_write_concern_t * mongoc_bulk_operation_get_write_concern (const mongoc_bulk_operation_t *bulk) { BSON_ASSERT_PARAM (bulk); return bulk->write_concern; } void mongoc_bulk_operation_set_database (mongoc_bulk_operation_t *bulk, const char *database) { BSON_ASSERT_PARAM (bulk); if (bulk->database) { bson_free (bulk->database); } bulk->database = bson_strdup (database); } void mongoc_bulk_operation_set_collection (mongoc_bulk_operation_t *bulk, const char *collection) { BSON_ASSERT_PARAM (bulk); if (bulk->collection) { bson_free (bulk->collection); } bulk->collection = bson_strdup (collection); } void mongoc_bulk_operation_set_client (mongoc_bulk_operation_t *bulk, void *client) { BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (client); if (bulk->session) { BSON_ASSERT (bulk->session->client == client); } /* NOP if the client is not changing; otherwise, assign it and increment and * fetch its operation_id. */ if ((void *) bulk->client == client) { return; } bulk->client = (mongoc_client_t *) client; bulk->operation_id = ++bulk->client->cluster.operation_id; } void mongoc_bulk_operation_set_client_session (mongoc_bulk_operation_t *bulk, struct _mongoc_client_session_t *client_session) { BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (client_session); if (bulk->client) { BSON_ASSERT (bulk->client == client_session->client); } bulk->session = client_session; } uint32_t mongoc_bulk_operation_get_hint (const mongoc_bulk_operation_t *bulk) { return mongoc_bulk_operation_get_server_id (bulk); } uint32_t mongoc_bulk_operation_get_server_id (const mongoc_bulk_operation_t *bulk) { BSON_ASSERT_PARAM (bulk); return bulk->server_id; } void mongoc_bulk_operation_set_hint (mongoc_bulk_operation_t *bulk, uint32_t server_id) { mongoc_bulk_operation_set_server_id (bulk, server_id); } void mongoc_bulk_operation_set_server_id (mongoc_bulk_operation_t *bulk, uint32_t server_id) { BSON_ASSERT_PARAM (bulk); bulk->server_id = server_id; } void mongoc_bulk_operation_set_bypass_document_validation (mongoc_bulk_operation_t *bulk, bool bypass) { BSON_ASSERT_PARAM (bulk); bulk->flags.bypass_document_validation = bypass; } void mongoc_bulk_operation_set_comment (mongoc_bulk_operation_t *bulk, const bson_value_t *comment) { BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (comment); BSON_ASSERT (comment->value_type != BSON_TYPE_EOD); /* This method cannot be called after appending operations, as the CRUD spec * states the option should apply to all commands. Since commands are * initialized as operations are added, allowing "comment" to be changed at * any time could violate that contract. */ BSON_ASSERT (bulk->commands.len == 0); bson_value_destroy (&bulk->comment); bson_value_copy (comment, &bulk->comment); } void mongoc_bulk_operation_set_let (mongoc_bulk_operation_t *bulk, const bson_t *let) { BSON_ASSERT_PARAM (bulk); BSON_ASSERT_PARAM (let); /* This method cannot be called after appending operations, as the CRUD spec * states the option should apply to all commands (excluding insert). Since * commands are initialized as operations are added, allowing "let" to be * changed at any time could violate that contract. */ BSON_ASSERT (bulk->commands.len == 0); bson_destroy (&bulk->let); bson_copy_to (let, &bulk->let); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-bulk-operation.h0000644000175100001660000001562714760300420024105 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_BULK_OPERATION_H #define MONGOC_BULK_OPERATION_H #include #include #include /* ordered, bypass_document_validation, has_collation, multi */ #define MONGOC_BULK_WRITE_FLAGS_INIT \ { \ true, false, 0 \ } BSON_BEGIN_DECLS /* forward decl */ struct _mongoc_client_session_t; typedef struct _mongoc_bulk_operation_t mongoc_bulk_operation_t; typedef struct _mongoc_bulk_write_flags_t mongoc_bulk_write_flags_t; MONGOC_EXPORT (void) mongoc_bulk_operation_destroy (mongoc_bulk_operation_t *bulk); MONGOC_EXPORT (uint32_t) mongoc_bulk_operation_execute (mongoc_bulk_operation_t *bulk, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (void) mongoc_bulk_operation_delete (mongoc_bulk_operation_t *bulk, const bson_t *selector) BSON_GNUC_DEPRECATED_FOR (mongoc_bulk_operation_remove); MONGOC_EXPORT (void) mongoc_bulk_operation_delete_one (mongoc_bulk_operation_t *bulk, const bson_t *selector) BSON_GNUC_DEPRECATED_FOR (mongoc_bulk_operation_remove_one); MONGOC_EXPORT (void) mongoc_bulk_operation_insert (mongoc_bulk_operation_t *bulk, const bson_t *document); MONGOC_EXPORT (bool) mongoc_bulk_operation_insert_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *document, const bson_t *opts, bson_error_t *error); /* OUT */ MONGOC_EXPORT (void) mongoc_bulk_operation_remove (mongoc_bulk_operation_t *bulk, const bson_t *selector); MONGOC_EXPORT (bool) mongoc_bulk_operation_remove_many_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *opts, bson_error_t *error); /* OUT */ MONGOC_EXPORT (void) mongoc_bulk_operation_remove_one (mongoc_bulk_operation_t *bulk, const bson_t *selector); MONGOC_EXPORT (bool) mongoc_bulk_operation_remove_one_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *opts, bson_error_t *error); /* OUT */ MONGOC_EXPORT (void) mongoc_bulk_operation_replace_one (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert); MONGOC_EXPORT (bool) mongoc_bulk_operation_replace_one_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, const bson_t *opts, bson_error_t *error); /* OUT */ MONGOC_EXPORT (void) mongoc_bulk_operation_update (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert); MONGOC_EXPORT (bool) mongoc_bulk_operation_update_many_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, const bson_t *opts, bson_error_t *error); /* OUT */ MONGOC_EXPORT (void) mongoc_bulk_operation_update_one (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, bool upsert); MONGOC_EXPORT (bool) mongoc_bulk_operation_update_one_with_opts (mongoc_bulk_operation_t *bulk, const bson_t *selector, const bson_t *document, const bson_t *opts, bson_error_t *error); /* OUT */ MONGOC_EXPORT (void) mongoc_bulk_operation_set_bypass_document_validation (mongoc_bulk_operation_t *bulk, bool bypass); MONGOC_EXPORT (void) mongoc_bulk_operation_set_comment (mongoc_bulk_operation_t *bulk, const bson_value_t *comment); MONGOC_EXPORT (void) mongoc_bulk_operation_set_let (mongoc_bulk_operation_t *bulk, const bson_t *let); /* * The following functions are really only useful by language bindings and * those wanting to replay a bulk operation to a number of clients or * collections. */ MONGOC_EXPORT (mongoc_bulk_operation_t *) mongoc_bulk_operation_new (bool ordered) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_bulk_operation_set_write_concern (mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (void) mongoc_bulk_operation_set_database (mongoc_bulk_operation_t *bulk, const char *database); MONGOC_EXPORT (void) mongoc_bulk_operation_set_collection (mongoc_bulk_operation_t *bulk, const char *collection); MONGOC_EXPORT (void) mongoc_bulk_operation_set_client (mongoc_bulk_operation_t *bulk, void *client); MONGOC_EXPORT (void) mongoc_bulk_operation_set_client_session (mongoc_bulk_operation_t *bulk, struct _mongoc_client_session_t *client_session); // `mongoc_bulk_operation_set_hint` is deprecated for the more aptly named `mongoc_bulk_operation_set_server_id`. MONGOC_EXPORT (void) mongoc_bulk_operation_set_hint (mongoc_bulk_operation_t *bulk, uint32_t server_id) BSON_GNUC_DEPRECATED_FOR (mongoc_bulk_operation_set_server_id); MONGOC_EXPORT (void) mongoc_bulk_operation_set_server_id (mongoc_bulk_operation_t *bulk, uint32_t server_id); // `mongoc_bulk_operation_get_hint` is deprecated for the more aptly named `mongoc_bulk_operation_get_server_id`. MONGOC_EXPORT (uint32_t) mongoc_bulk_operation_get_hint (const mongoc_bulk_operation_t *bulk) BSON_GNUC_DEPRECATED_FOR (mongoc_bulk_operation_get_server_id); MONGOC_EXPORT (uint32_t) mongoc_bulk_operation_get_server_id (const mongoc_bulk_operation_t *bulk); MONGOC_EXPORT (const mongoc_write_concern_t *) mongoc_bulk_operation_get_write_concern (const mongoc_bulk_operation_t *bulk); BSON_END_DECLS #endif /* MONGOC_BULK_OPERATION_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-bulkwrite.c0000644000175100001660000020121514760300420023143 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include // MC_ENABLE_CONVERSION_WARNING_BEGIN #include #include #include #include #include #include #include #include // _mongoc_iter_document_as_bson #include #include MC_ENABLE_CONVERSION_WARNING_BEGIN struct _mongoc_bulkwriteopts_t { mongoc_optional_t ordered; mongoc_optional_t bypassdocumentvalidation; bson_t *let; mongoc_write_concern_t *writeconcern; mongoc_optional_t verboseresults; bson_value_t comment; bson_t *extra; uint32_t serverid; }; // `set_bson_opt` sets `*dst` by copying `src`. If `src` is NULL, `dst` is cleared. static void set_bson_opt (bson_t **dst, const bson_t *src) { BSON_ASSERT_PARAM (dst); bson_destroy (*dst); *dst = NULL; if (src) { *dst = bson_copy (src); } } static void set_bson_value_opt (bson_value_t *dst, const bson_value_t *src) { BSON_ASSERT_PARAM (dst); bson_value_destroy (dst); *dst = (bson_value_t){0}; if (src) { bson_value_copy (src, dst); } } mongoc_bulkwriteopts_t * mongoc_bulkwriteopts_new (void) { return bson_malloc0 (sizeof (mongoc_bulkwriteopts_t)); } void mongoc_bulkwriteopts_set_ordered (mongoc_bulkwriteopts_t *self, bool ordered) { BSON_ASSERT_PARAM (self); mongoc_optional_set_value (&self->ordered, ordered); } void mongoc_bulkwriteopts_set_bypassdocumentvalidation (mongoc_bulkwriteopts_t *self, bool bypassdocumentvalidation) { BSON_ASSERT_PARAM (self); mongoc_optional_set_value (&self->bypassdocumentvalidation, bypassdocumentvalidation); } void mongoc_bulkwriteopts_set_let (mongoc_bulkwriteopts_t *self, const bson_t *let) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (let); set_bson_opt (&self->let, let); } void mongoc_bulkwriteopts_set_writeconcern (mongoc_bulkwriteopts_t *self, const mongoc_write_concern_t *writeconcern) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (writeconcern); mongoc_write_concern_destroy (self->writeconcern); self->writeconcern = mongoc_write_concern_copy (writeconcern); } void mongoc_bulkwriteopts_set_verboseresults (mongoc_bulkwriteopts_t *self, bool verboseresults) { BSON_ASSERT_PARAM (self); mongoc_optional_set_value (&self->verboseresults, verboseresults); } void mongoc_bulkwriteopts_set_comment (mongoc_bulkwriteopts_t *self, const bson_value_t *comment) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (comment); set_bson_value_opt (&self->comment, comment); } void mongoc_bulkwriteopts_set_extra (mongoc_bulkwriteopts_t *self, const bson_t *extra) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (extra); set_bson_opt (&self->extra, extra); } void mongoc_bulkwriteopts_set_serverid (mongoc_bulkwriteopts_t *self, uint32_t serverid) { BSON_ASSERT_PARAM (self); self->serverid = serverid; } void mongoc_bulkwriteopts_destroy (mongoc_bulkwriteopts_t *self) { if (!self) { return; } bson_destroy (self->extra); bson_value_destroy (&self->comment); mongoc_write_concern_destroy (self->writeconcern); bson_destroy (self->let); bson_free (self); } typedef enum { MODEL_OP_INSERT, MODEL_OP_UPDATE, MODEL_OP_DELETE } model_op_t; typedef struct { model_op_t op; // `id_loc` locates the "_id" field of an insert document. struct { size_t op_start; // Offset in `mongoc_bulkwrite_t::ops` to the BSON for the insert op: { "document": ... } size_t op_len; // Length of insert op. uint32_t id_offset; // Offset in the insert op to the "_id" field. } id_loc; char *ns; } modeldata_t; struct _mongoc_bulkwrite_t { mongoc_client_t *client; // `executed` is set to true once `mongoc_bulkwrite_execute` is called. // `mongoc_bulkwrite_t` may not be executed more than once. bool executed; // `ops` is a document sequence. mongoc_buffer_t ops; size_t n_ops; // `arrayof_modeldata` is an array of `modeldata_t` sized to the number of models. It stores per-model data. mongoc_array_t arrayof_modeldata; // `max_insert_len` tracks the maximum length of any document to-be inserted. uint32_t max_insert_len; // `has_multi_write` is true if there are any multi-document update or delete operations. Multi-document // writes are ineligible for retryable writes. bool has_multi_write; int64_t operation_id; mongoc_client_session_t *session; }; // `mongoc_client_bulkwrite_new` creates a new bulk write operation. mongoc_bulkwrite_t * mongoc_client_bulkwrite_new (mongoc_client_t *self) { BSON_ASSERT_PARAM (self); mongoc_bulkwrite_t *bw = mongoc_bulkwrite_new (); bw->client = self; bw->operation_id = ++self->cluster.operation_id; return bw; } mongoc_bulkwrite_t * mongoc_bulkwrite_new (void) { mongoc_bulkwrite_t *bw = bson_malloc0 (sizeof (mongoc_bulkwrite_t)); _mongoc_buffer_init (&bw->ops, NULL, 0, NULL, NULL); _mongoc_array_init (&bw->arrayof_modeldata, sizeof (modeldata_t)); return bw; } void mongoc_bulkwrite_destroy (mongoc_bulkwrite_t *self) { if (!self) { return; } for (size_t i = 0; i < self->arrayof_modeldata.len; i++) { modeldata_t md = _mongoc_array_index (&self->arrayof_modeldata, modeldata_t, i); bson_free (md.ns); } _mongoc_array_destroy (&self->arrayof_modeldata); _mongoc_buffer_destroy (&self->ops); bson_free (self); } struct _mongoc_bulkwrite_insertoneopts_t { // No fields yet. Include an unused placeholder to prevent compile errors due to an empty struct. int unused; }; mongoc_bulkwrite_insertoneopts_t * mongoc_bulkwrite_insertoneopts_new (void) { return bson_malloc0 (sizeof (mongoc_bulkwrite_insertoneopts_t)); } void mongoc_bulkwrite_insertoneopts_destroy (mongoc_bulkwrite_insertoneopts_t *self) { if (!self) { return; } bson_free (self); } #define ERROR_IF_EXECUTED \ if (self->executed) { \ bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "bulk write already executed"); \ return false; \ } else \ (void) 0 bool mongoc_bulkwrite_append_insertone (mongoc_bulkwrite_t *self, const char *ns, const bson_t *document, BSON_MAYBE_UNUSED const mongoc_bulkwrite_insertoneopts_t *opts, // may be NULL bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (ns); BSON_ASSERT_PARAM (document); BSON_ASSERT (document->len >= 5); BSON_OPTIONAL_PARAM (opts); BSON_OPTIONAL_PARAM (error); ERROR_IF_EXECUTED; bson_t op = BSON_INITIALIZER; BSON_ASSERT (BSON_APPEND_INT32 (&op, "insert", -1)); // Append -1 as a placeholder. Will be overwritten later. // `persisted_id_offset` is the byte offset the `_id` in `op`. uint32_t persisted_id_offset = 0; { // Refer: bsonspec.org for BSON format. persisted_id_offset += 4; // Document length. persisted_id_offset += 1; // BSON type for int32. persisted_id_offset += (uint32_t) strlen ("insert") + 1u; // Key + 1 for NULL byte. persisted_id_offset += 4; // int32 value. persisted_id_offset += 1; // BSON type for document. persisted_id_offset += (uint32_t) strlen ("document") + 1u; // Key + 1 for NULL byte. } // If `document` does not contain `_id`, add one in the beginning. bson_iter_t existing_id_iter; if (!bson_iter_init_find (&existing_id_iter, document, "_id")) { bson_t tmp = BSON_INITIALIZER; bson_oid_t oid; bson_oid_init (&oid, NULL); BSON_ASSERT (BSON_APPEND_OID (&tmp, "_id", &oid)); BSON_ASSERT (bson_concat (&tmp, document)); BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "document", &tmp)); self->max_insert_len = BSON_MAX (self->max_insert_len, tmp.len); bson_destroy (&tmp); persisted_id_offset += 4; // Document length. } else { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "document", document)); self->max_insert_len = BSON_MAX (self->max_insert_len, document->len); // `existing_id_offset` is offset of `_id` in the input `document`. const uint32_t existing_id_offset = bson_iter_offset (&existing_id_iter); BSON_ASSERT (persisted_id_offset <= UINT32_MAX - existing_id_offset); persisted_id_offset += existing_id_offset; } size_t op_start = self->ops.len; // Save location of `op` to retrieve `_id` later. BSON_ASSERT (mcommon_in_range_size_t_unsigned (op.len)); BSON_ASSERT (_mongoc_buffer_append (&self->ops, bson_get_data (&op), (size_t) op.len)); self->n_ops++; modeldata_t md = {.op = MODEL_OP_INSERT, .id_loc = {.op_start = op_start, .op_len = (size_t) op.len, .id_offset = persisted_id_offset}, .ns = bson_strdup (ns)}; _mongoc_array_append_val (&self->arrayof_modeldata, md); bson_destroy (&op); return true; } static bool validate_update (const bson_t *update, bool *is_pipeline, bson_error_t *error) { BSON_ASSERT_PARAM (update); BSON_ASSERT_PARAM (is_pipeline); BSON_OPTIONAL_PARAM (error); bson_iter_t iter; *is_pipeline = _mongoc_document_is_pipeline (update); if (*is_pipeline) { return true; } BSON_ASSERT (bson_iter_init (&iter, update)); if (bson_iter_next (&iter)) { const char *key = bson_iter_key (&iter); if (key[0] != '$') { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid key '%s': update only works with $ operators" " and pipelines", key); return false; } } return true; } struct _mongoc_bulkwrite_updateoneopts_t { bson_t *arrayfilters; bson_t *collation; bson_value_t hint; mongoc_optional_t upsert; bson_t *sort; }; mongoc_bulkwrite_updateoneopts_t * mongoc_bulkwrite_updateoneopts_new (void) { return bson_malloc0 (sizeof (mongoc_bulkwrite_updateoneopts_t)); } void mongoc_bulkwrite_updateoneopts_set_arrayfilters (mongoc_bulkwrite_updateoneopts_t *self, const bson_t *arrayfilters) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (arrayfilters); set_bson_opt (&self->arrayfilters, arrayfilters); } void mongoc_bulkwrite_updateoneopts_set_collation (mongoc_bulkwrite_updateoneopts_t *self, const bson_t *collation) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (collation); set_bson_opt (&self->collation, collation); } void mongoc_bulkwrite_updateoneopts_set_hint (mongoc_bulkwrite_updateoneopts_t *self, const bson_value_t *hint) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (hint); set_bson_value_opt (&self->hint, hint); } void mongoc_bulkwrite_updateoneopts_set_upsert (mongoc_bulkwrite_updateoneopts_t *self, bool upsert) { BSON_ASSERT_PARAM (self); mongoc_optional_set_value (&self->upsert, upsert); } void mongoc_bulkwrite_updateoneopts_set_sort (mongoc_bulkwrite_updateoneopts_t *self, const bson_t *sort) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (sort); set_bson_opt (&self->sort, sort); } void mongoc_bulkwrite_updateoneopts_destroy (mongoc_bulkwrite_updateoneopts_t *self) { if (!self) { return; } bson_destroy (self->arrayfilters); bson_destroy (self->collation); bson_value_destroy (&self->hint); bson_destroy (self->sort); bson_free (self); } bool mongoc_bulkwrite_append_updateone (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const bson_t *update, const mongoc_bulkwrite_updateoneopts_t *opts /* May be NULL */, bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (ns); BSON_ASSERT_PARAM (filter); BSON_ASSERT (filter->len >= 5); BSON_ASSERT_PARAM (update); BSON_ASSERT (update->len >= 5); BSON_OPTIONAL_PARAM (opts); BSON_OPTIONAL_PARAM (error); ERROR_IF_EXECUTED; mongoc_bulkwrite_updateoneopts_t defaults = {0}; if (!opts) { opts = &defaults; } bool is_pipeline = false; if (!validate_update (update, &is_pipeline, error)) { return false; } bson_t op = BSON_INITIALIZER; BSON_ASSERT (BSON_APPEND_INT32 (&op, "update", -1)); // Append -1 as a placeholder. Will be overwritten later. BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "filter", filter)); if (is_pipeline) { BSON_ASSERT (BSON_APPEND_ARRAY (&op, "updateMods", update)); } else { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "updateMods", update)); } BSON_ASSERT (BSON_APPEND_BOOL (&op, "multi", false)); if (opts->arrayfilters) { BSON_ASSERT (BSON_APPEND_ARRAY (&op, "arrayFilters", opts->arrayfilters)); } if (opts->collation) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "collation", opts->collation)); } if (opts->hint.value_type != BSON_TYPE_EOD) { BSON_ASSERT (BSON_APPEND_VALUE (&op, "hint", &opts->hint)); } if (mongoc_optional_is_set (&opts->upsert)) { BSON_ASSERT (BSON_APPEND_BOOL (&op, "upsert", mongoc_optional_value (&opts->upsert))); } if (opts->sort) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "sort", opts->sort)); } BSON_ASSERT (_mongoc_buffer_append (&self->ops, bson_get_data (&op), op.len)); self->n_ops++; modeldata_t md = {.op = MODEL_OP_UPDATE, .ns = bson_strdup (ns)}; _mongoc_array_append_val (&self->arrayof_modeldata, md); bson_destroy (&op); return true; } struct _mongoc_bulkwrite_replaceoneopts_t { bson_t *collation; bson_value_t hint; mongoc_optional_t upsert; bson_t *sort; }; mongoc_bulkwrite_replaceoneopts_t * mongoc_bulkwrite_replaceoneopts_new (void) { return bson_malloc0 (sizeof (mongoc_bulkwrite_replaceoneopts_t)); } void mongoc_bulkwrite_replaceoneopts_set_collation (mongoc_bulkwrite_replaceoneopts_t *self, const bson_t *collation) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (collation); set_bson_opt (&self->collation, collation); } void mongoc_bulkwrite_replaceoneopts_set_hint (mongoc_bulkwrite_replaceoneopts_t *self, const bson_value_t *hint) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (hint); set_bson_value_opt (&self->hint, hint); } void mongoc_bulkwrite_replaceoneopts_set_upsert (mongoc_bulkwrite_replaceoneopts_t *self, bool upsert) { BSON_ASSERT_PARAM (self); mongoc_optional_set_value (&self->upsert, upsert); } void mongoc_bulkwrite_replaceoneopts_set_sort (mongoc_bulkwrite_replaceoneopts_t *self, const bson_t *sort) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (sort); set_bson_opt (&self->sort, sort); } void mongoc_bulkwrite_replaceoneopts_destroy (mongoc_bulkwrite_replaceoneopts_t *self) { if (!self) { return; } bson_destroy (self->collation); bson_value_destroy (&self->hint); bson_destroy (self->sort); bson_free (self); } bool validate_replace (const bson_t *doc, bson_error_t *error) { BSON_OPTIONAL_PARAM (doc); BSON_OPTIONAL_PARAM (error); bson_iter_t iter; BSON_ASSERT (bson_iter_init (&iter, doc)); if (bson_iter_next (&iter)) { const char *key = bson_iter_key (&iter); if (key[0] == '$') { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid key '%s': replace prohibits $ operators", key); return false; } } return true; } bool mongoc_bulkwrite_append_replaceone (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const bson_t *replacement, const mongoc_bulkwrite_replaceoneopts_t *opts /* May be NULL */, bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (ns); BSON_ASSERT_PARAM (filter); BSON_ASSERT (filter->len >= 5); BSON_ASSERT_PARAM (replacement); BSON_ASSERT (replacement->len >= 5); BSON_OPTIONAL_PARAM (opts); BSON_OPTIONAL_PARAM (error); ERROR_IF_EXECUTED; mongoc_bulkwrite_replaceoneopts_t defaults = {0}; if (!opts) { opts = &defaults; } if (!validate_replace (replacement, error)) { return false; } bson_t op = BSON_INITIALIZER; BSON_ASSERT (BSON_APPEND_INT32 (&op, "update", -1)); // Append -1 as a placeholder. Will be overwritten later. BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "filter", filter)); BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "updateMods", replacement)); BSON_ASSERT (BSON_APPEND_BOOL (&op, "multi", false)); if (opts->collation) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "collation", opts->collation)); } if (opts->hint.value_type != BSON_TYPE_EOD) { BSON_ASSERT (BSON_APPEND_VALUE (&op, "hint", &opts->hint)); } if (mongoc_optional_is_set (&opts->upsert)) { BSON_ASSERT (BSON_APPEND_BOOL (&op, "upsert", mongoc_optional_value (&opts->upsert))); } if (opts->sort) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "sort", opts->sort)); } BSON_ASSERT (_mongoc_buffer_append (&self->ops, bson_get_data (&op), op.len)); self->n_ops++; self->max_insert_len = BSON_MAX (self->max_insert_len, replacement->len); modeldata_t md = {.op = MODEL_OP_UPDATE, .ns = bson_strdup (ns)}; _mongoc_array_append_val (&self->arrayof_modeldata, md); bson_destroy (&op); return true; } struct _mongoc_bulkwrite_updatemanyopts_t { bson_t *arrayfilters; bson_t *collation; bson_value_t hint; mongoc_optional_t upsert; }; mongoc_bulkwrite_updatemanyopts_t * mongoc_bulkwrite_updatemanyopts_new (void) { return bson_malloc0 (sizeof (mongoc_bulkwrite_updatemanyopts_t)); } void mongoc_bulkwrite_updatemanyopts_set_arrayfilters (mongoc_bulkwrite_updatemanyopts_t *self, const bson_t *arrayfilters) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (arrayfilters); set_bson_opt (&self->arrayfilters, arrayfilters); } void mongoc_bulkwrite_updatemanyopts_set_collation (mongoc_bulkwrite_updatemanyopts_t *self, const bson_t *collation) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (collation); set_bson_opt (&self->collation, collation); } void mongoc_bulkwrite_updatemanyopts_set_hint (mongoc_bulkwrite_updatemanyopts_t *self, const bson_value_t *hint) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (hint); set_bson_value_opt (&self->hint, hint); } void mongoc_bulkwrite_updatemanyopts_set_upsert (mongoc_bulkwrite_updatemanyopts_t *self, bool upsert) { BSON_ASSERT_PARAM (self); mongoc_optional_set_value (&self->upsert, upsert); } void mongoc_bulkwrite_updatemanyopts_destroy (mongoc_bulkwrite_updatemanyopts_t *self) { if (!self) { return; } bson_destroy (self->arrayfilters); bson_destroy (self->collation); bson_value_destroy (&self->hint); bson_free (self); } bool mongoc_bulkwrite_append_updatemany (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const bson_t *update, const mongoc_bulkwrite_updatemanyopts_t *opts /* May be NULL */, bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (ns); BSON_ASSERT_PARAM (filter); BSON_ASSERT (filter->len >= 5); BSON_ASSERT_PARAM (update); BSON_ASSERT (update->len >= 5); BSON_OPTIONAL_PARAM (opts); BSON_OPTIONAL_PARAM (error); ERROR_IF_EXECUTED; mongoc_bulkwrite_updatemanyopts_t defaults = {0}; if (!opts) { opts = &defaults; } bool is_pipeline = false; if (!validate_update (update, &is_pipeline, error)) { return false; } bson_t op = BSON_INITIALIZER; BSON_ASSERT (BSON_APPEND_INT32 (&op, "update", -1)); // Append -1 as a placeholder. Will be overwritten later. BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "filter", filter)); if (is_pipeline) { BSON_ASSERT (BSON_APPEND_ARRAY (&op, "updateMods", update)); } else { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "updateMods", update)); } BSON_ASSERT (BSON_APPEND_BOOL (&op, "multi", true)); if (opts->arrayfilters) { BSON_ASSERT (BSON_APPEND_ARRAY (&op, "arrayFilters", opts->arrayfilters)); } if (opts->collation) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "collation", opts->collation)); } if (opts->hint.value_type != BSON_TYPE_EOD) { BSON_ASSERT (BSON_APPEND_VALUE (&op, "hint", &opts->hint)); } if (mongoc_optional_is_set (&opts->upsert)) { BSON_ASSERT (BSON_APPEND_BOOL (&op, "upsert", mongoc_optional_value (&opts->upsert))); } BSON_ASSERT (_mongoc_buffer_append (&self->ops, bson_get_data (&op), op.len)); self->has_multi_write = true; self->n_ops++; modeldata_t md = {.op = MODEL_OP_UPDATE, .ns = bson_strdup (ns)}; _mongoc_array_append_val (&self->arrayof_modeldata, md); bson_destroy (&op); return true; } struct _mongoc_bulkwrite_deleteoneopts_t { bson_t *collation; bson_value_t hint; }; mongoc_bulkwrite_deleteoneopts_t * mongoc_bulkwrite_deleteoneopts_new (void) { return bson_malloc0 (sizeof (mongoc_bulkwrite_deleteoneopts_t)); } void mongoc_bulkwrite_deleteoneopts_set_collation (mongoc_bulkwrite_deleteoneopts_t *self, const bson_t *collation) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (collation); set_bson_opt (&self->collation, collation); } void mongoc_bulkwrite_deleteoneopts_set_hint (mongoc_bulkwrite_deleteoneopts_t *self, const bson_value_t *hint) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (hint); set_bson_value_opt (&self->hint, hint); } void mongoc_bulkwrite_deleteoneopts_destroy (mongoc_bulkwrite_deleteoneopts_t *self) { if (!self) { return; } bson_value_destroy (&self->hint); bson_destroy (self->collation); bson_free (self); } bool mongoc_bulkwrite_append_deleteone (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const mongoc_bulkwrite_deleteoneopts_t *opts /* May be NULL */, bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (ns); BSON_ASSERT_PARAM (filter); BSON_ASSERT (filter->len >= 5); BSON_OPTIONAL_PARAM (opts); BSON_OPTIONAL_PARAM (error); ERROR_IF_EXECUTED; mongoc_bulkwrite_deleteoneopts_t defaults = {0}; if (!opts) { opts = &defaults; } bson_t op = BSON_INITIALIZER; BSON_ASSERT (BSON_APPEND_INT32 (&op, "delete", -1)); // Append -1 as a placeholder. Will be overwritten later. BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "filter", filter)); BSON_ASSERT (BSON_APPEND_BOOL (&op, "multi", false)); if (opts->collation) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "collation", opts->collation)); } if (opts->hint.value_type != BSON_TYPE_EOD) { BSON_ASSERT (BSON_APPEND_VALUE (&op, "hint", &opts->hint)); } BSON_ASSERT (_mongoc_buffer_append (&self->ops, bson_get_data (&op), op.len)); self->n_ops++; modeldata_t md = {.op = MODEL_OP_DELETE, .ns = bson_strdup (ns)}; _mongoc_array_append_val (&self->arrayof_modeldata, md); bson_destroy (&op); return true; } struct _mongoc_bulkwrite_deletemanyopts_t { bson_t *collation; bson_value_t hint; }; mongoc_bulkwrite_deletemanyopts_t * mongoc_bulkwrite_deletemanyopts_new (void) { return bson_malloc0 (sizeof (mongoc_bulkwrite_deletemanyopts_t)); } void mongoc_bulkwrite_deletemanyopts_set_collation (mongoc_bulkwrite_deletemanyopts_t *self, const bson_t *collation) { BSON_ASSERT_PARAM (self); set_bson_opt (&self->collation, collation); } void mongoc_bulkwrite_deletemanyopts_set_hint (mongoc_bulkwrite_deletemanyopts_t *self, const bson_value_t *hint) { BSON_ASSERT_PARAM (self); set_bson_value_opt (&self->hint, hint); } void mongoc_bulkwrite_deletemanyopts_destroy (mongoc_bulkwrite_deletemanyopts_t *self) { if (!self) { return; } bson_value_destroy (&self->hint); bson_destroy (self->collation); bson_free (self); } bool mongoc_bulkwrite_append_deletemany (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const mongoc_bulkwrite_deletemanyopts_t *opts /* May be NULL */, bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (ns); BSON_ASSERT_PARAM (filter); BSON_ASSERT (filter->len >= 5); BSON_OPTIONAL_PARAM (opts); BSON_OPTIONAL_PARAM (error); ERROR_IF_EXECUTED; mongoc_bulkwrite_deletemanyopts_t defaults = {0}; if (!opts) { opts = &defaults; } bson_t op = BSON_INITIALIZER; BSON_ASSERT (BSON_APPEND_INT32 (&op, "delete", -1)); // Append -1 as a placeholder. Will be overwritten later. BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "filter", filter)); BSON_ASSERT (BSON_APPEND_BOOL (&op, "multi", true)); if (opts->collation) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&op, "collation", opts->collation)); } if (opts->hint.value_type != BSON_TYPE_EOD) { BSON_ASSERT (BSON_APPEND_VALUE (&op, "hint", &opts->hint)); } BSON_ASSERT (_mongoc_buffer_append (&self->ops, bson_get_data (&op), op.len)); self->has_multi_write = true; self->n_ops++; modeldata_t md = {.op = MODEL_OP_DELETE, .ns = bson_strdup (ns)}; _mongoc_array_append_val (&self->arrayof_modeldata, md); bson_destroy (&op); return true; } struct _mongoc_bulkwriteresult_t { int64_t insertedcount; int64_t upsertedcount; int64_t matchedcount; int64_t modifiedcount; int64_t deletedcount; int64_t errorscount; // sum of all `nErrors`. struct { bool isset; int64_t index; } first_error_index; uint32_t serverid; bson_t insertresults; bson_t updateresults; bson_t deleteresults; bool verboseresults; }; int64_t mongoc_bulkwriteresult_insertedcount (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); return self->insertedcount; } int64_t mongoc_bulkwriteresult_upsertedcount (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); return self->upsertedcount; } int64_t mongoc_bulkwriteresult_matchedcount (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); return self->matchedcount; } int64_t mongoc_bulkwriteresult_modifiedcount (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); return self->modifiedcount; } int64_t mongoc_bulkwriteresult_deletedcount (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); return self->deletedcount; } const bson_t * mongoc_bulkwriteresult_insertresults (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); if (!self->verboseresults) { return NULL; } return &self->insertresults; } const bson_t * mongoc_bulkwriteresult_updateresults (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); if (!self->verboseresults) { return NULL; } return &self->updateresults; } const bson_t * mongoc_bulkwriteresult_deleteresults (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); if (!self->verboseresults) { return NULL; } return &self->deleteresults; } uint32_t mongoc_bulkwriteresult_serverid (const mongoc_bulkwriteresult_t *self) { BSON_ASSERT_PARAM (self); return self->serverid; } void mongoc_bulkwriteresult_destroy (mongoc_bulkwriteresult_t *self) { if (!self) { return; } bson_destroy (&self->deleteresults); bson_destroy (&self->updateresults); bson_destroy (&self->insertresults); bson_free (self); } static mongoc_bulkwriteresult_t * _bulkwriteresult_new (void) { mongoc_bulkwriteresult_t *self = bson_malloc0 (sizeof (*self)); bson_init (&self->insertresults); bson_init (&self->updateresults); bson_init (&self->deleteresults); return self; } static void _bulkwriteresult_set_updateresult ( mongoc_bulkwriteresult_t *self, int64_t n, int64_t nModified, const bson_value_t *upserted_id, size_t models_idx) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (upserted_id); bson_t updateresult; { char *key = bson_strdup_printf ("%zu", models_idx); BSON_APPEND_DOCUMENT_BEGIN (&self->updateresults, key, &updateresult); bson_free (key); } BSON_ASSERT (BSON_APPEND_INT64 (&updateresult, "matchedCount", n)); BSON_ASSERT (BSON_APPEND_INT64 (&updateresult, "modifiedCount", nModified)); if (upserted_id) { BSON_ASSERT (BSON_APPEND_VALUE (&updateresult, "upsertedId", upserted_id)); } BSON_ASSERT (bson_append_document_end (&self->updateresults, &updateresult)); } static void _bulkwriteresult_set_deleteresult (mongoc_bulkwriteresult_t *self, int64_t n, size_t models_idx) { BSON_ASSERT_PARAM (self); bson_t deleteresult; { char *key = bson_strdup_printf ("%zu", models_idx); BSON_APPEND_DOCUMENT_BEGIN (&self->deleteresults, key, &deleteresult); bson_free (key); } BSON_ASSERT (BSON_APPEND_INT64 (&deleteresult, "deletedCount", n)); BSON_ASSERT (bson_append_document_end (&self->deleteresults, &deleteresult)); } static void _bulkwriteresult_set_insertresult (mongoc_bulkwriteresult_t *self, const bson_iter_t *id_iter, size_t models_idx) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (id_iter); bson_t insertresult; { char *key = bson_strdup_printf ("%zu", models_idx); BSON_APPEND_DOCUMENT_BEGIN (&self->insertresults, key, &insertresult); bson_free (key); } BSON_ASSERT (BSON_APPEND_ITER (&insertresult, "insertedId", id_iter)); BSON_ASSERT (bson_append_document_end (&self->insertresults, &insertresult)); } struct _mongoc_bulkwriteexception_t { bson_error_t error; bson_t error_reply; bson_t write_concern_errors; size_t write_concern_errors_len; bson_t write_errors; // If `has_any_error` is false, the bulk write exception is not returned. bool has_any_error; }; static mongoc_bulkwriteexception_t * _bulkwriteexception_new (void) { mongoc_bulkwriteexception_t *self = bson_malloc0 (sizeof (*self)); bson_init (&self->write_concern_errors); bson_init (&self->write_errors); bson_init (&self->error_reply); return self; } // Returns true if there was a top-level error. bool mongoc_bulkwriteexception_error (const mongoc_bulkwriteexception_t *self, bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (error); if (self->error.code != 0) { memcpy (error, &self->error, sizeof (*error)); return true; } return false; // No top-level error. } const bson_t * mongoc_bulkwriteexception_writeerrors (const mongoc_bulkwriteexception_t *self) { BSON_ASSERT_PARAM (self); return &self->write_errors; } const bson_t * mongoc_bulkwriteexception_writeconcernerrors (const mongoc_bulkwriteexception_t *self) { BSON_ASSERT_PARAM (self); return &self->write_concern_errors; } const bson_t * mongoc_bulkwriteexception_errorreply (const mongoc_bulkwriteexception_t *self) { BSON_ASSERT_PARAM (self); return &self->error_reply; } void mongoc_bulkwriteexception_destroy (mongoc_bulkwriteexception_t *self) { if (!self) { return; } bson_destroy (&self->write_errors); bson_destroy (&self->write_concern_errors); bson_destroy (&self->error_reply); bson_free (self); } static void _bulkwriteexception_set_error (mongoc_bulkwriteexception_t *self, bson_error_t *error) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (error); BSON_ASSERT (error->code != 0); memcpy (&self->error, error, sizeof (*error)); self->has_any_error = true; } static void _bulkwriteexception_set_error_reply (mongoc_bulkwriteexception_t *self, const bson_t *error_reply) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (error_reply); bson_copy_to (error_reply, &self->error_reply); self->has_any_error = true; } static void _bulkwriteexception_append_writeconcernerror (mongoc_bulkwriteexception_t *self, int32_t code, const char *errmsg, const bson_t *errInfo) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (errmsg); BSON_ASSERT_PARAM (errInfo); char *key = bson_strdup_printf ("%zu", self->write_concern_errors_len); self->write_concern_errors_len++; bson_t write_concern_error; BSON_ASSERT (BSON_APPEND_DOCUMENT_BEGIN (&self->write_concern_errors, key, &write_concern_error)); BSON_ASSERT (BSON_APPEND_INT32 (&write_concern_error, "code", code)); BSON_ASSERT (BSON_APPEND_UTF8 (&write_concern_error, "message", errmsg)); BSON_ASSERT (BSON_APPEND_DOCUMENT (&write_concern_error, "details", errInfo)); BSON_ASSERT (bson_append_document_end (&self->write_concern_errors, &write_concern_error)); self->has_any_error = true; bson_free (key); } static void _bulkwriteexception_set_writeerror ( mongoc_bulkwriteexception_t *self, int32_t code, const char *errmsg, const bson_t *errInfo, size_t models_idx) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (errmsg); BSON_ASSERT_PARAM (errInfo); bson_t write_error; { char *key = bson_strdup_printf ("%zu", models_idx); BSON_APPEND_DOCUMENT_BEGIN (&self->write_errors, key, &write_error); bson_free (key); } BSON_ASSERT (BSON_APPEND_INT32 (&write_error, "code", code)); BSON_ASSERT (BSON_APPEND_UTF8 (&write_error, "message", errmsg)); BSON_ASSERT (BSON_APPEND_DOCUMENT (&write_error, "details", errInfo)); BSON_ASSERT (bson_append_document_end (&self->write_errors, &write_error)); self->has_any_error = true; } static bool lookup_int32 (const bson_t *bson, const char *key, int32_t *out, const char *source, mongoc_bulkwriteexception_t *exc) { BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (out); BSON_OPTIONAL_PARAM (source); BSON_ASSERT_PARAM (exc); bson_iter_t iter; if (bson_iter_init_find (&iter, bson, key) && BSON_ITER_HOLDS_INT32 (&iter)) { *out = bson_iter_int32 (&iter); return true; } bson_error_t error; if (source) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected to find int32 `%s` in %s, but did not", key, source); } else { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected to find int32 `%s`, but did not", key); } _bulkwriteexception_set_error (exc, &error); return false; } // `lookup_as_int64` looks for `key` as a BSON int32, int64, or double and returns as an int64_t. Doubles are truncated. static int64_t lookup_as_int64 ( const bson_t *bson, const char *key, int64_t *out, const char *source, mongoc_bulkwriteexception_t *exc) { BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (out); BSON_OPTIONAL_PARAM (source); BSON_ASSERT_PARAM (exc); bson_iter_t iter; if (bson_iter_init_find (&iter, bson, key) && BSON_ITER_HOLDS_NUMBER (&iter)) { *out = bson_iter_as_int64 (&iter); return true; } bson_error_t error; if (source) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected to find int32, int64, or double `%s` in %s, but did not", key, source); } else { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected to find int32, int64, or double `%s`, but did not", key); } _bulkwriteexception_set_error (exc, &error); return false; } static bool lookup_string ( const bson_t *bson, const char *key, const char **out, const char *source, mongoc_bulkwriteexception_t *exc) { BSON_ASSERT_PARAM (bson); BSON_ASSERT_PARAM (key); BSON_ASSERT_PARAM (out); BSON_OPTIONAL_PARAM (source); BSON_ASSERT_PARAM (exc); bson_iter_t iter; if (bson_iter_init_find (&iter, bson, key) && BSON_ITER_HOLDS_UTF8 (&iter)) { *out = bson_iter_utf8 (&iter, NULL); return true; } bson_error_t error; if (source) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected to find string `%s` in %s, but did not", key, source); } else { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected to find string `%s`, but did not", key); } _bulkwriteexception_set_error (exc, &error); return false; } // `_bulkwritereturn_apply_reply` applies the top-level fields of a server reply to the returned results. static bool _bulkwritereturn_apply_reply (mongoc_bulkwritereturn_t *self, const bson_t *cmd_reply) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (cmd_reply); // Parse top-level fields. // These fields are expected to be int32 as of server 8.0. However, drivers return the values as int64. // Use `lookup_as_int64` to support other numeric types to future-proof. int64_t nInserted; if (!lookup_as_int64 (cmd_reply, "nInserted", &nInserted, NULL, self->exc)) { return false; } self->res->insertedcount += nInserted; int64_t nMatched; if (!lookup_as_int64 (cmd_reply, "nMatched", &nMatched, NULL, self->exc)) { return false; } self->res->matchedcount += nMatched; int64_t nModified; if (!lookup_as_int64 (cmd_reply, "nModified", &nModified, NULL, self->exc)) { return false; } self->res->modifiedcount += nModified; int64_t nDeleted; if (!lookup_as_int64 (cmd_reply, "nDeleted", &nDeleted, NULL, self->exc)) { return false; } self->res->deletedcount += nDeleted; int64_t nUpserted; if (!lookup_as_int64 (cmd_reply, "nUpserted", &nUpserted, NULL, self->exc)) { return false; } self->res->upsertedcount += nUpserted; int64_t nErrors; if (!lookup_as_int64 (cmd_reply, "nErrors", &nErrors, NULL, self->exc)) { return false; } self->res->errorscount += nErrors; bson_error_t error; bson_iter_t iter; if (bson_iter_init_find (&iter, cmd_reply, "writeConcernError")) { bson_iter_t wce_iter; bson_t wce_bson; if (!_mongoc_iter_document_as_bson (&iter, &wce_bson, &error)) { _bulkwriteexception_set_error (self->exc, &error); _bulkwriteexception_set_error_reply (self->exc, cmd_reply); return false; } // Parse `code`. int32_t code; if (!lookup_int32 (&wce_bson, "code", &code, "writeConcernError", self->exc)) { return false; } // Parse `errmsg`. const char *errmsg; if (!lookup_string (&wce_bson, "errmsg", &errmsg, "writeConcernError", self->exc)) { return false; } // Parse optional `errInfo`. bson_t errInfo = BSON_INITIALIZER; if (bson_iter_init_find (&wce_iter, &wce_bson, "errInfo")) { if (!_mongoc_iter_document_as_bson (&wce_iter, &errInfo, &error)) { _bulkwriteexception_set_error (self->exc, &error); _bulkwriteexception_set_error_reply (self->exc, cmd_reply); return false; } } _bulkwriteexception_append_writeconcernerror (self->exc, code, errmsg, &errInfo); } return true; } // `_bulkwritereturn_apply_result` applies an individual cursor result to the returned results. static bool _bulkwritereturn_apply_result (mongoc_bulkwritereturn_t *self, const bson_t *result, size_t ops_doc_offset, const mongoc_array_t *arrayof_modeldata, const mongoc_buffer_t *ops) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (result); BSON_ASSERT_PARAM (arrayof_modeldata); bson_error_t error; // Parse for `ok`. int64_t ok; if (!lookup_as_int64 (result, "ok", &ok, "result", self->exc)) { return false; } // Parse `idx`. int64_t idx; { if (!lookup_as_int64 (result, "idx", &idx, "result", self->exc)) { return false; } if (idx < 0) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected to find non-negative int64 `idx` in " "result, but did not"); _bulkwriteexception_set_error (self->exc, &error); return false; } } BSON_ASSERT (mcommon_in_range_size_t_signed (idx)); // `models_idx` is the index of the model that produced this result. size_t models_idx = (size_t) idx + ops_doc_offset; if (ok == 0) { if (!self->res->first_error_index.isset) { self->res->first_error_index.isset = true; self->res->first_error_index.index = idx; } bson_iter_t result_iter; // Parse `code`. int32_t code; if (!lookup_int32 (result, "code", &code, "result", self->exc)) { return false; } // Parse `errmsg`. const char *errmsg; if (!lookup_string (result, "errmsg", &errmsg, "result", self->exc)) { return false; } // Parse optional `errInfo`. bson_t errInfo = BSON_INITIALIZER; if (bson_iter_init_find (&result_iter, result, "errInfo")) { if (!_mongoc_iter_document_as_bson (&result_iter, &errInfo, &error)) { _bulkwriteexception_set_error (self->exc, &error); return false; } } // Store a copy of the write error. _bulkwriteexception_set_writeerror (self->exc, code, errmsg, &errInfo, models_idx); } else { // This is a successful result of an individual operation. // Server only reports successful results of individual // operations when verbose results are requested // (`errorsOnly: false` is sent). modeldata_t *md = &_mongoc_array_index (arrayof_modeldata, modeldata_t, models_idx); // Check if model is an update. switch (md->op) { case MODEL_OP_UPDATE: { bson_iter_t result_iter; // Parse `n`. int64_t n; if (!lookup_as_int64 (result, "n", &n, "result", self->exc)) { return false; } // Parse `nModified`. int64_t nModified; if (!lookup_as_int64 (result, "nModified", &nModified, "result", self->exc)) { return false; } // Check for an optional `upserted._id`. const bson_value_t *upserted_id = NULL; bson_iter_t id_iter; if (bson_iter_init_find (&result_iter, result, "upserted")) { BSON_ASSERT (bson_iter_init (&result_iter, result)); if (!bson_iter_find_descendant (&result_iter, "upserted._id", &id_iter)) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected `upserted` to be a document " "containing `_id`, but did not find `_id`"); _bulkwriteexception_set_error (self->exc, &error); return false; } upserted_id = bson_iter_value (&id_iter); } _bulkwriteresult_set_updateresult (self->res, n, nModified, upserted_id, models_idx); break; } case MODEL_OP_DELETE: { // Parse `n`. int64_t n; if (!lookup_as_int64 (result, "n", &n, "result", self->exc)) { return false; } _bulkwriteresult_set_deleteresult (self->res, n, models_idx); break; } case MODEL_OP_INSERT: { bson_iter_t id_iter; BSON_ASSERT (bson_iter_init_from_data_at_offset ( &id_iter, ops->data + md->id_loc.op_start, md->id_loc.op_len, md->id_loc.id_offset, strlen ("_id"))); _bulkwriteresult_set_insertresult (self->res, &id_iter, models_idx); break; } default: // Add an unreachable default case to silence `switch-default` warnings. BSON_UNREACHABLE ("unexpected default"); } } return true; } void mongoc_bulkwrite_set_client (mongoc_bulkwrite_t *self, mongoc_client_t *client) { BSON_ASSERT_PARAM (self); BSON_ASSERT_PARAM (client); if (self->session) { BSON_ASSERT (self->session->client == client); } /* NOP if the client is not changing; otherwise, assign it and increment and * fetch its operation_id. */ if (self->client == client) { return; } self->client = client; self->operation_id = ++client->cluster.operation_id; } void mongoc_bulkwrite_set_session (mongoc_bulkwrite_t *self, mongoc_client_session_t *session) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (session); if (self->client && session) { BSON_ASSERT (self->client == session->client); } self->session = session; } mongoc_bulkwritereturn_t mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t *opts) { BSON_ASSERT_PARAM (self); BSON_OPTIONAL_PARAM (opts); bool has_successful_results = false; mongoc_bulkwritereturn_t ret = {0}; bson_error_t error = {0}; mongoc_server_stream_t *ss = NULL; bson_t cmd = BSON_INITIALIZER; mongoc_cmd_parts_t parts = {{0}}; mongoc_bulkwriteopts_t defaults = {{0}}; if (!opts) { opts = &defaults; } bool is_ordered = mongoc_optional_is_set (&opts->ordered) ? mongoc_optional_value (&opts->ordered) : true; // default. bool is_acknowledged = false; // Create empty result and exception to collect results/errors from batches. ret.res = _bulkwriteresult_new (); ret.exc = _bulkwriteexception_new (); if (!self->client) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "bulk write requires a client and one has not been set"); _bulkwriteexception_set_error (ret.exc, &error); goto fail; } if (self->executed) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "bulk write already executed"); _bulkwriteexception_set_error (ret.exc, &error); goto fail; } self->executed = true; if (self->n_ops == 0) { bson_set_error ( &error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "cannot do `bulkWrite` with no models"); _bulkwriteexception_set_error (ret.exc, &error); goto fail; } if (_mongoc_cse_is_enabled (self->client)) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "bulkWrite does not currently support automatic encryption"); _bulkwriteexception_set_error (ret.exc, &error); goto fail; } const mongoc_ss_log_context_t ss_log_context = { .operation = "bulkWrite", .has_operation_id = true, .operation_id = self->operation_id}; // Select a stream. { bson_t reply; if (opts->serverid) { ss = mongoc_cluster_stream_for_server ( &self->client->cluster, opts->serverid, true /* reconnect_ok */, self->session, &reply, &error); } else { ss = mongoc_cluster_stream_for_writes ( &self->client->cluster, &ss_log_context, self->session, NULL /* deprioritized servers */, &reply, &error); } if (!ss) { _bulkwriteexception_set_error (ret.exc, &error); _bulkwriteexception_set_error_reply (ret.exc, &reply); bson_destroy (&reply); goto fail; } } bool verboseresults = mongoc_optional_is_set (&opts->verboseresults) ? mongoc_optional_value (&opts->verboseresults) : false; ret.res->verboseresults = verboseresults; int32_t maxBsonObjectSize = mongoc_server_stream_max_bson_obj_size (ss); // Create the payload 0. { BSON_ASSERT (BSON_APPEND_INT32 (&cmd, "bulkWrite", 1)); // errorsOnly is default true. Set to false if verboseResults requested. BSON_ASSERT (BSON_APPEND_BOOL (&cmd, "errorsOnly", !verboseresults)); // ordered is default true. BSON_ASSERT (BSON_APPEND_BOOL (&cmd, "ordered", is_ordered)); if (opts->comment.value_type != BSON_TYPE_EOD) { BSON_ASSERT (BSON_APPEND_VALUE (&cmd, "comment", &opts->comment)); } if (mongoc_optional_is_set (&opts->bypassdocumentvalidation)) { BSON_ASSERT (BSON_APPEND_BOOL ( &cmd, "bypassDocumentValidation", mongoc_optional_value (&opts->bypassdocumentvalidation))); } if (opts->let) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&cmd, "let", opts->let)); } // Add optional extra fields. if (opts->extra) { BSON_ASSERT (bson_concat (&cmd, opts->extra)); } mongoc_cmd_parts_init (&parts, self->client, "admin", MONGOC_QUERY_NONE, &cmd); parts.assembled.operation_id = self->operation_id; parts.allow_txn_number = MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_YES; // To append `lsid`. if (self->has_multi_write) { // Write commands that include multi-document operations are not // retryable. parts.allow_txn_number = MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_NO; } parts.is_write_command = true; // To append `txnNumber`. if (self->session) { mongoc_cmd_parts_set_session (&parts, self->session); } // Apply write concern: { const mongoc_write_concern_t *wc = self->client->write_concern; // Default to client. if (opts->writeconcern) { if (_mongoc_client_session_in_txn (self->session)) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set write concern after starting a transaction."); _bulkwriteexception_set_error (ret.exc, &error); goto fail; } wc = opts->writeconcern; } if (!mongoc_cmd_parts_set_write_concern (&parts, wc, &error)) { _bulkwriteexception_set_error (ret.exc, &error); goto fail; } if (!mongoc_write_concern_is_acknowledged (wc) && mcommon_cmp_greater_us (self->max_insert_len, maxBsonObjectSize)) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Unacknowledged `bulkWrite` includes insert of size: %" PRIu32 ", exceeding maxBsonObjectSize: %" PRId32, self->max_insert_len, maxBsonObjectSize); _bulkwriteexception_set_error (ret.exc, &error); goto fail; } is_acknowledged = mongoc_write_concern_is_acknowledged (wc); } if (verboseresults && !is_acknowledged) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot request unacknowledged write concern and verbose results."); _bulkwriteexception_set_error (ret.exc, &error); goto fail; } if (is_ordered && !is_acknowledged) { bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot request unacknowledged write concern and ordered writes."); _bulkwriteexception_set_error (ret.exc, &error); goto fail; } if (!mongoc_cmd_parts_assemble (&parts, ss, &error)) { _bulkwriteexception_set_error (ret.exc, &error); goto fail; } } int32_t maxWriteBatchSize = mongoc_server_stream_max_write_batch_size (ss); int32_t maxMessageSizeBytes = mongoc_server_stream_max_msg_size (ss); // `ops_doc_offset` is an offset into the `ops` document sequence. Counts the number of documents sent. size_t ops_doc_offset = 0; // `ops_byte_offset` is an offset into the `ops` document sequence. Counts the number of bytes sent. size_t ops_byte_offset = 0; // Calculate overhead of OP_MSG and the `bulkWrite` command. See bulk write specification for explanation. size_t opmsg_overhead = 0; { opmsg_overhead += 1000; // Add size of `bulkWrite` command. Exclude command-agnostic fields added in `mongoc_cmd_parts_assemble` (e.g. // `txnNumber` and `lsid`). opmsg_overhead += cmd.len; } // Send one or more `bulkWrite` commands. Split input payload if necessary to satisfy server size limits. while (true) { bool has_write_errors = false; bool batch_ok = false; bson_t cmd_reply = BSON_INITIALIZER; mongoc_cursor_t *reply_cursor = NULL; // `ops_byte_len` is the number of bytes from `ops` to send in this batch. size_t ops_byte_len = 0; // `ops_doc_len` is the number of documents from `ops` to send in this batch. size_t ops_doc_len = 0; if (ops_byte_offset == self->ops.len) { // All write models were sent. break; } // Track the nsInfo entries to include in this batch. mcd_nsinfo_t *nsinfo = mcd_nsinfo_new (); // Read as many documents from payload as possible. while (true) { if (ops_byte_offset + ops_byte_len >= self->ops.len) { // All remaining ops are readied. break; } if (ops_doc_len >= maxWriteBatchSize) { // Maximum number of operations are readied. break; } // Read length of next document. uint32_t doc_len; memcpy (&doc_len, self->ops.data + ops_byte_offset + ops_byte_len, 4); doc_len = BSON_UINT32_FROM_LE (doc_len); // Check if adding this operation requires adding an `nsInfo` entry. // `models_idx` is the index of the model that produced this result. size_t models_idx = ops_doc_len + ops_doc_offset; modeldata_t *md = &_mongoc_array_index (&self->arrayof_modeldata, modeldata_t, models_idx); uint32_t nsinfo_bson_size = 0; int32_t ns_index = mcd_nsinfo_find (nsinfo, md->ns); if (ns_index == -1) { // Need to append `nsInfo` entry. Append after checking that both the document and the `nsInfo` entry fit. nsinfo_bson_size = mcd_nsinfo_get_bson_size (md->ns); } if (opmsg_overhead + ops_byte_len + doc_len + nsinfo_bson_size > maxMessageSizeBytes) { if (ops_byte_len == 0) { // Could not even fit one document within an OP_MSG. bson_set_error (&error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "unable to send document at index %zu. Sending " "would exceed maxMessageSizeBytes=%" PRId32, ops_doc_len, maxMessageSizeBytes); _bulkwriteexception_set_error (ret.exc, &error); goto batch_fail; } break; } // Check if a new `nsInfo` entry is needed. if (ns_index == -1) { ns_index = mcd_nsinfo_append (nsinfo, md->ns, &error); if (ns_index == -1) { _bulkwriteexception_set_error (ret.exc, &error); goto batch_fail; } } // Overwrite the placeholder to the index of the `nsInfo` entry. { bson_iter_t nsinfo_iter; bson_t doc; BSON_ASSERT (bson_init_static (&doc, self->ops.data + ops_byte_offset + ops_byte_len, doc_len)); // Find the index. BSON_ASSERT (bson_iter_init (&nsinfo_iter, &doc)); BSON_ASSERT (bson_iter_next (&nsinfo_iter)); bson_iter_overwrite_int32 (&nsinfo_iter, ns_index); } // Include document. { ops_byte_len += doc_len; ops_doc_len += 1; } } // Send batch. { parts.assembled.payloads_count = 2; // Create the `nsInfo` payload. { mongoc_cmd_payload_t *payload = &parts.assembled.payloads[0]; const mongoc_buffer_t *nsinfo_docseq = mcd_nsinfo_as_document_sequence (nsinfo); payload->documents = nsinfo_docseq->data; BSON_ASSERT (mcommon_in_range_int32_t_unsigned (nsinfo_docseq->len)); payload->size = (int32_t) nsinfo_docseq->len; payload->identifier = "nsInfo"; } // Create the `ops` payload. { mongoc_cmd_payload_t *payload = &parts.assembled.payloads[1]; payload->identifier = "ops"; payload->documents = self->ops.data + ops_byte_offset; BSON_ASSERT (mcommon_in_range_int32_t_unsigned (ops_byte_len)); payload->size = (int32_t) ops_byte_len; } // Check if stream is valid. A previous call to `mongoc_cluster_run_retryable_write` may have invalidated // stream (e.g. due to processing an error). If invalid, select a new stream before processing more batches. if (!mongoc_cluster_stream_valid (&self->client->cluster, parts.assembled.server_stream)) { bson_t reply; // Select a server and create a stream again. mongoc_server_stream_cleanup (ss); ss = mongoc_cluster_stream_for_writes (&self->client->cluster, &ss_log_context, NULL /* session */, NULL /* deprioritized servers */, &reply, &error); if (ss) { parts.assembled.server_stream = ss; } else { _bulkwriteexception_set_error (ret.exc, &error); _bulkwriteexception_set_error_reply (ret.exc, &reply); bson_destroy (&reply); goto batch_fail; } } // Send command. { mongoc_server_stream_t *new_ss = NULL; bool ok = mongoc_cluster_run_retryable_write ( &self->client->cluster, &parts.assembled, parts.is_retryable_write, &new_ss, &cmd_reply, &error); if (new_ss) { // A retry occurred. Save the newly created stream to use for subsequent commands. mongoc_server_stream_cleanup (ss); ss = new_ss; parts.assembled.server_stream = ss; } // Check for a command ('ok': 0) error. if (!ok) { if (error.code != 0) { // The original error was a command ('ok': 0) error. _bulkwriteexception_set_error (ret.exc, &error); } _bulkwriteexception_set_error_reply (ret.exc, &cmd_reply); goto batch_fail; } } // Add to result and/or exception. if (is_acknowledged) { // Parse top-level fields. if (!_bulkwritereturn_apply_reply (&ret, &cmd_reply)) { goto batch_fail; } // Construct reply cursor and read individual results. { bson_t cursor_opts = BSON_INITIALIZER; { uint32_t serverid = parts.assembled.server_stream->sd->id; BSON_ASSERT (mcommon_in_range_int32_t_unsigned (serverid)); int32_t serverid_i32 = (int32_t) serverid; BSON_ASSERT (BSON_APPEND_INT32 (&cursor_opts, "serverId", serverid_i32)); // Use same session if one was applied. if (parts.assembled.session && !mongoc_client_session_append (parts.assembled.session, &cursor_opts, &error)) { _bulkwriteexception_set_error (ret.exc, &error); _bulkwriteexception_set_error_reply (ret.exc, &cmd_reply); goto batch_fail; } } // Construct the reply cursor. reply_cursor = mongoc_cursor_new_from_command_reply_with_opts (self->client, &cmd_reply, &cursor_opts); bson_destroy (&cursor_opts); // `cmd_reply` is stolen. Clear it. bson_init (&cmd_reply); // Ensure constructing cursor did not error. { const bson_t *error_document; if (mongoc_cursor_error_document (reply_cursor, &error, &error_document)) { _bulkwriteexception_set_error (ret.exc, &error); if (error_document) { _bulkwriteexception_set_error_reply (ret.exc, error_document); } goto batch_fail; } } // Iterate over cursor results. const bson_t *result; while (mongoc_cursor_next (reply_cursor, &result)) { if (!_bulkwritereturn_apply_result ( &ret, result, ops_doc_offset, &self->arrayof_modeldata, &self->ops)) { goto batch_fail; } } has_write_errors = !bson_empty (&ret.exc->write_errors); // Ensure iterating cursor did not error. { const bson_t *error_document; if (mongoc_cursor_error_document (reply_cursor, &error, &error_document)) { _bulkwriteexception_set_error (ret.exc, &error); if (error_document) { _bulkwriteexception_set_error_reply (ret.exc, error_document); } goto batch_fail; } } } } } ops_doc_offset += ops_doc_len; ops_byte_offset += ops_byte_len; batch_ok = true; batch_fail: mcd_nsinfo_destroy (nsinfo); mongoc_cursor_destroy (reply_cursor); bson_destroy (&cmd_reply); if (!batch_ok) { goto fail; } if (has_write_errors && is_ordered) { // Ordered writes must not continue to send batches once an error is // occurred. An individual write error is not a top-level error. break; } } fail: if (is_ordered) { // Ordered writes stop on first error. If the error reported is for an index > 0, assume some writes suceeded. if (ret.res->errorscount == 0 || (ret.res->first_error_index.isset && ret.res->first_error_index.index > 0)) { has_successful_results = true; } } else { BSON_ASSERT (mcommon_in_range_size_t_signed (ret.res->errorscount)); size_t errorscount_sz = (size_t) ret.res->errorscount; if (errorscount_sz < self->n_ops) { has_successful_results = true; } } if (!is_acknowledged || !has_successful_results) { mongoc_bulkwriteresult_destroy (ret.res); ret.res = NULL; } if (parts.body) { // Only clean-up if initialized. mongoc_cmd_parts_cleanup (&parts); } bson_destroy (&cmd); if (ret.res && ss) { // Set the returned server ID to the most recently selected server. ret.res->serverid = ss->sd->id; } mongoc_server_stream_cleanup (ss); if (!ret.exc->has_any_error) { mongoc_bulkwriteexception_destroy (ret.exc); ret.exc = NULL; } return ret; } MC_ENABLE_CONVERSION_WARNING_END mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-bulkwrite.h0000644000175100001660000003203314760300420023150 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_BULKWRITE_H #define MONGOC_BULKWRITE_H #include #include BSON_BEGIN_DECLS typedef struct _mongoc_bulkwriteopts_t mongoc_bulkwriteopts_t; MONGOC_EXPORT (mongoc_bulkwriteopts_t *) mongoc_bulkwriteopts_new (void); MONGOC_EXPORT (void) mongoc_bulkwriteopts_set_ordered (mongoc_bulkwriteopts_t *self, bool ordered); MONGOC_EXPORT (void) mongoc_bulkwriteopts_set_bypassdocumentvalidation (mongoc_bulkwriteopts_t *self, bool bypassdocumentvalidation); MONGOC_EXPORT (void) mongoc_bulkwriteopts_set_let (mongoc_bulkwriteopts_t *self, const bson_t *let); MONGOC_EXPORT (void) mongoc_bulkwriteopts_set_writeconcern (mongoc_bulkwriteopts_t *self, const mongoc_write_concern_t *writeconcern); MONGOC_EXPORT (void) mongoc_bulkwriteopts_set_comment (mongoc_bulkwriteopts_t *self, const bson_value_t *comment); MONGOC_EXPORT (void) mongoc_bulkwriteopts_set_verboseresults (mongoc_bulkwriteopts_t *self, bool verboseresults); // `mongoc_bulkwriteopts_set_extra` appends `extra` to bulkWrite command. // It is intended to support future server options. MONGOC_EXPORT (void) mongoc_bulkwriteopts_set_extra (mongoc_bulkwriteopts_t *self, const bson_t *extra); // `mongoc_bulkwriteopts_set_serverid` identifies which server to perform the operation. This is intended for use by // wrapping drivers that select a server before running the operation. MONGOC_EXPORT (void) mongoc_bulkwriteopts_set_serverid (mongoc_bulkwriteopts_t *self, uint32_t serverid); MONGOC_EXPORT (void) mongoc_bulkwriteopts_destroy (mongoc_bulkwriteopts_t *self); typedef struct _mongoc_bulkwriteresult_t mongoc_bulkwriteresult_t; MONGOC_EXPORT (int64_t) mongoc_bulkwriteresult_insertedcount (const mongoc_bulkwriteresult_t *self); MONGOC_EXPORT (int64_t) mongoc_bulkwriteresult_upsertedcount (const mongoc_bulkwriteresult_t *self); MONGOC_EXPORT (int64_t) mongoc_bulkwriteresult_matchedcount (const mongoc_bulkwriteresult_t *self); MONGOC_EXPORT (int64_t) mongoc_bulkwriteresult_modifiedcount (const mongoc_bulkwriteresult_t *self); MONGOC_EXPORT (int64_t) mongoc_bulkwriteresult_deletedcount (const mongoc_bulkwriteresult_t *self); // `mongoc_bulkwriteresult_insertresults` returns a BSON document mapping model indexes to insert results. // Example: // { // "0" : { "insertedId" : "foo" }, // "1" : { "insertedId" : "bar" } // } // Returns NULL if verbose results were not requested. MONGOC_EXPORT (const bson_t *) mongoc_bulkwriteresult_insertresults (const mongoc_bulkwriteresult_t *self); // `mongoc_bulkwriteresult_updateresults` returns a BSON document mapping model indexes to update results. // Example: // { // "0" : { "matchedCount" : 2, "modifiedCount" : 2 }, // "1" : { "matchedCount" : 1, "modifiedCount" : 0, "upsertedId" : "foo" } // } // Returns NULL if verbose results were not requested. MONGOC_EXPORT (const bson_t *) mongoc_bulkwriteresult_updateresults (const mongoc_bulkwriteresult_t *self); // `mongoc_bulkwriteresult_deleteresults` returns a BSON document mapping model indexes to delete results. // Example: // { // "0" : { "deletedCount" : 1 }, // "1" : { "deletedCount" : 2 } // } // Returns NULL if verbose results were not requested. MONGOC_EXPORT (const bson_t *) mongoc_bulkwriteresult_deleteresults (const mongoc_bulkwriteresult_t *self); // `mongoc_bulkwriteresult_serverid` identifies the most recently selected server. This may differ from a // previously set serverid if a retry occurred. This is intended for use by wrapping drivers that select a server before // running the operation. MONGOC_EXPORT (uint32_t) mongoc_bulkwriteresult_serverid (const mongoc_bulkwriteresult_t *self); MONGOC_EXPORT (void) mongoc_bulkwriteresult_destroy (mongoc_bulkwriteresult_t *self); typedef struct _mongoc_bulkwriteexception_t mongoc_bulkwriteexception_t; // Returns true if there was a top-level error. MONGOC_EXPORT (bool) mongoc_bulkwriteexception_error (const mongoc_bulkwriteexception_t *self, bson_error_t *error); // `mongoc_bulkwriteexception_writeerrors` returns a BSON document mapping model indexes to write errors. // Example: // { // "0" : { "code" : 123, "message" : "foo", "details" : { } }, // "1" : { "code" : 456, "message" : "bar", "details" : { } } // } // Returns an empty document if there are no write errors. MONGOC_EXPORT (const bson_t *) mongoc_bulkwriteexception_writeerrors (const mongoc_bulkwriteexception_t *self); // `mongoc_bulkwriteexception_writeconcernerrors` returns a BSON array of write concern errors. // Example: // [ // { "code" : 123, "message" : "foo", "details" : { } }, // { "code" : 456, "message" : "bar", "details" : { } } // ] // Returns an empty array if there are no write concern errors. MONGOC_EXPORT (const bson_t *) mongoc_bulkwriteexception_writeconcernerrors (const mongoc_bulkwriteexception_t *self); // `mongoc_bulkwriteexception_errorreply` returns a possible server reply related to the error, or an empty document. MONGOC_EXPORT (const bson_t *) mongoc_bulkwriteexception_errorreply (const mongoc_bulkwriteexception_t *self); MONGOC_EXPORT (void) mongoc_bulkwriteexception_destroy (mongoc_bulkwriteexception_t *self); typedef struct _mongoc_bulkwrite_t mongoc_bulkwrite_t; MONGOC_EXPORT (mongoc_bulkwrite_t *) mongoc_client_bulkwrite_new (mongoc_client_t *self); typedef struct _mongoc_bulkwrite_insertoneopts_t mongoc_bulkwrite_insertoneopts_t; MONGOC_EXPORT (mongoc_bulkwrite_insertoneopts_t *) mongoc_bulkwrite_insertoneopts_new (void); MONGOC_EXPORT (void) mongoc_bulkwrite_insertoneopts_destroy (mongoc_bulkwrite_insertoneopts_t *self); MONGOC_EXPORT (bool) mongoc_bulkwrite_append_insertone (mongoc_bulkwrite_t *self, const char *ns, const bson_t *document, const mongoc_bulkwrite_insertoneopts_t *opts /* May be NULL */, bson_error_t *error); typedef struct _mongoc_bulkwrite_updateoneopts_t mongoc_bulkwrite_updateoneopts_t; MONGOC_EXPORT (mongoc_bulkwrite_updateoneopts_t *) mongoc_bulkwrite_updateoneopts_new (void); MONGOC_EXPORT (void) mongoc_bulkwrite_updateoneopts_set_arrayfilters (mongoc_bulkwrite_updateoneopts_t *self, const bson_t *arrayfilters); MONGOC_EXPORT (void) mongoc_bulkwrite_updateoneopts_set_collation (mongoc_bulkwrite_updateoneopts_t *self, const bson_t *collation); MONGOC_EXPORT (void) mongoc_bulkwrite_updateoneopts_set_hint (mongoc_bulkwrite_updateoneopts_t *self, const bson_value_t *hint); MONGOC_EXPORT (void) mongoc_bulkwrite_updateoneopts_set_upsert (mongoc_bulkwrite_updateoneopts_t *self, bool upsert); MONGOC_EXPORT (void) mongoc_bulkwrite_updateoneopts_set_sort (mongoc_bulkwrite_updateoneopts_t *self, const bson_t *sort); MONGOC_EXPORT (void) mongoc_bulkwrite_updateoneopts_destroy (mongoc_bulkwrite_updateoneopts_t *self); MONGOC_EXPORT (bool) mongoc_bulkwrite_append_updateone (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const bson_t *update, const mongoc_bulkwrite_updateoneopts_t *opts /* May be NULL */, bson_error_t *error); typedef struct _mongoc_bulkwrite_updatemanyopts_t mongoc_bulkwrite_updatemanyopts_t; MONGOC_EXPORT (mongoc_bulkwrite_updatemanyopts_t *) mongoc_bulkwrite_updatemanyopts_new (void); MONGOC_EXPORT (void) mongoc_bulkwrite_updatemanyopts_set_arrayfilters (mongoc_bulkwrite_updatemanyopts_t *self, const bson_t *arrayfilters); MONGOC_EXPORT (void) mongoc_bulkwrite_updatemanyopts_set_collation (mongoc_bulkwrite_updatemanyopts_t *self, const bson_t *collation); MONGOC_EXPORT (void) mongoc_bulkwrite_updatemanyopts_set_hint (mongoc_bulkwrite_updatemanyopts_t *self, const bson_value_t *hint); MONGOC_EXPORT (void) mongoc_bulkwrite_updatemanyopts_set_upsert (mongoc_bulkwrite_updatemanyopts_t *self, bool upsert); MONGOC_EXPORT (void) mongoc_bulkwrite_updatemanyopts_destroy (mongoc_bulkwrite_updatemanyopts_t *self); MONGOC_EXPORT (bool) mongoc_bulkwrite_append_updatemany (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const bson_t *update, const mongoc_bulkwrite_updatemanyopts_t *opts /* May be NULL */, bson_error_t *error); typedef struct _mongoc_bulkwrite_replaceoneopts_t mongoc_bulkwrite_replaceoneopts_t; MONGOC_EXPORT (mongoc_bulkwrite_replaceoneopts_t *) mongoc_bulkwrite_replaceoneopts_new (void); MONGOC_EXPORT (void) mongoc_bulkwrite_replaceoneopts_set_collation (mongoc_bulkwrite_replaceoneopts_t *self, const bson_t *collation); MONGOC_EXPORT (void) mongoc_bulkwrite_replaceoneopts_set_hint (mongoc_bulkwrite_replaceoneopts_t *self, const bson_value_t *hint); MONGOC_EXPORT (void) mongoc_bulkwrite_replaceoneopts_set_upsert (mongoc_bulkwrite_replaceoneopts_t *self, bool upsert); MONGOC_EXPORT (void) mongoc_bulkwrite_replaceoneopts_set_sort (mongoc_bulkwrite_replaceoneopts_t *self, const bson_t *sort); MONGOC_EXPORT (void) mongoc_bulkwrite_replaceoneopts_destroy (mongoc_bulkwrite_replaceoneopts_t *self); MONGOC_EXPORT (bool) mongoc_bulkwrite_append_replaceone (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const bson_t *replacement, const mongoc_bulkwrite_replaceoneopts_t *opts /* May be NULL */, bson_error_t *error); typedef struct _mongoc_bulkwrite_deleteoneopts_t mongoc_bulkwrite_deleteoneopts_t; MONGOC_EXPORT (mongoc_bulkwrite_deleteoneopts_t *) mongoc_bulkwrite_deleteoneopts_new (void); MONGOC_EXPORT (void) mongoc_bulkwrite_deleteoneopts_set_collation (mongoc_bulkwrite_deleteoneopts_t *self, const bson_t *collation); MONGOC_EXPORT (void) mongoc_bulkwrite_deleteoneopts_set_hint (mongoc_bulkwrite_deleteoneopts_t *self, const bson_value_t *hint); MONGOC_EXPORT (void) mongoc_bulkwrite_deleteoneopts_destroy (mongoc_bulkwrite_deleteoneopts_t *self); MONGOC_EXPORT (bool) mongoc_bulkwrite_append_deleteone (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const mongoc_bulkwrite_deleteoneopts_t *opts /* May be NULL */, bson_error_t *error); typedef struct _mongoc_bulkwrite_deletemanyopts_t mongoc_bulkwrite_deletemanyopts_t; MONGOC_EXPORT (mongoc_bulkwrite_deletemanyopts_t *) mongoc_bulkwrite_deletemanyopts_new (void); MONGOC_EXPORT (void) mongoc_bulkwrite_deletemanyopts_set_collation (mongoc_bulkwrite_deletemanyopts_t *self, const bson_t *collation); MONGOC_EXPORT (void) mongoc_bulkwrite_deletemanyopts_set_hint (mongoc_bulkwrite_deletemanyopts_t *self, const bson_value_t *hint); MONGOC_EXPORT (void) mongoc_bulkwrite_deletemanyopts_destroy (mongoc_bulkwrite_deletemanyopts_t *self); MONGOC_EXPORT (bool) mongoc_bulkwrite_append_deletemany (mongoc_bulkwrite_t *self, const char *ns, const bson_t *filter, const mongoc_bulkwrite_deletemanyopts_t *opts /* May be NULL */, bson_error_t *error); // `mongoc_bulkwritereturn_t` may outlive `mongoc_bulkwrite_t`. typedef struct { mongoc_bulkwriteresult_t *res; // NULL if no known successful writes or write was unacknowledged. mongoc_bulkwriteexception_t *exc; // NULL if no error. } mongoc_bulkwritereturn_t; // `mongoc_bulkwrite_new` and `mongoc_bulkwrite_set_client` may be used by // language bindings that want to assemble a `mongoc_bulkwrite_t` and defer // `mongoc_client_t` assignment to execution time. MONGOC_EXPORT (mongoc_bulkwrite_t *) mongoc_bulkwrite_new (void); MONGOC_EXPORT (void) mongoc_bulkwrite_set_client (mongoc_bulkwrite_t *self, mongoc_client_t *client); // `mongoc_bulkwrite_set_session` sets an optional explicit session. // `*session` may be modified when `mongoc_bulkwrite_execute` is called. MONGOC_EXPORT (void) mongoc_bulkwrite_set_session (mongoc_bulkwrite_t *self, mongoc_client_session_t *session); // `mongoc_bulkwrite_execute` executes a bulk write operation. MONGOC_EXPORT (mongoc_bulkwritereturn_t) mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t *opts); MONGOC_EXPORT (void) mongoc_bulkwrite_destroy (mongoc_bulkwrite_t *self); BSON_END_DECLS #endif // MONGOC_BULKWRITE_H mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-change-stream-private.h0000644000175100001660000000470714760300420025335 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CHANGE_STREAM_PRIVATE_H #define MONGOC_CHANGE_STREAM_PRIVATE_H #include #include #include #include #include #include typedef enum { MONGOC_CHANGE_STREAM_COLLECTION, MONGOC_CHANGE_STREAM_DATABASE, MONGOC_CHANGE_STREAM_CLIENT } mongoc_change_stream_type_t; struct _mongoc_change_stream_t { mongoc_change_stream_opts_t opts; mongoc_timestamp_t operation_time; bson_t pipeline_to_append; bson_t resume_token; bson_t *full_document; bson_t *full_document_before_change; bool show_expanded_events; bson_error_t err; bson_t err_doc; mongoc_cursor_t *cursor; mongoc_client_t *client; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_change_stream_type_t change_stream_type; char *db; char *coll; int64_t max_await_time_ms; int32_t batch_size; bool has_returned_results; /* Track whether the change stream has resumed after an error, as this * determines how we construct an initial or resuming aggregate command. */ bool resumed; mongoc_client_session_t *implicit_session; /* The max_wire_version of the server the change stream is tied to. */ uint32_t max_wire_version; }; mongoc_change_stream_t * _mongoc_change_stream_new_from_collection (const mongoc_collection_t *coll, const bson_t *pipeline, const bson_t *opts); mongoc_change_stream_t * _mongoc_change_stream_new_from_database (const mongoc_database_t *db, const bson_t *pipeline, const bson_t *opts); mongoc_change_stream_t * _mongoc_change_stream_new_from_client (mongoc_client_t *client, const bson_t *pipeline, const bson_t *opts); #endif /* MONGOC_CHANGE_STREAM_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-change-stream.c0000644000175100001660000005402314760300420023654 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #define CHANGE_STREAM_ERR(_str) \ bson_set_error (&stream->err, MONGOC_ERROR_CURSOR, MONGOC_ERROR_BSON, "Could not set " _str) /* the caller knows either a client or server error has occurred. * `reply` contains the server reply or an empty document. */ static bool _is_resumable_error (mongoc_change_stream_t *stream, const bson_t *reply) { bson_error_t error = {0}; /* Change Streams Spec resumable criteria: "any error encountered which is * not a server error (e.g. a timeout error or network error)" */ if (bson_empty (reply)) { return true; } if (_mongoc_cmd_check_ok (reply, MONGOC_ERROR_API_VERSION_2, &error)) { return true; } if (error.code == MONGOC_SERVER_ERR_CURSOR_NOT_FOUND) { return true; } if (stream->max_wire_version >= WIRE_VERSION_4_4) { return mongoc_error_has_label (reply, "ResumableChangeStreamError"); } switch (error.code) { case MONGOC_SERVER_ERR_HOSTUNREACHABLE: case MONGOC_SERVER_ERR_HOSTNOTFOUND: case MONGOC_SERVER_ERR_NETWORKTIMEOUT: case MONGOC_SERVER_ERR_SHUTDOWNINPROGRESS: case MONGOC_SERVER_ERR_PRIMARYSTEPPEDDOWN: case MONGOC_SERVER_ERR_EXCEEDEDTIMELIMIT: case MONGOC_SERVER_ERR_SOCKETEXCEPTION: case MONGOC_SERVER_ERR_NOTPRIMARY: case MONGOC_SERVER_ERR_INTERRUPTEDATSHUTDOWN: case MONGOC_SERVER_ERR_INTERRUPTEDDUETOREPLSTATECHANGE: case MONGOC_SERVER_ERR_NOTPRIMARYNOSECONDARYOK: case MONGOC_SERVER_ERR_NOTPRIMARYORSECONDARY: case MONGOC_SERVER_ERR_STALESHARDVERSION: case MONGOC_SERVER_ERR_STALEEPOCH: case MONGOC_SERVER_ERR_STALECONFIG: case MONGOC_SERVER_ERR_RETRYCHANGESTREAM: case MONGOC_SERVER_ERR_FAILEDTOSATISFYREADPREFERENCE: return true; default: return false; } } static void _set_resume_token (mongoc_change_stream_t *stream, const bson_t *resume_token) { BSON_ASSERT (stream); BSON_ASSERT (resume_token); bson_destroy (&stream->resume_token); bson_copy_to (resume_token, &stream->resume_token); } /* construct the aggregate command in cmd. looks like one of the following: * for a collection change stream: * { aggregate: collname, pipeline: [], cursor: { batchSize: x } } * for a database change stream: * { aggregate: 1, pipeline: [], cursor: { batchSize: x } } * for a client change stream: * { aggregate: 1, pipeline: [{$changeStream: {allChangesForCluster: true}}], * cursor: { batchSize: x } } */ static void _make_command (mongoc_change_stream_t *stream, bson_t *command) { bson_iter_t iter; bson_t change_stream_stage; /* { $changeStream: } */ bson_t change_stream_doc; bson_array_builder_t *pipeline; bson_t cursor_doc; if (stream->change_stream_type == MONGOC_CHANGE_STREAM_COLLECTION) { bson_append_utf8 (command, "aggregate", 9, stream->coll, (int) strlen (stream->coll)); } else { bson_append_int32 (command, "aggregate", 9, 1); } bson_append_array_builder_begin (command, "pipeline", 8, &pipeline); /* append the $changeStream stage. */ bson_array_builder_append_document_begin (pipeline, &change_stream_stage); bson_append_document_begin (&change_stream_stage, "$changeStream", 13, &change_stream_doc); if (stream->full_document) { bson_concat (&change_stream_doc, stream->full_document); } if (stream->full_document_before_change) { bson_concat (&change_stream_doc, stream->full_document_before_change); } if (stream->show_expanded_events) { BSON_APPEND_BOOL (&change_stream_doc, "showExpandedEvents", stream->show_expanded_events); } if (stream->resumed) { /* Change stream spec: Resume Process */ /* If there is a cached resumeToken: */ if (!bson_empty (&stream->resume_token)) { /* If the ChangeStream was started with startAfter and has yet to return a result document: */ if (!bson_empty (&stream->opts.startAfter) && !stream->has_returned_results) { /* The driver MUST set startAfter to the cached resumeToken */ BSON_APPEND_DOCUMENT (&change_stream_doc, "startAfter", &stream->resume_token); } else { /* The driver MUST set resumeAfter to the cached resumeToken */ BSON_APPEND_DOCUMENT (&change_stream_doc, "resumeAfter", &stream->resume_token); } } else if (!_mongoc_timestamp_empty (&stream->operation_time) && stream->max_wire_version >= WIRE_VERSION_4_0) { /* Else if there is no cached resumeToken and the ChangeStream has a saved operation time and the max wire version is >= 7, the driver MUST set startAtOperationTime */ _mongoc_timestamp_append (&stream->operation_time, &change_stream_doc, "startAtOperationTime"); } } else { /* Change streams spec: "startAtOperationTime, resumeAfter, and startAfter * are all mutually exclusive; if any two are set, the server will return * an error. Drivers MUST NOT throw a custom error, and MUST defer to the * server error." */ if (!bson_empty (&stream->opts.resumeAfter)) { BSON_APPEND_DOCUMENT (&change_stream_doc, "resumeAfter", &stream->opts.resumeAfter); /* Update the cached resume token */ _set_resume_token (stream, &stream->opts.resumeAfter); } if (!bson_empty (&stream->opts.startAfter)) { BSON_APPEND_DOCUMENT (&change_stream_doc, "startAfter", &stream->opts.startAfter); /* Update the cached resume token (take precedence over resumeAfter) */ _set_resume_token (stream, &stream->opts.startAfter); } if (!_mongoc_timestamp_empty (&stream->operation_time)) { _mongoc_timestamp_append (&stream->operation_time, &change_stream_doc, "startAtOperationTime"); } } if (stream->change_stream_type == MONGOC_CHANGE_STREAM_CLIENT) { bson_append_bool (&change_stream_doc, "allChangesForCluster", 20, true); } bson_append_document_end (&change_stream_stage, &change_stream_doc); bson_array_builder_append_document_end (pipeline, &change_stream_stage); /* Append user pipeline if it exists */ if (bson_iter_init_find (&iter, &stream->pipeline_to_append, "pipeline") && BSON_ITER_HOLDS_ARRAY (&iter)) { bson_iter_t child_iter; BSON_ASSERT (bson_iter_recurse (&iter, &child_iter)); while (bson_iter_next (&child_iter)) { /* the user pipeline may consist of invalid stages or non-documents. * append anyway, and rely on the server error. */ bson_array_builder_append_value (pipeline, bson_iter_value (&child_iter)); } } bson_append_array_builder_end (command, pipeline); /* Add batch size if needed */ bson_append_document_begin (command, "cursor", 6, &cursor_doc); if (stream->batch_size > 0) { bson_append_int32 (&cursor_doc, "batchSize", 9, stream->batch_size); } bson_append_document_end (command, &cursor_doc); } /*--------------------------------------------------------------------------- * * _make_cursor -- * * Construct and send the aggregate command and create the resulting * cursor. On error, stream->cursor remains NULL, otherwise it is * created and must be destroyed. * * Return: * False on error and sets stream->err. * *-------------------------------------------------------------------------- */ static bool _make_cursor (mongoc_change_stream_t *stream) { mongoc_client_session_t *cs = NULL; bson_t command_opts; bson_t command; /* { aggregate: "coll", pipeline: [], ... } */ bson_t reply; bson_t getmore_opts = BSON_INITIALIZER; bson_iter_t iter; mongoc_server_stream_t *server_stream; BSON_ASSERT (stream); BSON_ASSERT (!stream->cursor); bson_init (&command); bson_copy_to (&(stream->opts.extra), &command_opts); if (stream->opts.comment.value_type != BSON_TYPE_EOD) { bson_append_value (&command_opts, "comment", 7, &stream->opts.comment); bson_append_value (&getmore_opts, "comment", 7, &stream->opts.comment); } if (bson_iter_init_find (&iter, &command_opts, "sessionId")) { if (!_mongoc_client_session_from_iter (stream->client, &iter, &cs, &stream->err)) { goto cleanup; } } else if (stream->implicit_session) { /* If an implicit session was created before, and this cursor is now * being recreated after resuming, then use the same session as before. */ cs = stream->implicit_session; if (!mongoc_client_session_append (cs, &command_opts, &stream->err)) { goto cleanup; } } else { /* Create an implicit session. This session lsid must be the same for the * agg command and the subsequent getMores. Thus, this implicit session is * passed as if it were an explicit session to * mongoc_client_read_command_with_opts and * _mongoc_cursor_change_stream_new, but it is still implicit and its * lifetime is owned by this change_stream_t. */ mongoc_session_opt_t *session_opts; session_opts = mongoc_session_opts_new (); mongoc_session_opts_set_causal_consistency (session_opts, false); /* returns NULL if sessions aren't supported. ignore errors. */ cs = mongoc_client_start_session (stream->client, session_opts, NULL); stream->implicit_session = cs; mongoc_session_opts_destroy (session_opts); if (cs && !mongoc_client_session_append (cs, &command_opts, &stream->err)) { goto cleanup; } } if (cs && !mongoc_client_session_append (cs, &getmore_opts, &stream->err)) { goto cleanup; } const mongoc_ss_log_context_t ss_log_context = {.operation = "aggregate"}; server_stream = mongoc_cluster_stream_for_reads ( &stream->client->cluster, &ss_log_context, stream->read_prefs, cs, NULL, &reply, &stream->err); if (!server_stream) { bson_destroy (&stream->err_doc); bson_copy_to (&reply, &stream->err_doc); bson_destroy (&reply); goto cleanup; } bson_append_int32 (&command_opts, "serverId", 8, server_stream->sd->id); bson_append_int32 (&getmore_opts, "serverId", 8, server_stream->sd->id); stream->max_wire_version = server_stream->sd->max_wire_version; mongoc_server_stream_cleanup (server_stream); if (stream->read_concern && !bson_has_field (&command_opts, "readConcern")) { mongoc_read_concern_append (stream->read_concern, &command_opts); } _make_command (stream, &command); /* even though serverId has already been set, still pass the read prefs. * they are necessary for OP_MSG if sending to a secondary. */ if (!mongoc_client_read_command_with_opts ( stream->client, stream->db, &command, stream->read_prefs, &command_opts, &reply, &stream->err)) { bson_destroy (&stream->err_doc); bson_copy_to (&reply, &stream->err_doc); bson_destroy (&reply); goto cleanup; } bson_append_bool (&getmore_opts, MONGOC_CURSOR_TAILABLE, MONGOC_CURSOR_TAILABLE_LEN, true); bson_append_bool (&getmore_opts, MONGOC_CURSOR_AWAIT_DATA, MONGOC_CURSOR_AWAIT_DATA_LEN, true); /* maxTimeMS is only appended to getMores if these are set in cursor opts. */ if (stream->max_await_time_ms > 0) { bson_append_int64 (&getmore_opts, MONGOC_CURSOR_MAX_AWAIT_TIME_MS, MONGOC_CURSOR_MAX_AWAIT_TIME_MS_LEN, stream->max_await_time_ms); } if (stream->batch_size > 0) { bson_append_int32 (&getmore_opts, MONGOC_CURSOR_BATCH_SIZE, MONGOC_CURSOR_BATCH_SIZE_LEN, stream->batch_size); } /* steals reply. */ stream->cursor = _mongoc_cursor_change_stream_new (stream->client, &reply, &getmore_opts); if (mongoc_cursor_error (stream->cursor, NULL)) { goto cleanup; } /* Change stream spec: "When aggregate or getMore returns: If an empty batch * was returned and a postBatchResumeToken was included, cache it." */ if (_mongoc_cursor_change_stream_end_of_batch (stream->cursor) && _mongoc_cursor_change_stream_has_post_batch_resume_token (stream->cursor)) { _set_resume_token (stream, _mongoc_cursor_change_stream_get_post_batch_resume_token (stream->cursor)); } /* Change stream spec: startAtOperationTime */ if (bson_empty (&stream->opts.resumeAfter) && bson_empty (&stream->opts.startAfter) && _mongoc_timestamp_empty (&stream->operation_time) && stream->max_wire_version >= WIRE_VERSION_4_0 && bson_empty (&stream->resume_token) && bson_iter_init_find (&iter, _mongoc_cursor_change_stream_get_reply (stream->cursor), "operationTime") && BSON_ITER_HOLDS_TIMESTAMP (&iter)) { _mongoc_timestamp_set_from_bson (&stream->operation_time, &iter); } cleanup: bson_destroy (&command); bson_destroy (&command_opts); bson_destroy (&getmore_opts); return stream->err.code == 0; } /*--------------------------------------------------------------------------- * * _change_stream_init -- * * Called after @stream has the collection name, database name, read * preferences, and read concern set. Creates the change streams * cursor. * *-------------------------------------------------------------------------- */ void _change_stream_init (mongoc_change_stream_t *stream, const bson_t *pipeline, const bson_t *opts) { BSON_ASSERT (pipeline); stream->max_await_time_ms = -1; stream->batch_size = -1; bson_init (&stream->pipeline_to_append); bson_init (&stream->resume_token); bson_init (&stream->err_doc); if (!_mongoc_change_stream_opts_parse (stream->client, opts, &stream->opts, &stream->err)) { return; } if (stream->opts.fullDocument) { stream->full_document = BCON_NEW ("fullDocument", stream->opts.fullDocument); } if (stream->opts.fullDocumentBeforeChange) { stream->full_document_before_change = BCON_NEW ("fullDocumentBeforeChange", stream->opts.fullDocumentBeforeChange); } _mongoc_timestamp_set (&stream->operation_time, &stream->opts.startAtOperationTime); stream->batch_size = stream->opts.batchSize; stream->max_await_time_ms = stream->opts.maxAwaitTimeMS; stream->show_expanded_events = stream->opts.showExpandedEvents; /* Accept two forms of user pipeline: * 1. A document like: { "pipeline": [...] } * 2. An array-like document: { "0": {}, "1": {}, ... } * If the passed pipeline is invalid, we pass it along and let the server * error instead. */ if (!bson_empty (pipeline)) { bson_iter_t iter; if (bson_iter_init_find (&iter, pipeline, "pipeline") && BSON_ITER_HOLDS_ARRAY (&iter)) { if (!BSON_APPEND_VALUE (&stream->pipeline_to_append, "pipeline", bson_iter_value (&iter))) { CHANGE_STREAM_ERR ("pipeline"); } } else { if (!BSON_APPEND_ARRAY (&stream->pipeline_to_append, "pipeline", pipeline)) { CHANGE_STREAM_ERR ("pipeline"); } } } if (stream->err.code == 0) { (void) _make_cursor (stream); } } mongoc_change_stream_t * _mongoc_change_stream_new_from_collection (const mongoc_collection_t *coll, const bson_t *pipeline, const bson_t *opts) { mongoc_change_stream_t *stream; BSON_ASSERT (coll); stream = BSON_ALIGNED_ALLOC0 (mongoc_change_stream_t); stream->db = bson_strdup (coll->db); stream->coll = bson_strdup (coll->collection); stream->read_prefs = mongoc_read_prefs_copy (coll->read_prefs); stream->read_concern = mongoc_read_concern_copy (coll->read_concern); stream->client = coll->client; stream->change_stream_type = MONGOC_CHANGE_STREAM_COLLECTION; _change_stream_init (stream, pipeline, opts); return stream; } mongoc_change_stream_t * _mongoc_change_stream_new_from_database (const mongoc_database_t *db, const bson_t *pipeline, const bson_t *opts) { mongoc_change_stream_t *stream; BSON_ASSERT (db); stream = BSON_ALIGNED_ALLOC0 (mongoc_change_stream_t); stream->db = bson_strdup (db->name); stream->coll = NULL; stream->read_prefs = mongoc_read_prefs_copy (db->read_prefs); stream->read_concern = mongoc_read_concern_copy (db->read_concern); stream->client = db->client; stream->change_stream_type = MONGOC_CHANGE_STREAM_DATABASE; _change_stream_init (stream, pipeline, opts); return stream; } mongoc_change_stream_t * _mongoc_change_stream_new_from_client (mongoc_client_t *client, const bson_t *pipeline, const bson_t *opts) { mongoc_change_stream_t *stream; BSON_ASSERT (client); stream = BSON_ALIGNED_ALLOC0 (mongoc_change_stream_t); stream->db = bson_strdup ("admin"); stream->coll = NULL; stream->read_prefs = mongoc_read_prefs_copy (client->read_prefs); stream->read_concern = mongoc_read_concern_copy (client->read_concern); stream->client = client; stream->change_stream_type = MONGOC_CHANGE_STREAM_CLIENT; _change_stream_init (stream, pipeline, opts); return stream; } const bson_t * mongoc_change_stream_get_resume_token (mongoc_change_stream_t *stream) { if (!bson_empty (&stream->resume_token)) { return &stream->resume_token; } return NULL; } bool mongoc_change_stream_next (mongoc_change_stream_t *stream, const bson_t **bson) { bson_iter_t iter; bson_t doc_resume_token; uint32_t len; const uint8_t *data; bool ret = false; BSON_ASSERT (stream); BSON_ASSERT (bson); if (stream->err.code != 0) { goto end; } BSON_ASSERT (stream->cursor); if (!mongoc_cursor_next (stream->cursor, bson)) { const bson_t *err_doc; bson_error_t err; bool resumable = false; if (!mongoc_cursor_error_document (stream->cursor, &err, &err_doc)) { /* no error occurred, just no documents left. */ goto end; } resumable = _is_resumable_error (stream, err_doc); while (resumable) { /* recreate the cursor. */ mongoc_cursor_destroy (stream->cursor); stream->cursor = NULL; stream->resumed = true; if (!_make_cursor (stream)) { goto end; } if (mongoc_cursor_next (stream->cursor, bson)) { break; } if (!mongoc_cursor_error_document (stream->cursor, &err, &err_doc)) { goto end; } if (err_doc) { resumable = _is_resumable_error (stream, err_doc); } else { resumable = false; } } if (!resumable) { stream->err = err; bson_destroy (&stream->err_doc); bson_copy_to (err_doc, &stream->err_doc); goto end; } } /* we have received documents, either from the first call to next or after a * resume. */ stream->has_returned_results = true; if (!bson_iter_init_find (&iter, *bson, "_id") || !BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_set_error (&stream->err, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CHANGE_STREAM_NO_RESUME_TOKEN, "Cannot provide resume functionality when the resume " "token is missing"); goto end; } /* copy the resume token. */ bson_iter_document (&iter, &len, &data); BSON_ASSERT (bson_init_static (&doc_resume_token, data, len)); _set_resume_token (stream, &doc_resume_token); /* clear out the operation time, since we no longer need it to resume. */ _mongoc_timestamp_clear (&stream->operation_time); ret = true; end: /* Change stream spec: Updating the Cached Resume Token */ if (stream->cursor && !mongoc_cursor_error (stream->cursor, NULL) && _mongoc_cursor_change_stream_end_of_batch (stream->cursor) && _mongoc_cursor_change_stream_has_post_batch_resume_token (stream->cursor)) { _set_resume_token (stream, _mongoc_cursor_change_stream_get_post_batch_resume_token (stream->cursor)); } /* Driver Sessions Spec: "When an implicit session is associated with a * cursor for use with getMore operations, the session MUST be returned to * the pool immediately following a getMore operation that indicates that the * cursor has been exhausted." */ if (stream->implicit_session) { /* if creating the change stream cursor errored, it may be null. */ if (!stream->cursor || stream->cursor->cursor_id == 0) { mongoc_client_session_destroy (stream->implicit_session); stream->implicit_session = NULL; } } return ret; } bool mongoc_change_stream_error_document (const mongoc_change_stream_t *stream, bson_error_t *err, const bson_t **bson) { BSON_ASSERT (stream); if (stream->err.code != 0) { if (err) { *err = stream->err; } if (bson) { *bson = &stream->err_doc; } return true; } if (bson) { *bson = NULL; } return false; } void mongoc_change_stream_destroy (mongoc_change_stream_t *stream) { if (!stream) { return; } bson_destroy (&stream->pipeline_to_append); bson_destroy (&stream->resume_token); bson_destroy (stream->full_document); bson_destroy (stream->full_document_before_change); bson_destroy (&stream->err_doc); _mongoc_change_stream_opts_cleanup (&stream->opts); mongoc_cursor_destroy (stream->cursor); mongoc_client_session_destroy (stream->implicit_session); mongoc_read_prefs_destroy (stream->read_prefs); mongoc_read_concern_destroy (stream->read_concern); bson_free (stream->db); bson_free (stream->coll); bson_free (stream); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-change-stream.h0000644000175100001660000000241314760300420023655 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CHANGE_STREAM_H #define MONGOC_CHANGE_STREAM_H #include #include BSON_BEGIN_DECLS typedef struct _mongoc_change_stream_t mongoc_change_stream_t; MONGOC_EXPORT (void) mongoc_change_stream_destroy (mongoc_change_stream_t *); MONGOC_EXPORT (const bson_t *) mongoc_change_stream_get_resume_token (mongoc_change_stream_t *); MONGOC_EXPORT (bool) mongoc_change_stream_next (mongoc_change_stream_t *, const bson_t **); MONGOC_EXPORT (bool) mongoc_change_stream_error_document (const mongoc_change_stream_t *, bson_error_t *, const bson_t **); BSON_END_DECLS #endif /* MONGOC_CHANGE_STREAM_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-pool-private.h0000644000175100001660000000242714760300420025041 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLIENT_POOL_PRIVATE_H #define MONGOC_CLIENT_POOL_PRIVATE_H #include #include #include #include BSON_BEGIN_DECLS /* for tests */ void _mongoc_client_pool_set_stream_initiator (mongoc_client_pool_t *pool, mongoc_stream_initiator_t si, void *user_data); size_t mongoc_client_pool_get_size (mongoc_client_pool_t *pool); size_t mongoc_client_pool_num_pushed (mongoc_client_pool_t *pool); mongoc_topology_t * _mongoc_client_pool_get_topology (mongoc_client_pool_t *pool); BSON_END_DECLS #endif /* MONGOC_CLIENT_POOL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-pool.c0000644000175100001660000004737214760300420023374 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #endif #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L #include #endif struct _mongoc_client_pool_t { bson_mutex_t mutex; mongoc_cond_t cond; mongoc_queue_t queue; mongoc_topology_t *topology; mongoc_uri_t *uri; uint32_t min_pool_size; uint32_t max_pool_size; uint32_t size; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t ssl_opts; bool ssl_opts_set; #endif bool apm_callbacks_set; bool error_api_set; bool structured_log_opts_set; bool client_initialized; int32_t error_api_version; mongoc_server_api_t *api; // `last_known_serverids` is a sorted array of uint32_t. mongoc_array_t last_known_serverids; }; #ifdef MONGOC_ENABLE_SSL void mongoc_client_pool_set_ssl_opts (mongoc_client_pool_t *pool, const mongoc_ssl_opt_t *opts) { BSON_ASSERT_PARAM (pool); bson_mutex_lock (&pool->mutex); _mongoc_ssl_opts_cleanup (&pool->ssl_opts, false /* don't free internal opts. */); pool->ssl_opts_set = false; if (opts) { _mongoc_ssl_opts_copy_to (opts, &pool->ssl_opts, false /* don't overwrite internal opts. */); pool->ssl_opts_set = true; /* Update the OpenSSL context associated with this client pool to match new ssl opts. */ /* All future clients popped from pool inherit this OpenSSL context. */ #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L SSL_CTX_free (pool->topology->scanner->openssl_ctx); pool->topology->scanner->openssl_ctx = _mongoc_openssl_ctx_new (&pool->ssl_opts); #endif } mongoc_topology_scanner_set_ssl_opts (pool->topology->scanner, &pool->ssl_opts); bson_mutex_unlock (&pool->mutex); } void _mongoc_client_pool_set_internal_tls_opts (mongoc_client_pool_t *pool, _mongoc_internal_tls_opts_t *internal) { BSON_ASSERT_PARAM (pool); bson_mutex_lock (&pool->mutex); if (!pool->ssl_opts_set) { bson_mutex_unlock (&pool->mutex); return; } pool->ssl_opts.internal = bson_malloc (sizeof (_mongoc_internal_tls_opts_t)); memcpy (pool->ssl_opts.internal, internal, sizeof (_mongoc_internal_tls_opts_t)); bson_mutex_unlock (&pool->mutex); } #endif mongoc_client_pool_t * mongoc_client_pool_new (const mongoc_uri_t *uri) { mongoc_client_pool_t *pool; bson_error_t error = {0}; if (!(pool = mongoc_client_pool_new_with_error (uri, &error))) { MONGOC_ERROR ("%s", error.message); } return pool; } mongoc_client_pool_t * mongoc_client_pool_new_with_error (const mongoc_uri_t *uri, bson_error_t *error) { mongoc_topology_t *topology; mongoc_client_pool_t *pool; const bson_t *b; bson_iter_t iter; const char *appname; ENTRY; BSON_ASSERT (uri); #ifndef MONGOC_ENABLE_SSL if (mongoc_uri_get_tls (uri)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Can't create SSL client pool, SSL not enabled in this " "build."); return NULL; } #endif topology = mongoc_topology_new (uri, false); if (!topology->valid) { if (error) { memcpy (error, &topology->scanner->error, sizeof (bson_error_t)); } mongoc_topology_destroy (topology); RETURN (NULL); } pool = (mongoc_client_pool_t *) bson_malloc0 (sizeof *pool); _mongoc_array_init (&pool->last_known_serverids, sizeof (uint32_t)); bson_mutex_init (&pool->mutex); mongoc_cond_init (&pool->cond); _mongoc_queue_init (&pool->queue); pool->uri = mongoc_uri_copy (uri); pool->min_pool_size = 0; pool->max_pool_size = 100; pool->size = 0; pool->topology = topology; pool->error_api_version = MONGOC_ERROR_API_VERSION_LEGACY; b = mongoc_uri_get_options (pool->uri); if (bson_iter_init_find_case (&iter, b, MONGOC_URI_MINPOOLSIZE)) { MONGOC_WARNING (MONGOC_URI_MINPOOLSIZE " is deprecated; its behavior does not match its name, and its actual" " behavior will likely hurt performance."); if (BSON_ITER_HOLDS_INT32 (&iter)) { pool->min_pool_size = BSON_MAX (0, bson_iter_int32 (&iter)); } } if (bson_iter_init_find_case (&iter, b, MONGOC_URI_MAXPOOLSIZE)) { if (BSON_ITER_HOLDS_INT32 (&iter)) { pool->max_pool_size = BSON_MAX (1, bson_iter_int32 (&iter)); } } appname = mongoc_uri_get_option_as_utf8 (pool->uri, MONGOC_URI_APPNAME, NULL); if (appname) { /* the appname should have already been validated */ BSON_ASSERT (mongoc_client_pool_set_appname (pool, appname)); } #ifdef MONGOC_ENABLE_SSL if (mongoc_uri_get_tls (pool->uri)) { mongoc_ssl_opt_t ssl_opt = {0}; _mongoc_internal_tls_opts_t internal_tls_opts = {0}; _mongoc_ssl_opts_from_uri (&ssl_opt, &internal_tls_opts, pool->uri); /* sets use_ssl = true */ mongoc_client_pool_set_ssl_opts (pool, &ssl_opt); _mongoc_client_pool_set_internal_tls_opts (pool, &internal_tls_opts); } #endif mongoc_counter_client_pools_active_inc (); RETURN (pool); } void mongoc_client_pool_destroy (mongoc_client_pool_t *pool) { mongoc_client_t *client; ENTRY; if (!pool) { EXIT; } if (!mongoc_server_session_pool_is_empty (pool->topology->session_pool)) { client = mongoc_client_pool_pop (pool); _mongoc_client_end_sessions (client); mongoc_client_pool_push (pool, client); } while ((client = (mongoc_client_t *) _mongoc_queue_pop_head (&pool->queue))) { mongoc_client_destroy (client); } mongoc_topology_destroy (pool->topology); mongoc_uri_destroy (pool->uri); bson_mutex_destroy (&pool->mutex); mongoc_cond_destroy (&pool->cond); mongoc_server_api_destroy (pool->api); #ifdef MONGOC_ENABLE_SSL _mongoc_ssl_opts_cleanup (&pool->ssl_opts, true); #endif _mongoc_array_destroy (&pool->last_known_serverids); bson_free (pool); mongoc_counter_client_pools_active_dec (); mongoc_counter_client_pools_disposed_inc (); EXIT; } /* * Start the background topology scanner. * * This function assumes the pool's mutex is locked */ static void _start_scanner_if_needed (mongoc_client_pool_t *pool) { BSON_ASSERT_PARAM (pool); if (!pool->topology->single_threaded) { _mongoc_topology_background_monitoring_start (pool->topology); } } static void _initialize_new_client (mongoc_client_pool_t *pool, mongoc_client_t *client) { BSON_ASSERT_PARAM (pool); BSON_ASSERT_PARAM (client); /* for tests */ mongoc_client_set_stream_initiator ( client, pool->topology->scanner->initiator, pool->topology->scanner->initiator_context); pool->client_initialized = true; client->error_api_version = pool->error_api_version; client->api = mongoc_server_api_copy (pool->api); #ifdef MONGOC_ENABLE_SSL if (pool->ssl_opts_set) { mongoc_client_set_ssl_opts (client, &pool->ssl_opts); } #endif } mongoc_client_t * mongoc_client_pool_pop (mongoc_client_pool_t *pool) { mongoc_client_t *client; int32_t wait_queue_timeout_ms; int64_t expire_at_ms = -1; int64_t now_ms; int r; ENTRY; BSON_ASSERT_PARAM (pool); wait_queue_timeout_ms = mongoc_uri_get_option_as_int32 (pool->uri, MONGOC_URI_WAITQUEUETIMEOUTMS, -1); if (wait_queue_timeout_ms > 0) { expire_at_ms = (bson_get_monotonic_time () / 1000) + wait_queue_timeout_ms; } bson_mutex_lock (&pool->mutex); again: if (!(client = (mongoc_client_t *) _mongoc_queue_pop_head (&pool->queue))) { if (pool->size < pool->max_pool_size) { client = _mongoc_client_new_from_topology (pool->topology); BSON_ASSERT (client); _initialize_new_client (pool, client); pool->size++; } else { if (wait_queue_timeout_ms > 0) { now_ms = bson_get_monotonic_time () / 1000; if (now_ms < expire_at_ms) { r = mongoc_cond_timedwait (&pool->cond, &pool->mutex, expire_at_ms - now_ms); if (mongo_cond_ret_is_timedout (r)) { GOTO (done); } } else { GOTO (done); } } else { mongoc_cond_wait (&pool->cond, &pool->mutex); } GOTO (again); } } _start_scanner_if_needed (pool); done: bson_mutex_unlock (&pool->mutex); RETURN (client); } mongoc_client_t * mongoc_client_pool_try_pop (mongoc_client_pool_t *pool) { mongoc_client_t *client; ENTRY; BSON_ASSERT_PARAM (pool); bson_mutex_lock (&pool->mutex); if (!(client = (mongoc_client_t *) _mongoc_queue_pop_head (&pool->queue))) { if (pool->size < pool->max_pool_size) { client = _mongoc_client_new_from_topology (pool->topology); BSON_ASSERT (client); _initialize_new_client (pool, client); pool->size++; } } if (client) { _start_scanner_if_needed (pool); } bson_mutex_unlock (&pool->mutex); RETURN (client); } typedef struct { mongoc_array_t *known_server_ids; mongoc_cluster_t *cluster; } prune_ctx; static int server_id_cmp (const void *a_, const void *b_) { const uint32_t *const a = (const uint32_t *) a_; const uint32_t *const b = (const uint32_t *) b_; if (*a == *b) { return 0; } return *a < *b ? -1 : 1; } // `maybe_prune` removes a `mongoc_cluster_node_t` if the node refers to a removed server. static bool maybe_prune (void *item, void *ctx_) { mongoc_cluster_node_t *cn = (mongoc_cluster_node_t *) item; prune_ctx *ctx = (prune_ctx *) ctx_; // Get the server ID from the cluster node. uint32_t server_id = cn->handshake_sd->id; // Check if the cluster node's server ID references a removed server. if (!bsearch ( &server_id, ctx->known_server_ids->data, ctx->known_server_ids->len, sizeof (uint32_t), server_id_cmp)) { mongoc_cluster_disconnect_node (ctx->cluster, server_id); } return true; } // `prune_client` closes connections from `client` to servers not contained in `known_server_ids`. static void prune_client (mongoc_client_t *client, mongoc_array_t *known_server_ids) { BSON_ASSERT_PARAM (client); BSON_ASSERT_PARAM (known_server_ids); mongoc_cluster_t *cluster = &client->cluster; prune_ctx ctx = {.cluster = cluster, .known_server_ids = known_server_ids}; mongoc_set_for_each (cluster->nodes, maybe_prune, &ctx); } void mongoc_client_pool_push (mongoc_client_pool_t *pool, mongoc_client_t *client) { ENTRY; BSON_ASSERT_PARAM (pool); BSON_ASSERT_PARAM (client); /* reset sockettimeoutms to the default in case it was changed with mongoc_client_set_sockettimeoutms() */ mongoc_cluster_reset_sockettimeoutms (&client->cluster); bson_mutex_lock (&pool->mutex); // Check if `last_known_server_ids` needs update. bool serverids_have_changed = false; { mongoc_array_t current_serverids; _mongoc_array_init (¤t_serverids, sizeof (uint32_t)); { mc_shared_tpld td = mc_tpld_take_ref (pool->topology); const mongoc_set_t *servers = mc_tpld_servers_const (td.ptr); for (size_t i = 0; i < servers->items_len; i++) { _mongoc_array_append_val (¤t_serverids, servers->items[i].id); } mc_tpld_drop_ref (&td); } serverids_have_changed = (current_serverids.len != pool->last_known_serverids.len) || memcmp (current_serverids.data, pool->last_known_serverids.data, current_serverids.len * current_serverids.element_size) != 0; if (serverids_have_changed) { _mongoc_array_destroy (&pool->last_known_serverids); pool->last_known_serverids = current_serverids; // Ownership transfer. } else { _mongoc_array_destroy (¤t_serverids); } } // Check if pooled clients need to be pruned. if (serverids_have_changed) { // The set of last known server IDs has changed. Prune all clients in pool. mongoc_queue_item_t *ptr = pool->queue.head; while (ptr != NULL) { prune_client ((mongoc_client_t *) ptr->data, &pool->last_known_serverids); ptr = ptr->next; } } // Always prune incoming client. The topology may have changed while client was checked out. prune_client (client, &pool->last_known_serverids); // Push client back into pool. _mongoc_queue_push_head (&pool->queue, client); if (pool->min_pool_size && _mongoc_queue_get_length (&pool->queue) > pool->min_pool_size) { mongoc_client_t *old_client; old_client = (mongoc_client_t *) _mongoc_queue_pop_tail (&pool->queue); if (old_client) { mongoc_client_destroy (old_client); pool->size--; } } mongoc_cond_signal (&pool->cond); bson_mutex_unlock (&pool->mutex); EXIT; } /* for tests */ void _mongoc_client_pool_set_stream_initiator (mongoc_client_pool_t *pool, mongoc_stream_initiator_t si, void *context) { BSON_ASSERT_PARAM (pool); mongoc_topology_scanner_set_stream_initiator (pool->topology->scanner, si, context); } /* for tests */ size_t mongoc_client_pool_get_size (mongoc_client_pool_t *pool) { size_t size = 0; ENTRY; BSON_ASSERT_PARAM (pool); bson_mutex_lock (&pool->mutex); size = pool->size; bson_mutex_unlock (&pool->mutex); RETURN (size); } size_t mongoc_client_pool_num_pushed (mongoc_client_pool_t *pool) { size_t num_pushed = 0; ENTRY; BSON_ASSERT_PARAM (pool); bson_mutex_lock (&pool->mutex); num_pushed = pool->queue.length; bson_mutex_unlock (&pool->mutex); RETURN (num_pushed); } mongoc_topology_t * _mongoc_client_pool_get_topology (mongoc_client_pool_t *pool) { BSON_ASSERT_PARAM (pool); return pool->topology; } void mongoc_client_pool_max_size (mongoc_client_pool_t *pool, uint32_t max_pool_size) { ENTRY; BSON_ASSERT_PARAM (pool); bson_mutex_lock (&pool->mutex); pool->max_pool_size = max_pool_size; bson_mutex_unlock (&pool->mutex); EXIT; } void mongoc_client_pool_min_size (mongoc_client_pool_t *pool, uint32_t min_pool_size) { ENTRY; BSON_ASSERT_PARAM (pool); MONGOC_WARNING ("mongoc_client_pool_min_size is deprecated; its behavior does not match" " its name, and its actual behavior will likely hurt performance."); bson_mutex_lock (&pool->mutex); pool->min_pool_size = min_pool_size; bson_mutex_unlock (&pool->mutex); EXIT; } bool mongoc_client_pool_set_apm_callbacks (mongoc_client_pool_t *pool, mongoc_apm_callbacks_t *callbacks, void *context) { BSON_ASSERT_PARAM (pool); BSON_OPTIONAL_PARAM (callbacks); BSON_OPTIONAL_PARAM (context); // Enforce documented thread-safety restrictions if (pool->apm_callbacks_set) { MONGOC_ERROR ("mongoc_client_pool_set_apm_callbacks can only be called once per pool"); return false; } else if (pool->client_initialized) { MONGOC_ERROR ("mongoc_client_pool_set_apm_callbacks can only be called before mongoc_client_pool_pop"); /* @todo Since 2017 this requirement has been documented but not actually enforced. For now we are leaving it * unenforced, for backward compatibility. This usage remains unsafe and incorrect. When possible, this should be * modified to return false without modifying the APM callbacks. */ mongoc_log_and_monitor_instance_set_apm_callbacks (&pool->topology->log_and_monitor, callbacks, context); pool->apm_callbacks_set = true; return true; } else { // Now we can be sure no other threads are relying on concurrent access to the instance yet. mongoc_log_and_monitor_instance_set_apm_callbacks (&pool->topology->log_and_monitor, callbacks, context); pool->apm_callbacks_set = true; return true; } } bool mongoc_client_pool_set_structured_log_opts (mongoc_client_pool_t *pool, const mongoc_structured_log_opts_t *opts) { BSON_ASSERT_PARAM (pool); BSON_OPTIONAL_PARAM (opts); /* The documented restriction for most pool options: They can be set at most once, * and only before the first client is initialized. Structured logging is generally * expected to warn but not quit when encountering initialization errors. */ if (pool->structured_log_opts_set) { MONGOC_ERROR ("mongoc_client_pool_set_structured_log_opts can only be called once per pool"); return false; } else if (pool->client_initialized) { MONGOC_ERROR ("mongoc_client_pool_set_structured_log_opts can only be called before mongoc_client_pool_pop"); return false; } else { // Now we can be sure no other threads are relying on concurrent access to the instance yet. mongoc_log_and_monitor_instance_set_structured_log_opts (&pool->topology->log_and_monitor, opts); pool->structured_log_opts_set = true; return true; } } bool mongoc_client_pool_set_error_api (mongoc_client_pool_t *pool, int32_t version) { if (version != MONGOC_ERROR_API_VERSION_LEGACY && version != MONGOC_ERROR_API_VERSION_2) { MONGOC_ERROR ("Unsupported Error API Version: %" PRId32, version); return false; } BSON_ASSERT_PARAM (pool); if (pool->error_api_set) { MONGOC_ERROR ("Can only set Error API Version once"); return false; } pool->error_api_version = version; pool->error_api_set = true; return true; } bool mongoc_client_pool_set_appname (mongoc_client_pool_t *pool, const char *appname) { bool ret; BSON_ASSERT_PARAM (pool); bson_mutex_lock (&pool->mutex); ret = _mongoc_topology_set_appname (pool->topology, appname); bson_mutex_unlock (&pool->mutex); return ret; } bool mongoc_client_pool_enable_auto_encryption (mongoc_client_pool_t *pool, mongoc_auto_encryption_opts_t *opts, bson_error_t *error) { BSON_ASSERT_PARAM (pool); return _mongoc_cse_client_pool_enable_auto_encryption (pool->topology, opts, error); } bool mongoc_client_pool_set_server_api (mongoc_client_pool_t *pool, const mongoc_server_api_t *api, bson_error_t *error) { BSON_ASSERT_PARAM (pool); BSON_ASSERT_PARAM (api); if (pool->api) { bson_set_error ( error, MONGOC_ERROR_POOL, MONGOC_ERROR_POOL_API_ALREADY_SET, "Cannot set server api more than once per pool"); return false; } if (pool->client_initialized) { bson_set_error (error, MONGOC_ERROR_POOL, MONGOC_ERROR_POOL_API_TOO_LATE, "Cannot set server api after a client has been created"); return false; } pool->api = mongoc_server_api_copy (api); _mongoc_topology_scanner_set_server_api (pool->topology->scanner, api); return true; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-pool.h0000644000175100001660000000573114760300420023372 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLIENT_POOL_H #define MONGOC_CLIENT_POOL_H #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #endif #include #include BSON_BEGIN_DECLS typedef struct _mongoc_client_pool_t mongoc_client_pool_t; MONGOC_EXPORT (mongoc_client_pool_t *) mongoc_client_pool_new (const mongoc_uri_t *uri) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_client_pool_t *) mongoc_client_pool_new_with_error (const mongoc_uri_t *uri, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_pool_destroy (mongoc_client_pool_t *pool); MONGOC_EXPORT (mongoc_client_t *) mongoc_client_pool_pop (mongoc_client_pool_t *pool) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_pool_push (mongoc_client_pool_t *pool, mongoc_client_t *client); MONGOC_EXPORT (mongoc_client_t *) mongoc_client_pool_try_pop (mongoc_client_pool_t *pool) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_pool_max_size (mongoc_client_pool_t *pool, uint32_t max_pool_size); MONGOC_EXPORT (void) mongoc_client_pool_min_size (mongoc_client_pool_t *pool, uint32_t min_pool_size) BSON_GNUC_DEPRECATED; #ifdef MONGOC_ENABLE_SSL MONGOC_EXPORT (void) mongoc_client_pool_set_ssl_opts (mongoc_client_pool_t *pool, const mongoc_ssl_opt_t *opts); #endif MONGOC_EXPORT (bool) mongoc_client_pool_set_apm_callbacks (mongoc_client_pool_t *pool, mongoc_apm_callbacks_t *callbacks, void *context); MONGOC_EXPORT (bool) mongoc_client_pool_set_error_api (mongoc_client_pool_t *pool, int32_t version); MONGOC_EXPORT (bool) mongoc_client_pool_set_appname (mongoc_client_pool_t *pool, const char *appname); MONGOC_EXPORT (bool) mongoc_client_pool_enable_auto_encryption (mongoc_client_pool_t *pool, mongoc_auto_encryption_opts_t *opts, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_pool_set_server_api (mongoc_client_pool_t *pool, const mongoc_server_api_t *api, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_pool_set_structured_log_opts (mongoc_client_pool_t *pool, const mongoc_structured_log_opts_t *opts); BSON_END_DECLS #endif /* MONGOC_CLIENT_POOL_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-private.h0000644000175100001660000002025714760300420024073 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLIENT_PRIVATE_H #define MONGOC_CLIENT_PRIVATE_H #include #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #endif #include #include #include #include BSON_BEGIN_DECLS /* version corresponding to server 4.0 release */ #define WIRE_VERSION_4_0 7 /* first version to support hint for "update" command */ #define WIRE_VERSION_UPDATE_HINT 8 /* version corresponding to server 4.2 release */ #define WIRE_VERSION_4_2 8 /* version corresponding to client side field level encryption support. */ #define WIRE_VERSION_CSE 8 /* first version to throw server-side errors for unsupported hint in * "findAndModify" command */ #define WIRE_VERSION_FIND_AND_MODIFY_HINT_SERVER_SIDE_ERROR 8 /* first version to support hint for "delete" command */ #define WIRE_VERSION_DELETE_HINT 9 /* first version to support hint for "findAndModify" command */ #define WIRE_VERSION_FIND_AND_MODIFY_HINT 9 /* version corresponding to server 4.4 release */ #define WIRE_VERSION_4_4 9 /* version corresponding to retryable writes error label */ #define WIRE_VERSION_RETRYABLE_WRITE_ERROR_LABEL 9 /* first version to support server hedged reads */ #define WIRE_VERSION_HEDGED_READS 9 /* first version to support estimatedDocumentCount with collStats */ #define WIRE_VERSION_4_9 12 /* version corresponding to server 5.0 release */ #define WIRE_VERSION_5_0 13 /* first version to support snapshot reads */ #define WIRE_VERSION_SNAPSHOT_READS 13 /* version corresponding to server 5.1 release */ #define WIRE_VERSION_5_1 14 /* version corresponding to server 6.0 release */ #define WIRE_VERSION_6_0 17 /* version corresponding to server 7.0 release */ #define WIRE_VERSION_7_0 21 /* version corresponding to server 7.1 release */ #define WIRE_VERSION_7_1 22 #define WIRE_VERSION_MONGOS_EXHAUST 22 /* version corresponding to server 8.0 release */ #define WIRE_VERSION_8_0 25 /* Range of wire protocol versions this driver supports. Bumping * WIRE_VERSION_MAX must be accompanied by an update to * `_mongoc_wire_version_to_server_version`. */ #define WIRE_VERSION_MIN WIRE_VERSION_4_0 /* a.k.a. minWireVersion */ #define WIRE_VERSION_MAX WIRE_VERSION_8_0 /* a.k.a. maxWireVersion */ struct _mongoc_collection_t; struct _mongoc_client_t { mongoc_uri_t *uri; mongoc_cluster_t cluster; bool in_exhaust; mongoc_stream_initiator_t initiator; void *initiator_data; #ifdef MONGOC_ENABLE_SSL bool use_ssl; mongoc_ssl_opt_t ssl_opts; #endif mongoc_topology_t *topology; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; int32_t error_api_version; bool error_api_set; mongoc_server_api_t *api; /* mongoc_client_session_t's in use, to look up lsids and clusterTimes */ mongoc_set_t *client_sessions; unsigned int csid_rand_seed; uint32_t generation; }; /* Defines whether _mongoc_client_command_with_opts() is acting as a read * command helper for a command like "distinct", or a write command helper for * a command like "createRole", or both, like "aggregate" with "$out". */ typedef enum { MONGOC_CMD_RAW = 0, MONGOC_CMD_READ = 1, MONGOC_CMD_WRITE = 2, MONGOC_CMD_RW = 3, } mongoc_command_mode_t; BSON_STATIC_ASSERT2 (mongoc_cmd_rw, MONGOC_CMD_RW == (MONGOC_CMD_READ | MONGOC_CMD_WRITE)); /* TODO (CDRIVER-4052): Move MONGOC_RR_DEFAULT_BUFFER_SIZE and * _mongoc_client_get_rr to mongoc-topology-private.h or in a separate file. * There is no reason these should be in mongoc-client. */ #define MONGOC_RR_DEFAULT_BUFFER_SIZE 1024 bool _mongoc_client_get_rr (const char *hostname, mongoc_rr_type_t rr_type, mongoc_rr_data_t *rr_data, size_t initial_buffer_size, bool prefer_tcp, bson_error_t *error); mongoc_client_t * _mongoc_client_new_from_topology (mongoc_topology_t *topology); mongoc_stream_t * mongoc_client_default_stream_initiator (const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *user_data, bson_error_t *error); mongoc_stream_t * _mongoc_client_create_stream (mongoc_client_t *client, const mongoc_host_list_t *host, bson_error_t *error); bool _mongoc_client_recv (mongoc_client_t *client, mcd_rpc_message *rpc, mongoc_buffer_t *buffer, mongoc_server_stream_t *server_stream, bson_error_t *error); void _mongoc_client_kill_cursor (mongoc_client_t *client, uint32_t server_id, int64_t cursor_id, int64_t operation_id, const char *db, const char *collection, mongoc_client_session_t *cs); bool _mongoc_client_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, mongoc_command_mode_t mode, const bson_t *opts, mongoc_query_flags_t flags, const mongoc_read_prefs_t *user_prefs, const mongoc_read_prefs_t *default_prefs, mongoc_read_concern_t *default_rc, mongoc_write_concern_t *default_wc, bson_t *reply, bson_error_t *error); mongoc_server_session_t * _mongoc_client_pop_server_session (mongoc_client_t *client, const mongoc_ss_log_context_t *log_context, bson_error_t *error); bool _mongoc_client_lookup_session (const mongoc_client_t *client, uint32_t client_session_id, mongoc_client_session_t **cs, bson_error_t *error); void _mongoc_client_unregister_session (mongoc_client_t *client, mongoc_client_session_t *session); void _mongoc_client_push_server_session (mongoc_client_t *client, mongoc_server_session_t *server_session); void _mongoc_client_end_sessions (mongoc_client_t *client); mongoc_stream_t * mongoc_client_connect_tcp (int32_t connecttimeoutms, const mongoc_host_list_t *host, bson_error_t *error); mongoc_stream_t * mongoc_client_connect (bool buffered, bool use_ssl, void *ssl_opts_void, const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *openssl_ctx_void, bson_error_t *error); /* Returns true if a versioned server API has been selected, otherwise returns * false. */ bool mongoc_client_uses_server_api (const mongoc_client_t *client); /* Returns true if load balancing mode has been selected, otherwise returns * false. */ bool mongoc_client_uses_loadbalanced (const mongoc_client_t *client); BSON_END_DECLS #endif /* MONGOC_CLIENT_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-session-private.h0000644000175100001660000001161014760300420025545 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLIENT_SESSION_PRIVATE_H #define MONGOC_CLIENT_SESSION_PRIVATE_H #include #include /* error labels: see Transactions Spec */ #define TRANSIENT_TXN_ERR "TransientTransactionError" #define UNKNOWN_COMMIT_RESULT "UnknownTransactionCommitResult" #define MAX_TIME_MS_EXPIRED "MaxTimeMSExpired" #define DEFAULT_MAX_COMMIT_TIME_MS 0 #define SESSION_NEVER_USED (-1) #define MONGOC_DEFAULT_WTIMEOUT_FOR_COMMIT_RETRY 10000 struct _mongoc_transaction_opt_t { mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; mongoc_read_prefs_t *read_prefs; int64_t max_commit_time_ms; }; struct _mongoc_session_opt_t { mongoc_optional_t causal_consistency; mongoc_optional_t snapshot; mongoc_transaction_opt_t default_txn_opts; }; typedef struct _mongoc_server_session_t { int64_t last_used_usec; bson_t lsid; /* logical session id */ int64_t txn_number; /* transaction number */ bool dirty; } mongoc_server_session_t; typedef enum { MONGOC_INTERNAL_TRANSACTION_NONE, MONGOC_INTERNAL_TRANSACTION_STARTING, MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS, MONGOC_INTERNAL_TRANSACTION_ENDING, MONGOC_INTERNAL_TRANSACTION_COMMITTED, MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY, MONGOC_INTERNAL_TRANSACTION_ABORTED, } mongoc_internal_transaction_state_t; typedef struct _mongoc_transaction_t { mongoc_internal_transaction_state_t state; mongoc_transaction_opt_t opts; } mongoc_transaction_t; struct _mongoc_client_session_t { mongoc_client_t *client; mongoc_session_opt_t opts; mongoc_server_session_t *server_session; mongoc_transaction_t txn; uint32_t client_session_id; bson_t cluster_time; uint32_t operation_timestamp; uint32_t operation_increment; uint32_t client_generation; uint32_t server_id; bson_t *recovery_token; uint32_t snapshot_time_timestamp; uint32_t snapshot_time_increment; bool snapshot_time_set; /* For testing only */ int64_t with_txn_timeout_ms; const char *fail_commit_label; }; bool _mongoc_parse_cluster_time (const bson_t *cluster_time, uint32_t *timestamp, uint32_t *increment); bool _mongoc_cluster_time_greater (const bson_t *new, const bson_t *old); void _mongoc_client_session_handle_reply (mongoc_client_session_t *session, bool is_acknowledged, const char *cmd_name, const bson_t *reply); bool _mongoc_server_session_init (mongoc_server_session_t *session, bson_error_t *error); void _mongoc_server_session_destroy (mongoc_server_session_t *session); bool _mongoc_server_session_timed_out (const mongoc_server_session_t *server_session, int64_t session_timeout_minutes); mongoc_client_session_t * _mongoc_client_session_new (mongoc_client_t *client, mongoc_server_session_t *server_session, const mongoc_session_opt_t *opts, uint32_t client_session_id); bool _mongoc_client_session_from_iter (mongoc_client_t *client, const bson_iter_t *iter, mongoc_client_session_t **cs, bson_error_t *error); bool _mongoc_client_session_in_txn (const mongoc_client_session_t *session); bool _mongoc_client_session_in_txn_or_ending (const mongoc_client_session_t *session); bool _mongoc_client_session_txn_in_progress (const mongoc_client_session_t *session); bool _mongoc_client_session_append_txn (mongoc_client_session_t *session, bson_t *cmd, bson_error_t *error); void _mongoc_client_session_append_read_concern (const mongoc_client_session_t *cs, const bson_t *user_read_concern, bool is_read_command, bson_t *cmd); void _mongoc_client_session_unpin (mongoc_client_session_t *session); void _mongoc_client_session_pin (mongoc_client_session_t *session, uint32_t server_id); void _mongoc_client_session_set_snapshot_time (mongoc_client_session_t *session, uint32_t t, uint32_t i); void _mongoc_client_session_clear_snapshot_time (mongoc_client_session_t *session); #endif /* MONGOC_CLIENT_SESSION_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-session.c0000644000175100001660000014414214760300420024077 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #define WITH_TXN_TIMEOUT_MS (120 * 1000) static void txn_opts_set (mongoc_transaction_opt_t *opts, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern, const mongoc_read_prefs_t *read_prefs, int64_t max_commit_time_ms) { if (read_concern) { mongoc_transaction_opts_set_read_concern (opts, read_concern); } if (write_concern) { mongoc_transaction_opts_set_write_concern (opts, write_concern); } if (read_prefs) { mongoc_transaction_opts_set_read_prefs (opts, read_prefs); } if (max_commit_time_ms != DEFAULT_MAX_COMMIT_TIME_MS) { mongoc_transaction_opts_set_max_commit_time_ms (opts, max_commit_time_ms); } } static void txn_opts_cleanup (mongoc_transaction_opt_t *opts) { /* null inputs are ok */ mongoc_read_concern_destroy (opts->read_concern); mongoc_write_concern_destroy (opts->write_concern); mongoc_read_prefs_destroy (opts->read_prefs); /* prepare opts for reuse */ opts->read_concern = NULL; opts->write_concern = NULL; opts->read_prefs = NULL; opts->max_commit_time_ms = DEFAULT_MAX_COMMIT_TIME_MS; } static void txn_opts_copy (const mongoc_transaction_opt_t *src, mongoc_transaction_opt_t *dst) { txn_opts_cleanup (dst); /* null inputs are ok for these copy functions */ dst->read_concern = mongoc_read_concern_copy (src->read_concern); dst->write_concern = mongoc_write_concern_copy (src->write_concern); dst->read_prefs = mongoc_read_prefs_copy (src->read_prefs); dst->max_commit_time_ms = src->max_commit_time_ms; } static bool txn_abort (mongoc_client_session_t *session, bson_t *reply, bson_error_t *error) { bson_t cmd = BSON_INITIALIZER; bson_t opts = BSON_INITIALIZER; bson_error_t err_local; bson_error_t *err_ptr = error ? error : &err_local; bson_t reply_local = BSON_INITIALIZER; bool r = false; _mongoc_bson_init_if_set (reply); if (!mongoc_client_session_append (session, &opts, err_ptr)) { GOTO (done); } if (session->txn.opts.write_concern) { if (!mongoc_write_concern_append (session->txn.opts.write_concern, &opts)) { bson_set_error (err_ptr, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Invalid transaction write concern"); GOTO (done); } } BSON_APPEND_INT32 (&cmd, "abortTransaction", 1); if (session->recovery_token) { BSON_APPEND_DOCUMENT (&cmd, "recoveryToken", session->recovery_token); } /* will be reinitialized by mongoc_client_write_command_with_opts */ bson_destroy (&reply_local); r = mongoc_client_write_command_with_opts (session->client, "admin", &cmd, &opts, &reply_local, err_ptr); /* Transactions Spec: "Drivers MUST retry the commitTransaction command once * after it fails with a retryable error", same for abort. Note that a * RetryableWriteError label has already been appended here. */ if (mongoc_error_has_label (&reply_local, RETRYABLE_WRITE_ERROR)) { _mongoc_client_session_unpin (session); bson_destroy (&reply_local); r = mongoc_client_write_command_with_opts (session->client, "admin", &cmd, &opts, &reply_local, err_ptr); } if (!r) { /* we won't return an error from abortTransaction, so warn */ MONGOC_WARNING ("Error in abortTransaction: %s", err_ptr->message); _mongoc_client_session_unpin (session); } done: bson_destroy (&reply_local); bson_destroy (&cmd); bson_destroy (&opts); return r; } static mongoc_write_concern_t * create_commit_retry_wc (const mongoc_write_concern_t *existing_wc) { mongoc_write_concern_t *wc; wc = existing_wc ? mongoc_write_concern_copy (existing_wc) : mongoc_write_concern_new (); /* Transactions spec: "If the modified write concern does not include a * wtimeout value, drivers MUST also apply wtimeout: 10000 to the write * concern in order to avoid waiting forever if the majority write concern * cannot be satisfied." */ if (mongoc_write_concern_get_wtimeout_int64 (wc) <= 0) { mongoc_write_concern_set_wtimeout_int64 (wc, MONGOC_DEFAULT_WTIMEOUT_FOR_COMMIT_RETRY); } /* Transactions spec: "If the transaction is using a write concern that is * not the server default, any other write concern options MUST be left as-is * when applying w:majority. */ mongoc_write_concern_set_w (wc, MONGOC_WRITE_CONCERN_W_MAJORITY); return wc; } static bool txn_commit (mongoc_client_session_t *session, bool explicitly_retrying, bson_t *reply, bson_error_t *error) { bson_t cmd = BSON_INITIALIZER; bson_t opts = BSON_INITIALIZER; bson_error_t err_local = {0}; bson_error_t *err_ptr = error ? error : &err_local; bson_t reply_local = BSON_INITIALIZER; mongoc_write_err_type_t error_type; bool r = false; bool retrying_after_error = false; mongoc_write_concern_t *retry_wc = NULL; _mongoc_bson_init_if_set (reply); BSON_APPEND_INT32 (&cmd, "commitTransaction", 1); if (session->recovery_token) { BSON_APPEND_DOCUMENT (&cmd, "recoveryToken", session->recovery_token); } retry: if (!mongoc_client_session_append (session, &opts, err_ptr)) { GOTO (done); } if (session->txn.opts.max_commit_time_ms != DEFAULT_MAX_COMMIT_TIME_MS) { if (!bson_append_int64 (&opts, "maxTimeMS", -1, session->txn.opts.max_commit_time_ms)) { bson_set_error (err_ptr, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "error appending maxCommitTimeMS"); GOTO (done); } } /* Transactions Spec: "When commitTransaction is retried, either by the * driver's internal retry-once logic or explicitly by the user calling * commitTransaction again, drivers MUST apply w:majority to the write * concern of the commitTransaction command." */ if (!retry_wc && (retrying_after_error || explicitly_retrying)) { retry_wc = create_commit_retry_wc (session->txn.opts.write_concern ? session->txn.opts.write_concern : session->client->write_concern); } if (retry_wc || session->txn.opts.write_concern) { if (!mongoc_write_concern_append (retry_wc ? retry_wc : session->txn.opts.write_concern, &opts)) { bson_set_error (err_ptr, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Invalid transaction write concern"); GOTO (done); } } /* will be reinitialized by mongoc_client_write_command_with_opts */ bson_destroy (&reply_local); r = mongoc_client_write_command_with_opts (session->client, "admin", &cmd, &opts, &reply_local, err_ptr); /* Transactions Spec: "Drivers MUST retry the commitTransaction command once * after it fails with a retryable error", same for abort. Note that a * RetryableWriteError label has already been appended here. */ error_type = _mongoc_write_error_get_type (&reply_local); if (!retrying_after_error && error_type == MONGOC_WRITE_ERR_RETRY) { retrying_after_error = true; /* retry after error only once */ _mongoc_client_session_unpin (session); bson_reinit (&opts); GOTO (retry); } /* Transactions Spec: "add the UnknownTransactionCommitResult error label * when commitTransaction fails with a network error, server selection * error, MaxTimeMSExpired error, or write concern failed / timeout." */ if (!r && (err_ptr->domain == MONGOC_ERROR_SERVER_SELECTION || error_type == MONGOC_WRITE_ERR_RETRY || error_type == MONGOC_WRITE_ERR_WRITE_CONCERN || err_ptr->code == MONGOC_ERROR_MAX_TIME_MS_EXPIRED)) { /* Drivers MUST unpin a ClientSession when any individual * commitTransaction command attempt fails with an * UnknownTransactionCommitResult error label. Do this even if we won't * actually apply the error label due to reply being NULL */ _mongoc_client_session_unpin (session); if (reply) { bsonBuildAppend (*reply, insert (reply_local, not(key ("errorLabels")))); _mongoc_error_copy_labels_and_upsert (&reply_local, reply, UNKNOWN_COMMIT_RESULT); } } else if (reply) { /* maintain invariants: reply & reply_local are valid until the end */ bson_destroy (reply); bson_steal (reply, &reply_local); bson_init (&reply_local); } done: bson_destroy (&reply_local); bson_destroy (&cmd); bson_destroy (&opts); if (retry_wc) { mongoc_write_concern_destroy (retry_wc); } return r; } mongoc_transaction_opt_t * mongoc_transaction_opts_new (void) { mongoc_transaction_opt_t *opts; opts = (mongoc_transaction_opt_t *) bson_malloc0 (sizeof (mongoc_transaction_opt_t)); opts->max_commit_time_ms = DEFAULT_MAX_COMMIT_TIME_MS; return opts; } mongoc_transaction_opt_t * mongoc_transaction_opts_clone (const mongoc_transaction_opt_t *opts) { mongoc_transaction_opt_t *cloned_opts; ENTRY; BSON_ASSERT (opts); cloned_opts = mongoc_transaction_opts_new (); txn_opts_copy (opts, cloned_opts); RETURN (cloned_opts); } void mongoc_transaction_opts_destroy (mongoc_transaction_opt_t *opts) { ENTRY; if (!opts) { EXIT; } txn_opts_cleanup (opts); bson_free (opts); EXIT; } void mongoc_transaction_opts_set_max_commit_time_ms (mongoc_transaction_opt_t *opts, int64_t max_commit_time_ms) { BSON_ASSERT (opts); opts->max_commit_time_ms = max_commit_time_ms; } int64_t mongoc_transaction_opts_get_max_commit_time_ms (mongoc_transaction_opt_t *opts) { BSON_ASSERT (opts); return opts->max_commit_time_ms; } void mongoc_transaction_opts_set_read_concern (mongoc_transaction_opt_t *opts, const mongoc_read_concern_t *read_concern) { BSON_ASSERT (opts); mongoc_read_concern_destroy (opts->read_concern); opts->read_concern = mongoc_read_concern_copy (read_concern); } const mongoc_read_concern_t * mongoc_transaction_opts_get_read_concern (const mongoc_transaction_opt_t *opts) { BSON_ASSERT (opts); return opts->read_concern; } void mongoc_transaction_opts_set_write_concern (mongoc_transaction_opt_t *opts, const mongoc_write_concern_t *write_concern) { BSON_ASSERT (opts); mongoc_write_concern_destroy (opts->write_concern); opts->write_concern = mongoc_write_concern_copy (write_concern); } const mongoc_write_concern_t * mongoc_transaction_opts_get_write_concern (const mongoc_transaction_opt_t *opts) { BSON_ASSERT (opts); return opts->write_concern; } void mongoc_transaction_opts_set_read_prefs (mongoc_transaction_opt_t *opts, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (opts); mongoc_read_prefs_destroy (opts->read_prefs); opts->read_prefs = mongoc_read_prefs_copy (read_prefs); } const mongoc_read_prefs_t * mongoc_transaction_opts_get_read_prefs (const mongoc_transaction_opt_t *opts) { BSON_ASSERT (opts); return opts->read_prefs; } bool mongoc_session_opts_get_causal_consistency (const mongoc_session_opt_t *opts) { ENTRY; BSON_ASSERT (opts); /* Causal Consistency spec: If no value is provided for causalConsistency * and snapshot reads are not requested a value of true is implied. */ if (!mongoc_optional_is_set (&opts->causal_consistency) && !mongoc_optional_value (&opts->snapshot)) { RETURN (true); } RETURN (mongoc_optional_value (&opts->causal_consistency)); } bool mongoc_session_opts_get_snapshot (const mongoc_session_opt_t *opts) { ENTRY; BSON_ASSERT (opts); RETURN (mongoc_optional_value (&opts->snapshot)); } void mongoc_session_opts_set_causal_consistency (mongoc_session_opt_t *opts, bool causal_consistency) { ENTRY; BSON_ASSERT (opts); mongoc_optional_set_value (&opts->causal_consistency, causal_consistency); EXIT; } void mongoc_session_opts_set_snapshot (mongoc_session_opt_t *opts, bool snapshot) { ENTRY; BSON_ASSERT (opts); mongoc_optional_set_value (&opts->snapshot, snapshot); EXIT; } mongoc_session_opt_t * mongoc_session_opts_new (void) { mongoc_session_opt_t *opts = bson_malloc0 (sizeof (mongoc_session_opt_t)); mongoc_optional_init (&opts->causal_consistency); mongoc_optional_init (&opts->snapshot); return opts; } void mongoc_session_opts_set_default_transaction_opts (mongoc_session_opt_t *opts, const mongoc_transaction_opt_t *txn_opts) { ENTRY; BSON_ASSERT (opts); BSON_ASSERT (txn_opts); txn_opts_set (&opts->default_txn_opts, txn_opts->read_concern, txn_opts->write_concern, txn_opts->read_prefs, txn_opts->max_commit_time_ms); EXIT; } const mongoc_transaction_opt_t * mongoc_session_opts_get_default_transaction_opts (const mongoc_session_opt_t *opts) { ENTRY; BSON_ASSERT (opts); RETURN (&opts->default_txn_opts); } mongoc_transaction_opt_t * mongoc_session_opts_get_transaction_opts (const mongoc_client_session_t *session) { ENTRY; BSON_ASSERT (session); if (mongoc_client_session_in_transaction (session)) { RETURN (mongoc_transaction_opts_clone (&session->txn.opts)); } RETURN (NULL); } static void _mongoc_session_opts_copy (const mongoc_session_opt_t *src, mongoc_session_opt_t *dst) { mongoc_optional_copy (&src->causal_consistency, &dst->causal_consistency); mongoc_optional_copy (&src->snapshot, &dst->snapshot); txn_opts_copy (&src->default_txn_opts, &dst->default_txn_opts); } mongoc_session_opt_t * mongoc_session_opts_clone (const mongoc_session_opt_t *opts) { mongoc_session_opt_t *cloned_opts; ENTRY; BSON_ASSERT (opts); cloned_opts = bson_malloc0 (sizeof (mongoc_session_opt_t)); _mongoc_session_opts_copy (opts, cloned_opts); RETURN (cloned_opts); } void mongoc_session_opts_destroy (mongoc_session_opt_t *opts) { ENTRY; if (!opts) { EXIT; } txn_opts_cleanup (&opts->default_txn_opts); bson_free (opts); EXIT; } static bool _mongoc_server_session_uuid (uint8_t *data /* OUT */, bson_error_t *error) { #ifdef MONGOC_ENABLE_CRYPTO /* https://tools.ietf.org/html/rfc4122#page-14 * o Set the two most significant bits (bits 6 and 7) of the * clock_seq_hi_and_reserved to zero and one, respectively. * * o Set the four most significant bits (bits 12 through 15) of the * time_hi_and_version field to the 4-bit version number from * Section 4.1.3. * * o Set all the other bits to randomly (or pseudo-randomly) chosen * values. */ if (!_mongoc_rand_bytes (data, 16)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_SESSION_FAILURE, "Could not generate UUID for logical session id"); return false; } data[6] = (uint8_t) (0x40 | (data[6] & 0xf)); data[8] = (uint8_t) (0x80 | (data[8] & 0x3f)); return true; #else /* no _mongoc_rand_bytes without a crypto library */ bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_SESSION_FAILURE, "Could not generate UUID for logical session id, we need a" " cryptography library like libcrypto, Common Crypto, or" " CNG"); return false; #endif } bool _mongoc_parse_cluster_time (const bson_t *cluster_time, uint32_t *timestamp, uint32_t *increment) { bson_iter_t iter; char *s; if (!cluster_time || !bson_iter_init_find (&iter, cluster_time, "clusterTime") || !BSON_ITER_HOLDS_TIMESTAMP (&iter)) { s = bson_as_relaxed_extended_json (cluster_time, NULL); MONGOC_ERROR ("Cannot parse cluster time from %s\n", s); bson_free (s); return false; } bson_iter_timestamp (&iter, timestamp, increment); return true; } bool _mongoc_cluster_time_greater (const bson_t *new, const bson_t *old) { uint32_t new_t, new_i, old_t, old_i; if (!_mongoc_parse_cluster_time (new, &new_t, &new_i) || !_mongoc_parse_cluster_time (old, &old_t, &old_i)) { return false; } return (new_t > old_t) || (new_t == old_t && new_i > old_i); } void _mongoc_client_session_handle_reply (mongoc_client_session_t *session, bool is_acknowledged, const char *cmd_name, const bson_t *reply) { bson_iter_t iter; bson_iter_t cursor_iter; uint32_t len; const uint8_t *data; bson_t cluster_time; uint32_t operation_t; uint32_t operation_i; uint32_t snapshot_t; uint32_t snapshot_i; bool is_find_aggregate_distinct; BSON_ASSERT (session); if (!reply || !bson_iter_init (&iter, reply)) { return; } is_find_aggregate_distinct = (!strcmp (cmd_name, "find") || !strcmp (cmd_name, "aggregate") || !strcmp (cmd_name, "distinct")); if (mongoc_error_has_label (reply, "TransientTransactionError")) { /* Transaction Spec: "Drivers MUST unpin a ClientSession when a command * within a transaction, including commitTransaction and abortTransaction, * fails with a TransientTransactionError". If the server reply included * a TransientTransactionError, we unpin here. If a network error caused * us to add a label client-side, we unpin in network_error_reply. */ _mongoc_client_session_unpin (session); } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "$clusterTime") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_iter_document (&iter, &len, &data); BSON_ASSERT (bson_init_static (&cluster_time, data, (size_t) len)); mongoc_client_session_advance_cluster_time (session, &cluster_time); } else if (!strcmp (bson_iter_key (&iter), "operationTime") && BSON_ITER_HOLDS_TIMESTAMP (&iter) && is_acknowledged) { bson_iter_timestamp (&iter, &operation_t, &operation_i); mongoc_client_session_advance_operation_time (session, operation_t, operation_i); } else if (is_find_aggregate_distinct && !strcmp (bson_iter_key (&iter), "atClusterTime") && mongoc_session_opts_get_snapshot (&session->opts) && !session->snapshot_time_set) { /* If command is "find", "aggregate" or "distinct", atClusterTime is on * top level of reply, snapshot is enabled for the session, and * snapshot_time has not already been set, set it. */ bson_iter_timestamp (&iter, &snapshot_t, &snapshot_i); _mongoc_client_session_set_snapshot_time (session, snapshot_t, snapshot_i); } else if (is_find_aggregate_distinct && !strcmp (bson_iter_key (&iter), "cursor") && mongoc_session_opts_get_snapshot (&session->opts) && !session->snapshot_time_set) { /* If command is "find", "aggregate" or "distinct", cursor is present, * snapshot is enabled for the session, and snapshot_time has not * already been set, try to find atClusterTime in cursor field to set * snapshot_time. */ bson_iter_recurse (&iter, &cursor_iter); while (bson_iter_next (&cursor_iter)) { /* If atClusterTime is in cursor and is a valid timestamp, use it to * set snapshot_time. */ if (!strcmp (bson_iter_key (&cursor_iter), "atClusterTime") && BSON_ITER_HOLDS_TIMESTAMP (&cursor_iter)) { bson_iter_timestamp (&cursor_iter, &snapshot_t, &snapshot_i); _mongoc_client_session_set_snapshot_time (session, snapshot_t, snapshot_i); } } } } } bool _mongoc_server_session_init (mongoc_server_session_t *self, bson_error_t *error) { uint8_t uuid_data[16]; ENTRY; BSON_ASSERT (self); if (!_mongoc_server_session_uuid (uuid_data, error)) { RETURN (false); } /* transaction number is a positive integer and will be incremented before * each use, so ensure it is initialized to zero. */ self->txn_number = 0; self->last_used_usec = SESSION_NEVER_USED; bson_init (&self->lsid); BSON_APPEND_BINARY (&self->lsid, "id", BSON_SUBTYPE_UUID, uuid_data, sizeof uuid_data); RETURN (true); } bool _mongoc_server_session_timed_out (const mongoc_server_session_t *server_session, int64_t session_timeout_minutes) { int64_t timeout_usec; const int64_t minute_to_usec = 60 * 1000 * 1000; ENTRY; if (session_timeout_minutes == MONGOC_NO_SESSIONS) { /* not connected right now; keep the session */ return false; } if (server_session->last_used_usec == SESSION_NEVER_USED) { return false; } /* Driver Sessions Spec: if a session has less than one minute left before * becoming stale, discard it */ timeout_usec = server_session->last_used_usec + session_timeout_minutes * minute_to_usec; RETURN (timeout_usec - bson_get_monotonic_time () < 1 * minute_to_usec); } void _mongoc_server_session_destroy (mongoc_server_session_t *self) { bson_destroy (&self->lsid); } mongoc_client_session_t * _mongoc_client_session_new (mongoc_client_t *client, mongoc_server_session_t *server_session, const mongoc_session_opt_t *opts, uint32_t client_session_id) { mongoc_client_session_t *session; ENTRY; BSON_ASSERT (client); BSON_ASSERT (server_session); session = BSON_ALIGNED_ALLOC0 (mongoc_client_session_t); session->client = client; session->client_generation = client->generation; session->server_session = server_session; session->client_session_id = client_session_id; bson_init (&session->cluster_time); mongoc_optional_init (&session->opts.causal_consistency); mongoc_optional_init (&session->opts.snapshot); txn_opts_set (&session->opts.default_txn_opts, client->read_concern, client->write_concern, client->read_prefs, DEFAULT_MAX_COMMIT_TIME_MS); if (opts) { mongoc_optional_copy (&opts->causal_consistency, &session->opts.causal_consistency); mongoc_optional_copy (&opts->snapshot, &session->opts.snapshot); txn_opts_set (&session->opts.default_txn_opts, opts->default_txn_opts.read_concern, opts->default_txn_opts.write_concern, opts->default_txn_opts.read_prefs, opts->default_txn_opts.max_commit_time_ms); } /* snapshot_time_set is false by default */ _mongoc_client_session_clear_snapshot_time (session); /* these values are used for testing only. */ session->with_txn_timeout_ms = 0; session->fail_commit_label = NULL; RETURN (session); } mongoc_client_t * mongoc_client_session_get_client (const mongoc_client_session_t *session) { BSON_ASSERT (session); return session->client; } const mongoc_session_opt_t * mongoc_client_session_get_opts (const mongoc_client_session_t *session) { BSON_ASSERT (session); return &session->opts; } const bson_t * mongoc_client_session_get_lsid (const mongoc_client_session_t *session) { BSON_ASSERT (session); return &session->server_session->lsid; } const bson_t * mongoc_client_session_get_cluster_time (const mongoc_client_session_t *session) { BSON_ASSERT (session); if (bson_empty (&session->cluster_time)) { return NULL; } return &session->cluster_time; } uint32_t mongoc_client_session_get_server_id (const mongoc_client_session_t *session) { BSON_ASSERT (session); return session->server_id; } void mongoc_client_session_advance_cluster_time (mongoc_client_session_t *session, const bson_t *cluster_time) { uint32_t t, i; ENTRY; if (bson_empty (&session->cluster_time) && _mongoc_parse_cluster_time (cluster_time, &t, &i)) { bson_destroy (&session->cluster_time); bson_copy_to (cluster_time, &session->cluster_time); EXIT; } if (_mongoc_cluster_time_greater (cluster_time, &session->cluster_time)) { bson_destroy (&session->cluster_time); bson_copy_to (cluster_time, &session->cluster_time); } EXIT; } void mongoc_client_session_get_operation_time (const mongoc_client_session_t *session, uint32_t *timestamp, uint32_t *increment) { BSON_ASSERT (session); BSON_ASSERT (timestamp); BSON_ASSERT (increment); *timestamp = session->operation_timestamp; *increment = session->operation_increment; } void mongoc_client_session_advance_operation_time (mongoc_client_session_t *session, uint32_t timestamp, uint32_t increment) { ENTRY; BSON_ASSERT (session); if (timestamp > session->operation_timestamp || (timestamp == session->operation_timestamp && increment > session->operation_increment)) { session->operation_timestamp = timestamp; session->operation_increment = increment; } EXIT; } static bool timeout_exceeded (int64_t expire_at) { int64_t current_time = bson_get_monotonic_time (); return current_time >= expire_at; } static bool _max_time_ms_failure (bson_t *reply) { bson_iter_t iter; bson_iter_t descendant; if (!reply) { return false; } /* We can fail with a maxTimeMS error with the error code at the top level, or nested within a writeConcernError. */ if (bson_iter_init_find (&iter, reply, "codeName") && BSON_ITER_HOLDS_UTF8 (&iter) && 0 == strcmp (bson_iter_utf8 (&iter, NULL), MAX_TIME_MS_EXPIRED)) { return true; } bson_iter_init (&iter, reply); if (bson_iter_find_descendant (&iter, "writeConcernError.codeName", &descendant) && BSON_ITER_HOLDS_UTF8 (&descendant) && 0 == strcmp (bson_iter_utf8 (&descendant, NULL), MAX_TIME_MS_EXPIRED)) { return true; } return false; } bool mongoc_client_session_with_transaction (mongoc_client_session_t *session, mongoc_client_session_with_transaction_cb_t cb, const mongoc_transaction_opt_t *opts, void *ctx, bson_t *reply, bson_error_t *error) { mongoc_internal_transaction_state_t state; int64_t timeout; int64_t expire_at; bson_t local_reply; bson_t *active_reply = NULL; bool res; ENTRY; timeout = session->with_txn_timeout_ms > 0 ? session->with_txn_timeout_ms : WITH_TXN_TIMEOUT_MS; expire_at = bson_get_monotonic_time () + ((int64_t) timeout * 1000); /* Attempt to wrap a user callback in start- and end- transaction semantics. If this fails for transient reasons, restart, either from the very beginning, or just retry committing the transaction. Will retry until the timeout WITH_TXN_TIMEOUT_MS is exhausted. At the top of this loop, active_reply should always be NULL, and local_reply should always be uninitialized. */ while (true) { res = mongoc_client_session_start_transaction (session, opts, error); if (!res) { GOTO (done); } res = cb (session, ctx, &active_reply, error); state = session->txn.state; /* If the user cb set a reply, use it. Otherwise, sub in local_reply since we must have an active reply object one way or another. */ if (!active_reply) { bson_init (&local_reply); active_reply = &local_reply; } if (!res) { if (state == MONGOC_INTERNAL_TRANSACTION_STARTING || state == MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS) { BSON_ASSERT (mongoc_client_session_abort_transaction (session, NULL)); } if (mongoc_error_has_label (active_reply, TRANSIENT_TXN_ERR) && !timeout_exceeded (expire_at)) { bson_destroy (active_reply); active_reply = NULL; continue; } /* Unknown error running callback, fail. */ GOTO (done); } if (state == MONGOC_INTERNAL_TRANSACTION_ABORTED || state == MONGOC_INTERNAL_TRANSACTION_NONE || state == MONGOC_INTERNAL_TRANSACTION_COMMITTED || state == MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY) { GOTO (done); } /* Whether or not we used local_reply above, use it now, but access it * through active_reply so cleanup in DONE is simpler. */ bson_destroy (active_reply); active_reply = &local_reply; /* Commit the transaction, retrying either from here or from the outer loop on error. At the top of this loop, active_reply should always be pointing to an uninitialized stack-allocated bson_t, so we can pass it into commit_transaction, which requires this like our other public functions that take a bson_t reply. */ while (true) { res = mongoc_client_session_commit_transaction (session, active_reply, error); if (!res) { /* If we have a MaxTimeMsExpired error, fail and propogate the error to the caller. */ if (_max_time_ms_failure (active_reply)) { GOTO (done); } if (mongoc_error_has_label (active_reply, UNKNOWN_COMMIT_RESULT) && !timeout_exceeded (expire_at)) { /* Commit_transaction applies majority write concern on retry * attempts. * * Here, we don't want to set active_reply = NULL when we * destroy, because we want it to point to an uninitialized * bson_t at the top of this loop every time.*/ bson_destroy (active_reply); continue; } if (mongoc_error_has_label (active_reply, TRANSIENT_TXN_ERR) && !timeout_exceeded (expire_at)) { /* In the case of a transient txn error, go back to outside loop. We must set the reply to NULL so it may be used by the cb. */ bson_destroy (active_reply); active_reply = NULL; break; } /* Unknown error committing transaction, fail. */ GOTO (done); } /* Transaction successfully committed! */ GOTO (done); } } done: /* At this point, active_reply is either pointing to the user's reply object, or our local one on the stack, or is NULL. */ if (reply && active_reply) { bson_copy_to (active_reply, reply); } else if (reply) { bson_init (reply); } bson_destroy (active_reply); RETURN (res); } bool mongoc_client_session_start_transaction (mongoc_client_session_t *session, const mongoc_transaction_opt_t *opts, bson_error_t *error) { mongoc_server_stream_t *server_stream = NULL; bool ret; ENTRY; BSON_ASSERT (session); ret = true; const mongoc_ss_log_context_t ss_log_context = {.operation = "mongoc_client_session_start_transaction"}; server_stream = mongoc_cluster_stream_for_writes ( &session->client->cluster, &ss_log_context, session, NULL /* deprioritized servers */, NULL /* reply */, error); if (!server_stream) { ret = false; GOTO (done); } if (mongoc_session_opts_get_snapshot (&session->opts)) { bson_set_error (error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Transactions are not supported in snapshot sessions"); ret = false; GOTO (done); } if (server_stream->sd->max_wire_version < 7 || (server_stream->sd->max_wire_version < 8 && server_stream->sd->type == MONGOC_SERVER_MONGOS)) { bson_set_error (error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Multi-document transactions are not supported by this " "server version"); ret = false; GOTO (done); } /* use "switch" so that static checkers ensure we handle all states */ switch (session->txn.state) { case MONGOC_INTERNAL_TRANSACTION_STARTING: case MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS: bson_set_error ( error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Transaction already in progress"); ret = false; GOTO (done); case MONGOC_INTERNAL_TRANSACTION_ENDING: MONGOC_ERROR ("starting txn in invalid state MONGOC_INTERNAL_TRANSACTION_ENDING"); abort (); case MONGOC_INTERNAL_TRANSACTION_COMMITTED: case MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY: case MONGOC_INTERNAL_TRANSACTION_ABORTED: case MONGOC_INTERNAL_TRANSACTION_NONE: default: break; } session->server_session->txn_number++; txn_opts_set (&session->txn.opts, session->opts.default_txn_opts.read_concern, session->opts.default_txn_opts.write_concern, session->opts.default_txn_opts.read_prefs, session->opts.default_txn_opts.max_commit_time_ms); if (opts) { txn_opts_set ( &session->txn.opts, opts->read_concern, opts->write_concern, opts->read_prefs, opts->max_commit_time_ms); } if (!mongoc_write_concern_is_acknowledged (session->txn.opts.write_concern)) { bson_set_error (error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Transactions do not support unacknowledged write concern"); ret = false; GOTO (done); } /* Transactions Spec: Starting a new transaction on a pinned ClientSession * MUST unpin the session. */ _mongoc_client_session_unpin (session); session->txn.state = MONGOC_INTERNAL_TRANSACTION_STARTING; /* Transactions spec: "Drivers MUST clear a session's cached * 'recoveryToken' when transitioning to the 'no transaction' or * 'starting transaction' state." */ bson_destroy (session->recovery_token); session->recovery_token = NULL; done: mongoc_server_stream_cleanup (server_stream); return ret; } bool mongoc_client_session_in_transaction (const mongoc_client_session_t *session) { ENTRY; BSON_ASSERT (session); /* call the internal function, which would allow a NULL session */ RETURN (_mongoc_client_session_in_txn (session)); } mongoc_transaction_state_t mongoc_client_session_get_transaction_state (const mongoc_client_session_t *session) { ENTRY; BSON_ASSERT (session); switch (session->txn.state) { case MONGOC_INTERNAL_TRANSACTION_NONE: RETURN (MONGOC_TRANSACTION_NONE); case MONGOC_INTERNAL_TRANSACTION_STARTING: RETURN (MONGOC_TRANSACTION_STARTING); case MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS: RETURN (MONGOC_TRANSACTION_IN_PROGRESS); case MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY: case MONGOC_INTERNAL_TRANSACTION_COMMITTED: RETURN (MONGOC_TRANSACTION_COMMITTED); case MONGOC_INTERNAL_TRANSACTION_ABORTED: RETURN (MONGOC_TRANSACTION_ABORTED); case MONGOC_INTERNAL_TRANSACTION_ENDING: MONGOC_ERROR ("invalid state MONGOC_INTERNAL_TRANSACTION_ENDING when " "getting transaction state"); abort (); default: MONGOC_ERROR ("invalid state %d when getting transaction state", (int) session->txn.state); abort (); } } bool mongoc_client_session_commit_transaction (mongoc_client_session_t *session, bson_t *reply, bson_error_t *error) { bool r = false; ENTRY; BSON_ASSERT (session); /* For testing only, mock out certain kinds of errors. */ if (session->fail_commit_label) { bson_array_builder_t *labels; BSON_ASSERT (reply); bson_init (reply); BSON_APPEND_ARRAY_BUILDER_BEGIN (reply, "errorLabels", &labels); bson_array_builder_append_utf8 (labels, session->fail_commit_label, -1); bson_append_array_builder_end (reply, labels); /* Waste the test timeout, if there is one set. */ if (session->with_txn_timeout_ms) { _mongoc_usleep (session->with_txn_timeout_ms * 1000); } RETURN (r); } /* See Transactions Spec for state diagram. In COMMITTED state, user can call * commit again to retry after network error */ switch (session->txn.state) { case MONGOC_INTERNAL_TRANSACTION_NONE: bson_set_error ( error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "No transaction started"); _mongoc_bson_init_if_set (reply); break; case MONGOC_INTERNAL_TRANSACTION_STARTING: case MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY: /* we sent no commands, not actually started on server */ session->txn.state = MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY; _mongoc_bson_init_if_set (reply); r = true; break; case MONGOC_INTERNAL_TRANSACTION_COMMITTED: case MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS: { bool explicitly_retrying = (session->txn.state == MONGOC_INTERNAL_TRANSACTION_COMMITTED); /* in MONGOC_INTERNAL_TRANSACTION_ENDING we add txnNumber and autocommit: * false to the commitTransaction command, but if it fails with network * error we add UnknownTransactionCommitResult not * TransientTransactionError */ session->txn.state = MONGOC_INTERNAL_TRANSACTION_ENDING; r = txn_commit (session, explicitly_retrying, reply, error); session->txn.state = MONGOC_INTERNAL_TRANSACTION_COMMITTED; break; } case MONGOC_INTERNAL_TRANSACTION_ENDING: MONGOC_ERROR ("commit called in invalid state MONGOC_INTERNAL_TRANSACTION_ENDING"); abort (); case MONGOC_INTERNAL_TRANSACTION_ABORTED: default: bson_set_error (error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Cannot call commitTransaction after calling abortTransaction"); _mongoc_bson_init_if_set (reply); break; } RETURN (r); } bool mongoc_client_session_abort_transaction (mongoc_client_session_t *session, bson_error_t *error) { ENTRY; BSON_ASSERT (session); switch (session->txn.state) { case MONGOC_INTERNAL_TRANSACTION_STARTING: /* we sent no commands, not actually started on server */ session->txn.state = MONGOC_INTERNAL_TRANSACTION_ABORTED; /* Transactions Spec: aborting a transaction MUST unpin the session. * It's likely the transaction is already unpinned if TRANSACTION_STARTING * was just assigned, but there is no harm in doing so again. */ _mongoc_client_session_unpin (session); txn_opts_cleanup (&session->txn.opts); RETURN (true); case MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS: session->txn.state = MONGOC_INTERNAL_TRANSACTION_ENDING; /* Transactions Spec: ignore errors from abortTransaction command */ txn_abort (session, NULL, NULL); session->txn.state = MONGOC_INTERNAL_TRANSACTION_ABORTED; /* Transactions Spec: aborting a transaction MUST unpin the session. */ _mongoc_client_session_unpin (session); RETURN (true); case MONGOC_INTERNAL_TRANSACTION_COMMITTED: case MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY: bson_set_error (error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Cannot call abortTransaction after calling commitTransaction"); RETURN (false); case MONGOC_INTERNAL_TRANSACTION_ABORTED: bson_set_error ( error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Cannot call abortTransaction twice"); RETURN (false); case MONGOC_INTERNAL_TRANSACTION_ENDING: MONGOC_ERROR ("abort called in invalid state MONGOC_INTERNAL_TRANSACTION_ENDING"); abort (); case MONGOC_INTERNAL_TRANSACTION_NONE: default: bson_set_error ( error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "No transaction started"); RETURN (false); } } bool _mongoc_client_session_from_iter (mongoc_client_t *client, const bson_iter_t *iter, mongoc_client_session_t **cs, bson_error_t *error) { ENTRY; BSON_ASSERT_PARAM (client); /* must be int64 that fits in uint32 */ if (!BSON_ITER_HOLDS_INT64 (iter) || bson_iter_int64 (iter) > 0xffffffff) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid sessionId"); RETURN (false); } RETURN (_mongoc_client_lookup_session (client, (uint32_t) bson_iter_int64 (iter), cs, error)); } /* Returns true if in the middle of a transaction. Note: this returns false if * the commit/abort is running. */ bool _mongoc_client_session_in_txn (const mongoc_client_session_t *session) { if (!session) { return false; } /* use "switch" so that static checkers ensure we handle all states */ switch (session->txn.state) { case MONGOC_INTERNAL_TRANSACTION_STARTING: case MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS: return true; case MONGOC_INTERNAL_TRANSACTION_NONE: case MONGOC_INTERNAL_TRANSACTION_ENDING: case MONGOC_INTERNAL_TRANSACTION_COMMITTED: case MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY: case MONGOC_INTERNAL_TRANSACTION_ABORTED: default: return false; } } /* Like _mongoc_client_session_in_txn, but also returns true if running the * commit/abort for this transaction. */ bool _mongoc_client_session_in_txn_or_ending (const mongoc_client_session_t *session) { if (!session) { return false; } /* use "switch" so that static checkers ensure we handle all states */ switch (session->txn.state) { case MONGOC_INTERNAL_TRANSACTION_STARTING: case MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS: case MONGOC_INTERNAL_TRANSACTION_ENDING: return true; case MONGOC_INTERNAL_TRANSACTION_NONE: case MONGOC_INTERNAL_TRANSACTION_COMMITTED: case MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY: case MONGOC_INTERNAL_TRANSACTION_ABORTED: default: return false; } } bool _mongoc_client_session_txn_in_progress (const mongoc_client_session_t *session) { if (!session) { return false; } return session->txn.state == MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS; } /* *-------------------------------------------------------------------------- * * _mongoc_client_session_append_txn -- * * Add transaction fields besides "readConcern" to @cmd. * * Returns: * Returns false and sets @error if @cmd is empty, otherwise returns * true. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool _mongoc_client_session_append_txn (mongoc_client_session_t *session, bson_t *cmd, bson_error_t *error) { mongoc_transaction_t *txn; ENTRY; if (!session) { RETURN (true); } if (bson_empty0 (cmd)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Empty command in transaction"); RETURN (false); } txn = &session->txn; /* See Transactions Spec for state transitions. In COMMITTED / ABORTED, the * next operation resets the session and moves to TRANSACTION_NONE */ switch (session->txn.state) { case MONGOC_INTERNAL_TRANSACTION_STARTING: txn->state = MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS; bson_append_bool (cmd, "startTransaction", 16, true); /* FALL THROUGH */ case MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS: case MONGOC_INTERNAL_TRANSACTION_ENDING: bson_append_int64 (cmd, "txnNumber", 9, session->server_session->txn_number); bson_append_bool (cmd, "autocommit", 10, false); RETURN (true); case MONGOC_INTERNAL_TRANSACTION_COMMITTED: if (!strcmp (_mongoc_get_command_name (cmd), "commitTransaction")) { /* send commitTransaction again */ bson_append_int64 (cmd, "txnNumber", 9, session->server_session->txn_number); bson_append_bool (cmd, "autocommit", 10, false); RETURN (true); } /* FALL THROUGH */ case MONGOC_INTERNAL_TRANSACTION_COMMITTED_EMPTY: case MONGOC_INTERNAL_TRANSACTION_ABORTED: txn_opts_cleanup (&session->txn.opts); txn->state = MONGOC_INTERNAL_TRANSACTION_NONE; /* Transactions spec: "Drivers MUST clear a session's cached * 'recoveryToken' when transitioning to the 'no transaction' or * 'starting transaction' state." */ bson_destroy (session->recovery_token); session->recovery_token = NULL; RETURN (true); case MONGOC_INTERNAL_TRANSACTION_NONE: default: RETURN (true); } } /* *-------------------------------------------------------------------------- * * _mongoc_client_session_append_read_concern -- * * Add read concern if we're doing a read outside a transaction, or if * we're starting a transaction, or if the user explicitly passed a read * concern in some function's "opts". The contents of the read concern * are "level" and/or "afterClusterTime" - if both are empty, don't add * read concern. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void _mongoc_client_session_append_read_concern (const mongoc_client_session_t *cs, const bson_t *rc, bool is_read_command, bson_t *cmd) { const mongoc_read_concern_t *txn_rc; mongoc_internal_transaction_state_t txn_state; bool user_rc_has_level; bool txn_has_level; bool has_timestamp; bool is_snapshot; bool has_level; bson_t child; ENTRY; BSON_ASSERT (cs); txn_state = cs->txn.state; txn_rc = cs->txn.opts.read_concern; if (txn_state == MONGOC_INTERNAL_TRANSACTION_IN_PROGRESS) { return; } has_timestamp = (txn_state == MONGOC_INTERNAL_TRANSACTION_STARTING || is_read_command) && mongoc_session_opts_get_causal_consistency (&cs->opts) && cs->operation_timestamp; is_snapshot = mongoc_session_opts_get_snapshot (&cs->opts); user_rc_has_level = rc && bson_has_field (rc, "level"); txn_has_level = txn_state == MONGOC_INTERNAL_TRANSACTION_STARTING && !mongoc_read_concern_is_default (txn_rc); has_level = user_rc_has_level || txn_has_level; /* do not append read concern if no causal consistency, snapshot disabled and * no read concern is provided. */ if (!has_timestamp && !is_snapshot && !has_level) { return; } bson_append_document_begin (cmd, "readConcern", 11, &child); if (rc) { bson_concat (&child, rc); } if (txn_state == MONGOC_INTERNAL_TRANSACTION_STARTING) { /* add transaction's read concern level unless user overrides or snapshot * is enabled. */ if (txn_has_level && !user_rc_has_level && !is_snapshot) { bson_append_utf8 (&child, "level", 5, txn_rc->level, -1); } } if (is_snapshot) { bson_append_utf8 (&child, "level", 5, MONGOC_READ_CONCERN_LEVEL_SNAPSHOT, -1); } /* append afterClusterTime if causal consistency and operation_time is set. * otherwise append atClusterTime if snapshot enabled and snapshot_time is * set. */ if (has_timestamp) { bson_append_timestamp (&child, "afterClusterTime", 16, cs->operation_timestamp, cs->operation_increment); } else if (is_snapshot && cs->snapshot_time_set) { bson_append_timestamp (&child, "atClusterTime", 13, cs->snapshot_time_timestamp, cs->snapshot_time_increment); } bson_append_document_end (cmd, &child); } bool mongoc_client_session_append (const mongoc_client_session_t *client_session, bson_t *opts, bson_error_t *error) { ENTRY; BSON_ASSERT (client_session); BSON_ASSERT (opts); if (!bson_append_int64 (opts, "sessionId", 9, client_session->client_session_id)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "invalid opts"); RETURN (false); } RETURN (true); } void mongoc_client_session_destroy (mongoc_client_session_t *session) { ENTRY; if (!session) { EXIT; } if (session->client_generation == session->client->generation) { if (mongoc_client_session_in_transaction (session)) { mongoc_client_session_abort_transaction (session, NULL); } _mongoc_client_unregister_session (session->client, session); _mongoc_client_push_server_session (session->client, session->server_session); } else { /** If the client has been reset, destroy the server session instead of * pushing it back into the topology's pool. */ mongoc_server_session_pool_drop (session->client->topology->session_pool, session->server_session); } txn_opts_cleanup (&session->opts.default_txn_opts); txn_opts_cleanup (&session->txn.opts); bson_destroy (&session->cluster_time); bson_destroy (session->recovery_token); bson_free (session); EXIT; } void _mongoc_client_session_unpin (mongoc_client_session_t *session) { BSON_ASSERT (session); session->server_id = 0; } void _mongoc_client_session_pin (mongoc_client_session_t *session, uint32_t server_id) { BSON_ASSERT (session); session->server_id = server_id; } void _mongoc_client_session_set_snapshot_time (mongoc_client_session_t *session, uint32_t t, uint32_t i) { BSON_ASSERT (session); BSON_ASSERT (!session->snapshot_time_set); session->snapshot_time_set = true; session->snapshot_time_timestamp = t; session->snapshot_time_increment = i; } void _mongoc_client_session_clear_snapshot_time (mongoc_client_session_t *session) { BSON_ASSERT (session); session->snapshot_time_set = false; } bool mongoc_client_session_get_dirty (mongoc_client_session_t *session) { BSON_ASSERT_PARAM (session); return session->server_session->dirty; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-session.h0000644000175100001660000001547214760300420024107 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLIENT_SESSION_H #define MONGOC_CLIENT_SESSION_H #include #include /* mongoc_client_session_t, mongoc_transaction_opt_t, and mongoc_session_opt_t are typedef'ed here */ #include BSON_BEGIN_DECLS typedef bool (*mongoc_client_session_with_transaction_cb_t) (mongoc_client_session_t *session, void *ctx, bson_t **reply, bson_error_t *error); typedef enum { MONGOC_TRANSACTION_NONE = 0, MONGOC_TRANSACTION_STARTING = 1, MONGOC_TRANSACTION_IN_PROGRESS = 2, MONGOC_TRANSACTION_COMMITTED = 3, MONGOC_TRANSACTION_ABORTED = 4, } mongoc_transaction_state_t; /* these options types are named "opt_t" but their functions are named with * "opts", for consistency with the older mongoc_ssl_opt_t */ MONGOC_EXPORT (mongoc_transaction_opt_t *) mongoc_transaction_opts_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_transaction_opt_t *) mongoc_transaction_opts_clone (const mongoc_transaction_opt_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_transaction_opts_destroy (mongoc_transaction_opt_t *opts); MONGOC_EXPORT (void) mongoc_transaction_opts_set_max_commit_time_ms (mongoc_transaction_opt_t *opts, int64_t max_commit_time_ms); MONGOC_EXPORT (int64_t) mongoc_transaction_opts_get_max_commit_time_ms (mongoc_transaction_opt_t *opts); MONGOC_EXPORT (void) mongoc_transaction_opts_set_read_concern (mongoc_transaction_opt_t *opts, const mongoc_read_concern_t *read_concern); MONGOC_EXPORT (const mongoc_read_concern_t *) mongoc_transaction_opts_get_read_concern (const mongoc_transaction_opt_t *opts); MONGOC_EXPORT (void) mongoc_transaction_opts_set_write_concern (mongoc_transaction_opt_t *opts, const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (const mongoc_write_concern_t *) mongoc_transaction_opts_get_write_concern (const mongoc_transaction_opt_t *opts); MONGOC_EXPORT (void) mongoc_transaction_opts_set_read_prefs (mongoc_transaction_opt_t *opts, const mongoc_read_prefs_t *read_prefs); MONGOC_EXPORT (const mongoc_read_prefs_t *) mongoc_transaction_opts_get_read_prefs (const mongoc_transaction_opt_t *opts); MONGOC_EXPORT (mongoc_session_opt_t *) mongoc_session_opts_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_session_opts_set_causal_consistency (mongoc_session_opt_t *opts, bool causal_consistency); MONGOC_EXPORT (bool) mongoc_session_opts_get_causal_consistency (const mongoc_session_opt_t *opts); MONGOC_EXPORT (void) mongoc_session_opts_set_snapshot (mongoc_session_opt_t *opts, bool snapshot); MONGOC_EXPORT (bool) mongoc_session_opts_get_snapshot (const mongoc_session_opt_t *opts); MONGOC_EXPORT (void) mongoc_session_opts_set_default_transaction_opts (mongoc_session_opt_t *opts, const mongoc_transaction_opt_t *txn_opts); MONGOC_EXPORT (const mongoc_transaction_opt_t *) mongoc_session_opts_get_default_transaction_opts (const mongoc_session_opt_t *opts); MONGOC_EXPORT (mongoc_transaction_opt_t *) mongoc_session_opts_get_transaction_opts (const mongoc_client_session_t *session) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_session_opt_t *) mongoc_session_opts_clone (const mongoc_session_opt_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_session_opts_destroy (mongoc_session_opt_t *opts); MONGOC_EXPORT (mongoc_client_t *) mongoc_client_session_get_client (const mongoc_client_session_t *session); MONGOC_EXPORT (const mongoc_session_opt_t *) mongoc_client_session_get_opts (const mongoc_client_session_t *session); MONGOC_EXPORT (const bson_t *) mongoc_client_session_get_lsid (const mongoc_client_session_t *session); MONGOC_EXPORT (const bson_t *) mongoc_client_session_get_cluster_time (const mongoc_client_session_t *session); MONGOC_EXPORT (void) mongoc_client_session_advance_cluster_time (mongoc_client_session_t *session, const bson_t *cluster_time); MONGOC_EXPORT (void) mongoc_client_session_get_operation_time (const mongoc_client_session_t *session, uint32_t *timestamp, uint32_t *increment); MONGOC_EXPORT (uint32_t) mongoc_client_session_get_server_id (const mongoc_client_session_t *session); MONGOC_EXPORT (void) mongoc_client_session_advance_operation_time (mongoc_client_session_t *session, uint32_t timestamp, uint32_t increment); MONGOC_EXPORT (bool) mongoc_client_session_with_transaction (mongoc_client_session_t *session, mongoc_client_session_with_transaction_cb_t cb, const mongoc_transaction_opt_t *opts, void *ctx, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_session_start_transaction (mongoc_client_session_t *session, const mongoc_transaction_opt_t *opts, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_session_in_transaction (const mongoc_client_session_t *session); MONGOC_EXPORT (mongoc_transaction_state_t) mongoc_client_session_get_transaction_state (const mongoc_client_session_t *session); MONGOC_EXPORT (bool) mongoc_client_session_commit_transaction (mongoc_client_session_t *session, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_session_abort_transaction (mongoc_client_session_t *session, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_session_append (const mongoc_client_session_t *client_session, bson_t *opts, bson_error_t *error); /* There is no mongoc_client_session_end, only mongoc_client_session_destroy. * Driver Sessions Spec: "In languages that have idiomatic ways of disposing of * resources, drivers SHOULD support that in addition to or instead of * endSession." */ MONGOC_EXPORT (void) mongoc_client_session_destroy (mongoc_client_session_t *session); MONGOC_EXPORT (bool) mongoc_client_session_get_dirty (mongoc_client_session_t *session); BSON_END_DECLS #endif /* MONGOC_CLIENT_SESSION_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-side-encryption-private.h0000644000175100001660000000721614760300420027205 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLIENT_SIDE_ENCRYPTION_PRIVATE_H #define MONGOC_CLIENT_SIDE_ENCRYPTION_PRIVATE_H #include #include #include #include #include #include /* cse is an abbreviation for "Client Side Encryption" */ bool _mongoc_cse_auto_encrypt (mongoc_client_t *client, const mongoc_cmd_t *cmd, mongoc_cmd_t *encrypted_cmd, bson_t *encrypted, bson_error_t *error); bool _mongoc_cse_auto_decrypt ( mongoc_client_t *client, const char *db_name, const bson_t *reply, bson_t *decrypted, bson_error_t *error); bool _mongoc_cse_client_enable_auto_encryption (mongoc_client_t *client, mongoc_auto_encryption_opts_t *opts /* may be NULL */, bson_error_t *error); bool _mongoc_cse_client_pool_enable_auto_encryption (mongoc_topology_t *topology, mongoc_auto_encryption_opts_t *opts /* may be NULL */, bson_error_t *error); /* If this returns true, client side encryption is enabled * on the client (or it's parent client pool), and cannot * be disabled. This check is done while holding the * topology lock. So if this returns true, callers are * guaranteed that CSE remains enabled afterwards. */ bool _mongoc_cse_is_enabled (mongoc_client_t *client); /** * @brief The context for the automatic creation of a datakey */ struct auto_datakey_context { /// The output destination for the new key ID. Never NULL. bson_value_t *out_keyid; /// An error output destination for the key generation. May be NULL. bson_error_t *out_error; /// The userdata pointer given to @ref /// _mongoc_encryptedFields_fill_auto_datakeys void *userdata; }; /** * @brief The type of a datakey-creating callback. * * @param ctx The context of the keyId request. @sa auto_datakey_context * @retval true Upon success * @retval false Otherwise. * * @note Errors should be written into `ctx->out_error`. */ typedef bool (*auto_datakey_factory) (struct auto_datakey_context *ctx); /** * @brief Process an array of encryptedFields.fields, automatically filling null * keyId elements by calling the given factory function. * * @param[out] out_fields The modified encryptedFields.fields. Must be destroyed * by the caller. * @param[in] in_fields The input encryptedFields.fields * @param factory A keyId factory. @see auto_datakey_factory * @param userdata The userdata pointer for `factory` * @param[out] error An error output parameter * @retval true On success * @retval false Otherwise */ bool _mongoc_encryptedFields_fill_auto_datakeys ( bson_t *out_fields, const bson_t *in_fields, auto_datakey_factory factory, void *userdata, bson_error_t *error); #endif /* MONGOC_CLIENT_SIDE_ENCRYPTION_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c0000644000175100001660000030344714760300420025535 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifndef _WIN32 #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include /*-------------------------------------------------------------------------- * Auto Encryption options. *-------------------------------------------------------------------------- */ struct _mongoc_auto_encryption_opts_t { /* keyvault_client and keyvault_client_pool are not owned and must outlive * auto encrypted client/pool. */ mongoc_client_t *keyvault_client; mongoc_client_pool_t *keyvault_client_pool; char *keyvault_db; char *keyvault_coll; bson_t *kms_providers; bson_t *tls_opts; bson_t *schema_map; bson_t *encrypted_fields_map; bool bypass_auto_encryption; bool bypass_query_analysis; mc_kms_credentials_callback creds_cb; bson_t *extra; mcd_optional_u64_t cache_expiration_ms; }; static void _set_creds_callback (mc_kms_credentials_callback *cb, mongoc_kms_credentials_provider_callback_fn fn, void *userdata) { BSON_ASSERT (cb); cb->fn = fn; cb->userdata = userdata; } mongoc_auto_encryption_opts_t * mongoc_auto_encryption_opts_new (void) { return bson_malloc0 (sizeof (mongoc_auto_encryption_opts_t)); } void mongoc_auto_encryption_opts_destroy (mongoc_auto_encryption_opts_t *opts) { if (!opts) { return; } bson_destroy (opts->extra); bson_destroy (opts->kms_providers); bson_destroy (opts->schema_map); bson_destroy (opts->encrypted_fields_map); bson_free (opts->keyvault_db); bson_free (opts->keyvault_coll); bson_destroy (opts->tls_opts); bson_free (opts); } void mongoc_auto_encryption_opts_set_keyvault_client (mongoc_auto_encryption_opts_t *opts, mongoc_client_t *client) { if (!opts) { return; } /* Does not own. */ opts->keyvault_client = client; } void mongoc_auto_encryption_opts_set_keyvault_client_pool (mongoc_auto_encryption_opts_t *opts, mongoc_client_pool_t *pool) { if (!opts) { return; } /* Does not own. */ opts->keyvault_client_pool = pool; } void mongoc_auto_encryption_opts_set_keyvault_namespace (mongoc_auto_encryption_opts_t *opts, const char *db, const char *coll) { if (!opts) { return; } bson_free (opts->keyvault_db); opts->keyvault_db = NULL; opts->keyvault_db = bson_strdup (db); bson_free (opts->keyvault_coll); opts->keyvault_coll = NULL; opts->keyvault_coll = bson_strdup (coll); } void mongoc_auto_encryption_opts_set_kms_providers (mongoc_auto_encryption_opts_t *opts, const bson_t *providers) { if (!opts) { return; } bson_destroy (opts->kms_providers); opts->kms_providers = NULL; if (providers) { opts->kms_providers = bson_copy (providers); } } void mongoc_auto_encryption_opts_set_key_expiration (mongoc_auto_encryption_opts_t *opts, uint64_t expiration) { if (!opts) { return; } opts->cache_expiration_ms.set = true; opts->cache_expiration_ms.value = expiration; } /* _bson_copy_or_null returns a copy of @bson or NULL if @bson is NULL */ static bson_t * _bson_copy_or_null (const bson_t *bson) { if (bson) { return bson_copy (bson); } return NULL; } void mongoc_auto_encryption_opts_set_tls_opts (mongoc_auto_encryption_opts_t *opts, const bson_t *tls_opts) { if (!opts) { return; } bson_destroy (opts->tls_opts); opts->tls_opts = _bson_copy_or_null (tls_opts); } void mongoc_auto_encryption_opts_set_schema_map (mongoc_auto_encryption_opts_t *opts, const bson_t *schema_map) { if (!opts) { return; } bson_destroy (opts->schema_map); opts->schema_map = NULL; if (schema_map) { opts->schema_map = bson_copy (schema_map); } } void mongoc_auto_encryption_opts_set_encrypted_fields_map (mongoc_auto_encryption_opts_t *opts, const bson_t *encrypted_fields_map) { if (!opts) { return; } bson_destroy (opts->encrypted_fields_map); opts->encrypted_fields_map = NULL; if (encrypted_fields_map) { opts->encrypted_fields_map = bson_copy (encrypted_fields_map); } } void mongoc_auto_encryption_opts_set_bypass_auto_encryption (mongoc_auto_encryption_opts_t *opts, bool bypass_auto_encryption) { if (!opts) { return; } opts->bypass_auto_encryption = bypass_auto_encryption; } void mongoc_auto_encryption_opts_set_bypass_query_analysis (mongoc_auto_encryption_opts_t *opts, bool bypass_query_analysis) { if (!opts) { return; } opts->bypass_query_analysis = bypass_query_analysis; } void mongoc_auto_encryption_opts_set_extra (mongoc_auto_encryption_opts_t *opts, const bson_t *extra) { if (!opts) { return; } bson_destroy (opts->extra); opts->extra = NULL; if (extra) { opts->extra = bson_copy (extra); } } void mongoc_auto_encryption_opts_set_kms_credential_provider_callback (mongoc_auto_encryption_opts_t *opts, mongoc_kms_credentials_provider_callback_fn fn, void *userdata) { _set_creds_callback (&opts->creds_cb, fn, userdata); } /*-------------------------------------------------------------------------- * Client Encryption options. *-------------------------------------------------------------------------- */ struct _mongoc_client_encryption_opts_t { mongoc_client_t *keyvault_client; char *keyvault_db; char *keyvault_coll; bson_t *kms_providers; bson_t *tls_opts; mc_kms_credentials_callback creds_cb; mcd_optional_u64_t cache_expiration_ms; }; mongoc_client_encryption_opts_t * mongoc_client_encryption_opts_new (void) { return bson_malloc0 (sizeof (mongoc_client_encryption_opts_t)); } void mongoc_client_encryption_opts_destroy (mongoc_client_encryption_opts_t *opts) { if (!opts) { return; } _set_creds_callback (&opts->creds_cb, NULL, NULL); bson_free (opts->keyvault_db); bson_free (opts->keyvault_coll); bson_destroy (opts->kms_providers); bson_destroy (opts->tls_opts); bson_free (opts); } void mongoc_client_encryption_opts_set_keyvault_client (mongoc_client_encryption_opts_t *opts, mongoc_client_t *keyvault_client) { if (!opts) { return; } opts->keyvault_client = keyvault_client; } void mongoc_client_encryption_opts_set_keyvault_namespace (mongoc_client_encryption_opts_t *opts, const char *db, const char *coll) { if (!opts) { return; } bson_free (opts->keyvault_db); opts->keyvault_db = NULL; opts->keyvault_db = bson_strdup (db); bson_free (opts->keyvault_coll); opts->keyvault_coll = NULL; opts->keyvault_coll = bson_strdup (coll); } void mongoc_client_encryption_opts_set_kms_providers (mongoc_client_encryption_opts_t *opts, const bson_t *kms_providers) { if (!opts) { return; } bson_destroy (opts->kms_providers); opts->kms_providers = NULL; if (kms_providers) { opts->kms_providers = bson_copy (kms_providers); } } void mongoc_client_encryption_opts_set_tls_opts (mongoc_client_encryption_opts_t *opts, const bson_t *tls_opts) { if (!opts) { return; } bson_destroy (opts->tls_opts); opts->tls_opts = _bson_copy_or_null (tls_opts); } void mongoc_client_encryption_opts_set_kms_credential_provider_callback (mongoc_client_encryption_opts_t *opts, mongoc_kms_credentials_provider_callback_fn fn, void *userdata) { BSON_ASSERT_PARAM (opts); opts->creds_cb.fn = fn; opts->creds_cb.userdata = userdata; } void mongoc_client_encryption_opts_set_key_expiration (mongoc_client_encryption_opts_t *opts, uint64_t cache_expiration_ms) { BSON_ASSERT_PARAM (opts); opts->cache_expiration_ms.set = true; opts->cache_expiration_ms.value = cache_expiration_ms; } /*-------------------------------------------------------------------------- * Data key options. *-------------------------------------------------------------------------- */ struct _mongoc_client_encryption_datakey_opts_t { bson_t *masterkey; char **keyaltnames; uint32_t keyaltnames_count; uint8_t *keymaterial; uint32_t keymaterial_len; }; mongoc_client_encryption_datakey_opts_t * mongoc_client_encryption_datakey_opts_new (void) { return bson_malloc0 (sizeof (mongoc_client_encryption_datakey_opts_t)); } static void _clear_datakey_keyaltnames (mongoc_client_encryption_datakey_opts_t *opts) { if (opts->keyaltnames) { for (uint32_t i = 0u; i < opts->keyaltnames_count; i++) { bson_free (opts->keyaltnames[i]); } bson_free (opts->keyaltnames); opts->keyaltnames = NULL; opts->keyaltnames_count = 0; } } void mongoc_client_encryption_datakey_opts_destroy (mongoc_client_encryption_datakey_opts_t *opts) { if (!opts) { return; } bson_destroy (opts->masterkey); _clear_datakey_keyaltnames (opts); bson_free (opts->keymaterial); bson_free (opts); } void mongoc_client_encryption_datakey_opts_set_masterkey (mongoc_client_encryption_datakey_opts_t *opts, const bson_t *masterkey) { if (!opts) { return; } bson_destroy (opts->masterkey); opts->masterkey = NULL; if (masterkey) { opts->masterkey = bson_copy (masterkey); } } void mongoc_client_encryption_datakey_opts_set_keyaltnames (mongoc_client_encryption_datakey_opts_t *opts, char **keyaltnames, uint32_t keyaltnames_count) { if (!opts) { return; } /* Free all first (if any have been set before). */ _clear_datakey_keyaltnames (opts); BSON_ASSERT (!opts->keyaltnames); if (keyaltnames_count) { opts->keyaltnames = bson_malloc (sizeof (char *) * keyaltnames_count); for (uint32_t i = 0u; i < keyaltnames_count; i++) { opts->keyaltnames[i] = bson_strdup (keyaltnames[i]); } opts->keyaltnames_count = keyaltnames_count; } } void mongoc_client_encryption_datakey_opts_set_keymaterial (mongoc_client_encryption_datakey_opts_t *opts, const uint8_t *data, uint32_t len) { if (!opts) { return; } if (opts->keymaterial) { bson_free (opts->keymaterial); } opts->keymaterial = bson_malloc (len); memcpy (opts->keymaterial, data, len); opts->keymaterial_len = len; } /*-------------------------------------------------------------------------- * Explicit Encryption options. *-------------------------------------------------------------------------- */ struct _mongoc_client_encryption_encrypt_range_opts_t { struct { bson_value_t value; bool set; } min; struct { bson_value_t value; bool set; } max; struct { int32_t value; bool set; } trim_factor; struct { int64_t value; bool set; } sparsity; struct { int32_t value; bool set; } precision; }; struct _mongoc_client_encryption_encrypt_opts_t { bson_value_t keyid; char *algorithm; char *keyaltname; struct { int64_t value; bool set; } contention_factor; char *query_type; mongoc_client_encryption_encrypt_range_opts_t *range_opts; }; mongoc_client_encryption_encrypt_opts_t * mongoc_client_encryption_encrypt_opts_new (void) { return bson_malloc0 (sizeof (mongoc_client_encryption_encrypt_opts_t)); } void mongoc_client_encryption_encrypt_range_opts_destroy (mongoc_client_encryption_encrypt_range_opts_t *range_opts) { if (!range_opts) { return; } if (range_opts->min.set) { bson_value_destroy (&range_opts->min.value); } if (range_opts->max.set) { bson_value_destroy (&range_opts->max.value); } bson_free (range_opts); } void mongoc_client_encryption_encrypt_opts_destroy (mongoc_client_encryption_encrypt_opts_t *opts) { if (!opts) { return; } mongoc_client_encryption_encrypt_range_opts_destroy (opts->range_opts); bson_value_destroy (&opts->keyid); bson_free (opts->algorithm); bson_free (opts->keyaltname); bson_free (opts->query_type); bson_free (opts); } void mongoc_client_encryption_encrypt_opts_set_keyid (mongoc_client_encryption_encrypt_opts_t *opts, const bson_value_t *keyid) { if (!opts) { return; } bson_value_destroy (&opts->keyid); memset (&opts->keyid, 0, sizeof (opts->keyid)); if (keyid) { bson_value_copy (keyid, &opts->keyid); } } void mongoc_client_encryption_encrypt_opts_set_keyaltname (mongoc_client_encryption_encrypt_opts_t *opts, const char *keyaltname) { if (!opts) { return; } bson_free (opts->keyaltname); opts->keyaltname = NULL; opts->keyaltname = bson_strdup (keyaltname); } void mongoc_client_encryption_encrypt_opts_set_algorithm (mongoc_client_encryption_encrypt_opts_t *opts, const char *algorithm) { if (!opts) { return; } bson_free (opts->algorithm); opts->algorithm = NULL; opts->algorithm = bson_strdup (algorithm); } void mongoc_client_encryption_encrypt_opts_set_contention_factor (mongoc_client_encryption_encrypt_opts_t *opts, int64_t contention_factor) { if (!opts) { return; } opts->contention_factor.value = contention_factor; opts->contention_factor.set = true; } void mongoc_client_encryption_encrypt_opts_set_query_type (mongoc_client_encryption_encrypt_opts_t *opts, const char *query_type) { if (!opts) { return; } bson_free (opts->query_type); opts->query_type = query_type ? bson_strdup (query_type) : NULL; } /*-------------------------------------------------------------------------- * Explicit Encryption Range Options *-------------------------------------------------------------------------- */ mongoc_client_encryption_encrypt_range_opts_t * mongoc_client_encryption_encrypt_range_opts_new (void) { return bson_malloc0 (sizeof (mongoc_client_encryption_encrypt_range_opts_t)); } void mongoc_client_encryption_encrypt_range_opts_set_trim_factor (mongoc_client_encryption_encrypt_range_opts_t *range_opts, int32_t trim_factor) { BSON_ASSERT_PARAM (range_opts); range_opts->trim_factor.set = true; range_opts->trim_factor.value = trim_factor; } void mongoc_client_encryption_encrypt_range_opts_set_sparsity (mongoc_client_encryption_encrypt_range_opts_t *range_opts, int64_t sparsity) { BSON_ASSERT_PARAM (range_opts); range_opts->sparsity.set = true; range_opts->sparsity.value = sparsity; } void mongoc_client_encryption_encrypt_range_opts_set_min (mongoc_client_encryption_encrypt_range_opts_t *range_opts, const bson_value_t *min) { BSON_ASSERT_PARAM (range_opts); BSON_ASSERT_PARAM (min); if (range_opts->min.set) { bson_value_destroy (&range_opts->min.value); } range_opts->min.set = true; bson_value_copy (min, &range_opts->min.value); } void mongoc_client_encryption_encrypt_range_opts_set_max (mongoc_client_encryption_encrypt_range_opts_t *range_opts, const bson_value_t *max) { BSON_ASSERT_PARAM (range_opts); BSON_ASSERT_PARAM (max); if (range_opts->max.set) { bson_value_destroy (&range_opts->max.value); } range_opts->max.set = true; bson_value_copy (max, &range_opts->max.value); } void mongoc_client_encryption_encrypt_range_opts_set_precision (mongoc_client_encryption_encrypt_range_opts_t *range_opts, int32_t precision) { BSON_ASSERT_PARAM (range_opts); range_opts->precision.set = true; range_opts->precision.value = precision; } static mongoc_client_encryption_encrypt_range_opts_t * copy_range_opts (const mongoc_client_encryption_encrypt_range_opts_t *opts) { BSON_ASSERT_PARAM (opts); mongoc_client_encryption_encrypt_range_opts_t *opts_new = mongoc_client_encryption_encrypt_range_opts_new (); if (opts->min.set) { bson_value_copy (&opts->min.value, &opts_new->min.value); opts_new->min.set = true; } if (opts->max.set) { bson_value_copy (&opts->max.value, &opts_new->max.value); opts_new->max.set = true; } if (opts->precision.set) { opts_new->precision.value = opts->precision.value; opts_new->precision.set = true; } opts_new->sparsity = opts->sparsity; opts_new->trim_factor = opts->trim_factor; return opts_new; } void mongoc_client_encryption_encrypt_opts_set_range_opts (mongoc_client_encryption_encrypt_opts_t *opts, const mongoc_client_encryption_encrypt_range_opts_t *range_opts) { BSON_ASSERT_PARAM (opts); if (opts->range_opts) { mongoc_client_encryption_encrypt_range_opts_destroy (opts->range_opts); opts->range_opts = NULL; } opts->range_opts = copy_range_opts (range_opts); } /*-------------------------------------------------------------------------- * RewrapManyDataKeyResult. *-------------------------------------------------------------------------- */ struct _mongoc_client_encryption_rewrap_many_datakey_result_t { bson_t bulk_write_result; }; mongoc_client_encryption_rewrap_many_datakey_result_t * mongoc_client_encryption_rewrap_many_datakey_result_new (void) { mongoc_client_encryption_rewrap_many_datakey_result_t *const res = BSON_ALIGNED_ALLOC0 (mongoc_client_encryption_rewrap_many_datakey_result_t); bson_init (&res->bulk_write_result); return res; } void mongoc_client_encryption_rewrap_many_datakey_result_destroy ( mongoc_client_encryption_rewrap_many_datakey_result_t *result) { if (!result) { return; } bson_destroy (&result->bulk_write_result); bson_free (result); } const bson_t * mongoc_client_encryption_rewrap_many_datakey_result_get_bulk_write_result ( mongoc_client_encryption_rewrap_many_datakey_result_t *result) { if (!result) { return NULL; } /* bulkWriteResult may be empty if no result of a bulk write operation has * been assigned to it. Treat as equivalent to an unset optional state. */ if (bson_empty (&result->bulk_write_result)) { return NULL; } return &result->bulk_write_result; } #ifndef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION static bool _disabled_error (bson_error_t *error) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "libmongoc is not built with support for Client-Side Field " "Level Encryption. Configure with " "ENABLE_CLIENT_SIDE_ENCRYPTION=ON."); return false; } bool _mongoc_cse_auto_encrypt (mongoc_client_t *client, const mongoc_cmd_t *cmd, mongoc_cmd_t *encrypted_cmd, bson_t *encrypted, bson_error_t *error) { BSON_UNUSED (client); BSON_UNUSED (cmd); BSON_UNUSED (encrypted_cmd); bson_init (encrypted); return _disabled_error (error); } bool _mongoc_cse_auto_decrypt ( mongoc_client_t *client, const char *db_name, const bson_t *reply, bson_t *decrypted, bson_error_t *error) { BSON_UNUSED (client); BSON_UNUSED (db_name); BSON_UNUSED (reply); bson_init (decrypted); return _disabled_error (error); } bool _mongoc_cse_client_enable_auto_encryption (mongoc_client_t *client, mongoc_auto_encryption_opts_t *opts /* may be NULL */, bson_error_t *error) { BSON_UNUSED (client); BSON_UNUSED (opts); return _disabled_error (error); } bool _mongoc_cse_client_pool_enable_auto_encryption (mongoc_topology_t *topology, mongoc_auto_encryption_opts_t *opts /* may be NULL */, bson_error_t *error) { BSON_UNUSED (topology); BSON_UNUSED (opts); return _disabled_error (error); } bool mongoc_client_encryption_create_datakey (mongoc_client_encryption_t *client_encryption, const char *kms_provider, const mongoc_client_encryption_datakey_opts_t *opts, bson_value_t *keyid, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (kms_provider); BSON_UNUSED (opts); if (keyid) { memset (keyid, 0, sizeof (*keyid)); } return _disabled_error (error); } bool mongoc_client_encryption_rewrap_many_datakey (mongoc_client_encryption_t *client_encryption, const bson_t *filter, const char *provider, const bson_t *master_key, mongoc_client_encryption_rewrap_many_datakey_result_t *result, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (filter); BSON_UNUSED (provider); BSON_UNUSED (master_key); BSON_UNUSED (result); return _disabled_error (error); } bool mongoc_client_encryption_delete_key (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, bson_t *reply, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (keyid); _mongoc_bson_init_if_set (reply); return _disabled_error (error); } bool mongoc_client_encryption_get_key (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, bson_t *key_doc, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (keyid); _mongoc_bson_init_if_set (key_doc); return _disabled_error (error); } mongoc_cursor_t * mongoc_client_encryption_get_keys (mongoc_client_encryption_t *client_encryption, bson_error_t *error) { BSON_UNUSED (client_encryption); _disabled_error (error); return NULL; } bool mongoc_client_encryption_add_key_alt_name (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, const char *keyaltname, bson_t *key_doc, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (keyid); BSON_UNUSED (keyaltname); _mongoc_bson_init_if_set (key_doc); return _disabled_error (error); } bool mongoc_client_encryption_remove_key_alt_name (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, const char *keyaltname, bson_t *key_doc, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (keyid); BSON_UNUSED (keyaltname); _mongoc_bson_init_if_set (key_doc); return _disabled_error (error); } bool mongoc_client_encryption_get_key_by_alt_name (mongoc_client_encryption_t *client_encryption, const char *keyaltname, bson_t *key_doc, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (keyaltname); _mongoc_bson_init_if_set (key_doc); return _disabled_error (error); } mongoc_client_encryption_t * mongoc_client_encryption_new (mongoc_client_encryption_opts_t *opts, bson_error_t *error) { BSON_UNUSED (opts); _disabled_error (error); return NULL; } void mongoc_client_encryption_destroy (mongoc_client_encryption_t *client_encryption) { BSON_UNUSED (client_encryption); } bool mongoc_client_encryption_encrypt (mongoc_client_encryption_t *client_encryption, const bson_value_t *value, mongoc_client_encryption_encrypt_opts_t *opts, bson_value_t *ciphertext, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (value); BSON_UNUSED (opts); if (ciphertext) { memset (ciphertext, 0, sizeof (*ciphertext)); } return _disabled_error (error); } bool mongoc_client_encryption_encrypt_expression (mongoc_client_encryption_t *client_encryption, const bson_t *expr, mongoc_client_encryption_encrypt_opts_t *opts, bson_t *expr_encrypted, bson_error_t *error) { BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT_PARAM (expr); BSON_ASSERT_PARAM (opts); BSON_ASSERT_PARAM (expr_encrypted); BSON_OPTIONAL_PARAM (error); bson_init (expr_encrypted); return _disabled_error (error); } bool mongoc_client_encryption_decrypt (mongoc_client_encryption_t *client_encryption, const bson_value_t *ciphertext, bson_value_t *value, bson_error_t *error) { BSON_UNUSED (client_encryption); BSON_UNUSED (ciphertext); if (value) { memset (value, 0, sizeof (*value)); } return _disabled_error (error); } bool _mongoc_cse_is_enabled (mongoc_client_t *client) { BSON_UNUSED (client); return false; } mongoc_collection_t * mongoc_client_encryption_create_encrypted_collection (mongoc_client_encryption_t *enc, struct _mongoc_database_t *database, const char *name, const bson_t *in_options, bson_t *opt_out_options, const char *const kms_provider, const bson_t *opt_masterkey, bson_error_t *error) { BSON_UNUSED (enc); BSON_UNUSED (database); BSON_UNUSED (name); BSON_UNUSED (in_options); BSON_UNUSED (opt_out_options); BSON_UNUSED (kms_provider); BSON_UNUSED (opt_masterkey); _disabled_error (error); return NULL; } #else /* Appends the range opts set by the user into a bson_t that can be passed to * libmongocrypt. */ static void append_bson_range_opts (bson_t *bson_range_opts, const mongoc_client_encryption_encrypt_opts_t *opts) { BSON_ASSERT_PARAM (bson_range_opts); BSON_ASSERT_PARAM (opts); if (opts->range_opts->min.set) { BSON_ASSERT (BSON_APPEND_VALUE (bson_range_opts, "min", &opts->range_opts->min.value)); } if (opts->range_opts->max.set) { BSON_ASSERT (BSON_APPEND_VALUE (bson_range_opts, "max", &opts->range_opts->max.value)); } if (opts->range_opts->precision.set) { BSON_ASSERT (BSON_APPEND_INT32 (bson_range_opts, "precision", opts->range_opts->precision.value)); } if (opts->range_opts->sparsity.set) { BSON_ASSERT (BSON_APPEND_INT64 (bson_range_opts, "sparsity", opts->range_opts->sparsity.value)); } if (opts->range_opts->trim_factor.set) { BSON_ASSERT (BSON_APPEND_INT32 (bson_range_opts, "trimFactor", opts->range_opts->trim_factor.value)); } } /*-------------------------------------------------------------------------- * * _prep_for_auto_encryption -- * If @cmd contains a type=1 payload (document sequence), convert it into * a type=0 payload (array payload). See OP_MSG spec for details. * Place the command BSON that should be encrypted into @out. * * Post-conditions: * @out is initialized and set to the full payload. If @cmd did not include * a type=1 payload, @out is statically initialized. Caller must not modify * @out after, but must call bson_destroy. * * -------------------------------------------------------------------------- */ static void _prep_for_auto_encryption (const mongoc_cmd_t *cmd, bson_t *out) { // If there are no document sequences (OP_MSG Section with payloadType=1), return the command unchanged. if (cmd->payloads_count == 0) { BSON_ASSERT (bson_init_static (out, bson_get_data (cmd->command), cmd->command->len)); return; } /* Otherwise, append the type=1 payload as an array. */ bson_copy_to (cmd->command, out); _mongoc_cmd_append_payload_as_array (cmd, out); } /* Return the mongocryptd client to use on a client with automatic encryption * enabled. * If @client_encrypted is single-threaded, use the client to mongocryptd. * If @client_encrypted is multi-threaded, use the client pool to mongocryptd. */ mongoc_client_t * _get_mongocryptd_client (mongoc_client_t *client_encrypted) { BSON_ASSERT_PARAM (client_encrypted); if (client_encrypted->topology->single_threaded) { return client_encrypted->topology->mongocryptd_client; } return mongoc_client_pool_pop (client_encrypted->topology->mongocryptd_client_pool); } void _release_mongocryptd_client (mongoc_client_t *client_encrypted, mongoc_client_t *mongocryptd_client) { BSON_ASSERT_PARAM (client_encrypted); if (!mongocryptd_client) { return; } if (!client_encrypted->topology->single_threaded) { mongoc_client_pool_push (client_encrypted->topology->mongocryptd_client_pool, mongocryptd_client); } } /* Return the key vault collection to use on a client with automatic encryption * enabled. * If no custom key vault client/pool is set, create a collection from the * @client_encrypted itself. * If @client_encrypted is single-threaded, use the client to mongocryptd to * create the collection. * If @client_encrypted is multi-threaded, use the client pool to mongocryptd * to create the collection. */ mongoc_collection_t * _get_keyvault_coll (mongoc_client_t *client_encrypted) { BSON_ASSERT_PARAM (client_encrypted); mongoc_write_concern_t *const wc = mongoc_write_concern_new (); mongoc_read_concern_t *const rc = mongoc_read_concern_new (); mongoc_client_t *keyvault_client; const char *db; const char *coll; mongoc_collection_t *res = NULL; db = client_encrypted->topology->keyvault_db; coll = client_encrypted->topology->keyvault_coll; if (client_encrypted->topology->single_threaded) { if (client_encrypted->topology->keyvault_client) { keyvault_client = client_encrypted->topology->keyvault_client; } else { keyvault_client = client_encrypted; } } else { if (client_encrypted->topology->keyvault_client_pool) { keyvault_client = mongoc_client_pool_pop (client_encrypted->topology->keyvault_client_pool); } else { keyvault_client = client_encrypted; } } res = mongoc_client_get_collection (keyvault_client, db, coll); mongoc_write_concern_set_w (wc, MONGOC_WRITE_CONCERN_W_MAJORITY); mongoc_collection_set_write_concern (res, wc); mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_MAJORITY); mongoc_collection_set_read_concern (res, rc); mongoc_write_concern_destroy (wc); mongoc_read_concern_destroy (rc); return res; } void _release_keyvault_coll (mongoc_client_t *client_encrypted, mongoc_collection_t *keyvault_coll) { mongoc_client_t *keyvault_client; BSON_ASSERT_PARAM (client_encrypted); if (!keyvault_coll) { return; } keyvault_client = keyvault_coll->client; mongoc_collection_destroy (keyvault_coll); if (!client_encrypted->topology->single_threaded && client_encrypted->topology->keyvault_client_pool) { mongoc_client_pool_push (client_encrypted->topology->keyvault_client_pool, keyvault_client); } } static bool _spawn_mongocryptd (const char *mongocryptd_spawn_path, const bson_t *mongocryptd_spawn_args, bson_error_t *error); /*-------------------------------------------------------------------------- * * _mongoc_cse_auto_encrypt -- * * Perform automatic encryption if enabled. * * Return: * True on success, false on error. * * Pre-conditions: * CSE is enabled on client or its associated client pool. * * Post-conditions: * If return false, @error is set. @encrypted is always initialized. * @encrypted_cmd is set to the mongoc_cmd_t to send, which may refer * to @encrypted. * If automatic encryption was bypassed, @encrypted is set to an empty * document, but @encrypted_cmd is a copy of @cmd. Caller must always * bson_destroy @encrypted. * *-------------------------------------------------------------------------- */ bool _mongoc_cse_auto_encrypt (mongoc_client_t *client_encrypted, const mongoc_cmd_t *cmd, mongoc_cmd_t *encrypted_cmd, bson_t *encrypted, bson_error_t *error) { bool ret = false; bson_t cmd_bson = BSON_INITIALIZER; bson_t *result = NULL; bson_iter_t iter; mongoc_client_t *mongocryptd_client = NULL; mongoc_collection_t *keyvault_coll = NULL; bool retried = false; ENTRY; BSON_ASSERT_PARAM (client_encrypted); bson_init (encrypted); if (client_encrypted->topology->bypass_auto_encryption) { memcpy (encrypted_cmd, cmd, sizeof (mongoc_cmd_t)); bson_destroy (&cmd_bson); RETURN (true); } if (cmd->server_stream->sd->max_wire_version < WIRE_VERSION_CSE) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "%s", "Auto-encryption requires a minimum MongoDB version of 4.2"); GOTO (fail); } /* Construct the command we're sending to libmongocrypt. If cmd includes a * type 1 payload, convert it to a type 0 payload. */ bson_destroy (&cmd_bson); _prep_for_auto_encryption (cmd, &cmd_bson); keyvault_coll = _get_keyvault_coll (client_encrypted); mongocryptd_client = _get_mongocryptd_client (client_encrypted); retry: bson_destroy (encrypted); if (!_mongoc_crypt_auto_encrypt (client_encrypted->topology->crypt, keyvault_coll, mongocryptd_client, client_encrypted, cmd->db_name, &cmd_bson, encrypted, error)) { /* From the Client-Side Encryption spec: If spawning is necessary, the * driver MUST spawn mongocryptd whenever server selection on the * MongoClient to mongocryptd fails. If the MongoClient fails to connect * after spawning, the server selection error is propagated to the user. */ if (!client_encrypted->topology->mongocryptd_bypass_spawn && error->domain == MONGOC_ERROR_SERVER_SELECTION && !retried) { if (!_spawn_mongocryptd (client_encrypted->topology->mongocryptd_spawn_path, client_encrypted->topology->mongocryptd_spawn_args, error)) { GOTO (fail); } /* Respawn and retry. */ memset (error, 0, sizeof (*error)); retried = true; GOTO (retry); } GOTO (fail); } /* Re-append $db if encryption stripped it. */ if (!bson_iter_init_find (&iter, encrypted, "$db")) { BSON_APPEND_UTF8 (encrypted, "$db", cmd->db_name); } /* Create the modified cmd_t. */ memcpy (encrypted_cmd, cmd, sizeof (mongoc_cmd_t)); /* Modify the mongoc_cmd_t and clear the payloads, since * _mongoc_cse_auto_encrypt converted the payloads into an embedded array. */ encrypted_cmd->payloads_count = 0; encrypted_cmd->command = encrypted; ret = true; fail: bson_destroy (result); bson_destroy (&cmd_bson); _release_mongocryptd_client (client_encrypted, mongocryptd_client); _release_keyvault_coll (client_encrypted, keyvault_coll); RETURN (ret); } /*-------------------------------------------------------------------------- * * _mongoc_cse_auto_decrypt -- * * Perform automatic decryption. * * Return: * True on success, false on error. * * Pre-conditions: * FLE is enabled on client or its associated client pool. * * Post-conditions: * If return false, @error is set. @decrypted is always initialized. * *-------------------------------------------------------------------------- */ bool _mongoc_cse_auto_decrypt ( mongoc_client_t *client_encrypted, const char *db_name, const bson_t *reply, bson_t *decrypted, bson_error_t *error) { bool ret = false; mongoc_collection_t *keyvault_coll = NULL; ENTRY; BSON_ASSERT_PARAM (client_encrypted); BSON_UNUSED (db_name); keyvault_coll = _get_keyvault_coll (client_encrypted); if (!_mongoc_crypt_auto_decrypt (client_encrypted->topology->crypt, keyvault_coll, reply, decrypted, error)) { GOTO (fail); } ret = true; fail: _release_keyvault_coll (client_encrypted, keyvault_coll); RETURN (ret); } static void _uri_construction_error (bson_error_t *error) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "Error constructing URI to mongocryptd"); } #ifdef _WIN32 static bool _do_spawn (const char *path, char **args, bson_error_t *error) { mcommon_string_append_t command; char **arg; PROCESS_INFORMATION process_information; STARTUPINFO startup_info; /* Construct the full command, quote path and arguments. */ mcommon_string_new_as_append (&command); mcommon_string_append (&command, "\""); if (path) { mcommon_string_append (&command, path); } mcommon_string_append (&command, "mongocryptd.exe"); mcommon_string_append (&command, "\""); /* skip the "mongocryptd" first arg. */ arg = args + 1; while (*arg) { mcommon_string_append (&command, " \""); mcommon_string_append (&command, *arg); mcommon_string_append (&command, "\""); arg++; } ZeroMemory (&process_information, sizeof (process_information)); ZeroMemory (&startup_info, sizeof (startup_info)); startup_info.cb = sizeof (startup_info); if (!CreateProcessA (NULL, mcommon_str_from_append (&command), NULL, NULL, false /* inherit descriptors */, DETACHED_PROCESS /* FLAGS */, NULL /* environment */, NULL /* current directory */, &startup_info, &process_information)) { long lastError = GetLastError (); LPSTR message = NULL; FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastError, 0, (LPSTR) &message, 0, NULL); bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "failed to spawn mongocryptd: %s", message); LocalFree (message); mcommon_string_from_append_destroy (&command); return false; } mcommon_string_from_append_destroy (&command); return true; } #else /*-------------------------------------------------------------------------- * * _do_spawn -- * * Spawn process defined by arg[0] on POSIX systems. * * Note, if mongocryptd fails to spawn (due to not being found on the path), * an error is not reported and true is returned. Users will get an error * later, upon first attempt to use mongocryptd. * * These comments refer to three distinct processes: parent, child, and * mongocryptd. * - parent is initial calling process * - child is the first forked child. It fork-execs mongocryptd then * terminates. This makes mongocryptd an orphan, making it immediately * adopted by the init process. * - mongocryptd is the final background daemon (grandchild process). * * Return: * False if an error definitely occurred. Returns true if no reportable * error occurred (though an error may have occurred in starting * mongocryptd, resulting in the process not running). * * Arguments: * args - A NULL terminated list of arguments. The first argument MUST * be the name of the process to execute, and the last argument MUST be * NULL. * * Post-conditions: * If return false, @error is set. * *-------------------------------------------------------------------------- */ static bool _do_spawn (const char *path, char **args, bson_error_t *error) { pid_t pid; int fd; char *to_exec; // String allocation must be done up-front, as allocation is not fork-safe. if (path) { to_exec = bson_strdup_printf ("%s%s", path, args[0]); } else { to_exec = bson_strdup (args[0]); } /* Fork. The child will terminate immediately (after fork-exec'ing * mongocryptd). This orphans mongocryptd, and allows parent to wait on * child. */ pid = fork (); if (pid < 0) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "failed to fork (errno=%d) '%s'", errno, strerror (errno)); bson_free (to_exec); return false; } else if (pid > 0) { int child_status; /* Child will spawn mongocryptd and immediately terminate to turn * mongocryptd into an orphan. */ if (waitpid (pid, &child_status, 0 /* options */) < 0) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "failed to wait for child (errno=%d) '%s'", errno, strerror (errno)); bson_free (to_exec); return false; } /* parent is done at this point, return. */ bson_free (to_exec); return true; } /* We're no longer in the parent process. Errors encountered result in an * exit. * Note, we're not logging here, because that would require the user's log * callback to be fork-safe. */ /* Start a new session for the child, so it is not bound to the current * session (e.g. terminal session). */ if (setsid () < 0) { _exit (EXIT_FAILURE); } /* Fork again. Child terminates so mongocryptd gets orphaned and immedately * adopted by init. */ signal (SIGHUP, SIG_IGN); pid = fork (); if (pid < 0) { _exit (EXIT_FAILURE); } else if (pid > 0) { /* Child terminates immediately. */ _exit (EXIT_SUCCESS); } /* If we later decide to change the working directory for the pid file path, * possibly change the process's working directory with chdir like: `chdir * (default_pid_path)`. Currently pid file ends up in application's working * directory. */ /* Set the user file creation mask to zero. */ umask (0); /* Close and reopen stdin. */ fd = open ("/dev/null", O_RDONLY); if (fd < 0) { _exit (EXIT_FAILURE); } dup2 (fd, STDIN_FILENO); close (fd); /* Close and reopen stdout. */ fd = open ("/dev/null", O_WRONLY); if (fd < 0) { _exit (EXIT_FAILURE); } if (dup2 (fd, STDOUT_FILENO) < 0 || close (fd) < 0) { _exit (EXIT_FAILURE); } /* Close and reopen stderr. */ fd = open ("/dev/null", O_RDWR); if (fd < 0) { _exit (EXIT_FAILURE); } if (dup2 (fd, STDERR_FILENO) < 0 || close (fd) < 0) { _exit (EXIT_FAILURE); } if (execvp (to_exec, args) < 0) { /* Need to exit. */ _exit (EXIT_FAILURE); } /* Will never execute. */ return false; } #endif /*-------------------------------------------------------------------------- * * _spawn_mongocryptd -- * * Attempt to spawn mongocryptd as a background process. * * Return: * False if an error definitely occurred. Returns true if no reportable * error occurred (though an error may have occurred in starting * mongocryptd, resulting in the process not running). * * Arguments: * mongocryptd_spawn_path May be NULL, otherwise the path to mongocryptd. * mongocryptd_spawn_args May be NULL, otherwise a bson_iter_t to the * value "mongocryptdSpawnArgs" in AutoEncryptionOpts.extraOptions * (see spec). * * Post-conditions: * If return false, @error is set. * *-------------------------------------------------------------------------- */ static bool _spawn_mongocryptd (const char *mongocryptd_spawn_path, const bson_t *mongocryptd_spawn_args, bson_error_t *error) { char **args = NULL; bson_iter_t iter; bool passed_idle_shutdown_timeout_secs = false; int num_args = 2; /* for leading "mongocrypt" and trailing NULL */ int i; bool ret; /* iterate once to get length and validate all are strings */ if (mongocryptd_spawn_args) { bson_iter_init (&iter, mongocryptd_spawn_args); while (bson_iter_next (&iter)) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "invalid argument for mongocryptd, must be string"); return false; } /* Check if the arg starts with --idleShutdownTimeoutSecs= or is equal * to --idleShutdownTimeoutSecs */ if (0 == strncmp ("--idleShutdownTimeoutSecs=", bson_iter_utf8 (&iter, NULL), 26) || 0 == strcmp ("--idleShutdownTimeoutSecs", bson_iter_utf8 (&iter, NULL))) { passed_idle_shutdown_timeout_secs = true; } num_args++; } } if (!passed_idle_shutdown_timeout_secs) { /* add one more */ num_args++; } args = (char **) bson_malloc (sizeof (char *) * num_args); i = 0; args[i++] = "mongocryptd"; if (mongocryptd_spawn_args) { bson_iter_init (&iter, mongocryptd_spawn_args); while (bson_iter_next (&iter)) { args[i++] = (char *) bson_iter_utf8 (&iter, NULL); } } if (!passed_idle_shutdown_timeout_secs) { args[i++] = "--idleShutdownTimeoutSecs=60"; } BSON_ASSERT (i == num_args - 1); args[i++] = NULL; ret = _do_spawn (mongocryptd_spawn_path, args, error); bson_free (args); return ret; } static bool _parse_extra (const bson_t *extra, mongoc_topology_t *topology, mongoc_uri_t **uri, bson_error_t *error) { bson_iter_t iter; bool ret = false; ENTRY; *uri = NULL; if (extra) { if (bson_iter_init_find (&iter, extra, "mongocryptdBypassSpawn")) { if (!BSON_ITER_HOLDS_BOOL (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Expected bool for option 'mongocryptdBypassSpawn'"); GOTO (fail); } topology->mongocryptd_bypass_spawn = bson_iter_bool (&iter); } if (bson_iter_init_find (&iter, extra, "mongocryptdSpawnPath")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Expected string for option 'mongocryptdSpawnPath'"); GOTO (fail); } topology->mongocryptd_spawn_path = bson_strdup (bson_iter_utf8 (&iter, NULL)); } if (bson_iter_init_find (&iter, extra, "mongocryptdSpawnArgs")) { uint32_t array_len; const uint8_t *array_data; if (!BSON_ITER_HOLDS_ARRAY (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Expected array for option 'mongocryptdSpawnArgs'"); GOTO (fail); } bson_iter_array (&iter, &array_len, &array_data); topology->mongocryptd_spawn_args = bson_new_from_data (array_data, array_len); } if (bson_iter_init_find (&iter, extra, "mongocryptdURI")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Expected string for option 'mongocryptdURI'"); GOTO (fail); } *uri = mongoc_uri_new_with_error (bson_iter_utf8 (&iter, NULL), error); if (!*uri) { GOTO (fail); } } if (bson_iter_init_find (&iter, extra, "cryptSharedLibPath")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Expected a string for 'cryptSharedLibPath'"); GOTO (fail); } size_t len; const char *ptr = bson_iter_utf8_unsafe (&iter, &len); bson_free (topology->clientSideEncryption.autoOptions.extraOptions.cryptSharedLibPath); topology->clientSideEncryption.autoOptions.extraOptions.cryptSharedLibPath = bson_strdup (ptr); } if (bson_iter_init_find (&iter, extra, "cryptSharedLibRequired")) { if (!BSON_ITER_HOLDS_BOOL (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Expected a bool for 'cryptSharedLibRequired'"); GOTO (fail); } topology->clientSideEncryption.autoOptions.extraOptions.cryptSharedLibRequired = bson_iter_bool_unsafe (&iter); } } if (!*uri) { *uri = mongoc_uri_new_with_error ("mongodb://localhost:27020", error); if (!*uri) { GOTO (fail); } if (!mongoc_uri_set_option_as_int32 (*uri, MONGOC_URI_SERVERSELECTIONTIMEOUTMS, 10000)) { _uri_construction_error (error); GOTO (fail); } } ret = true; fail: RETURN (ret); } bool _mongoc_cse_client_enable_auto_encryption (mongoc_client_t *client, mongoc_auto_encryption_opts_t *opts, bson_error_t *error) { bool ret = false; mongoc_uri_t *mongocryptd_uri = NULL; ENTRY; BSON_ASSERT (client); if (!client->topology->single_threaded) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Automatic encryption on pooled clients must be set on the pool"); GOTO (fail); } if (!opts) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Auto encryption options required"); GOTO (fail); } if (opts->keyvault_client_pool) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "The key vault client pool only applies to a client " "pool, not a single threaded client"); GOTO (fail); } if (opts->keyvault_client && !opts->keyvault_client->topology->single_threaded) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "The key vault client must be single threaded, not be " "from a client pool"); GOTO (fail); } /* Check for required options */ if (!opts->keyvault_db || !opts->keyvault_coll) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Key vault namespace option required"); GOTO (fail); } if (!opts->kms_providers) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "KMS providers option required"); GOTO (fail); } if (client->topology->cse_state != MONGOC_CSE_DISABLED) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "Automatic encryption already set"); GOTO (fail); } else { client->topology->cse_state = MONGOC_CSE_ENABLED; } if (!_parse_extra (opts->extra, client->topology, &mongocryptd_uri, error)) { GOTO (fail); } client->topology->crypt = _mongoc_crypt_new (opts->kms_providers, opts->schema_map, opts->encrypted_fields_map, opts->tls_opts, client->topology->clientSideEncryption.autoOptions.extraOptions.cryptSharedLibPath, client->topology->clientSideEncryption.autoOptions.extraOptions.cryptSharedLibRequired, opts->bypass_auto_encryption, opts->bypass_query_analysis, opts->creds_cb, opts->cache_expiration_ms, error); if (!client->topology->crypt) { GOTO (fail); } const bool have_crypt_shared = _mongoc_crypt_get_crypt_shared_version (client->topology->crypt) != NULL; client->topology->bypass_auto_encryption = opts->bypass_auto_encryption; client->topology->bypass_query_analysis = opts->bypass_query_analysis; if (!client->topology->bypass_auto_encryption && !client->topology->bypass_query_analysis && !have_crypt_shared) { if (!client->topology->mongocryptd_bypass_spawn) { if (!_spawn_mongocryptd ( client->topology->mongocryptd_spawn_path, client->topology->mongocryptd_spawn_args, error)) { GOTO (fail); } } /* By default, single threaded clients set serverSelectionTryOnce to * true, which means server selection fails if a topology scan fails * the first time (i.e. it will not make repeat attempts until * serverSelectionTimeoutMS expires). Override this, since the first * attempt to connect to mongocryptd may fail when spawning, as it * takes some time for mongocryptd to listen on sockets. */ if (!mongoc_uri_set_option_as_bool (mongocryptd_uri, MONGOC_URI_SERVERSELECTIONTRYONCE, false)) { _uri_construction_error (error); GOTO (fail); } client->topology->mongocryptd_client = mongoc_client_new_from_uri (mongocryptd_uri); if (!client->topology->mongocryptd_client) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "Unable to create client to mongocryptd"); GOTO (fail); } /* Similarly, single threaded clients will by default wait for 5 second * cooldown period after failing to connect to a server before making * another attempt. Meaning if the first attempt to mongocryptd fails * to connect, then the user observes a 5 second delay. This is not * configurable in the URI, so override. */ _mongoc_topology_bypass_cooldown (client->topology->mongocryptd_client->topology); /* Also, since single threaded server selection can foreseeably take * connectTimeoutMS (which by default is longer than 10 seconds), reduce * this as well. */ if (!mongoc_uri_set_option_as_int32 (mongocryptd_uri, MONGOC_URI_CONNECTTIMEOUTMS, 10000)) { _uri_construction_error (error); GOTO (fail); } } client->topology->keyvault_db = bson_strdup (opts->keyvault_db); client->topology->keyvault_coll = bson_strdup (opts->keyvault_coll); if (opts->keyvault_client) { client->topology->keyvault_client = opts->keyvault_client; } if (opts->encrypted_fields_map) { client->topology->encrypted_fields_map = bson_copy (opts->encrypted_fields_map); } ret = true; fail: mongoc_uri_destroy (mongocryptd_uri); RETURN (ret); } bool _mongoc_cse_client_pool_enable_auto_encryption (mongoc_topology_t *topology, mongoc_auto_encryption_opts_t *opts, bson_error_t *error) { bool setup_okay = false; mongoc_uri_t *mongocryptd_uri = NULL; mongoc_topology_cse_state_t prev_cse_state = MONGOC_CSE_STARTING; BSON_ASSERT (topology); if (!opts) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Auto encryption options required"); GOTO (fail); } if (opts->keyvault_client) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "The key vault client only applies to a single threaded " "client not a client pool. Set a key vault client pool"); GOTO (fail); } /* Check for required options */ if (!opts->keyvault_db || !opts->keyvault_coll) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Key vault namespace option required"); GOTO (fail); } if (!opts->kms_providers) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "KMS providers option required"); GOTO (fail); } prev_cse_state = mcommon_atomic_int_compare_exchange_strong ( (int *) &topology->cse_state, MONGOC_CSE_DISABLED, MONGOC_CSE_STARTING, mcommon_memory_order_acquire); while (prev_cse_state == MONGOC_CSE_STARTING) { /* Another thread is starting client-side encryption. It may take some * time to start, but don't continue until it is finished. */ bson_thrd_yield (); prev_cse_state = mcommon_atomic_int_compare_exchange_strong ( (int *) &topology->cse_state, MONGOC_CSE_DISABLED, MONGOC_CSE_STARTING, mcommon_memory_order_acquire); } if (prev_cse_state == MONGOC_CSE_ENABLED) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "Automatic encryption already set"); GOTO (fail); } /* We just set the CSE state from DISABLED to STARTING. Start it up now. */ if (!_parse_extra (opts->extra, topology, &mongocryptd_uri, error)) { GOTO (fail); } topology->crypt = _mongoc_crypt_new (opts->kms_providers, opts->schema_map, opts->encrypted_fields_map, opts->tls_opts, topology->clientSideEncryption.autoOptions.extraOptions.cryptSharedLibPath, topology->clientSideEncryption.autoOptions.extraOptions.cryptSharedLibRequired, opts->bypass_auto_encryption, opts->bypass_query_analysis, opts->creds_cb, opts->cache_expiration_ms, error); if (!topology->crypt) { GOTO (fail); } topology->bypass_auto_encryption = opts->bypass_auto_encryption; topology->bypass_query_analysis = opts->bypass_query_analysis; if (!topology->bypass_auto_encryption && !topology->bypass_query_analysis) { if (!topology->mongocryptd_bypass_spawn) { if (!_spawn_mongocryptd (topology->mongocryptd_spawn_path, topology->mongocryptd_spawn_args, error)) { GOTO (fail); } } topology->mongocryptd_client_pool = mongoc_client_pool_new (mongocryptd_uri); if (!topology->mongocryptd_client_pool) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "Unable to create client pool to mongocryptd"); GOTO (fail); } } topology->keyvault_db = bson_strdup (opts->keyvault_db); topology->keyvault_coll = bson_strdup (opts->keyvault_coll); if (opts->keyvault_client_pool) { topology->keyvault_client_pool = opts->keyvault_client_pool; } if (opts->encrypted_fields_map) { topology->encrypted_fields_map = bson_copy (opts->encrypted_fields_map); } setup_okay = true; BSON_ASSERT (prev_cse_state == MONGOC_CSE_DISABLED); fail: if (prev_cse_state == MONGOC_CSE_DISABLED) { /* We need to set the new CSE state. */ mongoc_topology_cse_state_t new_state = setup_okay ? MONGOC_CSE_ENABLED : MONGOC_CSE_DISABLED; mcommon_atomic_int_exchange ((int *) &topology->cse_state, new_state, mcommon_memory_order_release); } mongoc_uri_destroy (mongocryptd_uri); RETURN (setup_okay); } struct _mongoc_client_encryption_t { _mongoc_crypt_t *crypt; mongoc_collection_t *keyvault_coll; bson_t *kms_providers; }; mongoc_client_encryption_t * mongoc_client_encryption_new (mongoc_client_encryption_opts_t *opts, bson_error_t *error) { mongoc_client_encryption_t *client_encryption = NULL; bool success = false; mongoc_write_concern_t *wc = NULL; mongoc_read_concern_t *rc = NULL; /* Check for required options */ if (!opts || !opts->keyvault_client || !opts->keyvault_db || !opts->keyvault_coll) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Key vault client and namespace option required"); goto fail; } if (!opts->kms_providers) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "KMS providers option required"); goto fail; } client_encryption = bson_malloc0 (sizeof (*client_encryption)); client_encryption->keyvault_coll = mongoc_client_get_collection (opts->keyvault_client, opts->keyvault_db, opts->keyvault_coll); wc = mongoc_write_concern_new (); mongoc_write_concern_set_w (wc, MONGOC_WRITE_CONCERN_W_MAJORITY); mongoc_collection_set_write_concern (client_encryption->keyvault_coll, wc); rc = mongoc_read_concern_new (); mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_MAJORITY); mongoc_collection_set_read_concern (client_encryption->keyvault_coll, rc); client_encryption->kms_providers = bson_copy (opts->kms_providers); client_encryption->crypt = _mongoc_crypt_new (opts->kms_providers, NULL /* schema_map */, NULL /* encrypted_fields_map */, opts->tls_opts, NULL /* No crypt_shared path */, false /* crypt_shared not requried */, true, /* bypassAutoEncryption (We are explicit) */ false, /* bypass_query_analysis. Not applicable. */ opts->creds_cb, opts->cache_expiration_ms, error); if (!client_encryption->crypt) { goto fail; } success = true; fail: mongoc_write_concern_destroy (wc); mongoc_read_concern_destroy (rc); if (!success) { mongoc_client_encryption_destroy (client_encryption); return NULL; } return client_encryption; } void mongoc_client_encryption_destroy (mongoc_client_encryption_t *client_encryption) { if (!client_encryption) { return; } _mongoc_crypt_destroy (client_encryption->crypt); mongoc_collection_destroy (client_encryption->keyvault_coll); bson_destroy (client_encryption->kms_providers); bson_free (client_encryption); } static bool _coll_has_write_concern_majority (const mongoc_collection_t *coll) { const mongoc_write_concern_t *const wc = mongoc_collection_get_write_concern (coll); return wc && mongoc_write_concern_get_wmajority (wc); } static bool _coll_has_read_concern_majority (const mongoc_collection_t *coll) { const mongoc_read_concern_t *const rc = mongoc_collection_get_read_concern (coll); const char *const level = rc ? mongoc_read_concern_get_level (rc) : NULL; return level && strcmp (level, MONGOC_READ_CONCERN_LEVEL_MAJORITY) == 0; } bool mongoc_client_encryption_create_datakey (mongoc_client_encryption_t *client_encryption, const char *kms_provider, const mongoc_client_encryption_datakey_opts_t *opts, bson_value_t *keyid, bson_error_t *error) { bool ret = false; bson_t datakey = BSON_INITIALIZER; bson_t insert_opts = BSON_INITIALIZER; ENTRY; BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT (_coll_has_write_concern_majority (client_encryption->keyvault_coll)); if (!opts) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "required 'opts' unset"); GOTO (fail); } /* reset, so it is safe for caller to call bson_value_destroy on error or * success. */ if (keyid) { keyid->value_type = BSON_TYPE_EOD; } bson_destroy (&datakey); if (!_mongoc_crypt_create_datakey (client_encryption->crypt, kms_provider, opts->masterkey, opts->keyaltnames, opts->keyaltnames_count, opts->keymaterial, opts->keymaterial_len, &datakey, error)) { GOTO (fail); } if (!mongoc_collection_insert_one ( client_encryption->keyvault_coll, &datakey, NULL /* opts */, NULL /* reply */, error)) { GOTO (fail); } if (keyid) { bson_iter_t iter; const bson_value_t *id_value; if (!bson_iter_init_find (&iter, &datakey, "_id")) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "data key not did not contain _id"); GOTO (fail); } else if (!BSON_ITER_HOLDS_BINARY (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "data key _id does not contain binary"); GOTO (fail); } else { id_value = bson_iter_value (&iter); bson_value_copy (id_value, keyid); } } ret = true; fail: bson_destroy (&insert_opts); bson_destroy (&datakey); RETURN (ret); } bool mongoc_client_encryption_rewrap_many_datakey (mongoc_client_encryption_t *client_encryption, const bson_t *filter, const char *provider, const bson_t *master_key, mongoc_client_encryption_rewrap_many_datakey_result_t *result, bson_error_t *error) { bson_t keys = BSON_INITIALIZER; bson_t local_result = BSON_INITIALIZER; bson_t *const bulk_write_result = result ? &result->bulk_write_result : &local_result; mongoc_bulk_operation_t *bulk = NULL; bson_iter_t iter; bool ret = false; ENTRY; BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT (_coll_has_read_concern_majority (client_encryption->keyvault_coll)); BSON_ASSERT (_coll_has_write_concern_majority (client_encryption->keyvault_coll)); bson_reinit (bulk_write_result); if (master_key && !provider) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "expected 'provider' to be set to identify type of 'master_key'"); GOTO (fail); } if (!_mongoc_crypt_rewrap_many_datakey ( client_encryption->crypt, client_encryption->keyvault_coll, filter, provider, master_key, &keys, error)) { GOTO (fail); } /* No keys rewrapped, no key documents to update. */ if (bson_empty (&keys)) { bson_destroy (&keys); bson_destroy (&local_result); return true; } bulk = mongoc_collection_create_bulk_operation_with_opts (client_encryption->keyvault_coll, NULL); BSON_ASSERT (bulk); if (!bson_iter_init_find (&iter, &keys, "v")) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "result did not contain expected field 'v'"); GOTO (fail); } if (!BSON_ITER_HOLDS_ARRAY (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "result did not return an array as expected"); GOTO (fail); } BSON_ASSERT (bson_iter_recurse (&iter, &iter)); while (bson_iter_next (&iter)) { const uint8_t *data = NULL; uint32_t len = 0u; bson_t key; bson_iter_t key_iter; bson_subtype_t subtype; bson_t selector = BSON_INITIALIZER; bson_t document = BSON_INITIALIZER; bool doc_success = false; bson_iter_document (&iter, &len, &data); if (!data || !bson_init_static (&key, data, len)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "element is not a valid BSON document"); goto doc_done; } /* Find _id and use as selector. */ { if (!bson_iter_init_find (&key_iter, &key, "_id")) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "could not find _id in key document"); goto doc_done; } bson_iter_binary (&key_iter, &subtype, &len, &data); if (!data || subtype != BSON_SUBTYPE_UUID) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "expected _id in key document to be a UUID"); goto doc_done; } BSON_ASSERT (bson_append_iter (&selector, "_id", 3, &key_iter)); } /* Find and include potentially updated fields. */ { bson_t child; BSON_ASSERT (BSON_APPEND_DOCUMENT_BEGIN (&document, "$set", &child)); { if (bson_iter_init_find (&key_iter, &key, "masterKey")) { BSON_ASSERT (bson_append_iter (&child, "masterKey", -1, &key_iter)); } if (bson_iter_init_find (&key_iter, &key, "keyMaterial")) { BSON_ASSERT (bson_append_iter (&child, "keyMaterial", -1, &key_iter)); } } BSON_ASSERT (bson_append_document_end (&document, &child)); } /* Update updateDate field. */ BCON_APPEND (&document, "$currentDate", "{", "updateDate", BCON_BOOL (true), "}"); if (!mongoc_bulk_operation_update_one_with_opts (bulk, &selector, &document, NULL, error)) { goto doc_done; } doc_success = true; doc_done: bson_destroy (&key); bson_destroy (&selector); bson_destroy (&document); if (!doc_success) { GOTO (fail); } } if (!mongoc_bulk_operation_execute (bulk, bulk_write_result, error)) { GOTO (fail); } ret = true; fail: bson_destroy (&keys); bson_destroy (&local_result); mongoc_bulk_operation_destroy (bulk); RETURN (ret); } bool mongoc_client_encryption_delete_key (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, bson_t *reply, bson_error_t *error) { bool ret = false; bson_t selector = BSON_INITIALIZER; ENTRY; BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT_PARAM (keyid); BSON_ASSERT (_coll_has_write_concern_majority (client_encryption->keyvault_coll)); BSON_ASSERT (keyid->value_type == BSON_TYPE_BINARY); BSON_ASSERT (keyid->value.v_binary.subtype == BSON_SUBTYPE_UUID); BSON_ASSERT (keyid->value.v_binary.data_len > 0u); BSON_ASSERT (BSON_APPEND_BINARY ( &selector, "_id", keyid->value.v_binary.subtype, keyid->value.v_binary.data, keyid->value.v_binary.data_len)); ret = mongoc_collection_delete_one (client_encryption->keyvault_coll, &selector, NULL, reply, error); bson_destroy (&selector); RETURN (ret); } bool mongoc_client_encryption_get_key (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, bson_t *key_doc, bson_error_t *error) { bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor = NULL; bool ret = false; ENTRY; BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT_PARAM (keyid); BSON_ASSERT (keyid->value_type == BSON_TYPE_BINARY); BSON_ASSERT (keyid->value.v_binary.subtype == BSON_SUBTYPE_UUID); BSON_ASSERT (keyid->value.v_binary.data_len > 0u); BSON_ASSERT (BSON_APPEND_BINARY ( &filter, "_id", keyid->value.v_binary.subtype, keyid->value.v_binary.data, keyid->value.v_binary.data_len)); BSON_ASSERT (_coll_has_read_concern_majority (client_encryption->keyvault_coll)); _mongoc_bson_init_if_set (key_doc); cursor = mongoc_collection_find_with_opts (client_encryption->keyvault_coll, &filter, NULL, NULL); ret = !mongoc_cursor_error (cursor, error); if (ret && key_doc) { const bson_t *bson = NULL; if (mongoc_cursor_next (cursor, &bson)) { bson_copy_to (bson, key_doc); } else if (mongoc_cursor_error (cursor, error)) { ret = false; } } bson_destroy (&filter); mongoc_cursor_destroy (cursor); RETURN (ret); } mongoc_cursor_t * mongoc_client_encryption_get_keys (mongoc_client_encryption_t *client_encryption, bson_error_t *error) { mongoc_cursor_t *cursor = NULL; bson_t filter = BSON_INITIALIZER; ENTRY; BSON_UNUSED (error); BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT (_coll_has_read_concern_majority (client_encryption->keyvault_coll)); /* If an error occurred, user should query cursor error. */ cursor = mongoc_collection_find_with_opts (client_encryption->keyvault_coll, &filter, NULL, NULL); bson_destroy (&filter); RETURN (cursor); } bool mongoc_client_encryption_add_key_alt_name (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, const char *keyaltname, bson_t *key_doc, bson_error_t *error) { mongoc_find_and_modify_opts_t *const opts = mongoc_find_and_modify_opts_new (); bson_t query = BSON_INITIALIZER; bool ret = false; bson_t local_reply; ENTRY; BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT_PARAM (keyid); BSON_ASSERT_PARAM (keyaltname); BSON_ASSERT (_coll_has_read_concern_majority (client_encryption->keyvault_coll)); BSON_ASSERT (_coll_has_write_concern_majority (client_encryption->keyvault_coll)); BSON_ASSERT (keyid->value_type == BSON_TYPE_BINARY); BSON_ASSERT (keyid->value.v_binary.subtype == BSON_SUBTYPE_UUID); BSON_ASSERT (keyid->value.v_binary.data_len > 0u); BSON_ASSERT (BSON_APPEND_BINARY ( &query, "_id", keyid->value.v_binary.subtype, keyid->value.v_binary.data, keyid->value.v_binary.data_len)); _mongoc_bson_init_if_set (key_doc); { bson_t *const update = BCON_NEW ("$addToSet", "{", "keyAltNames", BCON_UTF8 (keyaltname), "}"); BSON_ASSERT (mongoc_find_and_modify_opts_set_update (opts, update)); bson_destroy (update); } ret = mongoc_collection_find_and_modify_with_opts (client_encryption->keyvault_coll, &query, opts, &local_reply, error); if (ret && key_doc) { bson_iter_t iter; if (bson_iter_init_find (&iter, &local_reply, "value")) { const bson_value_t *const value = bson_iter_value (&iter); if (value->value_type == BSON_TYPE_DOCUMENT) { bson_t bson; BSON_ASSERT (bson_init_static (&bson, value->value.v_doc.data, value->value.v_doc.data_len)); bson_copy_to (&bson, key_doc); bson_destroy (&bson); } else if (value->value_type == BSON_TYPE_NULL) { bson_t bson = BSON_INITIALIZER; bson_copy_to (&bson, key_doc); bson_destroy (&bson); } else { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "expected field value to be a document or null"); ret = false; } } } mongoc_find_and_modify_opts_destroy (opts); bson_destroy (&query); bson_destroy (&local_reply); RETURN (ret); } bool mongoc_client_encryption_remove_key_alt_name (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, const char *keyaltname, bson_t *key_doc, bson_error_t *error) { bson_t query = BSON_INITIALIZER; bool ret = false; bson_t local_reply; ENTRY; BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT_PARAM (keyid); BSON_ASSERT_PARAM (keyaltname); BSON_ASSERT (_coll_has_write_concern_majority (client_encryption->keyvault_coll)); BSON_ASSERT (keyid->value_type == BSON_TYPE_BINARY); BSON_ASSERT (keyid->value.v_binary.subtype == BSON_SUBTYPE_UUID); BSON_ASSERT (keyid->value.v_binary.data_len > 0u); BSON_ASSERT (BSON_APPEND_BINARY ( &query, "_id", keyid->value.v_binary.subtype, keyid->value.v_binary.data, keyid->value.v_binary.data_len)); _mongoc_bson_init_if_set (key_doc); { mongoc_find_and_modify_opts_t *const opts = mongoc_find_and_modify_opts_new (); /* clang-format off */ bson_t *const update = BCON_NEW ( "0", "{", "$set", "{", "keyAltNames", "{", "$cond", "[", "{", "$eq", "[", "$keyAltNames", "[", keyaltname, "]", "]", "}", "$$REMOVE", "{", "$filter", "{", "input", "$keyAltNames", "cond", "{", "$ne", "[", "$$this", keyaltname, "]", "}", "}", "}", "]", "}", "}", "}"); /* clang-format on */ BSON_ASSERT (mongoc_find_and_modify_opts_set_update (opts, update)); ret = mongoc_collection_find_and_modify_with_opts ( client_encryption->keyvault_coll, &query, opts, &local_reply, error); bson_destroy (update); mongoc_find_and_modify_opts_destroy (opts); } if (ret && key_doc) { bson_iter_t iter; if (bson_iter_init_find (&iter, &local_reply, "value")) { const bson_value_t *const value = bson_iter_value (&iter); if (value->value_type == BSON_TYPE_DOCUMENT) { bson_t bson; BSON_ASSERT (bson_init_static (&bson, value->value.v_doc.data, value->value.v_doc.data_len)); bson_copy_to (&bson, key_doc); bson_destroy (&bson); } else if (value->value_type == BSON_TYPE_NULL) { bson_t bson = BSON_INITIALIZER; bson_copy_to (&bson, key_doc); bson_destroy (&bson); } else { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "expected field value to be a document or null"); ret = false; } } } bson_destroy (&query); bson_destroy (&local_reply); RETURN (ret); } bool mongoc_client_encryption_get_key_by_alt_name (mongoc_client_encryption_t *client_encryption, const char *keyaltname, bson_t *key_doc, bson_error_t *error) { bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor = NULL; bool ret = false; ENTRY; BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT_PARAM (keyaltname); BSON_ASSERT (_coll_has_write_concern_majority (client_encryption->keyvault_coll)); BSON_ASSERT (BSON_APPEND_UTF8 (&filter, "keyAltNames", keyaltname)); _mongoc_bson_init_if_set (key_doc); cursor = mongoc_collection_find_with_opts (client_encryption->keyvault_coll, &filter, NULL, NULL); ret = !mongoc_cursor_error (cursor, error); if (ret && key_doc) { const bson_t *bson = NULL; if (mongoc_cursor_next (cursor, &bson)) { bson_copy_to (bson, key_doc); } else if (mongoc_cursor_error (cursor, error)) { ret = false; } } bson_destroy (&filter); mongoc_cursor_destroy (cursor); RETURN (ret); } bool mongoc_client_encryption_encrypt (mongoc_client_encryption_t *client_encryption, const bson_value_t *value, mongoc_client_encryption_encrypt_opts_t *opts, bson_value_t *ciphertext, bson_error_t *error) { bool ret = false; bson_t *range_opts = NULL; ENTRY; BSON_ASSERT (client_encryption); if (!ciphertext) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "required 'ciphertext' unset"); GOTO (fail); } /* reset, so it is safe for caller to call bson_value_destroy on error or * success. */ ciphertext->value_type = BSON_TYPE_EOD; if (!opts) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "required 'opts' unset"); GOTO (fail); } if (opts->range_opts) { range_opts = bson_new (); append_bson_range_opts (range_opts, opts); } if (!_mongoc_crypt_explicit_encrypt (client_encryption->crypt, client_encryption->keyvault_coll, opts->algorithm, &opts->keyid, opts->keyaltname, opts->query_type, opts->contention_factor.set ? &opts->contention_factor.value : NULL, range_opts, value, ciphertext, error)) { GOTO (fail); } ret = true; fail: bson_destroy (range_opts); RETURN (ret); } bool mongoc_client_encryption_encrypt_expression (mongoc_client_encryption_t *client_encryption, const bson_t *expr, mongoc_client_encryption_encrypt_opts_t *opts, bson_t *expr_out, bson_error_t *error) { ENTRY; BSON_ASSERT_PARAM (client_encryption); BSON_ASSERT_PARAM (expr); BSON_ASSERT_PARAM (opts); BSON_ASSERT_PARAM (expr_out); BSON_OPTIONAL_PARAM (error); bson_init (expr_out); bson_t *range_opts = NULL; if (opts->range_opts) { range_opts = bson_new (); append_bson_range_opts (range_opts, opts); } if (!_mongoc_crypt_explicit_encrypt_expression (client_encryption->crypt, client_encryption->keyvault_coll, opts->algorithm, &opts->keyid, opts->keyaltname, opts->query_type, opts->contention_factor.set ? &opts->contention_factor.value : NULL, range_opts, expr, expr_out, error)) { bson_destroy (range_opts); RETURN (false); } bson_destroy (range_opts); RETURN (true); } bool mongoc_client_encryption_decrypt (mongoc_client_encryption_t *client_encryption, const bson_value_t *ciphertext, bson_value_t *value, bson_error_t *error) { bool ret = false; ENTRY; BSON_ASSERT (client_encryption); if (!value) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "required 'value' unset"); GOTO (fail); } /* reset, so it is safe for caller to call bson_value_destroy on error or * success. */ value->value_type = BSON_TYPE_EOD; if (ciphertext->value_type != BSON_TYPE_BINARY || ciphertext->value.v_binary.subtype != BSON_SUBTYPE_ENCRYPTED) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "ciphertext must be BSON binary subtype 6"); GOTO (fail); } if (!_mongoc_crypt_explicit_decrypt ( client_encryption->crypt, client_encryption->keyvault_coll, ciphertext, value, error)) { GOTO (fail); } ret = true; fail: RETURN (ret); } bool _mongoc_cse_is_enabled (mongoc_client_t *client) { BSON_ASSERT_PARAM (client); while (1) { mongoc_topology_cse_state_t state = mcommon_atomic_int_fetch ((int *) &client->topology->cse_state, mcommon_memory_order_relaxed); if (state != MONGOC_CSE_STARTING) { return state == MONGOC_CSE_ENABLED; } /* CSE is starting up. Wait until that succeeds or fails. */ bson_thrd_yield (); } } /// Context for creating a new datakey using an existing ClientEncryption state struct cec_context { mongoc_client_encryption_t *enc; const mongoc_client_encryption_datakey_opts_t *dk_opts; const char *kms_provider; }; /// Automatically create a new datakey. @see auto_datakey_factory static bool _auto_datakey (struct auto_datakey_context *ctx) { struct cec_context *cec = ctx->userdata; return mongoc_client_encryption_create_datakey ( cec->enc, cec->kms_provider, cec->dk_opts, ctx->out_keyid, ctx->out_error); } mongoc_collection_t * mongoc_client_encryption_create_encrypted_collection (mongoc_client_encryption_t *enc, struct _mongoc_database_t *database, const char *name, const bson_t *in_options, bson_t *opt_out_options, const char *const kms_provider, const bson_t *opt_masterkey, bson_error_t *error) { BSON_ASSERT_PARAM (enc); BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (name); BSON_ASSERT_PARAM (in_options); BSON_OPTIONAL_PARAM (opt_out_options); BSON_ASSERT_PARAM (kms_provider); BSON_OPTIONAL_PARAM (error); mongoc_collection_t *ret = NULL; bson_t in_encryptedFields = BSON_INITIALIZER; bson_t new_encryptedFields = BSON_INITIALIZER; bson_t local_new_options = BSON_INITIALIZER; mongoc_client_encryption_datakey_opts_t *dk_opts = mongoc_client_encryption_datakey_opts_new (); if (opt_masterkey) { mongoc_client_encryption_datakey_opts_set_masterkey (dk_opts, opt_masterkey); } if (!opt_out_options) { // We'll use our own storage for the new options opt_out_options = &local_new_options; } // Init the storage. Either inits the caller's copy, or our local version. bson_init (opt_out_options); // Look up the encryptedfields that we should use for this collection. They // may be in the given options, or they may be in the encryptedFieldsMap. if (!_mongoc_get_collection_encryptedFields (database->client, mongoc_database_get_name (database), name, in_options, false /* checkEncryptedFieldsMap */, &in_encryptedFields, error)) { // Error finding the encryptedFields goto done; } if (bson_empty (&in_encryptedFields)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "No 'encryptedFields' are defined for the creation of " "the '%s' collection", name); goto done; } // Add the keyIds to the encryptedFields. // Context for the creation of new datakeys: struct cec_context ctx = { .enc = enc, .dk_opts = dk_opts, .kms_provider = kms_provider, }; bson_t fields_ref; bsonVisitEach (in_encryptedFields, case ( // We only care about the "fields" array when (not(key ("fields")), appendTo (new_encryptedFields)), // Automaticall fill in the "keyId" no each field: else (storeDocRef (fields_ref), do ({ bson_t new_fields = BSON_INITIALIZER; // Create the new fields, filling out the 'keyId' // automatically: if (!_mongoc_encryptedFields_fill_auto_datakeys ( &new_fields, &fields_ref, _auto_datakey, &ctx, error)) { bsonParseError = "Error creating datakeys"; } else { BSON_APPEND_ARRAY (&new_encryptedFields, "fields", &new_fields); bson_destroy (&new_fields); } })))); if (bsonParseError) { // Error creating the new datakeys. // `error` was set by _mongoc_encryptedFields_fill_auto_datakeys goto done; } // We've successfully filled out all null keyIds. Now create the collection // with our new options: bsonBuild (*opt_out_options, insert (*in_options, not(key ("encryptedFields"))), kv ("encryptedFields", bson (new_encryptedFields))); if (bsonBuildError) { // Error while building the new options. bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Error while building new createCollection options: %s", bsonBuildError); goto done; } ret = mongoc_database_create_collection (database, name, opt_out_options, error); done: bson_destroy (&new_encryptedFields); bson_destroy (&in_encryptedFields); mongoc_client_encryption_datakey_opts_destroy (dk_opts); // Destroy the local options, which may or may not have been used. If unused, // the new options are now owned by the caller and this is a no-op. bson_destroy (&local_new_options); // The resulting collection, or NULL on error: return ret; } #endif /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */ /// Generate one encryptedField element. static void _init_1_encryptedField ( bson_t *out_field, const bson_t *in_field, auto_datakey_factory fac, void *fac_userdata, bson_error_t *error) { BSON_ASSERT_PARAM (out_field); BSON_ASSERT_PARAM (in_field); BSON_ASSERT_PARAM (fac); BSON_OPTIONAL_PARAM (fac_userdata); BSON_OPTIONAL_PARAM (error); bsonVisitEach (*in_field, // If it is not a "keyId":null element, just copy it to the output. if (not(keyWithType ("keyId", null)), then (appendTo (*out_field), continue)), // Otherwise: do ({ // Set up factory context bson_value_t new_key = {0}; struct auto_datakey_context ctx = { .out_keyid = &new_key, .out_error = error, .userdata = fac_userdata, }; // Call the callback to create the new key if (!fac (&ctx)) { bsonParseError = "Factory function indicated failure"; } else { // Append to the field BSON_APPEND_VALUE (out_field, "keyId", &new_key); } bson_value_destroy (&new_key); })); } /// Generate the "encryptedFields" output for auto-datakeys static void _init_encryptedFields ( bson_t *out_fields, const bson_t *in_fields, auto_datakey_factory fac, void *fac_userdata, bson_error_t *error) { BSON_ASSERT_PARAM (out_fields); BSON_ASSERT_PARAM (in_fields); BSON_ASSERT_PARAM (fac); BSON_OPTIONAL_PARAM (fac_userdata); BSON_OPTIONAL_PARAM (error); // Ref to one encyrptedField bson_t cur_field; bsonVisitEach ( *in_fields, // Each field must be a document element if (not(type (doc)), then (error ("Each 'encryptedFields' element must be a document"))), // Append a new element with the same name as the field: storeDocRef (cur_field), append (*out_fields, kv (bson_iter_key (&bsonVisitIter), // Construct the encryptedField document from the input: doc (do (_init_1_encryptedField (bsonBuildContext.doc, &cur_field, fac, fac_userdata, error)))))); if (error && error->code == 0) { // The factory/internal code did not set error, so we may have to set it // for an error while BSON parsing/generating. if (bsonParseError) { bson_set_error ( error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Error while generating datakeys: %s", bsonParseError); } if (bsonBuildError) { bson_set_error ( error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Error while generating datakeys: %s", bsonBuildError); } } } bool _mongoc_encryptedFields_fill_auto_datakeys ( bson_t *out_fields, const bson_t *in_fields, auto_datakey_factory factory, void *userdata, bson_error_t *error) { BSON_ASSERT_PARAM (in_fields); BSON_ASSERT_PARAM (out_fields); BSON_ASSERT_PARAM (factory); if (error) { *error = (bson_error_t){0}; } bson_init (out_fields); _init_encryptedFields (out_fields, in_fields, factory, userdata, error); // DSL errors will be set in case of failure return bsonParseError == NULL && bsonBuildError == NULL; } const char * mongoc_client_encryption_get_crypt_shared_version (const mongoc_client_encryption_t *enc) { #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION return _mongoc_crypt_get_crypt_shared_version (enc->crypt); #else BSON_UNUSED (enc); return NULL; #endif } const char * mongoc_client_get_crypt_shared_version (const mongoc_client_t *client) { BSON_ASSERT_PARAM (client); #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION if (!client->topology->crypt) { return NULL; } return _mongoc_crypt_get_crypt_shared_version (client->topology->crypt); #else BSON_UNUSED (client); return NULL; #endif } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client-side-encryption.h0000644000175100001660000003627114760300420025540 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLIENT_SIDE_ENCRYPTION_H #define MONGOC_CLIENT_SIDE_ENCRYPTION_H #include /* Forward declare */ struct _mongoc_client_t; struct _mongoc_client_pool_t; struct _mongoc_cursor_t; struct _mongoc_collection_t; struct _mongoc_database_t; #define MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM "AEAD_AES_256_CBC_HMAC_SHA_512-Random" #define MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" #define MONGOC_ENCRYPT_ALGORITHM_INDEXED "Indexed" #define MONGOC_ENCRYPT_ALGORITHM_UNINDEXED "Unindexed" #define MONGOC_ENCRYPT_ALGORITHM_RANGE "Range" #define MONGOC_ENCRYPT_ALGORITHM_RANGEPREVIEW "RangePreview" #define MONGOC_ENCRYPT_QUERY_TYPE_EQUALITY "equality" #define MONGOC_ENCRYPT_QUERY_TYPE_RANGE "range" #define MONGOC_ENCRYPT_QUERY_TYPE_RANGEPREVIEW "rangePreview" BSON_BEGIN_DECLS typedef struct _mongoc_auto_encryption_opts_t mongoc_auto_encryption_opts_t; typedef bool (*mongoc_kms_credentials_provider_callback_fn) (void *userdata, const bson_t *params, bson_t *out, bson_error_t *error); MONGOC_EXPORT (mongoc_auto_encryption_opts_t *) mongoc_auto_encryption_opts_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_auto_encryption_opts_destroy (mongoc_auto_encryption_opts_t *opts); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_keyvault_client (mongoc_auto_encryption_opts_t *opts, struct _mongoc_client_t *client); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_keyvault_client_pool (mongoc_auto_encryption_opts_t *opts, struct _mongoc_client_pool_t *pool); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_keyvault_namespace (mongoc_auto_encryption_opts_t *opts, const char *db, const char *coll); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_kms_providers (mongoc_auto_encryption_opts_t *opts, const bson_t *kms_providers); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_key_expiration (mongoc_auto_encryption_opts_t *opts, uint64_t expiration); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_tls_opts (mongoc_auto_encryption_opts_t *opts, const bson_t *tls_opts); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_schema_map (mongoc_auto_encryption_opts_t *opts, const bson_t *schema_map); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_encrypted_fields_map (mongoc_auto_encryption_opts_t *opts, const bson_t *encrypted_fields_map); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_bypass_auto_encryption (mongoc_auto_encryption_opts_t *opts, bool bypass_auto_encryption); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_bypass_query_analysis (mongoc_auto_encryption_opts_t *opts, bool bypass_query_analysis); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_extra (mongoc_auto_encryption_opts_t *opts, const bson_t *extra); MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_kms_credential_provider_callback (mongoc_auto_encryption_opts_t *opts, mongoc_kms_credentials_provider_callback_fn fn, void *userdata); typedef struct _mongoc_client_encryption_opts_t mongoc_client_encryption_opts_t; typedef struct _mongoc_client_encryption_t mongoc_client_encryption_t; typedef struct _mongoc_client_encryption_encrypt_range_opts_t mongoc_client_encryption_encrypt_range_opts_t; typedef struct _mongoc_client_encryption_encrypt_opts_t mongoc_client_encryption_encrypt_opts_t; typedef struct _mongoc_client_encryption_datakey_opts_t mongoc_client_encryption_datakey_opts_t; typedef struct _mongoc_client_encryption_rewrap_many_datakey_result_t mongoc_client_encryption_rewrap_many_datakey_result_t; MONGOC_EXPORT (mongoc_client_encryption_opts_t *) mongoc_client_encryption_opts_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_encryption_opts_destroy (mongoc_client_encryption_opts_t *opts); MONGOC_EXPORT (void) mongoc_client_encryption_opts_set_keyvault_client (mongoc_client_encryption_opts_t *opts, struct _mongoc_client_t *keyvault_client); MONGOC_EXPORT (void) mongoc_client_encryption_opts_set_keyvault_namespace (mongoc_client_encryption_opts_t *opts, const char *db, const char *coll); MONGOC_EXPORT (void) mongoc_client_encryption_opts_set_kms_providers (mongoc_client_encryption_opts_t *opts, const bson_t *kms_providers); MONGOC_EXPORT (void) mongoc_client_encryption_opts_set_tls_opts (mongoc_client_encryption_opts_t *opts, const bson_t *tls_opts); MONGOC_EXPORT (void) mongoc_client_encryption_opts_set_kms_credential_provider_callback (mongoc_client_encryption_opts_t *opts, mongoc_kms_credentials_provider_callback_fn fn, void *userdata); MONGOC_EXPORT (void) mongoc_client_encryption_opts_set_key_expiration (mongoc_client_encryption_opts_t *opts, uint64_t cache_expiration_ms); MONGOC_EXPORT (mongoc_client_encryption_rewrap_many_datakey_result_t *) mongoc_client_encryption_rewrap_many_datakey_result_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_encryption_rewrap_many_datakey_result_destroy ( mongoc_client_encryption_rewrap_many_datakey_result_t *result); MONGOC_EXPORT (const bson_t *) mongoc_client_encryption_rewrap_many_datakey_result_get_bulk_write_result ( mongoc_client_encryption_rewrap_many_datakey_result_t *result) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_client_encryption_t *) mongoc_client_encryption_new (mongoc_client_encryption_opts_t *opts, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_encryption_destroy (mongoc_client_encryption_t *client_encryption); MONGOC_EXPORT (bool) mongoc_client_encryption_create_datakey (mongoc_client_encryption_t *client_encryption, const char *kms_provider, const mongoc_client_encryption_datakey_opts_t *opts, bson_value_t *keyid, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_rewrap_many_datakey (mongoc_client_encryption_t *client_encryption, const bson_t *filter, const char *provider, const bson_t *master_key, mongoc_client_encryption_rewrap_many_datakey_result_t *result, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_delete_key (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_get_key (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, bson_t *key_doc, bson_error_t *error); MONGOC_EXPORT (struct _mongoc_cursor_t *) mongoc_client_encryption_get_keys (mongoc_client_encryption_t *client_encryption, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_add_key_alt_name (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, const char *keyaltname, bson_t *key_doc, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_remove_key_alt_name (mongoc_client_encryption_t *client_encryption, const bson_value_t *keyid, const char *keyaltname, bson_t *key_doc, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_get_key_by_alt_name (mongoc_client_encryption_t *client_encryption, const char *keyaltname, bson_t *key_doc, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_encrypt (mongoc_client_encryption_t *client_encryption, const bson_value_t *value, mongoc_client_encryption_encrypt_opts_t *opts, bson_value_t *ciphertext, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_encrypt_expression (mongoc_client_encryption_t *client_encryption, const bson_t *expr, mongoc_client_encryption_encrypt_opts_t *opts, bson_t *expr_out, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_encryption_decrypt (mongoc_client_encryption_t *client_encryption, const bson_value_t *ciphertext, bson_value_t *value, bson_error_t *error); MONGOC_EXPORT (mongoc_client_encryption_encrypt_opts_t *) mongoc_client_encryption_encrypt_opts_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_opts_destroy (mongoc_client_encryption_encrypt_opts_t *opts); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_opts_set_keyid (mongoc_client_encryption_encrypt_opts_t *opts, const bson_value_t *keyid); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_opts_set_keyaltname (mongoc_client_encryption_encrypt_opts_t *opts, const char *keyaltname); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_opts_set_algorithm (mongoc_client_encryption_encrypt_opts_t *opts, const char *algorithm); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_opts_set_contention_factor (mongoc_client_encryption_encrypt_opts_t *opts, int64_t contention_factor); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_opts_set_query_type (mongoc_client_encryption_encrypt_opts_t *opts, const char *query_type); MONGOC_EXPORT (mongoc_client_encryption_encrypt_range_opts_t *) mongoc_client_encryption_encrypt_range_opts_new (void); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_range_opts_destroy (mongoc_client_encryption_encrypt_range_opts_t *range_opts); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_range_opts_set_trim_factor (mongoc_client_encryption_encrypt_range_opts_t *range_opts, int32_t trim_factor); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_range_opts_set_sparsity (mongoc_client_encryption_encrypt_range_opts_t *range_opts, int64_t sparsity); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_range_opts_set_min (mongoc_client_encryption_encrypt_range_opts_t *range_opts, const bson_value_t *min); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_range_opts_set_max (mongoc_client_encryption_encrypt_range_opts_t *range_opts, const bson_value_t *max); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_range_opts_set_precision (mongoc_client_encryption_encrypt_range_opts_t *range_opts, int32_t precision); MONGOC_EXPORT (void) mongoc_client_encryption_encrypt_opts_set_range_opts (mongoc_client_encryption_encrypt_opts_t *opts, const mongoc_client_encryption_encrypt_range_opts_t *range_opts); MONGOC_EXPORT (mongoc_client_encryption_datakey_opts_t *) mongoc_client_encryption_datakey_opts_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_encryption_datakey_opts_destroy (mongoc_client_encryption_datakey_opts_t *opts); MONGOC_EXPORT (void) mongoc_client_encryption_datakey_opts_set_masterkey (mongoc_client_encryption_datakey_opts_t *opts, const bson_t *masterkey); MONGOC_EXPORT (void) mongoc_client_encryption_datakey_opts_set_keyaltnames (mongoc_client_encryption_datakey_opts_t *opts, char **keyaltnames, uint32_t keyaltnames_count); MONGOC_EXPORT (void) mongoc_client_encryption_datakey_opts_set_keymaterial (mongoc_client_encryption_datakey_opts_t *opts, const uint8_t *data, uint32_t len); MONGOC_EXPORT (const char *) mongoc_client_encryption_get_crypt_shared_version (mongoc_client_encryption_t const *enc) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (struct _mongoc_collection_t *) mongoc_client_encryption_create_encrypted_collection (mongoc_client_encryption_t *enc, struct _mongoc_database_t *database, const char *name, const bson_t *in_options, bson_t *opt_out_options, const char *const kms_provider, const bson_t *opt_masterkey, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_CLIENT_SIDE_ENCRYPTION_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client.c0000644000175100001660000026761714760300420022433 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #ifdef MONGOC_HAVE_DNSAPI /* for DnsQuery_UTF8 */ #include #include #include #else #if defined(MONGOC_HAVE_RES_NSEARCH) || defined(MONGOC_HAVE_RES_SEARCH) #include #include #include #include #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #include #include #include #endif #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L #include #include #endif #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "client" static void _mongoc_client_op_killcursors (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id, int64_t operation_id, const char *db, const char *collection); static void _mongoc_client_killcursors_command (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id, const char *db, const char *collection, mongoc_client_session_t *cs); #define DNS_ERROR(_msg, ...) \ do { \ bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, _msg, __VA_ARGS__); \ GOTO (done); \ } while (0) #if MONGOC_ENABLE_SRV == 0 // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ ENABLE_SRV disabled /* SRV support is disabled */ #elif defined(MONGOC_HAVE_DNSAPI) // ↑↑↑ ENABLE_SRV disabled / Win32 Dnsapi ↓↓↓↓ typedef bool (*mongoc_rr_callback_t) (const char *hostname, PDNS_RECORD pdns, mongoc_rr_data_t *rr_data, bson_error_t *error); static bool srv_callback (const char *hostname, PDNS_RECORD pdns, mongoc_rr_data_t *rr_data, bson_error_t *error) { mongoc_host_list_t new_host; if (rr_data && rr_data->hosts) { _mongoc_host_list_remove_host (&(rr_data->hosts), pdns->Data.SRV.pNameTarget, pdns->Data.SRV.wPort); } if (!_mongoc_host_list_from_hostport_with_err (&new_host, pdns->Data.SRV.pNameTarget, pdns->Data.SRV.wPort, error)) { return false; } _mongoc_host_list_upsert (&rr_data->hosts, &new_host); return true; } /* rr_data is unused, but here to match srv_callback signature */ static bool txt_callback (const char *hostname, PDNS_RECORD pdns, mongoc_rr_data_t *rr_data, bson_error_t *error) { DWORD i; mcommon_string_append_t txt; mcommon_string_new_with_capacity_as_append (&txt, pdns->wDataLength); for (i = 0; i < pdns->Data.TXT.dwStringCount; i++) { mcommon_string_append (&txt, pdns->Data.TXT.pStringArray[i]); } rr_data->txt_record_opts = mcommon_string_from_append_destroy_with_steal (&txt); return true; } /* *-------------------------------------------------------------------------- * * _mongoc_get_rr_dnsapi -- * * Fetch SRV or TXT resource records using the Windows DNS API and * put results in @rr_data. * * Returns: * Success or failure. * * For an SRV lookup, returns false if there is any error. * * For TXT lookup, ignores any error fetching the resource record and * always returns true. * * Side effects: * @error is set if there is a failure. * @rr_data->hosts may be set if querying SRV. Caller must destroy. * @rr_data->txt_record_opts may be set if querying TXT. Caller must * free. * *-------------------------------------------------------------------------- */ static bool _mongoc_get_rr_dnsapi ( const char *hostname, mongoc_rr_type_t rr_type, mongoc_rr_data_t *rr_data, bool prefer_tcp, bson_error_t *error) { const char *rr_type_name; WORD nst; mongoc_rr_callback_t callback; PDNS_RECORD pdns = NULL; DNS_STATUS res; LPVOID lpMsgBuf = NULL; bool dns_success; bool callback_success = true; int i; ENTRY; if (rr_type == MONGOC_RR_SRV) { /* return true only if DNS succeeds */ dns_success = false; rr_type_name = "SRV"; nst = DNS_TYPE_SRV; callback = srv_callback; } else { /* return true whether or not DNS succeeds */ dns_success = true; rr_type_name = "TXT"; nst = DNS_TYPE_TEXT; callback = txt_callback; } DWORD options = DNS_QUERY_BYPASS_CACHE; if (prefer_tcp) { options |= DNS_QUERY_USE_TCP_ONLY; } res = DnsQuery_UTF8 (hostname, nst, options, NULL /* IP Address */, &pdns, 0 /* reserved */); if (res) { DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; if (FormatMessage (flags, 0, res, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, 0)) { DNS_ERROR ("Failed to look up %s record \"%s\": %s", rr_type_name, hostname, (char *) lpMsgBuf); } DNS_ERROR ("Failed to look up %s record \"%s\": Unknown error", rr_type_name, hostname); } if (!pdns) { DNS_ERROR ("No %s records for \"%s\"", rr_type_name, hostname); } i = 0; do { /* DnsQuery can return additional records not of the requested type */ if ((rr_type == MONGOC_RR_TXT && pdns->wType == DNS_TYPE_TEXT) || (rr_type == MONGOC_RR_SRV && pdns->wType == DNS_TYPE_SRV)) { if (i > 0 && rr_type == MONGOC_RR_TXT) { /* Initial DNS Seedlist Discovery Spec: a client "MUST raise an error when multiple TXT records are encountered". */ callback_success = false; DNS_ERROR ("Multiple TXT records for \"%s\"", hostname); } if (rr_data) { if ((i == 0) || (pdns->dwTtl < rr_data->min_ttl)) { rr_data->min_ttl = pdns->dwTtl; } } if (!callback (hostname, pdns, rr_data, error)) { callback_success = false; GOTO (done); } i++; } pdns = pdns->pNext; } while (pdns); rr_data->count = i; if (i == 0) { DNS_ERROR ("No matching %s records for \"%s\"", rr_type_name, hostname); } dns_success = true; done: if (pdns) { DnsRecordListFree (pdns, DnsFreeRecordList); } if (lpMsgBuf) { LocalFree (lpMsgBuf); } RETURN (dns_success && callback_success); } #elif (defined(MONGOC_HAVE_RES_NSEARCH) || defined(MONGOC_HAVE_RES_SEARCH)) // ↑↑↑↑↑↑↑ Win32 Dnsapi / resolv ↓↓↓↓↓↓↓↓ typedef bool (*mongoc_rr_callback_t) ( const char *hostname, ns_msg *ns_answer, ns_rr *rr, mongoc_rr_data_t *rr_data, bson_error_t *error); static const char * _mongoc_hstrerror (int code) { switch (code) { case HOST_NOT_FOUND: return "The specified host is unknown."; case NO_ADDRESS: return "The requested name is valid but does not have an IP address."; case NO_RECOVERY: return "A nonrecoverable name server error occurred."; case TRY_AGAIN: return "A temporary error occurred on an authoritative name server. Try " "again later."; default: return "An unknown error occurred."; } } static bool srv_callback (const char *hostname, ns_msg *ns_answer, ns_rr *rr, mongoc_rr_data_t *rr_data, bson_error_t *error) { const uint8_t *data; char name[1024]; uint16_t port; int size; bool ret = false; mongoc_host_list_t new_host; data = ns_rr_rdata (*rr); /* memcpy the network endian port before converting to host endian. we cannot * cast (data + 4) directly as a uint16_t*, because it may not align on an * 2-byte boundary. */ memcpy (&port, data + 4, sizeof (port)); port = ntohs (port); size = dn_expand (ns_msg_base (*ns_answer), ns_msg_end (*ns_answer), data + 6, name, sizeof (name)); if (size < 1) { DNS_ERROR ("Invalid record in SRV answer for \"%s\": \"%s\"", hostname, _mongoc_hstrerror (h_errno)); } if (!_mongoc_host_list_from_hostport_with_err (&new_host, name, port, error)) { GOTO (done); } _mongoc_host_list_upsert (&rr_data->hosts, &new_host); ret = true; done: return ret; } static bool txt_callback (const char *hostname, ns_msg *ns_answer, ns_rr *rr, mongoc_rr_data_t *rr_data, bson_error_t *error) { bool ret = false; BSON_UNUSED (ns_answer); uint16_t total = (uint16_t) ns_rr_rdlen (*rr); if (total < 1 || total > 255) { DNS_ERROR ("Invalid TXT record size %hu for \"%s\"", total, hostname); } /* a TXT record has one or more strings, each up to 255 chars, each is prefixed by its length as 1 byte. * In this usage, they are all concatenated without any spacers. */ mcommon_string_append_t txt; mcommon_string_new_with_capacity_as_append (&txt, total); uint16_t pos = 0; const uint8_t *data = ns_rr_rdata (*rr); while (pos < total) { uint8_t len = data[pos++]; if (total - pos < (uint16_t) len) { DNS_ERROR ("Invalid TXT string size %hu at %hu in %hu-byte TXT record for \"%s\"", (uint16_t) len, pos, total, hostname); } mcommon_string_append_bytes (&txt, (const char *) (data + pos), (uint32_t) len); pos += len; } rr_data->txt_record_opts = mcommon_string_from_append_destroy_with_steal (&txt); ret = true; done: return ret; } /* *-------------------------------------------------------------------------- * * _mongoc_get_rr_search -- * * Fetch SRV or TXT resource records using libresolv and put results in * @rr_data. * * Returns: * Success or failure. * * For an SRV lookup, returns false if there is any error. * * For TXT lookup, ignores any error fetching the resource record and * always returns true. * * Side effects: * @error is set if there is a failure. * @rr_data->hosts may be set if querying SRV. Caller must destroy. * @rr_data->txt_record_opts may be set if querying TXT. Caller must * free. * *-------------------------------------------------------------------------- */ static bool _mongoc_get_rr_search (const char *hostname, mongoc_rr_type_t rr_type, mongoc_rr_data_t *rr_data, size_t initial_buffer_size, bool prefer_tcp, bson_error_t *error) { #ifdef MONGOC_HAVE_RES_NSEARCH struct __res_state state = {0}; #endif int size = 0; unsigned char *search_buf = NULL; size_t buffer_size = initial_buffer_size; ns_msg ns_answer; int n; int i; const char *rr_type_name; ns_type nst; mongoc_rr_callback_t callback; ns_rr resource_record; bool dns_success; bool callback_success = true; int num_matching_records; uint32_t ttl; ENTRY; if (rr_type == MONGOC_RR_SRV) { /* return true only if DNS succeeds */ dns_success = false; rr_type_name = "SRV"; nst = ns_t_srv; callback = srv_callback; } else { /* return true whether or not DNS succeeds */ dns_success = true; rr_type_name = "TXT"; nst = ns_t_txt; callback = txt_callback; } do { if (search_buf) { bson_free (search_buf); /* increase buffer size by the previous response size. This ensures * that even if a subsequent response is larger, we'll still be able * to fit it in the response buffer */ buffer_size = buffer_size + size; } search_buf = (unsigned char *) bson_malloc (buffer_size); BSON_ASSERT (search_buf); #ifdef MONGOC_HAVE_RES_NSEARCH /* thread-safe */ res_ninit (&state); if (prefer_tcp) { state.options |= RES_USEVC; } size = res_nsearch (&state, hostname, ns_c_in, nst, search_buf, buffer_size); #elif defined(MONGOC_HAVE_RES_SEARCH) size = res_search (hostname, ns_c_in, nst, search_buf, buffer_size); #endif if (size < 0) { DNS_ERROR ("Failed to look up %s record \"%s\": %s", rr_type_name, hostname, _mongoc_hstrerror (h_errno)); } } while (size >= buffer_size); if (ns_initparse (search_buf, size, &ns_answer)) { DNS_ERROR ("Invalid %s answer for \"%s\"", rr_type_name, hostname); } n = ns_msg_count (ns_answer, ns_s_an); if (!n) { DNS_ERROR ("No %s records for \"%s\"", rr_type_name, hostname); } rr_data->count = n; num_matching_records = 0; for (i = 0; i < n; i++) { if (ns_parserr (&ns_answer, ns_s_an, i, &resource_record)) { DNS_ERROR ("Invalid record %d of %s answer for \"%s\": \"%s\"", i, rr_type_name, hostname, _mongoc_hstrerror (h_errno)); } /* Skip records that don't match the ones we requested. CDRIVER-3628 shows * that we can receive records that were not requested. */ if (rr_type == MONGOC_RR_TXT) { if (ns_rr_type (resource_record) != ns_t_txt) { continue; } } else if (rr_type == MONGOC_RR_SRV) { if (ns_rr_type (resource_record) != ns_t_srv) { continue; } } if (num_matching_records > 0 && rr_type == MONGOC_RR_TXT) { /* Initial DNS Seedlist Discovery Spec: a client "MUST raise an error * when multiple TXT records are encountered". */ callback_success = false; DNS_ERROR ("Multiple TXT records for \"%s\"", hostname); } num_matching_records++; ttl = ns_rr_ttl (resource_record); if ((i == 0) || (ttl < rr_data->min_ttl)) { rr_data->min_ttl = ttl; } if (!callback (hostname, &ns_answer, &resource_record, rr_data, error)) { callback_success = false; GOTO (done); } } if (num_matching_records == 0) { DNS_ERROR ("No matching %s records for \"%s\"", rr_type_name, hostname); } dns_success = true; done: bson_free (search_buf); #ifdef MONGOC_HAVE_RES_NDESTROY /* defined on BSD/Darwin, and only if MONGOC_HAVE_RES_NSEARCH is defined */ res_ndestroy (&state); #elif defined(MONGOC_HAVE_RES_NCLOSE) /* defined on Linux, and only if MONGOC_HAVE_RES_NSEARCH is defined */ res_nclose (&state); #endif RETURN (dns_success && callback_success); } #endif // ↑↑↑↑↑↑↑↑↑↑↑↑↑ resolv /* *-------------------------------------------------------------------------- * * _mongoc_client_get_rr -- * * Fetch an SRV or TXT resource record and update put results in * @rr_data. * * See RFCs 1464 and 2782, MongoDB's "Initial DNS Seedlist Discovery" * spec, and MongoDB's "Polling SRV Records for Mongos Discovery" * spec. * * Returns: * Success or failure. * * Side effects: * @error is set if there is a failure. Errors fetching TXT are * ignored. * @rr_data->hosts may be set if querying SRV. Caller must destroy. * @rr_data->txt_record_opts may be set if querying TXT. Caller must * free. * *-------------------------------------------------------------------------- */ bool _mongoc_client_get_rr (const char *hostname, mongoc_rr_type_t rr_type, mongoc_rr_data_t *rr_data, size_t initial_buffer_size, bool prefer_tcp, bson_error_t *error) { BSON_ASSERT (rr_data); #if MONGOC_ENABLE_SRV == 0 // Disabled bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "libresolv unavailable, cannot use mongodb+srv URI"); return false; #elif defined(MONGOC_HAVE_DNSAPI) return _mongoc_get_rr_dnsapi (hostname, rr_type, rr_data, prefer_tcp, error); #elif (defined(MONGOC_HAVE_RES_NSEARCH) || defined(MONGOC_HAVE_RES_SEARCH)) return _mongoc_get_rr_search (hostname, rr_type, rr_data, initial_buffer_size, prefer_tcp, error); #else #error No SRV library is available, but ENABLE_SRV is true! #endif } #undef DNS_ERROR /* *-------------------------------------------------------------------------- * * mongoc_client_connect_tcp -- * * Connect to a host using a TCP socket. * * This will be performed synchronously and return a mongoc_stream_t * that can be used to connect with the remote host. * * Returns: * A newly allocated mongoc_stream_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error is set if return value is NULL. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_client_connect_tcp (int32_t connecttimeoutms, const mongoc_host_list_t *host, bson_error_t *error) { mongoc_socket_t *sock = NULL; struct addrinfo hints; struct addrinfo *result, *rp; int64_t expire_at; char portstr[8]; int s; ENTRY; BSON_ASSERT (connecttimeoutms); BSON_ASSERT (host); // Expect no truncation. int req = bson_snprintf (portstr, sizeof portstr, "%hu", host->port); BSON_ASSERT (mcommon_cmp_less_su (req, sizeof portstr)); memset (&hints, 0, sizeof hints); hints.ai_family = host->family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = 0; TRACE ("DNS lookup for %s", host->host); s = getaddrinfo (host->host, portstr, &hints, &result); if (s != 0) { mongoc_counter_dns_failure_inc (); TRACE ("Failed to resolve %s", host->host); bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "Failed to resolve %s", host->host); RETURN (NULL); } mongoc_counter_dns_success_inc (); for (rp = result; rp; rp = rp->ai_next) { /* * Create a new non-blocking socket. */ if (!(sock = mongoc_socket_new (rp->ai_family, rp->ai_socktype, rp->ai_protocol))) { continue; } /* * Try to connect to the peer. */ expire_at = bson_get_monotonic_time () + (connecttimeoutms * 1000L); if (0 != mongoc_socket_connect (sock, rp->ai_addr, (mongoc_socklen_t) rp->ai_addrlen, expire_at)) { mongoc_socket_destroy (sock); sock = NULL; continue; } break; } if (!sock) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to connect to target host: %s", host->host_and_port); freeaddrinfo (result); RETURN (NULL); } freeaddrinfo (result); return mongoc_stream_socket_new (sock); } /* *-------------------------------------------------------------------------- * * mongoc_client_connect_unix -- * * Connect to a MongoDB server using a UNIX domain socket. * * Returns: * A newly allocated mongoc_stream_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error is set if return value is NULL. * *-------------------------------------------------------------------------- */ static mongoc_stream_t * mongoc_client_connect_unix (const mongoc_host_list_t *host, bson_error_t *error) { #ifdef _WIN32 ENTRY; bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "UNIX domain sockets not supported on win32."); RETURN (NULL); #else struct sockaddr_un saddr; mongoc_socket_t *sock; mongoc_stream_t *ret = NULL; ENTRY; BSON_ASSERT (host); memset (&saddr, 0, sizeof saddr); saddr.sun_family = AF_UNIX; // Expect no truncation. int req = bson_snprintf (saddr.sun_path, sizeof saddr.sun_path - 1, "%s", host->host); if (mcommon_cmp_greater_equal_su (req, sizeof saddr.sun_path - 1)) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to define socket address path."); RETURN (NULL); } sock = mongoc_socket_new (AF_UNIX, SOCK_STREAM, 0); if (sock == NULL) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to create socket."); RETURN (NULL); } if (-1 == mongoc_socket_connect (sock, (struct sockaddr *) &saddr, sizeof saddr, -1)) { mongoc_socket_destroy (sock); bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to connect to UNIX domain socket."); RETURN (NULL); } ret = mongoc_stream_socket_new (sock); RETURN (ret); #endif } mongoc_stream_t * mongoc_client_connect (bool buffered, bool use_ssl, void *ssl_opts_void, const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *openssl_ctx_void, bson_error_t *error) { mongoc_stream_t *base_stream = NULL; int32_t connecttimeoutms; BSON_ASSERT (uri); BSON_ASSERT (host); #ifndef MONGOC_ENABLE_SSL if (ssl_opts_void || mongoc_uri_get_tls (uri)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_NO_ACCEPTABLE_PEER, "TLS is not enabled in this build of mongo-c-driver."); return NULL; } #endif connecttimeoutms = mongoc_uri_get_option_as_int32 (uri, MONGOC_URI_CONNECTTIMEOUTMS, MONGOC_DEFAULT_CONNECTTIMEOUTMS); switch (host->family) { case AF_UNSPEC: #if defined(AF_INET6) case AF_INET6: #endif case AF_INET: base_stream = mongoc_client_connect_tcp (connecttimeoutms, host, error); break; case AF_UNIX: base_stream = mongoc_client_connect_unix (host, error); break; default: bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_INVALID_TYPE, "Invalid address family: 0x%02x", (unsigned int) host->family); break; } #ifdef MONGOC_ENABLE_SSL if (base_stream) { mongoc_ssl_opt_t *ssl_opts; const char *mechanism; ssl_opts = (mongoc_ssl_opt_t *) ssl_opts_void; mechanism = mongoc_uri_get_auth_mechanism (uri); if (use_ssl || (mechanism && (0 == strcmp (mechanism, "MONGODB-X509")))) { mongoc_stream_t *original = base_stream; #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L // Use shared OpenSSL context. base_stream = mongoc_stream_tls_new_with_hostname_and_openssl_context ( base_stream, host->host, ssl_opts, true, (SSL_CTX *) openssl_ctx_void); #else base_stream = mongoc_stream_tls_new_with_hostname (base_stream, host->host, ssl_opts, true); #endif if (!base_stream) { mongoc_stream_destroy (original); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed initialize TLS state."); return NULL; } if (!mongoc_stream_tls_handshake_block (base_stream, host->host, connecttimeoutms, error)) { mongoc_stream_destroy (base_stream); return NULL; } } } #endif if (!base_stream) { return NULL; } if (buffered) { return mongoc_stream_buffered_new (base_stream, 1024); } return base_stream; } /* *-------------------------------------------------------------------------- * * mongoc_client_default_stream_initiator -- * * A mongoc_stream_initiator_t that will handle the various type * of supported sockets by MongoDB including TCP and UNIX. * * Also supports sharing of OpenSSL context owned by a client. * * Language binding authors may want to implement an alternate * version of this method to use their native stream format. * * Returns: * A mongoc_stream_t if successful; otherwise NULL and @error is set. * * Side effects: * @error is set if return value is NULL. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_client_default_stream_initiator (const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *user_data, bson_error_t *error) { void *ssl_opts_void = NULL; bool use_ssl = false; #ifdef MONGOC_ENABLE_SSL mongoc_client_t *client = (mongoc_client_t *) user_data; use_ssl = client->use_ssl; ssl_opts_void = (void *) &client->ssl_opts; #endif #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L SSL_CTX *ssl_ctx = client->topology->scanner->openssl_ctx; return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, (void *) ssl_ctx, error); #else return mongoc_client_connect (true, use_ssl, ssl_opts_void, uri, host, NULL, error); #endif } /* *-------------------------------------------------------------------------- * * _mongoc_client_create_stream -- * * INTERNAL API * * This function is used by the mongoc_cluster_t to initiate a * new stream. This is done because cluster is private API and * those using mongoc_client_t may need to override this process. * * This function calls the default initiator for new streams. * * Returns: * A newly allocated mongoc_stream_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error is set if return value is NULL. * *-------------------------------------------------------------------------- */ mongoc_stream_t * _mongoc_client_create_stream (mongoc_client_t *client, const mongoc_host_list_t *host, bson_error_t *error) { BSON_ASSERT_PARAM (client); BSON_ASSERT (host); return client->initiator (client->uri, host, client->initiator_data, error); } bool _mongoc_client_recv (mongoc_client_t *client, mcd_rpc_message *rpc, mongoc_buffer_t *buffer, mongoc_server_stream_t *server_stream, bson_error_t *error) { BSON_ASSERT_PARAM (client); BSON_ASSERT (rpc); BSON_ASSERT (buffer); BSON_ASSERT (server_stream); BSON_ASSERT_PARAM (error); return mongoc_cluster_try_recv (&client->cluster, rpc, buffer, server_stream, error); } mongoc_client_t * mongoc_client_new (const char *uri_string) { mongoc_client_t *client; mongoc_uri_t *uri; bson_error_t error = {0}; if (!uri_string) { uri_string = "mongodb://127.0.0.1/"; } if (!(uri = mongoc_uri_new_with_error (uri_string, &error))) { /* Log URI errors as a warning for consistency with mongoc_uri_new */ MONGOC_WARNING ("Error parsing URI: '%s'", error.message); return NULL; } if (!(client = mongoc_client_new_from_uri_with_error (uri, &error))) { MONGOC_ERROR ("%s", error.message); } mongoc_uri_destroy (uri); return client; } /* *-------------------------------------------------------------------------- * * mongoc_client_set_ssl_opts * * set ssl opts for a client * * Returns: * Nothing * * Side effects: * None. * *-------------------------------------------------------------------------- */ #ifdef MONGOC_ENABLE_SSL /* Only called internally. Caller must ensure opts->internal is valid. */ void _mongoc_client_set_internal_tls_opts (mongoc_client_t *client, _mongoc_internal_tls_opts_t *internal) { BSON_ASSERT_PARAM (client); if (!client->use_ssl) { return; } client->ssl_opts.internal = bson_malloc (sizeof (_mongoc_internal_tls_opts_t)); memcpy (client->ssl_opts.internal, internal, sizeof (_mongoc_internal_tls_opts_t)); } void mongoc_client_set_ssl_opts (mongoc_client_t *client, const mongoc_ssl_opt_t *opts) { BSON_ASSERT_PARAM (client); BSON_ASSERT (opts); _mongoc_ssl_opts_cleanup (&client->ssl_opts, false /* don't free internal opts */); client->use_ssl = true; _mongoc_ssl_opts_copy_to (opts, &client->ssl_opts, false /* don't overwrite internal opts */); if (client->topology->single_threaded) { mongoc_topology_scanner_set_ssl_opts (client->topology->scanner, &client->ssl_opts); /* Update the OpenSSL context associated with this client to match new ssl opts. */ /* Active connections previously made by client can still access original OpenSSL context. */ #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L SSL_CTX_free (client->topology->scanner->openssl_ctx); client->topology->scanner->openssl_ctx = _mongoc_openssl_ctx_new (&client->ssl_opts); #endif } } #endif mongoc_client_t * mongoc_client_new_from_uri (const mongoc_uri_t *uri) { mongoc_client_t *client; bson_error_t error = {0}; if (!(client = mongoc_client_new_from_uri_with_error (uri, &error))) { MONGOC_ERROR ("%s", error.message); } return client; } mongoc_client_t * mongoc_client_new_from_uri_with_error (const mongoc_uri_t *uri, bson_error_t *error) { mongoc_client_t *client; mongoc_topology_t *topology; ENTRY; BSON_ASSERT (uri); #ifndef MONGOC_ENABLE_SSL if (mongoc_uri_get_tls (uri)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Can't create SSL client, SSL not enabled in this build."); RETURN (NULL); } #endif topology = mongoc_topology_new (uri, true); if (!topology->valid) { if (error) { memcpy (error, &topology->scanner->error, sizeof (bson_error_t)); } mongoc_topology_destroy (topology); RETURN (NULL); } client = _mongoc_client_new_from_topology (topology); BSON_ASSERT (client); RETURN (client); } /* precondition: topology is valid */ mongoc_client_t * _mongoc_client_new_from_topology (mongoc_topology_t *topology) { mongoc_client_t *client; const mongoc_read_prefs_t *read_prefs; const mongoc_read_concern_t *read_concern; const mongoc_write_concern_t *write_concern; const char *appname; BSON_ASSERT (topology); BSON_ASSERT (topology->valid); client = (mongoc_client_t *) bson_malloc0 (sizeof *client); client->uri = mongoc_uri_copy (topology->uri); client->initiator = mongoc_client_default_stream_initiator; client->initiator_data = client; client->topology = topology; client->error_api_version = MONGOC_ERROR_API_VERSION_LEGACY; client->error_api_set = false; client->client_sessions = mongoc_set_new (8, NULL, NULL); client->csid_rand_seed = (unsigned int) bson_get_monotonic_time (); write_concern = mongoc_uri_get_write_concern (client->uri); client->write_concern = mongoc_write_concern_copy (write_concern); read_concern = mongoc_uri_get_read_concern (client->uri); client->read_concern = mongoc_read_concern_copy (read_concern); read_prefs = mongoc_uri_get_read_prefs_t (client->uri); client->read_prefs = mongoc_read_prefs_copy (read_prefs); appname = mongoc_uri_get_option_as_utf8 (client->uri, MONGOC_URI_APPNAME, NULL); if (appname && client->topology->single_threaded) { /* the appname should have already been validated */ BSON_ASSERT (mongoc_client_set_appname (client, appname)); } mongoc_cluster_init (&client->cluster, client->uri, client); #ifdef MONGOC_ENABLE_SSL client->use_ssl = false; if (mongoc_uri_get_tls (client->uri)) { mongoc_ssl_opt_t ssl_opt = {0}; _mongoc_internal_tls_opts_t internal_tls_opts = {0}; _mongoc_ssl_opts_from_uri (&ssl_opt, &internal_tls_opts, client->uri); /* sets use_ssl = true */ /* this call creates an ssl ctx only if single-threaded, otherwise client inherits from pool */ mongoc_client_set_ssl_opts (client, &ssl_opt); _mongoc_client_set_internal_tls_opts (client, &internal_tls_opts); } #endif mongoc_structured_log (topology->log_and_monitor.structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_CONNECTION, "Client created"); mongoc_counter_clients_active_inc (); return client; } /* *-------------------------------------------------------------------------- * * mongoc_client_destroy -- * * Destroys a mongoc_client_t and cleans up all resources associated * with the client instance. * * Returns: * None. * * Side effects: * @client is destroyed. * *-------------------------------------------------------------------------- */ void mongoc_client_destroy (mongoc_client_t *client) { if (client) { if (client->topology->single_threaded) { _mongoc_client_end_sessions (client); mongoc_topology_destroy (client->topology); } mongoc_write_concern_destroy (client->write_concern); mongoc_read_concern_destroy (client->read_concern); mongoc_read_prefs_destroy (client->read_prefs); mongoc_cluster_destroy (&client->cluster); mongoc_uri_destroy (client->uri); mongoc_set_destroy (client->client_sessions); mongoc_server_api_destroy (client->api); #ifdef MONGOC_ENABLE_SSL _mongoc_ssl_opts_cleanup (&client->ssl_opts, true); #endif bson_free (client); mongoc_counter_clients_active_dec (); mongoc_counter_clients_disposed_inc (); } } void mongoc_client_set_sockettimeoutms (mongoc_client_t *client, int32_t timeoutms) { BSON_ASSERT_PARAM (client); mongoc_cluster_set_sockettimeoutms (&client->cluster, timeoutms); } /* *-------------------------------------------------------------------------- * * mongoc_client_get_uri -- * * Fetch the URI used for @client. * * Returns: * A mongoc_uri_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_uri_t * mongoc_client_get_uri (const mongoc_client_t *client) { BSON_ASSERT_PARAM (client); return client->uri; } /* *-------------------------------------------------------------------------- * * mongoc_client_start_session -- * * Creates a structure to communicate in a session over @client. * * This structure should be freed when the caller is done with it * using mongoc_client_session_destroy(). * * Returns: * A newly allocated mongoc_client_session_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_client_session_t * mongoc_client_start_session (mongoc_client_t *client, const mongoc_session_opt_t *opts, bson_error_t *error) { BSON_ASSERT_PARAM (client); mongoc_server_session_t *ss; mongoc_client_session_t *cs; uint32_t csid; ENTRY; const mongoc_ss_log_context_t ss_log_context = {.operation = "startSession"}; ss = _mongoc_client_pop_server_session (client, &ss_log_context, error); if (!ss) { RETURN (NULL); } /* get a random internal id for the session, retrying on collision */ do { csid = (uint32_t) _mongoc_rand_simple (&client->csid_rand_seed); } while (mongoc_set_get (client->client_sessions, csid)); /* causal consistency and snapshot cannot both be set. */ if (opts && mongoc_session_opts_get_causal_consistency (opts) && mongoc_session_opts_get_snapshot (opts)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_SESSION_FAILURE, "Only one of causal consistency and snapshot can be enabled."); _mongoc_client_push_server_session (client, ss); RETURN (NULL); } cs = _mongoc_client_session_new (client, ss, opts, csid); /* remember session so if we see its client_session_id in a command, we can * find its lsid and clusterTime */ mongoc_set_add (client->client_sessions, csid, cs); RETURN (cs); } /* *-------------------------------------------------------------------------- * * mongoc_client_get_database -- * * Fetches a newly allocated database structure to communicate with * a database over @client. * * @database should be a db name such as "test". * * This structure should be freed when the caller is done with it * using mongoc_database_destroy(). * * Returns: * A newly allocated mongoc_database_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_database_t * mongoc_client_get_database (mongoc_client_t *client, const char *name) { BSON_ASSERT_PARAM (client); BSON_ASSERT (name); return _mongoc_database_new (client, name, client->read_prefs, client->read_concern, client->write_concern); } /* *-------------------------------------------------------------------------- * * mongoc_client_get_default_database -- * * Get the database named in the MongoDB connection URI, or NULL * if none was specified in the URI. * * This structure should be freed when the caller is done with it * using mongoc_database_destroy(). * * Returns: * A newly allocated mongoc_database_t or NULL. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_database_t * mongoc_client_get_default_database (mongoc_client_t *client) { const char *db; BSON_ASSERT_PARAM (client); db = mongoc_uri_get_database (client->uri); if (db) { return mongoc_client_get_database (client, db); } return NULL; } /* *-------------------------------------------------------------------------- * * mongoc_client_get_collection -- * * This function returns a newly allocated collection structure. * * @db should be the name of the database, such as "test". * @collection should be the name of the collection such as "test". * * The above would result in the namespace "test.test". * * You should free this structure when you are done with it using * mongoc_collection_destroy(). * * Returns: * A newly allocated mongoc_collection_t that should be freed with * mongoc_collection_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_collection_t * mongoc_client_get_collection (mongoc_client_t *client, const char *db, const char *collection) { BSON_ASSERT_PARAM (client); BSON_ASSERT (db); BSON_ASSERT (collection); return _mongoc_collection_new ( client, db, collection, client->read_prefs, client->read_concern, client->write_concern); } /* *-------------------------------------------------------------------------- * * mongoc_client_get_gridfs -- * * This function returns a newly allocated collection structure. * * @db should be the name of the database, such as "test". * * @prefix optional prefix for GridFS collection names, or NULL. Default * is "fs", thus the default collection names for GridFS are "fs.files" * and "fs.chunks". * * Returns: * A newly allocated mongoc_gridfs_t that should be freed with * mongoc_gridfs_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_gridfs_t * mongoc_client_get_gridfs (mongoc_client_t *client, const char *db, const char *prefix, bson_error_t *error) { BSON_ASSERT_PARAM (client); BSON_ASSERT (db); if (!prefix) { prefix = "fs"; } return _mongoc_gridfs_new (client, db, prefix, error); } /* *-------------------------------------------------------------------------- * * mongoc_client_get_write_concern -- * * Fetches the default write concern for @client. * * Returns: * A mongoc_write_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_write_concern_t * mongoc_client_get_write_concern (const mongoc_client_t *client) { BSON_ASSERT_PARAM (client); return client->write_concern; } /* *-------------------------------------------------------------------------- * * mongoc_client_set_write_concern -- * * Sets the default write concern for @client. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_client_set_write_concern (mongoc_client_t *client, const mongoc_write_concern_t *write_concern) { BSON_ASSERT_PARAM (client); if (write_concern != client->write_concern) { if (client->write_concern) { mongoc_write_concern_destroy (client->write_concern); } client->write_concern = write_concern ? mongoc_write_concern_copy (write_concern) : mongoc_write_concern_new (); } } /* *-------------------------------------------------------------------------- * * mongoc_client_get_read_concern -- * * Fetches the default read concern for @client. * * Returns: * A mongoc_read_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_concern_t * mongoc_client_get_read_concern (const mongoc_client_t *client) { BSON_ASSERT_PARAM (client); return client->read_concern; } /* *-------------------------------------------------------------------------- * * mongoc_client_set_read_concern -- * * Sets the default read concern for @client. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_client_set_read_concern (mongoc_client_t *client, const mongoc_read_concern_t *read_concern) { BSON_ASSERT_PARAM (client); if (read_concern != client->read_concern) { if (client->read_concern) { mongoc_read_concern_destroy (client->read_concern); } client->read_concern = read_concern ? mongoc_read_concern_copy (read_concern) : mongoc_read_concern_new (); } } /* *-------------------------------------------------------------------------- * * mongoc_client_get_read_prefs -- * * Fetch the default read preferences for @client. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_prefs_t * mongoc_client_get_read_prefs (const mongoc_client_t *client) { BSON_ASSERT_PARAM (client); return client->read_prefs; } /* *-------------------------------------------------------------------------- * * mongoc_client_set_read_prefs -- * * Set the default read preferences for @client. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_client_set_read_prefs (mongoc_client_t *client, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT_PARAM (client); if (read_prefs != client->read_prefs) { if (client->read_prefs) { mongoc_read_prefs_destroy (client->read_prefs); } client->read_prefs = read_prefs ? mongoc_read_prefs_copy (read_prefs) : mongoc_read_prefs_new (MONGOC_READ_PRIMARY); } } mongoc_cursor_t * mongoc_client_command (mongoc_client_t *client, const char *db_name, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { char *ns = NULL; mongoc_cursor_t *cursor; BSON_UNUSED (flags); BSON_UNUSED (skip); BSON_UNUSED (limit); BSON_UNUSED (batch_size); BSON_UNUSED (fields); BSON_ASSERT_PARAM (client); BSON_ASSERT (db_name); BSON_ASSERT (query); /* * Allow a caller to provide a fully qualified namespace */ if (NULL == strstr (db_name, "$cmd")) { ns = bson_strdup_printf ("%s.$cmd", db_name); db_name = ns; } cursor = _mongoc_cursor_cmd_deprecated_new (client, db_name, query, read_prefs); bson_free (ns); return cursor; } static bool _mongoc_client_retryable_read_command_with_stream (mongoc_client_t *client, mongoc_cmd_parts_t *parts, mongoc_server_stream_t *server_stream, bson_t *reply, bson_error_t *error) { mongoc_server_stream_t *retry_server_stream = NULL; bool is_retryable = true; bool ret; bson_t reply_local; BSON_ASSERT_PARAM (client); BSON_UNUSED (server_stream); if (reply == NULL) { reply = &reply_local; } ENTRY; BSON_ASSERT (parts->is_retryable_read); retry: ret = mongoc_cluster_run_command_monitored (&client->cluster, &parts->assembled, reply, error); /* If a retryable error is encountered and the read is retryable, select * a new readable stream and retry. If server selection fails or the selected * server does not support retryable reads, fall through and allow the * original error to be reported. */ if (is_retryable && _mongoc_read_error_get_type (ret, error, reply) == MONGOC_READ_ERR_RETRY) { /* each read command may be retried at most once */ is_retryable = false; { mongoc_deprioritized_servers_t *const ds = mongoc_deprioritized_servers_new (); if (retry_server_stream) { mongoc_deprioritized_servers_add_if_sharded ( ds, retry_server_stream->topology_type, retry_server_stream->sd); mongoc_server_stream_cleanup (retry_server_stream); } else { mongoc_deprioritized_servers_add_if_sharded (ds, server_stream->topology_type, server_stream->sd); } const mongoc_ss_log_context_t ss_log_context = { .operation = parts->assembled.command_name, .has_operation_id = true, .operation_id = parts->assembled.operation_id, }; retry_server_stream = mongoc_cluster_stream_for_reads (&client->cluster, &ss_log_context, parts->read_prefs, parts->assembled.session, ds, NULL /* reply */, NULL /* error */); mongoc_deprioritized_servers_destroy (ds); } if (retry_server_stream) { parts->assembled.server_stream = retry_server_stream; bson_destroy (reply); GOTO (retry); } } if (retry_server_stream) { mongoc_server_stream_cleanup (retry_server_stream); } if (ret && error) { /* if a retry succeeded, clear the initial error */ memset (error, 0, sizeof (bson_error_t)); } RETURN (ret); } static bool _mongoc_client_command_with_stream (mongoc_client_t *client, mongoc_cmd_parts_t *parts, const mongoc_read_prefs_t *read_prefs, mongoc_server_stream_t *server_stream, bson_t *reply, bson_error_t *error) { ENTRY; BSON_ASSERT_PARAM (client); BSON_UNUSED (read_prefs); parts->assembled.operation_id = ++client->cluster.operation_id; if (!mongoc_cmd_parts_assemble (parts, server_stream, error)) { _mongoc_bson_init_if_set (reply); return false; } if (parts->is_retryable_write) { mongoc_server_stream_t *retry_server_stream = NULL; bool ret = mongoc_cluster_run_retryable_write ( &client->cluster, &parts->assembled, true /* is_retryable */, &retry_server_stream, reply, error); if (retry_server_stream) { mongoc_server_stream_cleanup (retry_server_stream); parts->assembled.server_stream = NULL; } RETURN (ret); } if (parts->is_retryable_read) { RETURN (_mongoc_client_retryable_read_command_with_stream (client, parts, server_stream, reply, error)); } RETURN (mongoc_cluster_run_command_monitored (&client->cluster, &parts->assembled, reply, error)); } bool mongoc_client_command_simple (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) { mongoc_cluster_t *cluster; mongoc_server_stream_t *server_stream = NULL; mongoc_cmd_parts_t parts; bool ret; ENTRY; BSON_ASSERT_PARAM (client); BSON_ASSERT (db_name); BSON_ASSERT (command); if (!_mongoc_read_prefs_validate (read_prefs, error)) { RETURN (false); } cluster = &client->cluster; mongoc_cmd_parts_init (&parts, client, db_name, MONGOC_QUERY_NONE, command); parts.read_prefs = read_prefs; /* Server Selection Spec: "The generic command method has a default read * preference of mode 'primary'. The generic command method MUST ignore any * default read preference from client, database or collection * configuration. The generic command method SHOULD allow an optional read * preference argument." */ const mongoc_ss_log_context_t ss_log_context = {.operation = _mongoc_get_command_name (command)}; server_stream = mongoc_cluster_stream_for_reads (cluster, &ss_log_context, read_prefs, NULL, NULL, reply, error); if (server_stream) { ret = _mongoc_client_command_with_stream (client, &parts, read_prefs, server_stream, reply, error); } else { /* reply initialized by mongoc_cluster_stream_for_reads */ ret = false; } mongoc_cmd_parts_cleanup (&parts); mongoc_server_stream_cleanup (server_stream); RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_client_command_with_opts -- * * Execute a command on the server. If mode is MONGOC_CMD_READ or * MONGOC_CMD_RW, then read concern is applied from @opts, or else from * @default_rc, and read preferences are applied from @user_prefs, or else * from @default_prefs. If mode is MONGOC_CMD_WRITE or MONGOC_CMD_RW, then * write concern is applied from @opts if present, or else @default_wc. * * If mode is MONGOC_CMD_RAW, then read concern and write concern are * applied from @opts only. Read preferences are applied from * @user_prefs. * * The mongoc_client_t's read preference, read concern, and write concern * are *NOT* applied. * * Returns: * Success or failure. * A write concern timeout or write concern error is considered a failure. * * Side effects: * @reply is always initialized. * @error is filled out if the command fails. * *-------------------------------------------------------------------------- */ bool _mongoc_client_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, mongoc_command_mode_t mode, const bson_t *opts, mongoc_query_flags_t flags, const mongoc_read_prefs_t *user_prefs, const mongoc_read_prefs_t *default_prefs, mongoc_read_concern_t *default_rc, mongoc_write_concern_t *default_wc, bson_t *reply, bson_error_t *error) { mongoc_read_write_opts_t read_write_opts; mongoc_cmd_parts_t parts; const char *command_name; const mongoc_read_prefs_t *prefs = COALESCE (user_prefs, default_prefs); mongoc_server_stream_t *server_stream = NULL; mongoc_cluster_t *cluster; mongoc_client_session_t *cs; bson_t reply_local; bson_t *reply_ptr; bool reply_initialized = false; bool ret = false; ENTRY; BSON_ASSERT_PARAM (client); BSON_ASSERT (db_name); BSON_ASSERT (command); command_name = _mongoc_get_command_name (command); cluster = &client->cluster; reply_ptr = reply ? reply : &reply_local; mongoc_cmd_parts_init (&parts, client, db_name, flags, command); parts.is_read_command = (mode & MONGOC_CMD_READ); parts.is_write_command = (mode & MONGOC_CMD_WRITE); if (!_mongoc_read_write_opts_parse (client, opts, &read_write_opts, error)) { GOTO (done); } cs = read_write_opts.client_session; if (!command_name) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Empty command document"); GOTO (done); } if (_mongoc_client_session_in_txn (read_write_opts.client_session)) { if ((mode == MONGOC_CMD_READ || mode == MONGOC_CMD_RAW) && !IS_PREF_PRIMARY (user_prefs)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Read preference in a transaction must be primary"); GOTO (done); } if (!bson_empty (&read_write_opts.readConcern)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set read concern after starting transaction"); GOTO (done); } if (read_write_opts.writeConcern && strcmp (command_name, "commitTransaction") != 0 && strcmp (command_name, "abortTransaction") != 0) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set write concern after starting transaction"); GOTO (done); } } if (mode == MONGOC_CMD_READ || mode == MONGOC_CMD_RAW) { /* NULL read pref is ok */ if (!_mongoc_read_prefs_validate (prefs, error)) { GOTO (done); } parts.read_prefs = prefs; } else { /* this is a command that writes */ prefs = NULL; } const mongoc_ss_log_context_t ss_log_context = {.operation = command_name}; if (read_write_opts.serverId) { /* "serverId" passed in opts */ server_stream = mongoc_cluster_stream_for_server ( cluster, read_write_opts.serverId, true /* reconnect ok */, cs, reply_ptr, error); if (server_stream && server_stream->sd->type != MONGOC_SERVER_MONGOS) { parts.user_query_flags |= MONGOC_QUERY_SECONDARY_OK; } } else if (parts.is_write_command) { server_stream = mongoc_cluster_stream_for_writes (cluster, &ss_log_context, cs, NULL, reply_ptr, error); } else { server_stream = mongoc_cluster_stream_for_reads (cluster, &ss_log_context, prefs, cs, NULL, reply_ptr, error); } if (!server_stream) { /* stream_for_reads/writes/server has initialized reply */ reply_initialized = true; GOTO (done); } if (!mongoc_cmd_parts_append_read_write (&parts, &read_write_opts, error)) { GOTO (done); } if (mode & MONGOC_CMD_WRITE) { /* use default write concern unless it's in opts */ if (!mongoc_write_concern_is_default (default_wc) && !read_write_opts.write_concern_owned) { if (!mongoc_cmd_parts_set_write_concern (&parts, default_wc, error)) { GOTO (done); } } } /* use default read concern for read command, unless it's in opts */ if ((mode & MONGOC_CMD_READ) && bson_empty (&read_write_opts.readConcern)) { if (!mongoc_cmd_parts_set_read_concern (&parts, default_rc, error)) { GOTO (done); } } ret = _mongoc_client_command_with_stream (client, &parts, user_prefs, server_stream, reply_ptr, error); reply_initialized = true; if (ret && (mode & MONGOC_CMD_WRITE)) { ret = !_mongoc_parse_wc_err (reply_ptr, error); } done: if (reply_ptr == &reply_local) { if (reply_initialized) { bson_destroy (reply_ptr); } } else if (!reply_initialized) { _mongoc_bson_init_if_set (reply); } if (server_stream) { mongoc_server_stream_cleanup (server_stream); } mongoc_cmd_parts_cleanup (&parts); _mongoc_read_write_opts_cleanup (&read_write_opts); RETURN (ret); } bool mongoc_client_read_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error) { return _mongoc_client_command_with_opts (client, db_name, command, MONGOC_CMD_READ, opts, MONGOC_QUERY_NONE, read_prefs, client->read_prefs, client->read_concern, client->write_concern, reply, error); } bool mongoc_client_write_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, const bson_t *opts, bson_t *reply, bson_error_t *error) { return _mongoc_client_command_with_opts (client, db_name, command, MONGOC_CMD_WRITE, opts, MONGOC_QUERY_NONE, NULL, client->read_prefs, client->read_concern, client->write_concern, reply, error); } bool mongoc_client_read_write_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs /* IGNORED */, const bson_t *opts, bson_t *reply, bson_error_t *error) { return _mongoc_client_command_with_opts (client, db_name, command, MONGOC_CMD_RW, opts, MONGOC_QUERY_NONE, read_prefs, client->read_prefs, client->read_concern, client->write_concern, reply, error); } bool mongoc_client_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error) { return _mongoc_client_command_with_opts (client, db_name, command, MONGOC_CMD_RAW, opts, MONGOC_QUERY_NONE, read_prefs, NULL, client->read_concern, client->write_concern, reply, error); } bool mongoc_client_command_simple_with_server_id (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, uint32_t server_id, bson_t *reply, bson_error_t *error) { mongoc_server_stream_t *server_stream; mongoc_cmd_parts_t parts; bool ret; ENTRY; BSON_ASSERT_PARAM (client); BSON_ASSERT (db_name); BSON_ASSERT (command); if (!_mongoc_read_prefs_validate (read_prefs, error)) { RETURN (false); } server_stream = mongoc_cluster_stream_for_server (&client->cluster, server_id, true /* reconnect ok */, NULL, reply, error); if (server_stream) { mongoc_cmd_parts_init (&parts, client, db_name, MONGOC_QUERY_NONE, command); parts.read_prefs = read_prefs; ret = _mongoc_client_command_with_stream (client, &parts, read_prefs, server_stream, reply, error); mongoc_cmd_parts_cleanup (&parts); mongoc_server_stream_cleanup (server_stream); RETURN (ret); } else { /* stream_for_server initialized reply */ RETURN (false); } } static void _mongoc_client_prepare_killcursors_command (int64_t cursor_id, const char *collection, bson_t *command) { bson_array_builder_t *child; bson_append_utf8 (command, "killCursors", 11, collection, -1); bson_append_array_builder_begin (command, "cursors", 7, &child); bson_array_builder_append_int64 (child, cursor_id); bson_append_array_builder_end (command, child); } void _mongoc_client_kill_cursor (mongoc_client_t *client, uint32_t server_id, int64_t cursor_id, int64_t operation_id, const char *db, const char *collection, mongoc_client_session_t *cs) { mongoc_server_stream_t *server_stream; ENTRY; BSON_ASSERT_PARAM (client); BSON_ASSERT (cursor_id); /* don't attempt reconnect if server unavailable, and ignore errors */ server_stream = mongoc_cluster_stream_for_server (&client->cluster, server_id, false /* reconnect_ok */, NULL, NULL, NULL); if (!server_stream) { return; } if (db && collection) { _mongoc_client_killcursors_command (&client->cluster, server_stream, cursor_id, db, collection, cs); } else { _mongoc_client_op_killcursors (&client->cluster, server_stream, cursor_id, operation_id, db, collection); } mongoc_server_stream_cleanup (server_stream); EXIT; } static void _mongoc_client_monitor_op_killcursors (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id, int64_t operation_id, const char *db, const char *collection) { bson_t doc; mongoc_apm_command_started_t event; ENTRY; mongoc_client_t *client = cluster->client; const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor; if (!log_and_monitor->apm_callbacks.started) { return; } bson_init (&doc); _mongoc_client_prepare_killcursors_command (cursor_id, collection, &doc); mongoc_apm_command_started_init (&event, &doc, db, "killCursors", cluster->request_id, operation_id, &server_stream->sd->host, server_stream->sd->id, &server_stream->sd->service_id, server_stream->sd->server_connection_id, NULL, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.started (&event); mongoc_apm_command_started_cleanup (&event); bson_destroy (&doc); EXIT; } static void _mongoc_client_monitor_op_killcursors_succeeded (mongoc_cluster_t *cluster, int64_t duration, mongoc_server_stream_t *server_stream, int64_t cursor_id, int64_t operation_id, const char *db) { bson_t doc; bson_array_builder_t *cursors_unknown; mongoc_apm_command_succeeded_t event; ENTRY; mongoc_client_t *client = cluster->client; const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor; if (!log_and_monitor->apm_callbacks.succeeded) { EXIT; } /* fake server reply to killCursors command: {ok: 1, cursorsUnknown: [42]} */ bson_init (&doc); bson_append_int32 (&doc, "ok", 2, 1); bson_append_array_builder_begin (&doc, "cursorsUnknown", 14, &cursors_unknown); bson_array_builder_append_int64 (cursors_unknown, cursor_id); bson_append_array_builder_end (&doc, cursors_unknown); mongoc_apm_command_succeeded_init (&event, duration, &doc, "killCursors", db, cluster->request_id, operation_id, &server_stream->sd->host, server_stream->sd->id, &server_stream->sd->service_id, server_stream->sd->server_connection_id, false, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.succeeded (&event); mongoc_apm_command_succeeded_cleanup (&event); bson_destroy (&doc); } static void _mongoc_client_monitor_op_killcursors_failed (mongoc_cluster_t *cluster, int64_t duration, mongoc_server_stream_t *server_stream, const bson_error_t *error, int64_t operation_id, const char *db) { bson_t doc; mongoc_apm_command_failed_t event; ENTRY; mongoc_client_t *client = cluster->client; const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor; if (!log_and_monitor->apm_callbacks.failed) { EXIT; } /* fake server reply to killCursors command: {ok: 0} */ bson_init (&doc); bson_append_int32 (&doc, "ok", 2, 0); mongoc_apm_command_failed_init (&event, duration, "killCursors", db, error, &doc, cluster->request_id, operation_id, &server_stream->sd->host, server_stream->sd->id, &server_stream->sd->service_id, server_stream->sd->server_connection_id, false, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.failed (&event); mongoc_apm_command_failed_cleanup (&event); bson_destroy (&doc); } static void _mongoc_client_op_killcursors (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id, int64_t operation_id, const char *db, const char *collection) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (server_stream); BSON_OPTIONAL_PARAM (db); BSON_OPTIONAL_PARAM (collection); const bool has_ns = db && collection; const int64_t started = bson_get_monotonic_time (); mcd_rpc_message *const rpc = mcd_rpc_message_new (); { int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (rpc, 0); message_length += mcd_rpc_header_set_request_id (rpc, ++cluster->request_id); message_length += mcd_rpc_header_set_response_to (rpc, 0); message_length += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_KILL_CURSORS); message_length += sizeof (int32_t); // ZERO message_length += mcd_rpc_op_kill_cursors_set_cursor_ids (rpc, &cursor_id, 1); mcd_rpc_message_set_length (rpc, message_length); } if (has_ns) { _mongoc_client_monitor_op_killcursors (cluster, server_stream, cursor_id, operation_id, db, collection); } bson_error_t error; const bool res = mongoc_cluster_legacy_rpc_sendv_to_server (cluster, rpc, server_stream, &error); if (has_ns) { if (res) { _mongoc_client_monitor_op_killcursors_succeeded ( cluster, bson_get_monotonic_time () - started, server_stream, cursor_id, operation_id, db); } else { _mongoc_client_monitor_op_killcursors_failed ( cluster, bson_get_monotonic_time () - started, server_stream, &error, operation_id, db); } } mcd_rpc_message_destroy (rpc); } static void _mongoc_client_killcursors_command (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, int64_t cursor_id, const char *db, const char *collection, mongoc_client_session_t *cs) { bson_t command = BSON_INITIALIZER; mongoc_cmd_parts_t parts; ENTRY; _mongoc_client_prepare_killcursors_command (cursor_id, collection, &command); mongoc_cmd_parts_init (&parts, cluster->client, db, MONGOC_QUERY_SECONDARY_OK, &command); parts.assembled.operation_id = ++cluster->operation_id; mongoc_cmd_parts_set_session (&parts, cs); if (mongoc_cmd_parts_assemble (&parts, server_stream, NULL)) { /* Find, getMore And killCursors Commands Spec: "The result from the * killCursors command MAY be safely ignored." */ (void) mongoc_cluster_run_command_monitored (cluster, &parts.assembled, NULL, NULL); } mongoc_cmd_parts_cleanup (&parts); bson_destroy (&command); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_client_kill_cursor -- * * Destroy a cursor on the server. * * NOTE: this is only reliable when connected to a single mongod or * mongos. If connected to a replica set, the driver attempts to * kill the cursor on the primary. If connected to multiple mongoses * the kill-cursors message is sent to a *random* mongos. * * If no primary, mongos, or standalone server is known, return * without attempting to reconnect. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_client_kill_cursor (mongoc_client_t *client, int64_t cursor_id) { BSON_ASSERT_PARAM (client); mongoc_topology_t *const topology = BSON_ASSERT_PTR_INLINE (client)->topology; mongoc_server_description_t const *selected_server; mongoc_read_prefs_t *read_prefs; bson_error_t error; uint32_t server_id = 0; mc_shared_tpld td = mc_tpld_take_ref (topology); read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); if (!mongoc_topology_compatible (td.ptr, NULL, &error)) { MONGOC_ERROR ("Could not kill cursor: %s", error.message); mc_tpld_drop_ref (&td); mongoc_read_prefs_destroy (read_prefs); return; } /* see if there's a known writable server - do no I/O or retries */ selected_server = mongoc_topology_description_select (td.ptr, MONGOC_SS_WRITE, read_prefs, NULL /* chosen read mode */, NULL /* deprioritized servers */, topology->local_threshold_msec); if (selected_server) { server_id = selected_server->id; } if (server_id) { _mongoc_client_kill_cursor ( client, server_id, cursor_id, 0 /* operation_id */, NULL /* db */, NULL /* collection */, NULL /* session */); } else { MONGOC_INFO ("No server available for mongoc_client_kill_cursor"); } mongoc_read_prefs_destroy (read_prefs); mc_tpld_drop_ref (&td); } char ** mongoc_client_get_database_names (mongoc_client_t *client, bson_error_t *error) { return mongoc_client_get_database_names_with_opts (client, NULL, error); } char ** mongoc_client_get_database_names_with_opts (mongoc_client_t *client, const bson_t *opts, bson_error_t *error) { bson_iter_t iter; const char *name; char **ret = NULL; int i = 0; mongoc_cursor_t *cursor; const bson_t *doc; bson_t cmd = BSON_INITIALIZER; BSON_ASSERT_PARAM (client); BSON_APPEND_INT32 (&cmd, "listDatabases", 1); BSON_APPEND_BOOL (&cmd, "nameOnly", true); /* ignore client read prefs */ cursor = _mongoc_cursor_array_new (client, "admin", &cmd, opts, "databases"); bson_destroy (&cmd); while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init (&iter, doc) && bson_iter_find (&iter, "name") && BSON_ITER_HOLDS_UTF8 (&iter) && (name = bson_iter_utf8 (&iter, NULL))) { ret = (char **) bson_realloc (ret, sizeof (char *) * (i + 2)); ret[i] = bson_strdup (name); ret[++i] = NULL; } } if (!ret && !mongoc_cursor_error (cursor, error)) { ret = (char **) bson_malloc0 (sizeof (void *)); } mongoc_cursor_destroy (cursor); return ret; } mongoc_cursor_t * mongoc_client_find_databases (mongoc_client_t *client, bson_error_t *error) { BSON_ASSERT_PARAM (client); BSON_UNUSED (error); /* existing bug in this deprecated API: error pointer is unused */ return mongoc_client_find_databases_with_opts (client, NULL); } mongoc_cursor_t * mongoc_client_find_databases_with_opts (mongoc_client_t *client, const bson_t *opts) { bson_t cmd = BSON_INITIALIZER; mongoc_cursor_t *cursor; BSON_ASSERT_PARAM (client); BSON_APPEND_INT32 (&cmd, "listDatabases", 1); cursor = _mongoc_cursor_array_new (client, "admin", &cmd, opts, "databases"); bson_destroy (&cmd); return cursor; } int32_t mongoc_client_get_max_message_size (mongoc_client_t *client) /* IN */ { BSON_ASSERT_PARAM (client); return mongoc_cluster_get_max_msg_size (&client->cluster); } int32_t mongoc_client_get_max_bson_size (mongoc_client_t *client) /* IN */ { BSON_ASSERT_PARAM (client); return mongoc_cluster_get_max_bson_obj_size (&client->cluster); } bool mongoc_client_get_server_status (mongoc_client_t *client, /* IN */ mongoc_read_prefs_t *read_prefs, /* IN */ bson_t *reply, /* OUT */ bson_error_t *error) /* OUT */ { bson_t cmd = BSON_INITIALIZER; bool ret = false; BSON_ASSERT_PARAM (client); BSON_APPEND_INT32 (&cmd, "serverStatus", 1); ret = mongoc_client_command_simple (client, "admin", &cmd, read_prefs, reply, error); bson_destroy (&cmd); return ret; } void mongoc_client_set_stream_initiator (mongoc_client_t *client, mongoc_stream_initiator_t initiator, void *user_data) { BSON_ASSERT_PARAM (client); if (!initiator) { initiator = mongoc_client_default_stream_initiator; user_data = client; } else { MONGOC_DEBUG ("Using custom stream initiator."); } client->initiator = initiator; client->initiator_data = user_data; if (client->topology->single_threaded) { mongoc_topology_scanner_set_stream_initiator (client->topology->scanner, initiator, user_data); } } bool mongoc_client_set_apm_callbacks (mongoc_client_t *client, mongoc_apm_callbacks_t *callbacks, void *context) { BSON_ASSERT_PARAM (client); if (!client->topology->single_threaded) { MONGOC_ERROR ("Cannot set callbacks on a pooled client, use " "mongoc_client_pool_set_apm_callbacks"); return false; } mongoc_log_and_monitor_instance_set_apm_callbacks (&client->topology->log_and_monitor, callbacks, context); return true; } bool mongoc_client_set_structured_log_opts (mongoc_client_t *client, const mongoc_structured_log_opts_t *opts) { BSON_ASSERT_PARAM (client); BSON_OPTIONAL_PARAM (opts); if (client->topology->single_threaded) { mongoc_log_and_monitor_instance_set_structured_log_opts (&client->topology->log_and_monitor, opts); return true; } else { MONGOC_WARNING ("Cannot set structured log options on a pooled client, use " "mongoc_client_pool_set_structured_log_opts before the first mongoc_client_pool_pop"); return false; } } mongoc_server_description_t * mongoc_client_get_server_description (mongoc_client_t *client, uint32_t server_id) { BSON_ASSERT_PARAM (client); mongoc_server_description_t *ret; mc_shared_tpld td = mc_tpld_take_ref (client->topology); mongoc_server_description_t const *sd = mongoc_topology_description_server_by_id_const (td.ptr, server_id, NULL /* <- the error info isn't useful */); ret = mongoc_server_description_new_copy (sd); mc_tpld_drop_ref (&td); return ret; } mongoc_server_description_t ** mongoc_client_get_server_descriptions (const mongoc_client_t *client, size_t *n /* OUT */) { BSON_ASSERT_PARAM (client); mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (client)->topology); mongoc_server_description_t **const sds = mongoc_topology_description_get_servers (td.ptr, BSON_ASSERT_PTR_INLINE (n)); mc_tpld_drop_ref (&td); return sds; } void mongoc_server_descriptions_destroy_all (mongoc_server_description_t **sds, size_t n) { size_t i; for (i = 0; i < n; ++i) { mongoc_server_description_destroy (sds[i]); } bson_free (sds); } mongoc_server_description_t * mongoc_client_select_server (mongoc_client_t *client, bool for_writes, const mongoc_read_prefs_t *prefs, bson_error_t *error) { BSON_ASSERT_PARAM (client); mongoc_ss_optype_t optype = for_writes ? MONGOC_SS_WRITE : MONGOC_SS_READ; mongoc_server_description_t *sd; if (for_writes && prefs) { bson_set_error (error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "Cannot use read preferences with for_writes = true"); return NULL; } if (!_mongoc_read_prefs_validate (prefs, error)) { return NULL; } const mongoc_ss_log_context_t ss_log_context = {.operation = "mongoc_client_select_server"}; sd = mongoc_topology_select (client->topology, optype, &ss_log_context, prefs, NULL /* chosen read mode */, error); if (!sd) { return NULL; } if (mongoc_cluster_check_interval (&client->cluster, sd->id)) { /* check not required, or it succeeded */ return sd; } /* check failed, retry once */ mongoc_server_description_destroy (sd); sd = mongoc_topology_select (client->topology, optype, &ss_log_context, prefs, NULL /* chosen read mode */, error); if (sd) { return sd; } return NULL; } bool mongoc_client_set_error_api (mongoc_client_t *client, int32_t version) { BSON_ASSERT_PARAM (client); if (!client->topology->single_threaded) { MONGOC_ERROR ("Cannot set Error API Version on a pooled client, use " "mongoc_client_pool_set_error_api"); return false; } if (version != MONGOC_ERROR_API_VERSION_LEGACY && version != MONGOC_ERROR_API_VERSION_2) { MONGOC_ERROR ("Unsupported Error API Version: %" PRId32, version); return false; } if (client->error_api_set) { MONGOC_ERROR ("Can only set Error API Version once"); return false; } client->error_api_version = version; client->error_api_set = true; return true; } bool mongoc_client_set_appname (mongoc_client_t *client, const char *appname) { BSON_ASSERT_PARAM (client); if (!client->topology->single_threaded) { MONGOC_ERROR ("Cannot call set_appname on a client from a pool"); return false; } return _mongoc_topology_set_appname (client->topology, appname); } mongoc_server_session_t * _mongoc_client_pop_server_session (mongoc_client_t *client, const mongoc_ss_log_context_t *log_context, bson_error_t *error) { BSON_ASSERT_PARAM (client); return _mongoc_topology_pop_server_session (client->topology, log_context, error); } /* *-------------------------------------------------------------------------- * * _mongoc_client_lookup_session -- * * Retrieve a mongoc_client_session_t associated with @client_session_id. * Use this to find the "lsid" and "$clusterTime" to send in the server * command. * * Returns: * True on success, false on error and @error is set. Will return false * if the session is from an outdated client generation, a holdover * from before a call to mongoc_client_reset. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool _mongoc_client_lookup_session (const mongoc_client_t *client, uint32_t client_session_id, mongoc_client_session_t **cs /* OUT */, bson_error_t *error /* OUT */) { ENTRY; BSON_ASSERT_PARAM (client); *cs = mongoc_set_get (client->client_sessions, client_session_id); if (*cs) { RETURN (true); } bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid sessionId"); RETURN (false); } void _mongoc_client_unregister_session (mongoc_client_t *client, mongoc_client_session_t *session) { BSON_ASSERT_PARAM (client); mongoc_set_rm (client->client_sessions, session->client_session_id); } void _mongoc_client_push_server_session (mongoc_client_t *client, mongoc_server_session_t *server_session) { BSON_ASSERT_PARAM (client); _mongoc_topology_push_server_session (client->topology, server_session); } /* *-------------------------------------------------------------------------- * * mongoc_client_end_sessions -- * * End all server sessions in the topology's server session pool. * Don't block long: if server selection or connecting fails, quit. * * The server session pool becomes invalid, but may not be empty. * Destroy the topology after this without using any sessions. * *-------------------------------------------------------------------------- */ void _mongoc_client_end_sessions (mongoc_client_t *client) { mongoc_topology_t *t = client->topology; mongoc_read_prefs_t *prefs; bson_error_t error; uint32_t server_id; bson_t cmd; mongoc_server_stream_t *stream; mongoc_cmd_parts_t parts; mongoc_cluster_t *cluster = &client->cluster; bool r; BSON_ASSERT_PARAM (client); while (!mongoc_server_session_pool_is_empty (t->session_pool)) { prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY_PREFERRED); const mongoc_ss_log_context_t ss_log_context = { .operation = "endSessions", .has_operation_id = true, .operation_id = 1 + cluster->operation_id}; server_id = mongoc_topology_select_server_id (t, MONGOC_SS_READ, &ss_log_context, prefs, NULL /* chosen read mode */, NULL /* deprioritized servers */, &error); mongoc_read_prefs_destroy (prefs); if (!server_id) { MONGOC_WARNING ("Couldn't send \"endSessions\": %s", error.message); return; } stream = mongoc_cluster_stream_for_server (cluster, server_id, false /* reconnect_ok */, NULL, NULL, &error); if (!stream) { MONGOC_WARNING ("Couldn't send \"endSessions\": %s", error.message); return; } /* end sessions in chunks */ while (_mongoc_topology_end_sessions_cmd (t, &cmd)) { mongoc_cmd_parts_init (&parts, client, "admin", MONGOC_QUERY_SECONDARY_OK, &cmd); parts.assembled.operation_id = ++cluster->operation_id; parts.prohibit_lsid = true; r = mongoc_cmd_parts_assemble (&parts, stream, &error); if (!r) { MONGOC_WARNING ("Couldn't construct \"endSessions\" command: %s", error.message); } else { r = mongoc_cluster_run_command_monitored (cluster, &parts.assembled, NULL, &error); if (!r) { MONGOC_WARNING ("Couldn't send \"endSessions\": %s", error.message); } } mongoc_cmd_parts_cleanup (&parts); if (!mongoc_cluster_stream_valid (cluster, stream)) { /* The stream was invalidated as a result of a network error, so we * stop sending commands. */ break; } bson_destroy (&cmd); } bson_destroy (&cmd); mongoc_server_stream_cleanup (stream); } } void mongoc_client_reset (mongoc_client_t *client) { BSON_ASSERT_PARAM (client); client->generation++; /* Client sessions are owned and destroyed by the user, but we keep local pointers to them for reference. On reset, clear our local set without destroying the sessions or calling endSessions. client_sessions has no dtor, so it won't destroy its items. Destroying the local cache of client sessions here ensures they cannot be used by future operations--lookup for them will fail. */ mongoc_set_destroy (client->client_sessions); client->client_sessions = mongoc_set_new (8, NULL, NULL); /* Server sessions are owned by us, so we clear the pool on reset. */ mongoc_server_session_pool_clear (client->topology->session_pool); } mongoc_change_stream_t * mongoc_client_watch (mongoc_client_t *client, const bson_t *pipeline, const bson_t *opts) { return _mongoc_change_stream_new_from_client (client, pipeline, opts); } bool mongoc_client_enable_auto_encryption (mongoc_client_t *client, mongoc_auto_encryption_opts_t *opts, bson_error_t *error) { BSON_ASSERT_PARAM (client); if (!client->topology->single_threaded) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Cannot enable auto encryption on a pooled client, use " "mongoc_client_pool_enable_auto_encryption"); return false; } return _mongoc_cse_client_enable_auto_encryption (client, opts, error); } bool mongoc_client_set_server_api (mongoc_client_t *client, const mongoc_server_api_t *api, bson_error_t *error) { BSON_ASSERT_PARAM (client); BSON_ASSERT_PARAM (api); if (!client->topology->single_threaded) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_API_FROM_POOL, "Cannot set server api on a client checked out from a pool"); return false; } if (mongoc_client_uses_server_api (client)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_API_ALREADY_SET, "Cannot set server api more than once per client"); return false; } client->api = mongoc_server_api_copy (api); _mongoc_topology_scanner_set_server_api (client->topology->scanner, api); return true; } mongoc_server_description_t * mongoc_client_get_handshake_description (mongoc_client_t *client, uint32_t server_id, bson_t *opts, bson_error_t *error) { mongoc_server_stream_t *server_stream; mongoc_server_description_t *sd; BSON_ASSERT_PARAM (client); BSON_UNUSED (opts); server_stream = mongoc_cluster_stream_for_server ( &client->cluster, server_id, true /* reconnect */, NULL /* client session */, NULL /* reply */, error); if (!server_stream) { return NULL; } sd = mongoc_server_description_new_copy (server_stream->sd); mongoc_server_stream_cleanup (server_stream); return sd; } bool mongoc_client_uses_server_api (const mongoc_client_t *client) { BSON_ASSERT_PARAM (client); return mongoc_topology_uses_server_api (client->topology); } bool mongoc_client_uses_loadbalanced (const mongoc_client_t *client) { BSON_ASSERT_PARAM (client); return mongoc_topology_uses_loadbalanced (client->topology); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-client.h0000644000175100001660000003044114760300420022417 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLIENT_H #define MONGOC_CLIENT_H #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #endif #include #include #include #include #include #include BSON_BEGIN_DECLS /* This define is part of our public API. But per MongoDB 4.4, there is no * longer a size limit on collection names. */ #define MONGOC_NAMESPACE_MAX 128 #ifndef MONGOC_DEFAULT_CONNECTTIMEOUTMS #define MONGOC_DEFAULT_CONNECTTIMEOUTMS (10 * 1000L) #endif #ifndef MONGOC_DEFAULT_SOCKETTIMEOUTMS /* * NOTE: The default socket timeout for connections is 5 minutes. This * means that if your MongoDB server dies or becomes unavailable * it will take 5 minutes to detect this. * * You can change this by providing sockettimeoutms= in your * connection URI. */ #define MONGOC_DEFAULT_SOCKETTIMEOUTMS (1000L * 60L * 5L) #endif /** * mongoc_client_t: * * The mongoc_client_t structure maintains information about a connection to * a MongoDB server. */ typedef struct _mongoc_client_t mongoc_client_t; typedef struct _mongoc_client_session_t mongoc_client_session_t; typedef struct _mongoc_session_opt_t mongoc_session_opt_t; typedef struct _mongoc_transaction_opt_t mongoc_transaction_opt_t; /** * mongoc_stream_initiator_t: * @uri: The uri and options for the stream. * @host: The host and port (or UNIX domain socket path) to connect to. * @user_data: The pointer passed to mongoc_client_set_stream_initiator. * @error: A location for an error. * * Creates a new mongoc_stream_t for the host and port. Begin a * non-blocking connect and return immediately. * * This can be used by language bindings to create network transports other * than those built into libmongoc. An example of such would be the streams * API provided by PHP. * * Returns: A newly allocated mongoc_stream_t or NULL on failure. */ typedef mongoc_stream_t *(*mongoc_stream_initiator_t) (const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *user_data, bson_error_t *error); MONGOC_EXPORT (mongoc_client_t *) mongoc_client_new (const char *uri_string) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_client_t *) mongoc_client_new_from_uri (const mongoc_uri_t *uri) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_client_t *) mongoc_client_new_from_uri_with_error (const mongoc_uri_t *uri, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_set_sockettimeoutms (mongoc_client_t *client, int32_t timeoutms); MONGOC_EXPORT (const mongoc_uri_t *) mongoc_client_get_uri (const mongoc_client_t *client); MONGOC_EXPORT (void) mongoc_client_set_stream_initiator (mongoc_client_t *client, mongoc_stream_initiator_t initiator, void *user_data); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_client_command (mongoc_client_t *client, const char *db_name, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_client_command_simple); MONGOC_EXPORT (void) mongoc_client_kill_cursor (mongoc_client_t *client, int64_t cursor_id) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (bool) mongoc_client_command_simple (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_read_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_write_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_read_write_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs /* IGNORED */, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_command_with_opts (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_client_command_simple_with_server_id (mongoc_client_t *client, const char *db_name, const bson_t *command, const mongoc_read_prefs_t *read_prefs, uint32_t server_id, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (void) mongoc_client_destroy (mongoc_client_t *client); MONGOC_EXPORT (mongoc_client_session_t *) mongoc_client_start_session (mongoc_client_t *client, const mongoc_session_opt_t *opts, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_database_t *) mongoc_client_get_database (mongoc_client_t *client, const char *name) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_database_t *) mongoc_client_get_default_database (mongoc_client_t *client) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_gridfs_t *) mongoc_client_get_gridfs (mongoc_client_t *client, const char *db, const char *prefix, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_collection_t *) mongoc_client_get_collection (mongoc_client_t *client, const char *db, const char *collection) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (char **) mongoc_client_get_database_names (mongoc_client_t *client, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_client_get_database_names_with_opts); MONGOC_EXPORT (char **) mongoc_client_get_database_names_with_opts (mongoc_client_t *client, const bson_t *opts, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_cursor_t *) mongoc_client_find_databases (mongoc_client_t *client, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_client_find_databases_with_opts); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_client_find_databases_with_opts (mongoc_client_t *client, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_client_get_server_status (mongoc_client_t *client, mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (int32_t) mongoc_client_get_max_message_size (mongoc_client_t *client) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (int32_t) mongoc_client_get_max_bson_size (mongoc_client_t *client) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (const mongoc_write_concern_t *) mongoc_client_get_write_concern (const mongoc_client_t *client); MONGOC_EXPORT (void) mongoc_client_set_write_concern (mongoc_client_t *client, const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (const mongoc_read_concern_t *) mongoc_client_get_read_concern (const mongoc_client_t *client); MONGOC_EXPORT (void) mongoc_client_set_read_concern (mongoc_client_t *client, const mongoc_read_concern_t *read_concern); MONGOC_EXPORT (const mongoc_read_prefs_t *) mongoc_client_get_read_prefs (const mongoc_client_t *client); MONGOC_EXPORT (void) mongoc_client_set_read_prefs (mongoc_client_t *client, const mongoc_read_prefs_t *read_prefs); #ifdef MONGOC_ENABLE_SSL MONGOC_EXPORT (void) mongoc_client_set_ssl_opts (mongoc_client_t *client, const mongoc_ssl_opt_t *opts); #endif MONGOC_EXPORT (bool) mongoc_client_set_apm_callbacks (mongoc_client_t *client, mongoc_apm_callbacks_t *callbacks, void *context); MONGOC_EXPORT (bool) mongoc_client_set_structured_log_opts (mongoc_client_t *client, const mongoc_structured_log_opts_t *opts); MONGOC_EXPORT (mongoc_server_description_t *) mongoc_client_get_server_description (mongoc_client_t *client, uint32_t server_id) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_server_description_t **) mongoc_client_get_server_descriptions (const mongoc_client_t *client, size_t *n) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_server_descriptions_destroy_all (mongoc_server_description_t **sds, size_t n); MONGOC_EXPORT (mongoc_server_description_t *) mongoc_client_select_server (mongoc_client_t *client, bool for_writes, const mongoc_read_prefs_t *prefs, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_client_set_error_api (mongoc_client_t *client, int32_t version); MONGOC_EXPORT (bool) mongoc_client_set_appname (mongoc_client_t *client, const char *appname); MONGOC_EXPORT (mongoc_change_stream_t *) mongoc_client_watch (mongoc_client_t *client, const bson_t *pipeline, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_client_reset (mongoc_client_t *client); MONGOC_EXPORT (bool) mongoc_client_enable_auto_encryption (mongoc_client_t *client, mongoc_auto_encryption_opts_t *opts, bson_error_t *error); MONGOC_EXPORT (const char *) mongoc_client_get_crypt_shared_version (const mongoc_client_t *client) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_client_set_server_api (mongoc_client_t *client, const mongoc_server_api_t *api, bson_error_t *error); MONGOC_EXPORT (mongoc_server_description_t *) mongoc_client_get_handshake_description (mongoc_client_t *client, uint32_t server_id, bson_t *opts, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_CLIENT_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-aws-private.h0000644000175100001660000001131214760300420025056 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLUSTER_AWS_PRIVATE_H #define MONGOC_CLUSTER_AWS_PRIVATE_H #include #include #include #include // bson_mutex_t bool _mongoc_cluster_auth_node_aws (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error); /* The following are declared in the private header for testing. It is only used * in test-mongoc-aws.c, mongoc-cluster-aws.c, and test-awsauth.c */ typedef struct { char *access_key_id; char *secret_access_key; char *session_token; // expiration is the time when these credentials expire. // If expiration.set is false, the credentials do not have a known // expiration. struct { mcd_timer value; bool set; } expiration; } _mongoc_aws_credentials_t; #define MONGOC_AWS_CREDENTIALS_INIT \ (_mongoc_aws_credentials_t) \ { \ .access_key_id = NULL, .secret_access_key = NULL, .session_token = NULL, \ .expiration = {.value = {.expire_at = {0}}, .set = false}, \ } #define MONGOC_AWS_CREDENTIALS_EXPIRATION_WINDOW_MS 60 * 5 * 1000 // _mongoc_aws_credentials_cache_t is a thread-safe global cache of AWS // credentials. typedef struct { struct { _mongoc_aws_credentials_t value; bool set; } cached; bson_mutex_t mutex; // guards cached. } _mongoc_aws_credentials_cache_t; extern _mongoc_aws_credentials_cache_t mongoc_aws_credentials_cache; // _mongoc_aws_credentials_cache_init initializes the global // `mongoc_aws_credentials_cache. It is expected to be called by mongoc_init. void _mongoc_aws_credentials_cache_init (void); // _mongoc_aws_credentials_cache_lock exclusively locks the cache. void _mongoc_aws_credentials_cache_lock (void); // _mongoc_aws_credentials_cache_unlock unlocks the cache. void _mongoc_aws_credentials_cache_unlock (void); // _mongoc_aws_credentials_cache_put_nolock is a non-locking variant of // _mongoc_aws_credentials_cache_put. void _mongoc_aws_credentials_cache_put_nolock (const _mongoc_aws_credentials_t *creds); // _mongoc_aws_credentials_cache_put adds credentials into the global cache. void _mongoc_aws_credentials_cache_put (const _mongoc_aws_credentials_t *creds); // _mongoc_aws_credentials_cache_get_nolock is a non-locking variant of // _mongoc_aws_credentials_cache_get. bool _mongoc_aws_credentials_cache_get_nolock (_mongoc_aws_credentials_t *creds); // _mongoc_aws_credentials_cache_get returns true if cached credentials were // retrieved. // The passed `creds` is expected to be initialized with // MONGOC_AWS_CREDENTIALS_INIT. Returns true if there are valid cached // credentials. Retrieved credentials are copied to `creds`. Callers are // expected to call // `_mongoc_aws_credentials_cleanup` on `creds`. // Returns false and zeroes `creds` if there are no valid cached credentials. bool _mongoc_aws_credentials_cache_get (_mongoc_aws_credentials_t *creds); // _mongoc_aws_credentials_cache_clear_nolock is the non-locking variant of // _mongoc_aws_credentials_cache_clear void _mongoc_aws_credentials_cache_clear_nolock (void); // _mongoc_aws_credentials_cache_clear clears credentials in the global cache void _mongoc_aws_credentials_cache_clear (void); // _mongoc_aws_credentials_cache_cleanup frees data for the global cache. // It is expected to be called by mongoc_cleanup. void _mongoc_aws_credentials_cache_cleanup (void); bool _mongoc_aws_credentials_obtain (mongoc_uri_t *uri, _mongoc_aws_credentials_t *creds, bson_error_t *error); void _mongoc_aws_credentials_copy_to (const _mongoc_aws_credentials_t *src, _mongoc_aws_credentials_t *dst); void _mongoc_aws_credentials_cleanup (_mongoc_aws_credentials_t *creds); bool _mongoc_validate_and_derive_region (char *sts_fqdn, size_t sts_fqdn_len, char **region, bson_error_t *error); #endif /* MONGOC_CLUSTER_AWS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-aws.c0000644000175100001660000013257414760300420023417 0ustar /* * Copyright 2009-present MongoDB, 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. */ /* All interaction with kms_message is limited to this file. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "aws_auth" #define AUTH_ERROR_AND_FAIL(...) \ do { \ bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, __VA_ARGS__); \ goto fail; \ } while (0) #ifdef MONGOC_ENABLE_MONGODB_AWS_AUTH #include /* * Run a single command on a stream. * * On success, returns true. * On failure, returns false and sets error. * reply is always initialized. */ static bool _run_command (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_t *command, bson_t *reply, bson_error_t *error) { mongoc_cmd_parts_t parts; mongoc_server_stream_t *server_stream; bool ret; mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (cluster)->client->topology); mongoc_cmd_parts_init (&parts, cluster->client, "$external", MONGOC_QUERY_NONE /* unused for OP_MSG */, command); /* Drivers must not append session ids to auth commands per sessions spec. */ parts.prohibit_lsid = true; server_stream = _mongoc_cluster_create_server_stream (td.ptr, sd, stream); mc_tpld_drop_ref (&td); ret = mongoc_cluster_run_command_parts (cluster, server_stream, &parts, reply, error); mongoc_server_stream_cleanup (server_stream); return ret; } /* * Utility function to parse out a server reply's payload. * * Given a server reply like { ok: 1, payload: , ... } parse out the * payload into a bson_t. * On success, returns true. * On failure, returns false and sets error. * payload is always initialized. */ static bool _sasl_reply_parse_payload_as_bson (const bson_t *reply, bson_t *payload, bson_error_t *error) { bson_iter_t iter; bson_subtype_t payload_subtype; const uint8_t *payload_data; uint32_t payload_len; bool ret = false; bson_init (payload); if (!bson_iter_init_find (&iter, reply, "payload") || !BSON_ITER_HOLDS_BINARY (&iter)) { AUTH_ERROR_AND_FAIL ("server reply did not contain binary payload"); } bson_iter_binary (&iter, &payload_subtype, &payload_len, &payload_data); if (payload_subtype != BSON_SUBTYPE_BINARY) { AUTH_ERROR_AND_FAIL ("server reply contained unexpected binary subtype"); } bson_destroy (payload); if (!bson_init_static (payload, payload_data, payload_len)) { AUTH_ERROR_AND_FAIL ("server payload is invalid BSON"); } ret = true; fail: return ret; } /* * Send an HTTP request and get a response. * On success, returns true. * On failure, returns false and sets error. * headers is a \r\n delimitted list of headers (or an empty string). * http_response_body is always set, and must be freed. * http_response_headers is always set, and must be freed. This may be used for * error reporting since the response headers should not include sensitive * credentials. */ static bool _send_http_request (bool use_tls, const char *ip, int port, const char *method, const char *path, const char *headers, char **http_response_body, char **http_response_headers, bson_error_t *error) { mongoc_http_request_t req; mongoc_http_response_t res; const int socket_timeout_ms = 10000; bool ret; mongoc_ssl_opt_t ssl_opt = {0}; *http_response_body = NULL; *http_response_headers = NULL; _mongoc_http_request_init (&req); _mongoc_http_response_init (&res); req.host = ip; req.port = port; req.method = method; req.path = path; req.extra_headers = headers; if (use_tls) { _mongoc_ssl_opts_copy_to (mongoc_ssl_opt_get_default (), &ssl_opt, true /* copy_internal */); } ret = _mongoc_http_send (&req, socket_timeout_ms, use_tls /* use_tls */, use_tls ? &ssl_opt : NULL, &res, error); if (ret) { *http_response_headers = bson_strndup (res.headers, res.headers_len); *http_response_body = (char *) bson_malloc0 (res.body_len + 1); memcpy (*http_response_body, res.body, res.body_len); } _mongoc_http_response_cleanup (&res); _mongoc_ssl_opts_cleanup (&ssl_opt, true); return ret; } static bool _creds_empty (_mongoc_aws_credentials_t *creds) { return creds->access_key_id == NULL && creds->secret_access_key == NULL && creds->session_token == NULL; } /* * Helper to validate and possibly set credentials. * * On success, returns true. * On failure, returns false and sets error. * Caller should use _creds_empty to determine whether credentials have been * set. */ static bool _validate_and_set_creds (const char *access_key_id, const char *secret_access_key, const char *session_token, _mongoc_aws_credentials_t *creds, bson_error_t *error) { bool has_access_key_id = access_key_id && strlen (access_key_id) != 0; bool has_secret_access_key = secret_access_key && strlen (secret_access_key) != 0; bool has_session_token = session_token && strlen (session_token) != 0; bool ret = false; /* Check for invalid combinations of URI parameters. */ if (has_access_key_id && !has_secret_access_key) { AUTH_ERROR_AND_FAIL ("ACCESS_KEY_ID is set, but SECRET_ACCESS_KEY is missing"); } if (!has_access_key_id && has_secret_access_key) { AUTH_ERROR_AND_FAIL ("SECRET_ACCESS_KEY is set, but ACCESS_KEY_ID is missing"); } if (!has_access_key_id && !has_secret_access_key && has_session_token) { AUTH_ERROR_AND_FAIL ("AWS_SESSION_TOKEN is set, but ACCESS_KEY_ID and " "SECRET_ACCESS_KEY are missing"); } creds->access_key_id = bson_strdup (access_key_id); creds->secret_access_key = bson_strdup (secret_access_key); creds->session_token = session_token ? bson_strdup (session_token) : NULL; ret = true; fail: return ret; } /* * Validate and possibly set credentials. * * On success, returns true. * On failure, returns false and sets error. * Caller should use _creds_empty to determine whether credentials have been * set. */ static bool _obtain_creds_from_uri (_mongoc_aws_credentials_t *creds, mongoc_uri_t *uri, bson_error_t *error) { bool ret = false; bson_t auth_mechanism_props; const char *uri_session_token = NULL; if (mongoc_uri_get_mechanism_properties (uri, &auth_mechanism_props)) { bson_iter_t iter; if (bson_iter_init_find_case (&iter, &auth_mechanism_props, "AWS_SESSION_TOKEN") && BSON_ITER_HOLDS_UTF8 (&iter)) { uri_session_token = bson_iter_utf8 (&iter, NULL); } } if (!_validate_and_set_creds ( mongoc_uri_get_username (uri), mongoc_uri_get_password (uri), uri_session_token, creds, error)) { goto fail; } ret = true; fail: return ret; } static bool _obtain_creds_from_env (_mongoc_aws_credentials_t *creds, bson_error_t *error) { bool ret = false; char *env_access_key_id = NULL; char *env_secret_access_key = NULL; char *env_session_token = NULL; /* Check environment variables. */ env_access_key_id = _mongoc_getenv ("AWS_ACCESS_KEY_ID"); env_secret_access_key = _mongoc_getenv ("AWS_SECRET_ACCESS_KEY"); env_session_token = _mongoc_getenv ("AWS_SESSION_TOKEN"); if (!_validate_and_set_creds (env_access_key_id, env_secret_access_key, env_session_token, creds, error)) { goto fail; } ret = true; fail: bson_free (env_access_key_id); bson_free (env_secret_access_key); bson_free (env_session_token); return ret; } // expiration_ms_to_timer converts milliseconds since Unix Epoch into the // mcd_timer `expiration_timer`. static bool expiration_ms_to_timer (int64_t expiration_ms, mcd_timer *expiration_timer, bson_error_t *error) { bool ret = false; // get current time in milliseconds since Unix Epoch. int64_t now_ms; { struct timeval now; if (0 != bson_gettimeofday (&now)) { AUTH_ERROR_AND_FAIL ("bson_gettimeofday returned failure. Unable to " "determine expiration."); } else { now_ms = (1000 * now.tv_sec) + (now.tv_usec / 1000); } } *expiration_timer = mcd_timer_expire_after (mcd_milliseconds (expiration_ms - now_ms - MONGOC_AWS_CREDENTIALS_EXPIRATION_WINDOW_MS)); ret = true; fail: return ret; } // expiration_iso8601_to_timer parses the "Expiration" string value returned // from an ECS or EC2 response. "Expiration" is expected to be an ISO-8601 // string. Example: "2023-02-07T20:04:27Z". On success, `expiration_timer` is // set to the expiration time. static bool expiration_iso8601_to_timer (const char *expiration_str, mcd_timer *expiration_timer, bson_error_t *error) { bool ret = false; // get expiration time in milliseconds since Unix Epoch. int64_t expiration_ms; { bson_error_t json_err; bson_t date_doc; bson_iter_t date_iter; char *date_doc_str; // libbson has private API `_bson_iso8601_date_parse` to parse ISO-8601 // strings. The private API is inaccessible to libmongoc. // Create a temporary bson document with a $date to parse. date_doc_str = bson_strdup_printf ("{\"Expiration\" : {\"$date\" : \"%s\"}}", expiration_str); if (!bson_init_from_json (&date_doc, date_doc_str, -1, &json_err)) { bson_free (date_doc_str); AUTH_ERROR_AND_FAIL ("failed to parse Expiration: %s", json_err.message); } BSON_ASSERT (bson_iter_init_find (&date_iter, &date_doc, "Expiration")); expiration_ms = bson_iter_date_time (&date_iter); bson_free (date_doc_str); bson_destroy (&date_doc); } if (!expiration_ms_to_timer (expiration_ms, expiration_timer, error)) { goto fail; } ret = true; fail: return ret; } // generate_AWS_ROLE_SESSION_NAME generates a 16 byte hex string (32 characters) // to use as the AWS_ROLE_SESSION_NAME. static char * generate_AWS_ROLE_SESSION_NAME (bson_error_t *error) { #define NUM_BYTES 16 bool ok = false; uint8_t data[NUM_BYTES]; char *out = bson_malloc (NUM_BYTES * 2 + 1); if (!_mongoc_rand_bytes (data, NUM_BYTES)) { AUTH_ERROR_AND_FAIL ("unable to generate random bytes for AWS_ROLE_SESSION_NAME"); } size_t i; for (i = 0; i < NUM_BYTES; i++) { // Expect no truncation. int req = bson_snprintf (out + (2 * i), 3, "%02x", data[i]); BSON_ASSERT (req < 3); } out[NUM_BYTES * 2] = '\0'; ok = true; fail: if (!ok) { bson_free (out); out = NULL; } return out; #undef NUM_BYTES } static bool _obtain_creds_from_ecs (_mongoc_aws_credentials_t *creds, bson_error_t *error) { bool ret = false; char *http_response_headers = NULL; char *http_response_body = NULL; char *relative_ecs_uri = NULL; bson_t *response_json = NULL; bson_iter_t iter; const char *ecs_access_key_id = NULL; const char *ecs_secret_access_key = NULL; const char *ecs_session_token = NULL; bson_error_t http_error; relative_ecs_uri = _mongoc_getenv ("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"); if (!relative_ecs_uri || strlen (relative_ecs_uri) == 0) { bson_free (relative_ecs_uri); return true; } if (!_send_http_request (false /* use_tls */, "169.254.170.2", 80, "GET", relative_ecs_uri, "", &http_response_body, &http_response_headers, &http_error)) { AUTH_ERROR_AND_FAIL ("failed to contact ECS link local server: %s", http_error.message); } response_json = bson_new_from_json ((const uint8_t *) http_response_body, strlen (http_response_body), error); if (!response_json) { AUTH_ERROR_AND_FAIL ("invalid JSON in ECS response. Response headers: %s", http_response_headers); } if (bson_iter_init_find_case (&iter, response_json, "AccessKeyId") && BSON_ITER_HOLDS_UTF8 (&iter)) { ecs_access_key_id = bson_iter_utf8 (&iter, NULL); } if (bson_iter_init_find_case (&iter, response_json, "SecretAccessKey") && BSON_ITER_HOLDS_UTF8 (&iter)) { ecs_secret_access_key = bson_iter_utf8 (&iter, NULL); } if (bson_iter_init_find_case (&iter, response_json, "Token") && BSON_ITER_HOLDS_UTF8 (&iter)) { ecs_session_token = bson_iter_utf8 (&iter, NULL); } if (bson_iter_init_find_case (&iter, response_json, "Expiration") && BSON_ITER_HOLDS_UTF8 (&iter)) { if (!expiration_iso8601_to_timer (bson_iter_utf8 (&iter, NULL), &creds->expiration.value, error)) { goto fail; } creds->expiration.set = true; } if (!_validate_and_set_creds (ecs_access_key_id, ecs_secret_access_key, ecs_session_token, creds, error)) { goto fail; } ret = true; fail: bson_destroy (response_json); bson_free (http_response_headers); bson_free (http_response_body); bson_free (relative_ecs_uri); return ret; } static bool _obtain_creds_from_assumerolewithwebidentity (_mongoc_aws_credentials_t *creds, bson_error_t *error) { bool ret = false; char *http_response_headers = NULL; char *http_response_body = NULL; char *aws_web_identity_token_file = NULL; char *aws_role_arn = NULL; char *aws_role_session_name = NULL; bson_t *response_bson = NULL; bson_iter_t iter; const char *access_key_id = NULL; const char *secret_access_key = NULL; const char *session_token = NULL; bson_error_t http_error; mongoc_stream_t *fstream = NULL; mcommon_string_t *token_file_contents = NULL; char *path_and_query = NULL; aws_web_identity_token_file = _mongoc_getenv ("AWS_WEB_IDENTITY_TOKEN_FILE"); aws_role_arn = _mongoc_getenv ("AWS_ROLE_ARN"); if (!aws_web_identity_token_file || strlen (aws_web_identity_token_file) == 0 || !aws_role_arn || strlen (aws_role_arn) == 0) { bson_free (aws_role_arn); bson_free (aws_web_identity_token_file); // Not an error. May need to obtain credentials another way. return true; } aws_role_session_name = _mongoc_getenv ("AWS_ROLE_SESSION_NAME"); if (!aws_role_session_name) { aws_role_session_name = generate_AWS_ROLE_SESSION_NAME (error); if (!aws_role_session_name) { goto fail; } } // Read the contents of the file given by ``AWS_WEB_IDENTITY_TOKEN_FILE``. { fstream = mongoc_stream_file_new_for_path (aws_web_identity_token_file, O_RDONLY, 0); if (!fstream) { AUTH_ERROR_AND_FAIL ("failed to open AWS_WEB_IDENTITY_TOKEN_FILE: %s. Reason: %s", aws_web_identity_token_file, strerror (errno)); } mcommon_string_append_t append; mcommon_string_new_as_append (&append); for (;;) { char buf[128]; ssize_t got = mongoc_stream_read (fstream, buf, sizeof (buf) - 1 /* leave space for null terminator */, 0 /* min_bytes */, 0 /* timeout_msec. Unused for file stream. */); if (got > 0) { mcommon_string_append_bytes (&append, (const char *) buf, (uint32_t) got); } else if (got == 0) { // EOF. break; } else { AUTH_ERROR_AND_FAIL ("failed to read AWS_WEB_IDENTITY_TOKEN_FILE: %s. Reason: %s", aws_web_identity_token_file, strerror (errno)); } } token_file_contents = mcommon_string_from_append (&append); } path_and_query = bson_strdup_printf ("/?Action=AssumeRoleWithWebIdentity" "&RoleSessionName=%s" "&RoleArn=%s" "&WebIdentityToken=%s&Version=2011-06-15", aws_role_session_name, aws_role_arn, token_file_contents->str); // send an HTTP request to sts.amazonaws.com. if (!_send_http_request (true /* use_tls */, "sts.amazonaws.com", 443, "POST", path_and_query, "Accept: application/json\r\n", &http_response_body, &http_response_headers, &http_error)) { AUTH_ERROR_AND_FAIL ("failed to contact sts.amazonaws.com: %s", http_error.message); } response_bson = bson_new_from_json ((const uint8_t *) http_response_body, strlen (http_response_body), error); if (!response_bson) { AUTH_ERROR_AND_FAIL ("invalid JSON in response from sts.amazonaws.com. " "Response headers: %s", http_response_headers); } if (!bson_iter_init (&iter, response_bson)) { AUTH_ERROR_AND_FAIL ("failed to initialize BSON iterator to response: %s", http_response_body); } // If the response contains "Error", return only the "Error" document. // Do not include http_response_body in subsequent errors to limit risk of // including credentials in error messages. bson_iter_t Error_iter; if (bson_iter_init_find (&Error_iter, response_bson, "Error")) { bson_t Error_bson; if (!_mongoc_iter_document_as_bson (&Error_iter, &Error_bson, error)) { goto fail; } char *Error_json = bson_as_relaxed_extended_json (&Error_bson, NULL); bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Response to AssumeRoleWithWebIdentity contains 'Error': %s", Error_json); bson_free (Error_json); goto fail; } bson_iter_t Credentials_iter; if (!bson_iter_find_descendant (&iter, "AssumeRoleWithWebIdentityResponse.AssumeRoleWithWebIdentityResult." "Credentials", &iter)) { AUTH_ERROR_AND_FAIL ("did not find " "AssumeRoleWithWebIdentityResponse.AssumeRoleWithWebIdentityResult." "Credentials in response from sts.amazonaws.com."); } if (!bson_iter_recurse (&iter, &Credentials_iter)) { AUTH_ERROR_AND_FAIL ("Unable to recurse in Credentials in response from sts.amazonaws.com"); } iter = Credentials_iter; if (bson_iter_find (&iter, "AccessKeyId") && BSON_ITER_HOLDS_UTF8 (&iter)) { access_key_id = bson_iter_utf8 (&iter, NULL); } else { AUTH_ERROR_AND_FAIL ("did not find AccessKeyId in response from sts.amazonaws.com"); } iter = Credentials_iter; if (bson_iter_find (&iter, "SecretAccessKey") && BSON_ITER_HOLDS_UTF8 (&iter)) { secret_access_key = bson_iter_utf8 (&iter, NULL); } else { AUTH_ERROR_AND_FAIL ("did not find SecretAccessKey in response from sts.amazonaws.com"); } iter = Credentials_iter; if (bson_iter_find (&iter, "SessionToken") && BSON_ITER_HOLDS_UTF8 (&iter)) { session_token = bson_iter_utf8 (&iter, NULL); } else { AUTH_ERROR_AND_FAIL ("did not find SessionToken in response from sts.amazonaws.com"); } iter = Credentials_iter; if (bson_iter_find (&iter, "Expiration") && BSON_ITER_HOLDS_DOUBLE (&iter)) { // "Expiration" is returned as a double representing the number of seconds // since Unix Epoch. This differs from the ISO-8601 string returned in EC2 // and ECS responses. int64_t expiration_ms = (int64_t) (1000.0 * bson_iter_double (&iter)); if (!expiration_ms_to_timer (expiration_ms, &creds->expiration.value, error)) { goto fail; } creds->expiration.set = true; } else { AUTH_ERROR_AND_FAIL ("did not find Expiration in response from sts.amazonaws.com"); } if (!_validate_and_set_creds (access_key_id, secret_access_key, session_token, creds, error)) { goto fail; } ret = true; fail: bson_free (path_and_query); bson_destroy (response_bson); bson_free (http_response_headers); bson_free (http_response_body); mcommon_string_destroy (token_file_contents); mongoc_stream_destroy (fstream); bson_free (aws_role_session_name); bson_free (aws_role_arn); bson_free (aws_web_identity_token_file); return ret; } static bool _obtain_creds_from_ec2 (_mongoc_aws_credentials_t *creds, bson_error_t *error) { bool ret = false; char *http_response_headers = NULL; char *http_response_body = NULL; char *token_header = NULL; char *token = NULL; char *role_name = NULL; char *relative_ecs_uri = NULL; char *path_with_role = NULL; bson_t *response_json = NULL; bson_iter_t iter; const char *ec2_access_key_id = NULL; const char *ec2_secret_access_key = NULL; const char *ec2_session_token = NULL; bson_error_t http_error; const char *ip = "169.254.169.254"; /* Get the token. */ if (!_send_http_request (false /* use_tls */, ip, 80, "PUT", "/latest/api/token", "X-aws-ec2-metadata-token-ttl-seconds: 30\r\n", &token, &http_response_headers, &http_error)) { AUTH_ERROR_AND_FAIL ("failed to contact EC2 link local server: %s", http_error.message); } if (0 == strlen (token)) { AUTH_ERROR_AND_FAIL ("unable to retrieve token from EC2 metadata. Headers: %s", http_response_headers); } bson_free (http_response_headers); http_response_headers = NULL; token_header = bson_strdup_printf ("X-aws-ec2-metadata-token: %s\r\n", token); /* Get the role name. */ if (!_send_http_request (false /* use_tls */, ip, 80, "GET", "/latest/meta-data/iam/security-credentials/", token_header, &role_name, &http_response_headers, &http_error)) { AUTH_ERROR_AND_FAIL ("failed to contact EC2 link local server: %s", http_error.message); } if (0 == strlen (role_name)) { AUTH_ERROR_AND_FAIL ("unable to retrieve role_name from EC2 metadata. Headers: %s", http_response_headers); } /* Get the creds. */ path_with_role = bson_strdup_printf ("/latest/meta-data/iam/security-credentials/%s", role_name); bson_free (http_response_headers); http_response_headers = NULL; if (!_send_http_request (false /* use_tls */, ip, 80, "GET", path_with_role, token_header, &http_response_body, &http_response_headers, &http_error)) { AUTH_ERROR_AND_FAIL ("failed to contact EC2 link local server: %s", http_error.message); } response_json = bson_new_from_json ((const uint8_t *) http_response_body, strlen (http_response_body), error); if (!response_json) { AUTH_ERROR_AND_FAIL ("invalid JSON in EC2 response. Response headers: %s", http_response_headers); } if (bson_iter_init_find_case (&iter, response_json, "AccessKeyId") && BSON_ITER_HOLDS_UTF8 (&iter)) { ec2_access_key_id = bson_iter_utf8 (&iter, NULL); } if (bson_iter_init_find_case (&iter, response_json, "SecretAccessKey") && BSON_ITER_HOLDS_UTF8 (&iter)) { ec2_secret_access_key = bson_iter_utf8 (&iter, NULL); } if (bson_iter_init_find_case (&iter, response_json, "Token") && BSON_ITER_HOLDS_UTF8 (&iter)) { ec2_session_token = bson_iter_utf8 (&iter, NULL); } if (bson_iter_init_find_case (&iter, response_json, "Expiration") && BSON_ITER_HOLDS_UTF8 (&iter)) { if (!expiration_iso8601_to_timer (bson_iter_utf8 (&iter, NULL), &creds->expiration.value, error)) { goto fail; } creds->expiration.set = true; } if (!_validate_and_set_creds (ec2_access_key_id, ec2_secret_access_key, ec2_session_token, creds, error)) { goto fail; } ret = true; fail: bson_destroy (response_json); bson_free (http_response_headers); bson_free (http_response_body); bson_free (token); bson_free (role_name); bson_free (token_header); bson_free (relative_ecs_uri); bson_free (path_with_role); return ret; } /* * Attempt to obtain AWS credentials. * * Credentials may be passed in multiple ways. The precedence is as follows: * 1. Username/password in the URI (and authMechanismProperty for session token) * 2. From environment variables. * 3. From querying the ECS local HTTP server. * 4. From querying the EC2 local HTTP server. * * On success, returns true. * On failure, returns false and sets error. */ bool _mongoc_aws_credentials_obtain (mongoc_uri_t *uri, _mongoc_aws_credentials_t *creds, bson_error_t *error) { bool ret = false; BSON_ASSERT_PARAM (creds); *creds = MONGOC_AWS_CREDENTIALS_INIT; // Check cache before enviroment variables. This is required by the // specification: "Even if the environment variables are present in // subsequent authorization attempts, the driver MUST use the cached // credentials" if (_mongoc_aws_credentials_cache_get (creds)) { goto succeed; } if (uri) { TRACE ("%s", "checking URI for credentials"); if (!_obtain_creds_from_uri (creds, uri, error)) { goto fail; } if (!_creds_empty (creds)) { goto succeed; } } TRACE ("%s", "checking environment variables for credentials"); if (!_obtain_creds_from_env (creds, error)) { goto fail; } if (!_creds_empty (creds)) { goto succeed; } // Try to fetch credentials from cacheable sources: // AssumeRoleWithWebIdentity, ECS or EC2. Lock the cache to prevent duplicate // requests. { _mongoc_aws_credentials_cache_lock (); // Check again if credentials have been cached. if (_mongoc_aws_credentials_cache_get_nolock (creds)) { _mongoc_aws_credentials_cache_unlock (); goto succeed; } TRACE ("%s", "checking AssumeRoleWithWebIdentity for credentials"); if (!_obtain_creds_from_assumerolewithwebidentity (creds, error)) { _mongoc_aws_credentials_cache_unlock (); goto fail; } if (!_creds_empty (creds)) { if (creds->expiration.set) { // Only try to cache credentials if an expiration time is included. _mongoc_aws_credentials_cache_put_nolock (creds); } _mongoc_aws_credentials_cache_unlock (); goto succeed; } TRACE ("%s", "checking ECS metadata for credentials"); if (!_obtain_creds_from_ecs (creds, error)) { _mongoc_aws_credentials_cache_unlock (); goto fail; } if (!_creds_empty (creds)) { if (creds->expiration.set) { // Only try to cache credentials if an expiration time is included. _mongoc_aws_credentials_cache_put_nolock (creds); } _mongoc_aws_credentials_cache_unlock (); goto succeed; } TRACE ("%s", "checking EC2 metadata for credentials"); if (!_obtain_creds_from_ec2 (creds, error)) { _mongoc_aws_credentials_cache_unlock (); goto fail; } if (!_creds_empty (creds)) { if (creds->expiration.set) { // Only try to cache credentials if an expiration time is included. _mongoc_aws_credentials_cache_put_nolock (creds); } _mongoc_aws_credentials_cache_unlock (); goto succeed; } _mongoc_aws_credentials_cache_unlock (); } AUTH_ERROR_AND_FAIL ("unable to get credentials\n"); succeed: ret = true; fail: return ret; } /* * Validate the STS host returned by the server and derive the region. * * On success, returns true. * On failure, returns false and sets error. * region is always set and must be freed by caller. */ bool _mongoc_validate_and_derive_region (char *sts_fqdn, size_t sts_fqdn_len, char **region, bson_error_t *error) { bool ret = false; char *ptr; char *ptr_prev; char *second_part = NULL; /* Default to us-east-1. */ *region = bson_strdup ("us-east-1"); /* Drivers must also validate that the host is greater than 0 and less than * or equal to 255 bytes per RFC 1035 */ if (sts_fqdn_len == 0u) { AUTH_ERROR_AND_FAIL ("invalid STS host: empty"); } if (sts_fqdn_len > 255u) { AUTH_ERROR_AND_FAIL ("invalid STS host: too large"); } /* If sts.amazonaws.com, then use default region. */ if (0 == bson_strcasecmp ("sts.amazonaws.com", sts_fqdn)) { goto succeed; } /* Drivers MUST reject FQDN names with empty labels, e.g., "abc..def" */ ptr_prev = sts_fqdn; ptr = strstr (sts_fqdn, "."); if (ptr) { second_part = ptr + 1; } if (0 == ptr - sts_fqdn) { AUTH_ERROR_AND_FAIL ("invalid STS host: empty part"); } while (ptr) { if (1 == ptr - ptr_prev) { AUTH_ERROR_AND_FAIL ("invalid STS host: empty part"); } ptr_prev = ptr; ptr = strstr (ptr + 1, "."); } if (strlen (ptr_prev + 1) == 0) { AUTH_ERROR_AND_FAIL ("invalid STS host: empty part"); } if (second_part) { char *second_part_end; second_part_end = strstr (second_part, "."); bson_free (*region); if (!second_part_end) { *region = bson_strdup (second_part); } else { *region = bson_strndup (second_part, second_part_end - second_part); } } succeed: ret = true; fail: return ret; } /* -------------------------------------------------------------------------- * Step 1 * -------------------------------------------------------------------------- * Client sends BSON payload: * { * "r": <32 byte client nonce>, * "p": 110 * } * Server responds with BSON payload: * { * "s": <32 byte client nonce + 32 byte server nonce>, * "h": * } * * Payloads are wrapped in SASL commands. The command a client sends is like: * { "saslStart": 1, "mechanism": "MONGODB-AWS", "payload": } * And similar for server responses: * { "ok": 1, "conversationId": 1, "done": false, "payload": } * * On success, returns true. * On failure, returns false and sets error. * -------------------------------------------------------------------------- */ static bool _client_first (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, uint8_t *server_nonce, char **sts_fqdn, char **region, int *conv_id, bson_error_t *error) { bool ret = false; uint8_t client_nonce[32]; bson_t client_payload = BSON_INITIALIZER; bson_t client_command = BSON_INITIALIZER; bson_t server_payload = BSON_INITIALIZER; bson_t server_reply = BSON_INITIALIZER; bson_iter_t iter; bson_subtype_t reply_nonce_subtype; const uint8_t *reply_nonce_data; uint32_t reply_nonce_len; uint32_t sts_fqdn_len; /* Reset out params. */ memset (server_nonce, 0, 32); *sts_fqdn = NULL; *region = NULL; *conv_id = 0; #ifdef MONGOC_ENABLE_CRYPTO /* Generate secure random nonce. */ if (!_mongoc_rand_bytes (client_nonce, 32)) { AUTH_ERROR_AND_FAIL ("Could not generate client nonce"); } #else AUTH_ERROR_AND_FAIL ("libmongoc requires a cryptography library (libcrypto, " "Common Crypto, or cng) to support MONGODB-AWS"); #endif BCON_APPEND (&client_payload, "r", BCON_BIN (BSON_SUBTYPE_BINARY, client_nonce, 32), "p", BCON_INT32 (110)); BCON_APPEND (&client_command, "saslStart", BCON_INT32 (1), "mechanism", "MONGODB-AWS", "payload", BCON_BIN (BSON_SUBTYPE_BINARY, bson_get_data (&client_payload), client_payload.len)); bson_destroy (&server_reply); if (!_run_command (cluster, stream, sd, &client_command, &server_reply, error)) { goto fail; } *conv_id = _mongoc_cluster_get_conversation_id (&server_reply); if (!*conv_id) { AUTH_ERROR_AND_FAIL ("server reply did not contain conversationId"); } bson_destroy (&server_payload); if (!_sasl_reply_parse_payload_as_bson (&server_reply, &server_payload, error)) { goto fail; } if (!bson_iter_init_find (&iter, &server_payload, "h") || !BSON_ITER_HOLDS_UTF8 (&iter)) { AUTH_ERROR_AND_FAIL ("server payload did not contain string STS FQDN"); } *sts_fqdn = bson_strdup (bson_iter_utf8 (&iter, &sts_fqdn_len)); if (!_mongoc_validate_and_derive_region (*sts_fqdn, sts_fqdn_len, region, error)) { goto fail; } if (!bson_iter_init_find (&iter, &server_payload, "s") || !BSON_ITER_HOLDS_BINARY (&iter)) { AUTH_ERROR_AND_FAIL ("server payload did not contain nonce"); } bson_iter_binary (&iter, &reply_nonce_subtype, &reply_nonce_len, &reply_nonce_data); if (reply_nonce_len != 64) { AUTH_ERROR_AND_FAIL ("server reply nonce was not 64 bytes"); } if (0 != memcmp (reply_nonce_data, client_nonce, 32)) { AUTH_ERROR_AND_FAIL ("server reply nonce prefix did not match client nonce"); } /* Drivers MUST error on any additional fields */ bson_iter_init (&iter, &server_payload); while (bson_iter_next (&iter)) { const char *field; field = bson_iter_key (&iter); if (0 == strcmp (field, "h")) { continue; } if (0 == strcmp (field, "s")) { continue; } AUTH_ERROR_AND_FAIL ("unexpected field from server's reply: %s", field); } memcpy (server_nonce, reply_nonce_data, 64); ret = true; fail: bson_destroy (&client_payload); bson_destroy (&client_command); bson_destroy (&server_reply); bson_destroy (&server_payload); return ret; } #define KMS_REQUEST_ADD_HEADER(key, value) \ do { \ if (!kms_request_add_header_field (request, key, value)) { \ AUTH_ERROR_AND_FAIL ("Failed to add header '%s'", key); \ } \ } while (0) #define KMS_REQUEST_SET(fn, name, value) \ do { \ if (!fn (request, value)) { \ AUTH_ERROR_AND_FAIL ("Failed to set %s", name); \ } \ } while (0) /* -------------------------------------------------------------------------- * Step 2 * -------------------------------------------------------------------------- * Client sends BSON payload: * { * "a": , * "d": * "t": * } * * Server responds with final result. * * On success, returns true. * On failure, returns false and sets error. * -------------------------------------------------------------------------- */ static bool _client_second (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, _mongoc_aws_credentials_t *creds, const uint8_t *server_nonce, const char *sts_fqdn, const char *region, int conv_id, bson_error_t *error) { bool ret = false; kms_request_t *request = NULL; char *signature = NULL; const char *date = NULL; const size_t server_nonce_str_len = mcommon_b64_ntop_calculate_target_size (64); char *server_nonce_str = NULL; const char *body = "Action=GetCallerIdentity&Version=2011-06-15"; bson_t client_payload = BSON_INITIALIZER; bson_t client_command = BSON_INITIALIZER; bson_t server_reply = BSON_INITIALIZER; BSON_ASSERT (cluster); BSON_ASSERT (stream); BSON_ASSERT (sd); BSON_ASSERT (creds); BSON_ASSERT (server_nonce); BSON_ASSERT (sts_fqdn); BSON_ASSERT (conv_id); BSON_ASSERT (creds->access_key_id); BSON_ASSERT (creds->secret_access_key); server_nonce_str = bson_malloc (server_nonce_str_len); request = kms_request_new ("POST", "/", NULL); if (kms_request_get_error (request)) { AUTH_ERROR_AND_FAIL ("Failed to create new KMS request: %s", kms_request_get_error (request)); } if (mcommon_b64_ntop (server_nonce, 64, server_nonce_str, server_nonce_str_len) == -1) { AUTH_ERROR_AND_FAIL ("Failed to parse server nonce"); } if (!kms_request_append_payload (request, body, strlen (body))) { AUTH_ERROR_AND_FAIL ("Failed to append payload"); } KMS_REQUEST_SET (kms_request_set_access_key_id, "access key ID", creds->access_key_id); KMS_REQUEST_SET (kms_request_set_secret_key, "secret key", creds->secret_access_key); KMS_REQUEST_SET (kms_request_set_date, "date", NULL /* use current time */); KMS_REQUEST_SET (kms_request_set_region, "region", region); KMS_REQUEST_SET (kms_request_set_service, "service", "sts"); KMS_REQUEST_ADD_HEADER ("Content-Type", "application/x-www-form-urlencoded"); KMS_REQUEST_ADD_HEADER ("Host", sts_fqdn); KMS_REQUEST_ADD_HEADER ("X-MongoDB-Server-Nonce", server_nonce_str); KMS_REQUEST_ADD_HEADER ("X-MongoDB-GS2-CB-Flag", "n"); if (creds->session_token) { KMS_REQUEST_ADD_HEADER ("X-Amz-Security-Token", creds->session_token); } signature = kms_request_get_signature (request); if (kms_request_get_error (request)) { AUTH_ERROR_AND_FAIL ("Failed to get signature: %s", kms_request_get_error (request)); } date = kms_request_get_canonical_header (request, "X-Amz-Date"); if (kms_request_get_error (request)) { AUTH_ERROR_AND_FAIL ("Failed to get canonical header: %s", kms_request_get_error (request)); } BCON_APPEND (&client_payload, "a", BCON_UTF8 (signature), "d", BCON_UTF8 (date)); if (creds->session_token) { BCON_APPEND (&client_payload, "t", BCON_UTF8 (creds->session_token)); } BCON_APPEND (&client_command, "saslContinue", BCON_INT32 (1), "conversationId", BCON_INT32 (conv_id), "payload", BCON_BIN (BSON_SUBTYPE_BINARY, bson_get_data (&client_payload), client_payload.len)); bson_destroy (&server_reply); if (!_run_command (cluster, stream, sd, &client_command, &server_reply, error)) { goto fail; } ret = true; fail: bson_destroy (&client_payload); bson_destroy (&client_command); bson_destroy (&server_reply); kms_request_destroy (request); bson_free (signature); bson_free (server_nonce_str); return ret; } bool _mongoc_cluster_auth_node_aws (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { bool ret = false; uint8_t server_nonce[64]; char *sts_fqdn = NULL; char *region = NULL; int conv_id = 0; _mongoc_aws_credentials_t creds = MONGOC_AWS_CREDENTIALS_INIT; if (!_mongoc_aws_credentials_obtain (cluster->client->uri, &creds, error)) { goto fail; } if (!_client_first (cluster, stream, sd, server_nonce, &sts_fqdn, ®ion, &conv_id, error)) { goto fail; } if (!_client_second (cluster, stream, sd, &creds, server_nonce, sts_fqdn, region, conv_id, error)) { goto fail; } ret = true; fail: if (!ret) { _mongoc_aws_credentials_cache_clear (); } _mongoc_aws_credentials_cleanup (&creds); bson_free (sts_fqdn); bson_free (region); return ret; } #else bool _mongoc_cluster_auth_node_aws (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { AUTH_ERROR_AND_FAIL ("AWS auth not supported, configure libmongoc with " "ENABLE_MONGODB_AWS_AUTH=ON"); fail: return false; } bool _mongoc_aws_credentials_obtain (mongoc_uri_t *uri, _mongoc_aws_credentials_t *creds, bson_error_t *error) { AUTH_ERROR_AND_FAIL ("AWS auth not supported, configure libmongoc with " "ENABLE_MONGODB_AWS_AUTH=ON"); fail: return false; } bool _mongoc_validate_and_derive_region (char *sts_fqdn, size_t sts_fqdn_len, char **region, bson_error_t *error) { AUTH_ERROR_AND_FAIL ("AWS auth not supported, configure libmongoc with " "ENABLE_MONGODB_AWS_AUTH=ON"); fail: return false; } #endif /* MONGOC_ENABLE_MONGODB_AWS_AUTH */ void _mongoc_aws_credentials_cleanup (_mongoc_aws_credentials_t *creds) { bson_free (creds->access_key_id); bson_free (creds->secret_access_key); bson_free (creds->session_token); } void _mongoc_aws_credentials_copy_to (const _mongoc_aws_credentials_t *src, _mongoc_aws_credentials_t *dst) { BSON_ASSERT_PARAM (src); BSON_ASSERT_PARAM (dst); dst->access_key_id = bson_strdup (src->access_key_id); dst->secret_access_key = bson_strdup (src->secret_access_key); dst->session_token = bson_strdup (src->session_token); dst->expiration = src->expiration; } _mongoc_aws_credentials_cache_t mongoc_aws_credentials_cache; void _mongoc_aws_credentials_cache_init (void) { _mongoc_aws_credentials_cache_t *cache = &mongoc_aws_credentials_cache; bson_mutex_init (&cache->mutex); } static bool check_expired (const _mongoc_aws_credentials_t *creds) { if (!creds->expiration.set) { return true; } return mcd_get_milliseconds (mcd_timer_remaining (creds->expiration.value)) == 0; } void _mongoc_aws_credentials_cache_lock (void) { _mongoc_aws_credentials_cache_t *cache = &mongoc_aws_credentials_cache; bson_mutex_lock (&cache->mutex); } void _mongoc_aws_credentials_cache_unlock (void) { _mongoc_aws_credentials_cache_t *cache = &mongoc_aws_credentials_cache; bson_mutex_unlock (&cache->mutex); } void _mongoc_aws_credentials_cache_put_nolock (const _mongoc_aws_credentials_t *creds) { _mongoc_aws_credentials_cache_t *cache = &mongoc_aws_credentials_cache; BSON_ASSERT_PARAM (creds); if (check_expired (creds)) { // Do not add expired credentials. return; } _mongoc_aws_credentials_cache_clear_nolock (); _mongoc_aws_credentials_copy_to (creds, &cache->cached.value); cache->cached.set = true; } void _mongoc_aws_credentials_cache_put (const _mongoc_aws_credentials_t *creds) { _mongoc_aws_credentials_cache_lock (); _mongoc_aws_credentials_cache_put_nolock (creds); _mongoc_aws_credentials_cache_unlock (); } bool _mongoc_aws_credentials_cache_get_nolock (_mongoc_aws_credentials_t *creds) { _mongoc_aws_credentials_cache_t *cache = &mongoc_aws_credentials_cache; BSON_ASSERT_PARAM (creds); bool found_valid = false; bool expired = false; if (cache->cached.set) { expired = check_expired (&cache->cached.value); if (!expired) { found_valid = true; _mongoc_aws_credentials_copy_to (&cache->cached.value, creds); } } if (expired) { _mongoc_aws_credentials_cache_clear_nolock (); return false; } return found_valid; } bool _mongoc_aws_credentials_cache_get (_mongoc_aws_credentials_t *creds) { _mongoc_aws_credentials_cache_lock (); bool got = _mongoc_aws_credentials_cache_get_nolock (creds); _mongoc_aws_credentials_cache_unlock (); return got; } void _mongoc_aws_credentials_cache_clear_nolock (void) { _mongoc_aws_credentials_cache_t *cache = &mongoc_aws_credentials_cache; if (cache->cached.set) { _mongoc_aws_credentials_cleanup (&cache->cached.value); } cache->cached.set = false; } void _mongoc_aws_credentials_cache_clear (void) { _mongoc_aws_credentials_cache_lock (); _mongoc_aws_credentials_cache_clear_nolock (); _mongoc_aws_credentials_cache_unlock (); } void _mongoc_aws_credentials_cache_cleanup (void) { _mongoc_aws_credentials_cache_t *cache = &mongoc_aws_credentials_cache; if (cache->cached.set) { _mongoc_aws_credentials_cleanup (&cache->cached.value); } bson_mutex_destroy (&cache->mutex); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-cyrus-private.h0000644000175100001660000000212414760300420025432 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLUSTER_CYRUS_PRIVATE_H #define MONGOC_CLUSTER_CYRUS_PRIVATE_H #include #include #include bool _mongoc_cluster_auth_node_cyrus (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error); #endif /* MONGOC_CLUSTER_CYRUS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-cyrus.c0000644000175100001660000001034414760300420023760 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SASL_CYRUS #include #include #include #include #include bool _mongoc_cluster_auth_node_cyrus (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { mongoc_cmd_parts_t parts; mongoc_cyrus_t sasl; bson_iter_t iter; bool ret = false; const char *tmpstr; /* input into cyrus */ uint8_t *inbuf = NULL; uint32_t inbuf_len = 0; /* output from cyrus */ uint8_t *outbuf = NULL; uint32_t outbuf_len = 0; mc_shared_tpld td = MC_SHARED_TPLD_NULL; bson_t cmd; bson_t reply; int conv_id = 0; mongoc_server_stream_t *server_stream; BSON_ASSERT (cluster); BSON_ASSERT (stream); if (!_mongoc_cyrus_new_from_cluster (&sasl, cluster, stream, sd->host.host, error)) { return false; } for (;;) { mongoc_cmd_parts_init (&parts, cluster->client, "$external", MONGOC_QUERY_SECONDARY_OK, &cmd); parts.prohibit_lsid = true; /* If this is the first step, input buffer is NULL. */ bson_free (outbuf); outbuf = NULL; outbuf_len = 0; if (!_mongoc_cyrus_step (&sasl, inbuf, inbuf_len, &outbuf, &outbuf_len, error)) { goto failure; } bson_init (&cmd); if (sasl.step == 1) { _mongoc_cluster_build_sasl_start (&cmd, sasl.credentials.mechanism, (const char *) outbuf, outbuf_len); } else { _mongoc_cluster_build_sasl_continue (&cmd, conv_id, (const char *) outbuf, outbuf_len); } TRACE ("SASL: authenticating (step %d)", sasl.step); mc_tpld_renew_ref (&td, cluster->client->topology); server_stream = _mongoc_cluster_create_server_stream (td.ptr, sd, stream); if (!mongoc_cmd_parts_assemble (&parts, server_stream, error)) { mongoc_server_stream_cleanup (server_stream); bson_destroy (&cmd); goto failure; } if (!mongoc_cluster_run_command_private (cluster, &parts.assembled, &reply, error)) { mongoc_server_stream_cleanup (server_stream); bson_destroy (&cmd); bson_destroy (&reply); goto failure; } mongoc_server_stream_cleanup (server_stream); bson_destroy (&cmd); if (bson_iter_init_find (&iter, &reply, "done") && bson_iter_as_bool (&iter)) { bson_destroy (&reply); break; } conv_id = _mongoc_cluster_get_conversation_id (&reply); if (!bson_iter_init_find (&iter, &reply, "payload") || !BSON_ITER_HOLDS_UTF8 (&iter)) { MONGOC_DEBUG ("SASL: authentication failed"); bson_destroy (&reply); bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Received invalid SASL reply from MongoDB server."); goto failure; } tmpstr = bson_iter_utf8 (&iter, &inbuf_len); bson_free (inbuf); /* include the trailing NULL byte, since base64 decoding expects a NULL * terminates string. */ inbuf = bson_malloc (inbuf_len + 1); memcpy (inbuf, tmpstr, inbuf_len + 1); bson_destroy (&reply); mongoc_cmd_parts_cleanup (&parts); } TRACE ("%s", "SASL: authenticated"); ret = true; failure: bson_free (inbuf); bson_free (outbuf); _mongoc_cyrus_destroy (&sasl); mongoc_cmd_parts_cleanup (&parts); mc_tpld_drop_ref (&td); return ret; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-private.h0000644000175100001660000002424614760300420024300 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLUSTER_PRIVATE_H #define MONGOC_CLUSTER_PRIVATE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_cluster_node_t { mongoc_stream_t *stream; char *connection_address; /* handshake_sd is a server description created from the handshake on the * stream. */ mongoc_server_description_t *handshake_sd; } mongoc_cluster_node_t; typedef struct _mongoc_cluster_t { int64_t operation_id; int32_t request_id; int32_t sockettimeoutms; int32_t socketcheckintervalms; mongoc_uri_t *uri; unsigned requires_auth : 1; mongoc_client_t *client; mongoc_set_t *nodes; mongoc_array_t iov; } mongoc_cluster_t; void mongoc_cluster_init (mongoc_cluster_t *cluster, const mongoc_uri_t *uri, void *client); void mongoc_cluster_destroy (mongoc_cluster_t *cluster); void mongoc_cluster_set_sockettimeoutms (mongoc_cluster_t *cluster, int32_t sockettimeoutms); void mongoc_cluster_reset_sockettimeoutms (mongoc_cluster_t *cluster); void mongoc_cluster_disconnect_node (mongoc_cluster_t *cluster, uint32_t id); int32_t mongoc_cluster_get_max_bson_obj_size (mongoc_cluster_t *cluster); int32_t mongoc_cluster_get_max_msg_size (mongoc_cluster_t *cluster); size_t _mongoc_cluster_buffer_iovec (mongoc_iovec_t *iov, size_t iovcnt, int skip, char *buffer); bool mongoc_cluster_check_interval (mongoc_cluster_t *cluster, uint32_t server_id); bool mongoc_cluster_legacy_rpc_sendv_to_server (mongoc_cluster_t *cluster, mcd_rpc_message *rpc, mongoc_server_stream_t *server_stream, bson_error_t *error); bool mongoc_cluster_try_recv (mongoc_cluster_t *cluster, mcd_rpc_message *rpc, mongoc_buffer_t *buffer, mongoc_server_stream_t *server_stream, bson_error_t *error); /** * @brief Obtain a server stream appropriate for read operations on the * cluster. * * Returns a new stream (that must be freed) or NULL and sets an error via * `error`. * * @note The returned stream must be released via * `mongoc_server_stream_cleanup`. * * @note May add nodes and/or update the cluster's topology. */ mongoc_server_stream_t * mongoc_cluster_stream_for_reads (mongoc_cluster_t *cluster, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, mongoc_client_session_t *cs, const mongoc_deprioritized_servers_t *ds, bson_t *reply, bson_error_t *error); /** * @brief Obtain a server stream appropriate for write operations on the * cluster. * * Returns a new stream (that must be freed) or NULL and sets an error via * `error`. * * @note The returned stream must be released via `mongoc_server_stream_cleanup` * * @note May add nodes and/or update the cluster's topology. */ mongoc_server_stream_t * mongoc_cluster_stream_for_writes (mongoc_cluster_t *cluster, const mongoc_ss_log_context_t *log_context, mongoc_client_session_t *cs, const mongoc_deprioritized_servers_t *ds, bson_t *reply, bson_error_t *error); /** * @brief Obtain a server stream appropriate for aggregate operations with * writes on the cluster. * * Returns a new stream (that must be freed) or NULL and sets an error via * `error`. * * @note The returned stream must be released via * `mongoc_server_stream_cleanup`. * * @note May add nodes and/or update the cluster's topology. */ mongoc_server_stream_t * mongoc_cluster_stream_for_aggr_with_write (mongoc_cluster_t *cluster, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, mongoc_client_session_t *cs, bson_t *reply, bson_error_t *error); /** * @brief Obtain a server stream associated with the cluster node associated * with the given server ID. * * Returns a new server stream (that must be freed) or NULL and sets `error`. * * @param server_id The ID of a server in the cluster topology. * @param reconnect_ok If `true`, the server exists in the topology but is not * connected, then attempt to reconnect with the server. If `false`, then only * create a stream if the server is connected and ready. * * @note The returned stream must be released via `mongoc_server_stream_cleanup` * * @note May update the cluster's topology. */ mongoc_server_stream_t * mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster, uint32_t server_id, bool reconnect_ok, mongoc_client_session_t *cs, bson_t *reply, bson_error_t *error); bool mongoc_cluster_stream_valid (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream); bool mongoc_cluster_run_command_monitored (mongoc_cluster_t *cluster, mongoc_cmd_t *cmd, bson_t *reply, bson_error_t *error); // `mongoc_cluster_run_retryable_write` executes a write command and may apply retryable writes behavior. // `cmd->server_stream` is set to `*retry_server_stream` on retry. Otherwise, it is unmodified. // `*retry_server_stream` is set to a new stream on retry. The caller must call `mongoc_server_stream_cleanup`. // `*reply` must be uninitialized and is always initialized upon return. The caller must call `bson_destroy`. bool mongoc_cluster_run_retryable_write (mongoc_cluster_t *cluster, mongoc_cmd_t *cmd, bool is_retryable_write, mongoc_server_stream_t **retry_server_stream, bson_t *reply, bson_error_t *error); bool mongoc_cluster_run_command_parts (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, mongoc_cmd_parts_t *parts, bson_t *reply, bson_error_t *error); bool mongoc_cluster_run_command_private (mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, bson_t *reply, bson_error_t *error); void _mongoc_cluster_build_sasl_start (bson_t *cmd, const char *mechanism, const char *buf, uint32_t buflen); void _mongoc_cluster_build_sasl_continue (bson_t *cmd, int conv_id, const char *buf, uint32_t buflen); int _mongoc_cluster_get_conversation_id (const bson_t *reply); mongoc_server_stream_t * _mongoc_cluster_create_server_stream (const mongoc_topology_description_t *td, const mongoc_server_description_t *sd, mongoc_stream_t *stream); bool _mongoc_cluster_get_auth_cmd_x509 (const mongoc_uri_t *uri, const mongoc_ssl_opt_t *ssl_opts, bson_t *cmd /* OUT */, bson_error_t *error /* OUT */); /* Returns true if a versioned server API has been selected, otherwise returns * false. */ bool mongoc_cluster_uses_server_api (const mongoc_cluster_t *cluster); /* Returns true if load balancing mode has been selected, otherwise returns * false. */ bool mongoc_cluster_uses_loadbalanced (const mongoc_cluster_t *cluster); #ifdef MONGOC_ENABLE_CRYPTO void _mongoc_cluster_init_scram (const mongoc_cluster_t *cluster, mongoc_scram_t *scram, mongoc_crypto_hash_algorithm_t algo); bool _mongoc_cluster_get_auth_cmd_scram (mongoc_crypto_hash_algorithm_t algo, mongoc_scram_t *scram, bson_t *cmd /* OUT */, bson_error_t *error /* OUT */); #endif /* MONGOC_ENABLE_CRYPTO */ bool mcd_rpc_message_compress (mcd_rpc_message *rpc, int32_t compressor_id, int32_t compression_level, void **compressed_data, size_t *compressed_data_len, bson_error_t *error); bool mcd_rpc_message_decompress (mcd_rpc_message *rpc, void **data, size_t *data_len); bool mcd_rpc_message_decompress_if_necessary (mcd_rpc_message *rpc, void **data, size_t *data_len); BSON_END_DECLS #endif /* MONGOC_CLUSTER_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-sasl-private.h0000644000175100001660000000211514760300420025227 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLUSTER_SASL_PRIVATE_H #define MONGOC_CLUSTER_SASL_PRIVATE_H #include #include #include bool _mongoc_cluster_auth_node_sasl (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error); #endif /* MONGOC_CLUSTER_SASL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-sasl.c0000644000175100001660000000616414760300420023562 0ustar /* * Copyright 2009-present MongoDB, 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. */ /* for size_t */ #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SASL #ifdef MONGOC_ENABLE_SASL_CYRUS #include #endif #ifdef MONGOC_ENABLE_SASL_SSPI #include #endif #endif void _mongoc_cluster_build_sasl_start (bson_t *cmd, const char *mechanism, const char *buf, uint32_t buflen) { BSON_APPEND_INT32 (cmd, "saslStart", 1); BSON_APPEND_UTF8 (cmd, "mechanism", mechanism); bson_append_utf8 (cmd, "payload", 7, buf, buflen); BSON_APPEND_INT32 (cmd, "autoAuthorize", 1); } void _mongoc_cluster_build_sasl_continue (bson_t *cmd, int conv_id, const char *buf, uint32_t buflen) { BSON_APPEND_INT32 (cmd, "saslContinue", 1); BSON_APPEND_INT32 (cmd, "conversationId", conv_id); bson_append_utf8 (cmd, "payload", 7, buf, buflen); } int _mongoc_cluster_get_conversation_id (const bson_t *reply) { bson_iter_t iter; if (bson_iter_init_find (&iter, reply, "conversationId") && BSON_ITER_HOLDS_INT32 (&iter)) { return bson_iter_int32 (&iter); } return 0; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node_sasl -- * * Perform authentication for a cluster node using SASL. This is * only supported for GSSAPI at the moment. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * error may be set. * *-------------------------------------------------------------------------- */ bool _mongoc_cluster_auth_node_sasl (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { #ifndef MONGOC_ENABLE_SASL bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "The GSSAPI authentication mechanism requires libmongoc " "built with ENABLE_SASL"); return false; #elif defined(MONGOC_ENABLE_SASL_CYRUS) return _mongoc_cluster_auth_node_cyrus (cluster, stream, sd, error); #elif defined(MONGOC_ENABLE_SASL_SSPI) return _mongoc_cluster_auth_node_sspi (cluster, stream, sd, error); #endif } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-sspi-private.h0000644000175100001660000000211514760300420025243 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CLUSTER_SSPI_PRIVATE_H #define MONGOC_CLUSTER_SSPI_PRIVATE_H #include #include #include bool _mongoc_cluster_auth_node_sspi (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error); #endif /* MONGOC_CLUSTER_SSPI_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster-sspi.c0000644000175100001660000001747014760300420023600 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SASL_SSPI #include #include #include #include #include #include #include static mongoc_sspi_client_state_t * _mongoc_cluster_sspi_new (mongoc_uri_t *uri, mongoc_stream_t *stream, const char *hostname) { WCHAR *service; /* L"serviceName@hostname@REALM" */ const char *service_name = "mongodb"; ULONG flags = ISC_REQ_MUTUAL_AUTH; const char *service_realm = NULL; char *service_ascii = NULL; mongoc_sspi_client_state_t *state; size_t service_ascii_len; size_t tmp_creds_len; bson_t properties; bson_iter_t iter; char real_name[BSON_HOST_NAME_MAX + 1]; int service_len; WCHAR *pass = NULL; WCHAR *user = NULL; size_t user_len = 0; size_t pass_len = 0; int res; state = (mongoc_sspi_client_state_t *) bson_malloc0 (sizeof *state); _mongoc_sasl_set_properties (&state->sasl, uri); if (state->sasl.canonicalize_host_name && _mongoc_sasl_get_canonicalized_name (stream, real_name, sizeof real_name)) { hostname = real_name; } /* service realm is an SSPI-specific feature */ if (mongoc_uri_get_mechanism_properties (uri, &properties) && bson_iter_init_find_case (&iter, &properties, "SERVICE_REALM") && BSON_ITER_HOLDS_UTF8 (&iter)) { service_realm = bson_iter_utf8 (&iter, NULL); service_ascii = bson_strdup_printf ("%s@%s@%s", service_name, hostname, service_realm); } else { service_ascii = bson_strdup_printf ("%s@%s", service_name, hostname); } service_ascii_len = strlen (service_ascii); /* this is donated to the sspi */ service = bson_malloc0 ((service_ascii_len + 1) * sizeof (WCHAR)); service_len = MultiByteToWideChar (CP_UTF8, 0, service_ascii, (int) service_ascii_len, service, (int) service_ascii_len); service[service_len] = L'\0'; bson_free (service_ascii); if (state->sasl.pass) { tmp_creds_len = strlen (state->sasl.pass); /* this is donated to the sspi */ pass = bson_malloc0 ((tmp_creds_len + 1) * sizeof (WCHAR)); pass_len = MultiByteToWideChar (CP_UTF8, 0, state->sasl.pass, (int) tmp_creds_len, pass, (int) tmp_creds_len); pass[pass_len] = L'\0'; } if (state->sasl.user) { tmp_creds_len = strlen (state->sasl.user); /* this is donated to the sspi */ user = bson_malloc0 ((tmp_creds_len + 1) * sizeof (WCHAR)); user_len = MultiByteToWideChar (CP_UTF8, 0, state->sasl.user, (int) tmp_creds_len, user, (int) tmp_creds_len); user[user_len] = L'\0'; } res = _mongoc_sspi_auth_sspi_client_init ( service, flags, user, (ULONG) user_len, NULL, 0, pass, (ULONG) pass_len, state); if (res != MONGOC_SSPI_AUTH_GSS_ERROR) { return state; } bson_free (state); return NULL; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node_sspi -- * * Perform authentication for a cluster node using SSPI * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * error may be set. * *-------------------------------------------------------------------------- */ bool _mongoc_cluster_auth_node_sspi (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { mongoc_cmd_parts_t parts; mongoc_sspi_client_state_t *state; SEC_CHAR *buf = NULL; bson_iter_t iter; uint32_t buflen; bson_t reply; const char *tmpstr; int conv_id; bson_t cmd; int res = MONGOC_SSPI_AUTH_GSS_CONTINUE; int step; mongoc_server_stream_t *server_stream; bool ret = false; mc_shared_tpld td = MC_SHARED_TPLD_NULL; state = _mongoc_cluster_sspi_new (cluster->uri, stream, sd->host.host); if (!state) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Couldn't initialize SSPI service."); goto failure; } for (step = 0;; step++) { mongoc_cmd_parts_init (&parts, cluster->client, "$external", MONGOC_QUERY_SECONDARY_OK, &cmd); parts.prohibit_lsid = true; bson_init (&cmd); if (res == MONGOC_SSPI_AUTH_GSS_CONTINUE) { res = _mongoc_sspi_auth_sspi_client_step (state, buf); } else if (res == MONGOC_SSPI_AUTH_GSS_COMPLETE) { char *response; size_t tmp_creds_len = strlen (state->sasl.user); res = _mongoc_sspi_auth_sspi_client_unwrap (state, buf); response = bson_strdup (state->response); _mongoc_sspi_auth_sspi_client_wrap (state, response, (SEC_CHAR *) state->sasl.user, (ULONG) tmp_creds_len, 0); bson_free (response); } if (res == MONGOC_SSPI_AUTH_GSS_ERROR) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Received invalid SSPI data."); mongoc_cmd_parts_cleanup (&parts); bson_destroy (&cmd); goto failure; } if (step == 0) { _mongoc_cluster_build_sasl_start (&cmd, "GSSAPI", state->response, (uint32_t) strlen (state->response)); } else { if (state->response) { _mongoc_cluster_build_sasl_continue (&cmd, conv_id, state->response, (uint32_t) strlen (state->response)); } else { _mongoc_cluster_build_sasl_continue (&cmd, conv_id, "", 0); } } mc_tpld_renew_ref (&td, cluster->client->topology); server_stream = _mongoc_cluster_create_server_stream (td.ptr, sd, stream); if (!mongoc_cmd_parts_assemble (&parts, server_stream, error)) { mongoc_server_stream_cleanup (server_stream); mongoc_cmd_parts_cleanup (&parts); bson_destroy (&cmd); goto failure; } if (!mongoc_cluster_run_command_private (cluster, &parts.assembled, &reply, error)) { mongoc_server_stream_cleanup (server_stream); mongoc_cmd_parts_cleanup (&parts); bson_destroy (&cmd); bson_destroy (&reply); goto failure; } mongoc_server_stream_cleanup (server_stream); mongoc_cmd_parts_cleanup (&parts); bson_destroy (&cmd); if (bson_iter_init_find (&iter, &reply, "done") && bson_iter_as_bool (&iter)) { bson_destroy (&reply); break; } conv_id = _mongoc_cluster_get_conversation_id (&reply); if (!bson_iter_init_find (&iter, &reply, "payload") || !BSON_ITER_HOLDS_UTF8 (&iter)) { bson_destroy (&reply); bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Received invalid SASL reply from MongoDB server."); goto failure; } tmpstr = bson_iter_utf8 (&iter, &buflen); bson_free (buf); buf = bson_malloc (sizeof (SEC_CHAR) * (buflen + 1)); memcpy (buf, tmpstr, buflen); buf[buflen] = (SEC_CHAR) 0; bson_destroy (&reply); } ret = true; failure: mc_tpld_drop_ref (&td); bson_free (buf); bson_free (state); return ret; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cluster.c0000644000175100001660000036310414760300420022622 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "cluster" #define CHECK_CLOSED_DURATION_MSEC 1000 #define IS_NOT_COMMAND(_name) (!!strcasecmp (cmd->command_name, _name)) static mongoc_server_stream_t * _cluster_fetch_stream_single (mongoc_cluster_t *cluster, const mongoc_topology_description_t *td, uint32_t server_id, bool reconnect_ok, bson_error_t *error); static mongoc_server_stream_t * _cluster_fetch_stream_pooled (mongoc_cluster_t *cluster, const mongoc_topology_description_t *td, uint32_t server_id, bool reconnect_ok, bson_error_t *error); static bool mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, bson_t *reply, bson_error_t *error); static void _bson_error_message_printf (bson_error_t *error, const char *format, ...) BSON_GNUC_PRINTF (2, 3); static void _handle_not_primary_error (mongoc_cluster_t *cluster, const mongoc_server_stream_t *server_stream, const bson_t *reply) { uint32_t server_id; server_id = server_stream->sd->id; if (_mongoc_topology_handle_app_error (cluster->client->topology, server_id, true /* handshake complete */, MONGOC_SDAM_APP_ERROR_COMMAND, reply, NULL, server_stream->sd->max_wire_version, server_stream->sd->generation, &server_stream->sd->service_id)) { mongoc_cluster_disconnect_node (cluster, server_id); } } /* Called when a network error occurs on an application socket. */ static void _handle_network_error (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, const bson_error_t *why) { mongoc_topology_t *topology; uint32_t server_id; _mongoc_sdam_app_error_type_t type; BSON_ASSERT (server_stream); ENTRY; topology = cluster->client->topology; server_id = server_stream->sd->id; type = MONGOC_SDAM_APP_ERROR_NETWORK; if (mongoc_stream_timed_out (server_stream->stream)) { type = MONGOC_SDAM_APP_ERROR_TIMEOUT; } _mongoc_topology_handle_app_error (topology, server_id, true, // handshake_complete type, NULL, why, server_stream->sd->max_wire_version, server_stream->sd->generation, &server_stream->sd->service_id); /* Always disconnect the current connection on network error. */ mongoc_cluster_disconnect_node (cluster, server_id); EXIT; } static int32_t _int32_from_le (const void *data) { BSON_ASSERT_PARAM (data); return bson_iter_int32_unsafe (&(bson_iter_t){.raw = data}); } static int32_t _compression_level_from_uri (int32_t compressor_id, const mongoc_uri_t *uri) { if (compressor_id == MONGOC_COMPRESSOR_ZLIB_ID) { return mongoc_uri_get_option_as_int32 (uri, MONGOC_URI_ZLIBCOMPRESSIONLEVEL, -1); } return -1; } size_t _mongoc_cluster_buffer_iovec (mongoc_iovec_t *iov, size_t iovcnt, int skip, char *buffer) { size_t buffer_offset = 0; int total_iov_len = 0; size_t difference = 0; for (size_t n = 0u; n < iovcnt; n++) { BSON_ASSERT (mcommon_in_range_unsigned (int, iov[n].iov_len)); const int iov_len = (int) iov[n].iov_len; total_iov_len += iov_len; if (total_iov_len <= skip) { continue; } /* If this iovec starts before the skip, and takes the total count * beyond the skip, we need to figure out the portion of the iovec * we should skip passed */ const int remaining = total_iov_len - iov_len; if (remaining < skip) { difference = (size_t) (skip - remaining); } else { difference = 0u; } memcpy (buffer + buffer_offset, ((char *) iov[n].iov_base) + difference, iov[n].iov_len - difference); buffer_offset += iov[n].iov_len - difference; } return buffer_offset; } /* Allows caller to safely overwrite error->message with a formatted string, * even if the formatted string includes original error->message. */ static void _bson_error_message_printf (bson_error_t *error, const char *format, ...) { va_list args; char error_message[sizeof error->message]; if (error) { va_start (args, format); bson_vsnprintf (error_message, sizeof error->message, format, args); va_end (args); bson_strncpy (error->message, error_message, sizeof error->message); } } #define RUN_CMD_ERR_DECORATE \ do { \ _bson_error_message_printf (error, \ "Failed to send \"%s\" command with database \"%s\": %s", \ cmd->command_name, \ cmd->db_name, \ error->message); \ } while (0) #define RUN_CMD_ERR(_domain, _code, ...) \ do { \ bson_set_error (error, _domain, _code, __VA_ARGS__); \ RUN_CMD_ERR_DECORATE; \ } while (0) // msgHeader consists of four int32 fields. static const int32_t message_header_length = 4u * sizeof (int32_t); static bool _mongoc_cluster_run_command_opquery_send ( mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, int32_t compressor_id, mcd_rpc_message *rpc, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (cmd); BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (error); bool ret = false; mongoc_stream_t *const stream = cmd->server_stream->stream; char *const ns = bson_strdup_printf ("%s.$cmd", cmd->db_name); const int32_t request_id = ++cluster->request_id; // Find, getMore And killCursors Commands Spec: "When sending a find command // rather than a legacy OP_QUERY find, only the secondaryOk flag is honored." // For other cursor-typed commands like aggregate, only secondaryOk can be // set. Clear bits except secondaryOk; leave secondaryOk set only if it is // already. const int32_t flags = (int32_t) cmd->query_flags & MONGOC_OP_QUERY_FLAG_SECONDARY_OK; { int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (rpc, 0); message_length += mcd_rpc_header_set_request_id (rpc, request_id); message_length += mcd_rpc_header_set_response_to (rpc, 0); message_length += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_QUERY); message_length += mcd_rpc_op_query_set_flags (rpc, flags); message_length += mcd_rpc_op_query_set_full_collection_name (rpc, ns); message_length += mcd_rpc_op_query_set_number_to_skip (rpc, 0); message_length += mcd_rpc_op_query_set_number_to_return (rpc, -1); message_length += mcd_rpc_op_query_set_query (rpc, bson_get_data (cmd->command)); mcd_rpc_message_set_length (rpc, message_length); } size_t num_iovecs = 0u; mongoc_iovec_t *const iovecs = mcd_rpc_message_to_iovecs (rpc, &num_iovecs); BSON_ASSERT (iovecs); const bool is_compressible = compressor_id != -1 && IS_NOT_COMMAND (HANDSHAKE_CMD_LEGACY_HELLO) && IS_NOT_COMMAND ("hello") && IS_NOT_COMMAND ("saslstart") && IS_NOT_COMMAND ("saslcontinue") && IS_NOT_COMMAND ("getnonce") && IS_NOT_COMMAND ("authenticate") && IS_NOT_COMMAND ("createuser") && IS_NOT_COMMAND ("updateuser"); void *compressed_data = NULL; size_t compressed_data_len = 0u; if (is_compressible && !mcd_rpc_message_compress (rpc, compressor_id, _compression_level_from_uri (compressor_id, cluster->uri), &compressed_data, &compressed_data_len, error)) { goto done; } if (cluster->client->in_exhaust) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_IN_EXHAUST, "a cursor derived from this client is in exhaust"); goto done; } mcd_rpc_message_egress (rpc); if (!_mongoc_stream_writev_full (stream, iovecs, num_iovecs, cluster->sockettimeoutms, error)) { RUN_CMD_ERR_DECORATE; _handle_network_error (cluster, cmd->server_stream, error); goto done; } ret = true; done: bson_free (compressed_data); bson_free (iovecs); bson_free (ns); return ret; } static bool _mongoc_cluster_run_command_opquery_recv ( mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, mcd_rpc_message *rpc, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (cmd); BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (reply); BSON_ASSERT_PARAM (error); bool ret = false; mongoc_stream_t *const stream = cmd->server_stream->stream; mongoc_buffer_t buffer; _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); void *decompressed_data = NULL; size_t decompressed_data_len = 0u; if (!_mongoc_buffer_append_from_stream (&buffer, stream, sizeof (int32_t), cluster->sockettimeoutms, error)) { RUN_CMD_ERR (MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "socket error or timeout"); _handle_network_error (cluster, cmd->server_stream, error); goto done; } const int32_t message_length = _int32_from_le (buffer.data); if (message_length < message_header_length || message_length > MONGOC_DEFAULT_MAX_MSG_SIZE) { RUN_CMD_ERR (MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "invalid message length"); _handle_network_error (cluster, cmd->server_stream, error); goto done; } const size_t remaining_bytes = (size_t) message_length - sizeof (int32_t); if (!_mongoc_buffer_append_from_stream (&buffer, stream, remaining_bytes, cluster->sockettimeoutms, error)) { RUN_CMD_ERR (MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "socket error or timeout"); _handle_network_error (cluster, cmd->server_stream, error); goto done; } if (!mcd_rpc_message_from_data_in_place (rpc, buffer.data, buffer.len, NULL)) { RUN_CMD_ERR (MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "malformed reply from server"); goto done; } mcd_rpc_message_ingress (rpc); if (!mcd_rpc_message_decompress_if_necessary (rpc, &decompressed_data, &decompressed_data_len)) { RUN_CMD_ERR (MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "could not decompress server reply"); goto done; } { bson_t body; if (!mcd_rpc_message_get_body (rpc, &body)) { RUN_CMD_ERR (MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "malformed reply from server"); goto done; } bson_copy_to (&body, reply); bson_destroy (&body); } if (!_mongoc_cmd_check_ok (reply, cluster->client->error_api_version, error)) { goto done; } ret = true; done: bson_free (decompressed_data); _mongoc_buffer_destroy (&buffer); return ret; } static bool mongoc_cluster_run_command_opquery ( mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, int32_t compressor_id, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (cmd); BSON_ASSERT_PARAM (cmd->server_stream); BSON_ASSERT_PARAM (reply); BSON_ASSERT_PARAM (error); ENTRY; bool ret = false; bson_init (reply); error->code = 0; mcd_rpc_message *const rpc = mcd_rpc_message_new (); if (!_mongoc_cluster_run_command_opquery_send (cluster, cmd, compressor_id, rpc, error)) { GOTO (done); } mcd_rpc_message_reset (rpc); if (!_mongoc_cluster_run_command_opquery_recv (cluster, cmd, rpc, reply, error)) { GOTO (done); } ret = true; done: if (!ret && error->code == 0) { /* generic error */ RUN_CMD_ERR (MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server"); } mcd_rpc_message_destroy (rpc); RETURN (ret); } static bool _in_sharded_txn (const mongoc_client_session_t *session) { return session && _mongoc_client_session_in_txn_or_ending (session) && _mongoc_topology_get_type (session->client->topology) == MONGOC_TOPOLOGY_SHARDED; } static bool _in_sharded_or_loadbalanced_txn (const mongoc_client_session_t *session) { if (!session) { return false; } if (!_mongoc_client_session_in_txn_or_ending (session)) { return false; } mongoc_topology_description_type_t type = _mongoc_topology_get_type (session->client->topology); return (type == MONGOC_TOPOLOGY_SHARDED) || (type == MONGOC_TOPOLOGY_LOAD_BALANCED); } static void _handle_txn_error_labels (bool cmd_ret, const bson_error_t *cmd_err, const mongoc_cmd_t *cmd, bson_t *reply) { if (!cmd->is_txn_finish) { return; } _mongoc_write_error_handle_labels (cmd_ret, cmd_err, reply, cmd->server_stream->sd); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_run_command_monitored -- * * Internal function to run a command on a given stream. * @error and @reply are optional out-pointers. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * If the client's APM callbacks are set, they are executed. * @reply is set and should ALWAYS be released with bson_destroy(). * *-------------------------------------------------------------------------- */ bool mongoc_cluster_run_command_monitored (mongoc_cluster_t *cluster, mongoc_cmd_t *cmd, bson_t *reply, bson_error_t *error) { bool retval; const int32_t request_id = ++cluster->request_id; uint32_t server_id; mongoc_apm_command_started_t started_event; mongoc_apm_command_succeeded_t succeeded_event; mongoc_apm_command_failed_t failed_event; int64_t started = bson_get_monotonic_time (); const mongoc_server_stream_t *server_stream; bson_t reply_local; bson_error_t error_local; bson_iter_t iter; bson_t encrypted = BSON_INITIALIZER; bson_t decrypted = BSON_INITIALIZER; mongoc_cmd_t encrypted_cmd; bool is_redacted_by_apm = false; server_stream = cmd->server_stream; server_id = server_stream->sd->id; const mongoc_log_and_monitor_instance_t *log_and_monitor = &cluster->client->topology->log_and_monitor; if (!reply) { reply = &reply_local; } if (!error) { error = &error_local; } if (_mongoc_cse_is_enabled (cluster->client)) { bson_destroy (&encrypted); retval = _mongoc_cse_auto_encrypt (cluster->client, cmd, &encrypted_cmd, &encrypted, error); cmd = &encrypted_cmd; if (!retval) { bson_init (reply); goto fail_no_events; } } mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND, "Command started", int32 ("requestId", request_id), server_description (server_stream->sd, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID, SERVICE_ID), cmd (cmd, DATABASE_NAME, COMMAND_NAME, OPERATION_ID, COMMAND)); if (log_and_monitor->apm_callbacks.started) { mongoc_apm_command_started_init_with_cmd ( &started_event, cmd, request_id, &is_redacted_by_apm, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.started (&started_event); mongoc_apm_command_started_cleanup (&started_event); } retval = mongoc_cluster_run_opmsg (cluster, cmd, reply, error); if (retval) { bson_t fake_reply = BSON_INITIALIZER; int64_t duration = bson_get_monotonic_time () - started; /* * Unacknowledged writes must provide a CommandSucceededEvent with an * {ok: 1} reply. * https://github.com/mongodb/specifications/blob/master/source/command-logging-and-monitoring/command-logging-and-monitoring.md#unacknowledgedacknowledged-writes */ if (!cmd->is_acknowledged) { bson_append_int32 (&fake_reply, "ok", 2, 1); } mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND, "Command succeeded", int32 ("requestId", request_id), monotonic_time_duration (duration), server_description (server_stream->sd, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID, SERVICE_ID), cmd (cmd, DATABASE_NAME, COMMAND_NAME, OPERATION_ID), cmd_reply (cmd, cmd->is_acknowledged ? reply : &fake_reply)); if (log_and_monitor->apm_callbacks.succeeded) { mongoc_apm_command_succeeded_init (&succeeded_event, duration, cmd->is_acknowledged ? reply : &fake_reply, cmd->command_name, cmd->db_name, request_id, cmd->operation_id, &server_stream->sd->host, server_id, &server_stream->sd->service_id, server_stream->sd->server_connection_id, is_redacted_by_apm, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.succeeded (&succeeded_event); mongoc_apm_command_succeeded_cleanup (&succeeded_event); } bson_destroy (&fake_reply); } else { int64_t duration = bson_get_monotonic_time () - started; mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND, "Command failed", int32 ("requestId", request_id), monotonic_time_duration (duration), server_description (server_stream->sd, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID, SERVICE_ID), cmd (cmd, DATABASE_NAME, COMMAND_NAME, OPERATION_ID), cmd_failure (cmd, reply, error)); if (log_and_monitor->apm_callbacks.failed) { mongoc_apm_command_failed_init (&failed_event, duration, cmd->command_name, cmd->db_name, error, reply, request_id, cmd->operation_id, &server_stream->sd->host, server_id, &server_stream->sd->service_id, server_stream->sd->server_connection_id, is_redacted_by_apm, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.failed (&failed_event); mongoc_apm_command_failed_cleanup (&failed_event); } } if (retval && _mongoc_cse_is_enabled (cluster->client)) { bson_destroy (&decrypted); retval = _mongoc_cse_auto_decrypt (cluster->client, cmd->db_name, reply, &decrypted, error); bson_destroy (reply); bson_steal (reply, &decrypted); bson_init (&decrypted); if (!retval) { goto fail_no_events; } } _handle_not_primary_error (cluster, server_stream, reply); _handle_txn_error_labels (retval, error, cmd, reply); if (retval && _in_sharded_or_loadbalanced_txn (cmd->session) && bson_iter_init_find (&iter, reply, "recoveryToken")) { bson_destroy (cmd->session->recovery_token); if (BSON_ITER_HOLDS_DOCUMENT (&iter)) { cmd->session->recovery_token = bson_new_from_data (bson_iter_value (&iter)->value.v_doc.data, bson_iter_value (&iter)->value.v_doc.data_len); } else { MONGOC_ERROR ("Malformed recovery token from server"); cmd->session->recovery_token = NULL; } } fail_no_events: if (reply == &reply_local) { bson_destroy (&reply_local); } bson_destroy (&encrypted); bson_destroy (&decrypted); _mongoc_topology_update_last_used (cluster->client->topology, server_id); return retval; } static bool _should_use_op_msg (const mongoc_cluster_t *cluster) { return mongoc_cluster_uses_server_api (cluster) || mongoc_cluster_uses_loadbalanced (cluster); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_run_command_private -- * * Internal function to run a command on a given stream. * @error and @reply are optional out-pointers. * The client's APM callbacks are not executed. * Automatic encryption/decryption is not performed. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @reply is set and should ALWAYS be released with bson_destroy(). * *-------------------------------------------------------------------------- */ bool mongoc_cluster_run_command_private (mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, bson_t *reply, bson_error_t *error) { bool retval; const mongoc_server_stream_t *server_stream; bson_t reply_local; bson_error_t error_local; if (!error) { error = &error_local; } /* If NULL was passed, we use our local variable as a temporary sink: */ if (!reply) { reply = &reply_local; } server_stream = cmd->server_stream; if (_should_use_op_msg (cluster) || server_stream->sd->max_wire_version >= WIRE_VERSION_MIN) { retval = mongoc_cluster_run_opmsg (cluster, cmd, reply, error); } else { retval = mongoc_cluster_run_command_opquery (cluster, cmd, -1, reply, error); } _handle_not_primary_error (cluster, server_stream, reply); if (reply == &reply_local) { bson_destroy (&reply_local); } _mongoc_topology_update_last_used (cluster->client->topology, server_stream->sd->id); return retval; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_run_command_parts -- * * Internal function to assemble command parts and run a command * on a given stream. @error and @reply are optional out-pointers. * The client's APM callbacks are not executed. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @reply is set and should ALWAYS be released with bson_destroy(). * mongoc_cmd_parts_cleanup will be always be called on parts. The * caller should *not* call cleanup on the parts. * *-------------------------------------------------------------------------- */ bool mongoc_cluster_run_command_parts (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream, mongoc_cmd_parts_t *parts, bson_t *reply, bson_error_t *error) { bool ret; if (!mongoc_cmd_parts_assemble (parts, server_stream, error)) { _mongoc_bson_init_if_set (reply); mongoc_cmd_parts_cleanup (parts); return false; } ret = mongoc_cluster_run_command_private (cluster, &parts->assembled, reply, error); mongoc_cmd_parts_cleanup (parts); return ret; } /* *-------------------------------------------------------------------------- * * _stream_run_hello -- * * Run a hello command on the given stream. If * @negotiate_sasl_supported_mechs is true, then saslSupportedMechs is * added to the hello command. * * Returns: * A mongoc_server_description_t you must destroy or NULL. If the call * failed its error is set and its type is MONGOC_SERVER_UNKNOWN. * *-------------------------------------------------------------------------- */ static mongoc_server_description_t * _stream_run_hello (mongoc_cluster_t *cluster, mongoc_stream_t *stream, const char *address, uint32_t server_id, bool negotiate_sasl_supported_mechs, mongoc_scram_t *scram, bson_t *speculative_auth_response /* OUT */, bson_error_t *error) { mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (cluster)->client->topology); ENTRY; BSON_ASSERT (stream); bson_t handshake_command; _mongoc_topology_dup_handshake_cmd (cluster->client->topology, &handshake_command); if (cluster->requires_auth && speculative_auth_response) { mongoc_ssl_opt_t *ssl_opts = NULL; #ifdef MONGOC_ENABLE_SSL ssl_opts = &cluster->client->ssl_opts; #endif _mongoc_topology_scanner_add_speculative_authentication (&handshake_command, cluster->uri, ssl_opts, scram); } if (negotiate_sasl_supported_mechs) { _mongoc_handshake_append_sasl_supported_mechs (cluster->uri, &handshake_command); } const int64_t start = bson_get_monotonic_time (); /* TODO CDRIVER-3654: do not use a mongoc_server_stream here. * Instead, use a plain stream. If a network error occurs, check the cluster * node's generation (which is the generation of the created connection) to * determine if the error should be handled. * The current behavior may double invalidate. * If a network error occurs in mongoc_cluster_run_command_private below, * that invalidates (thinking the error is a post-handshake network error). * Then _mongoc_cluster_stream_for_server also handles the error, and * invalidates again. */ mongoc_server_description_t empty_sd; mongoc_server_description_init (&empty_sd, address, server_id); mongoc_server_stream_t *const server_stream = _mongoc_cluster_create_server_stream (td.ptr, &empty_sd, stream); mongoc_server_description_cleanup (&empty_sd); mongoc_query_flags_t query_flags = MONGOC_QUERY_NONE; /* Use OP_QUERY for the handshake, unless the user has specified an * API version; the correct hello_cmd has already been selected: */ if (!_should_use_op_msg (cluster)) { /* Complete OPCODE_QUERY setup: */ query_flags |= MONGOC_QUERY_SECONDARY_OK; } else { /* We're using OP_MSG, and require some additional doctoring: */ bson_append_utf8 (&handshake_command, "$db", 3, "admin", 5); } /* Set up the shared parts of the mongo_cmd_t, which will later be converted to either an op_msg or op_query: */ const mongoc_cmd_t hello_cmd = { .db_name = "admin", .command = &handshake_command, .command_name = _mongoc_get_command_name (&handshake_command), .server_stream = server_stream, .is_acknowledged = true, .query_flags = query_flags, }; bson_t reply; // The final resulting server description mongoc_server_description_t *ret_handshake_sd = NULL; if (!mongoc_cluster_run_command_private (cluster, &hello_cmd, &reply, error)) { // Command execution failed. if (negotiate_sasl_supported_mechs) { // Negotiating a new SASL mechanism bsonParse (reply, find (allOf (key ("ok"), isFalse), // do ({ /* hello response returned ok: 0. According to * auth spec: "If the hello of the MongoDB * Handshake fails with an error, drivers MUST * treat this an authentication error." */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; }))); } } else { // "hello" succeeded // Round-trip time for the hello command const int64_t rtt_msec = (bson_get_monotonic_time () - start) / 1000; ret_handshake_sd = BSON_ALIGNED_ALLOC0 (mongoc_server_description_t); mongoc_server_description_init (ret_handshake_sd, address, server_id); /* send the error from run_command IN to handle_hello */ mongoc_server_description_handle_hello (ret_handshake_sd, &reply, rtt_msec, error); if (cluster->requires_auth && speculative_auth_response) { _mongoc_topology_scanner_parse_speculative_authentication (&reply, speculative_auth_response); } /* Note: This call will render our copy of the topology description to be * stale */ const bool update_okay = _mongoc_topology_update_from_handshake (cluster->client->topology, ret_handshake_sd); if (!update_okay) { mongoc_server_description_reset (ret_handshake_sd); bson_set_error (&ret_handshake_sd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "\"%s\" removed from topology", address); } } mongoc_server_stream_cleanup (server_stream); bson_destroy (&handshake_command); bson_destroy (&reply); mc_tpld_drop_ref (&td); RETURN (ret_handshake_sd); } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_run_hello -- * * Run an initial hello command for the given node and handle result. * * Returns: * mongoc_server_description_t on success, NULL otherwise. * the mongoc_server_description_t MUST BE DESTROYED BY THE CALLER. * * Side effects: * Makes a blocking I/O call, updates cluster->topology->description * with hello result. * *-------------------------------------------------------------------------- */ static mongoc_server_description_t * _cluster_run_hello (mongoc_cluster_t *cluster, mongoc_cluster_node_t *node, uint32_t server_id, mongoc_scram_t *scram /* OUT */, bson_t *speculative_auth_response /* OUT */, bson_error_t *error /* OUT */) { mongoc_server_description_t *sd; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (node); BSON_ASSERT (node->stream); sd = _stream_run_hello (cluster, node->stream, node->connection_address, server_id, _mongoc_uri_requires_auth_negotiation (cluster->uri), scram, speculative_auth_response, error); if (!sd) { return NULL; } if (sd->type == MONGOC_SERVER_UNKNOWN) { memcpy (error, &sd->error, sizeof (bson_error_t)); mongoc_server_description_destroy (sd); return NULL; } return sd; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node_plain -- * * Perform SASL PLAIN authentication for @node. We do this manually * instead of using the SASL module because it is rather simplistic. * * Returns: * true if successful; otherwise false and error is set. * * Side effects: * error may be set. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_node_plain (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { mongoc_cmd_parts_t parts; char buf[4096]; int buflen = 0; const char *username; const char *password; bson_t b = BSON_INITIALIZER; bson_t reply; size_t len; char *str; bool ret; mongoc_server_stream_t *server_stream; mc_shared_tpld td; BSON_ASSERT (cluster); BSON_ASSERT (stream); username = mongoc_uri_get_username (cluster->uri); if (!username) { username = ""; } password = mongoc_uri_get_password (cluster->uri); if (!password) { password = ""; } str = bson_strdup_printf ("%c%s%c%s", '\0', username, '\0', password); len = strlen (username) + strlen (password) + 2; buflen = mcommon_b64_ntop ((const uint8_t *) str, len, buf, sizeof buf); bson_free (str); if (buflen == -1) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "failed base64 encoding message"); return false; } BSON_APPEND_INT32 (&b, "saslStart", 1); BSON_APPEND_UTF8 (&b, "mechanism", "PLAIN"); bson_append_utf8 (&b, "payload", 7, (const char *) buf, buflen); BSON_APPEND_INT32 (&b, "autoAuthorize", 1); mongoc_cmd_parts_init (&parts, cluster->client, "$external", MONGOC_QUERY_SECONDARY_OK, &b); parts.prohibit_lsid = true; td = mc_tpld_take_ref (cluster->client->topology); server_stream = _mongoc_cluster_create_server_stream (td.ptr, sd, stream); mc_tpld_drop_ref (&td); ret = mongoc_cluster_run_command_parts (cluster, server_stream, &parts, &reply, error); mongoc_server_stream_cleanup (server_stream); if (!ret) { /* error->message is already set */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; } bson_destroy (&b); bson_destroy (&reply); return ret; } bool _mongoc_cluster_get_auth_cmd_x509 (const mongoc_uri_t *uri, const mongoc_ssl_opt_t *ssl_opts, bson_t *cmd /* OUT */, bson_error_t *error /* OUT */) { #ifndef MONGOC_ENABLE_SSL bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "The MONGODB-X509 authentication mechanism requires " "libmongoc built with ENABLE_SSL"); return false; #else const char *username_from_uri = NULL; char *username_from_subject = NULL; BSON_ASSERT (uri); username_from_uri = mongoc_uri_get_username (uri); if (username_from_uri) { TRACE ("%s", "X509: got username from URI"); } else { if (!ssl_opts || !ssl_opts->pem_file) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "cannot determine username for " "X-509 authentication."); return false; } username_from_subject = mongoc_ssl_extract_subject (ssl_opts->pem_file, ssl_opts->pem_pwd); if (!username_from_subject) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "No username provided for X509 authentication."); return false; } TRACE ("%s", "X509: got username from certificate"); } bson_init (cmd); BSON_APPEND_INT32 (cmd, "authenticate", 1); BSON_APPEND_UTF8 (cmd, "mechanism", "MONGODB-X509"); BSON_APPEND_UTF8 (cmd, "user", username_from_uri ? username_from_uri : username_from_subject); bson_free (username_from_subject); return true; #endif } static bool _mongoc_cluster_auth_node_x509 (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { #ifndef MONGOC_ENABLE_SSL bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "The MONGODB-X509 authentication mechanism requires " "libmongoc built with ENABLE_SSL"); return false; #else mongoc_cmd_parts_t parts; bson_t cmd; bson_t reply; bool ret; mongoc_server_stream_t *server_stream; mc_shared_tpld td; BSON_ASSERT (cluster); BSON_ASSERT (stream); if (!_mongoc_cluster_get_auth_cmd_x509 (cluster->uri, &cluster->client->ssl_opts, &cmd, error)) { return false; } mongoc_cmd_parts_init (&parts, cluster->client, "$external", MONGOC_QUERY_SECONDARY_OK, &cmd); parts.prohibit_lsid = true; td = mc_tpld_take_ref (cluster->client->topology); server_stream = _mongoc_cluster_create_server_stream (td.ptr, sd, stream); mc_tpld_drop_ref (&td); ret = mongoc_cluster_run_command_parts (cluster, server_stream, &parts, &reply, error); mongoc_server_stream_cleanup (server_stream); if (!ret) { /* error->message is already set */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; } bson_destroy (&cmd); bson_destroy (&reply); return ret; #endif } bool mongoc_cluster_uses_server_api (const mongoc_cluster_t *cluster) { BSON_ASSERT_PARAM (cluster); return mongoc_client_uses_server_api (cluster->client); } bool mongoc_cluster_uses_loadbalanced (const mongoc_cluster_t *cluster) { BSON_ASSERT_PARAM (cluster); return mongoc_client_uses_loadbalanced (cluster->client); } #ifdef MONGOC_ENABLE_CRYPTO void _mongoc_cluster_init_scram (const mongoc_cluster_t *cluster, mongoc_scram_t *scram, mongoc_crypto_hash_algorithm_t algo) { _mongoc_uri_init_scram (cluster->uri, scram, algo); } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_get_auth_cmd_scram -- * * Generates the saslStart command for scram authentication. Used * during explicit authentication as well as speculative * authentication during hello. * * * Returns: * true if the command could be generated, false otherwise * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ bool _mongoc_cluster_get_auth_cmd_scram (mongoc_crypto_hash_algorithm_t algo, mongoc_scram_t *scram, bson_t *cmd /* OUT */, bson_error_t *error /* OUT */) { uint8_t buf[4096] = {0}; uint32_t buflen = 0; bson_t options; if (!_mongoc_scram_step (scram, buf, buflen, buf, sizeof buf, &buflen, error)) { return false; } BSON_ASSERT (scram->step == 1); bson_init (cmd); BSON_APPEND_INT32 (cmd, "saslStart", 1); if (algo == MONGOC_CRYPTO_ALGORITHM_SHA_1) { BSON_APPEND_UTF8 (cmd, "mechanism", "SCRAM-SHA-1"); } else if (algo == MONGOC_CRYPTO_ALGORITHM_SHA_256) { BSON_APPEND_UTF8 (cmd, "mechanism", "SCRAM-SHA-256"); } else { BSON_ASSERT (false); } bson_append_binary (cmd, "payload", 7, BSON_SUBTYPE_BINARY, buf, buflen); BSON_APPEND_INT32 (cmd, "autoAuthorize", 1); BSON_APPEND_DOCUMENT_BEGIN (cmd, "options", &options); BSON_APPEND_BOOL (&options, "skipEmptyExchange", true); bson_append_document_end (cmd, &options); bson_destroy (&options); return true; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_run_scram_command -- * * Runs a scram authentication command, handling auth_source and * errors during the command. * * * Returns: * true if the command was successful, false otherwise * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_run_scram_command (mongoc_cluster_t *cluster, mongoc_stream_t *stream, const mongoc_server_description_t *handshake_sd, const bson_t *cmd, bson_t *reply, bson_error_t *error) { mongoc_cmd_parts_t parts; mongoc_server_stream_t *server_stream; const char *auth_source; mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (cluster)->client->topology); if (!(auth_source = mongoc_uri_get_auth_source (cluster->uri)) || (*auth_source == '\0')) { auth_source = "admin"; } mongoc_cmd_parts_init (&parts, cluster->client, auth_source, MONGOC_QUERY_SECONDARY_OK, cmd); parts.prohibit_lsid = true; server_stream = _mongoc_cluster_create_server_stream (td.ptr, handshake_sd, stream); mc_tpld_drop_ref (&td); if (!mongoc_cluster_run_command_parts (cluster, server_stream, &parts, reply, error)) { mongoc_server_stream_cleanup (server_stream); bson_destroy (reply); /* error->message is already set */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; return false; } mongoc_server_stream_cleanup (server_stream); return true; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_scram_start -- * * Starts scram authentication by generating and sending the saslStart * command. The conversation can then be resumed using * _mongoc_cluster_auth_scram_continue. * * * Returns: * true if the saslStart command was successful, false otherwise * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_scram_start (mongoc_cluster_t *cluster, mongoc_stream_t *stream, const mongoc_server_description_t *handshake_sd, mongoc_crypto_hash_algorithm_t algo, mongoc_scram_t *scram, bson_t *reply, bson_error_t *error) { bson_t cmd; BSON_ASSERT (scram->step == 0); if (!_mongoc_cluster_get_auth_cmd_scram (algo, scram, &cmd, error)) { /* error->message is already set */ error->domain = MONGOC_ERROR_CLIENT; error->code = MONGOC_ERROR_CLIENT_AUTHENTICATE; return false; } if (!_mongoc_cluster_run_scram_command (cluster, stream, handshake_sd, &cmd, reply, error)) { bson_destroy (&cmd); return false; } bson_destroy (&cmd); return true; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_scram_handle_reply -- * * Handles replies from _mongoc_cluster_run_scram_command. The @done * argument will be set to true if the scram conversation was * completed successfully. * * * Returns: * true if the reply was handled successfully, false if there was an * error. Note that the return value itself does not indicate whether * authentication was completed successfully. * * Side effects: * @error is set on failure. @done, @conv_id, @buf, and @buflen are * set for use in the next scram step. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_scram_handle_reply (mongoc_scram_t *scram, const bson_t *reply, bool *done /* OUT */, int *conv_id /* OUT */, uint8_t *buf /* OUT */, uint32_t bufmax, uint32_t *buflen /* OUT */, bson_error_t *error) { bson_iter_t iter; bson_subtype_t btype; const char *tmpstr; BSON_ASSERT (scram); bool is_done = false; bsonParse (*reply, find (key ("done"), storeBool (is_done))); if (is_done) { if (scram->step < 2) { /* Prior to step 2, we haven't even received server proof. */ bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Incorrect step for 'done'"); return false; } *done = true; if (scram->step >= 3) { return true; } } if (!bson_iter_init_find (&iter, reply, "conversationId") || !BSON_ITER_HOLDS_INT32 (&iter) || !(*conv_id = bson_iter_int32 (&iter)) || !bson_iter_init_find (&iter, reply, "payload") || !BSON_ITER_HOLDS_BINARY (&iter)) { const char *errmsg = "Received invalid SCRAM reply from MongoDB server."; MONGOC_DEBUG ("SCRAM: authentication failed"); if (bson_iter_init_find (&iter, reply, "errmsg") && BSON_ITER_HOLDS_UTF8 (&iter)) { errmsg = bson_iter_utf8 (&iter, NULL); } bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "%s", errmsg); return false; } bson_iter_binary (&iter, &btype, buflen, (const uint8_t **) &tmpstr); if (*buflen > bufmax) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "SCRAM reply from MongoDB is too large."); return false; } memcpy (buf, tmpstr, *buflen); return true; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_scram_continue -- * * Continues the scram conversation from the reply to a saslStart * command, either sent explicitly or received through speculative * authentication during hello. * * * Returns: * true if authenticated. false on failure and @error is set. * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_scram_continue (mongoc_cluster_t *cluster, mongoc_stream_t *stream, const mongoc_server_description_t *handshake_sd, mongoc_scram_t *scram, const bson_t *sasl_start_reply, bson_error_t *error) { bson_t cmd; uint8_t buf[4096] = {0}; uint32_t buflen = 0; int conv_id = 0; bool done = false; bson_t reply_local; if (!_mongoc_cluster_scram_handle_reply ( scram, sasl_start_reply, &done, &conv_id, buf, sizeof buf, &buflen, error)) { return false; } for (;;) { if (!_mongoc_scram_step (scram, buf, buflen, buf, sizeof buf, &buflen, error)) { return false; } if (done && (scram->step >= 3)) { break; } bson_init (&cmd); BSON_APPEND_INT32 (&cmd, "saslContinue", 1); BSON_APPEND_INT32 (&cmd, "conversationId", conv_id); bson_append_binary (&cmd, "payload", 7, BSON_SUBTYPE_BINARY, buf, buflen); TRACE ("SCRAM: authenticating (step %d)", scram->step); if (!_mongoc_cluster_run_scram_command (cluster, stream, handshake_sd, &cmd, &reply_local, error)) { bson_destroy (&cmd); return false; } bson_destroy (&cmd); if (!_mongoc_cluster_scram_handle_reply (scram, &reply_local, &done, &conv_id, buf, sizeof buf, &buflen, error)) { bson_destroy (&reply_local); return false; } bson_destroy (&reply_local); if (done && (scram->step >= 3)) { break; } } TRACE ("%s", "SCRAM: authenticated"); return true; } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node_scram -- * * Invokes scram authentication by sending a saslStart command and * handling all replies. * * * Returns: * true if authenticated. false on failure and @error is set. * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_node_scram (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *handshake_sd, mongoc_crypto_hash_algorithm_t algo, bson_error_t *error) { mongoc_scram_t scram; bool ret = false; bson_t reply; BSON_ASSERT (cluster); _mongoc_cluster_init_scram (cluster, &scram, algo); if (!_mongoc_cluster_auth_scram_start (cluster, stream, handshake_sd, algo, &scram, &reply, error)) { goto failure; } if (!_mongoc_cluster_auth_scram_continue (cluster, stream, handshake_sd, &scram, &reply, error)) { bson_destroy (&reply); goto failure; } TRACE ("%s", "SCRAM: authenticated"); ret = true; bson_destroy (&reply); failure: _mongoc_scram_destroy (&scram); return ret; } #endif static bool _mongoc_cluster_auth_node_scram_sha_1 (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { #ifndef MONGOC_ENABLE_CRYPTO bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "The SCRAM_SHA_1 authentication mechanism requires " "libmongoc built with ENABLE_SSL"); return false; #else return _mongoc_cluster_auth_node_scram (cluster, stream, sd, MONGOC_CRYPTO_ALGORITHM_SHA_1, error); #endif } static bool _mongoc_cluster_auth_node_scram_sha_256 (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, bson_error_t *error) { #ifndef MONGOC_ENABLE_CRYPTO bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "The SCRAM_SHA_256 authentication mechanism requires " "libmongoc built with ENABLE_SSL"); return false; #else return _mongoc_cluster_auth_node_scram (cluster, stream, sd, MONGOC_CRYPTO_ALGORITHM_SHA_256, error); #endif } /* *-------------------------------------------------------------------------- * * _mongoc_cluster_auth_node -- * * Authenticate a cluster node depending on the required mechanism. * * Returns: * true if authenticated. false on failure and @error is set. * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_cluster_auth_node (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *sd, const mongoc_handshake_sasl_supported_mechs_t *sasl_supported_mechs, bson_error_t *error) { bool ret = false; const char *mechanism; ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (stream); mechanism = mongoc_uri_get_auth_mechanism (cluster->uri); if (!mechanism) { if (sasl_supported_mechs->scram_sha_256) { /* Auth spec: "If SCRAM-SHA-256 is present in the list of mechanisms, * then it MUST be used as the default; otherwise, SCRAM-SHA-1 MUST be * used as the default, regardless of whether SCRAM-SHA-1 is in the * list. Drivers MUST NOT attempt to use any other mechanism (e.g. * PLAIN) as the default." [...] "If saslSupportedMechs is not present * in the hello results for mechanism negotiation, then SCRAM-SHA-1 * MUST be used when talking to servers >= 3.0." */ mechanism = "SCRAM-SHA-256"; } else { mechanism = "SCRAM-SHA-1"; } } if (0 == strcasecmp (mechanism, "MONGODB-X509")) { ret = _mongoc_cluster_auth_node_x509 (cluster, stream, sd, error); } else if (0 == strcasecmp (mechanism, "SCRAM-SHA-1")) { ret = _mongoc_cluster_auth_node_scram_sha_1 (cluster, stream, sd, error); } else if (0 == strcasecmp (mechanism, "SCRAM-SHA-256")) { ret = _mongoc_cluster_auth_node_scram_sha_256 (cluster, stream, sd, error); } else if (0 == strcasecmp (mechanism, "GSSAPI")) { ret = _mongoc_cluster_auth_node_sasl (cluster, stream, sd, error); } else if (0 == strcasecmp (mechanism, "PLAIN")) { ret = _mongoc_cluster_auth_node_plain (cluster, stream, sd, error); } else if (0 == strcasecmp (mechanism, "MONGODB-AWS")) { ret = _mongoc_cluster_auth_node_aws (cluster, stream, sd, error); } else { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Unknown authentication mechanism \"%s\".", mechanism); } if (!ret) { mongoc_counter_auth_failure_inc (); MONGOC_DEBUG ("Authentication failed: %s", error->message); } else { mongoc_counter_auth_success_inc (); TRACE ("%s", "Authentication succeeded"); } RETURN (ret); } /* * Close the connection associated with this server. * * Called when a network error occurs, or to close connection tied to an exhaust * cursor. * If the cluster is pooled, removes the node from cluster's set of nodes. * WARNING: pointers to a disconnected mongoc_cluster_node_t or its stream are * now invalid, be careful of dangling pointers. */ void mongoc_cluster_disconnect_node (mongoc_cluster_t *cluster, uint32_t server_id) { mongoc_topology_t *topology = cluster->client->topology; ENTRY; if (topology->single_threaded) { mongoc_topology_scanner_node_t *scanner_node; scanner_node = mongoc_topology_scanner_get_node (topology->scanner, server_id); /* might never actually have connected */ if (scanner_node && scanner_node->stream) { mongoc_topology_scanner_node_disconnect (scanner_node, true); } } else { mongoc_set_rm (cluster->nodes, server_id); } EXIT; } static void _mongoc_cluster_node_destroy (mongoc_cluster_node_t *node) { /* Failure, or Replica Set reconfigure without this node */ mongoc_stream_failed (node->stream); bson_free (node->connection_address); mongoc_server_description_destroy (node->handshake_sd); bson_free (node); } static void _mongoc_cluster_node_dtor (void *data_, void *ctx_) { mongoc_cluster_node_t *node = (mongoc_cluster_node_t *) data_; BSON_UNUSED (ctx_); _mongoc_cluster_node_destroy (node); } static mongoc_cluster_node_t * _mongoc_cluster_node_new (mongoc_stream_t *stream, const char *connection_address) { mongoc_cluster_node_t *node; if (!stream) { return NULL; } node = (mongoc_cluster_node_t *) bson_malloc0 (sizeof *node); node->stream = stream; node->connection_address = bson_strdup (connection_address); /* Note that the node->sd field is set to NULL by bson_malloc0(), rather than being explicitly initialized. */ return node; } static bool _mongoc_cluster_finish_speculative_auth (mongoc_cluster_t *cluster, mongoc_stream_t *stream, mongoc_server_description_t *handshake_sd, bson_t *speculative_auth_response, mongoc_scram_t *scram, bson_error_t *error) { const char *mechanism = _mongoc_topology_scanner_get_speculative_auth_mechanism (cluster->uri); bool ret = false; bool auth_handled = false; BSON_ASSERT (handshake_sd); BSON_ASSERT (speculative_auth_response); if (!mechanism) { return false; } if (bson_empty (speculative_auth_response)) { return false; } #ifdef MONGOC_ENABLE_SSL if (strcasecmp (mechanism, "MONGODB-X509") == 0) { /* For X509, a successful hello with speculativeAuthenticate field * indicates successful auth */ ret = true; auth_handled = true; } #endif #ifdef MONGOC_ENABLE_CRYPTO if (strcasecmp (mechanism, "SCRAM-SHA-1") == 0 || strcasecmp (mechanism, "SCRAM-SHA-256") == 0) { /* Don't attempt authentication if scram objects have advanced past * saslStart */ if (scram->step != 1) { return false; } auth_handled = true; ret = _mongoc_cluster_auth_scram_continue (cluster, stream, handshake_sd, scram, speculative_auth_response, error); } #endif if (auth_handled) { if (!ret) { mongoc_counter_auth_failure_inc (); MONGOC_DEBUG ("Speculative authentication failed: %s", error->message); } else { mongoc_counter_auth_success_inc (); TRACE ("%s", "Speculative authentication succeeded"); } } bson_reinit (speculative_auth_response); return ret; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_add_node -- * * Add a new node to this cluster for the given server description. * * NOTE: does NOT check if this server is already in the cluster. * * Returns: * A stream connected to the server, or NULL on failure. * * Side effects: * Adds a cluster node, or sets error on failure. * *-------------------------------------------------------------------------- */ static mongoc_cluster_node_t * _cluster_add_node (mongoc_cluster_t *cluster, const mongoc_topology_description_t *td, uint32_t server_id, bson_error_t *error /* OUT */) { mongoc_host_list_t *host = NULL; mongoc_cluster_node_t *cluster_node = NULL; mongoc_stream_t *stream; mongoc_server_description_t *handshake_sd; mongoc_handshake_sasl_supported_mechs_t sasl_supported_mechs; mongoc_scram_t scram = {0}; bson_t speculative_auth_response = BSON_INITIALIZER; ENTRY; BSON_ASSERT (!cluster->client->topology->single_threaded); host = _mongoc_topology_host_by_id (td, server_id, error); if (!host) { GOTO (error); } TRACE ("Adding new server to cluster: %s", host->host_and_port); stream = _mongoc_client_create_stream (cluster->client, host, error); if (!stream) { MONGOC_WARNING ("Failed connection to %s (%s)", host->host_and_port, error->message); GOTO (error); /* TODO CDRIVER-3654: if this is a non-timeout network error and the * generation is not stale, mark the server unknown and increment the * generation. */ } /* take critical fields from a fresh hello */ cluster_node = _mongoc_cluster_node_new (stream, host->host_and_port); handshake_sd = _cluster_run_hello (cluster, cluster_node, server_id, &scram, &speculative_auth_response, error); if (!handshake_sd) { GOTO (error); } _mongoc_handshake_parse_sasl_supported_mechs (&handshake_sd->last_hello_response, &sasl_supported_mechs); if (cluster->requires_auth) { /* Complete speculative authentication */ bool is_auth = _mongoc_cluster_finish_speculative_auth ( cluster, stream, handshake_sd, &speculative_auth_response, &scram, error); if (!is_auth && !_mongoc_cluster_auth_node (cluster, cluster_node->stream, handshake_sd, &sasl_supported_mechs, error)) { MONGOC_WARNING ("Failed authentication to %s (%s)", host->host_and_port, error->message); mongoc_server_description_destroy (handshake_sd); GOTO (error); } } /* Transfer ownership of the server description into the cluster node. */ cluster_node->handshake_sd = handshake_sd; /* Copy the latest connection pool generation. * TODO (CDRIVER-4078) do not store the generation counter on the server * description */ handshake_sd->generation = _mongoc_topology_get_connection_pool_generation (td, server_id, &handshake_sd->service_id); bson_destroy (&speculative_auth_response); mongoc_set_add (cluster->nodes, server_id, cluster_node); _mongoc_host_list_destroy_all (host); #ifdef MONGOC_ENABLE_CRYPTO _mongoc_scram_destroy (&scram); #endif RETURN (cluster_node); error: bson_destroy (&speculative_auth_response); _mongoc_host_list_destroy_all (host); /* null ok */ #ifdef MONGOC_ENABLE_CRYPTO _mongoc_scram_destroy (&scram); #endif if (cluster_node) { _mongoc_cluster_node_destroy (cluster_node); /* also destroys stream */ } RETURN (NULL); } static void node_not_found (const mongoc_topology_description_t *td, uint32_t server_id, bson_error_t *error /* OUT */) { mongoc_server_description_t const *sd; if (!error) { return; } sd = mongoc_topology_description_server_by_id_const (td, server_id, error); if (!sd) { return; } if (sd->error.code) { memcpy (error, &sd->error, sizeof *error); } else { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "Could not find node %s", sd->host.host_and_port); } } static void stream_not_found (const mongoc_topology_description_t *td, uint32_t server_id, const char *connection_address, bson_error_t *error /* OUT */) { mongoc_server_description_t const *sd; sd = mongoc_topology_description_server_by_id_const (td, server_id, error); if (error) { if (sd && sd->error.code) { memcpy (error, &sd->error, sizeof *error); } else { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "Could not find stream for node %s", connection_address); } } } static mongoc_server_stream_t * _try_get_server_stream (mongoc_cluster_t *cluster, const mongoc_topology_description_t *td, uint32_t server_id, bool reconnect_ok, bson_error_t *error) { if (cluster->client->topology->single_threaded) { /* in the single-threaded use case we share topology's streams */ return _cluster_fetch_stream_single (cluster, td, server_id, reconnect_ok, error); } else { return _cluster_fetch_stream_pooled (cluster, td, server_id, reconnect_ok, error); } } static mongoc_server_stream_t * _mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster, uint32_t server_id, bool reconnect_ok, const mongoc_client_session_t *cs, bson_t *reply, bson_error_t *error /* OUT */) { mongoc_topology_t *const topology = BSON_ASSERT_PTR_INLINE (cluster)->client->topology; mongoc_server_stream_t *ret_server_stream; bson_error_t err_local; /* if fetch_stream fails we need a place to receive error details and pass * them to mongoc_topology_description_invalidate_server. */ bson_error_t *err_ptr = error ? error : &err_local; mc_tpld_modification tdmod; mc_shared_tpld td; ENTRY; td = mc_tpld_take_ref (topology); ret_server_stream = _try_get_server_stream (cluster, td.ptr, server_id, reconnect_ok, err_ptr); if (!ret_server_stream) { /* TODO CDRIVER-3654. A null server stream could be due to: * 1. Network error during handshake. * 2. Failure to retrieve server description (if it was removed from * topology). * 3. Auth error during handshake. * Only (1) should mark the server unknown and clear the pool. * Network errors should be checked at a lower layer than this, when an * operation on a stream fails, and should take the connection generation * into account. */ _mongoc_bson_init_if_set (reply); // Add a transient transaction label if applicable. _mongoc_add_transient_txn_error (cs, reply); /* Update the topology */ tdmod = mc_tpld_modify_begin (topology); /* When establishing a new connection in load balanced mode, drivers MUST * NOT perform SDAM error handling for any errors that occur before the * MongoDB Handshake. */ if (tdmod.new_td->type == MONGOC_TOPOLOGY_LOAD_BALANCED) { mc_tpld_modify_drop (tdmod); ret_server_stream = NULL; goto done; } mongoc_topology_description_invalidate_server (tdmod.new_td, &topology->log_and_monitor, server_id, err_ptr); mongoc_cluster_disconnect_node (cluster, server_id); /* This is not load balanced mode, so there are no service IDs associated * with connections. Pass kZeroObjectId to clear the entire connection * pool to this server. */ _mongoc_topology_description_clear_connection_pool (tdmod.new_td, server_id, &kZeroObjectId); if (!topology->single_threaded) { _mongoc_topology_background_monitoring_cancel_check (topology, server_id); } mc_tpld_modify_commit (tdmod); ret_server_stream = NULL; goto done; } /* If this is a load balanced topology and the server stream does not have a * service id, disconnect and return an error. */ if (td.ptr->type == MONGOC_TOPOLOGY_LOAD_BALANCED) { if (!mongoc_server_description_has_service_id (ret_server_stream->sd)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_LOAD_BALANCER, "Driver attempted to initialize in load balancing " "mode, but the server does not support this mode."); mongoc_server_stream_cleanup (ret_server_stream); mongoc_cluster_disconnect_node (cluster, server_id); _mongoc_bson_init_if_set (reply); ret_server_stream = NULL; goto done; } } done: mc_tpld_drop_ref (&td); RETURN (ret_server_stream); } mongoc_server_stream_t * mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster, uint32_t server_id, bool reconnect_ok, mongoc_client_session_t *cs, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_OPTIONAL_PARAM (cs); BSON_OPTIONAL_PARAM (reply); BSON_OPTIONAL_PARAM (error); ENTRY; BSON_ASSERT (cluster); if (cs && cs->server_id && cs->server_id != server_id) { _mongoc_bson_init_if_set (reply); bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_SERVER_SELECTION_INVALID_ID, "Requested server id does not matched pinned server id"); RETURN (NULL); } mongoc_server_stream_t *const server_stream = _mongoc_cluster_stream_for_server (cluster, server_id, reconnect_ok, cs, reply, error); if (_in_sharded_txn (cs)) { _mongoc_client_session_pin (cs, server_id); } else { /* Transactions Spec: Additionally, any non-transaction operation using * a pinned ClientSession MUST unpin the session and the operation MUST * perform normal server selection. */ if (cs && !_mongoc_client_session_in_txn_or_ending (cs)) { _mongoc_client_session_unpin (cs); } } RETURN (server_stream); } static mongoc_server_stream_t * _cluster_fetch_stream_single (mongoc_cluster_t *cluster, const mongoc_topology_description_t *td, uint32_t server_id, bool reconnect_ok, bson_error_t *error /* OUT */) { mongoc_server_description_t *handshake_sd; mongoc_topology_scanner_node_t *scanner_node; char *address; scanner_node = mongoc_topology_scanner_get_node (cluster->client->topology->scanner, server_id); /* This could happen if a user explicitly passes a bad server id. */ if (!scanner_node) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Could not find server with id: %" PRIu32, server_id); return NULL; } /* Retired scanner nodes are removed at the end of a scan. If the node was * retired, that would indicate a bug. */ if (scanner_node->retired) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Unexpected, selecting server marked for removal: %s", scanner_node->host.host_and_port); return NULL; } if (scanner_node->stream) { handshake_sd = mongoc_server_description_new_copy (scanner_node->handshake_sd); } else { if (!reconnect_ok) { stream_not_found (td, server_id, scanner_node->host.host_and_port, error); return NULL; } /* save the scanner node address in case it is removed during the scan. */ address = bson_strdup (scanner_node->host.host_and_port); _mongoc_topology_do_blocking_scan (cluster->client->topology, error); if (error->code) { bson_free (address); return NULL; } scanner_node = mongoc_topology_scanner_get_node (cluster->client->topology->scanner, server_id); if (!scanner_node || !scanner_node->stream) { stream_not_found (td, server_id, address, error); bson_free (address); return NULL; } bson_free (address); handshake_sd = mongoc_server_description_new_copy (scanner_node->handshake_sd); } if (handshake_sd->type == MONGOC_SERVER_UNKNOWN) { *error = handshake_sd->error; mongoc_server_description_destroy (handshake_sd); return NULL; } /* stream open but not auth'ed: first use since connect or reconnect */ if (cluster->requires_auth && !scanner_node->has_auth) { /* Complete speculative authentication */ bool has_speculative_auth = _mongoc_cluster_finish_speculative_auth (cluster, scanner_node->stream, handshake_sd, &scanner_node->speculative_auth_response, &scanner_node->scram, &handshake_sd->error); #ifdef MONGOC_ENABLE_CRYPTO _mongoc_scram_destroy (&scanner_node->scram); #endif if (!scanner_node->stream) { *error = handshake_sd->error; mongoc_server_description_destroy (handshake_sd); return NULL; } if (!has_speculative_auth && !_mongoc_cluster_auth_node ( cluster, scanner_node->stream, handshake_sd, &scanner_node->sasl_supported_mechs, &handshake_sd->error)) { *error = handshake_sd->error; mongoc_server_description_destroy (handshake_sd); return NULL; } scanner_node->has_auth = true; } /* Copy the latest connection pool generation. * TODO (CDRIVER-4078) do not store the generation counter on the server * description */ handshake_sd->generation = _mongoc_topology_get_connection_pool_generation (td, server_id, &handshake_sd->service_id); return mongoc_server_stream_new (td, handshake_sd, scanner_node->stream); } /* *-------------------------------------------------------------------------- * * mongoc_cluster_stream_valid -- * * Internal function to determine if @server_stream is valid and * associated with the given cluster. * * Returns: * true if @server_stream is not NULL, hasn't been freed or changed; * otherwise false. * *-------------------------------------------------------------------------- */ bool mongoc_cluster_stream_valid (mongoc_cluster_t *cluster, mongoc_server_stream_t *server_stream) { mongoc_server_stream_t *tmp_stream = NULL; mongoc_topology_t *topology = BSON_ASSERT_PTR_INLINE (cluster)->client->topology; const mongoc_server_description_t *sd; bool ret = false; bson_error_t error; mc_shared_tpld td = mc_tpld_take_ref (topology); if (!server_stream) { goto done; } tmp_stream = mongoc_cluster_stream_for_server (cluster, server_stream->sd->id, false, NULL, NULL, NULL); if (!tmp_stream || tmp_stream->stream != server_stream->stream) { /* stream was freed, or has changed. */ goto done; } /* Check that the server stream is still valid for the given server, and that * the server is still registered. */ sd = mongoc_topology_description_server_by_id_const (td.ptr, server_stream->sd->id, &error); if (!sd || server_stream->sd->generation < _mongoc_topology_get_connection_pool_generation ( td.ptr, server_stream->sd->id, &server_stream->sd->service_id)) { /* No server description, or the pool has been cleared. */ goto done; } ret = true; done: mc_tpld_drop_ref (&td); mongoc_server_stream_cleanup (tmp_stream); return ret; } mongoc_server_stream_t * _mongoc_cluster_create_server_stream (mongoc_topology_description_t const *td, const mongoc_server_description_t *handshake_sd, mongoc_stream_t *stream) { mongoc_server_description_t *const sd = mongoc_server_description_new_copy (handshake_sd); /* can't just use mongoc_topology_server_by_id(), since we must hold the * lock while copying topology->shared_descr.ptr->logical_time below */ return mongoc_server_stream_new (td, sd, stream); } static mongoc_server_stream_t * _cluster_fetch_stream_pooled (mongoc_cluster_t *cluster, const mongoc_topology_description_t *td, uint32_t server_id, bool reconnect_ok, bson_error_t *error /* OUT */) { mongoc_cluster_node_t *cluster_node; mongoc_server_description_t const *sd; bool has_server_description = false; cluster_node = (mongoc_cluster_node_t *) mongoc_set_get (cluster->nodes, server_id); sd = mongoc_topology_description_server_by_id_const (td, server_id, error); if (sd) { has_server_description = true; } if (cluster_node) { uint32_t connection_pool_generation = 0; BSON_ASSERT (cluster_node->stream); connection_pool_generation = _mongoc_topology_get_connection_pool_generation (td, server_id, &cluster_node->handshake_sd->service_id); if (!has_server_description || cluster_node->handshake_sd->generation < connection_pool_generation) { /* Since the stream was created, connections to this server were * invalidated. * This may have happened if: * - A background scan removed the server description. * - A network error or a "not primary"/"node is recovering" error * occurred on an app connection. * - A network error occurred on the monitor connection. */ mongoc_cluster_disconnect_node (cluster, server_id); } else { return _mongoc_cluster_create_server_stream (td, cluster_node->handshake_sd, cluster_node->stream); } } /* no node, or out of date */ if (!reconnect_ok) { node_not_found (td, server_id, error); return NULL; } cluster_node = _cluster_add_node (cluster, td, server_id, error); if (cluster_node) { return _mongoc_cluster_create_server_stream (td, cluster_node->handshake_sd, cluster_node->stream); } else { return NULL; } } /* *-------------------------------------------------------------------------- * * mongoc_cluster_init -- * * Initializes @cluster using the @uri and @client provided. The * @uri is used to determine the "mode" of the cluster. Based on the * uri we can determine if we are connected to a single host, a * replicaSet, or a shardedCluster. * * Returns: * None. * * Side effects: * @cluster is initialized. * *-------------------------------------------------------------------------- */ void mongoc_cluster_init (mongoc_cluster_t *cluster, const mongoc_uri_t *uri, void *client) { ENTRY; BSON_ASSERT (cluster); BSON_ASSERT (uri); memset (cluster, 0, sizeof *cluster); cluster->uri = mongoc_uri_copy (uri); cluster->client = (mongoc_client_t *) client; cluster->requires_auth = (mongoc_uri_get_username (uri) || mongoc_uri_get_auth_mechanism (uri)); mongoc_cluster_reset_sockettimeoutms (cluster); cluster->socketcheckintervalms = mongoc_uri_get_option_as_int32 (uri, MONGOC_URI_SOCKETCHECKINTERVALMS, MONGOC_TOPOLOGY_SOCKET_CHECK_INTERVAL_MS); /* TODO for single-threaded case we don't need this */ cluster->nodes = mongoc_set_new (8, _mongoc_cluster_node_dtor, NULL); _mongoc_array_init (&cluster->iov, sizeof (mongoc_iovec_t)); cluster->operation_id = rand (); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_destroy -- * * Clean up after @cluster and destroy all active connections. * All resources for @cluster are released. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ void mongoc_cluster_destroy (mongoc_cluster_t *cluster) /* INOUT */ { ENTRY; BSON_ASSERT (cluster); mongoc_uri_destroy (cluster->uri); mongoc_set_destroy (cluster->nodes); _mongoc_array_destroy (&cluster->iov); EXIT; } void mongoc_cluster_set_sockettimeoutms (mongoc_cluster_t *cluster, int32_t timeoutms) { BSON_ASSERT_PARAM (cluster); cluster->sockettimeoutms = timeoutms; } void mongoc_cluster_reset_sockettimeoutms (mongoc_cluster_t *cluster) { BSON_ASSERT_PARAM (cluster); cluster->sockettimeoutms = mongoc_uri_get_option_as_int32 (cluster->uri, MONGOC_URI_SOCKETTIMEOUTMS, MONGOC_DEFAULT_SOCKETTIMEOUTMS); } static uint32_t _mongoc_cluster_select_server_id (mongoc_client_session_t *cs, mongoc_topology_t *topology, mongoc_ss_optype_t optype, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, bool *must_use_primary, const mongoc_deprioritized_servers_t *ds, bson_error_t *error) { BSON_OPTIONAL_PARAM (cs); BSON_ASSERT_PARAM (topology); BSON_OPTIONAL_PARAM (read_prefs); BSON_ASSERT_PARAM (must_use_primary); BSON_OPTIONAL_PARAM (error); uint32_t server_id; if (_in_sharded_txn (cs)) { server_id = cs->server_id; if (!server_id) { server_id = mongoc_topology_select_server_id (topology, optype, log_context, read_prefs, must_use_primary, ds, error); if (server_id) { _mongoc_client_session_pin (cs, server_id); } } } else { server_id = mongoc_topology_select_server_id (topology, optype, log_context, read_prefs, must_use_primary, ds, error); /* Transactions Spec: Additionally, any non-transaction operation using a * pinned ClientSession MUST unpin the session and the operation MUST * perform normal server selection. */ if (cs && !_mongoc_client_session_in_txn_or_ending (cs)) { _mongoc_client_session_unpin (cs); } } return server_id; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_stream_for_optype -- * * Internal server selection. * * Returns: * A mongoc_server_stream_t on which you must call * mongoc_server_stream_cleanup, or NULL on failure (sets @error) * * Side effects: * May add or disconnect nodes in @cluster->nodes. * Sets @error and initializes @reply on error. * *-------------------------------------------------------------------------- */ static mongoc_server_stream_t * _mongoc_cluster_stream_for_optype (mongoc_cluster_t *cluster, mongoc_ss_optype_t optype, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, mongoc_client_session_t *cs, bool is_retryable, const mongoc_deprioritized_servers_t *ds, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_OPTIONAL_PARAM (read_prefs); BSON_OPTIONAL_PARAM (cs); BSON_OPTIONAL_PARAM (reply); BSON_OPTIONAL_PARAM (error); mongoc_server_stream_t *server_stream; uint32_t server_id; mongoc_topology_t *topology = cluster->client->topology; bool must_use_primary = false; ENTRY; BSON_ASSERT (cluster); server_id = _mongoc_cluster_select_server_id (cs, topology, optype, log_context, read_prefs, &must_use_primary, ds, error); if (!server_id) { if (reply) { bson_init (reply); _mongoc_add_transient_txn_error (cs, reply); } RETURN (NULL); } if (!mongoc_cluster_check_interval (cluster, server_id)) { /* Server Selection Spec: try once more */ server_id = _mongoc_cluster_select_server_id (cs, topology, optype, log_context, read_prefs, &must_use_primary, ds, error); if (!server_id) { if (reply) { bson_init (reply); _mongoc_add_transient_txn_error (cs, reply); } RETURN (NULL); } } bson_t first_reply; bson_error_t first_error = {0}; server_stream = _mongoc_cluster_stream_for_server (cluster, server_id, true /* reconnect_ok */, cs, &first_reply, &first_error); if (server_stream) { server_stream->must_use_primary = must_use_primary; RETURN (server_stream); } // Important: authentication errors are also considered retryable even if // they not considered a network error. const bool retryable_error = _mongoc_error_is_network (&first_error) || _mongoc_error_is_auth (&first_error); if (is_retryable && retryable_error) { bson_t retry_reply; bson_error_t retry_error = {0}; server_stream = _mongoc_cluster_stream_for_server ( cluster, server_id, true /* reconnect_ok */, cs, &retry_reply, &retry_error); if (server_stream) { server_stream->must_use_primary = must_use_primary; server_stream->retry_attempted = true; bson_destroy (&first_reply); RETURN (server_stream); } if (optype != MONGOC_SS_READ) { // Retryable Writes Spec: When the driver encounters a network error // establishing an initial connection to a server, it MUST add a // RetryableWriteError label to that error if the MongoClient // performing the operation has the retryWrites configuration option // set to true. _mongoc_write_error_append_retryable_label (&first_reply); } bson_destroy (&retry_reply); } // Retryable Writes Spec: If the driver cannot select a server for the retry // attempt [...], retrying is not possible and drivers MUST raise the // original retryable error. { if (reply) { bson_copy_to (&first_reply, reply); } bson_destroy (&first_reply); if (error) { *error = first_error; } } RETURN (NULL); } mongoc_server_stream_t * mongoc_cluster_stream_for_reads (mongoc_cluster_t *cluster, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, mongoc_client_session_t *cs, const mongoc_deprioritized_servers_t *ds, bson_t *reply, bson_error_t *error) { const mongoc_read_prefs_t *const prefs_override = _mongoc_client_session_in_txn (cs) ? cs->txn.opts.read_prefs : read_prefs; // Retryable Reads Spec: This boolean option determines whether retryable // behavior will be applied to all read operations executed within the // MongoClient. const bool is_retryable = mongoc_uri_get_option_as_bool (cluster->uri, MONGOC_URI_RETRYREADS, MONGOC_DEFAULT_RETRYREADS); return _mongoc_cluster_stream_for_optype ( cluster, MONGOC_SS_READ, log_context, prefs_override, cs, is_retryable, ds, reply, error); } mongoc_server_stream_t * mongoc_cluster_stream_for_writes (mongoc_cluster_t *cluster, const mongoc_ss_log_context_t *log_context, mongoc_client_session_t *cs, const mongoc_deprioritized_servers_t *ds, bson_t *reply, bson_error_t *error) { const bool is_retryable = mongoc_uri_get_option_as_bool (cluster->uri, MONGOC_URI_RETRYWRITES, MONGOC_DEFAULT_RETRYWRITES); return _mongoc_cluster_stream_for_optype ( cluster, MONGOC_SS_WRITE, log_context, NULL, cs, is_retryable, ds, reply, error); } mongoc_server_stream_t * mongoc_cluster_stream_for_aggr_with_write (mongoc_cluster_t *cluster, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, mongoc_client_session_t *cs, bson_t *reply, bson_error_t *error) { const mongoc_read_prefs_t *const prefs_override = _mongoc_client_session_in_txn (cs) ? cs->txn.opts.read_prefs : read_prefs; const bool is_retryable = mongoc_uri_get_option_as_bool (cluster->uri, MONGOC_URI_RETRYWRITES, MONGOC_DEFAULT_RETRYWRITES); return _mongoc_cluster_stream_for_optype ( cluster, MONGOC_SS_AGGREGATE_WITH_WRITE, log_context, prefs_override, cs, is_retryable, NULL, reply, error); } static bool _mongoc_cluster_min_of_max_obj_size_sds (const void *item, void *ctx) { const mongoc_server_description_t *sd = item; int32_t *current_min = (int32_t *) ctx; if (sd->max_bson_obj_size < *current_min) { *current_min = sd->max_bson_obj_size; } return true; } static bool _mongoc_cluster_min_of_max_obj_size_nodes (void *item, void *ctx) { mongoc_cluster_node_t *node = (mongoc_cluster_node_t *) item; int32_t *current_min = (int32_t *) ctx; if (node->handshake_sd->max_bson_obj_size < *current_min) { *current_min = node->handshake_sd->max_bson_obj_size; } return true; } static bool _mongoc_cluster_min_of_max_msg_size_sds (const void *item, void *ctx) { const mongoc_server_description_t *sd = item; int32_t *current_min = (int32_t *) ctx; if (sd->max_msg_size < *current_min) { *current_min = sd->max_msg_size; } return true; } static bool _mongoc_cluster_min_of_max_msg_size_nodes (void *item, void *ctx) { mongoc_cluster_node_t *node = (mongoc_cluster_node_t *) item; int32_t *current_min = (int32_t *) ctx; if (node->handshake_sd->max_msg_size < *current_min) { *current_min = node->handshake_sd->max_msg_size; } return true; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_get_max_bson_obj_size -- * * Return the minimum max_bson_obj_size across all servers in cluster. * * Returns: * The minimum max_bson_obj_size. * * Side effects: * None * *-------------------------------------------------------------------------- */ int32_t mongoc_cluster_get_max_bson_obj_size (mongoc_cluster_t *cluster) { int32_t max_bson_obj_size = -1; max_bson_obj_size = MONGOC_DEFAULT_BSON_OBJ_SIZE; if (!cluster->client->topology->single_threaded) { mongoc_set_for_each (cluster->nodes, _mongoc_cluster_min_of_max_obj_size_nodes, &max_bson_obj_size); } else { mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (cluster)->client->topology); mongoc_set_for_each_const ( mc_tpld_servers_const (td.ptr), _mongoc_cluster_min_of_max_obj_size_sds, &max_bson_obj_size); mc_tpld_drop_ref (&td); } return max_bson_obj_size; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_get_max_msg_size -- * * Return the minimum max msg size across all servers in cluster. * * Returns: * The minimum max_msg_size * * Side effects: * None * *-------------------------------------------------------------------------- */ int32_t mongoc_cluster_get_max_msg_size (mongoc_cluster_t *cluster) { int32_t max_msg_size = MONGOC_DEFAULT_MAX_MSG_SIZE; if (!cluster->client->topology->single_threaded) { mongoc_set_for_each (cluster->nodes, _mongoc_cluster_min_of_max_msg_size_nodes, &max_msg_size); } else { mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (cluster)->client->topology); mongoc_set_for_each_const ( mc_tpld_servers_const (td.ptr), _mongoc_cluster_min_of_max_msg_size_sds, &max_msg_size); mc_tpld_drop_ref (&td); } return max_msg_size; } /* *-------------------------------------------------------------------------- * * mongoc_cluster_check_interval -- * * Server Selection Spec: * * Only for single-threaded drivers. * * If a server is selected that has an existing connection that has been * idle for socketCheckIntervalMS, the driver MUST check the connection * with the "ping" command. If the ping succeeds, use the selected * connection. If not, set the server's type to Unknown and update the * Topology Description according to the Server Discovery and Monitoring * Spec, and attempt once more to select a server. * * Returns: * True if the check succeeded or no check was required, false if the * check failed. * * Side effects: * If a check fails, closes stream and may set server type Unknown. * *-------------------------------------------------------------------------- */ bool mongoc_cluster_check_interval (mongoc_cluster_t *cluster, uint32_t server_id) { mongoc_cmd_parts_t parts; mongoc_topology_t *topology; mongoc_topology_scanner_node_t *scanner_node; mongoc_stream_t *stream; int64_t now; bson_t command; bson_error_t error; bool r = true; mongoc_server_stream_t *server_stream; mongoc_server_description_t *handshake_sd; topology = cluster->client->topology; if (!topology->single_threaded) { return true; } scanner_node = mongoc_topology_scanner_get_node (topology->scanner, server_id); if (!scanner_node) { return false; } BSON_ASSERT (!scanner_node->retired); stream = scanner_node->stream; if (!stream) { return false; } handshake_sd = scanner_node->handshake_sd; BSON_ASSERT (handshake_sd); now = bson_get_monotonic_time (); if (scanner_node->last_used + (1000 * CHECK_CLOSED_DURATION_MSEC) < now) { if (mongoc_stream_check_closed (stream)) { mc_tpld_modification tdmod; bson_set_error (&error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "connection closed"); mongoc_cluster_disconnect_node (cluster, server_id); tdmod = mc_tpld_modify_begin (topology); /* invalidate_server() is okay if 'server_id' was already removed. */ mongoc_topology_description_invalidate_server (tdmod.new_td, &topology->log_and_monitor, server_id, &error); mc_tpld_modify_commit (tdmod); return false; } } if (scanner_node->last_used + (1000 * cluster->socketcheckintervalms) < now) { mc_shared_tpld td; bson_init (&command); BSON_APPEND_INT32 (&command, "ping", 1); mongoc_cmd_parts_init (&parts, cluster->client, "admin", MONGOC_QUERY_SECONDARY_OK, &command); parts.prohibit_lsid = true; td = mc_tpld_take_ref (topology); server_stream = _mongoc_cluster_create_server_stream (td.ptr, handshake_sd, stream); mc_tpld_drop_ref (&td); if (!server_stream) { bson_destroy (&command); return false; } r = mongoc_cluster_run_command_parts (cluster, server_stream, &parts, NULL, &error); mongoc_server_stream_cleanup (server_stream); bson_destroy (&command); if (!r) { mc_tpld_modification tdmod; mongoc_cluster_disconnect_node (cluster, server_id); tdmod = mc_tpld_modify_begin (topology); /* invalidate_server() is okay if 'server_id' was already removed. */ mongoc_topology_description_invalidate_server (tdmod.new_td, &topology->log_and_monitor, server_id, &error); mc_tpld_modify_commit (tdmod); } } return r; } bool mongoc_cluster_legacy_rpc_sendv_to_server (mongoc_cluster_t *cluster, mcd_rpc_message *rpc, mongoc_server_stream_t *server_stream, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (server_stream); BSON_ASSERT_PARAM (error); ENTRY; bool ret = false; void *compressed_data = NULL; size_t compressed_data_len = 0u; mongoc_iovec_t *iovecs = NULL; size_t num_iovecs = 0u; if (cluster->client->in_exhaust) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_IN_EXHAUST, "a cursor derived from this client is in exhaust"); GOTO (done); } const int32_t compressor_id = mongoc_server_description_compressor_id (server_stream->sd); if (compressor_id != -1 && !mcd_rpc_message_compress (rpc, compressor_id, _compression_level_from_uri (compressor_id, cluster->uri), &compressed_data, &compressed_data_len, error)) { GOTO (done); } const uint32_t server_id = server_stream->sd->id; const int32_t max_msg_size = mongoc_server_stream_max_msg_size (server_stream); const int32_t message_length = mcd_rpc_header_get_message_length (rpc); if (message_length > max_msg_size) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_TOO_BIG, "attempted to send an RPC message with length %" PRId32 " which exceeds the maximum allowed length %" PRId32, message_length, max_msg_size); GOTO (done); } iovecs = mcd_rpc_message_to_iovecs (rpc, &num_iovecs); BSON_ASSERT (iovecs); mcd_rpc_message_egress (rpc); if (!_mongoc_stream_writev_full (server_stream->stream, iovecs, num_iovecs, cluster->sockettimeoutms, error)) { GOTO (done); } _mongoc_topology_update_last_used (cluster->client->topology, server_id); ret = true; done: bson_free (iovecs); bson_free (compressed_data); RETURN (ret); } bool mongoc_cluster_try_recv (mongoc_cluster_t *cluster, mcd_rpc_message *rpc, mongoc_buffer_t *buffer, mongoc_server_stream_t *server_stream, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (server_stream); BSON_ASSERT_PARAM (error); ENTRY; bool ret = false; TRACE ("Waiting for reply from server_id \"%u\"", server_stream->sd->id); const size_t offset = buffer->len; if (!_mongoc_buffer_append_from_stream ( buffer, server_stream->stream, sizeof (int32_t), cluster->sockettimeoutms, error)) { MONGOC_DEBUG ("could not read message length, stream probably closed or timed out"); mongoc_counter_protocol_ingress_error_inc (); _handle_network_error (cluster, server_stream, error); GOTO (done); } const int32_t message_length = _int32_from_le (buffer->data + offset); const int32_t max_msg_size = mongoc_server_stream_max_msg_size (server_stream); if (message_length < message_header_length || message_length > max_msg_size) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "message length %" PRId32 " is not within valid range of %" PRId32 "-%" PRId32 " bytes", message_header_length, message_length, server_stream->sd->max_msg_size); _handle_network_error (cluster, server_stream, error); mongoc_counter_protocol_ingress_error_inc (); GOTO (done); } const size_t remaining_bytes = (size_t) message_length - sizeof (int32_t); if (!_mongoc_buffer_append_from_stream ( buffer, server_stream->stream, remaining_bytes, cluster->sockettimeoutms, error)) { _handle_network_error (cluster, server_stream, error); mongoc_counter_protocol_ingress_error_inc (); GOTO (done); } if (!mcd_rpc_message_from_data_in_place (rpc, buffer->data + offset, (size_t) message_length, NULL)) { bson_set_error ( error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "failed to decode reply from server"); _handle_network_error (cluster, server_stream, error); mongoc_counter_protocol_ingress_error_inc (); GOTO (done); } mcd_rpc_message_ingress (rpc); void *decompressed_data = NULL; size_t decompressed_data_len = 0u; if (!mcd_rpc_message_decompress_if_necessary (rpc, &decompressed_data, &decompressed_data_len)) { bson_set_error ( error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "could not decompress server reply"); GOTO (done); } if (decompressed_data) { _mongoc_buffer_destroy (buffer); _mongoc_buffer_init (buffer, decompressed_data, decompressed_data_len, NULL, NULL); } ret = true; done: return ret; } static void network_error_reply (bson_t *reply, const mongoc_cmd_t *cmd) { bson_array_builder_t *labels; if (reply) { bson_init (reply); } if (cmd->session) { if (cmd->session->server_session) { cmd->session->server_session->dirty = true; } /* Transactions Spec defines TransientTransactionError: "Any * network error or server selection error encountered running any * command besides commitTransaction in a transaction. In the case * of command errors, the server adds the label; in the case of * network errors or server selection errors where the client * receives no server reply, the client adds the label." */ if (_mongoc_client_session_in_txn (cmd->session) && !cmd->is_txn_finish) { /* Transaction Spec: "Drivers MUST unpin a ClientSession when a command * within a transaction, including commitTransaction and * abortTransaction, * fails with a TransientTransactionError". If we're about to add * a TransientTransactionError label due to a client side error then we * unpin. If commitTransaction/abortTransation includes a label in the * server reply, we unpin in _mongoc_client_session_handle_reply. */ cmd->session->server_id = 0; if (!reply) { return; } BSON_APPEND_ARRAY_BUILDER_BEGIN (reply, "errorLabels", &labels); bson_array_builder_append_utf8 (labels, TRANSIENT_TXN_ERR, -1); bson_append_array_builder_end (reply, labels); } } } static bool _mongoc_cluster_run_opmsg_send ( mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, mcd_rpc_message *rpc, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (cmd); BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (reply); BSON_ASSERT_PARAM (error); mongoc_server_stream_t *const server_stream = cmd->server_stream; const uint32_t flags = (cmd->is_acknowledged ? MONGOC_OP_MSG_FLAG_NONE : MONGOC_OP_MSG_FLAG_MORE_TO_COME) | (cmd->op_msg_is_exhaust ? MONGOC_OP_MSG_FLAG_EXHAUST_ALLOWED : MONGOC_OP_MSG_FLAG_NONE); { int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (rpc, 0); message_length += mcd_rpc_header_set_request_id (rpc, ++cluster->request_id); message_length += mcd_rpc_header_set_response_to (rpc, 0); message_length += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_MSG); BSON_ASSERT (cmd->payloads_count <= MONGOC_CMD_PAYLOADS_COUNT_MAX); // Reserve one section for the body (kind 0) and any needed sections for document sequences (kind 1) mcd_rpc_op_msg_set_sections_count (rpc, 1u + cmd->payloads_count); message_length += mcd_rpc_op_msg_set_flag_bits (rpc, flags); message_length += mcd_rpc_op_msg_section_set_kind (rpc, 0u, 0); message_length += mcd_rpc_op_msg_section_set_body (rpc, 0u, bson_get_data (cmd->command)); for (size_t i = 0; i < cmd->payloads_count; i++) { const mongoc_cmd_payload_t payload = cmd->payloads[i]; BSON_ASSERT (mcommon_in_range_signed (size_t, payload.size)); const size_t section_length = sizeof (int32_t) + strlen (payload.identifier) + 1u + (size_t) payload.size; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, section_length)); size_t section_idx = 1u + i; message_length += mcd_rpc_op_msg_section_set_kind (rpc, section_idx, 1); message_length += mcd_rpc_op_msg_section_set_length (rpc, section_idx, (int32_t) section_length); message_length += mcd_rpc_op_msg_section_set_identifier (rpc, section_idx, payload.identifier); message_length += mcd_rpc_op_msg_section_set_document_sequence (rpc, section_idx, payload.documents, (size_t) payload.size); } mcd_rpc_message_set_length (rpc, message_length); } void *compressed_data = NULL; size_t compressed_data_len = 0u; if (mongoc_cmd_is_compressible (cmd)) { const int32_t compressor_id = mongoc_server_description_compressor_id (server_stream->sd); TRACE ("Function '%s' is compressible: %d", cmd->command_name, compressor_id); if (compressor_id != -1 && !mcd_rpc_message_compress (rpc, compressor_id, _compression_level_from_uri (compressor_id, cluster->uri), &compressed_data, &compressed_data_len, error)) { RUN_CMD_ERR_DECORATE; _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); return false; } } size_t num_iovecs = 0u; mongoc_iovec_t *const iovecs = mcd_rpc_message_to_iovecs (rpc, &num_iovecs); BSON_ASSERT (iovecs); mcd_rpc_message_egress (rpc); const bool res = _mongoc_stream_writev_full (server_stream->stream, iovecs, num_iovecs, cluster->sockettimeoutms, error); if (!res) { RUN_CMD_ERR_DECORATE; _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); } bson_free (iovecs); bson_free (compressed_data); return res; } static bool _mongoc_cluster_run_opmsg_recv ( mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, mcd_rpc_message *rpc, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (cmd); BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (reply); BSON_ASSERT_PARAM (error); bool ret = false; mongoc_server_stream_t *const server_stream = cmd->server_stream; mongoc_buffer_t buffer; _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); if (!_mongoc_buffer_append_from_stream ( &buffer, server_stream->stream, sizeof (int32_t), cluster->sockettimeoutms, error)) { MONGOC_DEBUG ("could not read message length, stream probably closed or timed out"); RUN_CMD_ERR_DECORATE; _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); goto done; } const int32_t message_length = _int32_from_le (buffer.data); if (message_length < message_header_length || message_length > server_stream->sd->max_msg_size) { RUN_CMD_ERR (MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "message length %" PRId32 " is not within valid range of %" PRId32 "-%" PRId32 " bytes", message_header_length, message_length, server_stream->sd->max_msg_size); _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); goto done; } const size_t remaining_bytes = (size_t) message_length - sizeof (int32_t); if (!_mongoc_buffer_append_from_stream ( &buffer, server_stream->stream, remaining_bytes, cluster->sockettimeoutms, error)) { RUN_CMD_ERR_DECORATE; _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); goto done; } if (!mcd_rpc_message_from_data_in_place (rpc, buffer.data, buffer.len, NULL)) { RUN_CMD_ERR (MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "malformed server message"); _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); goto done; } mcd_rpc_message_ingress (rpc); void *decompressed_data = NULL; size_t decompressed_data_len = 0u; if (!mcd_rpc_message_decompress_if_necessary (rpc, &decompressed_data, &decompressed_data_len)) { bson_set_error ( error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "could not decompress message from server"); _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); GOTO (done); } if (decompressed_data) { _mongoc_buffer_destroy (&buffer); _mongoc_buffer_init (&buffer, decompressed_data, decompressed_data_len, NULL, NULL); } // CDRIVER-5584 { const int32_t op_code = mcd_rpc_header_get_op_code (rpc); if (op_code != MONGOC_OP_CODE_MSG) { RUN_CMD_ERR (MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "malformed message from server: expected opCode %" PRId32 ", got %" PRId32, MONGOC_OP_CODE_MSG, op_code); _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); goto done; } } bson_t body; if (!mcd_rpc_message_get_body (rpc, &body)) { RUN_CMD_ERR (MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "malformed message from server"); _handle_network_error (cluster, server_stream, error); server_stream->stream = NULL; network_error_reply (reply, cmd); goto done; } cluster->client->in_exhaust = (mcd_rpc_op_msg_get_flag_bits (rpc) & MONGOC_OP_MSG_FLAG_MORE_TO_COME) != 0u; _mongoc_topology_update_cluster_time (cluster->client->topology, &body); ret = _mongoc_cmd_check_ok (&body, cluster->client->error_api_version, error); if (cmd->session) { _mongoc_client_session_handle_reply (cmd->session, cmd->is_acknowledged, cmd->command_name, &body); } bson_copy_to (&body, reply); bson_destroy (&body); done: _mongoc_buffer_destroy (&buffer); return ret; } static bool mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster, const mongoc_cmd_t *cmd, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (cmd); BSON_ASSERT_PARAM (reply); BSON_ASSERT_PARAM (error); if (!cmd->command_name) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "empty command document"); bson_init (reply); return false; } if (!cmd->op_msg_is_exhaust && cluster->client->in_exhaust) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_IN_EXHAUST, "another cursor derived from this client is in exhaust"); bson_init (reply); return false; } bool ret = false; mcd_rpc_message *const rpc = mcd_rpc_message_new (); if (!cluster->client->in_exhaust && !_mongoc_cluster_run_opmsg_send (cluster, cmd, rpc, reply, error)) { goto done; } if (!cmd->is_acknowledged) { // Nothing more to do. bson_init (reply); ret = true; goto done; } mcd_rpc_message_reset (rpc); if (!_mongoc_cluster_run_opmsg_recv (cluster, cmd, rpc, reply, error)) { goto done; } ret = true; done: mcd_rpc_message_destroy (rpc); return ret; } bool mcd_rpc_message_compress (mcd_rpc_message *rpc, int32_t compressor_id, int32_t compression_level, void **data, size_t *data_len, bson_error_t *error) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (data); BSON_ASSERT_PARAM (data_len); bool ret = false; char *uncompressed_message = NULL; char *compressed_message = NULL; mongoc_iovec_t *iovecs = NULL; const int32_t original_message_length = mcd_rpc_header_get_message_length (rpc); // msgHeader consists of four int32 fields. const int32_t message_header_length = 4u * sizeof (int32_t); // compressedMessage does not include msgHeader fields. BSON_ASSERT (original_message_length >= message_header_length); const size_t uncompressed_size = (size_t) (original_message_length - message_header_length); BSON_ASSERT (mcommon_in_range_unsigned (int32_t, uncompressed_size)); const size_t estimated_compressed_size = mongoc_compressor_max_compressed_length (compressor_id, uncompressed_size); if (estimated_compressed_size == 0u) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Could not determine compression bounds for %s", mongoc_compressor_id_to_name (compressor_id)); goto fail; } // Store values before they are converted to little endian. const int32_t request_id = mcd_rpc_header_get_request_id (rpc); const int32_t response_to = mcd_rpc_header_get_response_to (rpc); const int32_t op_code = mcd_rpc_header_get_op_code (rpc); size_t num_iovecs; iovecs = mcd_rpc_message_to_iovecs (rpc, &num_iovecs); BSON_ASSERT (iovecs); uncompressed_message = bson_malloc (uncompressed_size); BSON_ASSERT (_mongoc_cluster_buffer_iovec (iovecs, num_iovecs, message_header_length, uncompressed_message) == uncompressed_size); compressed_message = bson_malloc (estimated_compressed_size); // This value may be passed as an argument to an in-out parameter depending // on the compressor, not just an out-parameter. size_t compressed_size = estimated_compressed_size; if (!mongoc_compress (compressor_id, compression_level, uncompressed_message, uncompressed_size, compressed_message, &compressed_size)) { MONGOC_WARNING ("Could not compress data with %s", mongoc_compressor_id_to_name (compressor_id)); goto fail; } mcd_rpc_message_reset (rpc); { int32_t message_len = 0; message_len += mcd_rpc_header_set_message_length (rpc, 0); message_len += mcd_rpc_header_set_request_id (rpc, request_id); message_len += mcd_rpc_header_set_response_to (rpc, response_to); message_len += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_COMPRESSED); message_len += mcd_rpc_op_compressed_set_original_opcode (rpc, op_code); message_len += mcd_rpc_op_compressed_set_uncompressed_size (rpc, (int32_t) uncompressed_size); message_len += mcd_rpc_op_compressed_set_compressor_id (rpc, (uint8_t) compressor_id); message_len += mcd_rpc_op_compressed_set_compressed_message (rpc, compressed_message, compressed_size); mcd_rpc_message_set_length (rpc, message_len); } *data = compressed_message; *data_len = compressed_size; compressed_message = NULL; ret = true; fail: bson_free (compressed_message); bson_free (uncompressed_message); bson_free (iovecs); return ret; } bool mcd_rpc_message_decompress (mcd_rpc_message *rpc, void **data, size_t *data_len) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (data); BSON_ASSERT_PARAM (data_len); BSON_ASSERT (mcd_rpc_header_get_op_code (rpc) == MONGOC_OP_CODE_COMPRESSED); // msgHeader consists of four int32 fields. const size_t message_header_length = 4u * sizeof (int32_t); const int32_t uncompressed_size_raw = mcd_rpc_op_compressed_get_uncompressed_size (rpc); // Malformed message: invalid uncompressedSize. if (BSON_UNLIKELY (uncompressed_size_raw < 0)) { return false; } const size_t uncompressed_size = (size_t) uncompressed_size_raw; // Malformed message: original message length is not representable. if (BSON_UNLIKELY (uncompressed_size > SIZE_MAX - message_header_length)) { return false; } // uncompressedSize does not include msgHeader fields. const size_t original_message_length = message_header_length + uncompressed_size; uint8_t *const ptr = bson_malloc (original_message_length); const int32_t message_length = original_message_length; const int32_t request_id = mcd_rpc_header_get_request_id (rpc); const int32_t response_to = mcd_rpc_header_get_response_to (rpc); const int32_t op_code = mcd_rpc_op_compressed_get_original_opcode (rpc); // Populate the msgHeader fields. { uint32_t storage; memcpy (&storage, &message_length, sizeof (storage)); storage = BSON_UINT32_TO_LE (storage); memcpy (ptr + 0, &storage, sizeof (storage)); memcpy (&storage, &request_id, sizeof (storage)); storage = BSON_UINT32_TO_LE (storage); memcpy (ptr + 4, &storage, sizeof (storage)); memcpy (&storage, &response_to, sizeof (storage)); storage = BSON_UINT32_TO_LE (storage); memcpy (ptr + 8, &storage, sizeof (storage)); memcpy (&storage, &op_code, sizeof (storage)); storage = BSON_UINT32_TO_LE (storage); memcpy (ptr + 12, &storage, sizeof (storage)); } // This value may be passed as an argument to an in-out parameter depending // on the compressor, not just an out-parameter. size_t actual_uncompressed_size = uncompressed_size; // Populate the rest of the uncompressed message. if (!mongoc_uncompress (mcd_rpc_op_compressed_get_compressor_id (rpc), mcd_rpc_op_compressed_get_compressed_message (rpc), mcd_rpc_op_compressed_get_compressed_message_length (rpc), ptr + message_header_length, &actual_uncompressed_size)) { bson_free (ptr); return false; } // Malformed message: size inconsistency. if (BSON_UNLIKELY (uncompressed_size != actual_uncompressed_size)) { bson_free (ptr); return false; } *data_len = original_message_length; *data = ptr; // Ownership transfer. mcd_rpc_message_reset (rpc); return mcd_rpc_message_from_data_in_place (rpc, *data, *data_len, NULL); } bool mcd_rpc_message_decompress_if_necessary (mcd_rpc_message *rpc, void **data, size_t *data_len) { BSON_ASSERT_PARAM (rpc); BSON_ASSERT_PARAM (data); BSON_ASSERT_PARAM (data_len); if (mcd_rpc_header_get_op_code (rpc) != MONGOC_OP_CODE_COMPRESSED) { // Nothing to do. *data = NULL; *data_len = 0u; return true; } return mcd_rpc_message_decompress (rpc, data, data_len); } bool mongoc_cluster_run_retryable_write (mongoc_cluster_t *cluster, mongoc_cmd_t *cmd, bool is_retryable_write, mongoc_server_stream_t **retry_server_stream, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (cluster); BSON_ASSERT_PARAM (cmd); BSON_ASSERT_PARAM (retry_server_stream); BSON_ASSERT_PARAM (reply); BSON_OPTIONAL_PARAM (error); bool ret; // `can_retry` is set to false on retry. A retry may only happen once. bool can_retry = is_retryable_write; // Increment the transaction number for the first attempt of each retryable write command. if (is_retryable_write) { bson_iter_t txn_number_iter; BSON_ASSERT (bson_iter_init_find (&txn_number_iter, cmd->command, "txnNumber")); bson_iter_overwrite_int64 (&txn_number_iter, ++cmd->session->server_session->txn_number); } // Store the original error and reply if needed. struct { bson_t reply; bson_error_t error; bool set; } original_error = {.reply = {0}, .error = {0}, .set = false}; // Ensure `*retry_server_stream` is always valid or null. *retry_server_stream = NULL; retry: ret = mongoc_cluster_run_command_monitored (cluster, cmd, reply, error); if (is_retryable_write) { _mongoc_write_error_handle_labels (ret, error, reply, cmd->server_stream->sd); _mongoc_write_error_update_if_unsupported_storage_engine (ret, error, reply); } // If a retryable error is encountered and the write is retryable, select a new writable stream and retry. If server // selection fails or the selected server does not support retryable writes, fall through and allow the original // error to be reported. if (can_retry && _mongoc_write_error_get_type (reply) == MONGOC_WRITE_ERR_RETRY) { can_retry = false; // Only retry once. // Select a server. { mongoc_deprioritized_servers_t *const ds = mongoc_deprioritized_servers_new (); // If talking to a sharded cluster, deprioritize the just-used mongos to prefer a new mongos for the retry. mongoc_deprioritized_servers_add_if_sharded (ds, cmd->server_stream->topology_type, cmd->server_stream->sd); const mongoc_ss_log_context_t ss_log_context = { .operation = cmd->command_name, .has_operation_id = true, .operation_id = cmd->operation_id}; *retry_server_stream = mongoc_cluster_stream_for_writes ( cluster, &ss_log_context, cmd->session, ds, NULL /* reply */, NULL /* error */); mongoc_deprioritized_servers_destroy (ds); } if (*retry_server_stream) { cmd->server_stream = *retry_server_stream; // Non-owning. { // Store the original error and reply before retry. BSON_ASSERT (!original_error.set); // Retry only happens once. original_error.set = true; bson_copy_to (reply, &original_error.reply); if (error) { original_error.error = *error; } } bson_destroy (reply); GOTO (retry); } } // If a retry attempt fails with an error labeled NoWritesPerformed, drivers MUST return the original error. if (original_error.set && mongoc_error_has_label (reply, "NoWritesPerformed")) { if (error) { *error = original_error.error; } bson_destroy (reply); bson_copy_to (&original_error.reply, reply); } if (original_error.set) { bson_destroy (&original_error.reply); } RETURN (ret); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cmd-private.h0000644000175100001660000001075614760300420023363 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include /* * Internal struct to represent a command we will send to the server - command * parameters are collected in a mongoc_cmd_parts_t until we know the server's * wire version and whether it is mongos, then we collect the parts into a * mongoc_cmd_t, and gather that into an RPC message. */ #ifndef MONGOC_CMD_PRIVATE_H #define MONGOC_CMD_PRIVATE_H #include #include #include #include #include #include BSON_BEGIN_DECLS #define MONGOC_DEFAULT_RETRYREADS true /* retryWrites requires sessions, which require crypto */ #ifdef MONGOC_ENABLE_CRYPTO #define MONGOC_DEFAULT_RETRYWRITES true #else #define MONGOC_DEFAULT_RETRYWRITES false #endif typedef enum { MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_UNKNOWN, MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_YES, MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_NO } mongoc_cmd_parts_allow_txn_number_t; // `mongoc_cmd_payload_t` represents a document sequence (OP_MSG Section with payloadType=1). typedef struct { int32_t size; const char *identifier; const uint8_t *documents; } mongoc_cmd_payload_t; // OP_MSG supports any number of document sequences. Increase array size to support more document sequences. #define MONGOC_CMD_PAYLOADS_COUNT_MAX 2 typedef struct _mongoc_cmd_t { const char *db_name; mongoc_query_flags_t query_flags; const bson_t *command; const char *command_name; size_t payloads_count; // `payloads[i]` may be read only when `0 <= i < payloads_count`. mongoc_cmd_payload_t payloads[MONGOC_CMD_PAYLOADS_COUNT_MAX]; mongoc_server_stream_t *server_stream; int64_t operation_id; mongoc_client_session_t *session; mongoc_server_api_t *api; bool is_acknowledged; bool is_txn_finish; bool op_msg_is_exhaust; } mongoc_cmd_t; typedef struct _mongoc_cmd_parts_t { mongoc_cmd_t assembled; mongoc_query_flags_t user_query_flags; const bson_t *body; bson_t read_concern_document; bson_t write_concern_document; bson_t extra; const mongoc_read_prefs_t *read_prefs; bson_t assembled_body; bool is_read_command; bool is_write_command; bool prohibit_lsid; mongoc_cmd_parts_allow_txn_number_t allow_txn_number; bool is_retryable_read; bool is_retryable_write; bool has_temp_session; mongoc_client_t *client; mongoc_server_api_t *api; } mongoc_cmd_parts_t; void mongoc_cmd_parts_init (mongoc_cmd_parts_t *op, mongoc_client_t *client, const char *db_name, mongoc_query_flags_t user_query_flags, const bson_t *command_body); void mongoc_cmd_parts_set_session (mongoc_cmd_parts_t *parts, mongoc_client_session_t *cs); void mongoc_cmd_parts_set_server_api (mongoc_cmd_parts_t *parts, mongoc_server_api_t *api); bool mongoc_cmd_parts_append_opts (mongoc_cmd_parts_t *parts, bson_iter_t *iter, bson_error_t *error); bool mongoc_cmd_parts_set_read_concern (mongoc_cmd_parts_t *parts, const mongoc_read_concern_t *rc, bson_error_t *error); bool mongoc_cmd_parts_set_write_concern (mongoc_cmd_parts_t *parts, const mongoc_write_concern_t *wc, bson_error_t *error); bool mongoc_cmd_parts_append_read_write (mongoc_cmd_parts_t *parts, mongoc_read_write_opts_t *rw_opts, bson_error_t *error); bool mongoc_cmd_parts_assemble (mongoc_cmd_parts_t *parts, mongoc_server_stream_t *server_stream, bson_error_t *error); bool mongoc_cmd_is_compressible (const mongoc_cmd_t *cmd); void mongoc_cmd_parts_cleanup (mongoc_cmd_parts_t *op); bool _is_retryable_read (const mongoc_cmd_parts_t *parts, const mongoc_server_stream_t *server_stream); void _mongoc_cmd_append_payload_as_array (const mongoc_cmd_t *cmd, bson_t *out); void _mongoc_cmd_append_server_api (bson_t *command_body, const mongoc_server_api_t *api); BSON_END_DECLS #endif /* MONGOC_CMD_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cmd.c0000644000175100001660000010414214760300420021677 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include /* For strcasecmp on Windows */ #include void mongoc_cmd_parts_init (mongoc_cmd_parts_t *parts, mongoc_client_t *client, const char *db_name, mongoc_query_flags_t user_query_flags, const bson_t *command_body) { BSON_ASSERT_PARAM (client); parts->body = command_body; parts->user_query_flags = user_query_flags; parts->read_prefs = NULL; parts->is_read_command = false; parts->is_write_command = false; parts->prohibit_lsid = false; parts->allow_txn_number = MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_UNKNOWN; parts->is_retryable_read = false; parts->is_retryable_write = false; parts->has_temp_session = false; parts->client = client; bson_init (&parts->read_concern_document); bson_init (&parts->write_concern_document); bson_init (&parts->extra); bson_init (&parts->assembled_body); parts->assembled.db_name = db_name; parts->assembled.command = NULL; parts->assembled.query_flags = MONGOC_QUERY_NONE; parts->assembled.op_msg_is_exhaust = false; parts->assembled.payloads_count = 0; memset (parts->assembled.payloads, 0, sizeof parts->assembled.payloads); parts->assembled.session = NULL; parts->assembled.is_acknowledged = true; parts->assembled.is_txn_finish = false; } /* *-------------------------------------------------------------------------- * * mongoc_cmd_parts_set_session -- * * Set the client session field. * * Side effects: * Aborts if the command is assembled or if mongoc_cmd_parts_append_opts * was called before. * *-------------------------------------------------------------------------- */ void mongoc_cmd_parts_set_session (mongoc_cmd_parts_t *parts, mongoc_client_session_t *cs) { BSON_ASSERT (parts); BSON_ASSERT (!parts->assembled.command); BSON_ASSERT (!parts->assembled.session); parts->assembled.session = cs; } /* *-------------------------------------------------------------------------- * * mongoc_cmd_parts_append_opts -- * * Take an iterator over user-supplied options document and append the * options to @parts->command_extra, taking the selected server's max * wire version into account. * * Return: * True if the options were successfully applied. If any options are * invalid, returns false and fills out @error. In that case @parts is * invalid and must not be used. * * Side effects: * May partly apply options before returning an error. * *-------------------------------------------------------------------------- */ bool mongoc_cmd_parts_append_opts (mongoc_cmd_parts_t *parts, bson_iter_t *iter, bson_error_t *error) { mongoc_client_session_t *cs = NULL; mongoc_write_concern_t *wc; uint32_t len; const uint8_t *data; bson_t read_concern; const char *to_append; ENTRY; /* not yet assembled */ BSON_ASSERT (!parts->assembled.command); while (bson_iter_next (iter)) { if (BSON_ITER_IS_KEY (iter, "writeConcern")) { wc = _mongoc_write_concern_new_from_iter (iter, error); if (!wc) { RETURN (false); } if (!mongoc_cmd_parts_set_write_concern (parts, wc, error)) { mongoc_write_concern_destroy (wc); RETURN (false); } mongoc_write_concern_destroy (wc); continue; } else if (BSON_ITER_IS_KEY (iter, "readConcern")) { if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "Invalid readConcern"); RETURN (false); } /* add readConcern later, once we know about causal consistency */ bson_iter_document (iter, &len, &data); BSON_ASSERT (bson_init_static (&read_concern, data, (size_t) len)); bson_destroy (&parts->read_concern_document); bson_copy_to (&read_concern, &parts->read_concern_document); continue; } else if (BSON_ITER_IS_KEY (iter, "sessionId")) { BSON_ASSERT (!parts->assembled.session); if (!_mongoc_client_session_from_iter (parts->client, iter, &cs, error)) { RETURN (false); } parts->assembled.session = cs; continue; } else if (BSON_ITER_IS_KEY (iter, "serverId") || BSON_ITER_IS_KEY (iter, "maxAwaitTimeMS") || BSON_ITER_IS_KEY (iter, "exhaust")) { continue; } to_append = bson_iter_key (iter); if (!bson_append_iter (&parts->extra, to_append, -1, iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Failed to append \"%s\" to create command.", to_append); RETURN (false); } } RETURN (true); } #define OPTS_ERR(_code, ...) \ do { \ bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_##_code, __VA_ARGS__); \ RETURN (false); \ } while (0) /* set readConcern if allowed, otherwise error */ bool mongoc_cmd_parts_set_read_concern (mongoc_cmd_parts_t *parts, const mongoc_read_concern_t *rc, bson_error_t *error) { const char *command_name; ENTRY; /* In a txn, set read concern in mongoc_cmd_parts_assemble, not here. * * Transactions Spec: "The readConcern MUST NOT be inherited from the * collection, database, or client associated with the driver method that * invokes the first command." */ if (_mongoc_client_session_in_txn (parts->assembled.session)) { RETURN (true); } command_name = _mongoc_get_command_name (parts->body); if (!command_name) { OPTS_ERR (COMMAND_INVALID_ARG, "Empty command document"); } if (mongoc_read_concern_is_default (rc)) { RETURN (true); } bson_destroy (&parts->read_concern_document); bson_copy_to (_mongoc_read_concern_get_bson ((mongoc_read_concern_t *) rc), &parts->read_concern_document); RETURN (true); } /* set writeConcern if allowed, otherwise ignore - unlike set_read_concern, it's * the caller's responsibility to check if writeConcern is supported */ bool mongoc_cmd_parts_set_write_concern (mongoc_cmd_parts_t *parts, const mongoc_write_concern_t *wc, bson_error_t *error) { ENTRY; if (!wc) { RETURN (true); } const char *const command_name = _mongoc_get_command_name (parts->body); if (!command_name) { OPTS_ERR (COMMAND_INVALID_ARG, "Empty command document"); } parts->assembled.is_acknowledged = mongoc_write_concern_is_acknowledged (wc); bson_destroy (&parts->write_concern_document); bson_copy_to (_mongoc_write_concern_get_bson ((mongoc_write_concern_t *) wc), &parts->write_concern_document); RETURN (true); } /* *-------------------------------------------------------------------------- * * mongoc_cmd_parts_append_read_write -- * * Append user-supplied options to @parts->command_extra, taking the * selected server's max wire version into account. * * Return: * True if the options were successfully applied. If any options are * invalid, returns false and fills out @error. In that case @parts is * invalid and must not be used. * * Side effects: * May partly apply options before returning an error. * *-------------------------------------------------------------------------- */ bool mongoc_cmd_parts_append_read_write (mongoc_cmd_parts_t *parts, mongoc_read_write_opts_t *rw_opts, bson_error_t *error) { ENTRY; /* not yet assembled */ BSON_ASSERT (!parts->assembled.command); if (!bson_empty (&rw_opts->collation)) { if (!bson_append_document (&parts->extra, "collation", 9, &rw_opts->collation)) { OPTS_ERR (COMMAND_INVALID_ARG, "'opts' with 'collation' is too large"); } } if (!mongoc_cmd_parts_set_write_concern (parts, rw_opts->writeConcern, error)) { RETURN (false); } /* process explicit read concern */ if (!bson_empty (&rw_opts->readConcern)) { /* save readConcern for later, once we know about causal consistency */ bson_destroy (&parts->read_concern_document); bson_copy_to (&rw_opts->readConcern, &parts->read_concern_document); } if (rw_opts->client_session) { BSON_ASSERT (!parts->assembled.session); parts->assembled.session = rw_opts->client_session; } if (!bson_concat (&parts->extra, &rw_opts->extra)) { OPTS_ERR (COMMAND_INVALID_ARG, "'opts' with extra fields is too large"); } RETURN (true); } #undef OPTS_ERR static void _mongoc_cmd_parts_ensure_copied (mongoc_cmd_parts_t *parts) { if (parts->assembled.command == parts->body) { bson_concat (&parts->assembled_body, parts->body); bson_concat (&parts->assembled_body, &parts->extra); parts->assembled.command = &parts->assembled_body; } } static void _mongoc_cmd_parts_add_write_concern (mongoc_cmd_parts_t *parts) { if (!bson_empty (&parts->write_concern_document)) { _mongoc_cmd_parts_ensure_copied (parts); bson_append_document (&parts->assembled_body, "writeConcern", 12, &parts->write_concern_document); } } /* The server type must be mongos, or message must be OP_MSG. */ static void _mongoc_cmd_parts_add_read_prefs (bson_t *query, const mongoc_read_prefs_t *prefs) { bson_t child; bson_append_document_begin (query, "$readPreference", 15, &child); mongoc_read_prefs_append_contents_to_bson ( prefs, &child, MONGOC_READ_PREFS_CONTENT_FLAG_MODE | MONGOC_READ_PREFS_CONTENT_FLAG_TAGS | MONGOC_READ_PREFS_CONTENT_FLAG_MAX_STALENESS_SECONDS | MONGOC_READ_PREFS_CONTENT_FLAG_HEDGE); bson_append_document_end (query, &child); } static void _iter_concat (bson_t *dst, bson_iter_t *iter) { uint32_t len; const uint8_t *data; bson_t src; bson_iter_document (iter, &len, &data); BSON_ASSERT (bson_init_static (&src, data, len)); BSON_ASSERT (bson_concat (dst, &src)); } /* Update result with the read prefs. Server must be mongos. */ static void _mongoc_cmd_parts_assemble_mongos (mongoc_cmd_parts_t *parts, const mongoc_server_stream_t *server_stream) { mongoc_read_mode_t mode; const bson_t *tags = NULL; int64_t max_staleness_seconds = MONGOC_NO_MAX_STALENESS; const bson_t *hedge = NULL; bool add_read_prefs = false; bson_t query; bson_iter_t dollar_query; bool has_dollar_query = false; bool requires_read_concern; bool requires_write_concern; ENTRY; mode = mongoc_read_prefs_get_mode (parts->read_prefs); if (parts->read_prefs) { max_staleness_seconds = mongoc_read_prefs_get_max_staleness_seconds (parts->read_prefs); tags = mongoc_read_prefs_get_tags (parts->read_prefs); hedge = mongoc_read_prefs_get_hedge (parts->read_prefs); } if (server_stream->must_use_primary) { /* Server selection has overriden the read mode used to generate this * server stream. This has effects on the body of the message that we send * to the server */ mode = MONGOC_READ_PRIMARY; } /* Server Selection Spec says: * * For mode 'primary', drivers MUST NOT set the secondaryOk wire protocol * flag and MUST NOT use $readPreference * * For mode 'secondary', drivers MUST set the secondaryOk wire protocol flag * and MUST also use $readPreference * * For mode 'primaryPreferred', drivers MUST set the secondaryOk wire * protocol flag and MUST also use $readPreference * * For mode 'secondaryPreferred', drivers MUST set the secondaryOk wire * protocol flag. If the read preference contains a non-empty tag_sets * parameter, maxStalenessSeconds is a positive integer, or the hedge * parameter is non-empty, drivers MUST use $readPreference; otherwise, * drivers MUST NOT use $readPreference * * For mode 'nearest', drivers MUST set the secondaryOk wire protocol flag * and MUST also use $readPreference */ switch (mode) { case MONGOC_READ_PRIMARY: break; case MONGOC_READ_SECONDARY_PREFERRED: if (!bson_empty0 (tags) || max_staleness_seconds > 0 || !bson_empty0 (hedge)) { add_read_prefs = true; } parts->assembled.query_flags |= MONGOC_QUERY_SECONDARY_OK; break; case MONGOC_READ_PRIMARY_PREFERRED: case MONGOC_READ_SECONDARY: case MONGOC_READ_NEAREST: default: parts->assembled.query_flags |= MONGOC_QUERY_SECONDARY_OK; add_read_prefs = true; } requires_read_concern = !bson_empty (&parts->read_concern_document) && strcmp (parts->assembled.command_name, "getMore") != 0; requires_write_concern = !bson_empty (&parts->write_concern_document); if (add_read_prefs) { /* produce {$query: {user query, readConcern}, $readPreference: ... } */ bson_append_document_begin (&parts->assembled_body, "$query", 6, &query); if (bson_iter_init_find (&dollar_query, parts->body, "$query")) { /* user provided something like {$query: {key: "x"}} */ has_dollar_query = true; _iter_concat (&query, &dollar_query); } else { bson_concat (&query, parts->body); } bson_concat (&query, &parts->extra); if (requires_read_concern) { bson_append_document (&query, "readConcern", 11, &parts->read_concern_document); } if (requires_write_concern) { bson_append_document (&query, "writeConcern", 12, &parts->write_concern_document); } bson_append_document_end (&parts->assembled_body, &query); _mongoc_cmd_parts_add_read_prefs (&parts->assembled_body, parts->read_prefs); if (has_dollar_query) { /* copy anything that isn't in user's $query */ bson_copy_to_excluding_noinit (parts->body, &parts->assembled_body, "$query", NULL); } parts->assembled.command = &parts->assembled_body; } else if (bson_iter_init_find (&dollar_query, parts->body, "$query")) { /* user provided $query, we have no read prefs */ bson_append_document_begin (&parts->assembled_body, "$query", 6, &query); _iter_concat (&query, &dollar_query); bson_concat (&query, &parts->extra); if (requires_read_concern) { bson_append_document (&query, "readConcern", 11, &parts->read_concern_document); } if (requires_write_concern) { bson_append_document (&query, "writeConcern", 12, &parts->write_concern_document); } bson_append_document_end (&parts->assembled_body, &query); /* copy anything that isn't in user's $query */ bson_copy_to_excluding_noinit (parts->body, &parts->assembled_body, "$query", NULL); parts->assembled.command = &parts->assembled_body; } else { if (requires_read_concern) { _mongoc_cmd_parts_ensure_copied (parts); bson_append_document (&parts->assembled_body, "readConcern", 11, &parts->read_concern_document); } _mongoc_cmd_parts_add_write_concern (parts); } if (!bson_empty (&parts->extra)) { /* if none of the above logic has merged "extra", do it now */ _mongoc_cmd_parts_ensure_copied (parts); } EXIT; } static void _mongoc_cmd_parts_assemble_mongod (mongoc_cmd_parts_t *parts, const mongoc_server_stream_t *server_stream) { ENTRY; if (!parts->is_write_command) { switch (server_stream->topology_type) { case MONGOC_TOPOLOGY_SINGLE: /* Server Selection Spec: for topology type single and server types * besides mongos, "clients MUST always set the secondaryOk wire * protocol flag on reads to ensure that any server type can handle * the request." */ parts->assembled.query_flags |= MONGOC_QUERY_SECONDARY_OK; break; case MONGOC_TOPOLOGY_RS_NO_PRIMARY: case MONGOC_TOPOLOGY_RS_WITH_PRIMARY: /* Server Selection Spec: for RS topology types, "For all read * preferences modes except primary, clients MUST set the secondaryOk * wire protocol flag to ensure that any suitable server can handle the * request. Clients MUST NOT set the secondaryOk wire protocol flag if * the read preference mode is primary. */ if (parts->read_prefs && parts->read_prefs->mode != MONGOC_READ_PRIMARY) { parts->assembled.query_flags |= MONGOC_QUERY_SECONDARY_OK; } break; case MONGOC_TOPOLOGY_SHARDED: case MONGOC_TOPOLOGY_UNKNOWN: case MONGOC_TOPOLOGY_LOAD_BALANCED: case MONGOC_TOPOLOGY_DESCRIPTION_TYPES: default: /* must not call this function w/ sharded, load balanced, or unknown * topology type */ BSON_ASSERT (false); } } /* if (!parts->is_write_command) */ if (!bson_empty (&parts->extra)) { _mongoc_cmd_parts_ensure_copied (parts); } if (!bson_empty (&parts->read_concern_document) && strcmp (parts->assembled.command_name, "getMore") != 0) { _mongoc_cmd_parts_ensure_copied (parts); bson_append_document (&parts->assembled_body, "readConcern", 11, &parts->read_concern_document); } _mongoc_cmd_parts_add_write_concern (parts); EXIT; } static const bson_t * _largest_cluster_time (const bson_t *a, const bson_t *b) { if (!a) { return b; } if (!b) { return a; } if (_mongoc_cluster_time_greater (a, b)) { return a; } return b; } /* Check if the command should allow a transaction number if that has not * already been determined. * * This should only return true for write commands that are always retryable for * the server stream's wire version. * * The basic write commands (i.e. insert, update, delete) are intentionally * excluded here. While insert is always retryable, update and delete are only * retryable if they include no multi-document writes. Since it would be costly * to inspect the command document here, the bulk operation API explicitly sets * allow_txn_number for us. This means that insert, update, and delete are not * retryable if executed via mongoc_client_write_command_with_opts(); however, * documentation already instructs users not to use that for basic writes. */ static bool _allow_txn_number (const mongoc_cmd_parts_t *parts, const mongoc_server_stream_t *server_stream) { /* There is no reason to call this function if allow_txn_number is set */ BSON_ASSERT (parts->allow_txn_number == MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_UNKNOWN); if (!parts->is_write_command) { return false; } if (server_stream->retry_attempted) { return false; } if (!parts->assembled.is_acknowledged) { return false; } if (!strcasecmp (parts->assembled.command_name, "findandmodify")) { return true; } return false; } /* Check if the write command should support retryable behavior. */ static bool _is_retryable_write (const mongoc_cmd_parts_t *parts, const mongoc_server_stream_t *server_stream) { if (!parts->assembled.session) { return false; } if (!parts->is_write_command) { return false; } if (parts->allow_txn_number != MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_YES) { return false; } if (server_stream->retry_attempted) { return false; } if (server_stream->sd->type == MONGOC_SERVER_STANDALONE) { return false; } if (_mongoc_client_session_in_txn (parts->assembled.session)) { return false; } if (!mongoc_uri_get_option_as_bool (parts->client->uri, MONGOC_URI_RETRYWRITES, MONGOC_DEFAULT_RETRYWRITES)) { return false; } return true; } /* Check if the read command should support retryable behavior. */ bool _is_retryable_read (const mongoc_cmd_parts_t *parts, const mongoc_server_stream_t *server_stream) { if (!parts->is_read_command) { return false; } /* Commands that go through read_write_command helpers are also write * commands. Prohibit from read retry. */ if (parts->is_write_command) { return false; } if (server_stream->retry_attempted) { return false; } if (_mongoc_client_session_in_txn (parts->assembled.session)) { return false; } if (!mongoc_uri_get_option_as_bool (parts->client->uri, MONGOC_URI_RETRYREADS, MONGOC_DEFAULT_RETRYREADS)) { return false; } return true; } /* *-------------------------------------------------------------------------- * * mongoc_cmd_parts_assemble -- * * Assemble the command body, options, and read preference into one * command. * * Return: * True if the options were successfully applied. If any options are * invalid, returns false and fills out @error. In that case @parts is * invalid and must not be used. * * Side effects: * May partly assemble before returning an error. * mongoc_cmd_parts_cleanup should be called in all cases. * *-------------------------------------------------------------------------- */ bool mongoc_cmd_parts_assemble (mongoc_cmd_parts_t *parts, mongoc_server_stream_t *server_stream, bson_error_t *error) { mongoc_server_description_type_t server_type; mongoc_client_session_t *cs; const bson_t *cluster_time = NULL; mongoc_read_prefs_t *prefs = NULL; const char *cmd_name; bool is_get_more; const mongoc_read_prefs_t *prefs_ptr; mongoc_read_mode_t mode; bool ret = false; ENTRY; BSON_ASSERT (parts); BSON_ASSERT (server_stream); server_type = server_stream->sd->type; cs = parts->prohibit_lsid ? NULL : parts->assembled.session; /* Assembling the command depends on the type of server. If the server has * been invalidated, error. */ if (server_type == MONGOC_SERVER_UNKNOWN) { if (error) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot assemble command for invalidated server: %s", server_stream->sd->error.message); } RETURN (false); } /* must not be assembled already */ BSON_ASSERT (!parts->assembled.command); BSON_ASSERT (bson_empty (&parts->assembled_body)); /* begin with raw flags/cmd as assembled flags/cmd, might change below */ parts->assembled.command = parts->body; /* unused in OP_MSG: */ parts->assembled.query_flags = parts->user_query_flags; parts->assembled.server_stream = server_stream; cmd_name = parts->assembled.command_name = _mongoc_get_command_name (parts->assembled.command); if (!parts->assembled.command_name) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Empty command document"); GOTO (done); } TRACE ("Preparing '%s'", cmd_name); is_get_more = !strcmp (cmd_name, "getMore"); parts->assembled.is_txn_finish = !strcmp (cmd_name, "commitTransaction") || !strcmp (cmd_name, "abortTransaction"); if (!parts->is_write_command && IS_PREF_PRIMARY (parts->read_prefs) && server_stream->topology_type == MONGOC_TOPOLOGY_SINGLE && server_type != MONGOC_SERVER_MONGOS) { prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY_PREFERRED); prefs_ptr = prefs; } else { prefs_ptr = parts->read_prefs; } mode = mongoc_read_prefs_get_mode (prefs_ptr); if (server_stream->must_use_primary) { /* Server selection may have overriden the read mode used to generate this * server stream. This has effects on the body of the message that we send * to the server */ mode = MONGOC_READ_PRIMARY; } if (mongoc_client_uses_server_api (parts->client) || mongoc_client_uses_loadbalanced (parts->client) || server_stream->sd->max_wire_version >= WIRE_VERSION_MIN) { if (!bson_has_field (parts->body, "$db")) { BSON_APPEND_UTF8 (&parts->extra, "$db", parts->assembled.db_name); } if (cs && _mongoc_client_session_in_txn (cs)) { if (!IS_PREF_PRIMARY (cs->txn.opts.read_prefs) && !parts->is_write_command) { bson_set_error (error, MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_TRANSACTION_INVALID_STATE, "Read preference in a transaction must be primary"); GOTO (done); } } else if (mode != MONGOC_READ_PRIMARY && server_type != MONGOC_SERVER_STANDALONE) { /* "Type Standalone: clients MUST NOT send the read preference to the * server" */ _mongoc_cmd_parts_add_read_prefs (&parts->extra, prefs_ptr); } if (!bson_empty (&parts->extra)) { _mongoc_cmd_parts_ensure_copied (parts); } /* If an explicit session was not provided and lsid is not prohibited, * attempt to create an implicit session (ignoring any errors). */ if (!cs && !parts->prohibit_lsid && parts->assembled.is_acknowledged) { cs = mongoc_client_start_session (parts->client, NULL, NULL); if (cs) { parts->assembled.session = cs; parts->has_temp_session = true; } } /* Driver Sessions Spec: "For unacknowledged writes with an explicit * session, drivers SHOULD raise an error.... Without an explicit * session, drivers SHOULD NOT use an implicit session." We intentionally * do not restrict this logic to parts->is_write_command, since * mongoc_client_command_with_opts() does not identify as a write * command but may still include a write concern. */ if (cs) { if (!parts->assembled.is_acknowledged) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot use client session with unacknowledged command"); GOTO (done); } _mongoc_cmd_parts_ensure_copied (parts); bson_append_document (&parts->assembled_body, "lsid", 4, mongoc_client_session_get_lsid (cs)); cs->server_session->last_used_usec = bson_get_monotonic_time (); cluster_time = mongoc_client_session_get_cluster_time (cs); } /* Ensure we know if the write command allows a transaction number */ if (!_mongoc_client_session_txn_in_progress (cs) && parts->is_write_command && parts->allow_txn_number == MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_UNKNOWN) { parts->allow_txn_number = _allow_txn_number (parts, server_stream) ? MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_YES : MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_NO; } /* Determine if the command is retryable. If so, append txnNumber now * for future use and mark the command as such. */ if (_is_retryable_write (parts, server_stream)) { _mongoc_cmd_parts_ensure_copied (parts); bson_append_int64 (&parts->assembled_body, "txnNumber", 9, 0); parts->is_retryable_write = true; } /* Conversely, check if the command is retryable if it is a read. */ if (_is_retryable_read (parts, server_stream) && !is_get_more) { parts->is_retryable_read = true; } if (!bson_empty (&server_stream->cluster_time)) { cluster_time = _largest_cluster_time (&server_stream->cluster_time, cluster_time); } if (cluster_time && server_type != MONGOC_SERVER_STANDALONE) { _mongoc_cmd_parts_ensure_copied (parts); bson_append_document (&parts->assembled_body, "$clusterTime", 12, cluster_time); } /* Add versioned server api, if it is set. */ if (mongoc_client_uses_server_api (parts->client)) { _mongoc_cmd_append_server_api (&parts->assembled_body, parts->client->api); } if (!is_get_more) { if (cs) { /* Snapshot Sessions Spec: "Snapshot reads require MongoDB 5.0+." * Throw an error if snapshot is enabled and wire version is less * than 13 before potentially appending "snapshot" read concern. */ if (mongoc_session_opts_get_snapshot (&cs->opts) && server_stream->sd->max_wire_version < WIRE_VERSION_SNAPSHOT_READS) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_SESSION_FAILURE, "Snapshot reads require MongoDB 5.0 or later"); GOTO (done); } _mongoc_cmd_parts_ensure_copied (parts); _mongoc_client_session_append_read_concern ( cs, &parts->read_concern_document, parts->is_read_command, &parts->assembled_body); } else if (!bson_empty (&parts->read_concern_document)) { _mongoc_cmd_parts_ensure_copied (parts); bson_append_document (&parts->assembled_body, "readConcern", 11, &parts->read_concern_document); } } /* if transaction is in progress do not inherit write concern */ if (parts->assembled.is_txn_finish || !_mongoc_client_session_in_txn (cs)) { _mongoc_cmd_parts_add_write_concern (parts); } _mongoc_cmd_parts_ensure_copied (parts); if (!_mongoc_client_session_append_txn (cs, &parts->assembled_body, error)) { GOTO (done); } ret = true; } else if (server_type == MONGOC_SERVER_MONGOS || server_stream->topology_type == MONGOC_TOPOLOGY_LOAD_BALANCED) { /* TODO (CDRIVER-4117) remove the check of the topology description type. */ _mongoc_cmd_parts_assemble_mongos (parts, server_stream); ret = true; } else { _mongoc_cmd_parts_assemble_mongod (parts, server_stream); ret = true; } done: mongoc_read_prefs_destroy (prefs); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_cmd_parts_cleanup -- * * Free memory associated with a stack-allocated mongoc_cmd_parts_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_cmd_parts_cleanup (mongoc_cmd_parts_t *parts) { bson_destroy (&parts->read_concern_document); bson_destroy (&parts->write_concern_document); bson_destroy (&parts->extra); bson_destroy (&parts->assembled_body); if (parts->has_temp_session) { /* client session returns its server session to server session pool */ mongoc_client_session_destroy (parts->assembled.session); } } bool mongoc_cmd_is_compressible (const mongoc_cmd_t *cmd) { BSON_ASSERT (cmd); BSON_ASSERT (cmd->command_name); return !!strcasecmp (cmd->command_name, "hello") && !!strcasecmp (cmd->command_name, HANDSHAKE_CMD_LEGACY_HELLO) && !!strcasecmp (cmd->command_name, "authenticate") && !!strcasecmp (cmd->command_name, "getnonce") && !!strcasecmp (cmd->command_name, "saslstart") && !!strcasecmp (cmd->command_name, "saslcontinue") && !!strcasecmp (cmd->command_name, "createuser") && !!strcasecmp (cmd->command_name, "updateuser"); } //`_mongoc_cmd_append_payload_as_array` appends document seqence payloads as BSON arrays. // `cmd` must contain one or more document sequence payloads (`cmd->payloads_count` > 0). // `out` must be initialized by the caller. // Used by APM and In-Use Encryption (document sequences are not supported for auto encryption). void _mongoc_cmd_append_payload_as_array (const mongoc_cmd_t *cmd, bson_t *out) { int32_t doc_len; bson_t doc; const uint8_t *pos; const char *field_name; bson_array_builder_t *bson; BSON_ASSERT (cmd->payloads_count > 0); BSON_ASSERT (cmd->payloads_count <= MONGOC_CMD_PAYLOADS_COUNT_MAX); for (size_t i = 0; i < cmd->payloads_count; i++) { BSON_ASSERT (cmd->payloads[i].documents && cmd->payloads[i].size); // Create a BSON array from a document sequence (OP_MSG Section with payloadType=1). field_name = cmd->payloads[i].identifier; BSON_ASSERT (field_name); BSON_ASSERT (BSON_APPEND_ARRAY_BUILDER_BEGIN (out, field_name, &bson)); pos = cmd->payloads[i].documents; while (pos < cmd->payloads[i].documents + cmd->payloads[i].size) { memcpy (&doc_len, pos, sizeof (doc_len)); doc_len = BSON_UINT32_FROM_LE (doc_len); BSON_ASSERT (bson_init_static (&doc, pos, (size_t) doc_len)); bson_array_builder_append_document (bson, &doc); pos += doc_len; } bson_append_array_builder_end (out, bson); } } /*-------------------------------------------------------------------------- * * _mongoc_cmd_append_server_api -- * Append versioned API fields to a mongoc_cmd_t * * Arguments: * cmd The mongoc_cmd_t, which will have versioned API fields added * api A mongoc_server_api_t holding server API information * * Pre-conditions: * - @api is initialized. * - @command_body is initialised * *-------------------------------------------------------------------------- */ void _mongoc_cmd_append_server_api (bson_t *command_body, const mongoc_server_api_t *api) { const char *string_version; BSON_ASSERT (command_body); BSON_ASSERT (api); string_version = mongoc_server_api_version_to_string (api->version); BSON_ASSERT (string_version); bson_append_utf8 (command_body, "apiVersion", -1, string_version, -1); if (api->strict.is_set) { bson_append_bool (command_body, "apiStrict", -1, api->strict.value); } if (api->deprecation_errors.is_set) { bson_append_bool (command_body, "apiDeprecationErrors", -1, api->deprecation_errors.value); } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-collection-private.h0000644000175100001660000000337414760300420024751 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_COLLECTION_PRIVATE_H #define MONGOC_COLLECTION_PRIVATE_H #include #include BSON_BEGIN_DECLS struct _mongoc_collection_t { mongoc_client_t *client; char *ns; uint32_t nslen; char *db; char *collection; uint32_t collectionlen; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; bson_t *gle; }; mongoc_collection_t * _mongoc_collection_new (mongoc_client_t *client, const char *db, const char *collection, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern); bool _mongoc_collection_create_index_if_not_exists (mongoc_collection_t *collection, const bson_t *keys, const bson_t *opts, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_COLLECTION_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-collection.c0000644000175100001660000034463714760300420023306 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // BEGIN_IGNORE_DEPRECATIONS #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "collection" static void _mongoc_collection_write_command_execute (mongoc_write_command_t *command, const mongoc_collection_t *collection, const mongoc_write_concern_t *write_concern, mongoc_client_session_t *cs, mongoc_write_result_t *result) { mongoc_server_stream_t *server_stream; ENTRY; const mongoc_ss_log_context_t ss_log_context = {.operation = _mongoc_write_command_get_name (command), .has_operation_id = true, .operation_id = command->operation_id}; server_stream = mongoc_cluster_stream_for_writes (&collection->client->cluster, &ss_log_context, cs, NULL, NULL, &result->error); if (!server_stream) { /* result->error has been filled out */ EXIT; } _mongoc_write_command_execute (command, collection->client, server_stream, collection->db, collection->collection, write_concern, 0 /* offset */, cs, result); mongoc_server_stream_cleanup (server_stream); EXIT; } static void _mongoc_collection_write_command_execute_idl (mongoc_write_command_t *command, const mongoc_collection_t *collection, mongoc_crud_opts_t *crud, mongoc_write_result_t *result) { mongoc_server_stream_t *server_stream; bson_t reply; ENTRY; const mongoc_ss_log_context_t ss_log_context = {.operation = _mongoc_write_command_get_name (command), .has_operation_id = true, .operation_id = command->operation_id}; server_stream = mongoc_cluster_stream_for_writes ( &collection->client->cluster, &ss_log_context, crud->client_session, NULL, &reply, &result->error); if (!server_stream) { /* result->error and reply have been filled out */ _mongoc_bson_array_copy_labels_to (&reply, &result->errorLabels); bson_destroy (&reply); EXIT; } if (_mongoc_client_session_in_txn (crud->client_session) && crud->writeConcern) { bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set write concern after starting transaction"); mongoc_server_stream_cleanup (server_stream); EXIT; } if (!crud->writeConcern && !_mongoc_client_session_in_txn (crud->client_session)) { crud->writeConcern = collection->write_concern; crud->write_concern_owned = false; } _mongoc_write_command_execute_idl ( command, collection->client, server_stream, collection->db, collection->collection, 0 /* offset */, crud, result); mongoc_server_stream_cleanup (server_stream); EXIT; } /* *-------------------------------------------------------------------------- * * _mongoc_collection_new -- * * INTERNAL API * * Create a new mongoc_collection_t structure for the given client. * * @client must remain valid during the lifetime of this structure. * @db is the db name of the collection. * @collection is the name of the collection. * @read_prefs is the default read preferences to apply or NULL. * @read_concern is the default read concern to apply or NULL. * @write_concern is the default write concern to apply or NULL. * * Returns: * A newly allocated mongoc_collection_t that should be freed with * mongoc_collection_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_collection_t * _mongoc_collection_new (mongoc_client_t *client, const char *db, const char *collection, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern) { mongoc_collection_t *col; ENTRY; BSON_ASSERT_PARAM (client); BSON_ASSERT_PARAM (db); BSON_ASSERT_PARAM (collection); col = (mongoc_collection_t *) bson_malloc0 (sizeof *col); col->client = client; col->write_concern = write_concern ? mongoc_write_concern_copy (write_concern) : mongoc_write_concern_new (); col->read_concern = read_concern ? mongoc_read_concern_copy (read_concern) : mongoc_read_concern_new (); col->read_prefs = read_prefs ? mongoc_read_prefs_copy (read_prefs) : mongoc_read_prefs_new (MONGOC_READ_PRIMARY); col->ns = bson_strdup_printf ("%s.%s", db, collection); col->db = bson_strdup (db); col->collection = bson_strdup (collection); col->collectionlen = (uint32_t) strlen (col->collection); col->nslen = (uint32_t) strlen (col->ns); col->gle = NULL; RETURN (col); } /* *-------------------------------------------------------------------------- * * mongoc_collection_destroy -- * * Release resources associated with @collection and frees the * structure. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_collection_destroy (mongoc_collection_t *collection) /* IN */ { ENTRY; if (!collection) { EXIT; } bson_clear (&collection->gle); if (collection->read_prefs) { mongoc_read_prefs_destroy (collection->read_prefs); collection->read_prefs = NULL; } if (collection->read_concern) { mongoc_read_concern_destroy (collection->read_concern); collection->read_concern = NULL; } if (collection->write_concern) { mongoc_write_concern_destroy (collection->write_concern); collection->write_concern = NULL; } bson_free (collection->collection); bson_free (collection->db); bson_free (collection->ns); bson_free (collection); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_collection_copy -- * * Returns a copy of @collection that needs to be freed by calling * mongoc_collection_destroy. * * Returns: * A copy of this collection. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_collection_t * mongoc_collection_copy (mongoc_collection_t *collection) /* IN */ { ENTRY; BSON_ASSERT_PARAM (collection); RETURN (_mongoc_collection_new (collection->client, collection->db, collection->collection, collection->read_prefs, collection->read_concern, collection->write_concern)); } mongoc_cursor_t * mongoc_collection_aggregate (mongoc_collection_t *collection, /* IN */ mongoc_query_flags_t flags, /* IN */ const bson_t *pipeline, /* IN */ const bson_t *opts, /* IN */ const mongoc_read_prefs_t *read_prefs) /* IN */ { return _mongoc_aggregate (collection->client, collection->ns, flags, pipeline, opts, read_prefs, collection->read_prefs, collection->read_concern, collection->write_concern); } /* *-------------------------------------------------------------------------- * * mongoc_collection_find -- * * DEPRECATED: use mongoc_collection_find_with_opts. * * Performs a query against the configured MongoDB server. If @read_prefs * is provided, it will be used to locate a MongoDB node in the cluster * to deliver the query to. * * @flags may be bitwise-or'd flags or MONGOC_QUERY_NONE. * * @skip may contain the number of documents to skip before returning the * matching document. * * @limit may contain the maximum number of documents that may be * returned. * * This function will always return a cursor, with the exception of * invalid API use. * * Parameters: * @collection: A mongoc_collection_t. * @flags: A bitwise or of mongoc_query_flags_t. * @skip: The number of documents to skip. * @limit: The maximum number of items. * @batch_size: The batch size * @query: The query to locate matching documents. * @fields: The fields to return, or NULL for all fields. * @read_prefs: Read preferences to choose cluster node. * * Returns: * A newly allocated mongoc_cursor_t that should be freed with * mongoc_cursor_destroy(). * * The client used by mongoc_collection_t must be valid for the * lifetime of the resulting mongoc_cursor_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_cursor_t * mongoc_collection_find (mongoc_collection_t *collection, /* IN */ mongoc_query_flags_t flags, /* IN */ uint32_t skip, /* IN */ uint32_t limit, /* IN */ uint32_t batch_size, /* IN */ const bson_t *query, /* IN */ const bson_t *fields, /* IN */ const mongoc_read_prefs_t *read_prefs) /* IN */ { bool has_unwrapped; bson_t unwrapped; bson_error_t error = {0}; bson_t opts; bool secondary_ok; mongoc_cursor_t *cursor; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (query); bson_clear (&collection->gle); bson_init (&opts); _mongoc_cursor_flags_to_opts (flags, &opts, &secondary_ok); /* check if the query is wrapped in $query */ has_unwrapped = _mongoc_cursor_translate_dollar_query_opts (query, &opts, &unwrapped, &error); if (!bson_empty0 (fields)) { bson_append_document (&opts, MONGOC_CURSOR_PROJECTION, MONGOC_CURSOR_PROJECTION_LEN, fields); } cursor = _mongoc_cursor_find_new (collection->client, collection->ns, has_unwrapped ? &unwrapped : query, &opts, read_prefs, collection->read_prefs, collection->read_concern); if (skip) { _mongoc_cursor_set_opt_int64 (cursor, MONGOC_CURSOR_SKIP, skip); } if (limit) { /* limit must be cast to int32_t. Although the argument is a uint32_t, * callers can specify a negative limit by casting to a signed int32_t * value to uint32_t. E.g. to set a limit of -4, the caller passes * UINT32_MAX - 3 */ (void) mongoc_cursor_set_limit (cursor, (int32_t) limit); } if (batch_size) { mongoc_cursor_set_batch_size (cursor, batch_size); } bson_destroy (&unwrapped); bson_destroy (&opts); if (error.domain) { memcpy (&cursor->error, &error, sizeof (error)); } return cursor; } /* *-------------------------------------------------------------------------- * * mongoc_collection_find_with_opts -- * * Create a cursor with a query filter. All other options are * specified in a free-form BSON document. * * Parameters: * @collection: A mongoc_collection_t. * @filter: The query to locate matching documents. * @opts: Other options. * @read_prefs: Optional read preferences to choose cluster node. * * Returns: * A newly allocated mongoc_cursor_t that should be freed with * mongoc_cursor_destroy(). * * The client used by mongoc_collection_t must be valid for the * lifetime of the resulting mongoc_cursor_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_cursor_t * mongoc_collection_find_with_opts (mongoc_collection_t *collection, const bson_t *filter, const bson_t *opts, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (filter); bson_clear (&collection->gle); return _mongoc_cursor_find_new ( collection->client, collection->ns, filter, opts, read_prefs, collection->read_prefs, collection->read_concern); } /* *-------------------------------------------------------------------------- * * mongoc_collection_command -- * * Executes a command on a cluster node matching @read_prefs. If * @read_prefs is not provided, it will be run on the primary node. * * This function will always return a mongoc_cursor_t. * * Parameters: * @collection: A mongoc_collection_t. * @flags: Bitwise-or'd flags for command. * @skip: Number of documents to skip, typically 0. * @limit : Number of documents to return * @batch_size : Batch size * @query: The command to execute. * @fields: The fields to return, or NULL. * @read_prefs: Command read preferences or NULL. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_cursor_t * mongoc_collection_command (mongoc_collection_t *collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { char *ns; mongoc_cursor_t *cursor; BSON_UNUSED (flags); BSON_UNUSED (skip); BSON_UNUSED (limit); BSON_UNUSED (batch_size); BSON_UNUSED (fields); BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (query); if (!read_prefs) { read_prefs = collection->read_prefs; } bson_clear (&collection->gle); if (NULL == strstr (collection->collection, "$cmd")) { ns = bson_strdup_printf ("%s.$cmd", collection->db); } else { ns = bson_strdup (collection->db); } /* Server Selection Spec: "The generic command method has a default read * preference of mode 'primary'. The generic command method MUST ignore any * default read preference from client, database or collection * configuration. The generic command method SHOULD allow an optional read * preference argument." */ /* flags, skip, limit, batch_size, fields are unused */ cursor = _mongoc_cursor_cmd_deprecated_new (collection->client, ns, query, read_prefs); bson_free (ns); return cursor; } bool mongoc_collection_read_command_with_opts (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (collection); return _mongoc_client_command_with_opts (collection->client, collection->db, command, MONGOC_CMD_READ, opts, MONGOC_QUERY_NONE, read_prefs, collection->read_prefs, collection->read_concern, collection->write_concern, reply, error); } bool mongoc_collection_write_command_with_opts ( mongoc_collection_t *collection, const bson_t *command, const bson_t *opts, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (collection); return _mongoc_client_command_with_opts (collection->client, collection->db, command, MONGOC_CMD_WRITE, opts, MONGOC_QUERY_NONE, NULL, collection->read_prefs, collection->read_concern, collection->write_concern, reply, error); } bool mongoc_collection_read_write_command_with_opts (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs /* IGNORED */, const bson_t *opts, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (collection); return _mongoc_client_command_with_opts (collection->client, collection->db, command, MONGOC_CMD_RW, opts, MONGOC_QUERY_NONE, read_prefs, collection->read_prefs, collection->read_concern, collection->write_concern, reply, error); } bool mongoc_collection_command_with_opts (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (collection); /* Server Selection Spec: "The generic command method has a default read * preference of mode 'primary'. The generic command method MUST ignore any * default read preference from client, database or collection * configuration. The generic command method SHOULD allow an optional read * preference argument." */ return _mongoc_client_command_with_opts (collection->client, collection->db, command, MONGOC_CMD_RAW, opts, MONGOC_QUERY_NONE, read_prefs, NULL /* default prefs */, collection->read_concern, collection->write_concern, reply, error); } bool mongoc_collection_command_simple (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (command); bson_clear (&collection->gle); /* Server Selection Spec: "The generic command method has a default read * preference of mode 'primary'. The generic command method MUST ignore any * default read preference from client, database or collection * configuration. The generic command method SHOULD allow an optional read * preference argument." */ return _mongoc_client_command_with_opts (collection->client, collection->db, command, MONGOC_CMD_RAW, NULL /* opts */, MONGOC_QUERY_NONE, read_prefs, NULL /* default prefs */, NULL /* read concern */, NULL /* write concern */, reply, error); } /* *-------------------------------------------------------------------------- * * mongoc_collection_count -- * * Count the number of documents matching @query. * * Parameters: * @flags: A mongoc_query_flags_t describing the query flags or 0. * @query: The query to perform or NULL for {}. * @skip: The $skip to perform within the query or 0. * @limit: The $limit to perform within the query or 0. * @read_prefs: desired read preferences or NULL. * @error: A location for an error or NULL. * * Returns: * -1 on failure; otherwise the number of matching documents. * * Side effects: * @error is set upon failure if non-NULL. * *-------------------------------------------------------------------------- */ int64_t mongoc_collection_count (mongoc_collection_t *collection, /* IN */ mongoc_query_flags_t flags, /* IN */ const bson_t *query, /* IN */ int64_t skip, /* IN */ int64_t limit, /* IN */ const mongoc_read_prefs_t *read_prefs, /* IN */ bson_error_t *error) /* OUT */ { int64_t ret; bson_t opts = BSON_INITIALIZER; /* Complex types must be parts of `opts`, otherwise we can't * follow various specs that require validation etc */ if (collection->read_concern->level != NULL) { const bson_t *read_concern_bson; read_concern_bson = _mongoc_read_concern_get_bson (collection->read_concern); BSON_APPEND_DOCUMENT (&opts, "readConcern", read_concern_bson); } /* Server Selection Spec: "may-use-secondary" commands SHOULD take a read * preference argument and otherwise MUST use the default read preference * from client, database or collection configuration. */ BEGIN_IGNORE_DEPRECATIONS ret = mongoc_collection_count_with_opts (collection, flags, query, skip, limit, &opts, read_prefs, error); END_IGNORE_DEPRECATIONS bson_destroy (&opts); return ret; } int64_t mongoc_collection_count_with_opts (mongoc_collection_t *collection, /* IN */ mongoc_query_flags_t flags, /* IN */ const bson_t *query, /* IN */ int64_t skip, /* IN */ int64_t limit, /* IN */ const bson_t *opts, /* IN */ const mongoc_read_prefs_t *read_prefs, /* IN */ bson_error_t *error) /* OUT */ { bson_iter_t iter; int64_t ret = -1; bool success; bson_t reply; bson_t cmd = BSON_INITIALIZER; ENTRY; BSON_ASSERT_PARAM (collection); bsonBuildAppend (cmd, kv ("count", utf8_w_len (collection->collection, collection->collectionlen)), kv ("query", if (query, // If we have a query, then (bson (*query)), // Copy it else (doc ()))), // Otherwise, add an empty doc if (limit, then (kv ("limit", int64 (limit)))), if (skip, then (kv ("skip", int64 (skip))))); success = _mongoc_client_command_with_opts (collection->client, collection->db, &cmd, MONGOC_CMD_READ, opts, flags, read_prefs, collection->read_prefs, collection->read_concern, collection->write_concern, &reply, error); if (success) { if (bson_iter_init_find (&iter, &reply, "n")) { ret = bson_iter_as_int64 (&iter); } } bson_destroy (&reply); bson_destroy (&cmd); RETURN (ret); } int64_t mongoc_collection_estimated_document_count (mongoc_collection_t *coll, const bson_t *opts, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) { ENTRY; BSON_ASSERT_PARAM (coll); // No sessionId allowed if (opts && bson_has_field (opts, "sessionId")) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Collection count must not specify explicit session"); RETURN (-1); } // Storage for the reply if no storage was given by caller bson_t reply_local = BSON_INITIALIZER; // Write the reply to either the caller's storage or a local variable bson_t *const reply_ptr = reply ? reply : &reply_local; // Create and execute a "count" command bsonBuildDecl (cmd, kv ("count", cstr (coll->collection))); const bool command_ok = _mongoc_client_command_with_opts (coll->client, coll->db, &cmd, MONGOC_CMD_READ, opts, MONGOC_QUERY_NONE, read_prefs, coll->read_prefs, coll->read_concern, coll->write_concern, reply_ptr, error); bson_destroy (&cmd); // Extract the "n" field from the response int64_t ret_count = -1; if (command_ok) { bsonParse (*reply_ptr, find (key ("n"), do (ret_count = bson_iter_as_int64 (&bsonVisitIter)))); } // Destroy the local storage. This is a no-op if we used the caller's storage. bson_destroy (&reply_local); RETURN (ret_count); } /* -------------------------------------------------------------------------- * * _make_aggregate_for_count -- * * Construct an aggregate pipeline with the following form: * { pipeline: [ * { $match: {...} }, * { $group: { _id: 1, n: { sum: 1 } } }, * { $skip: ... }, * { $limit: ... } * ] * } * *-------------------------------------------------------------------------- */ static void _make_aggregate_for_count (const mongoc_collection_t *coll, const bson_t *filter, mongoc_count_document_opts_t *opts, bson_t *out) { bson_array_builder_t *pipeline; bson_t match_stage; bson_t group_stage; bson_t group_stage_doc; bson_t sum; bson_t empty; bson_init (out); bson_append_utf8 (out, "aggregate", 9, coll->collection, coll->collectionlen); bson_append_document_begin (out, "cursor", 6, &empty); bson_append_document_end (out, &empty); bson_append_array_builder_begin (out, "pipeline", 8, &pipeline); bson_array_builder_append_document_begin (pipeline, &match_stage); bson_append_document (&match_stage, "$match", 6, filter); bson_array_builder_append_document_end (pipeline, &match_stage); /* if @opts includes "skip", or "limit", append $skip and $limit stages to * the aggregate pipeline. */ if (opts->skip.value_type != BSON_TYPE_EOD) { bson_t skip_stage; bson_array_builder_append_document_begin (pipeline, &skip_stage); bson_append_value (&skip_stage, "$skip", 5, &opts->skip); bson_array_builder_append_document_end (pipeline, &skip_stage); } if (opts->limit.value_type != BSON_TYPE_EOD) { bson_t limit_stage; bson_array_builder_append_document_begin (pipeline, &limit_stage); bson_append_value (&limit_stage, "$limit", 6, &opts->limit); bson_array_builder_append_document_end (pipeline, &limit_stage); } bson_array_builder_append_document_begin (pipeline, &group_stage); bson_append_document_begin (&group_stage, "$group", 6, &group_stage_doc); bson_append_int32 (&group_stage_doc, "_id", 3, 1); bson_append_document_begin (&group_stage_doc, "n", 1, &sum); bson_append_int32 (&sum, "$sum", 4, 1); bson_append_document_end (&group_stage_doc, &sum); bson_append_document_end (&group_stage, &group_stage_doc); bson_array_builder_append_document_end (pipeline, &group_stage); bson_append_array_builder_end (out, pipeline); } int64_t mongoc_collection_count_documents (mongoc_collection_t *coll, const bson_t *filter, const bson_t *opts, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) { bson_t aggregate_cmd; bson_t aggregate_opts; bool ret; const bson_t *result; mongoc_cursor_t *cursor = NULL; int64_t count = -1; bson_t cmd_reply; bson_iter_t iter; ENTRY; BSON_ASSERT_PARAM (coll); BSON_ASSERT_PARAM (filter); // Parse options to validate. mongoc_count_document_opts_t cd_opts; if (!_mongoc_count_document_opts_parse (coll->client, opts, &cd_opts, error)) { GOTO (done); } _make_aggregate_for_count (coll, filter, &cd_opts, &aggregate_cmd); bson_init (&aggregate_opts); if (opts) { bsonBuildAppend (aggregate_opts, insert (*opts, not(key ("skip", "limit")))); } ret = mongoc_collection_read_command_with_opts (coll, &aggregate_cmd, read_prefs, &aggregate_opts, &cmd_reply, error); bson_destroy (&aggregate_cmd); bson_destroy (&aggregate_opts); if (reply) { bson_copy_to (&cmd_reply, reply); } if (!ret) { bson_destroy (&cmd_reply); GOTO (done); } /* steals reply */ cursor = mongoc_cursor_new_from_command_reply_with_opts (coll->client, &cmd_reply, NULL); BSON_ASSERT (mongoc_cursor_get_id (cursor) == 0); ret = mongoc_cursor_next (cursor, &result); if (!ret) { if (mongoc_cursor_error (cursor, error)) { GOTO (done); } else { count = 0; GOTO (done); } } if (bson_iter_init_find (&iter, result, "n") && BSON_ITER_HOLDS_INT (&iter)) { count = bson_iter_as_int64 (&iter); } done: _mongoc_count_document_opts_cleanup (&cd_opts); if (cursor) { mongoc_cursor_destroy (cursor); } RETURN (count); } /* *-------------------------------------------------------------------------- * * mongoc_collection_drop -- * * Request the MongoDB server drop the collection. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error is set upon failure. * *-------------------------------------------------------------------------- */ bool mongoc_collection_drop (mongoc_collection_t *collection, /* IN */ bson_error_t *error) /* OUT */ { return mongoc_collection_drop_with_opts (collection, NULL, error); } static bool drop_with_opts (mongoc_collection_t *collection, const bson_t *opts, bson_error_t *error) { bool ret; bson_t cmd; BSON_ASSERT_PARAM (collection); bson_init (&cmd); bson_append_utf8 (&cmd, "drop", 4, collection->collection, collection->collectionlen); ret = _mongoc_client_command_with_opts (collection->client, collection->db, &cmd, MONGOC_CMD_WRITE, opts, MONGOC_QUERY_NONE, NULL, /* user prefs */ collection->read_prefs, collection->read_concern, collection->write_concern, NULL, /* reply */ error); bson_destroy (&cmd); return ret; } static bool drop_with_opts_with_encryptedFields (mongoc_collection_t *collection, const bson_t *opts, const bson_t *encryptedFields, bson_error_t *error) { char *escName = NULL; char *ecocName = NULL; mongoc_collection_t *escCollection = NULL; mongoc_collection_t *ecocCollection = NULL; bool ok = false; const char *name = mongoc_collection_get_name (collection); bson_error_t local_error = {0}; if (!error) { /* If no error is passed, use a local error. Error codes are checked * when collections are dropped. */ error = &local_error; } /* Drop ESC collection. */ escName = _mongoc_get_encryptedField_state_collection (encryptedFields, name, "esc", error); if (!escName) { goto fail; } escCollection = mongoc_client_get_collection (collection->client, collection->db, escName); if (!drop_with_opts (escCollection, NULL /* opts */, error)) { if (error->code == MONGOC_SERVER_ERR_NS_NOT_FOUND) { memset (error, 0, sizeof (bson_error_t)); } else { goto fail; } } /* Drop ECOC collection. */ ecocName = _mongoc_get_encryptedField_state_collection (encryptedFields, name, "ecoc", error); if (!ecocName) { goto fail; } ecocCollection = mongoc_client_get_collection (collection->client, collection->db, ecocName); if (!drop_with_opts (ecocCollection, NULL /* opts */, error)) { if (error->code == MONGOC_SERVER_ERR_NS_NOT_FOUND) { memset (error, 0, sizeof (bson_error_t)); } else { goto fail; } } /* Drop data collection. */ if (!drop_with_opts (collection, opts, error)) { if (error->code == MONGOC_SERVER_ERR_NS_NOT_FOUND) { memset (error, 0, sizeof (bson_error_t)); } else { goto fail; } } ok = true; fail: mongoc_collection_destroy (ecocCollection); bson_free (ecocName); mongoc_collection_destroy (escCollection); bson_free (escName); return ok; } bool mongoc_collection_drop_with_opts (mongoc_collection_t *collection, const bson_t *opts, bson_error_t *error) { // The encryptedFields for the collection. bson_t encryptedFields = BSON_INITIALIZER; bson_t opts_without_encryptedFields = BSON_INITIALIZER; bool okay = false; // Try to find the encryptedFields from the collection options or from the // encryptedFieldsMap. if (!_mongoc_get_collection_encryptedFields (collection->client, collection->db, mongoc_collection_get_name (collection), opts, true /* checkEncryptedFieldsMap */, &encryptedFields, error)) { goto done; } if (bson_empty (&encryptedFields)) { // We didn't find the encryptedFields (yet) if (collection->client->topology->encrypted_fields_map != NULL) { // but we can ask the server for them: if (!_mongoc_get_encryptedFields_from_server ( collection->client, collection->db, mongoc_collection_get_name (collection), &encryptedFields, error)) { goto done; } } } if (bson_empty (&encryptedFields)) { // There are no encryptedFields with this collection, so we can just do a // regular drop okay = drop_with_opts (collection, opts, error); goto done; } // We've found the encryptedFields, so we need to do something different // to drop this collection: bsonBuildAppend (opts_without_encryptedFields, if (opts, then (insert (*opts, not(key ("encryptedFields")))))); if (bsonBuildError) { bson_set_error ( error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Error while updating drop options: %s", bsonBuildError); goto done; } okay = drop_with_opts_with_encryptedFields (collection, &opts_without_encryptedFields, &encryptedFields, error); done: bson_destroy (&opts_without_encryptedFields); bson_destroy (&encryptedFields); return okay; } /* *-------------------------------------------------------------------------- * * mongoc_collection_drop_index -- * * Request the MongoDB server drop the named index. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error is setup upon failure if non-NULL. * *-------------------------------------------------------------------------- */ bool mongoc_collection_drop_index (mongoc_collection_t *collection, /* IN */ const char *index_name, /* IN */ bson_error_t *error) /* OUT */ { return mongoc_collection_drop_index_with_opts (collection, index_name, NULL, error); } bool mongoc_collection_drop_index_with_opts (mongoc_collection_t *collection, const char *index_name, const bson_t *opts, bson_error_t *error) { bool ret; bson_t cmd; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (index_name); bson_init (&cmd); bson_append_utf8 (&cmd, "dropIndexes", -1, collection->collection, collection->collectionlen); bson_append_utf8 (&cmd, "index", -1, index_name, -1); ret = _mongoc_client_command_with_opts (collection->client, collection->db, &cmd, MONGOC_CMD_WRITE, opts, MONGOC_QUERY_NONE, NULL, /* user prefs */ collection->read_prefs, collection->read_concern, collection->write_concern, NULL, /* reply */ error); bson_destroy (&cmd); return ret; } char * mongoc_collection_keys_to_index_string (const bson_t *keys) { mcommon_string_append_t append; bson_iter_t iter; bson_type_t type; int i = 0; BSON_ASSERT_PARAM (keys); if (!bson_iter_init (&iter, keys)) { return NULL; } mcommon_string_new_as_append (&append); while (bson_iter_next (&iter)) { /* Index type can be specified as a string ("2d") or as an integer * representing direction */ type = bson_iter_type (&iter); if (type == BSON_TYPE_UTF8) { mcommon_string_append_printf ( &append, (i++ ? "_%s_%s" : "%s_%s"), bson_iter_key (&iter), bson_iter_utf8 (&iter, NULL)); } else if (type == BSON_TYPE_INT32) { mcommon_string_append_printf ( &append, (i++ ? "_%s_%d" : "%s_%d"), bson_iter_key (&iter), bson_iter_int32 (&iter)); } else if (type == BSON_TYPE_INT64) { mcommon_string_append_printf ( &append, (i++ ? "_%s_%" PRId64 : "%s_%" PRId64), bson_iter_key (&iter), bson_iter_int64 (&iter)); } else { mcommon_string_from_append_destroy (&append); return NULL; } } return mcommon_string_from_append_destroy_with_steal (&append); } bool mongoc_collection_create_index (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error) { bson_t reply; bool ret; BEGIN_IGNORE_DEPRECATIONS ret = mongoc_collection_create_index_with_opts (collection, keys, opt, NULL, &reply, error); END_IGNORE_DEPRECATIONS bson_destroy (&reply); return ret; } static bool _mongoc_collection_index_keys_equal (const bson_t *expected, const bson_t *actual) { bson_iter_t iter_expected; bson_iter_t iter_actual; bson_iter_init (&iter_expected, expected); bson_iter_init (&iter_actual, actual); while (bson_iter_next (&iter_expected)) { /* If the key document has fewer items than expected, indexes are unequal */ if (!bson_iter_next (&iter_actual)) { return false; } /* If key order does not match, indexes are unequal */ if (strcmp (bson_iter_key (&iter_expected), bson_iter_key (&iter_actual)) != 0) { return false; } if (BSON_ITER_HOLDS_NUMBER (&iter_expected) && BSON_ITER_HOLDS_NUMBER (&iter_actual)) { if (bson_iter_as_int64 (&iter_expected) != bson_iter_as_int64 (&iter_actual)) { return false; } } else if (BSON_ITER_HOLDS_UTF8 (&iter_expected) && BSON_ITER_HOLDS_UTF8 (&iter_actual)) { if (strcmp (bson_iter_utf8 (&iter_expected, NULL), bson_iter_utf8 (&iter_actual, NULL)) != 0) { return false; } } else { return false; } } /* If our expected document is exhausted, make sure there are no extra keys * in the actual key document */ if (bson_iter_next (&iter_actual)) { return false; } return true; } bool _mongoc_collection_create_index_if_not_exists (mongoc_collection_t *collection, const bson_t *keys, const bson_t *opts, bson_error_t *error) { mongoc_cursor_t *cursor; bool index_exists; bool r = false; const bson_t *doc; bson_iter_t iter; bson_t inner_doc; uint32_t data_len; const uint8_t *data; bson_t index; bson_t command; BSON_ASSERT (collection); BSON_ASSERT (keys); cursor = mongoc_collection_find_indexes_with_opts (collection, NULL); index_exists = false; while (mongoc_cursor_next (cursor, &doc) && !index_exists) { r = bson_iter_init_find (&iter, doc, "key"); if (!r) { continue; } bson_iter_document (&iter, &data_len, &data); BSON_ASSERT (bson_init_static (&inner_doc, data, data_len)); if (_mongoc_collection_index_keys_equal (keys, &inner_doc)) { index_exists = true; } bson_destroy (&inner_doc); } if (mongoc_cursor_error (cursor, error)) { mongoc_cursor_destroy (cursor); return false; } mongoc_cursor_destroy (cursor); if (index_exists) { return true; } if (opts) { bson_copy_to (opts, &index); } else { bson_init (&index); } BSON_APPEND_DOCUMENT (&index, "key", keys); if (!bson_has_field (&index, "name")) { char *alloc_name = mongoc_collection_keys_to_index_string (keys); if (!alloc_name) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Cannot generate index name from invalid `keys` argument"); GOTO (done); } BSON_APPEND_UTF8 (&index, "name", alloc_name); bson_free (alloc_name); } bson_init (&command); BCON_APPEND (&command, "createIndexes", BCON_UTF8 (mongoc_collection_get_name (collection)), "indexes", "[", BCON_DOCUMENT (&index), "]"); r = mongoc_collection_write_command_with_opts (collection, &command, NULL, NULL, error); done: bson_destroy (&index); bson_destroy (&command); return r; } bool mongoc_collection_create_index_with_opts (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, const bson_t *opts, bson_t *reply, bson_error_t *error) { mongoc_create_index_opts_t parsed; mongoc_cmd_parts_t parts; const mongoc_index_opt_t *def_opt; const mongoc_index_opt_geo_t *def_geo; const char *name; bson_t cmd = BSON_INITIALIZER; bson_array_builder_t *ar; bson_t doc; bson_t storage_doc; bson_t wt_doc; const mongoc_index_opt_geo_t *geo_opt; const mongoc_index_opt_storage_t *storage_opt; const mongoc_index_opt_wt_t *wt_opt; char *alloc_name = NULL; bool ret = false; bool reply_initialized = false; mongoc_server_stream_t *server_stream = NULL; mongoc_cluster_t *cluster; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (keys); def_opt = mongoc_index_opt_get_default (); opt = opt ? opt : def_opt; mongoc_cmd_parts_init (&parts, collection->client, collection->db, MONGOC_QUERY_NONE, &cmd); parts.is_write_command = true; if (!_mongoc_create_index_opts_parse (collection->client, opts, &parsed, error)) { GOTO (done); } if (!parsed.writeConcern) { parsed.writeConcern = collection->write_concern; parsed.write_concern_owned = false; } /* * Generate the key name if it was not provided. */ name = (opt->name != def_opt->name) ? opt->name : NULL; if (!name) { alloc_name = mongoc_collection_keys_to_index_string (keys); if (alloc_name) { name = alloc_name; } else { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Cannot generate index name from invalid `keys` argument"); GOTO (done); } } /* * Build our createIndexes command to send to the server. */ BSON_ASSERT (BSON_APPEND_UTF8 (&cmd, "createIndexes", collection->collection)); bson_append_array_builder_begin (&cmd, "indexes", 7, &ar); bson_array_builder_append_document_begin (ar, &doc); BSON_ASSERT (BSON_APPEND_DOCUMENT (&doc, "key", keys)); BSON_ASSERT (BSON_APPEND_UTF8 (&doc, "name", name)); if (opt->background) { BSON_ASSERT (BSON_APPEND_BOOL (&doc, "background", true)); } if (opt->unique) { BSON_ASSERT (BSON_APPEND_BOOL (&doc, "unique", true)); } if (opt->drop_dups) { BSON_ASSERT (BSON_APPEND_BOOL (&doc, "dropDups", true)); } if (opt->sparse) { BSON_ASSERT (BSON_APPEND_BOOL (&doc, "sparse", true)); } if (opt->expire_after_seconds != def_opt->expire_after_seconds) { BSON_ASSERT (BSON_APPEND_INT32 (&doc, "expireAfterSeconds", opt->expire_after_seconds)); } if (opt->v != def_opt->v) { BSON_ASSERT (BSON_APPEND_INT32 (&doc, "v", opt->v)); } if (opt->weights && (opt->weights != def_opt->weights)) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&doc, "weights", opt->weights)); } if (opt->default_language != def_opt->default_language) { BSON_ASSERT (BSON_APPEND_UTF8 (&doc, "default_language", opt->default_language)); } if (opt->language_override != def_opt->language_override) { BSON_ASSERT (BSON_APPEND_UTF8 (&doc, "language_override", opt->language_override)); } if (opt->partial_filter_expression) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&doc, "partialFilterExpression", opt->partial_filter_expression)); } if (opt->collation) { BSON_ASSERT (BSON_APPEND_DOCUMENT (&doc, "collation", opt->collation)); } if (opt->geo_options) { geo_opt = opt->geo_options; def_geo = mongoc_index_opt_geo_get_default (); if (geo_opt->twod_sphere_version != def_geo->twod_sphere_version) { BSON_ASSERT (BSON_APPEND_INT32 (&doc, "2dsphereIndexVersion", geo_opt->twod_sphere_version)); } if (geo_opt->twod_bits_precision != def_geo->twod_bits_precision) { BSON_ASSERT (BSON_APPEND_INT32 (&doc, "bits", geo_opt->twod_bits_precision)); } if (geo_opt->twod_location_min != def_geo->twod_location_min) { BSON_ASSERT (BSON_APPEND_DOUBLE (&doc, "min", geo_opt->twod_location_min)); } if (geo_opt->twod_location_max != def_geo->twod_location_max) { BSON_ASSERT (BSON_APPEND_DOUBLE (&doc, "max", geo_opt->twod_location_max)); } if (geo_opt->haystack_bucket_size != def_geo->haystack_bucket_size) { BSON_ASSERT (BSON_APPEND_DOUBLE (&doc, "bucketSize", geo_opt->haystack_bucket_size)); } } if (opt->storage_options) { storage_opt = opt->storage_options; switch (storage_opt->type) { case MONGOC_INDEX_STORAGE_OPT_WIREDTIGER: wt_opt = (mongoc_index_opt_wt_t *) storage_opt; BSON_APPEND_DOCUMENT_BEGIN (&doc, "storageEngine", &storage_doc); BSON_APPEND_DOCUMENT_BEGIN (&storage_doc, "wiredTiger", &wt_doc); BSON_ASSERT (BSON_APPEND_UTF8 (&wt_doc, "configString", wt_opt->config_str)); bson_append_document_end (&storage_doc, &wt_doc); bson_append_document_end (&doc, &storage_doc); break; default: break; } } bson_array_builder_append_document_end (ar, &doc); bson_append_array_builder_end (&cmd, ar); const mongoc_ss_log_context_t ss_log_context = {.operation = "createIndexes"}; server_stream = mongoc_cluster_stream_for_writes ( &collection->client->cluster, &ss_log_context, parsed.client_session, NULL, reply, error); if (!server_stream) { reply_initialized = true; GOTO (done); } if (!mongoc_cmd_parts_set_write_concern (&parts, parsed.writeConcern, error)) { GOTO (done); } parts.assembled.session = parsed.client_session; if (!bson_concat (&parts.extra, &parsed.extra)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "'opts' is too large"); GOTO (done); } cluster = &collection->client->cluster; if (mongoc_cmd_parts_assemble (&parts, server_stream, error)) { ret = mongoc_cluster_run_command_monitored (cluster, &parts.assembled, reply, error); } else { _mongoc_bson_init_if_set (reply); } reply_initialized = true; if (ret) { if (reply) { ret = !_mongoc_parse_wc_err (reply, error); } } done: bson_destroy (&cmd); bson_free (alloc_name); _mongoc_create_index_opts_cleanup (&parsed); mongoc_server_stream_cleanup (server_stream); mongoc_cmd_parts_cleanup (&parts); if (!reply_initialized && reply) { bson_init (reply); } RETURN (ret); } bool mongoc_collection_ensure_index (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error) { BEGIN_IGNORE_DEPRECATIONS return mongoc_collection_create_index (collection, keys, opt, error); END_IGNORE_DEPRECATIONS } mongoc_cursor_t * mongoc_collection_find_indexes (mongoc_collection_t *collection, bson_error_t *error) { mongoc_cursor_t *cursor; cursor = mongoc_collection_find_indexes_with_opts (collection, NULL); (void) mongoc_cursor_error (cursor, error); return cursor; } mongoc_cursor_t * mongoc_collection_find_indexes_with_opts (mongoc_collection_t *collection, const bson_t *opts) { mongoc_cursor_t *cursor; bson_t cmd = BSON_INITIALIZER; bson_t child; bson_error_t error; BSON_ASSERT_PARAM (collection); bson_append_utf8 (&cmd, "listIndexes", -1, collection->collection, collection->collectionlen); BSON_APPEND_DOCUMENT_BEGIN (&cmd, "cursor", &child); bson_append_document_end (&cmd, &child); /* No read preference. Index Enumeration Spec: "run listIndexes on the * primary node in replicaSet mode". */ cursor = _mongoc_cursor_cmd_new (collection->client, collection->ns, &cmd, opts, NULL, NULL, NULL); if (!mongoc_cursor_error (cursor, &error)) { _mongoc_cursor_prime (cursor); } if (mongoc_cursor_error (cursor, &error) && error.code == MONGOC_ERROR_COLLECTION_DOES_NOT_EXIST) { /* collection does not exist. from spec: return no documents but no err: * https://github.com/mongodb/specifications/blob/master/source/enumerate-collections/enumerate-collections.md#getting-full-collection-information */ _mongoc_cursor_set_empty (cursor); } bson_destroy (&cmd); return cursor; } /* *-------------------------------------------------------------------------- * * mongoc_collection_insert_bulk -- * * Bulk insert documents into a MongoDB collection. * * Parameters: * @collection: A mongoc_collection_t. * @flags: flags for the insert or 0. * @documents: The documents to insert. * @n_documents: The number of documents to insert. * @write_concern: A write concern or NULL. * @error: a location for an error or NULL. * * Returns: * true if successful; otherwise false and @error is set. * * If the write concern does not dictate checking the result of the * insert, then true may be returned even though the document was * not actually inserted on the MongoDB server or cluster. * * Side effects: * @collection->gle is setup, depending on write_concern->w value. * @error may be set upon failure if non-NULL. * *-------------------------------------------------------------------------- */ bool mongoc_collection_insert_bulk (mongoc_collection_t *collection, mongoc_insert_flags_t flags, const bson_t **documents, uint32_t n_documents, const mongoc_write_concern_t *write_concern, bson_error_t *error) { mongoc_write_command_t command; mongoc_write_result_t result; mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; uint32_t i; bool ret; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (documents); if (!write_concern) { write_concern = collection->write_concern; } if (!(flags & MONGOC_INSERT_NO_VALIDATE)) { for (i = 0; i < n_documents; i++) { if (!_mongoc_validate_new_document (documents[i], _mongoc_default_insert_vflags, error)) { RETURN (false); } } } bson_clear (&collection->gle); _mongoc_write_result_init (&result); write_flags.ordered = !(flags & MONGOC_INSERT_CONTINUE_ON_ERROR); _mongoc_write_command_init_insert (&command, NULL, NULL, write_flags, ++collection->client->cluster.operation_id); for (i = 0; i < n_documents; i++) { _mongoc_write_command_insert_append (&command, documents[i]); } _mongoc_collection_write_command_execute (&command, collection, write_concern, NULL, &result); collection->gle = bson_new (); ret = MONGOC_WRITE_RESULT_COMPLETE (&result, collection->client->error_api_version, write_concern, /* no error domain override */ (mongoc_error_domain_t) 0, collection->gle, error); _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); return ret; } bool mongoc_collection_insert (mongoc_collection_t *collection, mongoc_insert_flags_t flags, const bson_t *document, const mongoc_write_concern_t *write_concern, bson_error_t *error) { bson_t opts = BSON_INITIALIZER; bson_t reply; bool r; bson_clear (&collection->gle); if (flags & MONGOC_INSERT_NO_VALIDATE) { bson_append_bool (&opts, "validate", 8, false); } if (write_concern) { mongoc_write_concern_append ((mongoc_write_concern_t *) write_concern, &opts); } r = mongoc_collection_insert_one (collection, document, &opts, &reply, error); collection->gle = bson_copy (&reply); bson_destroy (&reply); bson_destroy (&opts); return r; } /* *-------------------------------------------------------------------------- * * mongoc_collection_insert_one -- * * Insert a document into a MongoDB collection. * * Parameters: * @collection: A mongoc_collection_t. * @document: The document to insert. * @opts: Standard command options. * @reply: Optional. Uninitialized doc to receive the update result. * @error: A location for an error or NULL. * * Returns: * true if successful; otherwise false and @error is set. * * If the write concern does not dictate checking the result of the * insert, then true may be returned even though the document was * not actually inserted on the MongoDB server or cluster. * *-------------------------------------------------------------------------- */ bool mongoc_collection_insert_one ( mongoc_collection_t *collection, const bson_t *document, const bson_t *opts, bson_t *reply, bson_error_t *error) { mongoc_insert_one_opts_t insert_one_opts; mongoc_write_command_t command; mongoc_write_result_t result; bson_t insert_id = BSON_INITIALIZER; bson_t cmd_opts = BSON_INITIALIZER; bool ret = false; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (document); _mongoc_bson_init_if_set (reply); if (!_mongoc_insert_one_opts_parse (collection->client, opts, &insert_one_opts, error)) { GOTO (done); } if (!bson_empty (&insert_one_opts.extra)) { bson_concat (&cmd_opts, &insert_one_opts.extra); } if (insert_one_opts.crud.comment.value_type != BSON_TYPE_EOD) { bson_append_value (&cmd_opts, "comment", 7, &insert_one_opts.crud.comment); } if (!_mongoc_validate_new_document (document, insert_one_opts.crud.validate, error)) { GOTO (done); } _mongoc_write_result_init (&result); _mongoc_write_command_init_insert_one_idl ( &command, document, &cmd_opts, &insert_id, ++collection->client->cluster.operation_id); command.flags.bypass_document_validation = insert_one_opts.bypass; _mongoc_collection_write_command_execute_idl (&command, collection, &insert_one_opts.crud, &result); ret = MONGOC_WRITE_RESULT_COMPLETE (&result, collection->client->error_api_version, insert_one_opts.crud.writeConcern, /* no error domain override */ (mongoc_error_domain_t) 0, reply, error, "insertedCount"); // Only record _id of document if it was actually inserted and reply is non-NULL. if (reply && result.nInserted > 0) { bson_concat (reply, &insert_id); } _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); done: _mongoc_insert_one_opts_cleanup (&insert_one_opts); bson_destroy (&insert_id); bson_destroy (&cmd_opts); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_collection_insert_many -- * * Insert documents into a MongoDB collection. Replaces * mongoc_collection_insert_bulk. * * Parameters: * @collection: A mongoc_collection_t. * @documents: The documents to insert. * @n_documents: Length of @documents array. * @opts: Standard command options. * @reply: Optional. Uninitialized doc to receive the update result. * @error: A location for an error or NULL. * * Returns: * true if successful; otherwise false and @error is set. * * If the write concern does not dictate checking the result of the * insert, then true may be returned even though the document was * not actually inserted on the MongoDB server or cluster. * *-------------------------------------------------------------------------- */ bool mongoc_collection_insert_many (mongoc_collection_t *collection, const bson_t **documents, size_t n_documents, const bson_t *opts, bson_t *reply, bson_error_t *error) { mongoc_insert_many_opts_t insert_many_opts; mongoc_write_command_t command; mongoc_write_result_t result; bson_t cmd_opts = BSON_INITIALIZER; size_t i; bool ret; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (documents); _mongoc_bson_init_if_set (reply); if (!_mongoc_insert_many_opts_parse (collection->client, opts, &insert_many_opts, error)) { _mongoc_insert_many_opts_cleanup (&insert_many_opts); return false; } if (insert_many_opts.crud.comment.value_type != BSON_TYPE_EOD) { bson_append_value (&cmd_opts, "comment", 7, &insert_many_opts.crud.comment); } if (!bson_empty (&insert_many_opts.extra)) { bson_concat (&cmd_opts, &insert_many_opts.extra); } _mongoc_write_result_init (&result); _mongoc_write_command_init_insert_idl (&command, NULL, &cmd_opts, ++collection->client->cluster.operation_id); command.flags.ordered = insert_many_opts.ordered; command.flags.bypass_document_validation = insert_many_opts.bypass; for (i = 0; i < n_documents; i++) { if (!_mongoc_validate_new_document (documents[i], insert_many_opts.crud.validate, error)) { ret = false; GOTO (done); } _mongoc_write_command_insert_append (&command, documents[i]); } _mongoc_collection_write_command_execute_idl (&command, collection, &insert_many_opts.crud, &result); ret = MONGOC_WRITE_RESULT_COMPLETE (&result, collection->client->error_api_version, insert_many_opts.crud.writeConcern, /* no error domain override */ (mongoc_error_domain_t) 0, reply, error, "insertedCount"); done: _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); _mongoc_insert_many_opts_cleanup (&insert_many_opts); bson_destroy (&cmd_opts); RETURN (ret); } bool mongoc_collection_update (mongoc_collection_t *collection, mongoc_update_flags_t uflags, const bson_t *selector, const bson_t *update, const mongoc_write_concern_t *write_concern, bson_error_t *error) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; bson_iter_t iter; bool ret; int flags = uflags; bson_t opts; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (selector); BSON_ASSERT_PARAM (update); bson_clear (&collection->gle); if (!write_concern) { write_concern = collection->write_concern; } if (!((uint32_t) flags & MONGOC_UPDATE_NO_VALIDATE) && bson_iter_init (&iter, update) && bson_iter_next (&iter)) { if (bson_iter_key (&iter)[0] == '$') { /* update document, all keys must be $-operators */ if (!_mongoc_validate_update (update, _mongoc_default_update_vflags, error)) { return false; } } else { if (!_mongoc_validate_replace (update, _mongoc_default_replace_vflags, error)) { return false; } } } bson_init (&opts); BSON_APPEND_BOOL (&opts, "upsert", !!(flags & MONGOC_UPDATE_UPSERT)); BSON_APPEND_BOOL (&opts, "multi", !!(flags & MONGOC_UPDATE_MULTI_UPDATE)); _mongoc_write_result_init (&result); _mongoc_write_command_init_update (&command, selector, update, NULL, /* cmd_opts */ &opts, write_flags, ++collection->client->cluster.operation_id); bson_destroy (&opts); command.flags.has_multi_write = !!(flags & MONGOC_UPDATE_MULTI_UPDATE); _mongoc_collection_write_command_execute (&command, collection, write_concern, NULL, &result); collection->gle = bson_new (); ret = MONGOC_WRITE_RESULT_COMPLETE (&result, collection->client->error_api_version, write_concern, /* no error domain override */ (mongoc_error_domain_t) 0, collection->gle, error); _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); RETURN (ret); } static bool _mongoc_collection_update_or_replace (mongoc_collection_t *collection, const bson_t *selector, const bson_t *update, mongoc_update_opts_t *update_opts, bool multi, bool bypass, const bson_t *array_filters, const bson_t *sort, bson_t *extra, bson_t *reply, bson_error_t *error) { mongoc_write_command_t command; mongoc_write_result_t result; mongoc_server_stream_t *server_stream = NULL; bson_t cmd_opts = BSON_INITIALIZER; bool reply_initialized = false; bool ret = false; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (selector); BSON_ASSERT_PARAM (update); if (!bson_empty (&update_opts->let)) { bson_append_document (&cmd_opts, "let", 3, &update_opts->let); } if (update_opts->crud.comment.value_type != BSON_TYPE_EOD) { bson_append_value (&cmd_opts, "comment", 7, &update_opts->crud.comment); } if (update_opts->upsert) { bson_append_bool (extra, "upsert", 6, true); } if (!bson_empty (&update_opts->collation)) { bson_append_document (extra, "collation", 9, &update_opts->collation); } if (update_opts->hint.value_type) { bson_append_value (extra, "hint", 4, &update_opts->hint); } if (!bson_empty0 (array_filters)) { bson_append_array (extra, "arrayFilters", 12, array_filters); } if (!bson_empty0 (sort)) { bson_append_document (extra, "sort", 4, sort); } if (multi) { bson_append_bool (extra, "multi", 5, true); } _mongoc_write_result_init (&result); _mongoc_write_command_init_update_idl ( &command, selector, update, &cmd_opts, extra, ++collection->client->cluster.operation_id); command.flags.has_multi_write = multi; command.flags.bypass_document_validation = bypass; if (!bson_empty (&update_opts->collation)) { command.flags.has_collation = true; } if (update_opts->hint.value_type) { command.flags.has_update_hint = true; } const mongoc_ss_log_context_t ss_log_context = {.operation = _mongoc_write_command_get_name (&command), .has_operation_id = true, .operation_id = command.operation_id}; server_stream = mongoc_cluster_stream_for_writes ( &collection->client->cluster, &ss_log_context, update_opts->crud.client_session, NULL, reply, error); if (!server_stream) { /* mongoc_cluster_stream_for_writes inits reply on error */ reply_initialized = true; GOTO (done); } if (!bson_empty0 (array_filters)) { if (!mongoc_write_concern_is_acknowledged (update_opts->crud.writeConcern)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "Cannot use array filters with unacknowledged writes"); GOTO (done); } } if (_mongoc_client_session_in_txn (update_opts->crud.client_session) && update_opts->crud.writeConcern) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set write concern after starting transaction"); GOTO (done); } if (!update_opts->crud.writeConcern && !_mongoc_client_session_in_txn (update_opts->crud.client_session)) { update_opts->crud.writeConcern = collection->write_concern; update_opts->crud.write_concern_owned = false; } _mongoc_write_command_execute_idl (&command, collection->client, server_stream, collection->db, collection->collection, 0 /* offset */, &update_opts->crud, &result); _mongoc_bson_init_if_set (reply); reply_initialized = true; /* set fields described in CRUD spec for the UpdateResult */ ret = MONGOC_WRITE_RESULT_COMPLETE (&result, collection->client->error_api_version, update_opts->crud.writeConcern, /* no error domain override */ (mongoc_error_domain_t) 0, reply, error, "modifiedCount", "matchedCount", "upsertedCount", "upsertedId"); done: _mongoc_write_result_destroy (&result); mongoc_server_stream_cleanup (server_stream); _mongoc_write_command_destroy (&command); bson_destroy (&cmd_opts); if (!reply_initialized) { _mongoc_bson_init_if_set (reply); } RETURN (ret); } bool mongoc_collection_update_one (mongoc_collection_t *collection, const bson_t *selector, const bson_t *update, const bson_t *opts, bson_t *reply, bson_error_t *error) { mongoc_update_one_opts_t update_one_opts; bool ret; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (update); if (!_mongoc_update_one_opts_parse (collection->client, opts, &update_one_opts, error)) { _mongoc_update_one_opts_cleanup (&update_one_opts); _mongoc_bson_init_if_set (reply); return false; } if (!_mongoc_validate_update (update, update_one_opts.update.crud.validate, error)) { _mongoc_update_one_opts_cleanup (&update_one_opts); _mongoc_bson_init_if_set (reply); return false; } ret = _mongoc_collection_update_or_replace (collection, selector, update, &update_one_opts.update, false /* multi */, update_one_opts.update.bypass, &update_one_opts.arrayFilters, &update_one_opts.sort, &update_one_opts.extra, reply, error); _mongoc_update_one_opts_cleanup (&update_one_opts); RETURN (ret); } bool mongoc_collection_update_many (mongoc_collection_t *collection, const bson_t *selector, const bson_t *update, const bson_t *opts, bson_t *reply, bson_error_t *error) { mongoc_update_many_opts_t update_many_opts; bool ret; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (update); if (!_mongoc_update_many_opts_parse (collection->client, opts, &update_many_opts, error)) { _mongoc_update_many_opts_cleanup (&update_many_opts); _mongoc_bson_init_if_set (reply); return false; } if (!_mongoc_validate_update (update, update_many_opts.update.crud.validate, error)) { _mongoc_update_many_opts_cleanup (&update_many_opts); _mongoc_bson_init_if_set (reply); return false; } ret = _mongoc_collection_update_or_replace (collection, selector, update, &update_many_opts.update, true /* multi */, update_many_opts.update.bypass, &update_many_opts.arrayFilters, NULL /* sort */, &update_many_opts.extra, reply, error); _mongoc_update_many_opts_cleanup (&update_many_opts); RETURN (ret); } bool mongoc_collection_replace_one (mongoc_collection_t *collection, const bson_t *selector, const bson_t *replacement, const bson_t *opts, bson_t *reply, bson_error_t *error) { mongoc_replace_one_opts_t replace_one_opts; bool ret; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (replacement); if (!_mongoc_replace_one_opts_parse (collection->client, opts, &replace_one_opts, error)) { _mongoc_replace_one_opts_cleanup (&replace_one_opts); _mongoc_bson_init_if_set (reply); return false; } if (!_mongoc_validate_replace (replacement, replace_one_opts.update.crud.validate, error)) { _mongoc_replace_one_opts_cleanup (&replace_one_opts); _mongoc_bson_init_if_set (reply); return false; } ret = _mongoc_collection_update_or_replace (collection, selector, replacement, &replace_one_opts.update, false /* multi */, replace_one_opts.update.bypass, NULL, &replace_one_opts.sort, &replace_one_opts.extra, reply, error); _mongoc_replace_one_opts_cleanup (&replace_one_opts); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_collection_save -- * * Save @document to @collection. * * If the document has an _id field, it will be updated. Otherwise, * the document will be inserted into the collection. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @error is set upon failure if non-NULL. * *-------------------------------------------------------------------------- */ bool mongoc_collection_save (mongoc_collection_t *collection, const bson_t *document, const mongoc_write_concern_t *write_concern, bson_error_t *error) { bson_iter_t iter; bool ret; bson_t selector; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (document); BEGIN_IGNORE_DEPRECATIONS if (!bson_iter_init_find (&iter, document, "_id")) { return mongoc_collection_insert (collection, MONGOC_INSERT_NONE, document, write_concern, error); } bson_init (&selector); if (!bson_append_iter (&selector, NULL, 0, &iter)) { bson_set_error ( error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Failed to append bson to create update."); bson_destroy (&selector); return false; } /* this document will be inserted, validate same as for inserts */ if (!_mongoc_validate_new_document (document, _mongoc_default_insert_vflags, error)) { return false; } ret = mongoc_collection_update ( collection, MONGOC_UPDATE_UPSERT | MONGOC_UPDATE_NO_VALIDATE, &selector, document, write_concern, error); END_IGNORE_DEPRECATIONS bson_destroy (&selector); return ret; } bool mongoc_collection_remove (mongoc_collection_t *collection, mongoc_remove_flags_t flags, const bson_t *selector, const mongoc_write_concern_t *write_concern, bson_error_t *error) { mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_command_t command; mongoc_write_result_t result; bson_t opts; bool ret; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (selector); bson_clear (&collection->gle); if (!write_concern) { write_concern = collection->write_concern; } bson_init (&opts); BSON_APPEND_INT32 (&opts, "limit", flags & MONGOC_REMOVE_SINGLE_REMOVE ? 1 : 0); _mongoc_write_result_init (&result); ++collection->client->cluster.operation_id; _mongoc_write_command_init_delete ( &command, selector, NULL, &opts, write_flags, collection->client->cluster.operation_id); bson_destroy (&opts); command.flags.has_multi_write = !(flags & MONGOC_REMOVE_SINGLE_REMOVE); _mongoc_collection_write_command_execute (&command, collection, write_concern, NULL, &result); collection->gle = bson_new (); ret = MONGOC_WRITE_RESULT_COMPLETE (&result, collection->client->error_api_version, write_concern, 0 /* no error domain override */, collection->gle, error); _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); RETURN (ret); } bool mongoc_collection_delete (mongoc_collection_t *collection, mongoc_delete_flags_t flags, const bson_t *selector, const mongoc_write_concern_t *write_concern, bson_error_t *error) { return mongoc_collection_remove (collection, (mongoc_remove_flags_t) flags, selector, write_concern, error); } static bool _mongoc_delete_one_or_many (mongoc_collection_t *collection, bool multi, const bson_t *selector, mongoc_delete_opts_t *delete_opts, const bson_t *extra, bson_t *reply, bson_error_t *error) { mongoc_write_command_t command; mongoc_write_result_t result; bson_t cmd_opts = BSON_INITIALIZER; bson_t opts = BSON_INITIALIZER; bool ret; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (selector); BSON_ASSERT (bson_empty0 (reply)); /* TODO: This function has historically used `extra` for top-level, command * options. That is inconsistent with the update function, which uses `extra` * for statement-level options. We will keep the original behavior for BC * reasons, but this should ultimately be addressed by CDRIVER-4306. */ if (!bson_empty0 (extra)) { bson_concat (&cmd_opts, extra); } if (!bson_empty (&delete_opts->let)) { bson_append_document (&cmd_opts, "let", 3, &delete_opts->let); } if (delete_opts->crud.comment.value_type != BSON_TYPE_EOD) { bson_append_value (&cmd_opts, "comment", 7, &delete_opts->crud.comment); } _mongoc_write_result_init (&result); bson_append_int32 (&opts, "limit", 5, multi ? 0 : 1); if (!bson_empty (&delete_opts->collation)) { bson_append_document (&opts, "collation", 9, &delete_opts->collation); } if (delete_opts->hint.value_type) { bson_append_value (&opts, "hint", 4, &delete_opts->hint); } _mongoc_write_command_init_delete_idl ( &command, selector, &cmd_opts, &opts, ++collection->client->cluster.operation_id); command.flags.has_multi_write = multi; if (!bson_empty (&delete_opts->collation)) { command.flags.has_collation = true; } if (delete_opts->hint.value_type) { command.flags.has_delete_hint = true; } _mongoc_collection_write_command_execute_idl (&command, collection, &delete_opts->crud, &result); /* set field described in CRUD spec for the DeleteResult */ ret = MONGOC_WRITE_RESULT_COMPLETE (&result, collection->client->error_api_version, delete_opts->crud.writeConcern, /* no error domain override */ (mongoc_error_domain_t) 0, reply, error, "deletedCount"); _mongoc_write_result_destroy (&result); _mongoc_write_command_destroy (&command); bson_destroy (&cmd_opts); bson_destroy (&opts); RETURN (ret); } bool mongoc_collection_delete_one ( mongoc_collection_t *collection, const bson_t *selector, const bson_t *opts, bson_t *reply, bson_error_t *error) { mongoc_delete_one_opts_t delete_one_opts; bool ret = false; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (selector); _mongoc_bson_init_if_set (reply); if (!_mongoc_delete_one_opts_parse (collection->client, opts, &delete_one_opts, error)) { GOTO (done); } ret = _mongoc_delete_one_or_many ( collection, false /* multi */, selector, &delete_one_opts.delete, &delete_one_opts.extra, reply, error); done: _mongoc_delete_one_opts_cleanup (&delete_one_opts); RETURN (ret); } bool mongoc_collection_delete_many ( mongoc_collection_t *collection, const bson_t *selector, const bson_t *opts, bson_t *reply, bson_error_t *error) { mongoc_delete_many_opts_t delete_many_opts; bool ret = false; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (selector); _mongoc_bson_init_if_set (reply); if (!_mongoc_delete_many_opts_parse (collection->client, opts, &delete_many_opts, error)) { GOTO (done); } ret = _mongoc_delete_one_or_many ( collection, true /* multi */, selector, &delete_many_opts.delete, &delete_many_opts.extra, reply, error); done: _mongoc_delete_many_opts_cleanup (&delete_many_opts); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_read_prefs -- * * Fetch the default read preferences for the collection. * * Returns: * A mongoc_read_prefs_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_prefs_t * mongoc_collection_get_read_prefs (const mongoc_collection_t *collection) { BSON_ASSERT_PARAM (collection); return collection->read_prefs; } /* *-------------------------------------------------------------------------- * * mongoc_collection_set_read_prefs -- * * Sets the default read preferences for the collection instance. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_collection_set_read_prefs (mongoc_collection_t *collection, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT_PARAM (collection); if (collection->read_prefs) { mongoc_read_prefs_destroy (collection->read_prefs); collection->read_prefs = NULL; } if (read_prefs) { collection->read_prefs = mongoc_read_prefs_copy (read_prefs); } } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_read_concern -- * * Fetches the default read concern for the collection instance. * * Returns: * A mongoc_read_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_concern_t * mongoc_collection_get_read_concern (const mongoc_collection_t *collection) { BSON_ASSERT_PARAM (collection); return collection->read_concern; } /* *-------------------------------------------------------------------------- * * mongoc_collection_set_read_concern -- * * Sets the default read concern for the collection instance. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_collection_set_read_concern (mongoc_collection_t *collection, const mongoc_read_concern_t *read_concern) { BSON_ASSERT_PARAM (collection); if (collection->read_concern) { mongoc_read_concern_destroy (collection->read_concern); collection->read_concern = NULL; } if (read_concern) { collection->read_concern = mongoc_read_concern_copy (read_concern); } } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_write_concern -- * * Fetches the default write concern for the collection instance. * * Returns: * A mongoc_write_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_write_concern_t * mongoc_collection_get_write_concern (const mongoc_collection_t *collection) { BSON_ASSERT_PARAM (collection); return collection->write_concern; } /* *-------------------------------------------------------------------------- * * mongoc_collection_set_write_concern -- * * Sets the default write concern for the collection instance. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_collection_set_write_concern (mongoc_collection_t *collection, const mongoc_write_concern_t *write_concern) { BSON_ASSERT_PARAM (collection); if (collection->write_concern) { mongoc_write_concern_destroy (collection->write_concern); collection->write_concern = NULL; } if (write_concern) { collection->write_concern = mongoc_write_concern_copy (write_concern); } } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_name -- * * Returns the name of the collection, excluding the database name. * * Returns: * A string which should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const char * mongoc_collection_get_name (mongoc_collection_t *collection) { BSON_ASSERT_PARAM (collection); return collection->collection; } /* *-------------------------------------------------------------------------- * * mongoc_collection_get_last_error -- * * Returns a bulk result. * * Returns: * NULL or a bson_t that should not be modified or freed. This value * is not guaranteed to be persistent between calls into the * mongoc_collection_t instance, and therefore must be copied if * you would like to keep it around. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const bson_t * mongoc_collection_get_last_error (const mongoc_collection_t *collection) /* IN */ { BSON_ASSERT_PARAM (collection); return collection->gle; } /* *-------------------------------------------------------------------------- * * mongoc_collection_validate -- * * Helper to call the validate command on the MongoDB server to * validate the collection. * * Options may be additional options, or NULL. * Currently supported options are: * * "full": Boolean * * If full is true, then perform a more resource intensive * validation. * * The result is stored in reply. * * Returns: * true if successful; otherwise false and @error is set. * * Side effects: * @reply is set if successful. * @error may be set. * *-------------------------------------------------------------------------- */ bool mongoc_collection_validate (mongoc_collection_t *collection, /* IN */ const bson_t *options, /* IN */ bson_t *reply, /* OUT */ bson_error_t *error) /* IN */ { bson_iter_t iter; bson_t cmd = BSON_INITIALIZER; bool ret = false; bool reply_initialized = false; BSON_ASSERT_PARAM (collection); if (options && bson_iter_init_find (&iter, options, "full") && !BSON_ITER_HOLDS_BOOL (&iter)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "'full' must be a boolean value."); goto cleanup; } bson_append_utf8 (&cmd, "validate", 8, collection->collection, collection->collectionlen); if (options) { bson_concat (&cmd, options); } ret = mongoc_collection_command_simple (collection, &cmd, NULL, reply, error); reply_initialized = true; cleanup: bson_destroy (&cmd); if (reply && !reply_initialized) { bson_init (reply); } return ret; } /* *-------------------------------------------------------------------------- * * mongoc_collection_rename -- * * Rename the collection to @new_name. * * If @new_db is NULL, the same db will be used. * * If @drop_target_before_rename is true, then a collection named * @new_name will be dropped before renaming @collection to * @new_name. * * Returns: * true on success; false on failure and @error is set. * * Side effects: * @error is set on failure. * *-------------------------------------------------------------------------- */ bool mongoc_collection_rename (mongoc_collection_t *collection, const char *new_db, const char *new_name, bool drop_target_before_rename, bson_error_t *error) { return mongoc_collection_rename_with_opts (collection, new_db, new_name, drop_target_before_rename, NULL, error); } bool mongoc_collection_rename_with_opts (mongoc_collection_t *collection, const char *new_db, const char *new_name, bool drop_target_before_rename, const bson_t *opts, bson_error_t *error) { bson_t cmd = BSON_INITIALIZER; char *newns; bool ret; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (new_name); if (strchr (new_name, '$')) { bson_set_error (error, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_NAMESPACE_INVALID, "\"%s\" is an invalid collection name.", new_name); return false; } newns = bson_strdup_printf ("%s.%s", new_db ? new_db : collection->db, new_name); BSON_APPEND_UTF8 (&cmd, "renameCollection", collection->ns); BSON_APPEND_UTF8 (&cmd, "to", newns); if (drop_target_before_rename) { BSON_APPEND_BOOL (&cmd, "dropTarget", true); } ret = _mongoc_client_command_with_opts (collection->client, "admin", &cmd, MONGOC_CMD_WRITE, opts, MONGOC_QUERY_NONE, NULL, /* user prefs */ collection->read_prefs, collection->read_concern, collection->write_concern, NULL, /* reply */ error); if (ret) { if (new_db) { bson_free (collection->db); collection->db = bson_strdup (new_db); } bson_free (collection->collection); collection->collection = bson_strdup (new_name); collection->collectionlen = (int) strlen (collection->collection); bson_free (collection->ns); collection->ns = bson_strdup_printf ("%s.%s", collection->db, new_name); collection->nslen = (int) strlen (collection->ns); } bson_free (newns); bson_destroy (&cmd); return ret; } /* *-------------------------------------------------------------------------- * * mongoc_collection_stats -- * * Fetches statistics about the collection. * * The result is stored in @stats, which should NOT be an initialized * bson_t or a leak will occur. * * @stats, @options, and @error are optional. * * Returns: * true on success and @stats is set. * false on failure and @error is set. * * Side effects: * @stats and @error. * *-------------------------------------------------------------------------- */ bool mongoc_collection_stats (mongoc_collection_t *collection, const bson_t *options, bson_t *stats, bson_error_t *error) { bson_iter_t iter; bson_t cmd = BSON_INITIALIZER; bool ret; BSON_ASSERT_PARAM (collection); if (options && bson_iter_init_find (&iter, options, "scale") && !BSON_ITER_HOLDS_INT32 (&iter)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "'scale' must be an int32 value."); return false; } BSON_APPEND_UTF8 (&cmd, "collStats", collection->collection); if (options) { bson_concat (&cmd, options); } /* Server Selection Spec: "may-use-secondary" commands SHOULD take a read * preference argument and otherwise MUST use the default read preference * from client, database or collection configuration. */ ret = mongoc_collection_command_simple (collection, &cmd, collection->read_prefs, stats, error); bson_destroy (&cmd); return ret; } mongoc_bulk_operation_t * mongoc_collection_create_bulk_operation (mongoc_collection_t *collection, bool ordered, const mongoc_write_concern_t *write_concern) { bson_t opts = BSON_INITIALIZER; mongoc_bulk_operation_t *bulk; bool wc_ok = true; bson_append_bool (&opts, "ordered", 7, ordered); if (write_concern) { wc_ok = mongoc_write_concern_append ((mongoc_write_concern_t *) write_concern, &opts); } bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts); bson_destroy (&opts); if (!wc_ok) { bson_set_error ( &bulk->result.error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "invalid writeConcern"); } return bulk; } mongoc_bulk_operation_t * mongoc_collection_create_bulk_operation_with_opts (mongoc_collection_t *collection, const bson_t *opts) { mongoc_bulk_opts_t bulk_opts; mongoc_bulk_write_flags_t write_flags = MONGOC_BULK_WRITE_FLAGS_INIT; mongoc_write_concern_t *wc = NULL; mongoc_bulk_operation_t *bulk; bson_error_t err = {0}; BSON_ASSERT_PARAM (collection); (void) _mongoc_bulk_opts_parse (collection->client, opts, &bulk_opts, &err); if (!_mongoc_client_session_in_txn (bulk_opts.client_session)) { wc = COALESCE (bulk_opts.writeConcern, collection->write_concern); } write_flags.ordered = bulk_opts.ordered; bulk = _mongoc_bulk_operation_new (collection->client, collection->db, collection->collection, write_flags, wc); if (!bson_empty (&bulk_opts.let)) { mongoc_bulk_operation_set_let (bulk, &bulk_opts.let); } if (bulk_opts.comment.value_type != BSON_TYPE_EOD) { mongoc_bulk_operation_set_comment (bulk, &bulk_opts.comment); } bulk->session = bulk_opts.client_session; if (err.domain) { /* _mongoc_bulk_opts_parse failed, above */ memcpy (&bulk->result.error, &err, sizeof (bson_error_t)); } else if (_mongoc_client_session_in_txn (bulk_opts.client_session) && !mongoc_write_concern_is_default (bulk_opts.writeConcern)) { bson_set_error (&bulk->result.error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set write concern after starting transaction"); } _mongoc_bulk_opts_cleanup (&bulk_opts); return bulk; } /* *-------------------------------------------------------------------------- * * mongoc_collection_find_and_modify_with_opts -- * * Find a document in @collection matching @query, applying @opts. * * If @reply is not NULL, then the result document will be placed * in reply and should be released with bson_destroy(). * * See for more information: * https://www.mongodb.com/docs/manual/reference/command/findAndModify/ * * Returns: * true on success; false on failure. * * Side effects: * reply is initialized. * error is set if false is returned. * *-------------------------------------------------------------------------- */ bool mongoc_collection_find_and_modify_with_opts (mongoc_collection_t *collection, const bson_t *query, const mongoc_find_and_modify_opts_t *opts, bson_t *reply, bson_error_t *error) { mongoc_cluster_t *cluster; mongoc_cmd_parts_t parts; bson_iter_t iter; bson_iter_t inner; const char *name; bson_t ss_reply; bson_t reply_local = BSON_INITIALIZER; bool ret = false; bson_t command = BSON_INITIALIZER; mongoc_server_stream_t *server_stream = NULL; mongoc_server_stream_t *retry_server_stream = NULL; mongoc_find_and_modify_appended_opts_t appended_opts; mongoc_write_concern_t *write_concern = NULL; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (query); BSON_ASSERT_PARAM (opts); if (reply) { bson_init (reply); } else { // Caller did not pass an output `reply`. Use a local `reply` to determine if a server error is retryable. reply = &reply_local; } cluster = &collection->client->cluster; mongoc_cmd_parts_init (&parts, collection->client, collection->db, MONGOC_QUERY_NONE, &command); parts.is_read_command = true; parts.is_write_command = true; if (!_mongoc_find_and_modify_appended_opts_parse (cluster->client, &opts->extra, &appended_opts, error)) { GOTO (done); } const mongoc_ss_log_context_t ss_log_context = {.operation = "findAndModify"}; server_stream = mongoc_cluster_stream_for_writes (cluster, &ss_log_context, appended_opts.client_session, NULL, &ss_reply, error); if (!server_stream) { bson_concat (reply, &ss_reply); bson_destroy (&ss_reply); GOTO (done); } name = mongoc_collection_get_name (collection); BSON_APPEND_UTF8 (&command, "findAndModify", name); BSON_APPEND_DOCUMENT (&command, "query", query); if (opts->sort) { BSON_APPEND_DOCUMENT (&command, "sort", opts->sort); } if (opts->update) { if (_mongoc_document_is_pipeline (opts->update)) { BSON_APPEND_ARRAY (&command, "update", opts->update); } else { BSON_APPEND_DOCUMENT (&command, "update", opts->update); } } if (opts->fields) { BSON_APPEND_DOCUMENT (&command, "fields", opts->fields); } if (opts->flags & MONGOC_FIND_AND_MODIFY_REMOVE) { BSON_APPEND_BOOL (&command, "remove", true); } if (opts->flags & MONGOC_FIND_AND_MODIFY_UPSERT) { BSON_APPEND_BOOL (&command, "upsert", true); } if (opts->flags & MONGOC_FIND_AND_MODIFY_RETURN_NEW) { BSON_APPEND_BOOL (&command, "new", true); } if (opts->bypass_document_validation) { BSON_APPEND_BOOL (&command, "bypassDocumentValidation", opts->bypass_document_validation); } if (opts->max_time_ms > 0) { BSON_APPEND_INT32 (&command, "maxTimeMS", opts->max_time_ms); } /* Some options set via mongoc_find_and_modify_opts_append were parsed. Set * them on the command parts. */ if (appended_opts.client_session) { mongoc_cmd_parts_set_session (&parts, appended_opts.client_session); } if (appended_opts.writeConcern) { if (_mongoc_client_session_in_txn (parts.assembled.session)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set write concern after starting transaction"); GOTO (done); } write_concern = appended_opts.writeConcern; } /* inherit write concern from collection if not in transaction */ else if (!_mongoc_client_session_in_txn (parts.assembled.session)) { if (!mongoc_write_concern_is_valid (collection->write_concern)) { bson_set_error ( error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The write concern is invalid."); GOTO (done); } write_concern = collection->write_concern; } if (appended_opts.hint.value_type) { int max_wire_version = mongoc_write_concern_is_acknowledged (write_concern) ? WIRE_VERSION_FIND_AND_MODIFY_HINT_SERVER_SIDE_ERROR : WIRE_VERSION_FIND_AND_MODIFY_HINT; if (server_stream->sd->max_wire_version < max_wire_version) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support hint for findAndModify"); GOTO (done); } bson_append_value (&parts.extra, "hint", 4, &appended_opts.hint); } if (!bson_empty (&appended_opts.let)) { bson_append_document (&parts.extra, "let", 3, &appended_opts.let); } if (appended_opts.comment.value_type != BSON_TYPE_EOD) { bson_append_value (&parts.extra, "comment", 7, &appended_opts.comment); } /* Append any remaining unparsed options set via * mongoc_find_and_modify_opts_append to the command part. */ if (bson_iter_init (&iter, &appended_opts.extra)) { if (!mongoc_cmd_parts_append_opts (&parts, &iter, error)) { GOTO (done); } } /* An empty write concern amounts to a no-op, so there's no need to guard * against it. */ if (!mongoc_cmd_parts_set_write_concern (&parts, write_concern, error)) { GOTO (done); } parts.assembled.operation_id = ++cluster->operation_id; if (!mongoc_cmd_parts_assemble (&parts, server_stream, error)) { GOTO (done); } bson_destroy (reply); ret = mongoc_cluster_run_retryable_write ( cluster, &parts.assembled, parts.is_retryable_write, &retry_server_stream, reply, error); if (bson_iter_init_find (&iter, reply, "writeConcernError") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { const char *errmsg = NULL; int32_t code = 0; BSON_ASSERT (bson_iter_recurse (&iter, &inner)); while (bson_iter_next (&inner)) { if (BSON_ITER_IS_KEY (&inner, "code")) { code = (uint32_t) bson_iter_as_int64 (&inner); } else if (BSON_ITER_IS_KEY (&inner, "errmsg")) { errmsg = bson_iter_utf8 (&inner, NULL); } } bson_set_error (error, MONGOC_ERROR_WRITE_CONCERN, code, "Write Concern error: %s", errmsg); ret = false; } done: mongoc_server_stream_cleanup (server_stream); mongoc_server_stream_cleanup (retry_server_stream); if (ret && error) { /* if a retry succeeded, clear the initial error */ memset (error, 0, sizeof (bson_error_t)); } mongoc_cmd_parts_cleanup (&parts); bson_destroy (&command); bson_destroy (&reply_local); _mongoc_find_and_modify_appended_opts_cleanup (&appended_opts); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_collection_find_and_modify -- * * Find a document in @collection matching @query and update it with * the update document @update. * * If @reply is not NULL, then the result document will be placed * in reply and should be released with bson_destroy(). * * If @remove is true, then the matching documents will be removed. * * If @fields is not NULL, it will be used to select the desired * resulting fields. * * If @_new is true, then the new version of the document is returned * instead of the old document. * * See for more information: * https://www.mongodb.com/docs/manual/reference/command/findAndModify/ * * Returns: * true on success; false on failure. * * Side effects: * reply is initialized. * error is set if false is returned. * *-------------------------------------------------------------------------- */ bool mongoc_collection_find_and_modify (mongoc_collection_t *collection, const bson_t *query, const bson_t *sort, const bson_t *update, const bson_t *fields, bool _remove, bool upsert, bool _new, bson_t *reply, bson_error_t *error) { mongoc_find_and_modify_opts_t *opts; int flags = 0; bool ret; ENTRY; BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (query); BSON_ASSERT (update || _remove); if (_remove) { flags |= MONGOC_FIND_AND_MODIFY_REMOVE; } if (upsert) { flags |= MONGOC_FIND_AND_MODIFY_UPSERT; } if (_new) { flags |= MONGOC_FIND_AND_MODIFY_RETURN_NEW; } opts = mongoc_find_and_modify_opts_new (); mongoc_find_and_modify_opts_set_sort (opts, sort); mongoc_find_and_modify_opts_set_update (opts, update); mongoc_find_and_modify_opts_set_fields (opts, fields); mongoc_find_and_modify_opts_set_flags (opts, flags); ret = mongoc_collection_find_and_modify_with_opts (collection, query, opts, reply, error); mongoc_find_and_modify_opts_destroy (opts); return ret; } mongoc_change_stream_t * mongoc_collection_watch (const mongoc_collection_t *coll, const bson_t *pipeline, const bson_t *opts) { return _mongoc_change_stream_new_from_collection (coll, pipeline, opts); } struct _mongoc_index_model_t { bson_t *keys; bson_t *opts; }; mongoc_index_model_t * mongoc_index_model_new (const bson_t *keys, const bson_t *opts) { BSON_ASSERT_PARAM (keys); // `opts` may be NULL. mongoc_index_model_t *im = bson_malloc (sizeof (mongoc_index_model_t)); im->keys = bson_copy (keys); im->opts = opts ? bson_copy (opts) : NULL; return im; } void mongoc_index_model_destroy (mongoc_index_model_t *im) { if (!im) { return; } bson_destroy (im->keys); bson_destroy (im->opts); bson_free (im); } bool mongoc_collection_create_indexes_with_opts (mongoc_collection_t *collection, mongoc_index_model_t *const *models, size_t n_models, const bson_t *opts, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (collection); BSON_ASSERT_PARAM (models); // `opts` may be NULL. // `reply` may be NULL. // `error` may be NULL. bson_t reply_local = BSON_INITIALIZER; bson_t *reply_ptr; mongoc_server_stream_t *server_stream = NULL; bool ok = false; bson_t cmd = BSON_INITIALIZER; reply_ptr = reply ? reply : &reply_local; // Always initialize `reply` if set. Caller is expected to `bson_destroy // (reply)`. bson_init (reply_ptr); // Check for commitQuorum option. if (opts && bson_has_field (opts, "commitQuorum")) { const mongoc_ss_log_context_t ss_log_context = {.operation = "createIndexes"}; server_stream = mongoc_cluster_stream_for_writes (&collection->client->cluster, &ss_log_context, NULL /* mongoc_client_session_t */, NULL /* deprioritized servers */, reply_ptr, error); if (server_stream->sd->max_wire_version < WIRE_VERSION_4_4) { // Raise an error required by the specification: // "Drivers MUST manually raise an error if this option is specified // when creating an index on a pre 4.4 server." bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support the commitQuorum option"); GOTO (fail); } } // Build the createIndexes command. BSON_ASSERT (BSON_APPEND_UTF8 (&cmd, "createIndexes", collection->collection)); bson_array_builder_t *indexes; BSON_ASSERT (BSON_APPEND_ARRAY_BUILDER_BEGIN (&cmd, "indexes", &indexes)); for (uint32_t idx = 0; idx < n_models; idx++) { /* Append a document of this form: : { key: { , , ... }, name: , , , ... }, */ bson_t index; BSON_ASSERT (bson_array_builder_append_document_begin (indexes, &index)); BSON_ASSERT (BSON_APPEND_DOCUMENT (&index, "key", models[idx]->keys)); bson_iter_t name_iter; if (models[idx]->opts && bson_iter_init_find (&name_iter, models[idx]->opts, "name")) { // `name` was specified as an index option. } else { // No `name` was specified. Create index `name` from keys. char *name = mongoc_collection_keys_to_index_string (models[idx]->keys); BSON_ASSERT (name); BSON_ASSERT (BSON_APPEND_UTF8 (&index, "name", name)); bson_free (name); } if (models[idx]->opts) { BSON_ASSERT (bson_concat (&index, models[idx]->opts)); } BSON_ASSERT (bson_array_builder_append_document_end (indexes, &index)); } BSON_ASSERT (bson_append_array_builder_end (&cmd, indexes)); ok = mongoc_client_command_with_opts ( collection->client, collection->db, &cmd, NULL /* read_prefs */, opts, reply_ptr, error); fail: mongoc_server_stream_cleanup (server_stream); bson_destroy (&cmd); bson_destroy (&reply_local); return ok; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-collection.h0000644000175100001660000004173514760300420023304 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_COLLECTION_H #define MONGOC_COLLECTION_H #include #include #include #include #include #include #include #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_collection_t mongoc_collection_t; MONGOC_EXPORT (mongoc_cursor_t *) mongoc_collection_aggregate (mongoc_collection_t *collection, mongoc_query_flags_t flags, const bson_t *pipeline, const bson_t *opts, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_collection_destroy (mongoc_collection_t *collection); MONGOC_EXPORT (mongoc_collection_t *) mongoc_collection_copy (mongoc_collection_t *collection) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_cursor_t *) mongoc_collection_command (mongoc_collection_t *collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *command, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_collection_command_simple); MONGOC_EXPORT (bool) mongoc_collection_read_command_with_opts (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_write_command_with_opts ( mongoc_collection_t *collection, const bson_t *command, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_read_write_command_with_opts (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs /* IGNORED */, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_command_with_opts (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_command_simple (mongoc_collection_t *collection, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (int64_t) mongoc_collection_count (mongoc_collection_t *collection, mongoc_query_flags_t flags, const bson_t *query, int64_t skip, int64_t limit, const mongoc_read_prefs_t *read_prefs, bson_error_t *error) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_count_documents or mongoc_collection_estimated_document_count); MONGOC_EXPORT (int64_t) mongoc_collection_count_with_opts (mongoc_collection_t *collection, mongoc_query_flags_t flags, const bson_t *query, int64_t skip, int64_t limit, const bson_t *opts, const mongoc_read_prefs_t *read_prefs, bson_error_t *error) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_count_documents or mongoc_collection_estimated_document_count); MONGOC_EXPORT (bool) mongoc_collection_drop (mongoc_collection_t *collection, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_drop_with_opts (mongoc_collection_t *collection, const bson_t *opts, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_drop_index (mongoc_collection_t *collection, const char *index_name, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_drop_index_with_opts (mongoc_collection_t *collection, const char *index_name, const bson_t *opts, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_create_index (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (bool) mongoc_collection_create_index_with_opts (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, const bson_t *opts, bson_t *reply, bson_error_t *error) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (bool) mongoc_collection_ensure_index (mongoc_collection_t *collection, const bson_t *keys, const mongoc_index_opt_t *opt, bson_error_t *error) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (mongoc_cursor_t *) mongoc_collection_find_indexes (mongoc_collection_t *collection, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_collection_find_indexes_with_opts); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_collection_find_indexes_with_opts (mongoc_collection_t *collection, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; typedef struct _mongoc_index_model_t mongoc_index_model_t; MONGOC_EXPORT (mongoc_index_model_t *) mongoc_index_model_new (const bson_t *keys, const bson_t *opts); MONGOC_EXPORT (void) mongoc_index_model_destroy (mongoc_index_model_t *model); MONGOC_EXPORT (bool) mongoc_collection_create_indexes_with_opts (mongoc_collection_t *collection, mongoc_index_model_t *const *models, size_t n_models, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_collection_find (mongoc_collection_t *collection, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *query, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_find_with_opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_cursor_t *) mongoc_collection_find_with_opts (mongoc_collection_t *collection, const bson_t *filter, const bson_t *opts, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_collection_insert (mongoc_collection_t *collection, mongoc_insert_flags_t flags, const bson_t *document, const mongoc_write_concern_t *write_concern, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_insert_one ( mongoc_collection_t *collection, const bson_t *document, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_insert_many (mongoc_collection_t *collection, const bson_t **documents, size_t n_documents, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_insert_bulk (mongoc_collection_t *collection, mongoc_insert_flags_t flags, const bson_t **documents, uint32_t n_documents, const mongoc_write_concern_t *write_concern, bson_error_t *error) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_insert_many); MONGOC_EXPORT (bool) mongoc_collection_update (mongoc_collection_t *collection, mongoc_update_flags_t flags, const bson_t *selector, const bson_t *update, const mongoc_write_concern_t *write_concern, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_update_one (mongoc_collection_t *collection, const bson_t *selector, const bson_t *update, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_update_many (mongoc_collection_t *collection, const bson_t *selector, const bson_t *update, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_replace_one (mongoc_collection_t *collection, const bson_t *selector, const bson_t *replacement, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_delete (mongoc_collection_t *collection, mongoc_delete_flags_t flags, const bson_t *selector, const mongoc_write_concern_t *write_concern, bson_error_t *error) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_delete_one or mongoc_collection_delete_many); MONGOC_EXPORT (bool) mongoc_collection_save (mongoc_collection_t *collection, const bson_t *document, const mongoc_write_concern_t *write_concern, bson_error_t *error) BSON_GNUC_DEPRECATED_FOR (mongoc_collection_insert_one or mongoc_collection_replace_one); MONGOC_EXPORT (bool) mongoc_collection_remove (mongoc_collection_t *collection, mongoc_remove_flags_t flags, const bson_t *selector, const mongoc_write_concern_t *write_concern, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_delete_one ( mongoc_collection_t *collection, const bson_t *selector, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_delete_many ( mongoc_collection_t *collection, const bson_t *selector, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_rename (mongoc_collection_t *collection, const char *new_db, const char *new_name, bool drop_target_before_rename, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_rename_with_opts (mongoc_collection_t *collection, const char *new_db, const char *new_name, bool drop_target_before_rename, const bson_t *opts, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_find_and_modify_with_opts (mongoc_collection_t *collection, const bson_t *query, const mongoc_find_and_modify_opts_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_find_and_modify (mongoc_collection_t *collection, const bson_t *query, const bson_t *sort, const bson_t *update, const bson_t *fields, bool _remove, bool upsert, bool _new, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_collection_stats (mongoc_collection_t *collection, const bson_t *options, bson_t *reply, bson_error_t *error) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (mongoc_bulk_operation_t *) mongoc_collection_create_bulk_operation (mongoc_collection_t *collection, bool ordered, const mongoc_write_concern_t *write_concern) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_collection_create_bulk_operation_with_opts); MONGOC_EXPORT (mongoc_bulk_operation_t *) mongoc_collection_create_bulk_operation_with_opts (mongoc_collection_t *collection, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (const mongoc_read_prefs_t *) mongoc_collection_get_read_prefs (const mongoc_collection_t *collection); MONGOC_EXPORT (void) mongoc_collection_set_read_prefs (mongoc_collection_t *collection, const mongoc_read_prefs_t *read_prefs); MONGOC_EXPORT (const mongoc_read_concern_t *) mongoc_collection_get_read_concern (const mongoc_collection_t *collection); MONGOC_EXPORT (void) mongoc_collection_set_read_concern (mongoc_collection_t *collection, const mongoc_read_concern_t *read_concern); MONGOC_EXPORT (const mongoc_write_concern_t *) mongoc_collection_get_write_concern (const mongoc_collection_t *collection); MONGOC_EXPORT (void) mongoc_collection_set_write_concern (mongoc_collection_t *collection, const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (const char *) mongoc_collection_get_name (mongoc_collection_t *collection); MONGOC_EXPORT (const bson_t *) mongoc_collection_get_last_error (const mongoc_collection_t *collection) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (char *) mongoc_collection_keys_to_index_string (const bson_t *keys) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_collection_validate (mongoc_collection_t *collection, const bson_t *options, bson_t *reply, bson_error_t *error) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (mongoc_change_stream_t *) mongoc_collection_watch (const mongoc_collection_t *coll, const bson_t *pipeline, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (int64_t) mongoc_collection_count_documents (mongoc_collection_t *coll, const bson_t *filter, const bson_t *opts, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (int64_t) mongoc_collection_estimated_document_count (mongoc_collection_t *coll, const bson_t *opts, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_COLLECTION_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-compression-private.h0000644000175100001660000000351714760300420025156 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_COMPRESSION_PRIVATE_H #define MONGOC_COMPRESSION_PRIVATE_H #include /* Compressor IDs */ #define MONGOC_COMPRESSOR_NOOP_ID 0 #define MONGOC_COMPRESSOR_NOOP_STR "noop" #define MONGOC_COMPRESSOR_SNAPPY_ID 1 #define MONGOC_COMPRESSOR_SNAPPY_STR "snappy" #define MONGOC_COMPRESSOR_ZLIB_ID 2 #define MONGOC_COMPRESSOR_ZLIB_STR "zlib" #define MONGOC_COMPRESSOR_ZSTD_ID 3 #define MONGOC_COMPRESSOR_ZSTD_STR "zstd" BSON_BEGIN_DECLS size_t mongoc_compressor_max_compressed_length (int32_t compressor_id, size_t size); bool mongoc_compressor_supported (const char *compressor); const char * mongoc_compressor_id_to_name (int32_t compressor_id); int mongoc_compressor_name_to_id (const char *compressor); bool mongoc_uncompress (int32_t compressor_id, const uint8_t *compressed, size_t compressed_len, uint8_t *uncompressed, size_t *uncompressed_size); bool mongoc_compress (int32_t compressor_id, int32_t compression_level, char *uncompressed, size_t uncompressed_len, char *compressed, size_t *compressed_len); BSON_END_DECLS #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-compression.c0000644000175100001660000002027214760300420023476 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #ifdef MONGOC_ENABLE_COMPRESSION #ifdef MONGOC_ENABLE_COMPRESSION_ZLIB #include #endif #ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY #include #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZSTD #include #endif #endif size_t mongoc_compressor_max_compressed_length (int32_t compressor_id, size_t len) { TRACE ("Getting compression length for '%s' (%d)", mongoc_compressor_id_to_name (compressor_id), compressor_id); switch (compressor_id) { #ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY case MONGOC_COMPRESSOR_SNAPPY_ID: return snappy_max_compressed_length (len); #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZLIB case MONGOC_COMPRESSOR_ZLIB_ID: BSON_ASSERT (mcommon_in_range_unsigned (unsigned_long, len)); return compressBound ((unsigned long) len); #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZSTD case MONGOC_COMPRESSOR_ZSTD_ID: return ZSTD_compressBound (len); #endif case MONGOC_COMPRESSOR_NOOP_ID: return len; default: return 0; } } bool mongoc_compressor_supported (const char *compressor) { #ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY if (!strcasecmp (compressor, MONGOC_COMPRESSOR_SNAPPY_STR)) { return true; } #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZLIB if (!strcasecmp (compressor, MONGOC_COMPRESSOR_ZLIB_STR)) { return true; } #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZSTD if (!strcasecmp (compressor, MONGOC_COMPRESSOR_ZSTD_STR)) { return true; } #endif if (!strcasecmp (compressor, MONGOC_COMPRESSOR_NOOP_STR)) { return true; } return false; } const char * mongoc_compressor_id_to_name (int32_t compressor_id) { switch (compressor_id) { case MONGOC_COMPRESSOR_SNAPPY_ID: return MONGOC_COMPRESSOR_SNAPPY_STR; case MONGOC_COMPRESSOR_ZLIB_ID: return MONGOC_COMPRESSOR_ZLIB_STR; case MONGOC_COMPRESSOR_ZSTD_ID: return MONGOC_COMPRESSOR_ZSTD_STR; case MONGOC_COMPRESSOR_NOOP_ID: return MONGOC_COMPRESSOR_NOOP_STR; default: return "unknown"; } } int mongoc_compressor_name_to_id (const char *compressor) { #ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY if (strcasecmp (MONGOC_COMPRESSOR_SNAPPY_STR, compressor) == 0) { return MONGOC_COMPRESSOR_SNAPPY_ID; } #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZLIB if (strcasecmp (MONGOC_COMPRESSOR_ZLIB_STR, compressor) == 0) { return MONGOC_COMPRESSOR_ZLIB_ID; } #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZSTD if (strcasecmp (MONGOC_COMPRESSOR_ZSTD_STR, compressor) == 0) { return MONGOC_COMPRESSOR_ZSTD_ID; } #endif if (strcasecmp (MONGOC_COMPRESSOR_NOOP_STR, compressor) == 0) { return MONGOC_COMPRESSOR_NOOP_ID; } return -1; } // To support unchecked casts from `unsigned long` to `size_t`. BSON_STATIC_ASSERT2 (size_t_gte_ulong, SIZE_MAX >= ULONG_MAX); bool mongoc_uncompress (int32_t compressor_id, const uint8_t *compressed, size_t compressed_len, uint8_t *uncompressed, size_t *uncompressed_len) { BSON_ASSERT_PARAM (compressed); BSON_ASSERT_PARAM (uncompressed); BSON_ASSERT_PARAM (uncompressed_len); TRACE ("Uncompressing with '%s' (%d)", mongoc_compressor_id_to_name (compressor_id), compressor_id); switch (compressor_id) { case MONGOC_COMPRESSOR_SNAPPY_ID: { #ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY const snappy_status status = snappy_uncompress ((const char *) compressed, compressed_len, (char *) uncompressed, uncompressed_len); return status == SNAPPY_OK; #else MONGOC_WARNING ("Received snappy compressed opcode, but snappy " "compression is not compiled in"); return false; #endif } case MONGOC_COMPRESSOR_ZLIB_ID: { #ifdef MONGOC_ENABLE_COMPRESSION_ZLIB // Malformed message: unrepresentable. if (BSON_UNLIKELY (!mcommon_in_range_unsigned (unsigned_long, compressed_len))) { return false; } // Malformed message: unrepresentable. if (BSON_UNLIKELY (!mcommon_in_range_unsigned (unsigned_long, *uncompressed_len))) { return false; } uLong actual_uncompressed_len = (uLong) *uncompressed_len; const int res = uncompress (uncompressed, &actual_uncompressed_len, (const Bytef *) compressed, (uLong) compressed_len); if (BSON_UNLIKELY (res != Z_OK)) { return false; } *uncompressed_len = (size_t) actual_uncompressed_len; return true; #else MONGOC_WARNING ("Received zlib compressed opcode, but zlib " "compression is not compiled in"); return false; #endif } case MONGOC_COMPRESSOR_ZSTD_ID: { #ifdef MONGOC_ENABLE_COMPRESSION_ZSTD const size_t res = ZSTD_decompress (uncompressed, *uncompressed_len, compressed, compressed_len); if (BSON_UNLIKELY (ZSTD_isError (res))) { return false; } *uncompressed_len = res; return true; #else MONGOC_WARNING ("Received zstd compressed opcode, but zstd " "compression is not compiled in"); return false; #endif } case MONGOC_COMPRESSOR_NOOP_ID: // Malformed message: not enough space. if (BSON_UNLIKELY (*uncompressed_len < compressed_len)) { return false; } memcpy (uncompressed, compressed, compressed_len); *uncompressed_len = compressed_len; return true; default: MONGOC_WARNING ("Unknown compressor ID %d", compressor_id); } return false; } bool mongoc_compress (int32_t compressor_id, int32_t compression_level, char *uncompressed, size_t uncompressed_len, char *compressed, size_t *compressed_len) { TRACE ("Compressing with '%s' (%d)", mongoc_compressor_id_to_name (compressor_id), compressor_id); switch (compressor_id) { case MONGOC_COMPRESSOR_SNAPPY_ID: #ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY /* No compression_level option for snappy */ return snappy_compress (uncompressed, uncompressed_len, compressed, compressed_len) == SNAPPY_OK; #else MONGOC_ERROR ("Client attempting to use compress with snappy, but snappy " "compression is not compiled in"); return false; #endif case MONGOC_COMPRESSOR_ZLIB_ID: #ifdef MONGOC_ENABLE_COMPRESSION_ZLIB BSON_ASSERT (mcommon_in_range_unsigned (unsigned_long, uncompressed_len)); return compress2 ((unsigned char *) compressed, (unsigned long *) compressed_len, (unsigned char *) uncompressed, (unsigned long) uncompressed_len, compression_level) == Z_OK; #else MONGOC_ERROR ("Client attempting to use compress with zlib, but zlib " "compression is not compiled in"); return false; #endif case MONGOC_COMPRESSOR_ZSTD_ID: { #ifdef MONGOC_ENABLE_COMPRESSION_ZSTD int ok; ok = ZSTD_compress ((void *) compressed, *compressed_len, (const void *) uncompressed, uncompressed_len, 0); if (!ZSTD_isError (ok)) { *compressed_len = ok; } return !ZSTD_isError (ok); #else MONGOC_ERROR ("Client attempting to use compress with zstd, but zstd " "compression is not compiled in"); return false; #endif } case MONGOC_COMPRESSOR_NOOP_ID: memcpy (compressed, uncompressed, uncompressed_len); *compressed_len = uncompressed_len; return true; default: return false; } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config.h0000644000175100001660000002274014760300420022411 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(MONGOC_INSIDE) && !defined(MONGOC_COMPILATION) #error "Only can be included directly." #endif #ifndef MONGOC_CONFIG_H #define MONGOC_CONFIG_H /* clang-format off */ /* * NOTICE: * If you're about to update this file and add a config flag, make sure to * update: * o The bitfield in mongoc-handshake-private.h * o _mongoc_handshake_get_config_hex_string() in mongoc-handshake.c * o examples/parse_handshake_cfg.py * o test_handshake_platform_config in test-mongoc-handshake.c */ /* MONGOC_USER_SET_CFLAGS is set from config based on what compiler flags were * used to compile mongoc */ #define MONGOC_USER_SET_CFLAGS "" #define MONGOC_USER_SET_LDFLAGS "" /* MONGOC_CC is used to determine what C compiler was used to compile mongoc */ #define MONGOC_CC "cc" /* * MONGOC_ENABLE_SSL_SECURE_CHANNEL is set from configure to determine if we are * compiled with Native SSL support on Windows */ #define MONGOC_ENABLE_SSL_SECURE_CHANNEL 0 #if MONGOC_ENABLE_SSL_SECURE_CHANNEL != 1 # undef MONGOC_ENABLE_SSL_SECURE_CHANNEL #endif /* * MONGOC_ENABLE_CRYPTO_CNG is set from configure to determine if we are * compiled with Native Crypto support on Windows */ #define MONGOC_ENABLE_CRYPTO_CNG 0 #if MONGOC_ENABLE_CRYPTO_CNG != 1 # undef MONGOC_ENABLE_CRYPTO_CNG #endif /* * MONGOC_HAVE_BCRYPT_PBKDF2 is set from configure to determine if * our Bcrypt Windows library supports PBKDF2 */ #define MONGOC_HAVE_BCRYPT_PBKDF2 0 #if MONGOC_HAVE_BCRYPT_PBKDF2 != 1 # undef MONGOC_HAVE_BCRYPT_PBKDF2 #endif /* * MONGOC_ENABLE_SSL_SECURE_TRANSPORT is set from configure to determine if we are * compiled with Native SSL support on Darwin */ #define MONGOC_ENABLE_SSL_SECURE_TRANSPORT 0 #if MONGOC_ENABLE_SSL_SECURE_TRANSPORT != 1 # undef MONGOC_ENABLE_SSL_SECURE_TRANSPORT #endif /* * MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO is set from configure to determine if we are * compiled with Native Crypto support on Darwin */ #define MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO 0 #if MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO != 1 # undef MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO #endif /* * MONGOC_ENABLE_SSL_LIBRESSL is set from configure to determine if we are * compiled with LibreSSL support. */ #define MONGOC_ENABLE_SSL_LIBRESSL 0 #if MONGOC_ENABLE_SSL_LIBRESSL != 1 # undef MONGOC_ENABLE_SSL_LIBRESSL #endif /* * MONGOC_ENABLE_SSL_OPENSSL is set from configure to determine if we are * compiled with OpenSSL support. */ #define MONGOC_ENABLE_SSL_OPENSSL 1 #if MONGOC_ENABLE_SSL_OPENSSL != 1 # undef MONGOC_ENABLE_SSL_OPENSSL #endif /* * MONGOC_ENABLE_CRYPTO_LIBCRYPTO is set from configure to determine if we are * compiled with OpenSSL support. */ #define MONGOC_ENABLE_CRYPTO_LIBCRYPTO 1 #if MONGOC_ENABLE_CRYPTO_LIBCRYPTO != 1 # undef MONGOC_ENABLE_CRYPTO_LIBCRYPTO #endif /* * MONGOC_ENABLE_SSL is set from configure to determine if we are * compiled with any SSL support. */ #define MONGOC_ENABLE_SSL 1 #if MONGOC_ENABLE_SSL != 1 # undef MONGOC_ENABLE_SSL #endif /* * MONGOC_ENABLE_CRYPTO is set from configure to determine if we are * compiled with any crypto support. */ #define MONGOC_ENABLE_CRYPTO 1 #if MONGOC_ENABLE_CRYPTO != 1 # undef MONGOC_ENABLE_CRYPTO #endif /* * Use system crypto profile */ #define MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE 0 #if MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE != 1 # undef MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE #endif /* * Use ASN1_STRING_get0_data () rather than the deprecated ASN1_STRING_data */ #define MONGOC_HAVE_ASN1_STRING_GET0_DATA 1 #if MONGOC_HAVE_ASN1_STRING_GET0_DATA != 1 # undef MONGOC_HAVE_ASN1_STRING_GET0_DATA #endif /* * MONGOC_ENABLE_SASL is set from configure to determine if we are * compiled with SASL support. */ #define MONGOC_ENABLE_SASL 0 #if MONGOC_ENABLE_SASL != 1 # undef MONGOC_ENABLE_SASL #endif /* * MONGOC_ENABLE_SASL_CYRUS is set from configure to determine if we are * compiled with Cyrus SASL support. */ #define MONGOC_ENABLE_SASL_CYRUS 0 #if MONGOC_ENABLE_SASL_CYRUS != 1 # undef MONGOC_ENABLE_SASL_CYRUS #endif /* * MONGOC_ENABLE_SASL_SSPI is set from configure to determine if we are * compiled with SSPI support. */ #define MONGOC_ENABLE_SASL_SSPI 0 #if MONGOC_ENABLE_SASL_SSPI != 1 # undef MONGOC_ENABLE_SASL_SSPI #endif /* * MONGOC_HAVE_SASL_CLIENT_DONE is set from configure to determine if we * have SASL and its version is new enough to use sasl_client_done (), * which supersedes sasl_done (). */ #define MONGOC_HAVE_SASL_CLIENT_DONE 0 #if MONGOC_HAVE_SASL_CLIENT_DONE != 1 # undef MONGOC_HAVE_SASL_CLIENT_DONE #endif /* * Disable automatic calls to mongoc_init() and mongoc_cleanup() * before main() is called, and after exit() (respectively). */ #define MONGOC_NO_AUTOMATIC_GLOBALS 1 #if MONGOC_NO_AUTOMATIC_GLOBALS != 1 # undef MONGOC_NO_AUTOMATIC_GLOBALS #endif /* * MONGOC_HAVE_SOCKLEN is set from configure to determine if we * need to emulate the type. */ #define MONGOC_HAVE_SOCKLEN 1 #if MONGOC_HAVE_SOCKLEN != 1 # undef MONGOC_HAVE_SOCKLEN #endif /** * @brief Defined to 0/1 for whether we were configured with ENABLE_SRV */ #define MONGOC_ENABLE_SRV 1 /* * MONGOC_HAVE_DNSAPI is set from configure to determine if we should use the * Windows dnsapi for SRV record lookups. */ #define MONGOC_HAVE_DNSAPI 0 #if MONGOC_HAVE_DNSAPI != 1 # undef MONGOC_HAVE_DNSAPI #endif /* * MONGOC_HAVE_RES_NSEARCH is set from configure to determine if we * have thread-safe res_nsearch(). */ #define MONGOC_HAVE_RES_NSEARCH 1 #if MONGOC_HAVE_RES_NSEARCH != 1 # undef MONGOC_HAVE_RES_NSEARCH #endif /* * MONGOC_HAVE_RES_NDESTROY is set from configure to determine if we * have BSD / Darwin's res_ndestroy(). */ #define MONGOC_HAVE_RES_NDESTROY 0 #if MONGOC_HAVE_RES_NDESTROY != 1 # undef MONGOC_HAVE_RES_NDESTROY #endif /* * MONGOC_HAVE_RES_NCLOSE is set from configure to determine if we * have Linux's res_nclose(). */ #define MONGOC_HAVE_RES_NCLOSE 1 #if MONGOC_HAVE_RES_NCLOSE != 1 # undef MONGOC_HAVE_RES_NCLOSE #endif /* * MONGOC_HAVE_RES_SEARCH is set from configure to determine if we * have thread-unsafe res_search(). It's unset if we have the preferred * res_nsearch(). */ #define MONGOC_HAVE_RES_SEARCH 0 #if MONGOC_HAVE_RES_SEARCH != 1 # undef MONGOC_HAVE_RES_SEARCH #endif /* * Set from configure, see * https://curl.haxx.se/mail/lib-2009-04/0287.html */ #define MONGOC_SOCKET_ARG2 struct sockaddr #define MONGOC_SOCKET_ARG3 socklen_t /* * Enable wire protocol compression negotiation * */ #define MONGOC_ENABLE_COMPRESSION 1 #if MONGOC_ENABLE_COMPRESSION != 1 # undef MONGOC_ENABLE_COMPRESSION #endif /* * Set if we have snappy compression support * */ #define MONGOC_ENABLE_COMPRESSION_SNAPPY 0 #if MONGOC_ENABLE_COMPRESSION_SNAPPY != 1 # undef MONGOC_ENABLE_COMPRESSION_SNAPPY #endif /* * Set if we have zlib compression support * */ #define MONGOC_ENABLE_COMPRESSION_ZLIB 1 #if MONGOC_ENABLE_COMPRESSION_ZLIB != 1 # undef MONGOC_ENABLE_COMPRESSION_ZLIB #endif /* * Set if we have zstd compression support * */ #define MONGOC_ENABLE_COMPRESSION_ZSTD 1 #if MONGOC_ENABLE_COMPRESSION_ZSTD != 1 # undef MONGOC_ENABLE_COMPRESSION_ZSTD #endif /* * Set if performance counters are available and not disabled. * */ #define MONGOC_ENABLE_SHM_COUNTERS 0 #if MONGOC_ENABLE_SHM_COUNTERS != 1 # undef MONGOC_ENABLE_SHM_COUNTERS #endif /* * Set if we have enabled fast counters on Intel using the RDTSCP instruction * */ #define MONGOC_ENABLE_RDTSCP 0 #if MONGOC_ENABLE_RDTSCP != 1 # undef MONGOC_ENABLE_RDTSCP #endif /* * Set if we have the sched_getcpu() function for use with counters * */ #define MONGOC_HAVE_SCHED_GETCPU 1 #if MONGOC_HAVE_SCHED_GETCPU != 1 # undef MONGOC_HAVE_SCHED_GETCPU #endif /* * Set if tracing is enabled. Logs things like network communication and * entry/exit of certain functions. */ #define MONGOC_TRACE 1 /* * Set if we have Client Side Encryption support. */ #define MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION 1 #if MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION != 1 # undef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION #endif /* * Set if struct sockaddr_storage has __ss_family (instead of ss_family) */ #define MONGOC_HAVE_SS_FAMILY 1 #if MONGOC_HAVE_SS_FAMILY != 1 # undef MONGOC_HAVE_SS_FAMILY #endif /* * Set if building with AWS IAM support. */ #define MONGOC_ENABLE_MONGODB_AWS_AUTH 1 #if MONGOC_ENABLE_MONGODB_AWS_AUTH != 1 # undef MONGOC_ENABLE_MONGODB_AWS_AUTH #endif enum { /** * @brief Compile-time constant determining whether the mongoc library was * compiled with tracing enabled. * * Can be controlled with the “ENABLE_TRACING†configure-time boolean option */ MONGOC_TRACE_ENABLED = MONGOC_TRACE, /** * @brief Compile-time constant indicating whether the mongoc library was * compiled with SRV server discovery support. * * Can be controled with the “ENABLE_SRV†configure-time boolean option. */ MONGOC_SRV_ENABLED = MONGOC_ENABLE_SRV, }; /* clang-format on */ #endif /* MONGOC_CONFIG_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config.h.in0000644000175100001660000002470314760300420023017 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(MONGOC_INSIDE) && !defined(MONGOC_COMPILATION) #error "Only can be included directly." #endif #ifndef MONGOC_CONFIG_H #define MONGOC_CONFIG_H /* clang-format off */ /* * NOTICE: * If you're about to update this file and add a config flag, make sure to * update: * o The bitfield in mongoc-handshake-private.h * o _mongoc_handshake_get_config_hex_string() in mongoc-handshake.c * o examples/parse_handshake_cfg.py * o test_handshake_platform_config in test-mongoc-handshake.c */ /* MONGOC_USER_SET_CFLAGS is set from config based on what compiler flags were * used to compile mongoc */ #define MONGOC_USER_SET_CFLAGS "@MONGOC_USER_SET_CFLAGS@" #define MONGOC_USER_SET_LDFLAGS "@MONGOC_USER_SET_LDFLAGS@" /* MONGOC_CC is used to determine what C compiler was used to compile mongoc */ #define MONGOC_CC "@MONGOC_CC@" /* * MONGOC_ENABLE_SSL_SECURE_CHANNEL is set from configure to determine if we are * compiled with Native SSL support on Windows */ #define MONGOC_ENABLE_SSL_SECURE_CHANNEL @MONGOC_ENABLE_SSL_SECURE_CHANNEL@ #if MONGOC_ENABLE_SSL_SECURE_CHANNEL != 1 # undef MONGOC_ENABLE_SSL_SECURE_CHANNEL #endif /* * MONGOC_ENABLE_CRYPTO_CNG is set from configure to determine if we are * compiled with Native Crypto support on Windows */ #define MONGOC_ENABLE_CRYPTO_CNG @MONGOC_ENABLE_CRYPTO_CNG@ #if MONGOC_ENABLE_CRYPTO_CNG != 1 # undef MONGOC_ENABLE_CRYPTO_CNG #endif /* * MONGOC_HAVE_BCRYPT_PBKDF2 is set from configure to determine if * our Bcrypt Windows library supports PBKDF2 */ #define MONGOC_HAVE_BCRYPT_PBKDF2 @MONGOC_HAVE_BCRYPT_PBKDF2@ #if MONGOC_HAVE_BCRYPT_PBKDF2 != 1 # undef MONGOC_HAVE_BCRYPT_PBKDF2 #endif /* * MONGOC_ENABLE_SSL_SECURE_TRANSPORT is set from configure to determine if we are * compiled with Native SSL support on Darwin */ #define MONGOC_ENABLE_SSL_SECURE_TRANSPORT @MONGOC_ENABLE_SSL_SECURE_TRANSPORT@ #if MONGOC_ENABLE_SSL_SECURE_TRANSPORT != 1 # undef MONGOC_ENABLE_SSL_SECURE_TRANSPORT #endif /* * MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO is set from configure to determine if we are * compiled with Native Crypto support on Darwin */ #define MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO @MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO@ #if MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO != 1 # undef MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO #endif /* * MONGOC_ENABLE_SSL_LIBRESSL is set from configure to determine if we are * compiled with LibreSSL support. */ #define MONGOC_ENABLE_SSL_LIBRESSL @MONGOC_ENABLE_SSL_LIBRESSL@ #if MONGOC_ENABLE_SSL_LIBRESSL != 1 # undef MONGOC_ENABLE_SSL_LIBRESSL #endif /* * MONGOC_ENABLE_SSL_OPENSSL is set from configure to determine if we are * compiled with OpenSSL support. */ #define MONGOC_ENABLE_SSL_OPENSSL @MONGOC_ENABLE_SSL_OPENSSL@ #if MONGOC_ENABLE_SSL_OPENSSL != 1 # undef MONGOC_ENABLE_SSL_OPENSSL #endif /* * MONGOC_ENABLE_CRYPTO_LIBCRYPTO is set from configure to determine if we are * compiled with OpenSSL support. */ #define MONGOC_ENABLE_CRYPTO_LIBCRYPTO @MONGOC_ENABLE_CRYPTO_LIBCRYPTO@ #if MONGOC_ENABLE_CRYPTO_LIBCRYPTO != 1 # undef MONGOC_ENABLE_CRYPTO_LIBCRYPTO #endif /* * MONGOC_ENABLE_SSL is set from configure to determine if we are * compiled with any SSL support. */ #define MONGOC_ENABLE_SSL @MONGOC_ENABLE_SSL@ #if MONGOC_ENABLE_SSL != 1 # undef MONGOC_ENABLE_SSL #endif /* * MONGOC_ENABLE_CRYPTO is set from configure to determine if we are * compiled with any crypto support. */ #define MONGOC_ENABLE_CRYPTO @MONGOC_ENABLE_CRYPTO@ #if MONGOC_ENABLE_CRYPTO != 1 # undef MONGOC_ENABLE_CRYPTO #endif /* * Use system crypto profile */ #define MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE @MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE@ #if MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE != 1 # undef MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE #endif /* * Use ASN1_STRING_get0_data () rather than the deprecated ASN1_STRING_data */ #define MONGOC_HAVE_ASN1_STRING_GET0_DATA @MONGOC_HAVE_ASN1_STRING_GET0_DATA@ #if MONGOC_HAVE_ASN1_STRING_GET0_DATA != 1 # undef MONGOC_HAVE_ASN1_STRING_GET0_DATA #endif /* * MONGOC_ENABLE_SASL is set from configure to determine if we are * compiled with SASL support. */ #define MONGOC_ENABLE_SASL @MONGOC_ENABLE_SASL@ #if MONGOC_ENABLE_SASL != 1 # undef MONGOC_ENABLE_SASL #endif /* * MONGOC_ENABLE_SASL_CYRUS is set from configure to determine if we are * compiled with Cyrus SASL support. */ #define MONGOC_ENABLE_SASL_CYRUS @MONGOC_ENABLE_SASL_CYRUS@ #if MONGOC_ENABLE_SASL_CYRUS != 1 # undef MONGOC_ENABLE_SASL_CYRUS #endif /* * MONGOC_ENABLE_SASL_SSPI is set from configure to determine if we are * compiled with SSPI support. */ #define MONGOC_ENABLE_SASL_SSPI @MONGOC_ENABLE_SASL_SSPI@ #if MONGOC_ENABLE_SASL_SSPI != 1 # undef MONGOC_ENABLE_SASL_SSPI #endif /* * MONGOC_HAVE_SASL_CLIENT_DONE is set from configure to determine if we * have SASL and its version is new enough to use sasl_client_done (), * which supersedes sasl_done (). */ #define MONGOC_HAVE_SASL_CLIENT_DONE @MONGOC_HAVE_SASL_CLIENT_DONE@ #if MONGOC_HAVE_SASL_CLIENT_DONE != 1 # undef MONGOC_HAVE_SASL_CLIENT_DONE #endif /* * Disable automatic calls to mongoc_init() and mongoc_cleanup() * before main() is called, and after exit() (respectively). */ #define MONGOC_NO_AUTOMATIC_GLOBALS @MONGOC_NO_AUTOMATIC_GLOBALS@ #if MONGOC_NO_AUTOMATIC_GLOBALS != 1 # undef MONGOC_NO_AUTOMATIC_GLOBALS #endif /* * MONGOC_HAVE_SOCKLEN is set from configure to determine if we * need to emulate the type. */ #define MONGOC_HAVE_SOCKLEN @MONGOC_HAVE_SOCKLEN@ #if MONGOC_HAVE_SOCKLEN != 1 # undef MONGOC_HAVE_SOCKLEN #endif /** * @brief Defined to 0/1 for whether we were configured with ENABLE_SRV */ #define MONGOC_ENABLE_SRV @MONGOC_ENABLE_SRV@ /* * MONGOC_HAVE_DNSAPI is set from configure to determine if we should use the * Windows dnsapi for SRV record lookups. */ #define MONGOC_HAVE_DNSAPI @MONGOC_HAVE_DNSAPI@ #if MONGOC_HAVE_DNSAPI != 1 # undef MONGOC_HAVE_DNSAPI #endif /* * MONGOC_HAVE_RES_NSEARCH is set from configure to determine if we * have thread-safe res_nsearch(). */ #define MONGOC_HAVE_RES_NSEARCH @MONGOC_HAVE_RES_NSEARCH@ #if MONGOC_HAVE_RES_NSEARCH != 1 # undef MONGOC_HAVE_RES_NSEARCH #endif /* * MONGOC_HAVE_RES_NDESTROY is set from configure to determine if we * have BSD / Darwin's res_ndestroy(). */ #define MONGOC_HAVE_RES_NDESTROY @MONGOC_HAVE_RES_NDESTROY@ #if MONGOC_HAVE_RES_NDESTROY != 1 # undef MONGOC_HAVE_RES_NDESTROY #endif /* * MONGOC_HAVE_RES_NCLOSE is set from configure to determine if we * have Linux's res_nclose(). */ #define MONGOC_HAVE_RES_NCLOSE @MONGOC_HAVE_RES_NCLOSE@ #if MONGOC_HAVE_RES_NCLOSE != 1 # undef MONGOC_HAVE_RES_NCLOSE #endif /* * MONGOC_HAVE_RES_SEARCH is set from configure to determine if we * have thread-unsafe res_search(). It's unset if we have the preferred * res_nsearch(). */ #define MONGOC_HAVE_RES_SEARCH @MONGOC_HAVE_RES_SEARCH@ #if MONGOC_HAVE_RES_SEARCH != 1 # undef MONGOC_HAVE_RES_SEARCH #endif /* * Set from configure, see * https://curl.haxx.se/mail/lib-2009-04/0287.html */ #define MONGOC_SOCKET_ARG2 @MONGOC_SOCKET_ARG2@ #define MONGOC_SOCKET_ARG3 @MONGOC_SOCKET_ARG3@ /* * Enable wire protocol compression negotiation * */ #define MONGOC_ENABLE_COMPRESSION @MONGOC_ENABLE_COMPRESSION@ #if MONGOC_ENABLE_COMPRESSION != 1 # undef MONGOC_ENABLE_COMPRESSION #endif /* * Set if we have snappy compression support * */ #define MONGOC_ENABLE_COMPRESSION_SNAPPY @MONGOC_ENABLE_COMPRESSION_SNAPPY@ #if MONGOC_ENABLE_COMPRESSION_SNAPPY != 1 # undef MONGOC_ENABLE_COMPRESSION_SNAPPY #endif /* * Set if we have zlib compression support * */ #define MONGOC_ENABLE_COMPRESSION_ZLIB @MONGOC_ENABLE_COMPRESSION_ZLIB@ #if MONGOC_ENABLE_COMPRESSION_ZLIB != 1 # undef MONGOC_ENABLE_COMPRESSION_ZLIB #endif /* * Set if we have zstd compression support * */ #define MONGOC_ENABLE_COMPRESSION_ZSTD @MONGOC_ENABLE_COMPRESSION_ZSTD@ #if MONGOC_ENABLE_COMPRESSION_ZSTD != 1 # undef MONGOC_ENABLE_COMPRESSION_ZSTD #endif /* * Set if performance counters are available and not disabled. * */ #define MONGOC_ENABLE_SHM_COUNTERS @MONGOC_ENABLE_SHM_COUNTERS@ #if MONGOC_ENABLE_SHM_COUNTERS != 1 # undef MONGOC_ENABLE_SHM_COUNTERS #endif /* * Set if we have enabled fast counters on Intel using the RDTSCP instruction * */ #define MONGOC_ENABLE_RDTSCP @MONGOC_ENABLE_RDTSCP@ #if MONGOC_ENABLE_RDTSCP != 1 # undef MONGOC_ENABLE_RDTSCP #endif /* * Set if we have the sched_getcpu() function for use with counters * */ #define MONGOC_HAVE_SCHED_GETCPU @MONGOC_HAVE_SCHED_GETCPU@ #if MONGOC_HAVE_SCHED_GETCPU != 1 # undef MONGOC_HAVE_SCHED_GETCPU #endif /* * Set if tracing is enabled. Logs things like network communication and * entry/exit of certain functions. */ #define MONGOC_TRACE @MONGOC_TRACE@ /* * Set if we have Client Side Encryption support. */ #define MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION @MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION@ #if MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION != 1 # undef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION #endif /* * Set if struct sockaddr_storage has __ss_family (instead of ss_family) */ #define MONGOC_HAVE_SS_FAMILY @MONGOC_HAVE_SS_FAMILY@ #if MONGOC_HAVE_SS_FAMILY != 1 # undef MONGOC_HAVE_SS_FAMILY #endif /* * Set if building with AWS IAM support. */ #define MONGOC_ENABLE_MONGODB_AWS_AUTH @MONGOC_ENABLE_MONGODB_AWS_AUTH@ #if MONGOC_ENABLE_MONGODB_AWS_AUTH != 1 # undef MONGOC_ENABLE_MONGODB_AWS_AUTH #endif enum { /** * @brief Compile-time constant determining whether the mongoc library was * compiled with tracing enabled. * * Can be controlled with the “ENABLE_TRACING†configure-time boolean option */ MONGOC_TRACE_ENABLED = MONGOC_TRACE, /** * @brief Compile-time constant indicating whether the mongoc library was * compiled with SRV server discovery support. * * Can be controled with the “ENABLE_SRV†configure-time boolean option. */ MONGOC_SRV_ENABLED = MONGOC_ENABLE_SRV, }; /* clang-format on */ #endif /* MONGOC_CONFIG_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-counters-private.h0000644000175100001660000002174414760300420024461 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_COUNTERS_PRIVATE_H #define MONGOC_COUNTERS_PRIVATE_H #include #include #include #ifdef __linux__ #include #include #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) #include #include #include #include #elif defined(__hpux__) #include #endif BSON_BEGIN_DECLS void _mongoc_counters_init (void); void _mongoc_counters_cleanup (void); static BSON_INLINE unsigned _mongoc_get_cpu_count (void) { #if defined(__linux__) && defined(_SC_NPROCESSORS_CONF) long count = sysconf (_SC_NPROCESSORS_CONF); if (count < 1) { return 1; } return count; #elif defined(__hpux__) struct pst_dynamic psd; if (pstat_getdynamic (&psd, sizeof (psd), (size_t) 1, 0) != -1) { return psd.psd_max_proc_cnt; } return 1; #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) int mib[2]; int maxproc; size_t len; mib[0] = CTL_HW; mib[1] = HW_NCPU; len = sizeof (maxproc); if (-1 == sysctl (mib, 2, &maxproc, &len, NULL, 0)) { return 1; } return len; #elif defined(__APPLE__) || defined(_AIX) int ncpu; ncpu = (int) sysconf (_SC_NPROCESSORS_ONLN); return (ncpu > 0) ? ncpu : 1; #elif defined(_MSC_VER) || defined(_WIN32) SYSTEM_INFO si; GetSystemInfo (&si); return si.dwNumberOfProcessors; #else #warning "_mongoc_get_cpu_count() not supported, defaulting to 1." return 1; #endif } #if defined(MONGOC_ENABLE_RDTSCP) static BSON_INLINE unsigned _mongoc_sched_getcpu (void) { volatile uint32_t rax, rdx, rcx; __asm__ volatile ("rdtscp\n" : "=a"(rax), "=d"(rdx), "=c"(rcx) : :); unsigned core_id; core_id = rcx & 0xFFF; return core_id; } #elif defined(MONGOC_HAVE_SCHED_GETCPU) #define _mongoc_sched_getcpu sched_getcpu #elif defined(__APPLE__) && defined(__aarch64__) static BSON_INLINE unsigned _mongoc_sched_getcpu (void) { uintptr_t tls; unsigned core_id; /* Get the current thread ID, not the core ID. * Getting the core ID requires privileged execution. */ __asm__ volatile ("mrs %x0, tpidrro_el0" : "=r"(tls)); /* In ARM, only 8 cores are manageable. */ core_id = tls & 0x07u; return core_id; } #else #define _mongoc_sched_getcpu() (0) #endif #ifndef SLOTS_PER_CACHELINE #define SLOTS_PER_CACHELINE 8 #endif typedef struct { int64_t slots[SLOTS_PER_CACHELINE]; } mongoc_counter_slots_t; typedef struct { mongoc_counter_slots_t *cpus; } mongoc_counter_t; #define COUNTER(ident, Category, Name, Description) extern mongoc_counter_t __mongoc_counter_##ident; #include #undef COUNTER enum { #define COUNTER(ident, Category, Name, Description) COUNTER_##ident, #include #undef COUNTER LAST_COUNTER }; #ifdef MONGOC_ENABLE_SHM_COUNTERS #define COUNTER(ident, Category, Name, Description) \ static BSON_INLINE void mongoc_counter_##ident##_add (int64_t val) \ { \ int64_t *counter = &BSON_CONCAT (__mongoc_counter_, ident) \ .cpus[_mongoc_sched_getcpu ()] \ .slots[BSON_CONCAT (COUNTER_, ident) % SLOTS_PER_CACHELINE]; \ mcommon_atomic_int64_fetch_add (counter, val, mcommon_memory_order_seq_cst); \ } \ static BSON_INLINE void mongoc_counter_##ident##_inc (void) \ { \ mongoc_counter_##ident##_add (1); \ } \ static BSON_INLINE void mongoc_counter_##ident##_dec (void) \ { \ mongoc_counter_##ident##_add (-1); \ } \ static BSON_INLINE void mongoc_counter_##ident##_reset (void) \ { \ uint32_t i; \ for (i = 0; i < _mongoc_get_cpu_count (); i++) { \ int64_t *counter = &__mongoc_counter_##ident.cpus[i].slots[COUNTER_##ident % SLOTS_PER_CACHELINE]; \ mcommon_atomic_int64_exchange (counter, 0, mcommon_memory_order_seq_cst); \ } \ mcommon_atomic_thread_fence (); \ } \ static BSON_INLINE int32_t mongoc_counter_##ident##_count (void) \ { \ int32_t _sum = 0; \ uint32_t _i; \ for (_i = 0; _i < _mongoc_get_cpu_count (); _i++) { \ const int64_t *counter = &BSON_CONCAT (__mongoc_counter_, ident) \ .cpus[_i] \ .slots[BSON_CONCAT (COUNTER_, ident) % SLOTS_PER_CACHELINE]; \ _sum += mcommon_atomic_int64_fetch (counter, mcommon_memory_order_seq_cst); \ } \ return _sum; \ } #include #undef COUNTER #else /* when counters are disabled, these functions are no-ops */ #define COUNTER(ident, Category, Name, Description) \ static BSON_INLINE void mongoc_counter_##ident##_add (BSON_MAYBE_UNUSED int64_t val) \ { \ } \ static BSON_INLINE void mongoc_counter_##ident##_inc (void) \ { \ } \ static BSON_INLINE void mongoc_counter_##ident##_dec (void) \ { \ } \ static BSON_INLINE void mongoc_counter_##ident##_reset (void) \ { \ } \ static BSON_INLINE void mongoc_counter_##ident##_count (void) \ { \ } #include #undef COUNTER #endif BSON_END_DECLS #endif /* MONGOC_COUNTERS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-counters.c0000644000175100001660000002017114760300420022775 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #ifdef BSON_OS_UNIX #include #include #include #endif #ifdef _MSC_VER #include #endif #include #include #include #pragma pack(1) typedef struct { uint32_t offset; uint32_t slot; char category[24]; char name[32]; char description[64]; } mongoc_counter_info_t; #pragma pack() BSON_STATIC_ASSERT2 (counter_info_t, sizeof (mongoc_counter_info_t) == 128); #pragma pack(1) typedef struct { uint32_t size; uint32_t n_cpu; uint32_t n_counters; uint32_t infos_offset; uint32_t values_offset; uint8_t padding[44]; } mongoc_counters_t; #pragma pack() BSON_STATIC_ASSERT2 (counters_t, sizeof (mongoc_counters_t) == 64); #ifdef MONGOC_ENABLE_SHM_COUNTERS /* When counters are enabled at compile time but fail to initiate a shared * memory segment, then fall back to a malloc'd segment. This malloc'd segment * isn't useful to anyone. But by using this fallback, the counter increment * functions can behave the same. I.e. they do not need to have a runtime check * for whether or not initiating the shared memory segment succeeded. */ static void *gCounterFallback = NULL; #define COUNTER(ident, Category, Name, Description) mongoc_counter_t __mongoc_counter_##ident; #include #undef COUNTER /** * mongoc_counters_use_shm: * * Checks to see if counters should be exported over a shared memory segment. * * Returns: true if SHM is to be used. */ static bool mongoc_counters_use_shm (void) { return !getenv ("MONGOC_DISABLE_SHM"); } /** * mongoc_counters_calc_size: * * Returns the number of bytes required for the shared memory segment of * the process. This segment contains the various statistical counters for * the process. * * Returns: The number of bytes required. */ static size_t mongoc_counters_calc_size (void) { size_t n_cpu; size_t n_groups; size_t size; n_cpu = _mongoc_get_cpu_count (); n_groups = (LAST_COUNTER / SLOTS_PER_CACHELINE) + 1; size = (sizeof (mongoc_counters_t) + (LAST_COUNTER * sizeof (mongoc_counter_info_t)) + (n_cpu * n_groups * sizeof (mongoc_counter_slots_t))); #ifdef BSON_OS_UNIX return BSON_MAX (sysconf (_SC_PAGESIZE), size); #else return size; #endif } #endif /** * mongoc_counters_destroy: * * Removes the shared memory segment for the current processes counters. */ void _mongoc_counters_cleanup (void) { #ifdef MONGOC_ENABLE_SHM_COUNTERS if (gCounterFallback) { bson_free (gCounterFallback); gCounterFallback = NULL; #if defined(BSON_OS_UNIX) && defined(MONGOC_ENABLE_SHM_COUNTERS) } else { char name[32]; int pid; pid = getpid (); // Truncation is OK. int req = bson_snprintf (name, sizeof name, "/mongoc-%d", pid); BSON_ASSERT (req > 0); shm_unlink (name); #endif } #endif } #ifdef MONGOC_ENABLE_SHM_COUNTERS /** * mongoc_counters_alloc: * @size: The size of the shared memory segment. * * This function allocates the shared memory segment for use by counters * within the process. * * Returns: A shared memory segment, or malloc'd memory on failure. */ static void * mongoc_counters_alloc (size_t size) { #if defined(BSON_OS_UNIX) && defined(MONGOC_ENABLE_SHM_COUNTERS) void *mem; char name[32]; int pid; int fd; if (!mongoc_counters_use_shm ()) { goto skip_shm; } pid = getpid (); // Truncation is OK. int req = bson_snprintf (name, sizeof name, "/mongoc-%d", pid); BSON_ASSERT (req > 0); #ifndef O_NOFOLLOW #define O_NOFOLLOW 0 #endif if (-1 == (fd = shm_open (name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR | O_NOFOLLOW))) { goto fail_noclean; } #if defined(__APPLE__) // macOS does not have posix_fallocate available. if (-1 == ftruncate (fd, size)) { goto fail_cleanup; } #else // Prefer posix_fallocate on Linux. posix_fallocate ensures that disk space // is allocated. if (0 != posix_fallocate (fd, 0, size)) { goto fail_cleanup; } #endif // __APPLE__ mem = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { goto fail_cleanup; } close (fd); memset (mem, 0, size); return mem; fail_cleanup: shm_unlink (name); close (fd); fail_noclean: MONGOC_WARNING ("Falling back to malloc for counters."); skip_shm: #endif gCounterFallback = (void *) bson_malloc0 (size); return gCounterFallback; } /** * mongoc_counters_register: * @counters: A mongoc_counter_t. * @num: The counter number. * @category: The counter category. * @name: THe counter name. * @description The counter description. * * Registers a new counter in the memory segment for counters. If the counters * are exported over shared memory, it will be made available. * * Returns: The offset to the data for the counters values. */ static size_t mongoc_counters_register ( mongoc_counters_t *counters, uint32_t num, const char *category, const char *name, const char *description) { mongoc_counter_info_t *infos; char *segment; int n_cpu; BSON_ASSERT (counters); BSON_ASSERT (category); BSON_ASSERT (name); BSON_ASSERT (description); /* * Implementation Note: * * The memory barrier is required so that all of the above has been * completed. Then increment the n_counters so that a reading application * only knows about the counter after we have initialized it. */ n_cpu = _mongoc_get_cpu_count (); segment = (char *) counters; infos = (mongoc_counter_info_t *) (segment + counters->infos_offset); infos = &infos[counters->n_counters]; infos->slot = num % SLOTS_PER_CACHELINE; infos->offset = (counters->values_offset + ((num / SLOTS_PER_CACHELINE) * n_cpu * sizeof (mongoc_counter_slots_t))); bson_strncpy (infos->category, category, sizeof infos->category); bson_strncpy (infos->name, name, sizeof infos->name); bson_strncpy (infos->description, description, sizeof infos->description); mcommon_atomic_thread_fence (); counters->n_counters++; return infos->offset; } #endif /** * mongoc_counters_init: * * Initializes the mongoc counters system. This should be run on library * initialization using the GCC constructor attribute. */ void _mongoc_counters_init (void) { #ifdef MONGOC_ENABLE_SHM_COUNTERS mongoc_counter_info_t *info; mongoc_counters_t *counters; size_t infos_size; size_t off; size_t size; char *segment; size = mongoc_counters_calc_size (); segment = (char *) mongoc_counters_alloc (size); infos_size = LAST_COUNTER * sizeof *info; counters = (mongoc_counters_t *) segment; counters->n_cpu = _mongoc_get_cpu_count (); counters->n_counters = 0; counters->infos_offset = sizeof *counters; counters->values_offset = (uint32_t) (counters->infos_offset + infos_size); BSON_ASSERT ((counters->values_offset % 64) == 0); #define COUNTER(ident, Category, Name, Desc) \ off = mongoc_counters_register (counters, COUNTER_##ident, Category, Name, Desc); \ __mongoc_counter_##ident.cpus = (mongoc_counter_slots_t *) (segment + off); #include #undef COUNTER /* * NOTE: * * Only update the size of the shared memory area for the client after * we have initialized the rest of the counters. Don't forget our memory * barrier to prevent compiler reordering. */ mcommon_atomic_thread_fence (); counters->size = (uint32_t) size; #endif } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-counters.defs0000644000175100001660000000737214760300420023504 0ustar /* * Copyright 2009-present MongoDB, 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. */ COUNTER(op_egress_total, "Operations", "Egress Total", "The number of sent operations.") COUNTER(op_ingress_total, "Operations", "Ingress Total", "The number of received operations.") COUNTER(op_egress_msg, "Operations", "Egress Messages", "The number of sent messages operations.") COUNTER(op_ingress_msg, "Operations", "Ingress Messages", "The number of received messages operations.") COUNTER(op_egress_compressed, "Operations", "Egress Compressed", "The number of sent compressed operations.") COUNTER(op_ingress_compressed, "Operations", "Ingress Compressed", "The number of received compressed operations.") COUNTER(op_egress_query, "Operations", "Egress Queries", "The number of sent Query operations.") COUNTER(op_ingress_reply, "Operations", "Ingress Reply", "The number of received Reply operations.") COUNTER(op_egress_getmore, "Operations", "Egress GetMore", "The number of sent GetMore operations.") COUNTER(op_egress_insert, "Operations", "Egress Insert", "The number of sent Insert operations.") COUNTER(op_egress_delete, "Operations", "Egress Delete", "The number of sent Delete operations.") COUNTER(op_egress_update, "Operations", "Egress Update", "The number of sent Update operations.") COUNTER(op_egress_killcursors, "Operations", "Egress KillCursors", "The number of sent KillCursors operations.") COUNTER(cursors_active, "Cursors", "Active", "The number of active cursors.") COUNTER(cursors_disposed, "Cursors", "Disposed", "The number of disposed cursors.") COUNTER(clients_active, "Clients", "Active", "The number of active clients.") COUNTER(clients_disposed, "Clients", "Disposed", "The number of disposed clients.") COUNTER(streams_active, "Streams", "Active", "The number of active streams.") COUNTER(streams_disposed, "Streams", "Disposed", "The number of disposed streams.") COUNTER(streams_egress, "Streams", "Egress Bytes", "The number of bytes sent.") COUNTER(streams_ingress, "Streams", "Ingress Bytes", "The number of bytes received.") COUNTER(streams_timeout, "Streams", "N Socket Timeouts", "The number of socket timeouts.") COUNTER(client_pools_active, "Client Pools", "Active", "The number of active client pools.") COUNTER(client_pools_disposed, "Client Pools", "Disposed", "The number of disposed client pools.") COUNTER(protocol_ingress_error, "Protocol", "Ingress Errors", "The number of protocol errors on ingress.") COUNTER(auth_failure, "Auth", "Failures", "The number of failed authentication requests.") COUNTER(auth_success, "Auth", "Success", "The number of successful authentication requests.") COUNTER(dns_failure, "DNS", "Failure", "The number of failed DNS requests.") COUNTER(dns_success, "DNS", "Success", "The number of successful DNS requests.") mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypt-private.h0000644000175100001660000001454514760300420023761 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CRYPT_PRIVATE_H #define MONGOC_CRYPT_PRIVATE_H #include #include #include typedef struct mc_kms_credentials_callback { mongoc_kms_credentials_provider_callback_fn fn; void *userdata; } mc_kms_credentials_callback; #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION /* For interacting with libmongocrypt */ typedef struct __mongoc_crypt_t _mongoc_crypt_t; /* Creates a new handle into libmongocrypt. - schema_map may be NULL. - may return NULL and set error. */ _mongoc_crypt_t * _mongoc_crypt_new (const bson_t *kms_providers, const bson_t *schema_map, const bson_t *encrypted_fields_map, const bson_t *tls_opts, const char *crypt_shared_lib_path, bool crypt_shared_lib_required, bool bypass_auto_encryption, bool bypass_query_analysis, mc_kms_credentials_callback creds_cb, mcd_optional_u64_t cache_expiration_ms, bson_error_t *error); void _mongoc_crypt_destroy (_mongoc_crypt_t *crypt); /* Perform auto encryption. - cmd_out is always initialized. - may return false and set error. */ bool _mongoc_crypt_auto_encrypt (_mongoc_crypt_t *crypt, mongoc_collection_t *key_vault_coll, mongoc_client_t *mongocryptd_client, mongoc_client_t *collinfo_client, const char *db_name, const bson_t *cmd_in, bson_t *cmd_out, bson_error_t *error); /* Perform auto decryption. - doc_out is always initialized. - may return false and set error. */ bool _mongoc_crypt_auto_decrypt (_mongoc_crypt_t *crypt, mongoc_collection_t *key_vault_coll, const bson_t *doc_in, bson_t *doc_out, bson_error_t *error); /* Perform explicit encryption. Return false on error and sets `error`. */ bool _mongoc_crypt_explicit_encrypt (_mongoc_crypt_t *crypt, mongoc_collection_t *key_vault_coll, const char *algorithm /* may be NULL */, const bson_value_t *keyid /* may be NULL */, const char *keyaltname /* may be NULL */, const char *query_type /* may be NULL */, const int64_t *contention_factor /* may be NULL */, const bson_t *range_opts /* may be NULL */, const bson_value_t *value_in, bson_value_t *value_out, bson_error_t *error); /* Perform explicit encryption on an expression. Return false on error and sets `error`. */ bool _mongoc_crypt_explicit_encrypt_expression (_mongoc_crypt_t *crypt, mongoc_collection_t *key_vault_coll, const char *algorithm /* may be NULL */, const bson_value_t *keyid /* may be NULL */, const char *keyaltname /* may be NULL */, const char *query_type /* may be NULL */, const int64_t *contention_factor /* may be NULL */, const bson_t *range_opts /* may be NULL */, const bson_t *expr_in, bson_t *expr_out, bson_error_t *error); /* Perform explicit decryption. - value_out is always initialized. - may return false and set error. */ bool _mongoc_crypt_explicit_decrypt (_mongoc_crypt_t *crypt, mongoc_collection_t *key_vault_coll, const bson_value_t *value_in, bson_value_t *value_out, bson_error_t *error); /* Create a data key document (does not insert into key vault). - keyaltnames may be NULL. - doc_out is always initialized. - may return false and set error. */ bool _mongoc_crypt_create_datakey (_mongoc_crypt_t *crypt, const char *kms_provider, const bson_t *masterkey, char **keyaltnames, uint32_t keyaltnames_count, const uint8_t *keymaterial, uint32_t keymaterial_len, bson_t *doc_out, bson_error_t *error); /* Rewrap datakeys in keyvault_coll matching the given filter with a new KMS provider (does not bulk-update into key vault). - filter may be NULL (equivalent to an empty document). - kms_provider may be NULL. - masterkey may be NULL if kms_provider is NULL. - doc_out is always initialized. - may return false and set error. */ bool _mongoc_crypt_rewrap_many_datakey (_mongoc_crypt_t *crypt, mongoc_collection_t *keyvault_coll, const bson_t *filter, const char *provider, const bson_t *master_key, bson_t *doc_out, bson_error_t *error); const char * _mongoc_crypt_get_crypt_shared_version (const _mongoc_crypt_t *crypt); #endif /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */ #endif /* MONGOC_CRYPT_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypt.c0000644000175100001660000021164514760300420022304 0ustar /* * Copyright 2009-present MongoDB, 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. */ #define MONGOC_LOG_DOMAIN "client-side-encryption" #include #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION #include #include #include #include #include #include #include #include #include #include #include #include #include #include // `mcd_mapof_kmsid_to_tlsopts` maps a KMS ID (e.g. `aws` or `aws:myname`) to a // `mongoc_ssl_opt_t`. The acryonym TLS is preferred over SSL for // consistency with the CSE and URI specifications. typedef struct { mongoc_array_t entries; } mcd_mapof_kmsid_to_tlsopts; typedef struct { char *kmsid; mongoc_ssl_opt_t tlsopts; } mcd_mapof_kmsid_to_tlsopts_entry; mcd_mapof_kmsid_to_tlsopts * mcd_mapof_kmsid_to_tlsopts_new (void) { mcd_mapof_kmsid_to_tlsopts *k2t = bson_malloc0 (sizeof (mcd_mapof_kmsid_to_tlsopts)); _mongoc_array_init (&k2t->entries, sizeof (mcd_mapof_kmsid_to_tlsopts_entry)); return k2t; } void mcd_mapof_kmsid_to_tlsopts_destroy (mcd_mapof_kmsid_to_tlsopts *k2t) { if (!k2t) { return; } for (size_t i = 0; i < k2t->entries.len; i++) { mcd_mapof_kmsid_to_tlsopts_entry *e = &_mongoc_array_index (&k2t->entries, mcd_mapof_kmsid_to_tlsopts_entry, i); bson_free (e->kmsid); _mongoc_ssl_opts_cleanup (&e->tlsopts, true /* free_internal */); } _mongoc_array_destroy (&k2t->entries); bson_free (k2t); } // `mcd_mapof_kmsid_to_tlsopts_insert` adds an entry into the map. // `kmsid` and `tlsopts` are copied. // No checking is done to prohibit duplicate entries. void mcd_mapof_kmsid_to_tlsopts_insert (mcd_mapof_kmsid_to_tlsopts *k2t, const char *kmsid, const mongoc_ssl_opt_t *tlsopts) { BSON_ASSERT_PARAM (k2t); BSON_ASSERT_PARAM (kmsid); BSON_ASSERT_PARAM (tlsopts); mcd_mapof_kmsid_to_tlsopts_entry e = {.kmsid = bson_strdup (kmsid)}; _mongoc_ssl_opts_copy_to (tlsopts, &e.tlsopts, true /* copy_internal */); _mongoc_array_append_val (&k2t->entries, e); } // `mcd_mapof_kmsid_to_tlsopts_get` returns the TLS options for a KMS ID, or // NULL. const mongoc_ssl_opt_t * mcd_mapof_kmsid_to_tlsopts_get (const mcd_mapof_kmsid_to_tlsopts *k2t, const char *kmsid) { BSON_ASSERT_PARAM (k2t); BSON_ASSERT_PARAM (kmsid); for (size_t i = 0; i < k2t->entries.len; i++) { mcd_mapof_kmsid_to_tlsopts_entry *e = &_mongoc_array_index (&k2t->entries, mcd_mapof_kmsid_to_tlsopts_entry, i); if (0 == strcmp (e->kmsid, kmsid)) { return &e->tlsopts; } } return NULL; } bool mcd_mapof_kmsid_to_tlsopts_has (const mcd_mapof_kmsid_to_tlsopts *k2t, const char *kmsid) { return NULL != mcd_mapof_kmsid_to_tlsopts_get (k2t, kmsid); } struct __mongoc_crypt_t { mongocrypt_t *handle; mongoc_ssl_opt_t kmip_tls_opt; mongoc_ssl_opt_t aws_tls_opt; mongoc_ssl_opt_t azure_tls_opt; mongoc_ssl_opt_t gcp_tls_opt; mcd_mapof_kmsid_to_tlsopts *kmsid_to_tlsopts; /// The kmsProviders that were provided by the user when encryption was /// initiated. We need to remember this in case we need to load on-demand /// credentials. bson_t kms_providers; mc_kms_credentials_callback creds_cb; /// The most recently auto-acquired Azure token, on null if it was destroyed /// or not yet acquired. mcd_azure_access_token azure_token; /// The time point at which the `azure_token` was acquired. mcd_time_point azure_token_issued_at; }; static void _log_callback (mongocrypt_log_level_t mongocrypt_log_level, const char *message, uint32_t message_len, void *ctx) { mongoc_log_level_t log_level = MONGOC_LOG_LEVEL_ERROR; BSON_UNUSED (message_len); BSON_UNUSED (ctx); switch (mongocrypt_log_level) { case MONGOCRYPT_LOG_LEVEL_FATAL: log_level = MONGOC_LOG_LEVEL_CRITICAL; break; case MONGOCRYPT_LOG_LEVEL_ERROR: log_level = MONGOC_LOG_LEVEL_ERROR; break; case MONGOCRYPT_LOG_LEVEL_WARNING: log_level = MONGOC_LOG_LEVEL_WARNING; break; case MONGOCRYPT_LOG_LEVEL_INFO: log_level = MONGOC_LOG_LEVEL_INFO; break; case MONGOCRYPT_LOG_LEVEL_TRACE: log_level = MONGOC_LOG_LEVEL_TRACE; break; default: log_level = MONGOC_LOG_LEVEL_CRITICAL; break; } mongoc_log (log_level, MONGOC_LOG_DOMAIN, "%s", message); } static void _prefix_mongocryptd_error (bson_error_t *error) { char buf[sizeof (error->message)]; // Truncation is OK. int req = bson_snprintf (buf, sizeof (buf), "mongocryptd error: %s:", error->message); BSON_ASSERT (req > 0); memcpy (error->message, buf, sizeof (buf)); } static void _prefix_keyvault_error (bson_error_t *error) { char buf[sizeof (error->message)]; // Truncation is OK. int req = bson_snprintf (buf, sizeof (buf), "key vault error: %s:", error->message); BSON_ASSERT (req > 0); memcpy (error->message, buf, sizeof (buf)); } static void _status_to_error (mongocrypt_status_t *status, bson_error_t *error) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, mongocrypt_status_code (status), "%s", mongocrypt_status_message (status, NULL)); } /* Checks for an error on mongocrypt context. * If error_expected, then we expect mongocrypt_ctx_status to report a failure * status (due to a previous failed function call). If it did not, return a * generic error. * Returns true if ok, and does not modify @error. * Returns false if error, and sets @error. */ bool _ctx_check_error (mongocrypt_ctx_t *ctx, bson_error_t *error, bool error_expected) { mongocrypt_status_t *status; status = mongocrypt_status_new (); if (!mongocrypt_ctx_status (ctx, status)) { _status_to_error (status, error); mongocrypt_status_destroy (status); return false; } else if (error_expected) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "generic error from libmongocrypt operation"); mongocrypt_status_destroy (status); return false; } mongocrypt_status_destroy (status); return true; } bool _kms_ctx_check_error (mongocrypt_kms_ctx_t *kms_ctx, bson_error_t *error, bool error_expected) { mongocrypt_status_t *status; status = mongocrypt_status_new (); if (!mongocrypt_kms_ctx_status (kms_ctx, status)) { _status_to_error (status, error); mongocrypt_status_destroy (status); return false; } else if (error_expected) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "generic error from libmongocrypt KMS operation"); mongocrypt_status_destroy (status); return false; } mongocrypt_status_destroy (status); return true; } bool _crypt_check_error (mongocrypt_t *crypt, bson_error_t *error, bool error_expected) { mongocrypt_status_t *status; status = mongocrypt_status_new (); if (!mongocrypt_status (crypt, status)) { _status_to_error (status, error); mongocrypt_status_destroy (status); return false; } else if (error_expected) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "generic error from libmongocrypt handle"); mongocrypt_status_destroy (status); return false; } mongocrypt_status_destroy (status); return true; } /* Convert a mongocrypt_binary_t to a static bson_t */ static bool _bin_to_static_bson (mongocrypt_binary_t *bin, bson_t *out, bson_error_t *error) { /* Copy bin into bson_t result. */ if (!bson_init_static (out, mongocrypt_binary_data (bin), mongocrypt_binary_len (bin))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "invalid returned bson"); return false; } return true; } typedef struct { mongocrypt_ctx_t *ctx; mongoc_collection_t *keyvault_coll; mongoc_client_t *mongocryptd_client; mongoc_client_t *collinfo_client; const char *db_name; _mongoc_crypt_t *crypt; } _state_machine_t; _state_machine_t * _state_machine_new (_mongoc_crypt_t *crypt) { _state_machine_t *sm = bson_malloc0 (sizeof (_state_machine_t)); sm->crypt = crypt; return sm; } void _state_machine_destroy (_state_machine_t *state_machine) { if (!state_machine) { return; } mongocrypt_ctx_destroy (state_machine->ctx); bson_free (state_machine); } /* State handler MONGOCRYPT_CTX_NEED_MONGO_COLLINFO */ static bool _state_need_mongo_collinfo (_state_machine_t *state_machine, bson_error_t *error) { mongoc_database_t *db = NULL; mongoc_cursor_t *cursor = NULL; bson_t filter_bson; const bson_t *collinfo_bson = NULL; bson_t opts = BSON_INITIALIZER; mongocrypt_binary_t *filter_bin = NULL; mongocrypt_binary_t *collinfo_bin = NULL; bool ret = false; /* 1. Run listCollections on the encrypted MongoClient with the filter * provided by mongocrypt_ctx_mongo_op */ filter_bin = mongocrypt_binary_new (); if (!mongocrypt_ctx_mongo_op (state_machine->ctx, filter_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } if (!_bin_to_static_bson (filter_bin, &filter_bson, error)) { goto fail; } bson_append_document (&opts, "filter", -1, &filter_bson); db = mongoc_client_get_database (state_machine->collinfo_client, state_machine->db_name); cursor = mongoc_database_find_collections_with_opts (db, &opts); if (mongoc_cursor_error (cursor, error)) { goto fail; } /* 2. Return the first result (if any) with mongocrypt_ctx_mongo_feed or * proceed to the next step if nothing was returned. */ if (mongoc_cursor_next (cursor, &collinfo_bson)) { collinfo_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (collinfo_bson), collinfo_bson->len); if (!mongocrypt_ctx_mongo_feed (state_machine->ctx, collinfo_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } } else if (mongoc_cursor_error (cursor, error)) { goto fail; } /* 3. Call mongocrypt_ctx_mongo_done */ if (!mongocrypt_ctx_mongo_done (state_machine->ctx)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } ret = true; fail: bson_destroy (&opts); mongocrypt_binary_destroy (filter_bin); mongocrypt_binary_destroy (collinfo_bin); mongoc_cursor_destroy (cursor); mongoc_database_destroy (db); return ret; } static bool _state_need_mongo_markings (_state_machine_t *state_machine, bson_error_t *error) { bool ret = false; mongocrypt_binary_t *mongocryptd_cmd_bin = NULL; mongocrypt_binary_t *mongocryptd_reply_bin = NULL; bson_t mongocryptd_cmd_bson; bson_t reply = BSON_INITIALIZER; mongocryptd_cmd_bin = mongocrypt_binary_new (); if (!mongocrypt_ctx_mongo_op (state_machine->ctx, mongocryptd_cmd_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } if (!_bin_to_static_bson (mongocryptd_cmd_bin, &mongocryptd_cmd_bson, error)) { goto fail; } /* 1. Use db.runCommand to run the command provided by * mongocrypt_ctx_mongo_op on the MongoClient connected to mongocryptd. */ bson_destroy (&reply); if (!mongoc_client_command_simple (state_machine->mongocryptd_client, state_machine->db_name, &mongocryptd_cmd_bson, NULL /* read_prefs */, &reply, error)) { _prefix_mongocryptd_error (error); goto fail; } /* 2. Feed the reply back with mongocrypt_ctx_mongo_feed. */ mongocryptd_reply_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (&reply), reply.len); if (!mongocrypt_ctx_mongo_feed (state_machine->ctx, mongocryptd_reply_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } /* 3. Call mongocrypt_ctx_mongo_done. */ if (!mongocrypt_ctx_mongo_done (state_machine->ctx)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } ret = true; fail: bson_destroy (&reply); mongocrypt_binary_destroy (mongocryptd_cmd_bin); mongocrypt_binary_destroy (mongocryptd_reply_bin); return ret; } static bool _state_need_mongo_keys (_state_machine_t *state_machine, bson_error_t *error) { bool ret = false; mongocrypt_binary_t *filter_bin = NULL; bson_t filter_bson; bson_t opts = BSON_INITIALIZER; mongocrypt_binary_t *key_bin = NULL; const bson_t *key_bson; mongoc_cursor_t *cursor = NULL; /* 1. Use MongoCollection.find on the MongoClient connected to the key vault * client (which may be the same as the encrypted client). Use the filter * provided by mongocrypt_ctx_mongo_op. */ filter_bin = mongocrypt_binary_new (); if (!mongocrypt_ctx_mongo_op (state_machine->ctx, filter_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } if (!_bin_to_static_bson (filter_bin, &filter_bson, error)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } { const mongoc_read_concern_t *const rc = mongoc_collection_get_read_concern (state_machine->keyvault_coll); const char *const level = rc ? mongoc_read_concern_get_level (rc) : NULL; BSON_ASSERT (level && strcmp (level, MONGOC_READ_CONCERN_LEVEL_MAJORITY) == 0); } cursor = mongoc_collection_find_with_opts (state_machine->keyvault_coll, &filter_bson, &opts, NULL /* read prefs */); /* 2. Feed all resulting documents back (if any) with repeated calls to * mongocrypt_ctx_mongo_feed. */ while (mongoc_cursor_next (cursor, &key_bson)) { mongocrypt_binary_destroy (key_bin); key_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (key_bson), key_bson->len); if (!mongocrypt_ctx_mongo_feed (state_machine->ctx, key_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } } if (mongoc_cursor_error (cursor, error)) { _prefix_keyvault_error (error); goto fail; } /* 3. Call mongocrypt_ctx_mongo_done. */ if (!mongocrypt_ctx_mongo_done (state_machine->ctx)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } ret = true; fail: mongocrypt_binary_destroy (filter_bin); mongoc_cursor_destroy (cursor); bson_destroy (&opts); mongocrypt_binary_destroy (key_bin); return ret; } static mongoc_stream_t * _get_stream (const char *endpoint, int32_t connecttimeoutms, const mongoc_ssl_opt_t *ssl_opt, bson_error_t *error) { mongoc_stream_t *base_stream = NULL; mongoc_stream_t *tls_stream = NULL; bool ret = false; mongoc_ssl_opt_t ssl_opt_copy = {0}; mongoc_host_list_t host; if (!_mongoc_host_list_from_string_with_err (&host, endpoint, error)) { goto fail; } base_stream = mongoc_client_connect_tcp (connecttimeoutms, &host, error); if (!base_stream) { goto fail; } /* Wrap in a tls_stream. */ _mongoc_ssl_opts_copy_to (ssl_opt, &ssl_opt_copy, true /* copy_internal */); tls_stream = mongoc_stream_tls_new_with_hostname (base_stream, host.host, &ssl_opt_copy, 1 /* client */); if (!tls_stream) { bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to create TLS stream to: %s", endpoint); goto fail; } if (!mongoc_stream_tls_handshake_block (tls_stream, host.host, connecttimeoutms, error)) { goto fail; } ret = true; fail: _mongoc_ssl_opts_cleanup (&ssl_opt_copy, true /* free_internal */); if (!ret) { if (tls_stream) { /* destroys base_stream too */ mongoc_stream_destroy (tls_stream); } else if (base_stream) { mongoc_stream_destroy (base_stream); } return NULL; } return tls_stream; } static bool _state_need_kms (_state_machine_t *state_machine, bson_error_t *error) { mongocrypt_kms_ctx_t *kms_ctx = NULL; mongoc_stream_t *tls_stream = NULL; bool ret = false; mongocrypt_binary_t *http_req = NULL; mongocrypt_binary_t *http_reply = NULL; const char *endpoint; const int32_t sockettimeout = MONGOC_DEFAULT_SOCKETTIMEOUTMS; int64_t sleep_usec = 0; while ((kms_ctx = mongocrypt_ctx_next_kms_ctx (state_machine->ctx))) { mongoc_iovec_t iov; const mongoc_ssl_opt_t *ssl_opt; const char *provider; provider = mongocrypt_kms_ctx_get_kms_provider (kms_ctx, NULL); if (0 == strcmp ("kmip", provider)) { ssl_opt = &state_machine->crypt->kmip_tls_opt; } else if (0 == strcmp ("aws", provider)) { ssl_opt = &state_machine->crypt->aws_tls_opt; } else if (0 == strcmp ("azure", provider)) { ssl_opt = &state_machine->crypt->azure_tls_opt; } else if (0 == strcmp ("gcp", provider)) { ssl_opt = &state_machine->crypt->gcp_tls_opt; } else if (mcd_mapof_kmsid_to_tlsopts_has (state_machine->crypt->kmsid_to_tlsopts, provider)) { ssl_opt = mcd_mapof_kmsid_to_tlsopts_get (state_machine->crypt->kmsid_to_tlsopts, provider); } else { ssl_opt = mongoc_ssl_opt_get_default (); } mongocrypt_binary_destroy (http_req); http_req = mongocrypt_binary_new (); if (!mongocrypt_kms_ctx_message (kms_ctx, http_req)) { _kms_ctx_check_error (kms_ctx, error, true); goto fail; } if (!mongocrypt_kms_ctx_endpoint (kms_ctx, &endpoint)) { _kms_ctx_check_error (kms_ctx, error, true); goto fail; } sleep_usec = mongocrypt_kms_ctx_usleep (kms_ctx); if (sleep_usec > 0) { _mongoc_usleep (sleep_usec); } mongoc_stream_destroy (tls_stream); tls_stream = _get_stream (endpoint, sockettimeout, ssl_opt, error); #ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL /* Retry once with schannel as a workaround for CDRIVER-3566. */ if (!tls_stream) { tls_stream = _get_stream (endpoint, sockettimeout, ssl_opt, error); } #endif if (!tls_stream) { if (mongocrypt_kms_ctx_fail (kms_ctx)) { continue; } else { /* TLS errors are set in _get_stream */ goto fail; } } iov.iov_base = (char *) mongocrypt_binary_data (http_req); iov.iov_len = mongocrypt_binary_len (http_req); if (!_mongoc_stream_writev_full (tls_stream, &iov, 1, sockettimeout, error)) { if (mongocrypt_kms_ctx_fail (kms_ctx)) { continue; } else { bson_error_t kms_error; BSON_ASSERT (!_kms_ctx_check_error (kms_ctx, &kms_error, true)); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "%s. Failed to write to KMS stream: %s", kms_error.message, endpoint); goto fail; } } /* Read and feed reply. */ while (mongocrypt_kms_ctx_bytes_needed (kms_ctx) > 0) { #define BUFFER_SIZE 1024 uint8_t buf[BUFFER_SIZE]; uint32_t bytes_needed = mongocrypt_kms_ctx_bytes_needed (kms_ctx); ssize_t read_ret; /* Cap the bytes requested at the buffer size. */ if (bytes_needed > BUFFER_SIZE) { bytes_needed = BUFFER_SIZE; } read_ret = mongoc_stream_read (tls_stream, buf, bytes_needed, 1 /* min_bytes. */, sockettimeout); if (read_ret <= 0) { if (mongocrypt_kms_ctx_fail (kms_ctx)) { break; // Stop reading reply. } else { bson_error_t kms_error; BSON_ASSERT (!_kms_ctx_check_error (kms_ctx, &kms_error, true)); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "%s. Failed to read from KMS stream to: %s", kms_error.message, endpoint); goto fail; } } mongocrypt_binary_destroy (http_reply); BSON_ASSERT (mcommon_in_range_signed (uint32_t, read_ret)); http_reply = mongocrypt_binary_new_from_data (buf, (uint32_t) read_ret); if (!mongocrypt_kms_ctx_feed (kms_ctx, http_reply)) { _kms_ctx_check_error (kms_ctx, error, true); goto fail; } } } /* When NULL is returned by mongocrypt_ctx_next_kms_ctx, this can either be * an error or end-of-list. */ if (!_ctx_check_error (state_machine->ctx, error, false)) { goto fail; } if (!mongocrypt_ctx_kms_done (state_machine->ctx)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } ret = true; fail: mongoc_stream_destroy (tls_stream); mongocrypt_binary_destroy (http_req); mongocrypt_binary_destroy (http_reply); return ret; #undef BUFFER_SIZE } /** * @brief Determine whether the given kmsProviders has an empty 'aws' * subdocument * * @param kms_providers The user-provided kmsProviders * @param error Output parameter for possible errors. * @retval true If 'aws' is present and an empty subdocument * @retval false Otherwise or on error */ static bool _needs_on_demand_aws_kms (bson_t const *kms_providers) { bson_iter_t iter; if (!bson_iter_init_find (&iter, kms_providers, "aws")) { // No "aws" subdocument return false; } if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { // "aws" is not a document? Should be validated by libmongocrypt return false; } const uint8_t *dataptr; uint32_t datalen; bson_iter_document (&iter, &datalen, &dataptr); bson_t subdoc; if (!bson_init_static (&subdoc, dataptr, datalen)) { // Invalid "aws" document? Should be validated by libmongocrypt return false; } if (bson_empty (&subdoc)) { // "aws" is present and is an empty subdocument, which means that the user // requests that the AWS credentials be loaded on-demand from the // environment. return true; } else { // "aws" is present and is non-empty, which means that the user has // already provided credentials for AWS. return false; } } /** * @brief Check whether the given kmsProviders object requests automatic Azure * credentials * * @param kmsprov The input kmsProviders that may have an "azure" property * @param error An output error * @retval true If success AND `kmsprov` requests automatic Azure credentials * @retval false Otherwise. Check error->code for failure. */ static bool _check_azure_kms_auto (const bson_t *kmsprov, bson_error_t *error) { if (error) { *error = (bson_error_t){0}; } bson_iter_t iter; if (!bson_iter_init_find (&iter, kmsprov, "azure")) { return false; } bson_t azure_subdoc; if (!_mongoc_iter_document_as_bson (&iter, &azure_subdoc, error)) { return false; } return bson_empty (&azure_subdoc); } /** * @brief Attempt to load AWS credentials from the environment and insert them * into the given kmsProviders bson document on the "aws" property. * * @param out A kmsProviders object to update * @param error An error-out parameter * @retval true If there was no error and we successfully loaded credentials. * @retval false If there was an error while updating the BSON data or obtaining * credentials. */ static bool _try_add_aws_from_env (bson_t *out, bson_error_t *error) { // Attempt to obtain AWS credentials from the environment. _mongoc_aws_credentials_t creds; if (!_mongoc_aws_credentials_obtain (NULL, &creds, error)) { // Error while obtaining credentials return false; } // Build the new "aws" subdoc bson_t aws; bool okay = BSON_APPEND_DOCUMENT_BEGIN (out, "aws", &aws) // Add the accessKeyId and the secretAccessKey && BSON_APPEND_UTF8 (&aws, "accessKeyId", creds.access_key_id) // && BSON_APPEND_UTF8 (&aws, "secretAccessKey", creds.secret_access_key) // // Add the sessionToken, if we got one: && (!creds.session_token || BSON_APPEND_UTF8 (&aws, "sessionToken", creds.session_token)) // // Finish the document && bson_append_document_end (out, &aws); BSON_ASSERT (okay && "Failed to build aws credentials document"); // Good! _mongoc_aws_credentials_cleanup (&creds); return true; } /** * @brief Attempt to request a new Azure access token from the IMDS HTTP server * * @param out The token to populate. Must later be destroyed by the caller. * @param error An output parameter to capture any errors * @retval true Upon successfully obtaining and parsing a token * @retval false If any error occurs. */ static bool _request_new_azure_token (mcd_azure_access_token *out, bson_error_t *error) { return mcd_azure_access_token_from_imds (out, NULL, // Use the default host 0, // Default port as well NULL, // No extra headers error); } /** * @brief Attempt to load an Azure access token from the environment and append * them to the kmsProviders * * @param out A kmsProviders object to update * @param error An error-out parameter * @retval true If there was no error and we loaded credentials * @retval false If there was an error obtaining or appending credentials */ static bool _try_add_azure_from_env (_mongoc_crypt_t *crypt, bson_t *out, bson_error_t *error) { if (crypt->azure_token.access_token) { // The access-token is non-null, so we may have one cached. mcd_time_point one_min_from_now = mcd_later (mcd_now (), mcd_minutes (1)); mcd_time_point expires_at = mcd_later (crypt->azure_token_issued_at, crypt->azure_token.expires_in); if (mcd_time_compare (expires_at, one_min_from_now) >= 0) { // The token is still valid for at least another minute } else { // The token will expire soon. Destroy it, and below we will below ask // IMDS for a new one. mcd_azure_access_token_destroy (&crypt->azure_token); } } if (crypt->azure_token.access_token == NULL) { // There is no access token in our cache. // Save the current time point as the "issue time" of the token, even // though it will take some time for the HTTP request to hit the metadata // server. This time is only used to track token expiry. IMDS gives us a // number of seconds that the token will be valid relative to its issue // time. Avoid reliance on system clocks by comparing the issue time to an // abstract monotonic "now" crypt->azure_token_issued_at = mcd_now (); // Get the token: if (!_request_new_azure_token (&crypt->azure_token, error)) { return false; } } // Build the new KMS credentials bson_t new_azure_creds = BSON_INITIALIZER; const bool okay = BSON_APPEND_UTF8 (&new_azure_creds, "accessToken", crypt->azure_token.access_token) && BSON_APPEND_DOCUMENT (out, "azure", &new_azure_creds); bson_destroy (&new_azure_creds); if (!okay) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_BSON_INVALID, "Failed to build new 'azure' credentials"); } return okay; } /** * @brief Check whether the given kmsProviders object requests automatic GCP * credentials * * @param kmsprov The input kmsProviders that may have an "gcp" property * @param error An output error * @retval true If success AND `kmsprov` requests automatic GCP credentials * @retval false Otherwise. Check error->code for failure. */ static bool _check_gcp_kms_auto (const bson_t *kmsprov, bson_error_t *error) { if (error) { *error = (bson_error_t){0}; } bson_iter_t iter; if (!bson_iter_init_find (&iter, kmsprov, "gcp")) { return false; } bson_t gcp_subdoc; if (!_mongoc_iter_document_as_bson (&iter, &gcp_subdoc, error)) { return false; } return bson_empty (&gcp_subdoc); } /** * @brief Attempt to request a new GCP access token from the HTTP server * * @param out The token to populate. Must later be destroyed by the caller. * @param error An output parameter to capture any errors * @retval true Upon successfully obtaining and parsing a token * @retval false If any error occurs. */ static bool _request_new_gcp_token (gcp_service_account_token *out, bson_error_t *error) { return (gcp_access_token_from_gcp_server (out, NULL, 0, NULL, error)); } /** * @brief Attempt to load an GCP access token from the environment and append * them to the kmsProviders * * @param out A kmsProviders object to update * @param error An error-out parameter * @retval true If there was no error and we loaded credentials * @retval false If there was an error obtaining or appending credentials */ static bool _try_add_gcp_from_env (bson_t *out, bson_error_t *error) { // Not caching gcp tokens, so we will always request a new one from the gcp // server. gcp_service_account_token gcp_token; if (!_request_new_gcp_token (&gcp_token, error)) { return false; } // Build the new KMS credentials bson_t new_gcp_creds = BSON_INITIALIZER; const bool okay = BSON_APPEND_UTF8 (&new_gcp_creds, "accessToken", gcp_token.access_token) && BSON_APPEND_DOCUMENT (out, "gcp", &new_gcp_creds); bson_destroy (&new_gcp_creds); gcp_access_token_destroy (&gcp_token); if (!okay) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_BSON_INVALID, "Failed to build new 'gcp' credentials"); } return okay; } static bool _state_need_kms_credentials (_state_machine_t *sm, bson_error_t *error) { bson_t creds = BSON_INITIALIZER; const bson_t empty = BSON_INITIALIZER; bool okay = false; if (sm->crypt->creds_cb.fn) { // We have a user-provided credentials callback. Try it. if (!sm->crypt->creds_cb.fn (sm->crypt->creds_cb.userdata, &empty, &creds, error)) { // User-provided callback indicated failure if (!error->code) { // The callback did not set an error, so we'll provide a default // one. bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "The user-provided callback for on-demand KMS " "credentials failed."); } goto fail; } // The user's callback reported success } bson_iter_t iter; const bool callback_provided_aws = bson_iter_init_find (&iter, &creds, "aws"); if (!callback_provided_aws && _needs_on_demand_aws_kms (&sm->crypt->kms_providers)) { // The original kmsProviders had an empty "aws" property, and the // user-provided callback did not fill in a new "aws" property for us. // Attempt instead to load the AWS credentials from the environment: if (!_try_add_aws_from_env (&creds, error)) { // Error while trying to add AWS credentials goto fail; } } // Whether the callback provided Azure credentials const bool cb_provided_azure = bson_iter_init_find (&iter, &creds, "azure"); // Whether the original kmsProviders requested auto-Azure credentials: const bool orig_wants_auto_azure = _check_azure_kms_auto (&sm->crypt->kms_providers, error); if (error->code) { // _check_azure_kms_auto failed goto fail; } const bool wants_auto_azure = orig_wants_auto_azure && !cb_provided_azure; if (wants_auto_azure) { if (!_try_add_azure_from_env (sm->crypt, &creds, error)) { goto fail; } } // Whether the callback provided GCP credentials const bool cb_provided_gcp = bson_iter_init_find (&iter, &creds, "gcp"); // Whether the original kmsProviders requested auto-GCP credentials: const bool orig_wants_auto_gcp = _check_gcp_kms_auto (&sm->crypt->kms_providers, error); if (error->code) { // _check_gcp_kms_auto failed goto fail; } const bool wants_auto_gcp = orig_wants_auto_gcp && !cb_provided_gcp; if (wants_auto_gcp) { if (!_try_add_gcp_from_env (&creds, error)) { goto fail; } } // Now actually send that data to libmongocrypt mongocrypt_binary_t *const def = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (&creds), creds.len); okay = mongocrypt_ctx_provide_kms_providers (sm->ctx, def); if (!okay) { _ctx_check_error (sm->ctx, error, true); } mongocrypt_binary_destroy (def); fail: bson_destroy (&creds); return okay; } static bool _state_ready (_state_machine_t *state_machine, bson_t *result, bson_error_t *error) { mongocrypt_binary_t *result_bin = NULL; bson_t tmp; bool ret = false; bson_init (result); result_bin = mongocrypt_binary_new (); if (!mongocrypt_ctx_finalize (state_machine->ctx, result_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } if (!_bin_to_static_bson (result_bin, &tmp, error)) { goto fail; } bson_destroy (result); bson_copy_to (&tmp, result); ret = true; fail: mongocrypt_binary_destroy (result_bin); return ret; } /*-------------------------------------------------------------------------- * * _mongoc_cse_run_state_machine -- * Run the mongocrypt_ctx state machine. * * Post-conditions: * *result may be set to a new bson_t, or NULL otherwise. Caller should * not assume return value of true means *result is set. If false returned, * @error is set. * * -------------------------------------------------------------------------- */ bool _state_machine_run (_state_machine_t *state_machine, bson_t *result, bson_error_t *error) { bool ret = false; mongocrypt_binary_t *bin = NULL; bson_init (result); while (true) { switch (mongocrypt_ctx_state (state_machine->ctx)) { default: case MONGOCRYPT_CTX_ERROR: _ctx_check_error (state_machine->ctx, error, true); goto fail; case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: if (!_state_need_mongo_collinfo (state_machine, error)) { goto fail; } break; case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: if (!_state_need_mongo_markings (state_machine, error)) { goto fail; } break; case MONGOCRYPT_CTX_NEED_MONGO_KEYS: if (!_state_need_mongo_keys (state_machine, error)) { goto fail; } break; case MONGOCRYPT_CTX_NEED_KMS: if (!_state_need_kms (state_machine, error)) { goto fail; } break; case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS: if (!_state_need_kms_credentials (state_machine, error)) { goto fail; } break; case MONGOCRYPT_CTX_READY: bson_destroy (result); if (!_state_ready (state_machine, result, error)) { goto fail; } break; case MONGOCRYPT_CTX_DONE: goto success; break; case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB: bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB is " "unimplemented"); goto fail; break; } } success: ret = true; fail: mongocrypt_binary_destroy (bin); return ret; } /* _parse_one_tls_opts parses one TLS document. * Pre-conditions: * - @iter is an iterator at the start of a KMS provider key/value pair. * - @out_opt must not be initialized. * Post-conditions: * - @out_opt is always initialized. * Returns false and sets @error on error. */ static bool _parse_one_tls_opts (bson_iter_t *iter, mongoc_ssl_opt_t *out_opt, bson_error_t *error) { bool ok = false; const char *kms_provider; bson_t tls_opts_doc; const uint8_t *data; uint32_t len; mcommon_string_append_t errmsg; bson_iter_t permitted_iter; mcommon_string_new_as_append (&errmsg); kms_provider = bson_iter_key (iter); memset (out_opt, 0, sizeof (mongoc_ssl_opt_t)); if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Expected TLS options for %s to be a document, got: %s", kms_provider, _mongoc_bson_type_to_str (bson_iter_type (iter))); goto fail; } bson_iter_document (iter, &len, &data); if (!bson_init_static (&tls_opts_doc, data, len) || !bson_iter_init (&permitted_iter, &tls_opts_doc)) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error iterating into TLS options document for %s", kms_provider); goto fail; } while (bson_iter_next (&permitted_iter)) { const char *key = bson_iter_key (&permitted_iter); if (0 == bson_strcasecmp (key, MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD)) { continue; } if (0 == bson_strcasecmp (key, MONGOC_URI_TLSCERTIFICATEKEYFILE)) { continue; } if (0 == bson_strcasecmp (key, MONGOC_URI_TLSCAFILE)) { continue; } if (0 == bson_strcasecmp (key, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK)) { continue; } bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error setting TLS option %s for %s. Insecure TLS options prohibited.", key, kms_provider); goto fail; } if (!_mongoc_ssl_opts_from_bson (out_opt, &tls_opts_doc, &errmsg)) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error parsing TLS options for %s: %s", kms_provider, mcommon_str_from_append (&errmsg)); goto fail; } ok = true; fail: mcommon_string_from_append_destroy (&errmsg); return ok; } /* _parse_all_tls_opts initializes TLS options for all KMS providers. * @tls_opts is the BSON document passed through * mongoc_client_encryption_opts_set_tls_opts or * mongoc_auto_encryption_opts_set_tls_opts. * Defaults to using mongoc_ssl_opt_get_default() if options are not passed for * a provider. Returns false and sets @error on error. */ static bool _parse_all_tls_opts (_mongoc_crypt_t *crypt, const bson_t *tls_opts, bson_error_t *error) { bson_iter_t iter; bool ok = false; bool has_aws = false; bool has_azure = false; bool has_gcp = false; bool has_kmip = false; if (!tls_opts) { return true; } if (!bson_iter_init (&iter, tls_opts)) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error starting iteration of TLS options"); goto fail; } while (bson_iter_next (&iter)) { const char *key; key = bson_iter_key (&iter); if (0 == strcmp (key, "aws")) { if (has_aws) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error parsing duplicate TLS options for %s", key); goto fail; } has_aws = true; if (!_parse_one_tls_opts (&iter, &crypt->aws_tls_opt, error)) { goto fail; } continue; } if (0 == strcmp (key, "azure")) { if (has_azure) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error parsing duplicate TLS options for %s", key); goto fail; } has_azure = true; if (!_parse_one_tls_opts (&iter, &crypt->azure_tls_opt, error)) { goto fail; } continue; } if (0 == strcmp (key, "gcp")) { if (has_gcp) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error parsing duplicate TLS options for %s", key); goto fail; } has_gcp = true; if (!_parse_one_tls_opts (&iter, &crypt->gcp_tls_opt, error)) { goto fail; } continue; } if (0 == strcmp (key, "kmip")) { if (has_kmip) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error parsing duplicate TLS options for %s", key); goto fail; } has_kmip = true; if (!_parse_one_tls_opts (&iter, &crypt->kmip_tls_opt, error)) { goto fail; } continue; } const char *colon_pos = strstr (key, ":"); if (colon_pos != NULL) { // Parse TLS options for a named KMS provider. if (mcd_mapof_kmsid_to_tlsopts_has (crypt->kmsid_to_tlsopts, key)) { bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Error parsing duplicate TLS options for %s", key); goto fail; } mongoc_ssl_opt_t tlsopts = {0}; if (!_parse_one_tls_opts (&iter, &tlsopts, error)) { _mongoc_ssl_opts_cleanup (&tlsopts, true /* free_internal */); goto fail; } mcd_mapof_kmsid_to_tlsopts_insert (crypt->kmsid_to_tlsopts, key, &tlsopts); _mongoc_ssl_opts_cleanup (&tlsopts, true /* free_internal */); continue; } bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "Cannot configure TLS options for KMS provider: %s", key); goto fail; } /* Configure with default TLS options. The mongoc_ssl_opt_t returned by * mongoc_ssl_opt_get_default may contain non-NULL fields if * MONGOC_SSL_DEFAULT_TRUST_FILE or MONGOC_SSL_DEFAULT_TRUST_DIR are defined. */ if (!has_aws) { _mongoc_ssl_opts_copy_to (mongoc_ssl_opt_get_default (), &crypt->aws_tls_opt, false /* copy internal */); } if (!has_azure) { _mongoc_ssl_opts_copy_to (mongoc_ssl_opt_get_default (), &crypt->azure_tls_opt, false /* copy internal */); } if (!has_gcp) { _mongoc_ssl_opts_copy_to (mongoc_ssl_opt_get_default (), &crypt->gcp_tls_opt, false /* copy internal */); } if (!has_kmip) { _mongoc_ssl_opts_copy_to (mongoc_ssl_opt_get_default (), &crypt->kmip_tls_opt, false /* copy internal */); } ok = true; fail: return ok; } /* Note, _mongoc_crypt_t only has one member, to the top-level handle of libmongocrypt, mongocrypt_t. The purpose of defining _mongoc_crypt_t is to limit all interaction with libmongocrypt to this one file. */ _mongoc_crypt_t * _mongoc_crypt_new (const bson_t *kms_providers, const bson_t *schema_map, const bson_t *encrypted_fields_map, const bson_t *tls_opts, const char *crypt_shared_lib_path, bool crypt_shared_lib_required, bool bypass_auto_encryption, bool bypass_query_analysis, mc_kms_credentials_callback creds_cb, mcd_optional_u64_t cache_expiration_ms, bson_error_t *error) { _mongoc_crypt_t *crypt; mongocrypt_binary_t *local_masterkey_bin = NULL; mongocrypt_binary_t *schema_map_bin = NULL; mongocrypt_binary_t *encrypted_fields_map_bin = NULL; mongocrypt_binary_t *kms_providers_bin = NULL; bool success = false; /* Create the handle to libmongocrypt. */ crypt = bson_malloc0 (sizeof (*crypt)); crypt->kmsid_to_tlsopts = mcd_mapof_kmsid_to_tlsopts_new (); crypt->handle = mongocrypt_new (); mongocrypt_setopt_retry_kms (crypt->handle, true); // Stash away a copy of the user's kmsProviders in case we need to lazily // load credentials. bson_copy_to (kms_providers, &crypt->kms_providers); if (!_parse_all_tls_opts (crypt, tls_opts, error)) { goto fail; } mongocrypt_setopt_log_handler (crypt->handle, _log_callback, NULL /* context */); kms_providers_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (kms_providers), kms_providers->len); if (!mongocrypt_setopt_kms_providers (crypt->handle, kms_providers_bin)) { _crypt_check_error (crypt->handle, error, true); goto fail; } if (schema_map) { schema_map_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (schema_map), schema_map->len); if (!mongocrypt_setopt_schema_map (crypt->handle, schema_map_bin)) { _crypt_check_error (crypt->handle, error, true); goto fail; } } if (encrypted_fields_map) { encrypted_fields_map_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (encrypted_fields_map), encrypted_fields_map->len); if (!mongocrypt_setopt_encrypted_field_config_map (crypt->handle, encrypted_fields_map_bin)) { _crypt_check_error (crypt->handle, error, true); goto fail; } } if (!bypass_auto_encryption) { mongocrypt_setopt_append_crypt_shared_lib_search_path (crypt->handle, "$SYSTEM"); if (!_crypt_check_error (crypt->handle, error, false)) { goto fail; } if (crypt_shared_lib_path != NULL) { mongocrypt_setopt_set_crypt_shared_lib_path_override (crypt->handle, crypt_shared_lib_path); if (!_crypt_check_error (crypt->handle, error, false)) { goto fail; } } } if (bypass_query_analysis) { mongocrypt_setopt_bypass_query_analysis (crypt->handle); if (!_crypt_check_error (crypt->handle, error, false)) { goto fail; } } // Enable the NEEDS_CREDENTIALS state for on-demand credential loading mongocrypt_setopt_use_need_kms_credentials_state (crypt->handle); if (!mongocrypt_setopt_use_range_v2 (crypt->handle)) { _crypt_check_error (crypt->handle, error, true); goto fail; } if (cache_expiration_ms.set) { mongocrypt_setopt_key_expiration (crypt->handle, cache_expiration_ms.value); if (!_crypt_check_error (crypt->handle, error, false)) { goto fail; } } if (!mongocrypt_init (crypt->handle)) { _crypt_check_error (crypt->handle, error, true); goto fail; } if (crypt_shared_lib_required) { uint32_t len = 0; const char *s = mongocrypt_crypt_shared_lib_version_string (crypt->handle, &len); if (!s || len == 0) { // empty/null version string indicates that crypt_shared was not loaded // by libmongocrypt bson_set_error (error, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "Option 'cryptSharedLibRequired' is 'true', but failed to " "load the crypt_shared runtime library"); goto fail; } mongoc_log ( MONGOC_LOG_LEVEL_DEBUG, MONGOC_LOG_DOMAIN, "crypt_shared library version '%s' was found and loaded", s); } crypt->creds_cb = creds_cb; success = true; fail: mongocrypt_binary_destroy (local_masterkey_bin); mongocrypt_binary_destroy (encrypted_fields_map_bin); mongocrypt_binary_destroy (schema_map_bin); mongocrypt_binary_destroy (kms_providers_bin); if (!success) { _mongoc_crypt_destroy (crypt); return NULL; } return crypt; } void _mongoc_crypt_destroy (_mongoc_crypt_t *crypt) { if (!crypt) { return; } mongocrypt_destroy (crypt->handle); _mongoc_ssl_opts_cleanup (&crypt->kmip_tls_opt, true /* free_internal */); _mongoc_ssl_opts_cleanup (&crypt->aws_tls_opt, true /* free_internal */); _mongoc_ssl_opts_cleanup (&crypt->azure_tls_opt, true /* free_internal */); _mongoc_ssl_opts_cleanup (&crypt->gcp_tls_opt, true /* free_internal */); bson_destroy (&crypt->kms_providers); mcd_azure_access_token_destroy (&crypt->azure_token); mcd_mapof_kmsid_to_tlsopts_destroy (crypt->kmsid_to_tlsopts); bson_free (crypt); } bool _mongoc_crypt_auto_encrypt (_mongoc_crypt_t *crypt, mongoc_collection_t *keyvault_coll, mongoc_client_t *mongocryptd_client, mongoc_client_t *collinfo_client, const char *db_name, const bson_t *cmd_in, bson_t *cmd_out, bson_error_t *error) { _state_machine_t *state_machine = NULL; mongocrypt_binary_t *cmd_bin = NULL; bool ret = false; BSON_ASSERT_PARAM (collinfo_client); bson_init (cmd_out); state_machine = _state_machine_new (crypt); state_machine->keyvault_coll = keyvault_coll; state_machine->mongocryptd_client = mongocryptd_client; state_machine->collinfo_client = collinfo_client; state_machine->db_name = db_name; state_machine->ctx = mongocrypt_ctx_new (crypt->handle); if (!state_machine->ctx) { _crypt_check_error (crypt->handle, error, true); goto fail; } cmd_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (cmd_in), cmd_in->len); if (!mongocrypt_ctx_encrypt_init (state_machine->ctx, db_name, -1, cmd_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } bson_destroy (cmd_out); if (!_state_machine_run (state_machine, cmd_out, error)) { goto fail; } ret = true; fail: mongocrypt_binary_destroy (cmd_bin); _state_machine_destroy (state_machine); return ret; } bool _mongoc_crypt_auto_decrypt (_mongoc_crypt_t *crypt, mongoc_collection_t *keyvault_coll, const bson_t *doc_in, bson_t *doc_out, bson_error_t *error) { bool ret = false; _state_machine_t *state_machine = NULL; mongocrypt_binary_t *doc_bin = NULL; bson_init (doc_out); state_machine = _state_machine_new (crypt); state_machine->keyvault_coll = keyvault_coll; state_machine->ctx = mongocrypt_ctx_new (crypt->handle); if (!state_machine->ctx) { _crypt_check_error (crypt->handle, error, true); goto fail; } doc_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (doc_in), doc_in->len); if (!mongocrypt_ctx_decrypt_init (state_machine->ctx, doc_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } bson_destroy (doc_out); if (!_state_machine_run (state_machine, doc_out, error)) { goto fail; } ret = true; fail: mongocrypt_binary_destroy (doc_bin); _state_machine_destroy (state_machine); return ret; } // _create_explicit_state_machine_t creates a _state_machine_t for explicit // encryption. The returned state machine may be used encrypting a value or // encrypting an expression. static _state_machine_t * _create_explicit_state_machine (_mongoc_crypt_t *crypt, mongoc_collection_t *keyvault_coll, const char *algorithm, const bson_value_t *keyid, const char *keyaltname, const char *query_type, const int64_t *contention_factor, const bson_t *range_opts, bson_error_t *error) { BSON_ASSERT_PARAM (crypt); BSON_ASSERT_PARAM (keyvault_coll); BSON_OPTIONAL_PARAM (algorithm); BSON_OPTIONAL_PARAM (keyid); BSON_OPTIONAL_PARAM (keyaltname); BSON_OPTIONAL_PARAM (query_type); BSON_OPTIONAL_PARAM (range_opts); BSON_OPTIONAL_PARAM (error); _state_machine_t *state_machine = NULL; bool ok = false; /* Create the context for the operation. */ state_machine = _state_machine_new (crypt); state_machine->keyvault_coll = keyvault_coll; state_machine->ctx = mongocrypt_ctx_new (crypt->handle); if (!state_machine->ctx) { _crypt_check_error (crypt->handle, error, true); goto fail; } if (!mongocrypt_ctx_setopt_algorithm (state_machine->ctx, algorithm, -1)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } if (range_opts != NULL) { /* mongocrypt error checks and parses range options */ mongocrypt_binary_t *binary_range_opts = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (range_opts), range_opts->len); if (!mongocrypt_ctx_setopt_algorithm_range (state_machine->ctx, binary_range_opts)) { mongocrypt_binary_destroy (binary_range_opts); _ctx_check_error (state_machine->ctx, error, true); goto fail; } mongocrypt_binary_destroy (binary_range_opts); } if (query_type != NULL) { if (!mongocrypt_ctx_setopt_query_type (state_machine->ctx, query_type, -1)) { goto fail; } } if (contention_factor != NULL) { if (!mongocrypt_ctx_setopt_contention_factor (state_machine->ctx, *contention_factor)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } } if (keyaltname) { bool keyaltname_ret; mongocrypt_binary_t *keyaltname_bin; bson_t *keyaltname_doc; keyaltname_doc = BCON_NEW ("keyAltName", keyaltname); keyaltname_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (keyaltname_doc), keyaltname_doc->len); keyaltname_ret = mongocrypt_ctx_setopt_key_alt_name (state_machine->ctx, keyaltname_bin); mongocrypt_binary_destroy (keyaltname_bin); bson_destroy (keyaltname_doc); if (!keyaltname_ret) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } } if (keyid && keyid->value_type == BSON_TYPE_BINARY) { mongocrypt_binary_t *keyid_bin; bool keyid_ret; if (keyid->value.v_binary.subtype != BSON_SUBTYPE_UUID) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, "keyid must be a UUID"); goto fail; } keyid_bin = mongocrypt_binary_new_from_data (keyid->value.v_binary.data, keyid->value.v_binary.data_len); keyid_ret = mongocrypt_ctx_setopt_key_id (state_machine->ctx, keyid_bin); mongocrypt_binary_destroy (keyid_bin); if (!keyid_ret) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } } ok = true; fail: if (!ok) { _state_machine_destroy (state_machine); state_machine = NULL; } return state_machine; } bool _mongoc_crypt_explicit_encrypt (_mongoc_crypt_t *crypt, mongoc_collection_t *keyvault_coll, const char *algorithm, const bson_value_t *keyid, const char *keyaltname, const char *query_type, const int64_t *contention_factor, const bson_t *range_opts, const bson_value_t *value_in, bson_value_t *value_out, bson_error_t *error) { BSON_ASSERT_PARAM (crypt); BSON_ASSERT_PARAM (keyvault_coll); BSON_OPTIONAL_PARAM (algorithm); BSON_OPTIONAL_PARAM (keyid); BSON_OPTIONAL_PARAM (keyaltname); BSON_OPTIONAL_PARAM (query_type); BSON_OPTIONAL_PARAM (range_opts); BSON_ASSERT_PARAM (value_in); BSON_ASSERT_PARAM (value_out); BSON_OPTIONAL_PARAM (error); _state_machine_t *state_machine = NULL; bson_t *to_encrypt_doc = NULL; mongocrypt_binary_t *to_encrypt_bin = NULL; bson_iter_t iter; bool ret = false; bson_t result = BSON_INITIALIZER; value_out->value_type = BSON_TYPE_EOD; state_machine = _create_explicit_state_machine ( crypt, keyvault_coll, algorithm, keyid, keyaltname, query_type, contention_factor, range_opts, error); if (!state_machine) { goto fail; } to_encrypt_doc = bson_new (); BSON_APPEND_VALUE (to_encrypt_doc, "v", value_in); to_encrypt_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (to_encrypt_doc), to_encrypt_doc->len); if (!mongocrypt_ctx_explicit_encrypt_init (state_machine->ctx, to_encrypt_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } bson_destroy (&result); if (!_state_machine_run (state_machine, &result, error)) { goto fail; } /* extract value */ if (!bson_iter_init_find (&iter, &result, "v")) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "encrypted result unexpected: no 'v' found"); goto fail; } else { const bson_value_t *tmp; tmp = bson_iter_value (&iter); bson_value_copy (tmp, value_out); } ret = true; fail: _state_machine_destroy (state_machine); mongocrypt_binary_destroy (to_encrypt_bin); bson_destroy (to_encrypt_doc); bson_destroy (&result); return ret; } bool _mongoc_crypt_explicit_encrypt_expression (_mongoc_crypt_t *crypt, mongoc_collection_t *keyvault_coll, const char *algorithm, const bson_value_t *keyid, const char *keyaltname, const char *query_type, const int64_t *contention_factor, const bson_t *range_opts, const bson_t *expr_in, bson_t *expr_out, bson_error_t *error) { BSON_ASSERT_PARAM (crypt); BSON_ASSERT_PARAM (keyvault_coll); BSON_OPTIONAL_PARAM (algorithm); BSON_OPTIONAL_PARAM (keyid); BSON_OPTIONAL_PARAM (keyaltname); BSON_OPTIONAL_PARAM (query_type); BSON_OPTIONAL_PARAM (range_opts); BSON_ASSERT_PARAM (expr_in); BSON_ASSERT_PARAM (expr_out); BSON_OPTIONAL_PARAM (error); _state_machine_t *state_machine = NULL; bson_t *to_encrypt_doc = NULL; mongocrypt_binary_t *to_encrypt_bin = NULL; bson_iter_t iter; bool ret = false; bson_t result = BSON_INITIALIZER; bson_init (expr_out); state_machine = _create_explicit_state_machine ( crypt, keyvault_coll, algorithm, keyid, keyaltname, query_type, contention_factor, range_opts, error); if (!state_machine) { goto fail; } to_encrypt_doc = bson_new (); BSON_APPEND_DOCUMENT (to_encrypt_doc, "v", expr_in); to_encrypt_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (to_encrypt_doc), to_encrypt_doc->len); if (!mongocrypt_ctx_explicit_encrypt_expression_init (state_machine->ctx, to_encrypt_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } bson_destroy (&result); if (!_state_machine_run (state_machine, &result, error)) { goto fail; } /* extract document */ if (!bson_iter_init_find (&iter, &result, "v")) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "encrypted result unexpected: no 'v' found"); goto fail; } else { bson_t tmp; if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_set_error (error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "encrypted result unexpected: 'v' is not a document, got: %s", _mongoc_bson_type_to_str (bson_iter_type (&iter))); goto fail; } if (!_mongoc_iter_document_as_bson (&iter, &tmp, error)) { goto fail; } bson_copy_to (&tmp, expr_out); } ret = true; fail: _state_machine_destroy (state_machine); mongocrypt_binary_destroy (to_encrypt_bin); bson_destroy (to_encrypt_doc); bson_destroy (&result); return ret; } bool _mongoc_crypt_explicit_decrypt (_mongoc_crypt_t *crypt, mongoc_collection_t *keyvault_coll, const bson_value_t *value_in, bson_value_t *value_out, bson_error_t *error) { _state_machine_t *state_machine = NULL; bson_t *to_decrypt_doc = NULL; mongocrypt_binary_t *to_decrypt_bin = NULL; bson_iter_t iter; bool ret = false; bson_t result = BSON_INITIALIZER; state_machine = _state_machine_new (crypt); state_machine->keyvault_coll = keyvault_coll; state_machine->ctx = mongocrypt_ctx_new (crypt->handle); if (!state_machine->ctx) { _crypt_check_error (crypt->handle, error, true); goto fail; } to_decrypt_doc = bson_new (); BSON_APPEND_VALUE (to_decrypt_doc, "v", value_in); to_decrypt_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (to_decrypt_doc), to_decrypt_doc->len); if (!mongocrypt_ctx_explicit_decrypt_init (state_machine->ctx, to_decrypt_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } bson_destroy (&result); if (!_state_machine_run (state_machine, &result, error)) { goto fail; } /* extract value */ if (!bson_iter_init_find (&iter, &result, "v")) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, "decrypted result unexpected"); goto fail; } else { const bson_value_t *tmp; tmp = bson_iter_value (&iter); bson_value_copy (tmp, value_out); } ret = true; fail: _state_machine_destroy (state_machine); mongocrypt_binary_destroy (to_decrypt_bin); bson_destroy (to_decrypt_doc); bson_destroy (&result); return ret; } bool _mongoc_crypt_create_datakey (_mongoc_crypt_t *crypt, const char *kms_provider, const bson_t *masterkey, char **keyaltnames, uint32_t keyaltnames_count, const uint8_t *keymaterial, uint32_t keymaterial_len, bson_t *doc_out, bson_error_t *error) { _state_machine_t *state_machine = NULL; bool ret = false; bson_t masterkey_w_provider = BSON_INITIALIZER; mongocrypt_binary_t *masterkey_w_provider_bin = NULL; bson_init (doc_out); state_machine = _state_machine_new (crypt); state_machine->ctx = mongocrypt_ctx_new (crypt->handle); if (!state_machine->ctx) { _crypt_check_error (crypt->handle, error, true); goto fail; } BSON_APPEND_UTF8 (&masterkey_w_provider, "provider", kms_provider); if (masterkey) { bson_concat (&masterkey_w_provider, masterkey); } masterkey_w_provider_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (&masterkey_w_provider), masterkey_w_provider.len); if (!mongocrypt_ctx_setopt_key_encryption_key (state_machine->ctx, masterkey_w_provider_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } if (keyaltnames) { for (uint32_t i = 0u; i < keyaltnames_count; i++) { bool keyaltname_ret; mongocrypt_binary_t *keyaltname_bin; bson_t *keyaltname_doc; keyaltname_doc = BCON_NEW ("keyAltName", keyaltnames[i]); keyaltname_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (keyaltname_doc), keyaltname_doc->len); keyaltname_ret = mongocrypt_ctx_setopt_key_alt_name (state_machine->ctx, keyaltname_bin); mongocrypt_binary_destroy (keyaltname_bin); bson_destroy (keyaltname_doc); if (!keyaltname_ret) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } } } if (keymaterial) { bson_t *const bson = BCON_NEW ("keyMaterial", BCON_BIN (BSON_SUBTYPE_BINARY, keymaterial, keymaterial_len)); mongocrypt_binary_t *const bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (bson), bson->len); mongocrypt_ctx_setopt_key_material (state_machine->ctx, bin); bson_destroy (bson); mongocrypt_binary_destroy (bin); } if (!mongocrypt_ctx_datakey_init (state_machine->ctx)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } bson_destroy (doc_out); if (!_state_machine_run (state_machine, doc_out, error)) { goto fail; } ret = true; fail: bson_destroy (&masterkey_w_provider); mongocrypt_binary_destroy (masterkey_w_provider_bin); _state_machine_destroy (state_machine); return ret; } bool _mongoc_crypt_rewrap_many_datakey (_mongoc_crypt_t *crypt, mongoc_collection_t *keyvault_coll, const bson_t *filter, const char *provider, const bson_t *master_key, bson_t *doc_out, bson_error_t *error) { _state_machine_t *state_machine = NULL; const bson_t empty_bson = BSON_INITIALIZER; mongocrypt_binary_t *filter_bin = NULL; bool ret = false; // Caller must ensure `provider` is provided alongside `master_key`. BSON_ASSERT (!master_key || provider); bson_init (doc_out); state_machine = _state_machine_new (crypt); state_machine->keyvault_coll = keyvault_coll; state_machine->ctx = mongocrypt_ctx_new (crypt->handle); if (!state_machine->ctx) { _crypt_check_error (crypt->handle, error, true); goto fail; } { bson_t new_provider = BSON_INITIALIZER; mongocrypt_binary_t *new_provider_bin = NULL; bool success = true; if (provider) { BSON_APPEND_UTF8 (&new_provider, "provider", provider); if (master_key) { bson_concat (&new_provider, master_key); } new_provider_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (&new_provider), new_provider.len); if (!mongocrypt_ctx_setopt_key_encryption_key (state_machine->ctx, new_provider_bin)) { _ctx_check_error (state_machine->ctx, error, true); success = false; } mongocrypt_binary_destroy (new_provider_bin); } bson_destroy (&new_provider); if (!success) { goto fail; } } if (!filter) { filter = &empty_bson; } filter_bin = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (filter), filter->len); if (!mongocrypt_ctx_rewrap_many_datakey_init (state_machine->ctx, filter_bin)) { _ctx_check_error (state_machine->ctx, error, true); goto fail; } bson_destroy (doc_out); if (!_state_machine_run (state_machine, doc_out, error)) { goto fail; } ret = true; fail: mongocrypt_binary_destroy (filter_bin); _state_machine_destroy (state_machine); return ret; } const char * _mongoc_crypt_get_crypt_shared_version (const _mongoc_crypt_t *crypt) { return mongocrypt_crypt_shared_lib_version_string (crypt->handle, NULL); } #else /* ensure the translation unit is not empty */ extern int no_mongoc_client_side_encryption; #endif /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypto-cng-private.h0000644000175100001660000000561114760300420024677 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_CRYPTO_CNG #ifndef MONGOC_CRYPTO_CNG_PRIVATE_H #define MONGOC_CRYPTO_CNG_PRIVATE_H #include BSON_BEGIN_DECLS void mongoc_crypto_cng_init (void); void mongoc_crypto_cng_cleanup (void); bool mongoc_crypto_cng_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output); void mongoc_crypto_cng_hmac_sha1 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out); bool mongoc_crypto_cng_sha1 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out); bool mongoc_crypto_cng_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output); void mongoc_crypto_cng_hmac_sha256 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out); bool mongoc_crypto_cng_sha256 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out); BSON_END_DECLS #endif /* MONGOC_CRYPTO_CNG_PRIVATE_H */ #endif /* MONGOC_ENABLE_CRYPTO_CNG */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypto-cng.c0000644000175100001660000002664114760300420023230 0ustar /* Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_CRYPTO_CNG #include #include #include #include #include #include #include #include #include #include #define NT_SUCCESS(Status) (((NTSTATUS) (Status)) >= 0) #define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L) static BCRYPT_ALG_HANDLE _sha1_hash_algo; static BCRYPT_ALG_HANDLE _sha1_hmac_algo; static BCRYPT_ALG_HANDLE _sha256_hash_algo; static BCRYPT_ALG_HANDLE _sha256_hmac_algo; void mongoc_crypto_cng_init (void) { NTSTATUS status = STATUS_UNSUCCESSFUL; _sha1_hash_algo = 0; status = BCryptOpenAlgorithmProvider (&_sha1_hash_algo, BCRYPT_SHA1_ALGORITHM, NULL, 0); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptOpenAlgorithmProvider(SHA1): %ld", status); } _sha1_hmac_algo = 0; status = BCryptOpenAlgorithmProvider (&_sha1_hmac_algo, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptOpenAlgorithmProvider(SHA1 HMAC): %ld", status); } _sha256_hash_algo = 0; status = BCryptOpenAlgorithmProvider (&_sha256_hash_algo, BCRYPT_SHA256_ALGORITHM, NULL, 0); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptOpenAlgorithmProvider(SHA256): %ld", status); } _sha256_hmac_algo = 0; status = BCryptOpenAlgorithmProvider (&_sha256_hmac_algo, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptOpenAlgorithmProvider(SHA256 HMAC): %ld", status); } } void mongoc_crypto_cng_cleanup (void) { if (_sha1_hash_algo) { BCryptCloseAlgorithmProvider (&_sha1_hash_algo, 0); } if (_sha1_hmac_algo) { BCryptCloseAlgorithmProvider (&_sha1_hmac_algo, 0); } if (_sha256_hash_algo) { BCryptCloseAlgorithmProvider (&_sha256_hash_algo, 0); } if (_sha256_hmac_algo) { BCryptCloseAlgorithmProvider (&_sha256_hmac_algo, 0); } } bool _mongoc_crypto_cng_hmac_or_hash ( BCRYPT_ALG_HANDLE algorithm, const void *key, size_t key_length, void *data, size_t data_length, void *output) { unsigned char *hash_object_buffer = 0; ULONG hash_object_length = 0; BCRYPT_HASH_HANDLE hash = 0; ULONG mac_length = 0; NTSTATUS status = STATUS_UNSUCCESSFUL; bool retval = false; ULONG noop = 0; status = BCryptGetProperty ( algorithm, BCRYPT_OBJECT_LENGTH, (unsigned char *) &hash_object_length, sizeof hash_object_length, &noop, 0); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptGetProperty(): OBJECT_LENGTH %ld", status); return false; } status = BCryptGetProperty (algorithm, BCRYPT_HASH_LENGTH, (unsigned char *) &mac_length, sizeof mac_length, &noop, 0); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptGetProperty(): HASH_LENGTH %ld", status); return false; } hash_object_buffer = bson_malloc (hash_object_length); status = BCryptCreateHash (algorithm, &hash, hash_object_buffer, hash_object_length, (PUCHAR) key, (ULONG) key_length, 0); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptCreateHash(): %ld", status); goto cleanup; } status = BCryptHashData (hash, data, (ULONG) data_length, 0); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptHashData(): %ld", status); goto cleanup; } status = BCryptFinishHash (hash, output, mac_length, 0); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptFinishHash(): %ld", status); goto cleanup; } retval = true; cleanup: if (hash) { (void) BCryptDestroyHash (hash); } bson_free (hash_object_buffer); return retval; } #if defined(MONGOC_HAVE_BCRYPT_PBKDF2) // Ensure lossless conversion between `uint64_t` and `ULONGLONG` below. BSON_STATIC_ASSERT2 (sizeof_ulonglong_uint64_t, sizeof (ULONGLONG) == sizeof (uint64_t)); /* Wrapper for BCryptDeriveKeyPBKDF2 */ static bool _bcrypt_derive_key_pbkdf2 (BCRYPT_ALG_HANDLE prf, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output) { if (BSON_UNLIKELY (mcommon_cmp_greater_uu (password_len, ULONG_MAX))) { MONGOC_ERROR ("PBDKF2 HMAC password length exceeds ULONG_MAX"); return false; } if (BSON_UNLIKELY (mcommon_cmp_greater_uu (salt_len, ULONG_MAX))) { MONGOC_ERROR ("PBDKF2 HMAC salt length exceeds ULONG_MAX"); return false; } // `(ULONGLONG) iterations` is statically asserted above. if (BSON_UNLIKELY (mcommon_cmp_greater_uu (output_len, ULONG_MAX))) { MONGOC_ERROR ("PBDKF2 HMAC output length exceeds ULONG_MAX"); return false; } // Make non-const versions of password and salt. unsigned char *password_copy = bson_malloc (password_len); memcpy (password_copy, password, password_len); unsigned char *salt_copy = bson_malloc (salt_len); memcpy (salt_copy, salt, salt_len); NTSTATUS status = BCryptDeriveKeyPBKDF2 (prf, password_copy, (ULONG) password_len, salt_copy, (ULONG) salt_len, (ULONGLONG) iterations, output, (ULONG) output_len, 0); bson_free (password_copy); bson_free (salt_copy); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("_bcrypt_derive_key_pbkdf2(): %ld", status); return false; } return true; } #else static size_t _crypto_hash_size (mongoc_crypto_t *crypto) { if (crypto->algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_1) { return MONGOC_SCRAM_SHA_1_HASH_SIZE; } else if (crypto->algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_256) { return MONGOC_SCRAM_SHA_256_HASH_SIZE; } else { BSON_UNREACHABLE ("Unexpected crypto algorithm"); } } /* Manually salts password if BCryptDeriveKeyPBKDF2 is unavailable */ static bool _bcrypt_derive_key_pbkdf2 (BCRYPT_ALG_HANDLE algorithm, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t hash_size, unsigned char *output) { uint8_t intermediate_digest[MONGOC_SCRAM_HASH_MAX_SIZE]; uint8_t start_key[MONGOC_SCRAM_HASH_MAX_SIZE]; memcpy (start_key, salt, salt_len); start_key[salt_len] = 0; start_key[salt_len + 1] = 0; start_key[salt_len + 2] = 0; start_key[salt_len + 3] = 1; if (!_mongoc_crypto_cng_hmac_or_hash (algorithm, password, password_len, start_key, hash_size, output)) { return false; } memcpy (intermediate_digest, output, hash_size); for (uint32_t i = 2u; i <= iterations; i++) { if (!_mongoc_crypto_cng_hmac_or_hash ( algorithm, password, password_len, intermediate_digest, hash_size, output)) { return false; } for (size_t k = 0; k < hash_size; k++) { output[k] ^= intermediate_digest[k]; } } return true; } #endif bool mongoc_crypto_cng_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output) { #if defined(MONGOC_HAVE_BCRYPT_PBKDF2) return _bcrypt_derive_key_pbkdf2 ( _sha1_hmac_algo, password, password_len, salt, salt_len, iterations, output_len, output); #else return _bcrypt_derive_key_pbkdf2 ( _sha1_hmac_algo, password, password_len, salt, salt_len, iterations, _crypto_hash_size (crypto), output); #endif } void mongoc_crypto_cng_hmac_sha1 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out) { if (!_sha1_hmac_algo) { return; } _mongoc_crypto_cng_hmac_or_hash (_sha1_hmac_algo, key, key_len, (void *) data, data_len, hmac_out); } bool mongoc_crypto_cng_sha1 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out) { bool res; if (!_sha1_hash_algo) { return false; } res = _mongoc_crypto_cng_hmac_or_hash (_sha1_hash_algo, NULL, 0, (void *) input, input_len, hash_out); return res; } bool mongoc_crypto_cng_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output) { #if defined(MONGOC_HAVE_BCRYPT_PBKDF2) BSON_UNUSED (crypto); return _bcrypt_derive_key_pbkdf2 ( _sha256_hmac_algo, password, password_len, salt, salt_len, iterations, output_len, output); #else BSON_UNUSED (output_len); return _bcrypt_derive_key_pbkdf2 ( _sha256_hmac_algo, password, password_len, salt, salt_len, iterations, _crypto_hash_size (crypto), output); #endif } void mongoc_crypto_cng_hmac_sha256 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out) { if (!_sha256_hmac_algo) { return; } _mongoc_crypto_cng_hmac_or_hash (_sha256_hmac_algo, key, key_len, (void *) data, data_len, hmac_out); } bool mongoc_crypto_cng_sha256 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out) { bool res; if (!_sha256_hash_algo) { return false; } res = _mongoc_crypto_cng_hmac_or_hash (_sha256_hash_algo, NULL, 0, (void *) input, input_len, hash_out); return res; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypto-common-crypto-private.h0000644000175100001660000000632414760300420026740 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO #ifndef MONGOC_CRYPTO_COMMON_CRYPTO_PRIVATE_H #define MONGOC_CRYPTO_COMMON_CRYPTO_PRIVATE_H #include BSON_BEGIN_DECLS bool mongoc_crypto_common_crypto_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output); void mongoc_crypto_common_crypto_hmac_sha1 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out); bool mongoc_crypto_common_crypto_sha1 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out); bool mongoc_crypto_common_crypto_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output); void mongoc_crypto_common_crypto_hmac_sha256 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out); bool mongoc_crypto_common_crypto_sha256 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out); BSON_END_DECLS #endif /* MONGOC_CRYPTO_COMMON_CRYPTO_PRIVATE_H */ #endif /* MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypto-common-crypto.c0000644000175100001660000001154614760300420025265 0ustar /* Copyright 2009-present MongoDB, 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. */ #include #include #ifdef MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO #include #include #include #include #include // Ensure lossless conversion between `uint32_t` and `uint` below. BSON_STATIC_ASSERT2 (sizeof_uint_uint32_t, sizeof (uint) == sizeof (uint32_t)); bool mongoc_crypto_common_crypto_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output) { BSON_UNUSED (crypto); return kCCSuccess == CCKeyDerivationPBKDF (kCCPBKDF2, password, password_len, salt, salt_len, kCCPRFHmacAlgSHA1, (uint) iterations, output, output_len); } void mongoc_crypto_common_crypto_hmac_sha1 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out) { /* U1 = HMAC(input, salt + 0001) */ CCHmac (kCCHmacAlgSHA1, key, (size_t) key_len, data, (size_t) data_len, hmac_out); } bool mongoc_crypto_common_crypto_sha1 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out) { if (CC_SHA1 (input, (CC_LONG) input_len, hash_out)) { return true; } return false; } bool mongoc_crypto_common_crypto_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output) { BSON_UNUSED (crypto); return kCCSuccess == CCKeyDerivationPBKDF (kCCPBKDF2, password, password_len, salt, salt_len, kCCPRFHmacAlgSHA256, (uint) iterations, output, output_len); } void mongoc_crypto_common_crypto_hmac_sha256 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out) { CCHmac (kCCHmacAlgSHA256, key, (size_t) key_len, data, (size_t) data_len, hmac_out); } bool mongoc_crypto_common_crypto_sha256 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out) { if (CC_SHA256 (input, (CC_LONG) input_len, hash_out)) { return true; } return false; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypto-openssl-private.h0000644000175100001660000000604114760300420025611 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #ifdef MONGOC_ENABLE_CRYPTO_LIBCRYPTO #ifndef MONGOC_CRYPTO_OPENSSL_PRIVATE_H #define MONGOC_CRYPTO_OPENSSL_PRIVATE_H #include BSON_BEGIN_DECLS bool mongoc_crypto_openssl_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output); void mongoc_crypto_openssl_hmac_sha1 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out); bool mongoc_crypto_openssl_sha1 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out); bool mongoc_crypto_openssl_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output); void mongoc_crypto_openssl_hmac_sha256 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out); bool mongoc_crypto_openssl_sha256 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out); BSON_END_DECLS #endif /* MONGOC_CRYPTO_OPENSSL_PRIVATE_H */ #endif /* MONGOC_ENABLE_CRYPTO_LIBCRYPTO */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypto-openssl.c0000644000175100001660000001474114760300420024142 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #ifdef MONGOC_ENABLE_CRYPTO_LIBCRYPTO #include #include #include #include #include #include #include bool mongoc_crypto_openssl_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output) { BSON_UNUSED (crypto); if (BSON_UNLIKELY (mcommon_cmp_greater_us (password_len, INT_MAX))) { MONGOC_ERROR ("PBKDF2 HMAC password length exceeds INT_MAX"); return false; } if (BSON_UNLIKELY (mcommon_cmp_greater_us (salt_len, INT_MAX))) { MONGOC_ERROR ("PBKDF2 HMAC salt length exceeds INT_MAX"); return false; } if (BSON_UNLIKELY (mcommon_cmp_greater_us (iterations, INT_MAX))) { MONGOC_ERROR ("PBKDF2 HMAC iteration count exceeds INT_MAX"); return false; } if (BSON_UNLIKELY (mcommon_cmp_greater_us (iterations, INT_MAX))) { MONGOC_ERROR ("PBKDF2 HMAC output buffer length exceeds INT_MAX"); return false; } return 0 != PKCS5_PBKDF2_HMAC (password, (int) password_len, salt, (int) salt_len, (int) iterations, EVP_sha1 (), (int) output_len, output); } void mongoc_crypto_openssl_hmac_sha1 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out) { BSON_UNUSED (crypto); /* U1 = HMAC(input, salt + 0001) */ HMAC (EVP_sha1 (), key, key_len, data, data_len, hmac_out, NULL); } #if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) static EVP_MD_CTX * EVP_MD_CTX_new (void) { return bson_malloc0 (sizeof (EVP_MD_CTX)); } static void EVP_MD_CTX_free (EVP_MD_CTX *ctx) { EVP_MD_CTX_cleanup (ctx); bson_free (ctx); } #endif bool mongoc_crypto_openssl_sha1 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out) { EVP_MD_CTX *digest_ctxp = EVP_MD_CTX_new (); bool rval = false; BSON_UNUSED (crypto); if (1 != EVP_DigestInit_ex (digest_ctxp, EVP_sha1 (), NULL)) { goto cleanup; } if (1 != EVP_DigestUpdate (digest_ctxp, input, input_len)) { goto cleanup; } rval = (1 == EVP_DigestFinal_ex (digest_ctxp, hash_out, NULL)); cleanup: EVP_MD_CTX_free (digest_ctxp); return rval; } bool mongoc_crypto_openssl_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output) { BSON_UNUSED (crypto); if (BSON_UNLIKELY (mcommon_cmp_greater_us (password_len, INT_MAX))) { MONGOC_ERROR ("PBKDF2 HMAC password length exceeds INT_MAX"); return false; } if (BSON_UNLIKELY (mcommon_cmp_greater_us (salt_len, INT_MAX))) { MONGOC_ERROR ("PBKDF2 HMAC salt length exceeds INT_MAX"); return false; } if (BSON_UNLIKELY (mcommon_cmp_greater_us (iterations, INT_MAX))) { MONGOC_ERROR ("PBKDF2 HMAC iteration count exceeds INT_MAX"); return false; } if (BSON_UNLIKELY (mcommon_cmp_greater_us (iterations, INT_MAX))) { MONGOC_ERROR ("PBKDF2 HMAC output buffer length exceeds INT_MAX"); return false; } return 0 != PKCS5_PBKDF2_HMAC (password, (int) password_len, salt, (int) salt_len, (int) iterations, EVP_sha256 (), (int) output_len, output); } void mongoc_crypto_openssl_hmac_sha256 (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out) { BSON_UNUSED (crypto); /* U1 = HMAC(input, salt + 0001) */ HMAC (EVP_sha256 (), key, key_len, data, data_len, hmac_out, NULL); } bool mongoc_crypto_openssl_sha256 (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out) { EVP_MD_CTX *digest_ctxp = EVP_MD_CTX_new (); bool rval = false; BSON_UNUSED (crypto); if (1 != EVP_DigestInit_ex (digest_ctxp, EVP_sha256 (), NULL)) { goto cleanup; } if (1 != EVP_DigestUpdate (digest_ctxp, input, input_len)) { goto cleanup; } rval = (1 == EVP_DigestFinal_ex (digest_ctxp, hash_out, NULL)); cleanup: EVP_MD_CTX_free (digest_ctxp); return rval; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypto-private.h0000644000175100001660000000514714760300420024136 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #ifdef MONGOC_ENABLE_CRYPTO #ifndef MONGOC_CRYPTO_PRIVATE_H #define MONGOC_CRYPTO_PRIVATE_H BSON_BEGIN_DECLS typedef struct _mongoc_crypto_t mongoc_crypto_t; typedef enum { MONGOC_CRYPTO_ALGORITHM_SHA_1, MONGOC_CRYPTO_ALGORITHM_SHA_256 } mongoc_crypto_hash_algorithm_t; struct _mongoc_crypto_t { void (*hmac) (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out); bool (*hash) (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out); bool (*pbkdf) (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output); mongoc_crypto_hash_algorithm_t algorithm; }; void mongoc_crypto_init (mongoc_crypto_t *crypto, mongoc_crypto_hash_algorithm_t algo); bool mongoc_crypto_pbkdf (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output); void mongoc_crypto_hmac (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out); bool mongoc_crypto_hash (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *hash_out); BSON_END_DECLS #endif /* MONGOC_CRYPTO_PRIVATE_H */ #endif /* MONGOC_ENABLE_CRYPTO */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-crypto.c0000644000175100001660000000717414760300420022463 0ustar /* Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_CRYPTO #include #include #include #if defined(MONGOC_ENABLE_CRYPTO_LIBCRYPTO) #include #elif defined(MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO) #include #elif defined(MONGOC_ENABLE_CRYPTO_CNG) #include #endif void mongoc_crypto_init (mongoc_crypto_t *crypto, mongoc_crypto_hash_algorithm_t algo) { crypto->pbkdf = NULL; crypto->hmac = NULL; crypto->hash = NULL; if (algo == MONGOC_CRYPTO_ALGORITHM_SHA_1) { #ifdef MONGOC_ENABLE_CRYPTO_LIBCRYPTO crypto->pbkdf = mongoc_crypto_openssl_pbkdf2_hmac_sha1; crypto->hmac = mongoc_crypto_openssl_hmac_sha1; crypto->hash = mongoc_crypto_openssl_sha1; #elif defined(MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO) crypto->pbkdf = mongoc_crypto_common_crypto_pbkdf2_hmac_sha1; crypto->hmac = mongoc_crypto_common_crypto_hmac_sha1; crypto->hash = mongoc_crypto_common_crypto_sha1; #elif defined(MONGOC_ENABLE_CRYPTO_CNG) crypto->pbkdf = mongoc_crypto_cng_pbkdf2_hmac_sha1; crypto->hmac = mongoc_crypto_cng_hmac_sha1; crypto->hash = mongoc_crypto_cng_sha1; #endif } else if (algo == MONGOC_CRYPTO_ALGORITHM_SHA_256) { #ifdef MONGOC_ENABLE_CRYPTO_LIBCRYPTO crypto->pbkdf = mongoc_crypto_openssl_pbkdf2_hmac_sha256; crypto->hmac = mongoc_crypto_openssl_hmac_sha256; crypto->hash = mongoc_crypto_openssl_sha256; #elif defined(MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO) crypto->pbkdf = mongoc_crypto_common_crypto_pbkdf2_hmac_sha256; crypto->hmac = mongoc_crypto_common_crypto_hmac_sha256; crypto->hash = mongoc_crypto_common_crypto_sha256; #elif defined(MONGOC_ENABLE_CRYPTO_CNG) crypto->pbkdf = mongoc_crypto_cng_pbkdf2_hmac_sha256; crypto->hmac = mongoc_crypto_cng_hmac_sha256; crypto->hash = mongoc_crypto_cng_sha256; #endif } BSON_ASSERT (crypto->pbkdf); BSON_ASSERT (crypto->hmac); BSON_ASSERT (crypto->hash); crypto->algorithm = algo; } bool mongoc_crypto_pbkdf (mongoc_crypto_t *crypto, const char *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iterations, size_t output_len, unsigned char *output) { return crypto->pbkdf (crypto, password, password_len, salt, salt_len, iterations, output_len, output); } void mongoc_crypto_hmac (mongoc_crypto_t *crypto, const void *key, int key_len, const unsigned char *data, int data_len, unsigned char *hmac_out) { crypto->hmac (crypto, key, key_len, data, data_len, hmac_out); } bool mongoc_crypto_hash (mongoc_crypto_t *crypto, const unsigned char *input, const size_t input_len, unsigned char *output) { return crypto->hash (crypto, input, input_len, output); } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-array.c0000644000175100001660000000622314760300420023566 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include typedef struct _data_array_t { bson_t cmd; bson_t array; bson_iter_t iter; bson_t bson; /* current document */ char *field_name; } data_array_t; static mongoc_cursor_state_t _prime (mongoc_cursor_t *cursor) { bson_iter_t iter; data_array_t *data = (data_array_t *) cursor->impl.data; bson_destroy (&data->array); /* this cursor is only used with the listDatabases command. it iterates * over the array in the response's "databases" field. */ if (_mongoc_cursor_run_command (cursor, &data->cmd, &cursor->opts, &data->array, false) && bson_iter_init_find (&iter, &data->array, data->field_name) && BSON_ITER_HOLDS_ARRAY (&iter) && bson_iter_recurse (&iter, &data->iter)) { return IN_BATCH; } return DONE; } static mongoc_cursor_state_t _pop_from_batch (mongoc_cursor_t *cursor) { uint32_t document_len; const uint8_t *document; data_array_t *data = (data_array_t *) cursor->impl.data; if (bson_iter_next (&data->iter)) { bson_iter_document (&data->iter, &document_len, &document); BSON_ASSERT (bson_init_static (&data->bson, document, document_len)); cursor->current = &data->bson; return IN_BATCH; } return DONE; } static void _clone (mongoc_cursor_impl_t *dst, const mongoc_cursor_impl_t *src) { data_array_t *data_dst = BSON_ALIGNED_ALLOC0 (data_array_t); data_array_t *data_src = (data_array_t *) src->data; bson_init (&data_dst->array); bson_copy_to (&data_src->cmd, &data_dst->cmd); data_dst->field_name = bson_strdup (data_src->field_name); dst->data = data_dst; } static void _destroy (mongoc_cursor_impl_t *impl) { data_array_t *data = (data_array_t *) impl->data; bson_destroy (&data->array); bson_destroy (&data->cmd); bson_free (data->field_name); bson_free (data); } mongoc_cursor_t * _mongoc_cursor_array_new ( mongoc_client_t *client, const char *db_and_coll, const bson_t *cmd, const bson_t *opts, const char *field_name) { BSON_ASSERT_PARAM (client); mongoc_cursor_t *cursor = _mongoc_cursor_new_with_opts (client, db_and_coll, opts, NULL, NULL, NULL); data_array_t *data = BSON_ALIGNED_ALLOC0 (data_array_t); bson_copy_to (cmd, &data->cmd); bson_init (&data->array); data->field_name = bson_strdup (field_name); cursor->impl.prime = _prime; cursor->impl.pop_from_batch = _pop_from_batch; cursor->impl.destroy = _destroy; cursor->impl.clone = _clone; cursor->impl.data = (void *) data; return cursor; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-change-stream.c0000644000175100001660000001231114760300420025161 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include typedef struct _data_change_stream_t { mongoc_cursor_response_t response; bson_t post_batch_resume_token; } _data_change_stream_t; static void _update_post_batch_resume_token (mongoc_cursor_t *cursor) { _data_change_stream_t *data = (_data_change_stream_t *) cursor->impl.data; bson_iter_t iter, child; if (mongoc_cursor_error (cursor, NULL)) { return; } if (bson_iter_init (&iter, &data->response.reply) && bson_iter_find_descendant (&iter, "cursor.postBatchResumeToken", &child) && BSON_ITER_HOLDS_DOCUMENT (&child)) { uint32_t len; const uint8_t *buf; bson_t post_batch_resume_token; bson_iter_document (&child, &len, &buf); BSON_ASSERT (bson_init_static (&post_batch_resume_token, buf, len)); bson_destroy (&data->post_batch_resume_token); bson_copy_to (&post_batch_resume_token, &data->post_batch_resume_token); } } static mongoc_cursor_state_t _prime (mongoc_cursor_t *cursor) { BSON_UNUSED (cursor); fprintf (stderr, "Prime unsupported on change stream cursor."); BSON_ASSERT (false); return IN_BATCH; } static mongoc_cursor_state_t _pop_from_batch (mongoc_cursor_t *cursor) { _data_change_stream_t *data = (_data_change_stream_t *) cursor->impl.data; _mongoc_cursor_response_read (cursor, &data->response, &cursor->current); if (cursor->current) { return IN_BATCH; } else { return cursor->cursor_id ? END_OF_BATCH : DONE; } } mongoc_cursor_state_t _get_next_batch (mongoc_cursor_t *cursor) { _data_change_stream_t *data = (_data_change_stream_t *) cursor->impl.data; bson_t getmore_cmd; _mongoc_cursor_prepare_getmore_command (cursor, &getmore_cmd); _mongoc_cursor_response_refresh (cursor, &getmore_cmd, NULL /* opts */, &data->response); bson_destroy (&getmore_cmd); _update_post_batch_resume_token (cursor); return IN_BATCH; } static void _destroy (mongoc_cursor_impl_t *impl) { _data_change_stream_t *data = (_data_change_stream_t *) impl->data; bson_destroy (&data->response.reply); bson_destroy (&data->post_batch_resume_token); bson_free (data); } static void _clone (mongoc_cursor_impl_t *dst, const mongoc_cursor_impl_t *src) { BSON_UNUSED (dst); BSON_UNUSED (src); fprintf (stderr, "Clone unsupported on change stream cursor."); BSON_ASSERT (false); } mongoc_cursor_t * _mongoc_cursor_change_stream_new (mongoc_client_t *client, bson_t *reply, const bson_t *getmore_opts) { mongoc_cursor_t *cursor; _data_change_stream_t *data; BSON_ASSERT_PARAM (client); BSON_ASSERT (reply); data = BSON_ALIGNED_ALLOC0 (_data_change_stream_t); /* _mongoc_cursor_response_t.reply is already uninitialized and we can trust * that reply comes from mongoc_client_read_command_with_opts() */ BSON_ASSERT (bson_steal (&data->response.reply, reply)); bson_init (&data->post_batch_resume_token); cursor = _mongoc_cursor_new_with_opts (client, NULL, getmore_opts, NULL, NULL, NULL); cursor->impl.prime = _prime; cursor->impl.pop_from_batch = _pop_from_batch; cursor->impl.get_next_batch = _get_next_batch; cursor->impl.destroy = _destroy; cursor->impl.clone = _clone; cursor->impl.data = (void *) data; cursor->state = IN_BATCH; if (!_mongoc_cursor_start_reading_response (cursor, &data->response)) { bson_set_error ( &cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Couldn't parse cursor document"); } _update_post_batch_resume_token (cursor); return cursor; } static bool _bson_iter_has_next (bson_iter_t *iter) { bson_iter_t iter_copy = {0}; memcpy (&iter_copy, iter, sizeof (bson_iter_t)); return bson_iter_next (&iter_copy); } bool _mongoc_cursor_change_stream_end_of_batch (mongoc_cursor_t *cursor) { _data_change_stream_t *data = (_data_change_stream_t *) cursor->impl.data; return !_bson_iter_has_next (&data->response.batch_iter); } const bson_t * _mongoc_cursor_change_stream_get_post_batch_resume_token (mongoc_cursor_t *cursor) { _data_change_stream_t *data = (_data_change_stream_t *) cursor->impl.data; return &data->post_batch_resume_token; } bool _mongoc_cursor_change_stream_has_post_batch_resume_token (mongoc_cursor_t *cursor) { _data_change_stream_t *data = (_data_change_stream_t *) cursor->impl.data; return !bson_empty (&data->post_batch_resume_token); } const bson_t * _mongoc_cursor_change_stream_get_reply (mongoc_cursor_t *cursor) { _data_change_stream_t *data = (_data_change_stream_t *) cursor->impl.data; return &data->response.reply; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-cmd-deprecated.c0000644000175100001660000000634014760300420025311 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include /* This cursor is returned by the deprecated functions mongoc_client_command, * mongoc_database_command, and mongoc_collection_command. It runs the command * on the first call to mongoc_cursor_next and returns the only result. */ typedef struct _data_cmd_deprecated_t { bson_t cmd; bson_t reply; } data_cmd_deprecated_t; static mongoc_cursor_state_t _prime (mongoc_cursor_t *cursor) { data_cmd_deprecated_t *data = (data_cmd_deprecated_t *) cursor->impl.data; bson_destroy (&data->reply); if (_mongoc_cursor_run_command (cursor, &data->cmd, &cursor->opts, &data->reply, true)) { return IN_BATCH; } else { return DONE; } } static mongoc_cursor_state_t _pop_from_batch (mongoc_cursor_t *cursor) { data_cmd_deprecated_t *data = (data_cmd_deprecated_t *) cursor->impl.data; cursor->current = &data->reply; /* don't return DONE here. a cursor is marked DONE when it returns NULL. */ return END_OF_BATCH; } static mongoc_cursor_state_t _get_next_batch (mongoc_cursor_t *cursor) { BSON_UNUSED (cursor); /* there's no next batch to get, return DONE immediately. */ return DONE; } static void _clone (mongoc_cursor_impl_t *dst, const mongoc_cursor_impl_t *src) { data_cmd_deprecated_t *data_src = (data_cmd_deprecated_t *) src->data; data_cmd_deprecated_t *data_dst = BSON_ALIGNED_ALLOC0 (data_cmd_deprecated_t); bson_init (&data_dst->reply); bson_copy_to (&data_src->cmd, &data_dst->cmd); dst->data = data_dst; } static void _destroy (mongoc_cursor_impl_t *impl) { data_cmd_deprecated_t *data = (data_cmd_deprecated_t *) impl->data; bson_destroy (&data->reply); bson_destroy (&data->cmd); bson_free (data); } mongoc_cursor_t * _mongoc_cursor_cmd_deprecated_new (mongoc_client_t *client, const char *db_and_coll, const bson_t *cmd, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT_PARAM (client); mongoc_cursor_t *cursor = _mongoc_cursor_new_with_opts ( client, db_and_coll, NULL, read_prefs /* user prefs */, NULL /* default prefs */, NULL); data_cmd_deprecated_t *data = BSON_ALIGNED_ALLOC0 (data_cmd_deprecated_t); _mongoc_cursor_check_and_copy_to (cursor, "command", cmd, &data->cmd); bson_init (&data->reply); cursor->impl.prime = _prime; cursor->impl.pop_from_batch = _pop_from_batch; cursor->impl.get_next_batch = _get_next_batch; cursor->impl.data = data; cursor->impl.clone = _clone; cursor->impl.destroy = _destroy; return cursor; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-cmd.c0000644000175100001660000001737614760300420023226 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include typedef enum { NONE, CMD_RESPONSE, OP_GETMORE_RESPONSE } reading_from_t; typedef enum { UNKNOWN, GETMORE_CMD, OP_GETMORE } getmore_type_t; typedef struct _data_cmd_t { /* Two paths: * - Mongo 3.2+, sent "getMore" cmd, we're reading reply's "nextBatch" array * - Mongo 2.6 to 3, after "aggregate" or similar command we sent OP_GETMORE, * we're reading the raw reply from a stream */ mongoc_cursor_response_t response; mongoc_cursor_response_legacy_t response_legacy; reading_from_t reading_from; getmore_type_t getmore_type; /* cache after first getmore. */ bson_t cmd; } data_cmd_t; static getmore_type_t _getmore_type (mongoc_cursor_t *cursor) { mongoc_server_stream_t *server_stream; int32_t wire_version; data_cmd_t *data = (data_cmd_t *) cursor->impl.data; if (data->getmore_type != UNKNOWN) { return data->getmore_type; } const mongoc_ss_log_context_t ss_log_context = { .operation = "getMore", .has_operation_id = true, .operation_id = cursor->operation_id}; server_stream = _mongoc_cursor_fetch_stream (cursor, &ss_log_context); if (!server_stream) { return UNKNOWN; } wire_version = server_stream->sd->max_wire_version; mongoc_server_stream_cleanup (server_stream); // CDRIVER-4722: always GETMORE_CMD once WIRE_VERSION_MIN >= // WIRE_VERSION_4_2. if (_mongoc_cursor_use_op_msg (cursor, wire_version)) { data->getmore_type = GETMORE_CMD; } else { data->getmore_type = OP_GETMORE; } return data->getmore_type; } static mongoc_cursor_state_t _prime (mongoc_cursor_t *cursor) { data_cmd_t *data = (data_cmd_t *) cursor->impl.data; bson_t copied_opts; bson_init (&copied_opts); cursor->operation_id = ++cursor->client->cluster.operation_id; /* commands like agg have a cursor field, so copy opts without "batchSize" */ bson_copy_to_excluding_noinit (&cursor->opts, &copied_opts, "batchSize", "tailable", NULL); /* server replies to aggregate/listIndexes/listCollections with: * {cursor: {id: N, firstBatch: []}} */ _mongoc_cursor_response_refresh (cursor, &data->cmd, &copied_opts, &data->response); data->reading_from = CMD_RESPONSE; bson_destroy (&copied_opts); return IN_BATCH; } static mongoc_cursor_state_t _pop_from_batch (mongoc_cursor_t *cursor) { data_cmd_t *data = (data_cmd_t *) cursor->impl.data; switch (data->reading_from) { case CMD_RESPONSE: _mongoc_cursor_response_read (cursor, &data->response, &cursor->current); break; case OP_GETMORE_RESPONSE: cursor->current = bson_reader_read (data->response_legacy.reader, NULL); break; case NONE: default: fprintf (stderr, "trying to pop from an uninitialized cursor reader.\n"); BSON_ASSERT (false); } if (cursor->current) { return IN_BATCH; } else { return cursor->cursor_id ? END_OF_BATCH : DONE; } } static mongoc_cursor_state_t _get_next_batch (mongoc_cursor_t *cursor) { data_cmd_t *data = (data_cmd_t *) cursor->impl.data; bson_t getmore_cmd; getmore_type_t getmore_type = _getmore_type (cursor); switch (getmore_type) { case GETMORE_CMD: _mongoc_cursor_prepare_getmore_command (cursor, &getmore_cmd); _mongoc_cursor_response_refresh (cursor, &getmore_cmd, NULL /* opts */, &data->response); bson_destroy (&getmore_cmd); data->reading_from = CMD_RESPONSE; return IN_BATCH; case OP_GETMORE: _mongoc_cursor_op_getmore (cursor, &data->response_legacy); data->reading_from = OP_GETMORE_RESPONSE; return IN_BATCH; case UNKNOWN: default: return DONE; } } static void _destroy (mongoc_cursor_impl_t *impl) { data_cmd_t *data = (data_cmd_t *) impl->data; bson_destroy (&data->response.reply); bson_destroy (&data->cmd); _mongoc_cursor_response_legacy_destroy (&data->response_legacy); bson_free (data); } static void _clone (mongoc_cursor_impl_t *dst, const mongoc_cursor_impl_t *src) { data_cmd_t *data_src = (data_cmd_t *) src->data; data_cmd_t *data_dst = BSON_ALIGNED_ALLOC0 (data_cmd_t); bson_init (&data_dst->response.reply); _mongoc_cursor_response_legacy_init (&data_dst->response_legacy); bson_copy_to (&data_src->cmd, &data_dst->cmd); dst->data = data_dst; } mongoc_cursor_t * _mongoc_cursor_cmd_new (mongoc_client_t *client, const char *db_and_coll, const bson_t *cmd, const bson_t *opts, const mongoc_read_prefs_t *user_prefs, const mongoc_read_prefs_t *default_prefs, const mongoc_read_concern_t *read_concern) { BSON_ASSERT_PARAM (client); mongoc_cursor_t *cursor; data_cmd_t *data = BSON_ALIGNED_ALLOC0 (data_cmd_t); cursor = _mongoc_cursor_new_with_opts (client, db_and_coll, opts, user_prefs, default_prefs, read_concern); _mongoc_cursor_response_legacy_init (&data->response_legacy); _mongoc_cursor_check_and_copy_to (cursor, "command", cmd, &data->cmd); bson_init (&data->response.reply); cursor->impl.prime = _prime; cursor->impl.pop_from_batch = _pop_from_batch; cursor->impl.get_next_batch = _get_next_batch; cursor->impl.destroy = _destroy; cursor->impl.clone = _clone; cursor->impl.data = (void *) data; return cursor; } mongoc_cursor_t * _mongoc_cursor_cmd_new_from_reply (mongoc_client_t *client, const bson_t *cmd, const bson_t *opts, bson_t *reply) { BSON_ASSERT_PARAM (client); mongoc_cursor_t *cursor = _mongoc_cursor_cmd_new (client, NULL, cmd, opts, NULL, NULL, NULL); data_cmd_t *data = (data_cmd_t *) cursor->impl.data; data->reading_from = CMD_RESPONSE; cursor->state = IN_BATCH; bson_destroy (&data->response.reply); if (!bson_steal (&data->response.reply, reply)) { bson_destroy (&data->response.reply); BSON_ASSERT (bson_steal (&data->response.reply, bson_copy (reply))); } if (!_mongoc_cursor_start_reading_response (cursor, &data->response)) { bson_set_error ( &cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Couldn't parse cursor document"); } if (0 != cursor->cursor_id && 0 == cursor->server_id) { // A non-zero cursor_id means the cursor is still open on the server. // Expect the "serverId" option to have been passed. The "serverId" option // identifies the server with the cursor. // The server with the cursor is required to send a "getMore" or // "killCursors" command. bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Expected `serverId` option to identify server with open cursor " "(cursor ID is %" PRId64 "). " "Consider using `mongoc_client_select_server` and using the " "resulting server ID to create the cursor.", cursor->cursor_id); // Reset cursor_id to 0 to avoid an assertion error in // `mongoc_cursor_destroy` when attempting to send "killCursors". cursor->cursor_id = 0; } return cursor; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-find-cmd.c0000644000175100001660000000620714760300420024133 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include typedef struct _data_find_cmd_t { mongoc_cursor_response_t response; bson_t filter; } data_find_cmd_t; static mongoc_cursor_state_t _prime (mongoc_cursor_t *cursor) { data_find_cmd_t *data = (data_find_cmd_t *) cursor->impl.data; bson_t find_cmd; bson_init (&find_cmd); cursor->operation_id = ++cursor->client->cluster.operation_id; /* construct { find: "", filter: {} } */ _mongoc_cursor_prepare_find_command (cursor, &data->filter, &find_cmd); _mongoc_cursor_response_refresh (cursor, &find_cmd, &cursor->opts, &data->response); bson_destroy (&find_cmd); return IN_BATCH; } static mongoc_cursor_state_t _pop_from_batch (mongoc_cursor_t *cursor) { data_find_cmd_t *data = (data_find_cmd_t *) cursor->impl.data; _mongoc_cursor_response_read (cursor, &data->response, &cursor->current); if (cursor->current) { return IN_BATCH; } else { return cursor->cursor_id ? END_OF_BATCH : DONE; } } static mongoc_cursor_state_t _get_next_batch (mongoc_cursor_t *cursor) { data_find_cmd_t *data = (data_find_cmd_t *) cursor->impl.data; bson_t getmore_cmd; if (!cursor->cursor_id) { return DONE; } _mongoc_cursor_prepare_getmore_command (cursor, &getmore_cmd); _mongoc_cursor_response_refresh (cursor, &getmore_cmd, NULL /* opts */, &data->response); bson_destroy (&getmore_cmd); return IN_BATCH; } static void _destroy (mongoc_cursor_impl_t *impl) { data_find_cmd_t *data = (data_find_cmd_t *) impl->data; bson_destroy (&data->filter); bson_destroy (&data->response.reply); bson_free (data); } static void _clone (mongoc_cursor_impl_t *dst, const mongoc_cursor_impl_t *src) { data_find_cmd_t *data_src = (data_find_cmd_t *) src->data; data_find_cmd_t *data_dst = BSON_ALIGNED_ALLOC0 (data_find_cmd_t); bson_init (&data_dst->response.reply); bson_copy_to (&data_src->filter, &data_dst->filter); dst->data = data_dst; } /* transition a find cursor to use the find command. */ void _mongoc_cursor_impl_find_cmd_init (mongoc_cursor_t *cursor, bson_t *filter) { data_find_cmd_t *data = BSON_ALIGNED_ALLOC0 (data_find_cmd_t); BSON_ASSERT (bson_steal (&data->filter, filter)); bson_init (&data->response.reply); cursor->impl.prime = _prime; cursor->impl.pop_from_batch = _pop_from_batch; cursor->impl.get_next_batch = _get_next_batch; cursor->impl.destroy = _destroy; cursor->impl.clone = _clone; cursor->impl.data = (void *) data; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-find-opquery.c0000644000175100001660000000631414760300420025073 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include typedef struct _data_find_opquery_t { mongoc_cursor_response_legacy_t response_legacy; bson_t filter; } data_find_opquery_t; static bool _hit_limit (mongoc_cursor_t *cursor) { int64_t limit, limit_abs; limit = mongoc_cursor_get_limit (cursor); /* don't use llabs, that is a C99 function. */ limit_abs = limit > 0 ? limit : -limit; /* mark as done if we've hit the limit. */ if (limit && cursor->count >= limit_abs) { return true; } return false; } static mongoc_cursor_state_t _prime (mongoc_cursor_t *cursor) { data_find_opquery_t *data = (data_find_opquery_t *) cursor->impl.data; if (_hit_limit (cursor)) { return DONE; } _mongoc_cursor_op_query_find (cursor, &data->filter, &data->response_legacy); return IN_BATCH; } static mongoc_cursor_state_t _pop_from_batch (mongoc_cursor_t *cursor) { data_find_opquery_t *data = (data_find_opquery_t *) cursor->impl.data; if (_hit_limit (cursor)) { return DONE; } cursor->current = bson_reader_read (data->response_legacy.reader, NULL); if (cursor->current) { return IN_BATCH; } else { return cursor->cursor_id ? END_OF_BATCH : DONE; } } static mongoc_cursor_state_t _get_next_batch (mongoc_cursor_t *cursor) { data_find_opquery_t *data = (data_find_opquery_t *) cursor->impl.data; _mongoc_cursor_op_getmore (cursor, &data->response_legacy); return IN_BATCH; } static void _destroy (mongoc_cursor_impl_t *impl) { data_find_opquery_t *data = (data_find_opquery_t *) impl->data; _mongoc_cursor_response_legacy_destroy (&data->response_legacy); bson_destroy (&data->filter); bson_free (data); } static void _clone (mongoc_cursor_impl_t *dst, const mongoc_cursor_impl_t *src) { data_find_opquery_t *data_dst = bson_malloc0 (sizeof (data_find_opquery_t)); data_find_opquery_t *data_src = (data_find_opquery_t *) src->data; _mongoc_cursor_response_legacy_init (&data_dst->response_legacy); bson_copy_to (&data_src->filter, &data_dst->filter); dst->data = data_dst; } void _mongoc_cursor_impl_find_opquery_init (mongoc_cursor_t *cursor, bson_t *filter) { data_find_opquery_t *data = BSON_ALIGNED_ALLOC0 (data_find_opquery_t); _mongoc_cursor_response_legacy_init (&data->response_legacy); BSON_ASSERT (bson_steal (&data->filter, filter)); cursor->impl.prime = _prime; cursor->impl.pop_from_batch = _pop_from_batch; cursor->impl.get_next_batch = _get_next_batch; cursor->impl.destroy = _destroy; cursor->impl.clone = _clone; cursor->impl.data = data; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-find.c0000644000175100001660000000654714760300420023401 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include typedef struct _data_find_t { bson_t filter; } data_find_t; extern void _mongoc_cursor_impl_find_cmd_init (mongoc_cursor_t *cursor, bson_t *filter); extern void _mongoc_cursor_impl_find_opquery_init (mongoc_cursor_t *cursor, bson_t *filter); static mongoc_cursor_state_t _prime (mongoc_cursor_t *cursor) { int32_t wire_version; mongoc_server_stream_t *server_stream; data_find_t *data = (data_find_t *) cursor->impl.data; /* determine if this should be a command or op_query cursor. */ const mongoc_ss_log_context_t ss_log_context = { .operation = "find", .has_operation_id = true, .operation_id = cursor->operation_id}; server_stream = _mongoc_cursor_fetch_stream (cursor, &ss_log_context); if (!server_stream) { return DONE; } wire_version = server_stream->sd->max_wire_version; mongoc_server_stream_cleanup (server_stream); /* set all mongoc_impl_t function pointers. */ /* CDRIVER-4722: always find_cmd when server >= 4.2 */ if (_mongoc_cursor_use_op_msg (cursor, wire_version)) { _mongoc_cursor_impl_find_cmd_init (cursor, &data->filter /* stolen */); } else { _mongoc_cursor_impl_find_opquery_init (cursor, &data->filter /* stolen */); } /* destroy this impl data since impl functions have been replaced. */ bson_free (data); /* prime with the new implementation. */ return cursor->impl.prime (cursor); } static void _clone (mongoc_cursor_impl_t *dst, const mongoc_cursor_impl_t *src) { data_find_t *data_dst = BSON_ALIGNED_ALLOC0 (data_find_t); data_find_t *data_src = (data_find_t *) src->data; bson_copy_to (&data_src->filter, &data_dst->filter); dst->data = data_dst; } static void _destroy (mongoc_cursor_impl_t *impl) { data_find_t *data = (data_find_t *) impl->data; bson_destroy (&data->filter); bson_free (data); } mongoc_cursor_t * _mongoc_cursor_find_new (mongoc_client_t *client, const char *db_and_coll, const bson_t *filter, const bson_t *opts, const mongoc_read_prefs_t *user_prefs, const mongoc_read_prefs_t *default_prefs, const mongoc_read_concern_t *read_concern) { BSON_ASSERT_PARAM (client); mongoc_cursor_t *cursor; data_find_t *data = BSON_ALIGNED_ALLOC0 (data_find_t); cursor = _mongoc_cursor_new_with_opts (client, db_and_coll, opts, user_prefs, default_prefs, read_concern); _mongoc_cursor_check_and_copy_to (cursor, "filter", filter, &data->filter); cursor->impl.prime = _prime; cursor->impl.clone = _clone; cursor->impl.destroy = _destroy; cursor->impl.data = data; return cursor; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-legacy.c0000644000175100001660000005763014760300420023724 0ustar /* * Copyright 2009-present MongoDB, 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. */ /* cursor functions for pre-3.2 MongoDB, including: * - OP_QUERY find (superseded by the find command) * - OP_GETMORE (superseded by the getMore command) * - receiving OP_REPLY documents in a stream (instead of batch) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static bool _mongoc_cursor_monitor_legacy_get_more (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream) { bson_t doc; char *db; mongoc_client_t *client; mongoc_apm_command_started_t event; ENTRY; client = cursor->client; _mongoc_cursor_prepare_getmore_command (cursor, &doc); const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor; mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND, "Command started", int32 ("requestId", client->cluster.request_id), server_description (server_stream->sd, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID, SERVICE_ID), utf8_n ("databaseName", cursor->ns, cursor->dblen), utf8 ("commandName", "getMore"), int64 ("operationId", cursor->operation_id), bson_as_json ("command", &doc)); if (!log_and_monitor->apm_callbacks.started) { /* successful */ bson_destroy (&doc); RETURN (true); } db = bson_strndup (cursor->ns, cursor->dblen); mongoc_apm_command_started_init (&event, &doc, db, "getMore", client->cluster.request_id, cursor->operation_id, &server_stream->sd->host, server_stream->sd->id, &server_stream->sd->service_id, server_stream->sd->server_connection_id, NULL, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.started (&event); mongoc_apm_command_started_cleanup (&event); bson_destroy (&doc); bson_free (db); RETURN (true); } static bool _mongoc_cursor_monitor_legacy_query (mongoc_cursor_t *cursor, const bson_t *filter, mongoc_server_stream_t *server_stream) { bson_t doc; char *db; bool r; ENTRY; bson_init (&doc); db = bson_strndup (cursor->ns, cursor->dblen); /* simulate a MongoDB 3.2+ "find" command */ _mongoc_cursor_prepare_find_command (cursor, filter, &doc); bsonBuildAppend (cursor->opts, insert (doc, not(key ("serverId", "maxAwaitTimeMS", "sessionId")))); r = _mongoc_cursor_monitor_command (cursor, server_stream, &doc, "find"); bson_destroy (&doc); bson_free (db); RETURN (r); } static bool _mongoc_cursor_op_getmore_send (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream, int32_t request_id, int32_t flags, mcd_rpc_message *rpc) { BSON_ASSERT_PARAM (cursor); BSON_ASSERT_PARAM (server_stream); BSON_ASSERT_PARAM (rpc); const int32_t n_return = (flags & MONGOC_OP_QUERY_FLAG_TAILABLE_CURSOR) != 0 ? 0 : _mongoc_n_return (cursor); { int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (rpc, 0); message_length += mcd_rpc_header_set_request_id (rpc, request_id); message_length += mcd_rpc_header_set_response_to (rpc, 0); message_length += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_GET_MORE); message_length += sizeof (int32_t); // ZERO message_length += mcd_rpc_op_get_more_set_full_collection_name (rpc, cursor->ns); message_length += mcd_rpc_op_get_more_set_number_to_return (rpc, n_return); message_length += mcd_rpc_op_get_more_set_cursor_id (rpc, cursor->cursor_id); mcd_rpc_message_set_length (rpc, message_length); } if (!_mongoc_cursor_monitor_legacy_get_more (cursor, server_stream)) { return false; } if (!mongoc_cluster_legacy_rpc_sendv_to_server (&cursor->client->cluster, rpc, server_stream, &cursor->error)) { return false; } return true; } void _mongoc_cursor_op_getmore (mongoc_cursor_t *cursor, mongoc_cursor_response_legacy_t *response) { BSON_ASSERT_PARAM (cursor); BSON_ASSERT_PARAM (response); ENTRY; const int64_t started = bson_get_monotonic_time (); const mongoc_ss_log_context_t ss_log_context = { .operation = "getMore", .has_operation_id = true, .operation_id = cursor->operation_id}; mongoc_server_stream_t *const server_stream = _mongoc_cursor_fetch_stream (cursor, &ss_log_context); if (!server_stream) { GOTO (done); } int32_t flags; if (!_mongoc_cursor_opts_to_flags (cursor, server_stream, &flags)) { GOTO (fail); } mongoc_cluster_t *const cluster = &cursor->client->cluster; const int32_t request_id = cursor->in_exhaust ? mcd_rpc_header_get_request_id (response->rpc) : ++cluster->request_id; if (!cursor->in_exhaust && !_mongoc_cursor_op_getmore_send (cursor, server_stream, request_id, flags, response->rpc)) { GOTO (fail); } mcd_rpc_message_reset (response->rpc); _mongoc_buffer_clear (&response->buffer, false); cursor->cursor_id = 0; if (!_mongoc_client_recv (cursor->client, response->rpc, &response->buffer, server_stream, &cursor->error)) { GOTO (fail); } const int32_t op_code = mcd_rpc_header_get_op_code (response->rpc); if (op_code != MONGOC_OP_CODE_REPLY) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid opcode for OP_GET_MORE: expected %" PRId32 ", got %" PRId32, MONGOC_OP_CODE_REPLY, op_code); GOTO (fail); } const int32_t response_to = mcd_rpc_header_get_response_to (response->rpc); if (response_to != request_id) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid response_to for OP_GET_MORE: expected %" PRId32 ", got %" PRId32, request_id, response_to); GOTO (fail); } if (!mcd_rpc_message_check_ok ( response->rpc, cursor->client->error_api_version, &cursor->error, &cursor->error_doc)) { GOTO (fail); } if (response->reader) { bson_reader_destroy (response->reader); } cursor->cursor_id = mcd_rpc_op_reply_get_cursor_id (response->rpc); const void *documents = mcd_rpc_op_reply_get_documents (response->rpc); if (documents == NULL) { // Use a non-NULL pointer to satisfy precondition of // `bson_reader_new_from_data`: documents = ""; } response->reader = bson_reader_new_from_data (documents, mcd_rpc_op_reply_get_documents_len (response->rpc)); _mongoc_cursor_monitor_succeeded (cursor, response, bson_get_monotonic_time () - started, false, /* not first batch */ server_stream, "getMore"); GOTO (done); fail: _mongoc_cursor_monitor_failed (cursor, bson_get_monotonic_time () - started, server_stream, "getMore"); done: mongoc_server_stream_cleanup (server_stream); } #define OPT_CHECK(_type) \ do { \ if (!BSON_ITER_HOLDS_##_type (&iter)) { \ bson_set_error (&cursor->error, \ MONGOC_ERROR_COMMAND, \ MONGOC_ERROR_COMMAND_INVALID_ARG, \ "invalid option %s, should be type %s", \ key, \ #_type); \ return NULL; \ } \ } while (false) #define OPT_CHECK_INT() \ do { \ if (!BSON_ITER_HOLDS_INT (&iter)) { \ bson_set_error (&cursor->error, \ MONGOC_ERROR_COMMAND, \ MONGOC_ERROR_COMMAND_INVALID_ARG, \ "invalid option %s, should be integer", \ key); \ return NULL; \ } \ } while (false) #define OPT_ERR(_msg) \ do { \ bson_set_error (&cursor->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, _msg); \ return NULL; \ } while (false) #define OPT_BSON_ERR(_msg) \ do { \ bson_set_error (&cursor->error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, _msg); \ return NULL; \ } while (false) #define OPT_FLAG(_flag) \ do { \ OPT_CHECK (BOOL); \ if (bson_iter_as_bool (&iter)) { \ *flags |= _flag; \ } \ } while (false) #define PUSH_DOLLAR_QUERY() \ do { \ if (!pushed_dollar_query) { \ pushed_dollar_query = true; \ bson_append_document (query, "$query", 6, filter); \ } \ } while (false) #define OPT_SUBDOCUMENT(_opt_name, _legacy_name) \ do { \ OPT_CHECK (DOCUMENT); \ bson_iter_document (&iter, &len, &data); \ if (!bson_init_static (&subdocument, data, (size_t) len)) { \ OPT_BSON_ERR ("Invalid '" #_opt_name "' subdocument in 'opts'."); \ } \ BSON_APPEND_DOCUMENT (query, "$" #_legacy_name, &subdocument); \ } while (false) static bson_t * _mongoc_cursor_parse_opts_for_op_query (mongoc_cursor_t *cursor, mongoc_server_stream_t *stream, bson_t *filter, bson_t *query /* OUT */, bson_t *fields /* OUT */, int32_t *flags /* OUT */, int32_t *skip /* OUT */) { bool pushed_dollar_query; bson_iter_t iter; uint32_t len; const uint8_t *data; bson_t subdocument; const char *key; char *dollar_modifier; *flags = MONGOC_OP_QUERY_FLAG_NONE; *skip = 0; /* assume we'll send filter straight to server, like "{a: 1}". if we find an * opt we must add, like "sort", we push the query like "$query: {a: 1}", * then add a query modifier for the option, in this example "$orderby". */ pushed_dollar_query = false; if (!bson_iter_init (&iter, &cursor->opts)) { OPT_BSON_ERR ("Invalid 'opts' parameter."); } while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); /* most common options first */ if (!strcmp (key, MONGOC_CURSOR_PROJECTION)) { OPT_CHECK (DOCUMENT); bson_iter_document (&iter, &len, &data); if (!bson_init_static (&subdocument, data, (size_t) len)) { OPT_BSON_ERR ("Invalid 'projection' subdocument in 'opts'."); } bson_destroy (fields); bson_copy_to (&subdocument, fields); } else if (!strcmp (key, MONGOC_CURSOR_SORT)) { PUSH_DOLLAR_QUERY (); OPT_SUBDOCUMENT (sort, orderby); } else if (!strcmp (key, MONGOC_CURSOR_SKIP)) { OPT_CHECK_INT (); *skip = (int32_t) bson_iter_as_int64 (&iter); } /* the rest of the options, alphabetically */ else if (!strcmp (key, MONGOC_CURSOR_ALLOW_PARTIAL_RESULTS)) { OPT_FLAG (MONGOC_OP_QUERY_FLAG_PARTIAL); } else if (!strcmp (key, MONGOC_CURSOR_AWAIT_DATA)) { OPT_FLAG (MONGOC_OP_QUERY_FLAG_AWAIT_DATA); } else if (!strcmp (key, MONGOC_CURSOR_COMMENT)) { OPT_CHECK (UTF8); PUSH_DOLLAR_QUERY (); BSON_APPEND_UTF8 (query, "$comment", bson_iter_utf8 (&iter, NULL)); } else if (!strcmp (key, MONGOC_CURSOR_HINT)) { if (BSON_ITER_HOLDS_UTF8 (&iter)) { PUSH_DOLLAR_QUERY (); BSON_APPEND_UTF8 (query, "$hint", bson_iter_utf8 (&iter, NULL)); } else if (BSON_ITER_HOLDS_DOCUMENT (&iter)) { PUSH_DOLLAR_QUERY (); OPT_SUBDOCUMENT (hint, hint); } else { OPT_ERR ("Wrong type for 'hint' field in 'opts'."); } } else if (!strcmp (key, MONGOC_CURSOR_MAX)) { PUSH_DOLLAR_QUERY (); OPT_SUBDOCUMENT (max, max); } else if (!strcmp (key, MONGOC_CURSOR_MAX_SCAN)) { OPT_CHECK_INT (); PUSH_DOLLAR_QUERY (); BSON_APPEND_INT64 (query, "$maxScan", bson_iter_as_int64 (&iter)); } else if (!strcmp (key, MONGOC_CURSOR_MAX_TIME_MS)) { OPT_CHECK_INT (); PUSH_DOLLAR_QUERY (); BSON_APPEND_INT64 (query, "$maxTimeMS", bson_iter_as_int64 (&iter)); } else if (!strcmp (key, MONGOC_CURSOR_MIN)) { PUSH_DOLLAR_QUERY (); OPT_SUBDOCUMENT (min, min); } else if (!strcmp (key, MONGOC_CURSOR_READ_CONCERN)) { OPT_ERR ("Set readConcern on client, database, or collection," " not in a query."); } else if (!strcmp (key, MONGOC_CURSOR_RETURN_KEY)) { OPT_CHECK (BOOL); PUSH_DOLLAR_QUERY (); BSON_APPEND_BOOL (query, "$returnKey", bson_iter_as_bool (&iter)); } else if (!strcmp (key, MONGOC_CURSOR_SHOW_RECORD_ID)) { OPT_CHECK (BOOL); PUSH_DOLLAR_QUERY (); BSON_APPEND_BOOL (query, "$showDiskLoc", bson_iter_as_bool (&iter)); } else if (!strcmp (key, MONGOC_CURSOR_SNAPSHOT)) { OPT_CHECK (BOOL); PUSH_DOLLAR_QUERY (); BSON_APPEND_BOOL (query, "$snapshot", bson_iter_as_bool (&iter)); } else if (!strcmp (key, MONGOC_CURSOR_COLLATION)) { bson_set_error (&cursor->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support collation"); return NULL; } /* singleBatch limit and batchSize are handled in _mongoc_n_return, * exhaust noCursorTimeout oplogReplay tailable in _mongoc_cursor_flags * maxAwaitTimeMS is handled in _mongoc_cursor_prepare_getmore_command * sessionId is used to retrieve the mongoc_client_session_t */ else if (strcmp (key, MONGOC_CURSOR_SINGLE_BATCH) && strcmp (key, MONGOC_CURSOR_LIMIT) && strcmp (key, MONGOC_CURSOR_BATCH_SIZE) && strcmp (key, MONGOC_CURSOR_EXHAUST) && strcmp (key, MONGOC_CURSOR_NO_CURSOR_TIMEOUT) && strcmp (key, MONGOC_CURSOR_OPLOG_REPLAY) && strcmp (key, MONGOC_CURSOR_TAILABLE) && strcmp (key, MONGOC_CURSOR_MAX_AWAIT_TIME_MS)) { /* pass unrecognized options to server, prefixed with $ */ PUSH_DOLLAR_QUERY (); dollar_modifier = bson_strdup_printf ("$%s", key); if (!bson_append_iter (query, dollar_modifier, -1, &iter)) { bson_set_error (&cursor->error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Error adding \"%s\" to query", dollar_modifier); bson_free (dollar_modifier); return NULL; } bson_free (dollar_modifier); } } if (!_mongoc_cursor_opts_to_flags (cursor, stream, flags)) { /* cursor->error is set */ return NULL; } return pushed_dollar_query ? query : filter; } #undef OPT_CHECK #undef OPT_ERR #undef OPT_BSON_ERR #undef OPT_FLAG #undef OPT_SUBDOCUMENT static bool _mongoc_cursor_op_query_find_send (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream, int32_t request_id, bson_t *filter, mcd_rpc_message *rpc) { bool ret = false; cursor->operation_id = ++cursor->client->cluster.operation_id; mongoc_assemble_query_result_t result = ASSEMBLE_QUERY_RESULT_INIT; bson_t query = BSON_INITIALIZER; bson_t fields = BSON_INITIALIZER; int32_t skip; int32_t flags; const bson_t *const query_ptr = _mongoc_cursor_parse_opts_for_op_query (cursor, server_stream, filter, &query, &fields, &flags, &skip); if (!query_ptr) { GOTO (done); } assemble_query (cursor->read_prefs, server_stream, query_ptr, flags, &result); { int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (rpc, 0); message_length += mcd_rpc_header_set_request_id (rpc, request_id); message_length += mcd_rpc_header_set_response_to (rpc, 0); message_length += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_QUERY); message_length += mcd_rpc_op_query_set_flags (rpc, result.flags); message_length += mcd_rpc_op_query_set_full_collection_name (rpc, cursor->ns); message_length += mcd_rpc_op_query_set_number_to_skip (rpc, skip); message_length += mcd_rpc_op_query_set_number_to_return (rpc, _mongoc_n_return (cursor)); message_length += mcd_rpc_op_query_set_query (rpc, bson_get_data (result.assembled_query)); if (!bson_empty (&fields)) { message_length += mcd_rpc_op_query_set_return_fields_selector (rpc, bson_get_data (&fields)); } mcd_rpc_message_set_length (rpc, message_length); } if (!_mongoc_cursor_monitor_legacy_query (cursor, filter, server_stream)) { GOTO (done); } if (!mongoc_cluster_legacy_rpc_sendv_to_server (&cursor->client->cluster, rpc, server_stream, &cursor->error)) { GOTO (done); } ret = true; done: assemble_query_result_cleanup (&result); bson_destroy (&fields); bson_destroy (&query); return ret; } bool _mongoc_cursor_op_query_find (mongoc_cursor_t *cursor, bson_t *filter, mongoc_cursor_response_legacy_t *response) { BSON_ASSERT_PARAM (cursor); BSON_ASSERT_PARAM (filter); BSON_ASSERT_PARAM (response); ENTRY; bool ret = false; const mongoc_ss_log_context_t ss_log_context = { .operation = "find", .has_operation_id = true, .operation_id = cursor->operation_id}; mongoc_server_stream_t *const server_stream = _mongoc_cursor_fetch_stream (cursor, &ss_log_context); if (!server_stream) { RETURN (false); } const int64_t started = bson_get_monotonic_time (); const int32_t request_id = ++cursor->client->cluster.request_id; mcd_rpc_message *const rpc = mcd_rpc_message_new (); if (!_mongoc_cursor_op_query_find_send (cursor, server_stream, request_id, filter, rpc)) { GOTO (done); } mcd_rpc_message_reset (rpc); _mongoc_buffer_clear (&response->buffer, false); if (!_mongoc_client_recv (cursor->client, response->rpc, &response->buffer, server_stream, &cursor->error)) { GOTO (done); } const int32_t op_code = mcd_rpc_header_get_op_code (response->rpc); if (op_code != MONGOC_OP_CODE_REPLY) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid opcode for OP_QUERY: expected %" PRId32 ", got %" PRId32, MONGOC_OP_CODE_REPLY, op_code); GOTO (done); } const int32_t response_to = mcd_rpc_header_get_response_to (response->rpc); if (response_to != request_id) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid response_to for OP_QUERY: expected %" PRId32 ", got %" PRId32, request_id, response_to); GOTO (done); } if (!mcd_rpc_message_check_ok ( response->rpc, cursor->client->error_api_version, &cursor->error, &cursor->error_doc)) { GOTO (done); } if (response->reader) { bson_reader_destroy (response->reader); } cursor->cursor_id = mcd_rpc_op_reply_get_cursor_id (response->rpc); const void *documents = mcd_rpc_op_reply_get_documents (response->rpc); if (documents == NULL) { // Use a non-NULL pointer to satisfy precondition of // `bson_reader_new_from_data`: documents = ""; } response->reader = bson_reader_new_from_data (documents, mcd_rpc_op_reply_get_documents_len (response->rpc)); if (_mongoc_cursor_get_opt_bool (cursor, MONGOC_CURSOR_EXHAUST)) { cursor->in_exhaust = true; cursor->client->in_exhaust = true; } _mongoc_cursor_monitor_succeeded (cursor, response, bson_get_monotonic_time () - started, true, /* first_batch */ server_stream, "find"); ret = true; done: if (!ret) { _mongoc_cursor_monitor_failed (cursor, bson_get_monotonic_time () - started, server_stream, "find"); } mcd_rpc_message_destroy (rpc); mongoc_server_stream_cleanup (server_stream); return ret; } void _mongoc_cursor_response_legacy_init (mongoc_cursor_response_legacy_t *response) { response->rpc = mcd_rpc_message_new (); _mongoc_buffer_init (&response->buffer, NULL, 0, NULL, NULL); } void _mongoc_cursor_response_legacy_destroy (mongoc_cursor_response_legacy_t *response) { if (response->reader) { bson_reader_destroy (response->reader); response->reader = NULL; } _mongoc_buffer_destroy (&response->buffer); mcd_rpc_message_destroy (response->rpc); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor-private.h0000644000175100001660000002654514760300420024140 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CURSOR_PRIVATE_H #define MONGOC_CURSOR_PRIVATE_H #include #include #include #include #include #include BSON_BEGIN_DECLS #define MONGOC_CURSOR_ALLOW_PARTIAL_RESULTS "allowPartialResults" #define MONGOC_CURSOR_ALLOW_PARTIAL_RESULTS_LEN 19 #define MONGOC_CURSOR_AWAIT_DATA "awaitData" #define MONGOC_CURSOR_AWAIT_DATA_LEN 9 #define MONGOC_CURSOR_BATCH_SIZE "batchSize" #define MONGOC_CURSOR_BATCH_SIZE_LEN 9 #define MONGOC_CURSOR_COLLATION "collation" #define MONGOC_CURSOR_COLLATION_LEN 9 #define MONGOC_CURSOR_COMMENT "comment" #define MONGOC_CURSOR_COMMENT_LEN 7 #define MONGOC_CURSOR_EXHAUST "exhaust" #define MONGOC_CURSOR_EXHAUST_LEN 7 #define MONGOC_CURSOR_FILTER "filter" #define MONGOC_CURSOR_FILTER_LEN 6 #define MONGOC_CURSOR_FIND "find" #define MONGOC_CURSOR_FIND_LEN 4 #define MONGOC_CURSOR_HINT "hint" #define MONGOC_CURSOR_HINT_LEN 4 #define MONGOC_CURSOR_LIMIT "limit" #define MONGOC_CURSOR_LIMIT_LEN 5 #define MONGOC_CURSOR_MAX "max" #define MONGOC_CURSOR_MAX_LEN 3 #define MONGOC_CURSOR_MAX_AWAIT_TIME_MS "maxAwaitTimeMS" #define MONGOC_CURSOR_MAX_AWAIT_TIME_MS_LEN 14 #define MONGOC_CURSOR_MAX_SCAN "maxScan" #define MONGOC_CURSOR_MAX_SCAN_LEN 7 #define MONGOC_CURSOR_MAX_TIME_MS "maxTimeMS" #define MONGOC_CURSOR_MAX_TIME_MS_LEN 9 #define MONGOC_CURSOR_MIN "min" #define MONGOC_CURSOR_MIN_LEN 3 #define MONGOC_CURSOR_NO_CURSOR_TIMEOUT "noCursorTimeout" #define MONGOC_CURSOR_NO_CURSOR_TIMEOUT_LEN 15 #define MONGOC_CURSOR_OPLOG_REPLAY "oplogReplay" #define MONGOC_CURSOR_OPLOG_REPLAY_LEN 11 #define MONGOC_CURSOR_ORDERBY "orderby" #define MONGOC_CURSOR_ORDERBY_LEN 7 #define MONGOC_CURSOR_PROJECTION "projection" #define MONGOC_CURSOR_PROJECTION_LEN 10 #define MONGOC_CURSOR_QUERY "query" #define MONGOC_CURSOR_QUERY_LEN 5 #define MONGOC_CURSOR_READ_CONCERN "readConcern" #define MONGOC_CURSOR_READ_CONCERN_LEN 11 #define MONGOC_CURSOR_RETURN_KEY "returnKey" #define MONGOC_CURSOR_RETURN_KEY_LEN 9 #define MONGOC_CURSOR_SHOW_DISK_LOC "showDiskLoc" #define MONGOC_CURSOR_SHOW_DISK_LOC_LEN 11 #define MONGOC_CURSOR_SHOW_RECORD_ID "showRecordId" #define MONGOC_CURSOR_SHOW_RECORD_ID_LEN 12 #define MONGOC_CURSOR_SINGLE_BATCH "singleBatch" #define MONGOC_CURSOR_SINGLE_BATCH_LEN 11 #define MONGOC_CURSOR_SKIP "skip" #define MONGOC_CURSOR_SKIP_LEN 4 #define MONGOC_CURSOR_SNAPSHOT "snapshot" #define MONGOC_CURSOR_SNAPSHOT_LEN 8 #define MONGOC_CURSOR_SORT "sort" #define MONGOC_CURSOR_SORT_LEN 4 #define MONGOC_CURSOR_TAILABLE "tailable" #define MONGOC_CURSOR_TAILABLE_LEN 8 typedef struct _mongoc_cursor_impl_t mongoc_cursor_impl_t; typedef enum { UNPRIMED, IN_BATCH, END_OF_BATCH, DONE } mongoc_cursor_state_t; typedef mongoc_cursor_state_t (*_mongoc_cursor_impl_transition_t) (mongoc_cursor_t *cursor); struct _mongoc_cursor_impl_t { void (*clone) (mongoc_cursor_impl_t *dst, const mongoc_cursor_impl_t *src); void (*destroy) (mongoc_cursor_impl_t *ctx); _mongoc_cursor_impl_transition_t prime; _mongoc_cursor_impl_transition_t pop_from_batch; _mongoc_cursor_impl_transition_t get_next_batch; void *data; }; /* pre-3.2 and exhaust cursor responses -- read documents from stream. */ typedef struct _mongoc_cursor_response_legacy { mcd_rpc_message *rpc; mongoc_buffer_t buffer; bson_reader_t *reader; } mongoc_cursor_response_legacy_t; /* 3.2+ responses -- read batch docs like {cursor:{id: 123, firstBatch: []}} */ typedef struct _mongoc_cursor_response_t { bson_t reply; /* the entire command reply */ bson_iter_t batch_iter; /* iterates over the batch array */ bson_t current_doc; /* the current doc inside the batch array */ } mongoc_cursor_response_t; struct _mongoc_cursor_t { mongoc_client_t *client; uint32_t client_generation; uint32_t server_id; bool secondary_ok; mongoc_cursor_state_t state; bool in_exhaust; bson_t opts; mongoc_read_concern_t *read_concern; mongoc_read_prefs_t *read_prefs; mongoc_write_concern_t *write_concern; /** If the cursor was created for an operation that might have overridden the * user's read preferences' read mode, then server selection forced the * cursor to use a read preference mode of 'primary' server. Whether this * force occurred is stored here: */ bool must_use_primary; /** Whether this cursor corresponds to an aggregate command that contains a * writing-stage */ bool is_aggr_with_write_stage; bool explicit_session; mongoc_client_session_t *client_session; uint32_t count; char *ns; uint32_t nslen; uint32_t dblen; bson_error_t error; bson_t error_doc; /* always initialized, and set with server errors. */ const bson_t *current; mongoc_cursor_impl_t impl; int64_t operation_id; int64_t cursor_id; }; int32_t _mongoc_n_return (mongoc_cursor_t *cursor); void _mongoc_set_cursor_ns (mongoc_cursor_t *cursor, const char *ns, uint32_t nslen); bool _mongoc_cursor_get_opt_bool (const mongoc_cursor_t *cursor, const char *option); void _mongoc_cursor_flags_to_opts (mongoc_query_flags_t qflags, bson_t *opts, bool *secondary_ok); bool _mongoc_cursor_translate_dollar_query_opts (const bson_t *query, bson_t *opts, bson_t *unwrapped, bson_error_t *error); mongoc_server_stream_t * _mongoc_cursor_fetch_stream (mongoc_cursor_t *cursor, const mongoc_ss_log_context_t *log_context); void _mongoc_cursor_collection (const mongoc_cursor_t *cursor, const char **collection, int *collection_len); bool _mongoc_cursor_run_command ( mongoc_cursor_t *cursor, const bson_t *command, const bson_t *opts, bson_t *reply, bool retry_prohibited); bool _mongoc_cursor_more (mongoc_cursor_t *cursor); bool _mongoc_cursor_set_opt_int64 (mongoc_cursor_t *cursor, const char *option, int64_t value); void _mongoc_cursor_monitor_failed (mongoc_cursor_t *cursor, int64_t duration, mongoc_server_stream_t *stream, const char *cmd_name); bool _mongoc_cursor_monitor_command (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream, const bson_t *cmd, const char *cmd_name); void _mongoc_cursor_prepare_find_command (mongoc_cursor_t *cursor, const bson_t *filter, bson_t *command); const bson_t * _mongoc_cursor_initial_query (mongoc_cursor_t *cursor); const bson_t * _mongoc_cursor_get_more (mongoc_cursor_t *cursor); bool _mongoc_cursor_opts_to_flags (mongoc_cursor_t *cursor, mongoc_server_stream_t *stream, int32_t *flags /* OUT */); bool _mongoc_cursor_use_op_msg (const mongoc_cursor_t *cursor, int32_t wire_version); void _mongoc_cursor_monitor_succeeded (mongoc_cursor_t *cursor, mongoc_cursor_response_legacy_t *response, int64_t duration, bool first_batch, mongoc_server_stream_t *stream, const char *cmd_name); /* start iterating a reply like * {cursor: {id: 1234, ns: "db.collection", firstBatch: [...]}} or * {cursor: {id: 1234, ns: "db.collection", nextBatch: [...]}} */ void _mongoc_cursor_response_refresh (mongoc_cursor_t *cursor, const bson_t *command, const bson_t *opts, mongoc_cursor_response_t *response); bool _mongoc_cursor_start_reading_response (mongoc_cursor_t *cursor, mongoc_cursor_response_t *response); void _mongoc_cursor_response_read (mongoc_cursor_t *cursor, mongoc_cursor_response_t *response, const bson_t **bson); void _mongoc_cursor_prepare_getmore_command (mongoc_cursor_t *cursor, bson_t *command); void _mongoc_cursor_set_empty (mongoc_cursor_t *cursor); bool _mongoc_cursor_check_and_copy_to (mongoc_cursor_t *cursor, const char *err_prefix, const bson_t *src, bson_t *dst); void _mongoc_cursor_prime (mongoc_cursor_t *cursor); /* legacy functions defined in mongoc-cursor-legacy.c */ bool _mongoc_cursor_next (mongoc_cursor_t *cursor, const bson_t **bson); bool _mongoc_cursor_op_query_find (mongoc_cursor_t *cursor, bson_t *filter, mongoc_cursor_response_legacy_t *response); void _mongoc_cursor_op_getmore (mongoc_cursor_t *cursor, mongoc_cursor_response_legacy_t *response); mongoc_cursor_t * _mongoc_cursor_new_with_opts (mongoc_client_t *client, const char *db_and_collection, const bson_t *opts, const mongoc_read_prefs_t *user_prefs, const mongoc_read_prefs_t *default_prefs, const mongoc_read_concern_t *read_concern); void _mongoc_cursor_response_legacy_init (mongoc_cursor_response_legacy_t *response); void _mongoc_cursor_response_legacy_destroy (mongoc_cursor_response_legacy_t *response); /* cursor constructors. */ mongoc_cursor_t * _mongoc_cursor_find_new (mongoc_client_t *client, const char *db_and_coll, const bson_t *filter, const bson_t *opts, const mongoc_read_prefs_t *user_prefs, const mongoc_read_prefs_t *default_prefs, const mongoc_read_concern_t *read_concern); mongoc_cursor_t * _mongoc_cursor_cmd_new (mongoc_client_t *client, const char *db_and_coll, const bson_t *cmd, const bson_t *opts, const mongoc_read_prefs_t *user_prefs, const mongoc_read_prefs_t *default_prefs, const mongoc_read_concern_t *read_concern); mongoc_cursor_t * _mongoc_cursor_cmd_new_from_reply (mongoc_client_t *client, const bson_t *cmd, const bson_t *opts, bson_t *reply); mongoc_cursor_t * _mongoc_cursor_cmd_deprecated_new (mongoc_client_t *client, const char *db_and_coll, const bson_t *cmd, const mongoc_read_prefs_t *read_prefs); mongoc_cursor_t * _mongoc_cursor_array_new ( mongoc_client_t *client, const char *db_and_coll, const bson_t *cmd, const bson_t *opts, const char *field_name); mongoc_cursor_t * _mongoc_cursor_change_stream_new (mongoc_client_t *client, bson_t *reply, const bson_t *opts); bool _mongoc_cursor_change_stream_end_of_batch (mongoc_cursor_t *cursor); const bson_t * _mongoc_cursor_change_stream_get_post_batch_resume_token (mongoc_cursor_t *cursor); bool _mongoc_cursor_change_stream_has_post_batch_resume_token (mongoc_cursor_t *cursor); const bson_t * _mongoc_cursor_change_stream_get_reply (mongoc_cursor_t *cursor); BSON_END_DECLS #endif /* MONGOC_CURSOR_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor.c0000644000175100001660000016102614760300420022455 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "cursor" #define CURSOR_FAILED(cursor_) ((cursor_)->error.domain != 0) static bool _translate_query_opt (const char *query_field, const char **cmd_field, int *len); bool _mongoc_cursor_set_opt_int64 (mongoc_cursor_t *cursor, const char *option, int64_t value) { bson_iter_t iter; if (bson_iter_init_find (&iter, &cursor->opts, option)) { if (!BSON_ITER_HOLDS_INT64 (&iter)) { return false; } bson_iter_overwrite_int64 (&iter, value); return true; } return BSON_APPEND_INT64 (&cursor->opts, option, value); } static int64_t _mongoc_cursor_get_opt_int64 (const mongoc_cursor_t *cursor, const char *option, int64_t default_value) { bson_iter_t iter; if (bson_iter_init_find (&iter, &cursor->opts, option)) { return bson_iter_as_int64 (&iter); } return default_value; } static bool _mongoc_cursor_set_opt_bool (mongoc_cursor_t *cursor, const char *option, bool value) { bson_iter_t iter; if (bson_iter_init_find (&iter, &cursor->opts, option)) { if (!BSON_ITER_HOLDS_BOOL (&iter)) { return false; } bson_iter_overwrite_bool (&iter, value); return true; } return BSON_APPEND_BOOL (&cursor->opts, option, value); } bool _mongoc_cursor_get_opt_bool (const mongoc_cursor_t *cursor, const char *option) { bson_iter_t iter; if (bson_iter_init_find (&iter, &cursor->opts, option)) { return bson_iter_as_bool (&iter); } return false; } int32_t _mongoc_n_return (mongoc_cursor_t *cursor) { int64_t limit; int64_t batch_size; int64_t n_return; /* calculate numberToReturn according to: * https://github.com/mongodb/specifications/blob/master/source/crud/crud.md#combining-limit-and-batch-size-for-the-wire-protocol */ limit = mongoc_cursor_get_limit (cursor); batch_size = mongoc_cursor_get_batch_size (cursor); if (limit < 0) { n_return = limit; } else if (limit == 0) { n_return = batch_size; } else if (batch_size == 0) { n_return = limit; } else if (limit < batch_size) { n_return = limit; } else { n_return = batch_size; } /* if a specified limit exists, account for documents already returned. */ if (limit > 0 && cursor->count) { int64_t remaining = limit - cursor->count; /* remaining can be 0 if we have retrieved "limit" documents, but still * have a cursor id: SERVER-21086. use nonzero batchSize to fetch final * empty batch and trigger server to close cursor. */ if (remaining <= 0) { return 1; } n_return = BSON_MIN (n_return, remaining); } /* check boundary conditions */ if (n_return < INT32_MIN) { return INT32_MIN; } else if (n_return > INT32_MAX) { return INT32_MAX; } else { return (int32_t) n_return; } } void _mongoc_set_cursor_ns (mongoc_cursor_t *cursor, const char *ns, uint32_t nslen) { const char *dot; bson_free (cursor->ns); cursor->ns = bson_strndup (ns, nslen); cursor->nslen = nslen; dot = strstr (cursor->ns, "."); if (dot) { cursor->dblen = (uint32_t) (dot - cursor->ns); } else { /* a database name with no collection name */ cursor->dblen = cursor->nslen; } } /* return first key beginning with $, or NULL. precondition: bson is valid. */ static const char * _first_dollar_field (const bson_t *bson) { bson_iter_t iter; const char *key; BSON_ASSERT (bson_iter_init (&iter, bson)); while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (key[0] == '$') { return key; } } return NULL; } /* if src is non-NULL, it is validated and copied to dst. returns false and * sets the cursor error if validation fails. */ bool _mongoc_cursor_check_and_copy_to (mongoc_cursor_t *cursor, const char *err_prefix, const bson_t *src, bson_t *dst) { bson_error_t validate_err; bson_init (dst); if (src) { if (!bson_validate_with_error (src, BSON_VALIDATE_EMPTY_KEYS, &validate_err)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Invalid %s: %s", err_prefix, validate_err.message); return false; } bson_destroy (dst); bson_copy_to (src, dst); } return true; } mongoc_cursor_t * _mongoc_cursor_new_with_opts (mongoc_client_t *client, const char *db_and_collection, const bson_t *opts, const mongoc_read_prefs_t *user_prefs, const mongoc_read_prefs_t *default_prefs, const mongoc_read_concern_t *read_concern) { mongoc_cursor_t *cursor; uint32_t server_id; mongoc_read_concern_t *read_concern_local = NULL; bson_error_t validate_err; const char *dollar_field; bson_iter_t iter; ENTRY; BSON_ASSERT_PARAM (client); cursor = BSON_ALIGNED_ALLOC0 (mongoc_cursor_t); cursor->client = client; cursor->state = UNPRIMED; cursor->client_generation = client->generation; cursor->is_aggr_with_write_stage = false; bson_init (&cursor->opts); bson_init (&cursor->error_doc); if (opts) { if (!bson_validate_with_error (opts, BSON_VALIDATE_EMPTY_KEYS, &validate_err)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Invalid opts: %s", validate_err.message); GOTO (finish); } dollar_field = _first_dollar_field (opts); if (dollar_field) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot use $-modifiers in opts: \"%s\"", dollar_field); GOTO (finish); } if (bson_iter_init_find (&iter, opts, "sessionId")) { if (!_mongoc_client_session_from_iter (client, &iter, &cursor->client_session, &cursor->error)) { GOTO (finish); } cursor->explicit_session = true; } if (bson_iter_init_find (&iter, opts, "readConcern")) { read_concern_local = _mongoc_read_concern_new_from_iter (&iter, &cursor->error); if (!read_concern_local) { /* invalid read concern */ GOTO (finish); } read_concern = read_concern_local; } /* true if there's a valid serverId or no serverId, false on err */ if (!_mongoc_get_server_id_from_opts ( opts, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, &server_id, &cursor->error)) { GOTO (finish); } if (server_id) { (void) mongoc_cursor_set_server_id (cursor, server_id); } // Selectively copy the options: bsonBuildAppend (cursor->opts, insert (*opts, not(key ("serverId", "sessionId"), // Drop bypassDocumentValidation if it isn't true: allOf (key ("bypassDocumentValidation"), isFalse)))); } if (_mongoc_client_session_in_txn (cursor->client_session)) { if (!IS_PREF_PRIMARY (user_prefs)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Read preference in a transaction must be primary"); GOTO (finish); } cursor->read_prefs = mongoc_read_prefs_copy (cursor->client_session->txn.opts.read_prefs); if (bson_has_field (opts, "readConcern")) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot set read concern after starting transaction"); GOTO (finish); } } else if (user_prefs) { cursor->read_prefs = mongoc_read_prefs_copy (user_prefs); } else if (default_prefs) { cursor->read_prefs = mongoc_read_prefs_copy (default_prefs); } else { cursor->read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); } cursor->read_concern = read_concern ? mongoc_read_concern_copy (read_concern) : mongoc_read_concern_new (); if (db_and_collection) { _mongoc_set_cursor_ns (cursor, db_and_collection, (uint32_t) strlen (db_and_collection)); } if (_mongoc_cursor_get_opt_bool (cursor, MONGOC_CURSOR_EXHAUST)) { if (_mongoc_cursor_get_opt_int64 (cursor, MONGOC_CURSOR_LIMIT, 0)) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot specify both 'exhaust' and 'limit'."); GOTO (finish); } } (void) _mongoc_read_prefs_validate (cursor->read_prefs, &cursor->error); finish: mongoc_read_concern_destroy (read_concern_local); mongoc_counter_cursors_active_inc (); RETURN (cursor); } static bool _translate_query_opt (const char *query_field, const char **cmd_field, int *len) { if (query_field[0] != '$') { *cmd_field = query_field; *len = -1; return true; } /* strip the leading '$' */ query_field++; if (!strcmp (MONGOC_CURSOR_ORDERBY, query_field)) { *cmd_field = MONGOC_CURSOR_SORT; *len = MONGOC_CURSOR_SORT_LEN; } else if (!strcmp (MONGOC_CURSOR_SHOW_DISK_LOC, query_field)) { /* <= MongoDb 3.0 */ *cmd_field = MONGOC_CURSOR_SHOW_RECORD_ID; *len = MONGOC_CURSOR_SHOW_RECORD_ID_LEN; } else if (!strcmp (MONGOC_CURSOR_HINT, query_field)) { *cmd_field = MONGOC_CURSOR_HINT; *len = MONGOC_CURSOR_HINT_LEN; } else if (!strcmp (MONGOC_CURSOR_COMMENT, query_field)) { *cmd_field = MONGOC_CURSOR_COMMENT; *len = MONGOC_CURSOR_COMMENT_LEN; } else if (!strcmp (MONGOC_CURSOR_MAX_SCAN, query_field)) { *cmd_field = MONGOC_CURSOR_MAX_SCAN; *len = MONGOC_CURSOR_MAX_SCAN_LEN; } else if (!strcmp (MONGOC_CURSOR_MAX_TIME_MS, query_field)) { *cmd_field = MONGOC_CURSOR_MAX_TIME_MS; *len = MONGOC_CURSOR_MAX_TIME_MS_LEN; } else if (!strcmp (MONGOC_CURSOR_MAX, query_field)) { *cmd_field = MONGOC_CURSOR_MAX; *len = MONGOC_CURSOR_MAX_LEN; } else if (!strcmp (MONGOC_CURSOR_MIN, query_field)) { *cmd_field = MONGOC_CURSOR_MIN; *len = MONGOC_CURSOR_MIN_LEN; } else if (!strcmp (MONGOC_CURSOR_RETURN_KEY, query_field)) { *cmd_field = MONGOC_CURSOR_RETURN_KEY; *len = MONGOC_CURSOR_RETURN_KEY_LEN; } else if (!strcmp (MONGOC_CURSOR_SNAPSHOT, query_field)) { *cmd_field = MONGOC_CURSOR_SNAPSHOT; *len = MONGOC_CURSOR_SNAPSHOT_LEN; } else { /* not a special command field, must be a query operator like $or */ return false; } return true; } /* set up a new opt bson from older ways of specifying options. * secondary_ok may be NULL. * error may be NULL. */ void _mongoc_cursor_flags_to_opts (mongoc_query_flags_t qflags, bson_t *opts, /* IN/OUT */ bool *secondary_ok /* OUT */) { ENTRY; BSON_ASSERT (opts); if (secondary_ok) { *secondary_ok = !!(qflags & MONGOC_QUERY_SECONDARY_OK); } if (qflags & MONGOC_QUERY_TAILABLE_CURSOR) { bson_append_bool (opts, MONGOC_CURSOR_TAILABLE, MONGOC_CURSOR_TAILABLE_LEN, true); } if (qflags & MONGOC_QUERY_OPLOG_REPLAY) { bson_append_bool (opts, MONGOC_CURSOR_OPLOG_REPLAY, MONGOC_CURSOR_OPLOG_REPLAY_LEN, true); } if (qflags & MONGOC_QUERY_NO_CURSOR_TIMEOUT) { bson_append_bool (opts, MONGOC_CURSOR_NO_CURSOR_TIMEOUT, MONGOC_CURSOR_NO_CURSOR_TIMEOUT_LEN, true); } if (qflags & MONGOC_QUERY_AWAIT_DATA) { bson_append_bool (opts, MONGOC_CURSOR_AWAIT_DATA, MONGOC_CURSOR_AWAIT_DATA_LEN, true); } if (qflags & MONGOC_QUERY_EXHAUST) { bson_append_bool (opts, MONGOC_CURSOR_EXHAUST, MONGOC_CURSOR_EXHAUST_LEN, true); } if (qflags & MONGOC_QUERY_PARTIAL) { bson_append_bool (opts, MONGOC_CURSOR_ALLOW_PARTIAL_RESULTS, MONGOC_CURSOR_ALLOW_PARTIAL_RESULTS_LEN, true); } } /* Checks if the passed query was wrapped in a $query, and if so, parses the * query modifiers: * https://www.mongodb.com/docs/manual/reference/operator/query-modifier/ * and translates them to find command options: * https://www.mongodb.com/docs/manual/reference/command/find/ * opts must be initialized, and may already have options set. * unwrapped must be uninitialized, and will be initialized at return. * Returns true if query was unwrapped. */ bool _mongoc_cursor_translate_dollar_query_opts (const bson_t *query, bson_t *opts, bson_t *unwrapped, bson_error_t *error) { bool has_filter = false; const char *key; bson_iter_t iter; const char *opt_key; int len; uint32_t data_len; const uint8_t *data; bson_error_t error_local = {0}; ENTRY; BSON_ASSERT (query); BSON_ASSERT (opts); /* If the query is explicitly specified wrapped in $query, unwrap it and * translate the options to new options. */ if (bson_has_field (query, "$query")) { /* like "{$query: {a: 1}, $orderby: {b: 1}, $otherModifier: true}" */ if (!bson_iter_init (&iter, query)) { bson_set_error (&error_local, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid BSON in query document"); GOTO (done); } while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (key[0] != '$') { bson_set_error (&error_local, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot mix $query with non-dollar field '%s'", key); GOTO (done); } if (!strcmp (key, "$query")) { /* set "filter" to the incoming document's "$query" */ bson_iter_document (&iter, &data_len, &data); if (!bson_init_static (unwrapped, data, (size_t) data_len)) { bson_set_error ( &error_local, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid BSON in $query subdocument"); GOTO (done); } has_filter = true; } else if (_translate_query_opt (key, &opt_key, &len)) { /* "$orderby" becomes "sort", etc., "$unknown" -> "unknown" */ if (!bson_append_iter (opts, opt_key, len, &iter)) { bson_set_error ( &error_local, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Error adding \"%s\" to query", opt_key); } } else { /* strip leading "$" */ if (!bson_append_iter (opts, key + 1, -1, &iter)) { bson_set_error ( &error_local, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Error adding \"%s\" to query", key); } } } } done: if (error) { memcpy (error, &error_local, sizeof (bson_error_t)); } if (!has_filter) { bson_init (unwrapped); } RETURN (has_filter); } void mongoc_cursor_destroy (mongoc_cursor_t *cursor) { char *db; ENTRY; if (!cursor) { EXIT; } if (cursor->impl.destroy) { cursor->impl.destroy (&cursor->impl); } /* Always close the socket for an exhaust cursor, even if the client was * reset with mongoc_client_reset. That prevents further use of that socket. */ if (cursor->in_exhaust) { cursor->client->in_exhaust = false; if (cursor->state != DONE) { /* The only way to stop an exhaust cursor is to kill the connection */ mongoc_cluster_disconnect_node (&cursor->client->cluster, cursor->server_id); } } else if (cursor->client_generation == cursor->client->generation) { if (cursor->cursor_id) { db = bson_strndup (cursor->ns, cursor->dblen); _mongoc_client_kill_cursor (cursor->client, cursor->server_id, cursor->cursor_id, cursor->operation_id, db, cursor->ns + cursor->dblen + 1, cursor->client_session); bson_free (db); } } if (cursor->client_session && !cursor->explicit_session) { mongoc_client_session_destroy (cursor->client_session); } mongoc_read_prefs_destroy (cursor->read_prefs); mongoc_read_concern_destroy (cursor->read_concern); mongoc_write_concern_destroy (cursor->write_concern); bson_destroy (&cursor->opts); bson_destroy (&cursor->error_doc); bson_free (cursor->ns); bson_free (cursor); mongoc_counter_cursors_active_dec (); mongoc_counter_cursors_disposed_inc (); EXIT; } mongoc_server_stream_t * _mongoc_cursor_fetch_stream (mongoc_cursor_t *cursor, const mongoc_ss_log_context_t *log_context) { mongoc_server_stream_t *server_stream; bson_t reply; ENTRY; if (cursor->server_id) { /* We already did server selection once before. Reuse the prior * selection to create a new stream on the same server. */ server_stream = mongoc_cluster_stream_for_server (&cursor->client->cluster, cursor->server_id, true /* reconnect_ok */, cursor->client_session, &reply, &cursor->error); if (server_stream) { /* Also restore whether primary read preference was forced by server * selection */ server_stream->must_use_primary = cursor->must_use_primary; } } else { server_stream = cursor->is_aggr_with_write_stage ? mongoc_cluster_stream_for_aggr_with_write (&cursor->client->cluster, log_context, cursor->read_prefs, cursor->client_session, &reply, &cursor->error) : mongoc_cluster_stream_for_reads (&cursor->client->cluster, log_context, cursor->read_prefs, cursor->client_session, NULL, &reply, &cursor->error); if (server_stream) { /* Remember the selected server_id and whether primary read mode was * forced so that we can re-create an equivalent server_stream at a * later time */ cursor->server_id = server_stream->sd->id; cursor->must_use_primary = server_stream->must_use_primary; } } if (!server_stream) { bson_destroy (&cursor->error_doc); bson_copy_to (&reply, &cursor->error_doc); bson_destroy (&reply); } RETURN (server_stream); } bool _mongoc_cursor_monitor_command (mongoc_cursor_t *cursor, mongoc_server_stream_t *server_stream, const bson_t *cmd, const char *cmd_name) { mongoc_apm_command_started_t event; char *db; ENTRY; mongoc_client_t *client = cursor->client; const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor; mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND, "Command started", int32 ("requestId", client->cluster.request_id), server_description (server_stream->sd, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID, SERVICE_ID), utf8_n ("databaseName", cursor->ns, cursor->dblen), utf8 ("commandName", cmd_name), int64 ("operationId", cursor->operation_id), bson_as_json ("command", cmd)); if (!log_and_monitor->apm_callbacks.started) { /* successful */ RETURN (true); } db = bson_strndup (cursor->ns, cursor->dblen); mongoc_apm_command_started_init (&event, cmd, db, cmd_name, client->cluster.request_id, cursor->operation_id, &server_stream->sd->host, server_stream->sd->id, &server_stream->sd->service_id, server_stream->sd->server_connection_id, NULL, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.started (&event); mongoc_apm_command_started_cleanup (&event); bson_free (db); RETURN (true); } /* append array of docs from current cursor batch */ static void _mongoc_cursor_append_docs_array (mongoc_cursor_t *cursor, bson_t *docs, mongoc_cursor_response_legacy_t *response) { bool eof = false; char str[16]; const char *key; uint32_t i = 0; size_t keylen; const bson_t *doc; BSON_UNUSED (cursor); while ((doc = bson_reader_read (response->reader, &eof))) { keylen = bson_uint32_to_string (i, &key, str, sizeof str); bson_append_document (docs, key, (int) keylen, doc); } bson_reader_reset (response->reader); } void _mongoc_cursor_monitor_succeeded (mongoc_cursor_t *cursor, mongoc_cursor_response_legacy_t *response, int64_t duration, bool first_batch, mongoc_server_stream_t *stream, const char *cmd_name) { bson_t docs_array; mongoc_apm_command_succeeded_t event; ENTRY; mongoc_client_t *client = cursor->client; const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor; /* we sent OP_QUERY/OP_GETMORE, fake a reply to find/getMore command: * {ok: 1, cursor: {id: 17, ns: "...", first/nextBatch: [ ... docs ... ]}} */ bson_init (&docs_array); _mongoc_cursor_append_docs_array (cursor, &docs_array, response); bsonBuildDecl (reply, kv ("ok", int32 (1)), kv ("cursor", doc (kv ("id", int64 (mongoc_cursor_get_id (cursor))), kv ("ns", utf8_w_len (cursor->ns, cursor->nslen)), kv (first_batch ? "firstBatch" : "nextBatch", bsonArray (docs_array))))); char *db = bson_strndup (cursor->ns, cursor->dblen); bson_destroy (&docs_array); mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND, "Command succeeded", int32 ("requestId", client->cluster.request_id), server_description (stream->sd, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID, SERVICE_ID), utf8 ("databaseName", db), utf8 ("commandName", cmd_name), int64 ("operationId", cursor->operation_id), monotonic_time_duration (duration), cmd_name_reply (cmd_name, &reply)); if (log_and_monitor->apm_callbacks.succeeded) { mongoc_apm_command_succeeded_init (&event, duration, &reply, cmd_name, db, client->cluster.request_id, cursor->operation_id, &stream->sd->host, stream->sd->id, &stream->sd->service_id, stream->sd->server_connection_id, false, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.succeeded (&event); mongoc_apm_command_succeeded_cleanup (&event); } bson_destroy (&reply); bson_free (db); EXIT; } void _mongoc_cursor_monitor_failed (mongoc_cursor_t *cursor, int64_t duration, mongoc_server_stream_t *stream, const char *cmd_name) { mongoc_apm_command_failed_t event; ENTRY; mongoc_client_t *client = cursor->client; const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor; /* we sent OP_QUERY/OP_GETMORE, fake a reply to find/getMore command: * {ok: 0} */ bsonBuildDecl (reply, kv ("ok", int32 (0))); char *db = bson_strndup (cursor->ns, cursor->dblen); mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND, "Command failed", int32 ("requestId", client->cluster.request_id), server_description (stream->sd, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID, SERVICE_ID), utf8 ("databaseName", db), utf8 ("commandName", cmd_name), int64 ("operationId", cursor->operation_id), monotonic_time_duration (duration), bson_as_json ("failure", &reply)); if (log_and_monitor->apm_callbacks.failed) { mongoc_apm_command_failed_init (&event, duration, cmd_name, db, &cursor->error, &reply, client->cluster.request_id, cursor->operation_id, &stream->sd->host, stream->sd->id, &stream->sd->service_id, stream->sd->server_connection_id, false, log_and_monitor->apm_context); log_and_monitor->apm_callbacks.failed (&event); mongoc_apm_command_failed_cleanup (&event); } bson_destroy (&reply); bson_free (db); EXIT; } #define ADD_FLAG(_flags, _value) \ do { \ if (!BSON_ITER_HOLDS_BOOL (&iter)) { \ bson_set_error (&cursor->error, \ MONGOC_ERROR_COMMAND, \ MONGOC_ERROR_COMMAND_INVALID_ARG, \ "invalid option %s, should be type bool", \ key); \ return false; \ } \ if (bson_iter_as_bool (&iter)) { \ *_flags |= _value; \ } \ } while (false) bool _mongoc_cursor_opts_to_flags (mongoc_cursor_t *cursor, mongoc_server_stream_t *stream, int32_t *flags /* OUT */) { /* CDRIVER-4722: these flags are only used in legacy OP_QUERY */ bson_iter_t iter; const char *key; *flags = MONGOC_OP_QUERY_FLAG_NONE; if (!bson_iter_init (&iter, &cursor->opts)) { bson_set_error (&cursor->error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (!strcmp (key, MONGOC_CURSOR_ALLOW_PARTIAL_RESULTS)) { ADD_FLAG (flags, MONGOC_OP_QUERY_FLAG_PARTIAL); } else if (!strcmp (key, MONGOC_CURSOR_AWAIT_DATA)) { ADD_FLAG (flags, MONGOC_OP_QUERY_FLAG_AWAIT_DATA); } else if (!strcmp (key, MONGOC_CURSOR_EXHAUST)) { ADD_FLAG (flags, MONGOC_OP_QUERY_FLAG_EXHAUST); } else if (!strcmp (key, MONGOC_CURSOR_NO_CURSOR_TIMEOUT)) { ADD_FLAG (flags, MONGOC_OP_QUERY_FLAG_NO_CURSOR_TIMEOUT); } else if (!strcmp (key, MONGOC_CURSOR_OPLOG_REPLAY)) { ADD_FLAG (flags, MONGOC_OP_QUERY_FLAG_OPLOG_REPLAY); } else if (!strcmp (key, MONGOC_CURSOR_TAILABLE)) { ADD_FLAG (flags, MONGOC_OP_QUERY_FLAG_TAILABLE_CURSOR); } } if (cursor->secondary_ok) { *flags |= MONGOC_OP_QUERY_FLAG_SECONDARY_OK; } else if (cursor->server_id && (stream->topology_type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY || stream->topology_type == MONGOC_TOPOLOGY_RS_NO_PRIMARY) && stream->sd->type != MONGOC_SERVER_RS_PRIMARY) { *flags |= MONGOC_OP_QUERY_FLAG_SECONDARY_OK; } return true; } bool _mongoc_cursor_use_op_msg (const mongoc_cursor_t *cursor, int32_t wire_version) { /* CDRIVER-4722: always true once 4.2 is the minimum supported No check needed for 3.6 as it's the current minimum */ return !_mongoc_cursor_get_opt_bool (cursor, MONGOC_CURSOR_EXHAUST) || wire_version >= WIRE_VERSION_4_2; } bool _mongoc_cursor_run_command ( mongoc_cursor_t *cursor, const bson_t *command, const bson_t *opts, bson_t *reply, bool retry_prohibited) { mongoc_server_stream_t *server_stream; bson_iter_t iter; mongoc_cmd_parts_t parts; bool is_primary; mongoc_read_prefs_t *prefs = NULL; char *db = NULL; mongoc_session_opt_t *session_opts; bool ret = false; bool is_retryable = true; ENTRY; const char *cmd_name = _mongoc_get_command_name (command); mongoc_cmd_parts_init (&parts, cursor->client, db, MONGOC_QUERY_NONE, command); parts.is_read_command = true; parts.read_prefs = cursor->read_prefs; parts.assembled.operation_id = cursor->operation_id; const mongoc_ss_log_context_t ss_log_context = { .operation = cmd_name, .has_operation_id = true, .operation_id = parts.assembled.operation_id}; server_stream = _mongoc_cursor_fetch_stream (cursor, &ss_log_context); if (!server_stream) { _mongoc_bson_init_if_set (reply); GOTO (done); } if (opts) { if (!bson_iter_init (&iter, opts)) { _mongoc_bson_init_if_set (reply); bson_set_error (&cursor->error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid BSON in opts document"); GOTO (done); } if (!mongoc_cmd_parts_append_opts (&parts, &iter, &cursor->error)) { _mongoc_bson_init_if_set (reply); GOTO (done); } } if (parts.assembled.session) { /* initial query/aggregate/etc, and opts contains "sessionId" */ BSON_ASSERT (!cursor->client_session); BSON_ASSERT (!cursor->explicit_session); cursor->client_session = parts.assembled.session; cursor->explicit_session = true; } else if (cursor->client_session) { /* a getMore with implicit or explicit session already acquired */ mongoc_cmd_parts_set_session (&parts, cursor->client_session); } else { /* try to create an implicit session. not causally consistent. we keep * the session but leave cursor->explicit_session as 0, so we use the * same lsid for getMores but destroy the session when the cursor dies. */ session_opts = mongoc_session_opts_new (); mongoc_session_opts_set_causal_consistency (session_opts, false); /* returns NULL if sessions aren't supported. ignore errors. */ cursor->client_session = mongoc_client_start_session (cursor->client, session_opts, NULL); mongoc_cmd_parts_set_session (&parts, cursor->client_session); mongoc_session_opts_destroy (session_opts); } if (!mongoc_cmd_parts_set_read_concern (&parts, cursor->read_concern, &cursor->error)) { _mongoc_bson_init_if_set (reply); GOTO (done); } db = bson_strndup (cursor->ns, cursor->dblen); parts.assembled.db_name = db; { int32_t flags; if (!_mongoc_cursor_opts_to_flags (cursor, server_stream, &flags)) { _mongoc_bson_init_if_set (reply); GOTO (done); } parts.user_query_flags = (mongoc_query_flags_t) flags; } if (_mongoc_cursor_get_opt_bool (cursor, MONGOC_CURSOR_EXHAUST)) { const bool sharded = _mongoc_topology_get_type (cursor->client->topology) == MONGOC_TOPOLOGY_SHARDED; const int32_t wire_version = server_stream->sd->max_wire_version; if (sharded && wire_version < WIRE_VERSION_MONGOS_EXHAUST) { /* Return error since mongos < 7.2 doesn't support exhaust cursors */ bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "exhaust cursors require mongos with wire version: " "%d, but mongos has wire version: %d.", wire_version, WIRE_VERSION_MONGOS_EXHAUST); _mongoc_bson_init_if_set (reply); GOTO (done); } parts.assembled.op_msg_is_exhaust = true; } /* we might use mongoc_cursor_set_hint to target a secondary but have no * read preference, so the secondary rejects the read. same if we have a * direct connection to a secondary (topology type "single"). with * OP_QUERY we handle this by setting secondaryOk. here we use * $readPreference. */ is_primary = !cursor->read_prefs || cursor->read_prefs->mode == MONGOC_READ_PRIMARY; if (strcmp (cmd_name, "getMore") != 0 && is_primary && parts.user_query_flags & MONGOC_QUERY_SECONDARY_OK) { parts.read_prefs = prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY_PREFERRED); } else { parts.read_prefs = cursor->read_prefs; } is_retryable = _is_retryable_read (&parts, server_stream); if (!strcmp (cmd_name, "getMore")) { is_retryable = false; } if (!strcmp (cmd_name, "aggregate")) { bson_iter_t pipeline_iter; if (bson_iter_init_find (&pipeline_iter, command, "pipeline") && BSON_ITER_HOLDS_ARRAY (&pipeline_iter) && bson_iter_recurse (&pipeline_iter, &pipeline_iter)) { if (_has_write_key (&pipeline_iter)) { is_retryable = false; } } } if (is_retryable && retry_prohibited) { is_retryable = false; } if (cursor->write_concern && !mongoc_write_concern_is_default (cursor->write_concern)) { parts.assembled.is_acknowledged = mongoc_write_concern_is_acknowledged (cursor->write_concern); mongoc_write_concern_append (cursor->write_concern, &parts.extra); } if (!mongoc_cmd_parts_assemble (&parts, server_stream, &cursor->error)) { _mongoc_bson_init_if_set (reply); GOTO (done); } retry: ret = mongoc_cluster_run_command_monitored (&cursor->client->cluster, &parts.assembled, reply, &cursor->error); if (ret) { memset (&cursor->error, 0, sizeof (bson_error_t)); } if (is_retryable && _mongoc_read_error_get_type (ret, &cursor->error, reply) == MONGOC_READ_ERR_RETRY) { is_retryable = false; { mongoc_deprioritized_servers_t *const ds = mongoc_deprioritized_servers_new (); mongoc_deprioritized_servers_add_if_sharded (ds, server_stream->topology_type, server_stream->sd); mongoc_server_stream_cleanup (server_stream); BSON_ASSERT (!cursor->is_aggr_with_write_stage && "Cannot attempt a retry on an aggregate operation that " "contains write stages"); server_stream = mongoc_cluster_stream_for_reads (&cursor->client->cluster, &ss_log_context, cursor->read_prefs, cursor->client_session, ds, reply, &cursor->error); mongoc_deprioritized_servers_destroy (ds); } if (server_stream) { cursor->server_id = server_stream->sd->id; parts.assembled.server_stream = server_stream; bson_destroy (reply); GOTO (retry); } } if (cursor->error.domain) { bson_destroy (&cursor->error_doc); bson_copy_to (reply, &cursor->error_doc); } /* Read and Write Concern Spec: "Drivers SHOULD parse server replies for a * "writeConcernError" field and report the error only in command-specific * helper methods that take a separate write concern parameter or an options * parameter that may contain a write concern option. * * Only command helpers with names like "_with_write_concern" can create * cursors with a non-NULL write_concern field. */ if (ret && cursor->write_concern) { ret = !_mongoc_parse_wc_err (reply, &cursor->error); } done: mongoc_server_stream_cleanup (server_stream); mongoc_cmd_parts_cleanup (&parts); mongoc_read_prefs_destroy (prefs); bson_free (db); return ret; } void _mongoc_cursor_collection (const mongoc_cursor_t *cursor, const char **collection, int *collection_len) { /* ns is like "db.collection". Collection name is located past the ".". */ *collection = cursor->ns + (cursor->dblen + 1); /* Collection name's length is ns length, minus length of db name and ".". */ *collection_len = cursor->nslen - cursor->dblen - 1; BSON_ASSERT (*collection_len > 0); } void _mongoc_cursor_prepare_find_command (mongoc_cursor_t *cursor, const bson_t *filter, bson_t *command) { const char *collection; int collection_len; _mongoc_cursor_collection (cursor, &collection, &collection_len); bson_append_utf8 (command, MONGOC_CURSOR_FIND, MONGOC_CURSOR_FIND_LEN, collection, collection_len); bson_append_document (command, MONGOC_CURSOR_FILTER, MONGOC_CURSOR_FILTER_LEN, filter); } bool mongoc_cursor_error (mongoc_cursor_t *cursor, bson_error_t *error) { ENTRY; RETURN (mongoc_cursor_error_document (cursor, error, NULL)); } bool mongoc_cursor_error_document (mongoc_cursor_t *cursor, bson_error_t *error, const bson_t **doc) { ENTRY; BSON_ASSERT (cursor); if (BSON_UNLIKELY (CURSOR_FAILED (cursor))) { bson_set_error (error, cursor->error.domain, cursor->error.code, "%s", cursor->error.message); if (doc) { *doc = &cursor->error_doc; } RETURN (true); } if (doc) { *doc = NULL; } RETURN (false); } static mongoc_cursor_state_t _call_transition (mongoc_cursor_t *cursor) { mongoc_cursor_state_t state = cursor->state; _mongoc_cursor_impl_transition_t fn = NULL; switch (state) { case UNPRIMED: fn = cursor->impl.prime; break; case IN_BATCH: fn = cursor->impl.pop_from_batch; break; case END_OF_BATCH: fn = cursor->impl.get_next_batch; break; case DONE: default: fn = NULL; break; } if (!fn) { return DONE; } state = fn (cursor); if (cursor->error.domain) { state = DONE; } return state; } bool mongoc_cursor_next (mongoc_cursor_t *cursor, const bson_t **bson) { bool ret = false; bool attempted_refresh = false; ENTRY; BSON_ASSERT (cursor); BSON_ASSERT (bson); TRACE ("cursor_id(%" PRId64 ")", cursor->cursor_id); if (cursor->client_generation != cursor->client->generation) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot advance cursor after client reset"); RETURN (false); } if (bson) { *bson = NULL; } if (CURSOR_FAILED (cursor)) { RETURN (false); } if (cursor->state == DONE) { bson_set_error (&cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot advance a completed or failed cursor."); RETURN (false); } /* * We cannot proceed if another cursor is receiving results in exhaust mode. */ if (cursor->client->in_exhaust && !cursor->in_exhaust) { bson_set_error (&cursor->error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_IN_EXHAUST, "Another cursor derived from this client is in exhaust."); RETURN (false); } cursor->current = NULL; /* if an error was set on this cursor before calling next, transition to DONE * immediately. */ if (cursor->error.domain) { cursor->state = DONE; GOTO (done); } while (cursor->state != DONE) { /* even when there is no data to return, some cursors remain open and * continue sending empty batches (e.g. a tailable or change stream * cursor). in that case, do not attempt to get another batch. */ if (cursor->state == END_OF_BATCH) { if (attempted_refresh) { RETURN (false); } attempted_refresh = true; } cursor->state = _call_transition (cursor); /* check if we received a document. */ if (cursor->current) { *bson = cursor->current; ret = true; GOTO (done); } if (cursor->state == DONE) { GOTO (done); } } done: cursor->count++; RETURN (ret); } bool mongoc_cursor_more (mongoc_cursor_t *cursor) { ENTRY; BSON_ASSERT (cursor); if (CURSOR_FAILED (cursor)) { RETURN (false); } RETURN (cursor->state != DONE); } void mongoc_cursor_get_host (mongoc_cursor_t *cursor, mongoc_host_list_t *host) { mongoc_server_description_t const *description; mc_shared_tpld td; BSON_ASSERT (cursor); BSON_ASSERT (host); memset (host, 0, sizeof *host); if (!cursor->server_id) { MONGOC_WARNING ("%s(): Must send query before fetching peer.", BSON_FUNC); return; } td = mc_tpld_take_ref (cursor->client->topology); description = mongoc_topology_description_server_by_id_const (td.ptr, cursor->server_id, &cursor->error); if (description) { *host = description->host; } mc_tpld_drop_ref (&td); EXIT; } mongoc_cursor_t * mongoc_cursor_clone (const mongoc_cursor_t *cursor) { mongoc_cursor_t *_clone; BSON_ASSERT (cursor); _clone = BSON_ALIGNED_ALLOC0 (mongoc_cursor_t); _clone->client = cursor->client; _clone->nslen = cursor->nslen; _clone->dblen = cursor->dblen; _clone->explicit_session = cursor->explicit_session; if (cursor->read_prefs) { _clone->read_prefs = mongoc_read_prefs_copy (cursor->read_prefs); } if (cursor->read_concern) { _clone->read_concern = mongoc_read_concern_copy (cursor->read_concern); } if (cursor->write_concern) { _clone->write_concern = mongoc_write_concern_copy (cursor->write_concern); } if (cursor->explicit_session) { _clone->client_session = cursor->client_session; } bson_copy_to (&cursor->opts, &_clone->opts); bson_init (&_clone->error_doc); _clone->ns = bson_strdup (cursor->ns); /* copy the context functions by default. */ memcpy (&_clone->impl, &cursor->impl, sizeof (cursor->impl)); if (cursor->impl.clone) { cursor->impl.clone (&_clone->impl, &cursor->impl); } mongoc_counter_cursors_active_inc (); RETURN (_clone); } /* *-------------------------------------------------------------------------- * * mongoc_cursor_is_alive -- * * Deprecated for mongoc_cursor_more. * *-------------------------------------------------------------------------- */ bool mongoc_cursor_is_alive (const mongoc_cursor_t *cursor) /* IN */ { return mongoc_cursor_more ((mongoc_cursor_t *) cursor); } const bson_t * mongoc_cursor_current (const mongoc_cursor_t *cursor) /* IN */ { BSON_ASSERT (cursor); return cursor->current; } void mongoc_cursor_set_batch_size (mongoc_cursor_t *cursor, uint32_t batch_size) { BSON_ASSERT (cursor); bson_iter_t iter; if (!bson_iter_init_find (&iter, &cursor->opts, MONGOC_CURSOR_BATCH_SIZE)) { bson_append_int64 (&cursor->opts, MONGOC_CURSOR_BATCH_SIZE, MONGOC_CURSOR_BATCH_SIZE_LEN, batch_size); } else if (BSON_ITER_HOLDS_INT64 (&iter)) { bson_iter_overwrite_int64 (&iter, (int64_t) batch_size); } else if (BSON_ITER_HOLDS_INT32 (&iter)) { if (!mcommon_in_range_int32_t_unsigned (batch_size)) { MONGOC_WARNING ("unable to overwrite stored int32 batchSize with " "out-of-range value %" PRIu32, batch_size); return; } bson_iter_overwrite_int32 (&iter, (int32_t) batch_size); } else if (BSON_ITER_HOLDS_DOUBLE (&iter)) { bson_iter_overwrite_double (&iter, (double) batch_size); } else if (BSON_ITER_HOLDS_DECIMAL128 (&iter)) { bson_decimal128_t val; val.high = 0x3040000000000000; val.low = (uint64_t) batch_size; bson_iter_overwrite_decimal128 (&iter, &val); } else { MONGOC_WARNING ("unable to overwrite non-numeric stored batchSize"); } } uint32_t mongoc_cursor_get_batch_size (const mongoc_cursor_t *cursor) { BSON_ASSERT (cursor); return (uint32_t) _mongoc_cursor_get_opt_int64 (cursor, MONGOC_CURSOR_BATCH_SIZE, 0); } bool mongoc_cursor_set_limit (mongoc_cursor_t *cursor, int64_t limit) { BSON_ASSERT (cursor); if (cursor->state == UNPRIMED) { if (limit < 0) { return _mongoc_cursor_set_opt_int64 (cursor, MONGOC_CURSOR_LIMIT, -limit) && _mongoc_cursor_set_opt_bool (cursor, MONGOC_CURSOR_SINGLE_BATCH, true); } else { return _mongoc_cursor_set_opt_int64 (cursor, MONGOC_CURSOR_LIMIT, limit); } } else { return false; } } int64_t mongoc_cursor_get_limit (const mongoc_cursor_t *cursor) { int64_t limit; bool single_batch; BSON_ASSERT (cursor); limit = _mongoc_cursor_get_opt_int64 (cursor, MONGOC_CURSOR_LIMIT, 0); single_batch = _mongoc_cursor_get_opt_bool (cursor, MONGOC_CURSOR_SINGLE_BATCH); if (limit > 0 && single_batch) { limit = -limit; } return limit; } bool mongoc_cursor_set_hint (mongoc_cursor_t *cursor, uint32_t server_id) { return mongoc_cursor_set_server_id (cursor, server_id); } bool mongoc_cursor_set_server_id (mongoc_cursor_t *cursor, uint32_t server_id) { BSON_ASSERT (cursor); if (cursor->server_id) { MONGOC_ERROR ("mongoc_cursor_set_server_id: server_id already set"); return false; } if (!server_id) { MONGOC_ERROR ("mongoc_cursor_set_server_id: cannot set server_id to 0"); return false; } cursor->server_id = server_id; return true; } uint32_t mongoc_cursor_get_hint (const mongoc_cursor_t *cursor) { return mongoc_cursor_get_server_id (cursor); } uint32_t mongoc_cursor_get_server_id (const mongoc_cursor_t *cursor) { BSON_ASSERT (cursor); return cursor->server_id; } int64_t mongoc_cursor_get_id (const mongoc_cursor_t *cursor) { BSON_ASSERT (cursor); return cursor->cursor_id; } void mongoc_cursor_set_max_await_time_ms (mongoc_cursor_t *cursor, uint32_t max_await_time_ms) { BSON_ASSERT (cursor); if (cursor->state == UNPRIMED) { _mongoc_cursor_set_opt_int64 (cursor, MONGOC_CURSOR_MAX_AWAIT_TIME_MS, (int64_t) max_await_time_ms); } } uint32_t mongoc_cursor_get_max_await_time_ms (const mongoc_cursor_t *cursor) { bson_iter_t iter; BSON_ASSERT (cursor); if (bson_iter_init_find (&iter, &cursor->opts, MONGOC_CURSOR_MAX_AWAIT_TIME_MS)) { return (uint32_t) bson_iter_as_int64 (&iter); } return 0; } /* deprecated for mongoc_cursor_new_from_command_reply_with_opts */ mongoc_cursor_t * mongoc_cursor_new_from_command_reply (mongoc_client_t *client, bson_t *reply, uint32_t server_id) { mongoc_cursor_t *cursor; bson_t cmd = BSON_INITIALIZER; bson_t opts = BSON_INITIALIZER; BSON_ASSERT_PARAM (client); BSON_ASSERT (reply); /* options are passed through by adding them to reply. */ bsonBuildAppend (*reply, insert (opts, not(key ("cursor", "ok", "operationTime", "$clusterTime", "$gleStats")))); if (server_id) { bson_append_int64 (&opts, "serverId", 8, server_id); } cursor = _mongoc_cursor_cmd_new_from_reply (client, &cmd, &opts, reply); bson_destroy (&cmd); bson_destroy (&opts); return cursor; } mongoc_cursor_t * mongoc_cursor_new_from_command_reply_with_opts (mongoc_client_t *client, bson_t *reply, const bson_t *opts) { mongoc_cursor_t *cursor; bson_t cmd = BSON_INITIALIZER; BSON_ASSERT_PARAM (client); BSON_ASSERT (reply); cursor = _mongoc_cursor_cmd_new_from_reply (client, &cmd, opts, reply); bson_destroy (&cmd); return cursor; } bool _mongoc_cursor_start_reading_response (mongoc_cursor_t *cursor, mongoc_cursor_response_t *response) { bson_iter_t iter; bson_iter_t child; const char *ns; uint32_t nslen; bool in_batch = false; if (bson_iter_init_find (&iter, &response->reply, "cursor") && BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) { while (bson_iter_next (&child)) { if (BSON_ITER_IS_KEY (&child, "id")) { cursor->cursor_id = bson_iter_as_int64 (&child); } else if (BSON_ITER_IS_KEY (&child, "ns")) { ns = bson_iter_utf8 (&child, &nslen); _mongoc_set_cursor_ns (cursor, ns, nslen); } else if (BSON_ITER_IS_KEY (&child, "firstBatch") || BSON_ITER_IS_KEY (&child, "nextBatch")) { if (BSON_ITER_HOLDS_ARRAY (&child) && bson_iter_recurse (&child, &response->batch_iter)) { in_batch = true; } } } } /* Driver Sessions Spec: "When an implicit session is associated with a * cursor for use with getMore operations, the session MUST be returned to * the pool immediately following a getMore operation that indicates that the * cursor has been exhausted." */ if (cursor->cursor_id == 0 && cursor->client_session && !cursor->explicit_session) { mongoc_client_session_destroy (cursor->client_session); cursor->client_session = NULL; } return in_batch; } void _mongoc_cursor_response_read (mongoc_cursor_t *cursor, mongoc_cursor_response_t *response, const bson_t **bson) { const uint8_t *data = NULL; uint32_t data_len = 0; ENTRY; BSON_UNUSED (cursor); if (bson_iter_next (&response->batch_iter) && BSON_ITER_HOLDS_DOCUMENT (&response->batch_iter)) { bson_iter_document (&response->batch_iter, &data_len, &data); /* bson_iter_next guarantees valid BSON, so this must succeed */ BSON_ASSERT (bson_init_static (&response->current_doc, data, data_len)); *bson = &response->current_doc; } } /* sets cursor error if could not get the next batch. */ void _mongoc_cursor_response_refresh (mongoc_cursor_t *cursor, const bson_t *command, const bson_t *opts, mongoc_cursor_response_t *response) { ENTRY; bson_destroy (&response->reply); /* server replies to find / aggregate with {cursor: {id: N, firstBatch: []}}, * to getMore command with {cursor: {id: N, nextBatch: []}}. */ if (_mongoc_cursor_run_command (cursor, command, opts, &response->reply, false)) { if (_mongoc_cursor_start_reading_response (cursor, response)) { cursor->in_exhaust = cursor->client->in_exhaust; return; } } if (!cursor->error.domain) { bson_set_error (&cursor->error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Invalid reply to %s command.", _mongoc_get_command_name (command)); } } void _mongoc_cursor_prepare_getmore_command (mongoc_cursor_t *cursor, bson_t *command) { const char *collection; int collection_len; int64_t batch_size; bson_iter_t iter; bool await_data; int64_t max_await_time_ms; ENTRY; _mongoc_cursor_collection (cursor, &collection, &collection_len); bson_init (command); bson_append_int64 (command, "getMore", 7, mongoc_cursor_get_id (cursor)); bson_append_utf8 (command, "collection", 10, collection, collection_len); batch_size = mongoc_cursor_get_batch_size (cursor); /* See find, getMore, and killCursors Spec for batchSize rules */ if (batch_size) { bson_append_int64 ( command, MONGOC_CURSOR_BATCH_SIZE, MONGOC_CURSOR_BATCH_SIZE_LEN, abs (_mongoc_n_return (cursor))); } if (bson_iter_init_find (&iter, &cursor->opts, MONGOC_CURSOR_COMMENT) && bson_iter_value (&iter)->value_type != BSON_TYPE_EOD) { const bson_value_t *comment = bson_iter_value (&iter); mongoc_server_stream_t *server_stream; /* CRUD spec: If a comment is provided, drivers MUST attach this comment * to all subsequent getMore commands run on the same cursor for server * versions 4.4 and above. For server versions below 4.4 drivers MUST NOT * attach a comment to getMore commands. * * Since this function has no error reporting, we also no-op if we cannot * fetch a stream. */ const mongoc_ss_log_context_t ss_log_context = {.operation = "getMore"}; server_stream = _mongoc_cursor_fetch_stream (cursor, &ss_log_context); if (server_stream != NULL && server_stream->sd->max_wire_version >= WIRE_VERSION_4_4) { bson_append_value (command, MONGOC_CURSOR_COMMENT, MONGOC_CURSOR_COMMENT_LEN, comment); } mongoc_server_stream_cleanup (server_stream); } /* Find, getMore And killCursors Commands Spec: "In the case of a tailable cursor with awaitData == true the driver MUST provide a Cursor level option named maxAwaitTimeMS (See CRUD specification for details). The maxTimeMS option on the getMore command MUST be set to the value of the option maxAwaitTimeMS. If no maxAwaitTimeMS is specified, the driver SHOULD not set maxTimeMS on the getMore command." */ await_data = _mongoc_cursor_get_opt_bool (cursor, MONGOC_CURSOR_TAILABLE) && _mongoc_cursor_get_opt_bool (cursor, MONGOC_CURSOR_AWAIT_DATA); if (await_data) { max_await_time_ms = _mongoc_cursor_get_opt_int64 (cursor, MONGOC_CURSOR_MAX_AWAIT_TIME_MS, 0); if (max_await_time_ms) { bson_append_int64 (command, MONGOC_CURSOR_MAX_TIME_MS, MONGOC_CURSOR_MAX_TIME_MS_LEN, max_await_time_ms); } } } /* sets the cursor to be empty so it returns NULL on the first call to * cursor_next but does not return an error. */ void _mongoc_cursor_set_empty (mongoc_cursor_t *cursor) { memset (&cursor->error, 0, sizeof (bson_error_t)); bson_reinit (&cursor->error_doc); cursor->state = IN_BATCH; } void _mongoc_cursor_prime (mongoc_cursor_t *cursor) { cursor->state = cursor->impl.prime (cursor); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cursor.h0000644000175100001660000000715414760300420022463 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CURSOR_H #define MONGOC_CURSOR_H #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_cursor_t mongoc_cursor_t; /* forward decl */ struct _mongoc_client_t; MONGOC_EXPORT (mongoc_cursor_t *) mongoc_cursor_clone (const mongoc_cursor_t *cursor) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_cursor_destroy (mongoc_cursor_t *cursor); MONGOC_EXPORT (bool) mongoc_cursor_more (mongoc_cursor_t *cursor); MONGOC_EXPORT (bool) mongoc_cursor_next (mongoc_cursor_t *cursor, const bson_t **bson); MONGOC_EXPORT (bool) mongoc_cursor_error (mongoc_cursor_t *cursor, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_cursor_error_document (mongoc_cursor_t *cursor, bson_error_t *error, const bson_t **doc); MONGOC_EXPORT (void) mongoc_cursor_get_host (mongoc_cursor_t *cursor, mongoc_host_list_t *host); MONGOC_EXPORT (bool) mongoc_cursor_is_alive (const mongoc_cursor_t *cursor) BSON_GNUC_DEPRECATED_FOR (mongoc_cursor_more); MONGOC_EXPORT (const bson_t *) mongoc_cursor_current (const mongoc_cursor_t *cursor); MONGOC_EXPORT (void) mongoc_cursor_set_batch_size (mongoc_cursor_t *cursor, uint32_t batch_size); MONGOC_EXPORT (uint32_t) mongoc_cursor_get_batch_size (const mongoc_cursor_t *cursor); MONGOC_EXPORT (bool) mongoc_cursor_set_limit (mongoc_cursor_t *cursor, int64_t limit); MONGOC_EXPORT (int64_t) mongoc_cursor_get_limit (const mongoc_cursor_t *cursor); // `mongoc_cursor_set_hint` is deprecated for more aptly named `mongoc_cursor_set_server_id`. MONGOC_EXPORT (bool) mongoc_cursor_set_hint (mongoc_cursor_t *cursor, uint32_t server_id) BSON_GNUC_DEPRECATED_FOR (mongoc_cursor_set_server_id); MONGOC_EXPORT (bool) mongoc_cursor_set_server_id (mongoc_cursor_t *cursor, uint32_t server_id); // `mongoc_cursor_get_hint` is deprecated for more aptly named `mongoc_cursor_get_server_id`. MONGOC_EXPORT (uint32_t) mongoc_cursor_get_hint (const mongoc_cursor_t *cursor) BSON_GNUC_DEPRECATED_FOR (mongoc_cursor_get_server_id); MONGOC_EXPORT (uint32_t) mongoc_cursor_get_server_id (const mongoc_cursor_t *cursor); MONGOC_EXPORT (int64_t) mongoc_cursor_get_id (const mongoc_cursor_t *cursor); MONGOC_EXPORT (void) mongoc_cursor_set_max_await_time_ms (mongoc_cursor_t *cursor, uint32_t max_await_time_ms); MONGOC_EXPORT (uint32_t) mongoc_cursor_get_max_await_time_ms (const mongoc_cursor_t *cursor); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_cursor_new_from_command_reply (struct _mongoc_client_t *client, bson_t *reply, uint32_t server_id) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_cursor_new_from_command_reply_with_opts); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_cursor_new_from_command_reply_with_opts (struct _mongoc_client_t *client, bson_t *reply, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_CURSOR_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cyrus-private.h0000644000175100001660000000362714760300420023764 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_CYRUS_PRIVATE_H #define MONGOC_CYRUS_PRIVATE_H #include #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_cyrus_t mongoc_cyrus_t; struct _mongoc_cyrus_t { mongoc_sasl_t credentials; sasl_callback_t callbacks[6]; sasl_conn_t *conn; bool done; int step; sasl_interact_t *interact; }; #ifndef SASL_CALLBACK_FN #define SASL_CALLBACK_FN(_f) ((int (*) (void)) ((void (*) (void)) (_f))) #endif int _mongoc_cyrus_verifyfile_cb (void *context, const char *file, sasl_verify_type_t type); void _mongoc_cyrus_init (mongoc_cyrus_t *sasl); bool _mongoc_cyrus_new_from_cluster ( mongoc_cyrus_t *sasl, mongoc_cluster_t *cluster, mongoc_stream_t *stream, const char *hostname, bson_error_t *error); int _mongoc_cyrus_log (mongoc_cyrus_t *sasl, int level, const char *message); void _mongoc_cyrus_destroy (mongoc_cyrus_t *sasl); bool _mongoc_cyrus_step (mongoc_cyrus_t *sasl, const uint8_t *inbuf, uint32_t inbuflen, uint8_t **outbuf, uint32_t *outbuflen, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_CYRUS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-cyrus.c0000644000175100001660000003505614760300420022310 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SASL_CYRUS #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "CYRUS-SASL" bool _mongoc_cyrus_set_mechanism (mongoc_cyrus_t *sasl, const char *mechanism, bson_error_t *error) { mcommon_string_append_t available_mechs_str; mcommon_string_new_as_append (&available_mechs_str); const char **mechs = sasl_global_listmech (); int i = 0; bool ok = false; BSON_ASSERT (sasl); for (i = 0; mechs[i]; i++) { if (!strcmp (mechs[i], mechanism)) { ok = true; break; } mcommon_string_append (&available_mechs_str, mechs[i]); if (mechs[i + 1]) { mcommon_string_append (&available_mechs_str, ","); } } if (ok) { bson_free (sasl->credentials.mechanism); sasl->credentials.mechanism = mechanism ? bson_strdup (mechanism) : NULL; } else { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOMECH, "SASL Failure: Unsupported mechanism by client: %s. " "Available mechanisms: %s", mechanism, mcommon_str_from_append (&available_mechs_str)); } mcommon_string_from_append_destroy (&available_mechs_str); return ok; } static int _mongoc_cyrus_get_pass (mongoc_cyrus_t *sasl, int param_id, const char **result, unsigned *result_len) { BSON_ASSERT (sasl); BSON_ASSERT (param_id == SASL_CB_PASS); if (result) { *result = sasl->credentials.pass; } if (result_len) { *result_len = sasl->credentials.pass ? (unsigned) strlen (sasl->credentials.pass) : 0; } return (sasl->credentials.pass != NULL) ? SASL_OK : SASL_FAIL; } static int _mongoc_cyrus_canon_user (sasl_conn_t *conn, mongoc_cyrus_t *sasl, const char *in, unsigned inlen, unsigned flags, const char *user_realm, char *out, unsigned out_max, unsigned *out_len) { BSON_UNUSED (conn); BSON_UNUSED (sasl); BSON_UNUSED (flags); BSON_UNUSED (user_realm); BSON_UNUSED (out_max); TRACE ("Canonicalizing %s (%" PRIu32 ")\n", in, inlen); strcpy (out, in); *out_len = inlen; return SASL_OK; } static int _mongoc_cyrus_get_user (mongoc_cyrus_t *sasl, int param_id, const char **result, unsigned *result_len) { BSON_ASSERT (sasl); BSON_ASSERT ((param_id == SASL_CB_USER) || (param_id == SASL_CB_AUTHNAME)); if (result) { *result = sasl->credentials.user; } if (result_len) { *result_len = sasl->credentials.user ? (unsigned) strlen (sasl->credentials.user) : 0; } return (sasl->credentials.user != NULL) ? SASL_OK : SASL_FAIL; } static const char * sasl_verify_type_to_str (sasl_verify_type_t type) { switch (type) { case SASL_VRFY_PLUGIN: return "SASL_VRFY_PLUGIN"; case SASL_VRFY_CONF: return "SASL_VRFY_CONF"; case SASL_VRFY_PASSWD: return "SASL_VRFY_PASSWD"; case SASL_VRFY_OTHER: return "SASL_VRFY_OTHER"; default: return "Unknown"; } } int _mongoc_cyrus_verifyfile_cb (void *context, const char *file, sasl_verify_type_t type) { BSON_UNUSED (context); TRACE ("Attempting to load file: `%s`. Type is %s\n", file, sasl_verify_type_to_str (type)); #ifdef _WIN32 // On Windows, Cyrus SASL hard-codes the plugin path. // Only permit loading plugin from user configured path to prevent unintentional library loading. if (type == SASL_VRFY_PLUGIN) { const char *path_prefix = MONGOC_CYRUS_PLUGIN_PATH_PREFIX; bool has_valid_prefix = (path_prefix && file == strstr (file, path_prefix)); // Check if `file` has necessary prefix. if (has_valid_prefix) { return SASL_OK; } MONGOC_WARNING ("Refusing to load Cyrus SASL plugin at: '%s'. If needed, set CYRUS_PLUGIN_PATH_PREFIX (currently " "'%s') to the absolute path prefix of the plugin during build configuration of the C Driver.", file, path_prefix ? path_prefix : "(unset)"); return SASL_CONTINUE; } #endif return SASL_OK; } void _mongoc_cyrus_init (mongoc_cyrus_t *sasl) { MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_BEGIN sasl_callback_t callbacks[] = {{SASL_CB_AUTHNAME, SASL_CALLBACK_FN (_mongoc_cyrus_get_user), sasl}, {SASL_CB_USER, SASL_CALLBACK_FN (_mongoc_cyrus_get_user), sasl}, {SASL_CB_PASS, SASL_CALLBACK_FN (_mongoc_cyrus_get_pass), sasl}, {SASL_CB_CANON_USER, SASL_CALLBACK_FN (_mongoc_cyrus_canon_user), sasl}, {SASL_CB_VERIFYFILE, SASL_CALLBACK_FN (_mongoc_cyrus_verifyfile_cb), NULL}, {SASL_CB_LIST_END}}; MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_END BSON_ASSERT (sasl); memset (sasl, 0, sizeof *sasl); memcpy (&sasl->callbacks, callbacks, sizeof callbacks); sasl->done = false; sasl->step = 0; sasl->conn = NULL; sasl->interact = NULL; sasl->credentials.mechanism = NULL; sasl->credentials.user = NULL; sasl->credentials.pass = NULL; sasl->credentials.service_name = NULL; sasl->credentials.service_host = NULL; } bool _mongoc_cyrus_new_from_cluster ( mongoc_cyrus_t *sasl, mongoc_cluster_t *cluster, mongoc_stream_t *stream, const char *hostname, bson_error_t *error) { const char *mechanism; char real_name[BSON_HOST_NAME_MAX + 1]; _mongoc_cyrus_init (sasl); mechanism = mongoc_uri_get_auth_mechanism (cluster->uri); if (!mechanism) { mechanism = "GSSAPI"; } if (!_mongoc_cyrus_set_mechanism (sasl, mechanism, error)) { _mongoc_cyrus_destroy (sasl); return false; } _mongoc_sasl_set_pass ((mongoc_sasl_t *) sasl, mongoc_uri_get_password (cluster->uri)); _mongoc_sasl_set_user ((mongoc_sasl_t *) sasl, mongoc_uri_get_username (cluster->uri)); _mongoc_sasl_set_properties ((mongoc_sasl_t *) sasl, cluster->uri); /* * If the URI requested canonicalizeHostname, we need to resolve the real * hostname for the IP Address and pass that to the SASL layer. Some * underlying GSSAPI layers will do this for us, but can be disabled in * their config (krb.conf). * * This allows the consumer to specify canonicalizeHostname=true in the URI * and have us do that for them. * * See CDRIVER-323 for more information. */ if (sasl->credentials.canonicalize_host_name && _mongoc_sasl_get_canonicalized_name (stream, real_name, sizeof real_name)) { _mongoc_sasl_set_service_host ((mongoc_sasl_t *) sasl, real_name); } else { _mongoc_sasl_set_service_host ((mongoc_sasl_t *) sasl, hostname); } return true; } void _mongoc_cyrus_destroy (mongoc_cyrus_t *sasl) { BSON_ASSERT (sasl); if (sasl->conn) { sasl_dispose (&sasl->conn); } bson_free (sasl->credentials.user); bson_free (sasl->credentials.pass); bson_free (sasl->credentials.mechanism); bson_free (sasl->credentials.service_name); bson_free (sasl->credentials.service_host); } static bool _mongoc_cyrus_is_failure (int status, bson_error_t *error) { bool ret = (status < 0); TRACE ("Got status: %d ok is %d, continue=%d interact=%d\n", status, SASL_OK, SASL_CONTINUE, SASL_INTERACT); if (ret) { switch (status) { case SASL_NOMEM: bson_set_error (error, MONGOC_ERROR_SASL, status, "SASL Failure: insufficient memory."); break; case SASL_NOMECH: { mcommon_string_append_t available_mechs_str; mcommon_string_new_as_append (&available_mechs_str); const char **mechs = sasl_global_listmech (); int i = 0; for (i = 0; mechs[i]; i++) { mcommon_string_append (&available_mechs_str, mechs[i]); if (mechs[i + 1]) { mcommon_string_append (&available_mechs_str, ","); } } bson_set_error (error, MONGOC_ERROR_SASL, status, "SASL Failure: failure to negotiate mechanism (available mechanisms: %s)", mcommon_str_from_append (&available_mechs_str)); mcommon_string_from_append_destroy (&available_mechs_str); } break; case SASL_BADPARAM: bson_set_error (error, MONGOC_ERROR_SASL, status, "Bad parameter supplied. Please file a bug " "with mongo-c-driver."); break; default: bson_set_error ( error, MONGOC_ERROR_SASL, status, "SASL Failure: (%d): %s", status, sasl_errstring (status, NULL, NULL)); break; } } return ret; } static bool _mongoc_cyrus_start (mongoc_cyrus_t *sasl, uint8_t **outbuf, uint32_t *outbuflen, bson_error_t *error) { const char *service_name = "mongodb"; const char *service_host = ""; const char *mechanism = NULL; const char *raw = NULL; unsigned raw_len = 0; int status; BSON_ASSERT (sasl); BSON_ASSERT (outbuf); BSON_ASSERT (outbuflen); if (sasl->credentials.service_name) { service_name = sasl->credentials.service_name; } if (sasl->credentials.service_host) { service_host = sasl->credentials.service_host; } status = sasl_client_new (service_name, service_host, NULL, NULL, sasl->callbacks, 0, &sasl->conn); TRACE ("Created new sasl client %s", status == SASL_OK ? "successfully" : "UNSUCCESSFULLY"); if (_mongoc_cyrus_is_failure (status, error)) { return false; } status = sasl_client_start (sasl->conn, sasl->credentials.mechanism, &sasl->interact, &raw, &raw_len, &mechanism); TRACE ("Started the sasl client %s", status == SASL_CONTINUE ? "successfully" : "UNSUCCESSFULLY"); if (_mongoc_cyrus_is_failure (status, error)) { return false; } if ((0 != strcasecmp (mechanism, "GSSAPI")) && (0 != strcasecmp (mechanism, "PLAIN"))) { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOMECH, "SASL Failure: invalid mechanism \"%s\"", mechanism); return false; } *outbuflen = 0; const size_t outbuf_capacity = mcommon_b64_ntop_calculate_target_size (raw_len); *outbuf = bson_malloc (outbuf_capacity); const int b64_ret = mcommon_b64_ntop ((uint8_t *) raw, raw_len, (char *) *outbuf, outbuf_capacity); if (b64_ret < 0) { bson_set_error ( error, MONGOC_ERROR_SASL, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Unable to base64 encode client SASL message"); return false; } else { BSON_ASSERT (mcommon_in_range_signed (uint32_t, b64_ret)); *outbuflen = (uint32_t) b64_ret; } return true; } bool _mongoc_cyrus_step (mongoc_cyrus_t *sasl, const uint8_t *inbuf, uint32_t inbuflen, uint8_t **outbuf, uint32_t *outbuflen, bson_error_t *error) { const char *raw = NULL; unsigned rawlen = 0; int status; BSON_ASSERT (sasl); if (sasl->step > 1) { BSON_ASSERT (inbuf); } BSON_ASSERT (outbuf); BSON_ASSERT (outbuflen); TRACE ("Running %d, inbuflen: %" PRIu32, sasl->step, inbuflen); sasl->step++; if (sasl->step == 1) { return _mongoc_cyrus_start (sasl, outbuf, outbuflen, error); } else if (sasl->step >= 10) { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOTDONE, "SASL Failure: maximum steps detected"); return false; } TRACE ("Running %d, inbuflen: %" PRIu32, sasl->step, inbuflen); if (!inbuflen) { bson_set_error (error, MONGOC_ERROR_SASL, MONGOC_ERROR_CLIENT_AUTHENTICATE, "SASL Failure: no payload provided from server: %s", sasl_errdetail (sasl->conn)); return false; } unsigned int decoded_len = 0; const size_t decoded_capacity = mcommon_b64_pton_calculate_target_size (inbuflen); char *const decoded = bson_malloc (decoded_capacity); { const int b64_ret = mcommon_b64_pton ((char *) inbuf, (uint8_t *) decoded, decoded_capacity); if (b64_ret < 0) { bson_set_error ( error, MONGOC_ERROR_SASL, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Unable to base64 decode client SASL message"); bson_free (decoded); bson_free (*outbuf); *outbuf = NULL; return false; } else { /* Set the output length to the number of bytes actually decoded to * excluding the NULL. */ decoded_len = (unsigned int) b64_ret; } } TRACE ("%s", "Running client_step"); status = sasl_client_step (sasl->conn, decoded, decoded_len, &sasl->interact, &raw, &rawlen); TRACE ("%s sent a client step", status == SASL_OK ? "Successfully" : "UNSUCCESSFULLY"); if (_mongoc_cyrus_is_failure (status, error)) { bson_free (decoded); return false; } *outbuflen = 0; const size_t outbuf_capacity = mcommon_b64_ntop_calculate_target_size (rawlen); *outbuf = bson_malloc0 (outbuf_capacity); { const int b64_ret = mcommon_b64_ntop ((const uint8_t *) raw, rawlen, (char *) *outbuf, outbuf_capacity); if (b64_ret < 0) { bson_set_error ( error, MONGOC_ERROR_SASL, MONGOC_ERROR_CLIENT_AUTHENTICATE, "Unable to base64 encode client SASL message"); bson_free (decoded); bson_free (*outbuf); *outbuf = NULL; return false; } else { /* Set the output length to the number of characters written excluding * the NULL. */ BSON_ASSERT (mcommon_in_range_signed (uint32_t, b64_ret)); *outbuflen = (uint32_t) b64_ret; } } bson_free (decoded); return true; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-database-private.h0000644000175100001660000000767114760300420024366 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_DATABASE_PRIVATE_H #define MONGOC_DATABASE_PRIVATE_H #include #include #include #include #include BSON_BEGIN_DECLS struct _mongoc_database_t { mongoc_client_t *client; char *name; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; }; mongoc_database_t * _mongoc_database_new (mongoc_client_t *client, const char *name, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern); /* _mongoc_get_encryptedFields_from_map checks the collection has an * encryptedFields set on the client encryptedFieldsMap. * encryptedFields is always initialized on return. */ bool _mongoc_get_encryptedFields_from_map ( mongoc_client_t *client, const char *dbName, const char *collName, bson_t *encryptedFields, bson_error_t *error); /* _mongoc_get_encryptedFields_from_map checks the collection has an * encryptedFields by running listCollections. * encryptedFields is always initialized on return. */ bool _mongoc_get_encryptedFields_from_server ( mongoc_client_t *client, const char *dbName, const char *collName, bson_t *encryptedFields, bson_error_t *error); /** * @brief Look up the encryptedFields to use for the given collection. * * If the collection options contains an encryptedFields, those are returned. * If the client has an encryptedFieldsMap entry for the collection within the * given database, those are returned. If neither, an empty document is * returned. * * @param client The client with which to search an encryptedFieldsMap * @param dbName The name of the database where the collection will/does live * @param collName The name of the collection * @param opts (Optional) The collection options, which may contain the * fields * @param checkEncryptedFieldsMap If false, the encryptedFieldsMap will not be * checked. * @param[out] encryptedFields An output where a view of the encryptedFields * will be written * @param[out] error An error output * @retval true If there was no error * @retval false Otherwise * * @note Upon returning `true`, check whether `*encryptedFields` is empty to * determine whether fields have been found. */ bool _mongoc_get_collection_encryptedFields (mongoc_client_t *client, const char *dbName, const char *collName, const bson_t *opts, bool checkEncryptedFieldsMap, bson_t *encryptedFields, bson_error_t *error); /* _mongoc_get_encryptedField_state_collection returns the state collection * name. Returns NULL on error. */ char * _mongoc_get_encryptedField_state_collection (const bson_t *encryptedFields, const char *data_collection, const char *state_collection_suffix, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_DATABASE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-database.c0000644000175100001660000012124714760300420022705 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "database" /* *-------------------------------------------------------------------------- * * _mongoc_database_new -- * * Create a new instance of mongoc_database_t for @client. * * @client must stay valid for the life of the resulting * database structure. * * Returns: * A newly allocated mongoc_database_t that should be freed with * mongoc_database_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_database_t * _mongoc_database_new (mongoc_client_t *client, const char *name, const mongoc_read_prefs_t *read_prefs, const mongoc_read_concern_t *read_concern, const mongoc_write_concern_t *write_concern) { mongoc_database_t *db; ENTRY; BSON_ASSERT_PARAM (client); BSON_ASSERT_PARAM (name); db = (mongoc_database_t *) bson_malloc0 (sizeof *db); db->client = client; db->write_concern = write_concern ? mongoc_write_concern_copy (write_concern) : mongoc_write_concern_new (); db->read_concern = read_concern ? mongoc_read_concern_copy (read_concern) : mongoc_read_concern_new (); db->read_prefs = read_prefs ? mongoc_read_prefs_copy (read_prefs) : mongoc_read_prefs_new (MONGOC_READ_PRIMARY); db->name = bson_strdup (name); RETURN (db); } /* *-------------------------------------------------------------------------- * * mongoc_database_destroy -- * * Releases resources associated with @database. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ void mongoc_database_destroy (mongoc_database_t *database) { ENTRY; if (!database) { EXIT; } if (database->read_prefs) { mongoc_read_prefs_destroy (database->read_prefs); database->read_prefs = NULL; } if (database->read_concern) { mongoc_read_concern_destroy (database->read_concern); database->read_concern = NULL; } if (database->write_concern) { mongoc_write_concern_destroy (database->write_concern); database->write_concern = NULL; } bson_free (database->name); bson_free (database); EXIT; } mongoc_cursor_t * mongoc_database_aggregate (mongoc_database_t *db, /* IN */ const bson_t *pipeline, /* IN */ const bson_t *opts, /* IN */ const mongoc_read_prefs_t *read_prefs) /* IN */ { return _mongoc_aggregate (db->client, db->name, MONGOC_QUERY_NONE, pipeline, opts, read_prefs, db->read_prefs, db->read_concern, db->write_concern); } /* *-------------------------------------------------------------------------- * * mongoc_database_copy -- * * Returns a copy of @database that needs to be freed by calling * mongoc_database_destroy. * * Returns: * A copy of this database. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_database_t * mongoc_database_copy (mongoc_database_t *database) { ENTRY; BSON_ASSERT_PARAM (database); RETURN (_mongoc_database_new ( database->client, database->name, database->read_prefs, database->read_concern, database->write_concern)); } mongoc_cursor_t * mongoc_database_command (mongoc_database_t *database, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *command, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) { char *ns; mongoc_cursor_t *cursor; BSON_UNUSED (flags); BSON_UNUSED (skip); BSON_UNUSED (limit); BSON_UNUSED (batch_size); BSON_UNUSED (fields); BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (command); ns = bson_strdup_printf ("%s.$cmd", database->name); /* Server Selection Spec: "The generic command method has a default read * preference of mode 'primary'. The generic command method MUST ignore any * default read preference from client, database or collection * configuration. The generic command method SHOULD allow an optional read * preference argument." */ /* flags, skip, limit, batch_size, fields are unused */ cursor = _mongoc_cursor_cmd_deprecated_new (database->client, ns, command, read_prefs); bson_free (ns); return cursor; } bool mongoc_database_command_simple (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error) { BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (command); /* Server Selection Spec: "The generic command method has a default read * preference of mode 'primary'. The generic command method MUST ignore any * default read preference from client, database or collection * configuration. The generic command method SHOULD allow an optional read * preference argument." */ return _mongoc_client_command_with_opts (database->client, database->name, command, MONGOC_CMD_RAW, NULL /* opts */, MONGOC_QUERY_NONE, read_prefs, NULL, /* user prefs */ NULL /* read concern */, NULL /* write concern */, reply, error); } bool mongoc_database_read_command_with_opts (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error) { return _mongoc_client_command_with_opts (database->client, database->name, command, MONGOC_CMD_READ, opts, MONGOC_QUERY_NONE, read_prefs, database->read_prefs, database->read_concern, database->write_concern, reply, error); } bool mongoc_database_write_command_with_opts ( mongoc_database_t *database, const bson_t *command, const bson_t *opts, bson_t *reply, bson_error_t *error) { return _mongoc_client_command_with_opts (database->client, database->name, command, MONGOC_CMD_WRITE, opts, MONGOC_QUERY_NONE, NULL, /* user prefs */ database->read_prefs, database->read_concern, database->write_concern, reply, error); } bool mongoc_database_read_write_command_with_opts (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs /* IGNORED */, const bson_t *opts, bson_t *reply, bson_error_t *error) { return _mongoc_client_command_with_opts (database->client, database->name, command, MONGOC_CMD_RW, opts, MONGOC_QUERY_NONE, read_prefs, database->read_prefs, database->read_concern, database->write_concern, reply, error); } bool mongoc_database_command_with_opts (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error) { return _mongoc_client_command_with_opts (database->client, database->name, command, MONGOC_CMD_RAW, opts, MONGOC_QUERY_NONE, read_prefs, NULL, /* default prefs */ database->read_concern, database->write_concern, reply, error); } /* *-------------------------------------------------------------------------- * * mongoc_database_drop -- * * Requests that the MongoDB server drops @database, including all * collections and indexes associated with @database. * * Make sure this is really what you want! * * Returns: * true if @database was dropped. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ bool mongoc_database_drop (mongoc_database_t *database, bson_error_t *error) { return mongoc_database_drop_with_opts (database, NULL, error); } bool mongoc_database_drop_with_opts (mongoc_database_t *database, const bson_t *opts, bson_error_t *error) { bool ret; bson_t cmd; BSON_ASSERT_PARAM (database); bson_init (&cmd); bson_append_int32 (&cmd, "dropDatabase", 12, 1); ret = _mongoc_client_command_with_opts (database->client, database->name, &cmd, MONGOC_CMD_WRITE, opts, MONGOC_QUERY_NONE, NULL, /* user prefs */ database->read_prefs, database->read_concern, database->write_concern, NULL, /* reply */ error); bson_destroy (&cmd); return ret; } bool mongoc_database_remove_user (mongoc_database_t *database, const char *username, bson_error_t *error) { bson_t cmd; bool ret; ENTRY; BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (username); bson_init (&cmd); BSON_APPEND_UTF8 (&cmd, "dropUser", username); ret = mongoc_database_command_simple (database, &cmd, NULL, NULL, error); bson_destroy (&cmd); RETURN (ret); } bool mongoc_database_remove_all_users (mongoc_database_t *database, bson_error_t *error) { bson_t cmd; bool ret; ENTRY; BSON_ASSERT_PARAM (database); bson_init (&cmd); BSON_APPEND_INT32 (&cmd, "dropAllUsersFromDatabase", 1); ret = mongoc_database_command_simple (database, &cmd, NULL, NULL, error); bson_destroy (&cmd); RETURN (ret); } /** * mongoc_database_add_user: * @database: A #mongoc_database_t. * @username: A string containing the username. * @password: (allow-none): A string containing password, or NULL. * @roles: (allow-none): An optional bson_t of roles. * @custom_data: (allow-none): An optional bson_t of data to store. * @error: (out) (allow-none): A location for a bson_error_t or %NULL. * * Creates a new user with access to @database. * * Returns: None. * Side effects: None. */ bool mongoc_database_add_user (mongoc_database_t *database, const char *username, const char *password, const bson_t *roles, const bson_t *custom_data, bson_error_t *error) { bson_t cmd; bson_array_builder_t *ar; bool ret = false; ENTRY; BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (username); bson_init (&cmd); BSON_APPEND_UTF8 (&cmd, "createUser", username); BSON_APPEND_UTF8 (&cmd, "pwd", password); if (custom_data) { BSON_APPEND_DOCUMENT (&cmd, "customData", custom_data); } if (roles) { BSON_APPEND_ARRAY (&cmd, "roles", roles); } else { bson_append_array_builder_begin (&cmd, "roles", 5, &ar); bson_append_array_builder_end (&cmd, ar); } ret = mongoc_database_command_simple (database, &cmd, NULL, NULL, error); bson_destroy (&cmd); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_database_get_read_prefs -- * * Fetch the read preferences for @database. * * Returns: * A mongoc_read_prefs_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_prefs_t * mongoc_database_get_read_prefs (const mongoc_database_t *database) /* IN */ { BSON_ASSERT_PARAM (database); return database->read_prefs; } /* *-------------------------------------------------------------------------- * * mongoc_database_set_read_prefs -- * * Sets the default read preferences for @database. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_database_set_read_prefs (mongoc_database_t *database, const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT_PARAM (database); if (database->read_prefs) { mongoc_read_prefs_destroy (database->read_prefs); database->read_prefs = NULL; } if (read_prefs) { database->read_prefs = mongoc_read_prefs_copy (read_prefs); } } /* *-------------------------------------------------------------------------- * * mongoc_database_get_read_concern -- * * Fetches the read concern for @database. * * Returns: * A mongoc_read_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_read_concern_t * mongoc_database_get_read_concern (const mongoc_database_t *database) { BSON_ASSERT_PARAM (database); return database->read_concern; } /* *-------------------------------------------------------------------------- * * mongoc_database_set_read_concern -- * * Set the default read concern for @database. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_database_set_read_concern (mongoc_database_t *database, const mongoc_read_concern_t *read_concern) { BSON_ASSERT_PARAM (database); if (database->read_concern) { mongoc_read_concern_destroy (database->read_concern); database->read_concern = NULL; } if (read_concern) { database->read_concern = mongoc_read_concern_copy (read_concern); } } /* *-------------------------------------------------------------------------- * * mongoc_database_get_write_concern -- * * Fetches the write concern for @database. * * Returns: * A mongoc_write_concern_t that should not be modified or freed. * * Side effects: * None. * *-------------------------------------------------------------------------- */ const mongoc_write_concern_t * mongoc_database_get_write_concern (const mongoc_database_t *database) { BSON_ASSERT_PARAM (database); return database->write_concern; } /* *-------------------------------------------------------------------------- * * mongoc_database_set_write_concern -- * * Set the default write concern for @database. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_database_set_write_concern (mongoc_database_t *database, const mongoc_write_concern_t *write_concern) { BSON_ASSERT_PARAM (database); if (database->write_concern) { mongoc_write_concern_destroy (database->write_concern); database->write_concern = NULL; } if (write_concern) { database->write_concern = mongoc_write_concern_copy (write_concern); } } /** * mongoc_database_has_collection: * @database: (in): A #mongoc_database_t. * @name: (in): The name of the collection to check for. * @error: (out) (allow-none): A location for a #bson_error_t, or %NULL. * * Checks to see if a collection exists within the database on the MongoDB * server. * * This will return %false if their was an error communicating with the * server, or if the collection does not exist. * * If @error is provided, it will first be zeroed. Upon error, error.domain * will be set. * * Returns: %true if @name exists, otherwise %false. @error may be set. */ bool mongoc_database_has_collection (mongoc_database_t *database, const char *name, bson_error_t *error) { bson_iter_t col_iter; bool ret = false; const char *cur_name; bson_t opts = BSON_INITIALIZER; bson_t filter; mongoc_cursor_t *cursor; const bson_t *doc; ENTRY; BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (name); if (error) { memset (error, 0, sizeof *error); } BSON_APPEND_DOCUMENT_BEGIN (&opts, "filter", &filter); BSON_APPEND_UTF8 (&filter, "name", name); bson_append_document_end (&opts, &filter); cursor = mongoc_database_find_collections_with_opts (database, &opts); while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init (&col_iter, doc) && bson_iter_find (&col_iter, "name") && BSON_ITER_HOLDS_UTF8 (&col_iter) && (cur_name = bson_iter_utf8 (&col_iter, NULL))) { if (!strcmp (cur_name, name)) { ret = true; GOTO (cleanup); } } } (void) mongoc_cursor_error (cursor, error); cleanup: mongoc_cursor_destroy (cursor); bson_destroy (&opts); RETURN (ret); } mongoc_cursor_t * mongoc_database_find_collections (mongoc_database_t *database, const bson_t *filter, bson_error_t *error) { bson_t opts = BSON_INITIALIZER; mongoc_cursor_t *cursor; BSON_ASSERT_PARAM (database); if (filter) { if (!BSON_APPEND_DOCUMENT (&opts, "filter", filter)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'filter' parameter."); bson_destroy (&opts); return NULL; } } cursor = mongoc_database_find_collections_with_opts (database, &opts); bson_destroy (&opts); /* this deprecated API returns NULL on error */ if (mongoc_cursor_error (cursor, error)) { mongoc_cursor_destroy (cursor); return NULL; } return cursor; } mongoc_cursor_t * mongoc_database_find_collections_with_opts (mongoc_database_t *database, const bson_t *opts) { mongoc_cursor_t *cursor; bson_t cmd = BSON_INITIALIZER; BSON_ASSERT_PARAM (database); BSON_APPEND_INT32 (&cmd, "listCollections", 1); /* Enumerate Collections Spec: "run listCollections on the primary node in * replicaset mode" */ cursor = _mongoc_cursor_cmd_new (database->client, database->name, &cmd, opts, NULL, NULL, NULL); if (cursor->error.domain == 0) { _mongoc_cursor_prime (cursor); } bson_destroy (&cmd); return cursor; } char ** mongoc_database_get_collection_names (mongoc_database_t *database, bson_error_t *error) { return mongoc_database_get_collection_names_with_opts (database, NULL, error); } char ** mongoc_database_get_collection_names_with_opts (mongoc_database_t *database, const bson_t *opts, bson_error_t *error) { bson_t opts_copy; bson_iter_t col; const char *name; char *namecopy; mongoc_array_t strv_buf; mongoc_cursor_t *cursor; const bson_t *doc; char **ret; BSON_ASSERT_PARAM (database); if (opts) { bson_copy_to (opts, &opts_copy); } else { bson_init (&opts_copy); } /* nameOnly option is faster in MongoDB 4+, ignored by older versions, * see Enumerating Collections Spec */ if (!bson_has_field (&opts_copy, "nameOnly")) { bson_append_bool (&opts_copy, "nameOnly", 8, true); } cursor = mongoc_database_find_collections_with_opts (database, &opts_copy); _mongoc_array_init (&strv_buf, sizeof (char *)); while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init (&col, doc) && bson_iter_find (&col, "name") && BSON_ITER_HOLDS_UTF8 (&col) && (name = bson_iter_utf8 (&col, NULL))) { namecopy = bson_strdup (name); _mongoc_array_append_val (&strv_buf, namecopy); } } /* append a null pointer for the last value. also handles the case * of no values. */ namecopy = NULL; _mongoc_array_append_val (&strv_buf, namecopy); if (mongoc_cursor_error (cursor, error)) { _mongoc_array_destroy (&strv_buf); ret = NULL; } else { ret = (char **) strv_buf.data; } mongoc_cursor_destroy (cursor); bson_destroy (&opts_copy); return ret; } static mongoc_collection_t * create_collection (mongoc_database_t *database, const char *name, const bson_t *opts, bson_error_t *error) { mongoc_collection_t *collection = NULL; bson_iter_t iter; bson_t cmd; bool capped = false; BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (name); if (strchr (name, '$')) { bson_set_error ( error, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_NAMESPACE_INVALID, "The namespace \"%s\" is invalid.", name); return NULL; } if (opts) { if (bson_iter_init_find (&iter, opts, "capped")) { if (!BSON_ITER_HOLDS_BOOL (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The argument \"capped\" must be a boolean."); return NULL; } capped = bson_iter_bool (&iter); } if (bson_iter_init_find (&iter, opts, "size")) { if (!BSON_ITER_HOLDS_INT (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The argument \"size\" must be an integer."); return NULL; } if (!capped) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"size\" parameter requires {\"capped\": true}"); return NULL; } } if (bson_iter_init_find (&iter, opts, "max")) { if (!BSON_ITER_HOLDS_INT (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The argument \"max\" must be an integer."); return NULL; } if (!capped) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"max\" parameter requires {\"capped\": true}"); return NULL; } } if (bson_iter_init_find (&iter, opts, "storageEngine")) { if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"storageEngine\" parameter must be a document"); return NULL; } if (bson_iter_find (&iter, "wiredTiger")) { if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"wiredTiger\" option must take a document " "argument with a \"configString\" field"); return NULL; } if (bson_iter_find (&iter, "configString")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"configString\" parameter must be a string"); return NULL; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The \"wiredTiger\" option must take a document " "argument with a \"configString\" field"); return NULL; } } } } bson_init (&cmd); BSON_APPEND_UTF8 (&cmd, "create", name); if (_mongoc_client_command_with_opts (database->client, database->name, &cmd, MONGOC_CMD_WRITE, opts, MONGOC_QUERY_NONE, NULL, /* user prefs */ database->read_prefs, database->read_concern, database->write_concern, NULL, /* reply */ error)) { collection = _mongoc_collection_new ( database->client, database->name, name, database->read_prefs, database->read_concern, database->write_concern); } bson_destroy (&cmd); return collection; } char * _mongoc_get_encryptedField_state_collection (const bson_t *encryptedFields, const char *data_collection, const char *state_collection_suffix, bson_error_t *error) { bson_iter_t iter; const char *fieldName = NULL; if (0 == strcmp (state_collection_suffix, "esc")) { fieldName = "escCollection"; } else if (0 == strcmp (state_collection_suffix, "ecoc")) { fieldName = "ecocCollection"; } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected state_collection_suffix to be 'esc' or " "'ecoc', got: %s", state_collection_suffix); return NULL; } if (bson_iter_init_find (&iter, encryptedFields, fieldName)) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected encryptedFields.%s to be UTF-8", fieldName); return NULL; } return bson_strdup (bson_iter_utf8 (&iter, NULL)); } return bson_strdup_printf ("enxcol_.%s.%s", data_collection, state_collection_suffix); } static bool create_encField_state_collection (mongoc_database_t *database, const bson_t *encryptedFields, const char *data_collection, const char *state_collection_suffix, bson_error_t *error) { char *state_collection = NULL; mongoc_collection_t *collection = NULL; bool ok = false; bson_t opts = BSON_INITIALIZER; state_collection = _mongoc_get_encryptedField_state_collection (encryptedFields, data_collection, state_collection_suffix, error); if (!state_collection) { goto fail; } BCON_APPEND (&opts, "clusteredIndex", "{", "key", "{", "_id", BCON_INT32 (1), "}", "unique", BCON_BOOL (true), "}"); collection = create_collection (database, state_collection, &opts, error); if (collection == NULL) { goto fail; } ok = true; fail: bson_free (state_collection); mongoc_collection_destroy (collection); bson_destroy (&opts); return ok; } static mongoc_collection_t * create_collection_with_encryptedFields (mongoc_database_t *database, const char *name, const bson_t *opts, const bson_t *encryptedFields, bson_error_t *error) { mongoc_collection_t *dataCollection = NULL; bool ok = false; bson_t *cc_opts = NULL; // Check the wire version to ensure server is 7.0.0 or newer. { const mongoc_ss_log_context_t ss_log_context = {.operation = "createCollection"}; mongoc_server_stream_t *stream = mongoc_cluster_stream_for_writes (&database->client->cluster, &ss_log_context, NULL /* client session */, NULL /* deprioritized servers */, NULL /* reply */, error); if (!stream) { goto fail; } if (stream->sd->max_wire_version < WIRE_VERSION_7_0) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "Driver support of Queryable Encryption is incompatible " "with server. Upgrade server to use Queryable Encryption. " "Got maxWireVersion %" PRId32 " but need maxWireVersion >= %d", stream->sd->max_wire_version, WIRE_VERSION_7_0); mongoc_server_stream_cleanup (stream); goto fail; } mongoc_server_stream_cleanup (stream); } bool state_collections_ok = create_encField_state_collection (database, encryptedFields, name, "esc", error) && create_encField_state_collection (database, encryptedFields, name, "ecoc", error); if (!state_collections_ok) { // Failed to create one or more state collections goto fail; } /* Create data collection. */ cc_opts = bson_copy (opts); if (!BSON_APPEND_DOCUMENT (cc_opts, "encryptedFields", encryptedFields)) { bson_set_error ( error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "unable to append encryptedFields"); goto fail; } dataCollection = create_collection (database, name, cc_opts, error); if (!dataCollection) { goto fail; } /* Create index on __safeContent__. */ { bson_t *keys = BCON_NEW ("__safeContent__", BCON_INT32 (1)); mongoc_index_model_t *im = mongoc_index_model_new (keys, NULL /* opts */); ok = mongoc_collection_create_indexes_with_opts (dataCollection, &im, 1, NULL /* opts */, NULL /* reply */, error); mongoc_index_model_destroy (im); bson_destroy (keys); if (!ok) { goto fail; } } ok = true; fail: bson_destroy (cc_opts); if (ok) { return dataCollection; } else { mongoc_collection_destroy (dataCollection); return NULL; } } bool _mongoc_get_encryptedFields_from_map ( mongoc_client_t *client, const char *dbName, const char *collName, bson_t *encryptedFields, bson_error_t *error) { BSON_ASSERT_PARAM (client); const bson_t *efMap = client->topology->encrypted_fields_map; bson_init (encryptedFields); if (bson_empty0 (efMap)) { /* Unset or empty efMap will have no encrypted fields */ return true; } char *ns = bson_strdup_printf ("%s.%s", dbName, collName); bson_iter_t iter; if (!bson_iter_init_find (&iter, efMap, ns)) { /* No efMap entry for this database+collection. */ bson_free (ns); return true; } bson_free (ns); if (!_mongoc_iter_document_as_bson (&iter, encryptedFields, error)) { /* The efMap entry should always be a document. */ return false; } return true; } bool _mongoc_get_encryptedFields_from_server ( mongoc_client_t *client, const char *dbName, const char *collName, bson_t *encryptedFields, bson_error_t *error) { BSON_ASSERT_PARAM (client); mongoc_database_t *db = mongoc_client_get_database (client, dbName); bson_t *opts = BCON_NEW ("filter", "{", "name", BCON_UTF8 (collName), "}"); mongoc_cursor_t *cursor; bool ret = false; const bson_t *collInfo; bson_init (encryptedFields); cursor = mongoc_database_find_collections_with_opts (db, opts); if (mongoc_cursor_error (cursor, error)) { goto fail; } if (mongoc_cursor_next (cursor, &collInfo)) { /* Check if the collInfo has options.encryptedFields. */ bson_iter_t iter; if (!bson_iter_init (&iter, collInfo)) { bson_set_error ( error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "unable to iterate listCollections result"); goto fail; } if (bson_iter_find_descendant (&iter, "options.encryptedFields", &iter)) { bson_t tmp; if (!_mongoc_iter_document_as_bson (&iter, &tmp, error)) { goto fail; } bson_copy_to (&tmp, encryptedFields); } } if (mongoc_cursor_error (cursor, error)) { goto fail; } ret = true; fail: mongoc_cursor_destroy (cursor); bson_destroy (opts); mongoc_database_destroy (db); return ret; } bool _mongoc_get_collection_encryptedFields (mongoc_client_t *client, const char *dbName, const char *collName, const bson_t *opts, bool checkEncryptedFieldsMap, bson_t *encryptedFields, bson_error_t *error) { BSON_ASSERT_PARAM (client); BSON_ASSERT_PARAM (dbName); BSON_ASSERT_PARAM (collName); BSON_OPTIONAL_PARAM (opts); BSON_ASSERT_PARAM (encryptedFields); BSON_OPTIONAL_PARAM (error); bson_init (encryptedFields); // Initially empty if (opts) { // We have collection options, which may have encryptedFields in it bool found = false; bsonParse (*opts, find (key ("encryptedFields"), if (not(type (doc)), then (error ("'encryptedFields' should be a document"))), // Update encryptedFields to be a reference to the subdocument: storeDocRef (*encryptedFields), do (found = true))); if (bsonParseError) { // Error while parsing bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid createCollection command options: %s", bsonParseError); return false; } else if (found) { // Found it! return true; } else { // Nothing found in the options } } // Look in the encryptedFieldsMap based on this collection name if (checkEncryptedFieldsMap && !_mongoc_get_encryptedFields_from_map (client, dbName, collName, encryptedFields, error)) { // Error during lookup. return false; } // No error. We may or may not have found encryptedFields. The caller // determines this by checking if encryptedFields is empty. return true; } mongoc_collection_t * mongoc_database_create_collection (mongoc_database_t *database, const char *name, const bson_t *opts, bson_error_t *error) { BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (name); BSON_OPTIONAL_PARAM (opts); BSON_OPTIONAL_PARAM (error); bson_t encryptedFields = BSON_INITIALIZER; if (!_mongoc_get_collection_encryptedFields (database->client, mongoc_database_get_name (database), name, opts, true /* checkEncryptedFieldsMap */, &encryptedFields, error)) { // Error during fields lookup bson_destroy (&encryptedFields); return NULL; } if (!bson_empty (&encryptedFields)) { // Clone 'opts' without the encryptedFields element bsonBuildDecl (opts_without_encryptedFields, if (opts, then (insert (*opts, not(key ("encryptedFields")))))); mongoc_collection_t *ret = create_collection_with_encryptedFields ( database, name, &opts_without_encryptedFields, &encryptedFields, error); bson_destroy (&encryptedFields); bson_destroy (&opts_without_encryptedFields); return ret; } bson_destroy (&encryptedFields); return create_collection (database, name, opts, error); } mongoc_collection_t * mongoc_database_get_collection (mongoc_database_t *database, const char *collection) { BSON_ASSERT_PARAM (database); BSON_ASSERT_PARAM (collection); return _mongoc_collection_new (database->client, database->name, collection, database->read_prefs, database->read_concern, database->write_concern); } const char * mongoc_database_get_name (mongoc_database_t *database) { BSON_ASSERT_PARAM (database); return database->name; } mongoc_change_stream_t * mongoc_database_watch (const mongoc_database_t *db, const bson_t *pipeline, const bson_t *opts) { return _mongoc_change_stream_new_from_database (db, pipeline, opts); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-database.h0000644000175100001660000001574414760300420022716 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_DATABASE_H #define MONGOC_DATABASE_H #include #include #include #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_database_t mongoc_database_t; MONGOC_EXPORT (const char *) mongoc_database_get_name (mongoc_database_t *database); MONGOC_EXPORT (bool) mongoc_database_remove_user (mongoc_database_t *database, const char *username, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_remove_all_users (mongoc_database_t *database, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_add_user (mongoc_database_t *database, const char *username, const char *password, const bson_t *roles, const bson_t *custom_data, bson_error_t *error); MONGOC_EXPORT (void) mongoc_database_destroy (mongoc_database_t *database); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_database_aggregate (mongoc_database_t *db, const bson_t *pipeline, const bson_t *opts, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_database_t *) mongoc_database_copy (mongoc_database_t *database) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_cursor_t *) mongoc_database_command (mongoc_database_t *database, mongoc_query_flags_t flags, uint32_t skip, uint32_t limit, uint32_t batch_size, const bson_t *command, const bson_t *fields, const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_database_command_simple); MONGOC_EXPORT (bool) mongoc_database_read_command_with_opts (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_write_command_with_opts ( mongoc_database_t *database, const bson_t *command, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_read_write_command_with_opts (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs /* IGNORED */, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_command_with_opts (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs, const bson_t *opts, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_command_simple (mongoc_database_t *database, const bson_t *command, const mongoc_read_prefs_t *read_prefs, bson_t *reply, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_drop (mongoc_database_t *database, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_drop_with_opts (mongoc_database_t *database, const bson_t *opts, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_database_has_collection (mongoc_database_t *database, const char *name, bson_error_t *error); MONGOC_EXPORT (mongoc_collection_t *) mongoc_database_create_collection (mongoc_database_t *database, const char *name, const bson_t *options, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (const mongoc_read_prefs_t *) mongoc_database_get_read_prefs (const mongoc_database_t *database); MONGOC_EXPORT (void) mongoc_database_set_read_prefs (mongoc_database_t *database, const mongoc_read_prefs_t *read_prefs); MONGOC_EXPORT (const mongoc_write_concern_t *) mongoc_database_get_write_concern (const mongoc_database_t *database); MONGOC_EXPORT (void) mongoc_database_set_write_concern (mongoc_database_t *database, const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (const mongoc_read_concern_t *) mongoc_database_get_read_concern (const mongoc_database_t *database); MONGOC_EXPORT (void) mongoc_database_set_read_concern (mongoc_database_t *database, const mongoc_read_concern_t *read_concern); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_database_find_collections (mongoc_database_t *database, const bson_t *filter, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_database_find_collections_with_opts); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_database_find_collections_with_opts (mongoc_database_t *database, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (char **) mongoc_database_get_collection_names (mongoc_database_t *database, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_database_get_collection_names_with_opts); MONGOC_EXPORT (char **) mongoc_database_get_collection_names_with_opts (mongoc_database_t *database, const bson_t *opts, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_collection_t *) mongoc_database_get_collection (mongoc_database_t *database, const char *name) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_change_stream_t *) mongoc_database_watch (const mongoc_database_t *db, const bson_t *pipeline, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_DATABASE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-deprioritized-servers-private.h0000644000175100001660000000255614760300420027163 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_DEPRIORITIZED_SERVERS_PRIVATE_H #define MONGOC_DEPRIORITIZED_SERVERS_PRIVATE_H #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_deprioritized_servers_t mongoc_deprioritized_servers_t; mongoc_deprioritized_servers_t * mongoc_deprioritized_servers_new (void); void mongoc_deprioritized_servers_destroy (mongoc_deprioritized_servers_t *ds); void mongoc_deprioritized_servers_add (mongoc_deprioritized_servers_t *ds, const mongoc_server_description_t *sd); bool mongoc_deprioritized_servers_contains (const mongoc_deprioritized_servers_t *ds, const mongoc_server_description_t *sd); BSON_END_DECLS #endif // MONGOC_DEPRIORITIZED_SERVERS_PRIVATE_H mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-deprioritized-servers.c0000644000175100001660000000264414760300420025504 0ustar #include #include // Dedicated non-zero value to avoid confusing "key is present with a NULL item" // from "key is not present" (also NULL). #define MONGOC_DEPRIORITIZED_SERVERS_ITEM_VALUE ((void *) 1) struct _mongoc_deprioritized_servers_t { // Use server ID (uint32_t) as keys to identify deprioritized servers. mongoc_set_t *ids; }; mongoc_deprioritized_servers_t * mongoc_deprioritized_servers_new (void) { mongoc_deprioritized_servers_t *const ret = bson_malloc (sizeof (*ret)); *ret = (mongoc_deprioritized_servers_t){ .ids = mongoc_set_new (1u, NULL, NULL), }; return ret; } void mongoc_deprioritized_servers_destroy (mongoc_deprioritized_servers_t *ds) { if (!ds) { return; } mongoc_set_destroy (ds->ids); bson_free (ds); } void mongoc_deprioritized_servers_add (mongoc_deprioritized_servers_t *ds, const mongoc_server_description_t *sd) { BSON_ASSERT_PARAM (ds); BSON_ASSERT_PARAM (sd); mongoc_set_add (ds->ids, mongoc_server_description_id (sd), MONGOC_DEPRIORITIZED_SERVERS_ITEM_VALUE); } bool mongoc_deprioritized_servers_contains (const mongoc_deprioritized_servers_t *ds, const mongoc_server_description_t *sd) { BSON_ASSERT_PARAM (ds); BSON_ASSERT_PARAM (sd); return mongoc_set_get_const (ds->ids, mongoc_server_description_id (sd)) == MONGOC_DEPRIORITIZED_SERVERS_ITEM_VALUE; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-errno-private.h0000644000175100001660000000241514760300420023736 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_ERRNO_PRIVATE_H #define MONGOC_ERRNO_PRIVATE_H #include #include #ifdef _WIN32 #include #include #endif BSON_BEGIN_DECLS #if defined(_WIN32) #define MONGOC_ERRNO_IS_AGAIN(errno) ((errno == EAGAIN) || (errno == WSAEWOULDBLOCK) || (errno == WSAEINPROGRESS)) #define MONGOC_ERRNO_IS_TIMEDOUT(errno) (errno == WSAETIMEDOUT) #else #define MONGOC_ERRNO_IS_AGAIN(errno) \ ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS)) #define MONGOC_ERRNO_IS_TIMEDOUT(errno) (errno == ETIMEDOUT) #endif BSON_END_DECLS #endif /* MONGOC_ERRNO_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-error-private.h0000644000175100001660000000676314760300420023754 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_ERROR_PRIVATE_H #define MONGOC_ERROR_PRIVATE_H #include #include #include BSON_BEGIN_DECLS typedef enum { MONGOC_READ_ERR_NONE, MONGOC_READ_ERR_OTHER, MONGOC_READ_ERR_RETRY } mongoc_read_err_type_t; /* Server error codes libmongoc cares about. Compare with: * https://github.com/mongodb/mongo/blob/master/src/mongo/base/error_codes.yml */ typedef enum { MONGOC_SERVER_ERR_HOSTUNREACHABLE = 6, MONGOC_SERVER_ERR_HOSTNOTFOUND = 7, MONGOC_SERVER_ERR_CURSOR_NOT_FOUND = 43, MONGOC_SERVER_ERR_STALESHARDVERSION = 63, MONGOC_SERVER_ERR_NETWORKTIMEOUT = 89, MONGOC_SERVER_ERR_SHUTDOWNINPROGRESS = 91, MONGOC_SERVER_ERR_FAILEDTOSATISFYREADPREFERENCE = 133, MONGOC_SERVER_ERR_READCONCERNMAJORITYNOTAVAILABLEYET = 134, MONGOC_SERVER_ERR_STALEEPOCH = 150, MONGOC_SERVER_ERR_PRIMARYSTEPPEDDOWN = 189, MONGOC_SERVER_ERR_ELECTIONINPROGRESS = 216, MONGOC_SERVER_ERR_RETRYCHANGESTREAM = 234, MONGOC_SERVER_ERR_EXCEEDEDTIMELIMIT = 262, MONGOC_SERVER_ERR_SOCKETEXCEPTION = 9001, MONGOC_SERVER_ERR_NOTPRIMARY = 10107, MONGOC_SERVER_ERR_INTERRUPTEDATSHUTDOWN = 11600, MONGOC_SERVER_ERR_INTERRUPTEDDUETOREPLSTATECHANGE = 11602, MONGOC_SERVER_ERR_STALECONFIG = 13388, MONGOC_SERVER_ERR_NOTPRIMARYNOSECONDARYOK = 13435, MONGOC_SERVER_ERR_NOTPRIMARYORSECONDARY = 13436, MONGOC_SERVER_ERR_LEGACYNOTPRIMARY = 10058, MONGOC_SERVER_ERR_NS_NOT_FOUND = 26 } mongoc_server_err_t; mongoc_read_err_type_t _mongoc_read_error_get_type (bool cmd_ret, const bson_error_t *cmd_err, const bson_t *reply); void _mongoc_error_copy_labels_and_upsert (const bson_t *src, bson_t *dst, char *label); void _mongoc_write_error_append_retryable_label (bson_t *reply); void _mongoc_write_error_handle_labels (bool cmd_ret, const bson_error_t *cmd_err, bson_t *reply, const mongoc_server_description_t *sd); bool _mongoc_error_is_shutdown (bson_error_t *error); bool _mongoc_error_is_recovering (bson_error_t *error); bool _mongoc_error_is_not_primary (bson_error_t *error); bool _mongoc_error_is_state_change (bson_error_t *error); bool _mongoc_error_is_network (const bson_error_t *error); bool _mongoc_error_is_server (const bson_error_t *error); bool _mongoc_error_is_auth (const bson_error_t *error); /* Try to append `s` to `error`. Truncates `s` if `error` is out of space. */ void _mongoc_error_append (bson_error_t *error, const char *s); typedef enum { MONGOC_ERROR_CONTENT_FLAG_CODE = (1 << 0), MONGOC_ERROR_CONTENT_FLAG_DOMAIN = (1 << 1), MONGOC_ERROR_CONTENT_FLAG_MESSAGE = (1 << 2), } mongoc_error_content_flags_t; bool mongoc_error_append_contents_to_bson (const bson_error_t *error, bson_t *bson, mongoc_error_content_flags_t flags); BSON_END_DECLS #endif /* MONGOC_ERROR_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-error.c0000644000175100001660000002367314760300420022276 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include bool mongoc_error_has_label (const bson_t *reply, const char *label) { bson_iter_t iter; bson_iter_t error_labels; BSON_ASSERT (reply); BSON_ASSERT (label); if (bson_iter_init_find (&iter, reply, "errorLabels") && bson_iter_recurse (&iter, &error_labels)) { while (bson_iter_next (&error_labels)) { if (BSON_ITER_HOLDS_UTF8 (&error_labels) && !strcmp (bson_iter_utf8 (&error_labels, NULL), label)) { return true; } } } return false; } bool _mongoc_error_is_server (const bson_error_t *error) { if (!error) { return false; } return error->domain == MONGOC_ERROR_SERVER || error->domain == MONGOC_ERROR_WRITE_CONCERN; } static bool _mongoc_write_error_is_retryable (bson_error_t *error) { if (!_mongoc_error_is_server (error)) { return false; } switch (error->code) { case MONGOC_SERVER_ERR_HOSTUNREACHABLE: case MONGOC_SERVER_ERR_HOSTNOTFOUND: case MONGOC_SERVER_ERR_NETWORKTIMEOUT: case MONGOC_SERVER_ERR_SHUTDOWNINPROGRESS: case MONGOC_SERVER_ERR_PRIMARYSTEPPEDDOWN: case MONGOC_SERVER_ERR_EXCEEDEDTIMELIMIT: case MONGOC_SERVER_ERR_SOCKETEXCEPTION: case MONGOC_SERVER_ERR_NOTPRIMARY: case MONGOC_SERVER_ERR_INTERRUPTEDATSHUTDOWN: case MONGOC_SERVER_ERR_INTERRUPTEDDUETOREPLSTATECHANGE: case MONGOC_SERVER_ERR_NOTPRIMARYNOSECONDARYOK: case MONGOC_SERVER_ERR_NOTPRIMARYORSECONDARY: return true; default: return false; } } void _mongoc_write_error_append_retryable_label (bson_t *reply) { bson_t reply_local = BSON_INITIALIZER; if (!reply) { bson_destroy (&reply_local); return; } bson_copy_to_excluding_noinit (reply, &reply_local, "errorLabels", NULL); _mongoc_error_copy_labels_and_upsert (reply, &reply_local, RETRYABLE_WRITE_ERROR); bson_destroy (reply); bson_steal (reply, &reply_local); } void _mongoc_write_error_handle_labels (bool cmd_ret, const bson_error_t *cmd_err, bson_t *reply, const mongoc_server_description_t *sd) { bson_error_t error; /* check for a client error. */ if (!cmd_ret && _mongoc_error_is_network (cmd_err)) { /* Retryable writes spec: When the driver encounters a network error * communicating with any server version that supports retryable * writes, it MUST add a RetryableWriteError label to that error. */ _mongoc_write_error_append_retryable_label (reply); return; } if (sd->max_wire_version >= WIRE_VERSION_RETRYABLE_WRITE_ERROR_LABEL) { return; } /* Check for a server error. Do not consult writeConcernError for pre-4.4 * mongos. */ if (sd->type == MONGOC_SERVER_MONGOS) { if (_mongoc_cmd_check_ok (reply, MONGOC_ERROR_API_VERSION_2, &error)) { return; } } else { if (_mongoc_cmd_check_ok_no_wce (reply, MONGOC_ERROR_API_VERSION_2, &error)) { return; } } if (_mongoc_write_error_is_retryable (&error)) { _mongoc_write_error_append_retryable_label (reply); } } /*-------------------------------------------------------------------------- * * _mongoc_read_error_get_type -- * * Checks if the error or reply from a read command is considered * retryable according to the retryable reads spec. Checks both * for a client error (a network exception) and a server error in * the reply. @cmd_ret and @cmd_err come from the result of a * read_command function. * * * Return: * A mongoc_read_error_type_t indicating the type of error (if any). * *-------------------------------------------------------------------------- */ mongoc_read_err_type_t _mongoc_read_error_get_type (bool cmd_ret, const bson_error_t *cmd_err, const bson_t *reply) { bson_error_t error; /* check for a client error. */ if (!cmd_ret && cmd_err && _mongoc_error_is_network (cmd_err)) { /* Retryable reads spec: "considered retryable if [...] any network * exception (e.g. socket timeout or error) */ return MONGOC_READ_ERR_RETRY; } /* check for a server error. */ if (_mongoc_cmd_check_ok_no_wce (reply, MONGOC_ERROR_API_VERSION_2, &error)) { return MONGOC_READ_ERR_NONE; } switch (error.code) { case MONGOC_SERVER_ERR_EXCEEDEDTIMELIMIT: case MONGOC_SERVER_ERR_INTERRUPTEDATSHUTDOWN: case MONGOC_SERVER_ERR_INTERRUPTEDDUETOREPLSTATECHANGE: case MONGOC_SERVER_ERR_NOTPRIMARY: case MONGOC_SERVER_ERR_NOTPRIMARYNOSECONDARYOK: case MONGOC_SERVER_ERR_NOTPRIMARYORSECONDARY: case MONGOC_SERVER_ERR_PRIMARYSTEPPEDDOWN: case MONGOC_SERVER_ERR_READCONCERNMAJORITYNOTAVAILABLEYET: case MONGOC_SERVER_ERR_SHUTDOWNINPROGRESS: case MONGOC_SERVER_ERR_HOSTNOTFOUND: case MONGOC_SERVER_ERR_HOSTUNREACHABLE: case MONGOC_SERVER_ERR_NETWORKTIMEOUT: case MONGOC_SERVER_ERR_SOCKETEXCEPTION: return MONGOC_READ_ERR_RETRY; default: if (strstr (error.message, "not master") || strstr (error.message, "node is recovering")) { return MONGOC_READ_ERR_RETRY; } return MONGOC_READ_ERR_OTHER; } } void _mongoc_error_copy_labels_and_upsert (const bson_t *src, bson_t *dst, char *label) { bson_iter_t iter; bson_iter_t src_label; bson_array_builder_t *dst_labels; BSON_APPEND_ARRAY_BUILDER_BEGIN (dst, "errorLabels", &dst_labels); bson_array_builder_append_utf8 (dst_labels, label, -1); /* append any other errorLabels already in "src" */ if (bson_iter_init_find (&iter, src, "errorLabels") && bson_iter_recurse (&iter, &src_label)) { while (bson_iter_next (&src_label) && BSON_ITER_HOLDS_UTF8 (&src_label)) { if (strcmp (bson_iter_utf8 (&src_label, NULL), label) != 0) { bson_array_builder_append_utf8 (dst_labels, bson_iter_utf8 (&src_label, NULL), -1); } } } bson_append_array_builder_end (dst, dst_labels); } /* Defined in SDAM spec under "Application Errors". * @error should have been obtained from a command reply, e.g. with * _mongoc_cmd_check_ok. */ bool _mongoc_error_is_shutdown (bson_error_t *error) { if (!_mongoc_error_is_server (error)) { return false; } switch (error->code) { case 11600: /* InterruptedAtShutdown */ case 91: /* ShutdownInProgress */ return true; default: return false; } } bool _mongoc_error_is_not_primary (bson_error_t *error) { if (!_mongoc_error_is_server (error)) { return false; } if (_mongoc_error_is_recovering (error)) { return false; } switch (error->code) { case MONGOC_SERVER_ERR_NOTPRIMARY: case MONGOC_SERVER_ERR_NOTPRIMARYNOSECONDARYOK: case MONGOC_SERVER_ERR_LEGACYNOTPRIMARY: return true; /* All errors where no code was found are marked as * MONGOC_ERROR_QUERY_FAILURE */ case MONGOC_ERROR_QUERY_FAILURE: return NULL != strstr (error->message, "not master"); default: return false; } } bool _mongoc_error_is_recovering (bson_error_t *error) { if (!_mongoc_error_is_server (error)) { return false; } switch (error->code) { case MONGOC_SERVER_ERR_INTERRUPTEDATSHUTDOWN: case MONGOC_SERVER_ERR_INTERRUPTEDDUETOREPLSTATECHANGE: case MONGOC_SERVER_ERR_NOTPRIMARYORSECONDARY: case MONGOC_SERVER_ERR_PRIMARYSTEPPEDDOWN: case MONGOC_SERVER_ERR_SHUTDOWNINPROGRESS: return true; /* All errors where no code was found are marked as * MONGOC_ERROR_QUERY_FAILURE */ case MONGOC_ERROR_QUERY_FAILURE: return NULL != strstr (error->message, "not master or secondary") || NULL != strstr (error->message, "node is recovering"); default: return false; } } /* Assumes @error was parsed as an API V2 error. */ bool _mongoc_error_is_state_change (bson_error_t *error) { return _mongoc_error_is_recovering (error) || _mongoc_error_is_not_primary (error); } bool _mongoc_error_is_network (const bson_error_t *error) { if (!error) { return false; } if (error->domain == MONGOC_ERROR_STREAM) { return true; } if (error->domain == MONGOC_ERROR_PROTOCOL && error->code == MONGOC_ERROR_PROTOCOL_INVALID_REPLY) { return true; } return false; } bool _mongoc_error_is_auth (const bson_error_t *error) { if (!error) { return false; } return error->domain == MONGOC_ERROR_CLIENT && error->code == MONGOC_ERROR_CLIENT_AUTHENTICATE; } void _mongoc_error_append (bson_error_t *error, const char *s) { BSON_ASSERT (error); const size_t error_len = strlen (error->message); const size_t remaining = sizeof (error->message) - error_len; bson_strncpy (error->message + error_len, s, remaining); } bool mongoc_error_append_contents_to_bson (const bson_error_t *error, bson_t *bson, mongoc_error_content_flags_t flags) { BSON_ASSERT_PARAM (error); BSON_ASSERT_PARAM (bson); if ((flags & MONGOC_ERROR_CONTENT_FLAG_CODE) && !BSON_APPEND_INT32 (bson, "code", error->code)) { return false; } if ((flags & MONGOC_ERROR_CONTENT_FLAG_DOMAIN) && !BSON_APPEND_INT32 (bson, "domain", error->domain)) { return false; } if ((flags & MONGOC_ERROR_CONTENT_FLAG_MESSAGE) && !BSON_APPEND_UTF8 (bson, "message", error->message)) { return false; } return true; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-error.h0000644000175100001660000001001414760300420022264 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_ERRORS_H #define MONGOC_ERRORS_H #include #include #define MONGOC_ERROR_API_VERSION_LEGACY 1 #define MONGOC_ERROR_API_VERSION_2 2 BSON_BEGIN_DECLS typedef enum { MONGOC_ERROR_CLIENT = 1, MONGOC_ERROR_STREAM, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_CURSOR, MONGOC_ERROR_QUERY, MONGOC_ERROR_INSERT, MONGOC_ERROR_SASL, MONGOC_ERROR_BSON, MONGOC_ERROR_MATCHER, MONGOC_ERROR_NAMESPACE, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COLLECTION, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_WRITE_CONCERN, MONGOC_ERROR_SERVER, /* Error API Version 2 only */ MONGOC_ERROR_TRANSACTION, MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION, /* An error coming from libmongocrypt */ MONGOC_ERROR_POOL, MONGOC_ERROR_AZURE, MONGOC_ERROR_GCP } mongoc_error_domain_t; typedef enum { MONGOC_ERROR_STREAM_INVALID_TYPE = 1, MONGOC_ERROR_STREAM_INVALID_STATE, MONGOC_ERROR_STREAM_NAME_RESOLUTION, MONGOC_ERROR_STREAM_SOCKET, MONGOC_ERROR_STREAM_CONNECT, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, MONGOC_ERROR_CLIENT_NOT_READY, MONGOC_ERROR_CLIENT_TOO_BIG, MONGOC_ERROR_CLIENT_TOO_SMALL, MONGOC_ERROR_CLIENT_GETNONCE, MONGOC_ERROR_CLIENT_AUTHENTICATE, MONGOC_ERROR_CLIENT_NO_ACCEPTABLE_PEER, MONGOC_ERROR_CLIENT_IN_EXHAUST, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, MONGOC_ERROR_CURSOR_INVALID_CURSOR, MONGOC_ERROR_QUERY_FAILURE, MONGOC_ERROR_BSON_INVALID, MONGOC_ERROR_MATCHER_INVALID, MONGOC_ERROR_NAMESPACE_INVALID, MONGOC_ERROR_NAMESPACE_INVALID_FILTER_TYPE, MONGOC_ERROR_COMMAND_INVALID_ARG, MONGOC_ERROR_COLLECTION_INSERT_FAILED, MONGOC_ERROR_COLLECTION_UPDATE_FAILED, MONGOC_ERROR_COLLECTION_DELETE_FAILED, MONGOC_ERROR_COLLECTION_DOES_NOT_EXIST = 26, MONGOC_ERROR_GRIDFS_INVALID_FILENAME, MONGOC_ERROR_SCRAM_NOT_DONE, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND = 59, MONGOC_ERROR_QUERY_NOT_TAILABLE = 13051, MONGOC_ERROR_SERVER_SELECTION_BAD_WIRE_VERSION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, MONGOC_ERROR_SERVER_SELECTION_INVALID_ID, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, MONGOC_ERROR_GRIDFS_PROTOCOL_ERROR, /* Dup with query failure. */ MONGOC_ERROR_PROTOCOL_ERROR = 17, MONGOC_ERROR_WRITE_CONCERN_ERROR = 64, MONGOC_ERROR_DUPLICATE_KEY = 11000, MONGOC_ERROR_MAX_TIME_MS_EXPIRED = 50, MONGOC_ERROR_CHANGE_STREAM_NO_RESUME_TOKEN, MONGOC_ERROR_CLIENT_SESSION_FAILURE, MONGOC_ERROR_TRANSACTION_INVALID_STATE, MONGOC_ERROR_GRIDFS_CORRUPT, MONGOC_ERROR_GRIDFS_BUCKET_FILE_NOT_FOUND, MONGOC_ERROR_GRIDFS_BUCKET_STREAM, /* An error related to initializing client side encryption. */ MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_STATE, MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG, /* An error related to server version api */ MONGOC_ERROR_CLIENT_API_ALREADY_SET, MONGOC_ERROR_CLIENT_API_FROM_POOL, MONGOC_ERROR_POOL_API_ALREADY_SET, MONGOC_ERROR_POOL_API_TOO_LATE, MONGOC_ERROR_CLIENT_INVALID_LOAD_BALANCER, /* An error related to either GCP metadata or Azure IMDS server */ MONGOC_ERROR_KMS_SERVER_HTTP, MONGOC_ERROR_KMS_SERVER_BAD_JSON, } mongoc_error_code_t; MONGOC_EXPORT (bool) mongoc_error_has_label (const bson_t *reply, const char *label); BSON_END_DECLS #endif /* MONGOC_ERRORS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-find-and-modify-private.h0000644000175100001660000000211014760300420025546 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_FIND_AND_MODIFY_PRIVATE_H #define MONGOC_FIND_AND_MODIFY_PRIVATE_H #include #include BSON_BEGIN_DECLS struct _mongoc_find_and_modify_opts_t { bson_t *sort; bson_t *update; bson_t *fields; mongoc_find_and_modify_flags_t flags; bool bypass_document_validation; uint32_t max_time_ms; bson_t extra; }; BSON_END_DECLS #endif /* MONGOC_FIND_AND_MODIFY_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-find-and-modify.c0000644000175100001660000001133314760300420024100 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include /** * mongoc_find_and_modify_new: * * Create a new mongoc_find_and_modify_t. * * Returns: A newly allocated mongoc_find_and_modify_t. This should be freed * with mongoc_find_and_modify_destroy(). */ mongoc_find_and_modify_opts_t * mongoc_find_and_modify_opts_new (void) { mongoc_find_and_modify_opts_t *opts = NULL; opts = BSON_ALIGNED_ALLOC0 (mongoc_find_and_modify_opts_t); bson_init (&opts->extra); opts->bypass_document_validation = false; return opts; } bool mongoc_find_and_modify_opts_set_sort (mongoc_find_and_modify_opts_t *opts, const bson_t *sort) { BSON_ASSERT (opts); if (sort) { bson_destroy (opts->sort); opts->sort = bson_copy (sort); return true; } return false; } void mongoc_find_and_modify_opts_get_sort (const mongoc_find_and_modify_opts_t *opts, bson_t *sort) { BSON_ASSERT (opts); BSON_ASSERT (sort); if (opts->sort) { bson_copy_to (opts->sort, sort); } else { bson_init (sort); } } bool mongoc_find_and_modify_opts_set_update (mongoc_find_and_modify_opts_t *opts, const bson_t *update) { BSON_ASSERT (opts); if (update) { bson_destroy (opts->update); opts->update = bson_copy (update); return true; } return false; } void mongoc_find_and_modify_opts_get_update (const mongoc_find_and_modify_opts_t *opts, bson_t *update) { BSON_ASSERT (opts); BSON_ASSERT (update); if (opts->update) { bson_copy_to (opts->update, update); } else { bson_init (update); } } bool mongoc_find_and_modify_opts_set_fields (mongoc_find_and_modify_opts_t *opts, const bson_t *fields) { BSON_ASSERT (opts); if (fields) { bson_destroy (opts->fields); opts->fields = bson_copy (fields); return true; } return false; } void mongoc_find_and_modify_opts_get_fields (const mongoc_find_and_modify_opts_t *opts, bson_t *fields) { BSON_ASSERT (opts); BSON_ASSERT (fields); if (opts->fields) { bson_copy_to (opts->fields, fields); } else { bson_init (fields); } } bool mongoc_find_and_modify_opts_set_flags (mongoc_find_and_modify_opts_t *opts, const mongoc_find_and_modify_flags_t flags) { BSON_ASSERT (opts); opts->flags = flags; return true; } mongoc_find_and_modify_flags_t mongoc_find_and_modify_opts_get_flags (const mongoc_find_and_modify_opts_t *opts) { BSON_ASSERT (opts); return opts->flags; } bool mongoc_find_and_modify_opts_set_bypass_document_validation (mongoc_find_and_modify_opts_t *opts, bool bypass) { BSON_ASSERT (opts); opts->bypass_document_validation = bypass; return true; } bool mongoc_find_and_modify_opts_get_bypass_document_validation (const mongoc_find_and_modify_opts_t *opts) { BSON_ASSERT (opts); return opts->bypass_document_validation; } bool mongoc_find_and_modify_opts_set_max_time_ms (mongoc_find_and_modify_opts_t *opts, uint32_t max_time_ms) { BSON_ASSERT (opts); opts->max_time_ms = max_time_ms; return true; } uint32_t mongoc_find_and_modify_opts_get_max_time_ms (const mongoc_find_and_modify_opts_t *opts) { BSON_ASSERT (opts); return opts->max_time_ms; } bool mongoc_find_and_modify_opts_append (mongoc_find_and_modify_opts_t *opts, const bson_t *extra) { BSON_ASSERT (opts); if (!extra) { return true; } return bson_concat (&opts->extra, extra); } void mongoc_find_and_modify_opts_get_extra (const mongoc_find_and_modify_opts_t *opts, bson_t *extra) { BSON_ASSERT (opts); BSON_ASSERT (extra); bson_copy_to (&opts->extra, extra); } /** * mongoc_find_and_modify_opts_destroy: * @opts: A mongoc_find_and_modify_opts_t. * * Releases a mongoc_find_and_modify_opts_t and all associated memory. */ void mongoc_find_and_modify_opts_destroy (mongoc_find_and_modify_opts_t *opts) { if (opts) { bson_destroy (opts->sort); bson_destroy (opts->update); bson_destroy (opts->fields); bson_destroy (&opts->extra); bson_free (opts); } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-find-and-modify.h0000644000175100001660000000601714760300420024110 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_FIND_AND_MODIFY_H #define MONGOC_FIND_AND_MODIFY_H #include #include BSON_BEGIN_DECLS typedef enum { MONGOC_FIND_AND_MODIFY_NONE = 0, MONGOC_FIND_AND_MODIFY_REMOVE = 1 << 0, MONGOC_FIND_AND_MODIFY_UPSERT = 1 << 1, MONGOC_FIND_AND_MODIFY_RETURN_NEW = 1 << 2, } mongoc_find_and_modify_flags_t; typedef struct _mongoc_find_and_modify_opts_t mongoc_find_and_modify_opts_t; MONGOC_EXPORT (mongoc_find_and_modify_opts_t *) mongoc_find_and_modify_opts_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_find_and_modify_opts_set_sort (mongoc_find_and_modify_opts_t *opts, const bson_t *sort); MONGOC_EXPORT (void) mongoc_find_and_modify_opts_get_sort (const mongoc_find_and_modify_opts_t *opts, bson_t *sort); MONGOC_EXPORT (bool) mongoc_find_and_modify_opts_set_update (mongoc_find_and_modify_opts_t *opts, const bson_t *update); MONGOC_EXPORT (void) mongoc_find_and_modify_opts_get_update (const mongoc_find_and_modify_opts_t *opts, bson_t *update); MONGOC_EXPORT (bool) mongoc_find_and_modify_opts_set_fields (mongoc_find_and_modify_opts_t *opts, const bson_t *fields); MONGOC_EXPORT (void) mongoc_find_and_modify_opts_get_fields (const mongoc_find_and_modify_opts_t *opts, bson_t *fields); MONGOC_EXPORT (bool) mongoc_find_and_modify_opts_set_flags (mongoc_find_and_modify_opts_t *opts, const mongoc_find_and_modify_flags_t flags); MONGOC_EXPORT (mongoc_find_and_modify_flags_t) mongoc_find_and_modify_opts_get_flags (const mongoc_find_and_modify_opts_t *opts); MONGOC_EXPORT (bool) mongoc_find_and_modify_opts_set_bypass_document_validation (mongoc_find_and_modify_opts_t *opts, bool bypass); MONGOC_EXPORT (bool) mongoc_find_and_modify_opts_get_bypass_document_validation (const mongoc_find_and_modify_opts_t *opts); MONGOC_EXPORT (bool) mongoc_find_and_modify_opts_set_max_time_ms (mongoc_find_and_modify_opts_t *opts, uint32_t max_time_ms); MONGOC_EXPORT (uint32_t) mongoc_find_and_modify_opts_get_max_time_ms (const mongoc_find_and_modify_opts_t *opts); MONGOC_EXPORT (bool) mongoc_find_and_modify_opts_append (mongoc_find_and_modify_opts_t *opts, const bson_t *extra); MONGOC_EXPORT (void) mongoc_find_and_modify_opts_get_extra (const mongoc_find_and_modify_opts_t *opts, bson_t *extra); MONGOC_EXPORT (void) mongoc_find_and_modify_opts_destroy (mongoc_find_and_modify_opts_t *opts); BSON_END_DECLS #endif /* MONGOC_FIND_AND_MODIFY_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-flags-private.h0000644000175100001660000000247614760300420023714 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_FLAGS_PRIVATE_H #define MONGOC_FLAGS_PRIVATE_H #include BSON_BEGIN_DECLS /** * mongoc_op_msg_flags_t: * @MONGOC_MSG_CHECKSUM_PRESENT: The message ends with 4 bytes containing a * CRC-32C checksum. * @MONGOC_MSG_MORE_TO_COME: If set to 0, wait for a server response. If set to * 1, do not expect a server response. * @MONGOC_MSG_EXHAUST_ALLOWED: If set, allows multiple replies to this request * using the moreToCome bit. */ typedef enum { MONGOC_MSG_NONE = 0, MONGOC_MSG_CHECKSUM_PRESENT = 1 << 0, MONGOC_MSG_MORE_TO_COME = 1 << 1, MONGOC_MSG_EXHAUST_ALLOWED = 1 << 16, } mongoc_op_msg_flags_t; BSON_END_DECLS #endif /* MONGOC_FLAGS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-flags.c0000644000175100001660000000627614760300420022241 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include // Document and ensure consistency between equivalent macros in mcd-rpc and // libmongoc. BSON_STATIC_ASSERT (MONGOC_OP_COMPRESSED_COMPRESSOR_ID_NOOP == MONGOC_COMPRESSOR_NOOP_ID); BSON_STATIC_ASSERT (MONGOC_OP_COMPRESSED_COMPRESSOR_ID_SNAPPY == MONGOC_COMPRESSOR_SNAPPY_ID); BSON_STATIC_ASSERT (MONGOC_OP_COMPRESSED_COMPRESSOR_ID_ZLIB == MONGOC_COMPRESSOR_ZLIB_ID); BSON_STATIC_ASSERT (MONGOC_OP_COMPRESSED_COMPRESSOR_ID_ZSTD == MONGOC_COMPRESSOR_ZSTD_ID); BSON_STATIC_ASSERT (MONGOC_OP_MSG_FLAG_NONE == MONGOC_MSG_NONE); BSON_STATIC_ASSERT (MONGOC_OP_MSG_FLAG_CHECKSUM_PRESENT == MONGOC_MSG_CHECKSUM_PRESENT); BSON_STATIC_ASSERT (MONGOC_OP_MSG_FLAG_MORE_TO_COME == MONGOC_MSG_MORE_TO_COME); BSON_STATIC_ASSERT (MONGOC_OP_MSG_FLAG_EXHAUST_ALLOWED == MONGOC_MSG_EXHAUST_ALLOWED); BSON_STATIC_ASSERT (MONGOC_OP_REPLY_RESPONSE_FLAG_NONE == MONGOC_REPLY_NONE); BSON_STATIC_ASSERT (MONGOC_OP_REPLY_RESPONSE_FLAG_CURSOR_NOT_FOUND == MONGOC_REPLY_CURSOR_NOT_FOUND); BSON_STATIC_ASSERT (MONGOC_OP_REPLY_RESPONSE_FLAG_QUERY_FAILURE == MONGOC_REPLY_QUERY_FAILURE); BSON_STATIC_ASSERT (MONGOC_OP_REPLY_RESPONSE_FLAG_SHARD_CONFIG_STALE == MONGOC_REPLY_SHARD_CONFIG_STALE); BSON_STATIC_ASSERT (MONGOC_OP_REPLY_RESPONSE_FLAG_AWAIT_CAPABLE == MONGOC_REPLY_AWAIT_CAPABLE); BSON_STATIC_ASSERT (MONGOC_OP_UPDATE_FLAG_NONE == MONGOC_UPDATE_NONE); BSON_STATIC_ASSERT (MONGOC_OP_UPDATE_FLAG_UPSERT == MONGOC_UPDATE_UPSERT); BSON_STATIC_ASSERT (MONGOC_OP_UPDATE_FLAG_MULTI_UPDATE == MONGOC_UPDATE_MULTI_UPDATE); BSON_STATIC_ASSERT (MONGOC_OP_INSERT_FLAG_NONE == MONGOC_INSERT_NONE); BSON_STATIC_ASSERT (MONGOC_OP_INSERT_FLAG_CONTINUE_ON_ERROR == MONGOC_INSERT_CONTINUE_ON_ERROR); BSON_STATIC_ASSERT (MONGOC_OP_QUERY_FLAG_NONE == MONGOC_QUERY_NONE); BSON_STATIC_ASSERT (MONGOC_OP_QUERY_FLAG_TAILABLE_CURSOR == MONGOC_QUERY_TAILABLE_CURSOR); BSON_STATIC_ASSERT (MONGOC_OP_QUERY_FLAG_SECONDARY_OK == MONGOC_QUERY_SECONDARY_OK); BSON_STATIC_ASSERT (MONGOC_OP_QUERY_FLAG_OPLOG_REPLAY == MONGOC_QUERY_OPLOG_REPLAY); BSON_STATIC_ASSERT (MONGOC_OP_QUERY_FLAG_NO_CURSOR_TIMEOUT == MONGOC_QUERY_NO_CURSOR_TIMEOUT); BSON_STATIC_ASSERT (MONGOC_OP_QUERY_FLAG_AWAIT_DATA == MONGOC_QUERY_AWAIT_DATA); BSON_STATIC_ASSERT (MONGOC_OP_QUERY_FLAG_EXHAUST == MONGOC_QUERY_EXHAUST); BSON_STATIC_ASSERT (MONGOC_OP_QUERY_FLAG_PARTIAL == MONGOC_QUERY_PARTIAL); BSON_STATIC_ASSERT (MONGOC_OP_DELETE_FLAG_NONE == MONGOC_DELETE_NONE); BSON_STATIC_ASSERT (MONGOC_OP_DELETE_FLAG_SINGLE_REMOVE == MONGOC_DELETE_SINGLE_REMOVE); mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-flags.h0000644000175100001660000001104514760300420022234 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_FLAGS_H #define MONGOC_FLAGS_H #include BSON_BEGIN_DECLS /** * mongoc_delete_flags_t: * @MONGOC_DELETE_NONE: Specify no delete flags. * @MONGOC_DELETE_SINGLE_REMOVE: Only remove the first document matching the * document selector. * * This type is only for use with deprecated functions and should not be * used in new code. Use mongoc_remove_flags_t instead. * * #mongoc_delete_flags_t are used when performing a delete operation. */ typedef enum { MONGOC_DELETE_NONE = 0, MONGOC_DELETE_SINGLE_REMOVE = 1 << 0, } mongoc_delete_flags_t; /** * mongoc_remove_flags_t: * @MONGOC_REMOVE_NONE: Specify no delete flags. * @MONGOC_REMOVE_SINGLE_REMOVE: Only remove the first document matching the * document selector. * * #mongoc_remove_flags_t are used when performing a remove operation. */ typedef enum { MONGOC_REMOVE_NONE = 0, MONGOC_REMOVE_SINGLE_REMOVE = 1 << 0, } mongoc_remove_flags_t; /** * mongoc_insert_flags_t: * @MONGOC_INSERT_NONE: Specify no insert flags. * @MONGOC_INSERT_CONTINUE_ON_ERROR: Continue inserting documents from * the insertion set even if one fails. * * #mongoc_insert_flags_t are used when performing an insert operation. */ typedef enum { MONGOC_INSERT_NONE = 0, MONGOC_INSERT_CONTINUE_ON_ERROR = 1 << 0, } mongoc_insert_flags_t; #define MONGOC_INSERT_NO_VALIDATE (1U << 31) /** * mongoc_query_flags_t: * @MONGOC_QUERY_NONE: No query flags supplied. * @MONGOC_QUERY_TAILABLE_CURSOR: Cursor will not be closed when the last * data is retrieved. You can resume this cursor later. * @MONGOC_QUERY_SECONDARY_OK: Allow query of secondaries in a replica set. * @MONGOC_QUERY_OPLOG_REPLAY: Used internally by Mongo. * @MONGOC_QUERY_NO_CURSOR_TIMEOUT: The server normally times out idle * cursors after an inactivity period (10 minutes). This prevents that. * @MONGOC_QUERY_AWAIT_DATA: Use with %MONGOC_QUERY_TAILABLE_CURSOR. Block * rather than returning no data. After a period, time out. * @MONGOC_QUERY_EXHAUST: Stream the data down full blast in multiple * "more" packages. Faster when you are pulling a lot of data and * know you want to pull it all down. * @MONGOC_QUERY_PARTIAL: Get partial results from mongos if some shards * are down (instead of throwing an error). * * #mongoc_query_flags_t is used for querying a Mongo instance. */ typedef enum { MONGOC_QUERY_NONE = 0, MONGOC_QUERY_TAILABLE_CURSOR = 1 << 1, MONGOC_QUERY_SLAVE_OK = 1 << 2, MONGOC_QUERY_SECONDARY_OK = 1 << 2, MONGOC_QUERY_OPLOG_REPLAY = 1 << 3, MONGOC_QUERY_NO_CURSOR_TIMEOUT = 1 << 4, MONGOC_QUERY_AWAIT_DATA = 1 << 5, MONGOC_QUERY_EXHAUST = 1 << 6, MONGOC_QUERY_PARTIAL = 1 << 7, } mongoc_query_flags_t; /** * mongoc_reply_flags_t: * @MONGOC_REPLY_NONE: No flags set. * @MONGOC_REPLY_CURSOR_NOT_FOUND: Cursor was not found. * @MONGOC_REPLY_QUERY_FAILURE: Query failed, error document provided. * @MONGOC_REPLY_SHARD_CONFIG_STALE: Shard configuration is stale. * @MONGOC_REPLY_AWAIT_CAPABLE: Wait for data to be returned until timeout * has passed. Used with %MONGOC_QUERY_TAILABLE_CURSOR. * * #mongoc_reply_flags_t contains flags supplied by the Mongo server in reply * to a request. */ typedef enum { MONGOC_REPLY_NONE = 0, MONGOC_REPLY_CURSOR_NOT_FOUND = 1 << 0, MONGOC_REPLY_QUERY_FAILURE = 1 << 1, MONGOC_REPLY_SHARD_CONFIG_STALE = 1 << 2, MONGOC_REPLY_AWAIT_CAPABLE = 1 << 3, } mongoc_reply_flags_t; /** * mongoc_update_flags_t: * @MONGOC_UPDATE_NONE: No update flags specified. * @MONGOC_UPDATE_UPSERT: Perform an upsert. * @MONGOC_UPDATE_MULTI_UPDATE: Continue updating after first match. * * #mongoc_update_flags_t is used when updating documents found in Mongo. */ typedef enum { MONGOC_UPDATE_NONE = 0, MONGOC_UPDATE_UPSERT = 1 << 0, MONGOC_UPDATE_MULTI_UPDATE = 1 << 1, } mongoc_update_flags_t; #define MONGOC_UPDATE_NO_VALIDATE (1U << 31) BSON_END_DECLS #endif /* MONGOC_FLAGS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-generation-map-private.h0000644000175100001660000000254714760300420025525 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #ifndef MONGOC_GENERATION_MAP_PRIVATE_H #define MONGOC_GENERATION_MAP_PRIVATE_H /* mongoc_generation_map_t maps a BSON ObjectID to an unsigned integer. * It is used to track connection generations. */ typedef struct _mongoc_generation_map mongoc_generation_map_t; mongoc_generation_map_t * mongoc_generation_map_new (void); mongoc_generation_map_t * mongoc_generation_map_copy (const mongoc_generation_map_t *gm); uint32_t mongoc_generation_map_get (const mongoc_generation_map_t *gm, const bson_oid_t *key); void mongoc_generation_map_increment (mongoc_generation_map_t *gm, const bson_oid_t *key); void mongoc_generation_map_destroy (mongoc_generation_map_t *gm); #endif /* MONGOC_GENERATION_MAP_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-generation-map.c0000644000175100001660000000572614760300420024052 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include typedef struct _gm_node_t { bson_oid_t key; uint32_t val; struct _gm_node_t *next; } gm_node_t; static gm_node_t * gm_node_new (void) { return bson_malloc0 (sizeof (gm_node_t)); } static void gm_node_destroy (gm_node_t *node) { bson_free (node); } static gm_node_t * gm_node_copy (const gm_node_t *node) { gm_node_t *node_copy = gm_node_new (); BSON_ASSERT (node_copy); BSON_ASSERT (node); bson_oid_copy (&node->key, &node_copy->key); node_copy->val = node->val; return node_copy; } struct _mongoc_generation_map { gm_node_t *list; }; mongoc_generation_map_t * mongoc_generation_map_new (void) { mongoc_generation_map_t *gm; gm = bson_malloc0 (sizeof (mongoc_generation_map_t)); return gm; } mongoc_generation_map_t * mongoc_generation_map_copy (const mongoc_generation_map_t *gm) { mongoc_generation_map_t *gm_copy; gm_node_t *iter; gm_copy = mongoc_generation_map_new (); BSON_ASSERT (gm_copy); LL_FOREACH (gm->list, iter) { gm_node_t *node_copy; node_copy = gm_node_copy (iter); BSON_ASSERT (node_copy); LL_PREPEND (gm_copy->list, node_copy); } return gm_copy; } uint32_t mongoc_generation_map_get (const mongoc_generation_map_t *gm, const bson_oid_t *key) { gm_node_t *iter = NULL; BSON_ASSERT (gm); BSON_ASSERT (key); LL_FOREACH (gm->list, iter) { if (bson_oid_equal (key, &iter->key)) { break; } } if (!iter) { return 0; } return iter->val; } void mongoc_generation_map_increment (mongoc_generation_map_t *gm, const bson_oid_t *key) { gm_node_t *match; gm_node_t *iter = NULL; BSON_ASSERT (gm); BSON_ASSERT (key); LL_FOREACH (gm->list, iter) { if (bson_oid_equal (key, &iter->key)) { break; } } if (iter) { match = iter; } else { gm_node_t *new_node = gm_node_new (); BSON_ASSERT (new_node); bson_oid_copy (key, &new_node->key); LL_PREPEND (gm->list, new_node); match = new_node; } BSON_ASSERT (match); match->val++; } void mongoc_generation_map_destroy (mongoc_generation_map_t *gm) { gm_node_t *iter = NULL; gm_node_t *tmp = NULL; if (!gm) { return; } LL_FOREACH_SAFE (gm->list, iter, tmp) { gm_node_destroy (iter); } bson_free (gm); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-bucket-file-private.h0000644000175100001660000000347114760300420026262 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_BUCKET_FILE_PRIVATE_H #define MONGOC_GRIDFS_BUCKET_FILE_PRIVATE_H #include #include #include #include BSON_BEGIN_DECLS typedef struct { /* corresponding bucket */ mongoc_gridfs_bucket_t *bucket; /* file data */ char *filename; bson_value_t *file_id; bson_t *metadata; int32_t chunk_size; int64_t length; /* fields for reading and writing */ uint8_t *buffer; size_t in_buffer; int32_t curr_chunk; /* for writing */ bool saved; /* for reading */ mongoc_cursor_t *cursor; size_t bytes_read; bool finished; /* Error */ bson_error_t err; } mongoc_gridfs_bucket_file_t; ssize_t _mongoc_gridfs_bucket_file_writev (mongoc_gridfs_bucket_file_t *file, const mongoc_iovec_t *iov, size_t iovcnt); ssize_t _mongoc_gridfs_bucket_file_readv (mongoc_gridfs_bucket_file_t *file, mongoc_iovec_t *iov, size_t iovcnt); bool _mongoc_gridfs_bucket_file_save (mongoc_gridfs_bucket_file_t *file); void _mongoc_gridfs_bucket_file_destroy (mongoc_gridfs_bucket_file_t *file); BSON_END_DECLS #endif /* MONGOC_GRIDFS_BUCKET_FILE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-bucket-file.c0000644000175100001660000003273014760300420024605 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include /* Returns the minimum of two numbers */ static size_t _mongoc_min (const size_t a, const size_t b) { return a < b ? a : b; } /*-------------------------------------------------------------------------- * * _mongoc_gridfs_bucket_create_indexes -- * * Creates the indexes needed for GridFS on the 'files' and 'chunks' * collections. * * Return: * True if creating the indexes was successful, otherwise returns * false. * *-------------------------------------------------------------------------- */ static bool _mongoc_gridfs_bucket_create_indexes (mongoc_gridfs_bucket_t *bucket, bson_error_t *error) { mongoc_read_prefs_t *prefs; bson_t filter; bson_t opts; mongoc_cursor_t *cursor; const bson_t *doc; bson_t files_index; bson_t chunks_index; bool r; /* Check to see if there already exists a document in the files collection */ bson_init (&filter); bson_append_int32 (&filter, "_id", 3, 1); bson_init (&opts); bson_append_bool (&opts, "singleBatch", 11, true); bson_append_int32 (&opts, "limit", 5, 1); prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); cursor = mongoc_collection_find_with_opts (bucket->files, &filter, &opts, prefs); bson_destroy (&filter); bson_destroy (&opts); r = mongoc_cursor_next (cursor, &doc); mongoc_read_prefs_destroy (prefs); if (r) { /* Files exist */ mongoc_cursor_destroy (cursor); return true; } else if (mongoc_cursor_error (cursor, error)) { mongoc_cursor_destroy (cursor); return false; } mongoc_cursor_destroy (cursor); /* Create files index */ bson_init (&files_index); BSON_APPEND_INT32 (&files_index, "filename", 1); BSON_APPEND_INT32 (&files_index, "uploadDate", 1); r = _mongoc_collection_create_index_if_not_exists (bucket->files, &files_index, NULL, error); bson_destroy (&files_index); if (!r) { return false; } /* Create unique chunks index */ bson_init (&opts); BSON_APPEND_BOOL (&opts, "unique", true); BSON_APPEND_UTF8 (&opts, "name", "files_id_1_n_1"); bson_init (&chunks_index); BSON_APPEND_INT32 (&chunks_index, "files_id", 1); BSON_APPEND_INT32 (&chunks_index, "n", 1); r = _mongoc_collection_create_index_if_not_exists (bucket->chunks, &chunks_index, &opts, error); bson_destroy (&opts); bson_destroy (&chunks_index); if (!r) { return false; } return true; } /*-------------------------------------------------------------------------- * * _mongoc_gridfs_bucket_write_chunk -- * * Writes a chunk from the buffer into the chunks collection. * * Return: * Returns true if the chunk was successfully written. Otherwise, * returns false and sets an error on the bucket file. * *-------------------------------------------------------------------------- */ static bool _mongoc_gridfs_bucket_write_chunk (mongoc_gridfs_bucket_file_t *file) { bson_t chunk; bool r; BSON_ASSERT (file); bson_init (&chunk); BSON_APPEND_INT32 (&chunk, "n", file->curr_chunk); BSON_APPEND_VALUE (&chunk, "files_id", file->file_id); BSON_APPEND_BINARY (&chunk, "data", BSON_SUBTYPE_BINARY, file->buffer, (uint32_t) file->in_buffer); r = mongoc_collection_insert_one (file->bucket->chunks, &chunk, NULL /* opts */, NULL /* reply */, &file->err); bson_destroy (&chunk); if (!r) { return false; } file->curr_chunk++; file->in_buffer = 0; return true; } /*-------------------------------------------------------------------------- * * _mongoc_gridfs_bucket_init_cursor -- * * Initializes the cursor at file->cursor for the given file. * *-------------------------------------------------------------------------- */ static void _mongoc_gridfs_bucket_init_cursor (mongoc_gridfs_bucket_file_t *file) { bson_t filter; bson_t opts; bson_t sort; BSON_ASSERT (file); bson_init (&filter); bson_init (&opts); bson_init (&sort); BSON_APPEND_VALUE (&filter, "files_id", file->file_id); BSON_APPEND_INT32 (&sort, "n", 1); BSON_APPEND_DOCUMENT (&opts, "sort", &sort); file->cursor = mongoc_collection_find_with_opts (file->bucket->chunks, &filter, &opts, NULL); bson_destroy (&filter); bson_destroy (&opts); bson_destroy (&sort); } /*-------------------------------------------------------------------------- * * _mongoc_gridfs_bucket_read_chunk -- * * Reads a chunk from the server and places it into the file's buffer * * Return: * True if the buffer has been filled with any available data. * Otherwise, false and sets the error on the bucket file. * *-------------------------------------------------------------------------- */ static bool _mongoc_gridfs_bucket_read_chunk (mongoc_gridfs_bucket_file_t *file) { const bson_t *next; bool r; bson_iter_t iter; int32_t n; const uint8_t *data; uint32_t data_len; int64_t total_chunks; int64_t expected_size; BSON_ASSERT (file); if (file->length == 0) { /* This file has zero length */ file->in_buffer = 0; file->finished = true; return true; } /* Calculate the total number of chunks for this file */ total_chunks = (file->length / file->chunk_size); if (file->length % file->chunk_size != 0) { total_chunks++; } if (file->curr_chunk == total_chunks) { /* All chunks have been read! */ file->in_buffer = 0; file->finished = true; return true; } if (file->cursor == NULL) { _mongoc_gridfs_bucket_init_cursor (file); } r = mongoc_cursor_next (file->cursor, &next); if (mongoc_cursor_error (file->cursor, &file->err)) { return false; } if (!r) { bson_set_error ( &file->err, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, "Missing chunk %d.", file->curr_chunk); return false; } r = bson_iter_init_find (&iter, next, "n"); if (!r) { bson_set_error (&file->err, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "Chunk %d missing a required field 'n'.", file->curr_chunk); return false; } n = bson_iter_int32 (&iter); if (n != file->curr_chunk) { bson_set_error ( &file->err, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, "Missing chunk %d.", file->curr_chunk); return false; } r = bson_iter_init_find (&iter, next, "data"); if (!r) { bson_set_error (&file->err, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "Chunk %d missing a required field 'data'.", file->curr_chunk); return false; } bson_iter_binary (&iter, NULL, &data_len, &data); /* Assert that the data is the correct length */ if (file->curr_chunk != total_chunks - 1) { expected_size = file->chunk_size; } else { expected_size = file->length - ((total_chunks - 1) * file->chunk_size); } if (data_len != expected_size) { bson_set_error (&file->err, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "Chunk %d expected to have size %" PRId64 " but is size %" PRIu32 ".", file->curr_chunk, expected_size, data_len); return false; } memcpy (file->buffer, data, data_len); file->in_buffer = data_len; file->bytes_read = 0u; file->curr_chunk++; return true; } ssize_t _mongoc_gridfs_bucket_file_writev (mongoc_gridfs_bucket_file_t *file, const mongoc_iovec_t *iov, size_t iovcnt) { BSON_ASSERT (file); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); size_t total = 0; if (file->err.code) { return -1; } if (file->saved) { bson_set_error (&file->err, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_PROTOCOL_ERROR, "Cannot write after saving/aborting on a GridFS file."); return -1; } if (!file->bucket->indexed) { if (!_mongoc_gridfs_bucket_create_indexes (file->bucket, &file->err)) { /* Error is set on file. */ return -1; } else { file->bucket->indexed = true; } } BSON_ASSERT (mcommon_in_range_signed (size_t, file->chunk_size)); const size_t chunk_size = (size_t) file->chunk_size; for (size_t i = 0u; i < iovcnt; i++) { size_t written_this_iov = 0u; while (written_this_iov < iov[i].iov_len) { const size_t bytes_available = iov[i].iov_len - written_this_iov; const size_t space_available = chunk_size - file->in_buffer; const size_t to_write = _mongoc_min (bytes_available, space_available); memcpy (file->buffer + file->in_buffer, ((char *) iov[i].iov_base) + written_this_iov, to_write); file->in_buffer += to_write; written_this_iov += to_write; total += to_write; if (file->in_buffer == chunk_size) { /* Buffer is filled, write the chunk */ _mongoc_gridfs_bucket_write_chunk (file); } } } BSON_ASSERT (mcommon_in_range_unsigned (ssize_t, total)); return (ssize_t) total; } ssize_t _mongoc_gridfs_bucket_file_readv (mongoc_gridfs_bucket_file_t *file, mongoc_iovec_t *iov, size_t iovcnt) { BSON_ASSERT (file); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); if (file->err.code) { return -1; } if (file->finished) { return 0; } size_t total = 0u; for (size_t i = 0u; i < iovcnt; i++) { size_t read_this_iov = 0u; while (read_this_iov < iov[i].iov_len) { const size_t bytes_available = file->in_buffer - file->bytes_read; const size_t space_available = iov[i].iov_len - read_this_iov; const size_t to_read = _mongoc_min (bytes_available, space_available); memcpy (((char *) iov[i].iov_base) + read_this_iov, file->buffer + file->bytes_read, to_read); file->bytes_read += to_read; read_this_iov += to_read; total += to_read; if (file->bytes_read == file->in_buffer) { /* Everything in the current chunk has been read, so read a new * chunk */ if (!_mongoc_gridfs_bucket_read_chunk (file)) { /* an error occured while reading the chunk */ return -1; } if (file->finished) { /* There's nothing left to read */ BSON_ASSERT (mcommon_in_range_unsigned (ssize_t, total)); RETURN ((ssize_t) total); } } } } BSON_ASSERT (mcommon_in_range_unsigned (ssize_t, total)); RETURN ((ssize_t) total); } /*-------------------------------------------------------------------------- * * _mongoc_gridfs_bucket_file_save -- * * Saves the file to the files collection in gridFS. This locks the * file into GridFS, and no more chunks are allowed to be written. * * Return: * True if saved or no-op. False otherwise, and sets the file error. * *-------------------------------------------------------------------------- */ bool _mongoc_gridfs_bucket_file_save (mongoc_gridfs_bucket_file_t *file) { bson_t new_doc; int64_t length; bool r; BSON_ASSERT (file); if (file->saved) { /* Already saved, or aborted. */ return true; } if (file->err.code) { return false; } length = ((int64_t) file->curr_chunk) * file->chunk_size; if (file->in_buffer != 0) { length += file->in_buffer; _mongoc_gridfs_bucket_write_chunk (file); } file->length = length; bson_init (&new_doc); BSON_APPEND_VALUE (&new_doc, "_id", file->file_id); BSON_APPEND_INT64 (&new_doc, "length", file->length); BSON_APPEND_INT32 (&new_doc, "chunkSize", file->chunk_size); BSON_APPEND_DATE_TIME (&new_doc, "uploadDate", _mongoc_get_real_time_ms ()); BSON_APPEND_UTF8 (&new_doc, "filename", file->filename); if (file->metadata) { BSON_APPEND_DOCUMENT (&new_doc, "metadata", file->metadata); } r = mongoc_collection_insert_one (file->bucket->files, &new_doc, NULL, NULL, &file->err); bson_destroy (&new_doc); file->saved = r; return (file->err.code) ? false : true; } void _mongoc_gridfs_bucket_file_destroy (mongoc_gridfs_bucket_file_t *file) { if (file) { bson_value_destroy (file->file_id); bson_free (file->file_id); bson_destroy (file->metadata); mongoc_cursor_destroy (file->cursor); bson_free (file->buffer); bson_free (file->filename); bson_free (file); } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-bucket-private.h0000644000175100001660000000174514760300420025347 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_BUCKET_PRIVATE_H #define MONGOC_GRIDFS_BUCKET_PRIVATE_H #include BSON_BEGIN_DECLS struct _mongoc_gridfs_bucket_t { mongoc_collection_t *chunks; mongoc_collection_t *files; int32_t chunk_size; char *bucket_name; bool indexed; }; BSON_END_DECLS #endif /* MONGOC_GRIDFS_BUCKET_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c0000644000175100001660000003673514760300420023701 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include /*-------------------------------------------------------------------------- * * _mongoc_gridfs_find_file_with_id -- * * Attempts to find the file corresponding to the given file_id in * GridFS. * * Return: * True on success and initializes file. Otherwise, returns false * and sets error. * *-------------------------------------------------------------------------- */ static bool _mongoc_gridfs_find_file_with_id (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, bson_t *file, bson_error_t *error) { mongoc_cursor_t *cursor; bson_t filter; const bson_t *doc; bool r; BSON_ASSERT (bucket); BSON_ASSERT (file_id); bson_init (&filter); BSON_APPEND_VALUE (&filter, "_id", file_id); cursor = mongoc_collection_find_with_opts (bucket->files, &filter, NULL, NULL); bson_destroy (&filter); r = mongoc_cursor_next (cursor, &doc); if (!r) { if (!mongoc_cursor_error (cursor, error)) { bson_set_error ( error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_BUCKET_FILE_NOT_FOUND, "No file with given id exists"); } } else { if (file) { bson_copy_to (doc, file); } } mongoc_cursor_destroy (cursor); return r; } mongoc_gridfs_bucket_t * mongoc_gridfs_bucket_new (mongoc_database_t *db, const bson_t *opts, const mongoc_read_prefs_t *read_prefs, bson_error_t *error) { mongoc_gridfs_bucket_t *bucket; char buf[128]; mongoc_gridfs_bucket_opts_t gridfs_opts; BSON_ASSERT (db); if (!_mongoc_gridfs_bucket_opts_parse (db->client, opts, &gridfs_opts, error)) { _mongoc_gridfs_bucket_opts_cleanup (&gridfs_opts); return NULL; } /* Initialize the bucket fields */ if (strlen (gridfs_opts.bucketName) + strlen (".chunks") + 1 > sizeof (buf)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "bucketName \"%s\" must have fewer than %d characters", gridfs_opts.bucketName, (int) (sizeof (buf) - (strlen (".chunks") + 1))); return NULL; } bucket = (mongoc_gridfs_bucket_t *) bson_malloc0 (sizeof *bucket); // Expect no truncation from above, checking no error occurred. int req = bson_snprintf (buf, sizeof (buf), "%s.chunks", gridfs_opts.bucketName); BSON_ASSERT (req > 0); bucket->chunks = mongoc_database_get_collection (db, buf); req = bson_snprintf (buf, sizeof (buf), "%s.files", gridfs_opts.bucketName); BSON_ASSERT (req > 0); bucket->files = mongoc_database_get_collection (db, buf); if (gridfs_opts.writeConcern) { mongoc_collection_set_write_concern (bucket->chunks, gridfs_opts.writeConcern); mongoc_collection_set_write_concern (bucket->files, gridfs_opts.writeConcern); } if (gridfs_opts.readConcern) { mongoc_collection_set_read_concern (bucket->chunks, gridfs_opts.readConcern); mongoc_collection_set_read_concern (bucket->files, gridfs_opts.readConcern); } if (read_prefs) { mongoc_collection_set_read_prefs (bucket->chunks, read_prefs); mongoc_collection_set_read_prefs (bucket->files, read_prefs); } bucket->chunk_size = gridfs_opts.chunkSizeBytes; bucket->bucket_name = bson_strdup (gridfs_opts.bucketName); _mongoc_gridfs_bucket_opts_cleanup (&gridfs_opts); return bucket; } mongoc_stream_t * mongoc_gridfs_bucket_open_upload_stream_with_id (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, const char *filename, const bson_t *opts, bson_error_t *error) { mongoc_gridfs_bucket_file_t *file; size_t len; mongoc_gridfs_bucket_upload_opts_t gridfs_opts; BSON_ASSERT (bucket); BSON_ASSERT (file_id); BSON_ASSERT (filename); if (!_mongoc_gridfs_bucket_upload_opts_parse (bucket->files->client, opts, &gridfs_opts, error)) { _mongoc_gridfs_bucket_upload_opts_cleanup (&gridfs_opts); return NULL; } /* default to bucket's chunk size. */ if (!gridfs_opts.chunkSizeBytes) { gridfs_opts.chunkSizeBytes = bucket->chunk_size; } /* Initialize the file's fields */ len = strlen (filename); file = (mongoc_gridfs_bucket_file_t *) bson_malloc0 (sizeof *file); file->filename = bson_malloc0 (len + 1); bson_strncpy (file->filename, filename, len + 1); file->file_id = (bson_value_t *) bson_malloc0 (sizeof *(file->file_id)); bson_value_copy (file_id, file->file_id); file->bucket = bucket; file->chunk_size = gridfs_opts.chunkSizeBytes; file->metadata = bson_copy (&gridfs_opts.metadata); file->buffer = bson_malloc ((size_t) gridfs_opts.chunkSizeBytes); file->in_buffer = 0; _mongoc_gridfs_bucket_upload_opts_cleanup (&gridfs_opts); return _mongoc_upload_stream_gridfs_new (file); } mongoc_stream_t * mongoc_gridfs_bucket_open_upload_stream (mongoc_gridfs_bucket_t *bucket, const char *filename, const bson_t *opts, bson_value_t *file_id /* OUT */, bson_error_t *error) { mongoc_stream_t *stream; bson_oid_t object_id; bson_value_t val; BSON_ASSERT (bucket); BSON_ASSERT (filename); /* Create an objectId to use as the file's id */ bson_oid_init (&object_id, NULL); val.value_type = BSON_TYPE_OID; val.value.v_oid = object_id; stream = mongoc_gridfs_bucket_open_upload_stream_with_id (bucket, &val, filename, opts, error); if (!stream) { return NULL; } if (file_id) { bson_value_copy (&val, file_id); } return stream; } bool mongoc_gridfs_bucket_upload_from_stream_with_id (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, const char *filename, mongoc_stream_t *source, const bson_t *opts, bson_error_t *error) { mongoc_stream_t *upload_stream; ssize_t bytes_read; ssize_t bytes_written; char buf[512]; BSON_ASSERT (bucket); BSON_ASSERT (file_id); BSON_ASSERT (filename); BSON_ASSERT (source); upload_stream = mongoc_gridfs_bucket_open_upload_stream_with_id (bucket, file_id, filename, opts, error); if (!upload_stream) { return false; } while ((bytes_read = mongoc_stream_read (source, buf, 512, 1, 0)) > 0) { bytes_written = mongoc_stream_write (upload_stream, buf, bytes_read, 0); if (bytes_written < 0) { BSON_ASSERT (mongoc_gridfs_bucket_stream_error (upload_stream, error)); mongoc_gridfs_bucket_abort_upload (upload_stream); mongoc_stream_destroy (upload_stream); return false; } } if (bytes_read < 0) { mongoc_gridfs_bucket_abort_upload (upload_stream); bson_set_error ( error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_BUCKET_STREAM, "Error occurred on the provided stream."); mongoc_stream_destroy (upload_stream); return false; } else { mongoc_stream_destroy (upload_stream); return true; } } bool mongoc_gridfs_bucket_upload_from_stream (mongoc_gridfs_bucket_t *bucket, const char *filename, mongoc_stream_t *source, const bson_t *opts, bson_value_t *file_id /* OUT */, bson_error_t *error) { bool r; bson_oid_t object_id; bson_value_t val; BSON_ASSERT (bucket); BSON_ASSERT (filename); BSON_ASSERT (source); /* Create an objectId to use as the file's id */ bson_oid_init (&object_id, bson_context_get_default ()); val.value_type = BSON_TYPE_OID; val.value.v_oid = object_id; r = mongoc_gridfs_bucket_upload_from_stream_with_id (bucket, &val, filename, source, opts, error); if (!r) { return false; } if (file_id) { bson_value_copy (&val, file_id); } return true; } mongoc_stream_t * mongoc_gridfs_bucket_open_download_stream (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, bson_error_t *error) { mongoc_gridfs_bucket_file_t *file; bson_t file_doc; const char *key; bson_iter_t iter; uint32_t data_len; const uint8_t *data; bool r; BSON_ASSERT (bucket); BSON_ASSERT (file_id); r = _mongoc_gridfs_find_file_with_id (bucket, file_id, &file_doc, error); if (!r) { /* Error should already be set. */ return NULL; } if (!bson_iter_init (&iter, &file_doc)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "File document malformed"); return NULL; } file = (mongoc_gridfs_bucket_file_t *) bson_malloc0 (sizeof *file); while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (strcmp (key, "length") == 0) { file->length = bson_iter_as_int64 (&iter); } else if (strcmp (key, "chunkSize") == 0) { file->chunk_size = bson_iter_int32 (&iter); } else if (strcmp (key, "filename") == 0) { file->filename = bson_strdup (bson_iter_utf8 (&iter, NULL)); } else if (strcmp (key, "metadata") == 0) { bson_iter_document (&iter, &data_len, &data); file->metadata = bson_new_from_data (data, data_len); } } bson_destroy (&file_doc); file->file_id = (bson_value_t *) bson_malloc0 (sizeof *(file->file_id)); bson_value_copy (file_id, file->file_id); file->bucket = bucket; file->buffer = bson_malloc0 ((size_t) file->chunk_size); BSON_ASSERT (file->file_id); return _mongoc_download_stream_gridfs_new (file); } bool mongoc_gridfs_bucket_download_to_stream (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, mongoc_stream_t *destination, bson_error_t *error) { mongoc_stream_t *download_stream; ssize_t bytes_read; ssize_t bytes_written; char buf[512]; BSON_ASSERT (bucket); BSON_ASSERT (file_id); BSON_ASSERT (destination); /* Make the download stream */ download_stream = mongoc_gridfs_bucket_open_download_stream (bucket, file_id, error); while ((bytes_read = mongoc_stream_read (download_stream, buf, 256, 1, 0)) > 0) { bytes_written = mongoc_stream_write (destination, buf, bytes_read, 0); if (bytes_written < 0) { bson_set_error ( error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_BUCKET_STREAM, "Error occurred on the provided stream."); mongoc_stream_destroy (download_stream); return false; } } mongoc_stream_destroy (download_stream); return bytes_read != -1; } bool mongoc_gridfs_bucket_delete_by_id (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, bson_error_t *error) { bson_t files_selector; bson_t chunks_selector; bson_t reply; bson_iter_t iter; bool r; BSON_ASSERT (bucket); BSON_ASSERT (file_id); bson_init (&files_selector); BSON_APPEND_VALUE (&files_selector, "_id", file_id); r = mongoc_collection_delete_one (bucket->files, &files_selector, NULL, &reply, error); bson_destroy (&files_selector); if (!r) { bson_destroy (&reply); return false; } BSON_ASSERT (bson_iter_init_find (&iter, &reply, "deletedCount")); if (bson_iter_as_int64 (&iter) != 1) { bson_set_error (error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_BUCKET_FILE_NOT_FOUND, "File not found"); bson_destroy (&reply); return false; } bson_destroy (&reply); bson_init (&chunks_selector); BSON_APPEND_VALUE (&chunks_selector, "files_id", file_id); r = mongoc_collection_delete_many (bucket->chunks, &chunks_selector, NULL, NULL, error); bson_destroy (&chunks_selector); if (!r) { return false; } return true; } mongoc_cursor_t * mongoc_gridfs_bucket_find (mongoc_gridfs_bucket_t *bucket, const bson_t *filter, const bson_t *opts) { mongoc_cursor_t *cursor; BSON_ASSERT (bucket); BSON_ASSERT (filter); cursor = mongoc_collection_find_with_opts (bucket->files, filter, opts, NULL); if (!cursor->error.code && opts && bson_has_field (opts, "sessionId")) { bson_set_error ( &cursor->error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "Cannot pass sessionId as an option"); } return cursor; } bool mongoc_gridfs_bucket_stream_error (mongoc_stream_t *stream, bson_error_t *error) { bson_error_t *stream_err; BSON_ASSERT (stream); BSON_ASSERT (error); if (stream->type == MONGOC_STREAM_GRIDFS_UPLOAD) { stream_err = &((mongoc_gridfs_upload_stream_t *) stream)->file->err; } else if (stream->type == MONGOC_STREAM_GRIDFS_DOWNLOAD) { stream_err = &((mongoc_gridfs_download_stream_t *) stream)->file->err; } else { return false; } if (stream_err->code) { memcpy (error, stream_err, sizeof (*stream_err)); return true; } else { return false; } } void mongoc_gridfs_bucket_destroy (mongoc_gridfs_bucket_t *bucket) { if (bucket) { mongoc_collection_destroy (bucket->chunks); mongoc_collection_destroy (bucket->files); bson_free (bucket->bucket_name); bson_free (bucket); } } bool mongoc_gridfs_bucket_abort_upload (mongoc_stream_t *stream) { mongoc_gridfs_bucket_file_t *file; bson_t chunks_selector; bool r; BSON_ASSERT (stream); BSON_ASSERT (stream->type == MONGOC_STREAM_GRIDFS_UPLOAD); file = ((mongoc_gridfs_upload_stream_t *) stream)->file; /* Pretend we've already saved. This way we won't add an entry to the files * collection when the stream is closed */ file->saved = true; bson_init (&chunks_selector); BSON_APPEND_VALUE (&chunks_selector, "files_id", file->file_id); r = mongoc_collection_delete_many (file->bucket->chunks, &chunks_selector, NULL, NULL, &file->err); bson_destroy (&chunks_selector); return r; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-bucket.h0000644000175100001660000001007314760300420023671 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_BUCKET_H #define MONGOC_GRIDFS_BUCKET_H #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_gridfs_bucket_t mongoc_gridfs_bucket_t; MONGOC_EXPORT (mongoc_gridfs_bucket_t *) mongoc_gridfs_bucket_new (mongoc_database_t *db, const bson_t *opts, const mongoc_read_prefs_t *read_prefs, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_stream_t *) mongoc_gridfs_bucket_open_upload_stream (mongoc_gridfs_bucket_t *bucket, const char *filename, const bson_t *opts, bson_value_t *file_id, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_stream_t *) mongoc_gridfs_bucket_open_upload_stream_with_id (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, const char *filename, const bson_t *opts, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_gridfs_bucket_upload_from_stream (mongoc_gridfs_bucket_t *bucket, const char *filename, mongoc_stream_t *source, const bson_t *opts, bson_value_t *file_id, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_gridfs_bucket_upload_from_stream_with_id (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, const char *filename, mongoc_stream_t *source, const bson_t *opts, bson_error_t *error); MONGOC_EXPORT (mongoc_stream_t *) mongoc_gridfs_bucket_open_download_stream (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_gridfs_bucket_download_to_stream (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, mongoc_stream_t *destination, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_gridfs_bucket_delete_by_id (mongoc_gridfs_bucket_t *bucket, const bson_value_t *file_id, bson_error_t *error); MONGOC_EXPORT (mongoc_cursor_t *) mongoc_gridfs_bucket_find (mongoc_gridfs_bucket_t *bucket, const bson_t *filter, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_gridfs_bucket_stream_error (mongoc_stream_t *stream, bson_error_t *error); MONGOC_EXPORT (void) mongoc_gridfs_bucket_destroy (mongoc_gridfs_bucket_t *bucket); MONGOC_EXPORT (bool) mongoc_gridfs_bucket_abort_upload (mongoc_stream_t *stream); BSON_END_DECLS #endif /* MONGOC_GRIDFS_BUCKET_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file-list-private.h0000644000175100001660000000245014760300420025754 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_FILE_LIST_PRIVATE_H #define MONGOC_GRIDFS_FILE_LIST_PRIVATE_H #include #include #include #include BSON_BEGIN_DECLS struct _mongoc_gridfs_file_list_t { mongoc_gridfs_t *gridfs; mongoc_cursor_t *cursor; bson_error_t error; }; mongoc_gridfs_file_list_t * _mongoc_gridfs_file_list_new (mongoc_gridfs_t *gridfs, const bson_t *query, uint32_t limit); mongoc_gridfs_file_list_t * _mongoc_gridfs_file_list_new_with_opts (mongoc_gridfs_t *gridfs, const bson_t *filter, const bson_t *opts); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_LIST_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file-list.c0000644000175100001660000000647614760300420024313 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs_file_list" mongoc_gridfs_file_list_t * _mongoc_gridfs_file_list_new (mongoc_gridfs_t *gridfs, const bson_t *query, uint32_t limit) { mongoc_gridfs_file_list_t *list; mongoc_cursor_t *cursor; bool use_unwrapped; bson_t opts; bson_t unwrapped; bson_error_t error; bson_init (&opts); use_unwrapped = _mongoc_cursor_translate_dollar_query_opts (query, &opts, &unwrapped, &error); cursor = _mongoc_cursor_find_new (gridfs->client, gridfs->files->ns, use_unwrapped ? &unwrapped : query, &opts, NULL, gridfs->files->read_prefs, gridfs->files->read_concern); BSON_ASSERT (cursor); bson_destroy (&opts); if (limit) { (void) mongoc_cursor_set_limit (cursor, limit); } bson_destroy (&unwrapped); if (error.domain) { memcpy (&cursor->error, &error, sizeof (bson_error_t)); } list = (mongoc_gridfs_file_list_t *) bson_malloc0 (sizeof *list); list->cursor = cursor; list->gridfs = gridfs; return list; } mongoc_gridfs_file_list_t * _mongoc_gridfs_file_list_new_with_opts (mongoc_gridfs_t *gridfs, const bson_t *filter, const bson_t *opts) { mongoc_gridfs_file_list_t *list; mongoc_cursor_t *cursor; cursor = mongoc_collection_find_with_opts (gridfs->files, filter, opts, NULL /* read prefs */); BSON_ASSERT (cursor); list = (mongoc_gridfs_file_list_t *) bson_malloc0 (sizeof *list); list->cursor = cursor; list->gridfs = gridfs; return list; } mongoc_gridfs_file_t * mongoc_gridfs_file_list_next (mongoc_gridfs_file_list_t *list) { const bson_t *bson; BSON_ASSERT (list); if (mongoc_cursor_next (list->cursor, &bson)) { return _mongoc_gridfs_file_new_from_bson (list->gridfs, bson); } else { return NULL; } } bool mongoc_gridfs_file_list_error (mongoc_gridfs_file_list_t *list, bson_error_t *error) { return mongoc_cursor_error (list->cursor, error); } void mongoc_gridfs_file_list_destroy (mongoc_gridfs_file_list_t *list) { if (!list) { return; } mongoc_cursor_destroy (list->cursor); bson_free (list); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file-list.h0000644000175100001660000000240314760300420024302 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_FILE_LIST_H #define MONGOC_GRIDFS_FILE_LIST_H #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_gridfs_file_list_t mongoc_gridfs_file_list_t; MONGOC_EXPORT (mongoc_gridfs_file_t *) mongoc_gridfs_file_list_next (mongoc_gridfs_file_list_t *list) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_gridfs_file_list_destroy (mongoc_gridfs_file_list_t *list); MONGOC_EXPORT (bool) mongoc_gridfs_file_list_error (mongoc_gridfs_file_list_t *list, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_LIST_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file-page-private.h0000644000175100001660000000355514760300420025724 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_FILE_PAGE_PRIVATE_H #define MONGOC_GRIDFS_FILE_PAGE_PRIVATE_H #include #include BSON_BEGIN_DECLS struct _mongoc_gridfs_file_page_t { const uint8_t *read_buf; uint8_t *buf; uint32_t len; uint32_t chunk_size; uint32_t offset; }; mongoc_gridfs_file_page_t * _mongoc_gridfs_file_page_new (const uint8_t *data, uint32_t len, uint32_t chunk_size); void _mongoc_gridfs_file_page_destroy (mongoc_gridfs_file_page_t *page); bool _mongoc_gridfs_file_page_seek (mongoc_gridfs_file_page_t *page, uint32_t offset); int32_t _mongoc_gridfs_file_page_read (mongoc_gridfs_file_page_t *page, void *dst, uint32_t len); int32_t _mongoc_gridfs_file_page_write (mongoc_gridfs_file_page_t *page, const void *src, uint32_t len); uint32_t _mongoc_gridfs_file_page_memset0 (mongoc_gridfs_file_page_t *page, uint32_t len); uint32_t _mongoc_gridfs_file_page_tell (mongoc_gridfs_file_page_t *page); const uint8_t * _mongoc_gridfs_file_page_get_data (mongoc_gridfs_file_page_t *page); uint32_t _mongoc_gridfs_file_page_get_len (mongoc_gridfs_file_page_t *page); bool _mongoc_gridfs_file_page_is_dirty (mongoc_gridfs_file_page_t *page); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_PAGE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file-page.c0000644000175100001660000001146714760300420024250 0ustar /* * Copyright 2009-present MongoDB, 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. */ #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs_file_page" #include #include #include /** create a new page from a buffer * * The buffer should stick around for the life of the page */ mongoc_gridfs_file_page_t * _mongoc_gridfs_file_page_new (const uint8_t *data, uint32_t len, uint32_t chunk_size) { mongoc_gridfs_file_page_t *page; ENTRY; BSON_ASSERT (data); BSON_ASSERT (len <= chunk_size); page = (mongoc_gridfs_file_page_t *) bson_malloc0 (sizeof *page); page->chunk_size = chunk_size; page->read_buf = data; page->len = len; RETURN (page); } bool _mongoc_gridfs_file_page_seek (mongoc_gridfs_file_page_t *page, uint32_t offset) { ENTRY; BSON_ASSERT (page); page->offset = offset; RETURN (1); } int32_t _mongoc_gridfs_file_page_read (mongoc_gridfs_file_page_t *page, void *dst, uint32_t len) { int bytes_read; const uint8_t *src; ENTRY; BSON_ASSERT (page); BSON_ASSERT (dst); bytes_read = BSON_MIN (len, page->len - page->offset); src = page->read_buf ? page->read_buf : page->buf; memcpy (dst, src + page->offset, bytes_read); page->offset += bytes_read; RETURN (bytes_read); } /** * _mongoc_gridfs_file_page_write: * * Write to a page. * * Writes are copy-on-write with regards to the buffer that was passed to the * mongoc_gridfs_file_page_t during construction. In other words, the first * write allocates a large enough buffer for file->chunk_size, which becomes * authoritative from then on. * * A write of zero bytes will trigger the copy-on-write mechanism. */ int32_t _mongoc_gridfs_file_page_write (mongoc_gridfs_file_page_t *page, const void *src, uint32_t len) { int bytes_written; ENTRY; BSON_ASSERT (page); BSON_ASSERT (src); bytes_written = BSON_MIN (len, page->chunk_size - page->offset); if (!page->buf) { page->buf = (uint8_t *) bson_malloc (page->chunk_size); memcpy (page->buf, page->read_buf, BSON_MIN (page->chunk_size, page->len)); } /* Copy bytes and adjust the page position */ memcpy (page->buf + page->offset, src, bytes_written); page->offset += bytes_written; page->len = BSON_MAX (page->offset, page->len); /* Don't use the old read buffer, which is no longer current */ page->read_buf = page->buf; RETURN (bytes_written); } /** * _mongoc_gridfs_file_page_memset0: * * Write zeros to a page, starting from the page's current position. Up to * `len` bytes will be set to zero or until the page is full, whichever * comes first. * * Like _mongoc_gridfs_file_page_write, operations are copy-on-write with * regards to the page buffer. * * Returns: * Number of bytes set. */ uint32_t _mongoc_gridfs_file_page_memset0 (mongoc_gridfs_file_page_t *page, uint32_t len) { uint32_t bytes_set; ENTRY; BSON_ASSERT (page); bytes_set = BSON_MIN (page->chunk_size - page->offset, len); if (!page->buf) { page->buf = (uint8_t *) bson_malloc0 (page->chunk_size); memcpy (page->buf, page->read_buf, BSON_MIN (page->chunk_size, page->len)); } /* Set bytes and adjust the page position */ memset (page->buf + page->offset, '\0', bytes_set); page->offset += bytes_set; page->len = BSON_MAX (page->offset, page->len); /* Don't use the old read buffer, which is no longer current */ page->read_buf = page->buf; RETURN (bytes_set); } const uint8_t * _mongoc_gridfs_file_page_get_data (mongoc_gridfs_file_page_t *page) { ENTRY; BSON_ASSERT (page); RETURN (page->buf ? page->buf : page->read_buf); } uint32_t _mongoc_gridfs_file_page_get_len (mongoc_gridfs_file_page_t *page) { ENTRY; BSON_ASSERT (page); RETURN (page->len); } uint32_t _mongoc_gridfs_file_page_tell (mongoc_gridfs_file_page_t *page) { ENTRY; BSON_ASSERT (page); RETURN (page->offset); } bool _mongoc_gridfs_file_page_is_dirty (mongoc_gridfs_file_page_t *page) { ENTRY; BSON_ASSERT (page); RETURN (page->buf ? 1 : 0); } void _mongoc_gridfs_file_page_destroy (mongoc_gridfs_file_page_t *page) { ENTRY; if (page->buf) { bson_free (page->buf); } bson_free (page); EXIT; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file-page.h0000644000175100001660000000174614760300420024254 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_FILE_PAGE_H #define MONGOC_GRIDFS_FILE_PAGE_H #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_gridfs_file_page_t mongoc_gridfs_file_page_t; BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_PAGE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file-private.h0000644000175100001660000000337214760300420025007 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_FILE_PRIVATE_H #define MONGOC_GRIDFS_FILE_PRIVATE_H #include #include #include #include #include BSON_BEGIN_DECLS struct _mongoc_gridfs_file_t { mongoc_gridfs_t *gridfs; bson_t bson; mongoc_gridfs_file_page_t *page; uint64_t pos; int32_t n; bson_error_t error; mongoc_cursor_t *cursor; uint32_t cursor_range[2]; /* current chunk, # of chunks */ bool is_dirty; bson_value_t files_id; int64_t length; int32_t chunk_size; int64_t upload_date; char *md5; char *filename; char *content_type; bson_t aliases; bson_t metadata; const char *bson_md5; const char *bson_filename; const char *bson_content_type; bson_t bson_aliases; bson_t bson_metadata; }; mongoc_gridfs_file_t * _mongoc_gridfs_file_new_from_bson (mongoc_gridfs_t *gridfs, const bson_t *data); mongoc_gridfs_file_t * _mongoc_gridfs_file_new (mongoc_gridfs_t *gridfs, mongoc_gridfs_file_opt_t *opt); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file.c0000644000175100001660000007252714760300420023342 0ustar /* * Copyright 2009-present MongoDB, 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. */ #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs_file" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static bool _mongoc_gridfs_file_refresh_page (mongoc_gridfs_file_t *file); static bool _mongoc_gridfs_file_flush_page (mongoc_gridfs_file_t *file); static ssize_t _mongoc_gridfs_file_extend (mongoc_gridfs_file_t *file); /***************************************************************** * Magic accessor generation * * We need some accessors to get and set properties on files, to handle memory * ownership and to determine dirtiness. These macros produce the getters and * setters we need *****************************************************************/ #define MONGOC_GRIDFS_FILE_STR_ACCESSOR(name) \ const char *mongoc_gridfs_file_get_##name (mongoc_gridfs_file_t *file) \ { \ return file->name ? file->name : file->bson_##name; \ } \ void mongoc_gridfs_file_set_##name (mongoc_gridfs_file_t *file, const char *str) \ { \ if (file->name) { \ bson_free (file->name); \ } \ file->name = bson_strdup (str); \ file->is_dirty = 1; \ } #define MONGOC_GRIDFS_FILE_BSON_ACCESSOR(name) \ const bson_t *mongoc_gridfs_file_get_##name (mongoc_gridfs_file_t *file) \ { \ if (file->name.len) { \ return &file->name; \ } else if (file->bson_##name.len) { \ return &file->bson_##name; \ } else { \ return NULL; \ } \ } \ void mongoc_gridfs_file_set_##name (mongoc_gridfs_file_t *file, const bson_t *bson) \ { \ if (file->name.len) { \ bson_destroy (&file->name); \ } \ bson_copy_to (bson, &(file->name)); \ file->is_dirty = 1; \ } MONGOC_GRIDFS_FILE_STR_ACCESSOR (md5) MONGOC_GRIDFS_FILE_STR_ACCESSOR (filename) MONGOC_GRIDFS_FILE_STR_ACCESSOR (content_type) MONGOC_GRIDFS_FILE_BSON_ACCESSOR (aliases) MONGOC_GRIDFS_FILE_BSON_ACCESSOR (metadata) /** * mongoc_gridfs_file_set_id: * * the user can set the files_id to an id of any type. Must be called before * mongoc_gridfs_file_save. * */ bool mongoc_gridfs_file_set_id (mongoc_gridfs_file_t *file, const bson_value_t *id, bson_error_t *error) { if (!file->is_dirty) { bson_set_error ( error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_PROTOCOL_ERROR, "Cannot set file id after saving file."); return false; } bson_value_copy (id, &file->files_id); return true; } /** save a gridfs file */ bool mongoc_gridfs_file_save (mongoc_gridfs_file_t *file) { bson_t *selector, *update, child; const char *md5; const char *filename; const char *content_type; const bson_t *aliases; const bson_t *metadata; bool r; ENTRY; if (!file->is_dirty) { return 1; } if (file->page && _mongoc_gridfs_file_page_is_dirty (file->page)) { if (!_mongoc_gridfs_file_flush_page (file)) { RETURN (false); } } md5 = mongoc_gridfs_file_get_md5 (file); filename = mongoc_gridfs_file_get_filename (file); content_type = mongoc_gridfs_file_get_content_type (file); aliases = mongoc_gridfs_file_get_aliases (file); metadata = mongoc_gridfs_file_get_metadata (file); selector = bson_new (); bson_append_value (selector, "_id", -1, &file->files_id); update = bson_new (); bson_append_document_begin (update, "$set", -1, &child); bson_append_int64 (&child, "length", -1, file->length); bson_append_int32 (&child, "chunkSize", -1, file->chunk_size); bson_append_date_time (&child, "uploadDate", -1, file->upload_date); if (md5) { bson_append_utf8 (&child, "md5", -1, md5, -1); } if (filename) { bson_append_utf8 (&child, "filename", -1, filename, -1); } if (content_type) { bson_append_utf8 (&child, "contentType", -1, content_type, -1); } if (aliases) { bson_append_array (&child, "aliases", -1, aliases); } if (metadata) { bson_append_document (&child, "metadata", -1, metadata); } bson_append_document_end (update, &child); r = mongoc_collection_update (file->gridfs->files, MONGOC_UPDATE_UPSERT, selector, update, NULL, &file->error); bson_destroy (selector); bson_destroy (update); file->is_dirty = 0; RETURN (r); } /** * _mongoc_gridfs_file_new_from_bson: * * creates a gridfs file from a bson object * * This is only really useful for instantiating a gridfs file from a server * side object */ mongoc_gridfs_file_t * _mongoc_gridfs_file_new_from_bson (mongoc_gridfs_t *gridfs, const bson_t *data) { mongoc_gridfs_file_t *file; const bson_value_t *value; const char *key; bson_iter_t iter; const uint8_t *buf; uint32_t buf_len; ENTRY; BSON_ASSERT (gridfs); BSON_ASSERT (data); file = BSON_ALIGNED_ALLOC0 (mongoc_gridfs_file_t); file->gridfs = gridfs; bson_copy_to (data, &file->bson); if (!bson_iter_init (&iter, &file->bson)) { GOTO (failure); } while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (0 == strcmp (key, "_id")) { value = bson_iter_value (&iter); bson_value_copy (value, &file->files_id); } else if (0 == strcmp (key, "length")) { if (!BSON_ITER_HOLDS_NUMBER (&iter)) { GOTO (failure); } file->length = bson_iter_as_int64 (&iter); } else if (0 == strcmp (key, "chunkSize")) { if (!BSON_ITER_HOLDS_NUMBER (&iter)) { GOTO (failure); } if (bson_iter_as_int64 (&iter) > INT32_MAX) { GOTO (failure); } file->chunk_size = (int32_t) bson_iter_as_int64 (&iter); } else if (0 == strcmp (key, "uploadDate")) { if (!BSON_ITER_HOLDS_DATE_TIME (&iter)) { GOTO (failure); } file->upload_date = bson_iter_date_time (&iter); } else if (0 == strcmp (key, "md5")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { GOTO (failure); } file->bson_md5 = bson_iter_utf8 (&iter, NULL); } else if (0 == strcmp (key, "filename")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { GOTO (failure); } file->bson_filename = bson_iter_utf8 (&iter, NULL); } else if (0 == strcmp (key, "contentType")) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) { GOTO (failure); } file->bson_content_type = bson_iter_utf8 (&iter, NULL); } else if (0 == strcmp (key, "aliases")) { if (!BSON_ITER_HOLDS_ARRAY (&iter)) { GOTO (failure); } bson_iter_array (&iter, &buf_len, &buf); if (!bson_init_static (&file->bson_aliases, buf, buf_len)) { GOTO (failure); } } else if (0 == strcmp (key, "metadata")) { if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { GOTO (failure); } bson_iter_document (&iter, &buf_len, &buf); if (!bson_init_static (&file->bson_metadata, buf, buf_len)) { GOTO (failure); } } } /* TODO: is there are a minimal object we should be verifying that we * actually have here? */ RETURN (file); failure: bson_destroy (&file->bson); RETURN (NULL); } /** * _mongoc_gridfs_file_new: * * Create a new empty gridfs file */ mongoc_gridfs_file_t * _mongoc_gridfs_file_new (mongoc_gridfs_t *gridfs, mongoc_gridfs_file_opt_t *opt) { mongoc_gridfs_file_t *file; mongoc_gridfs_file_opt_t default_opt = {0}; ENTRY; BSON_ASSERT (gridfs); if (!opt) { opt = &default_opt; } file = BSON_ALIGNED_ALLOC0 (mongoc_gridfs_file_t); file->gridfs = gridfs; file->is_dirty = 1; if (opt->chunk_size) { file->chunk_size = opt->chunk_size; } else { /* * The default chunk size is now 255kb. This used to be 256k but has been * reduced to allow for them to fit within power of two sizes in mongod. * * See CDRIVER-322. */ file->chunk_size = (1 << 18) - 1024; } file->files_id.value_type = BSON_TYPE_OID; bson_oid_init (&file->files_id.value.v_oid, NULL); file->upload_date = _mongoc_get_real_time_ms (); if (opt->md5) { file->md5 = bson_strdup (opt->md5); } if (opt->filename) { file->filename = bson_strdup (opt->filename); } if (opt->content_type) { file->content_type = bson_strdup (opt->content_type); } if (opt->aliases) { bson_copy_to (opt->aliases, &(file->aliases)); } if (opt->metadata) { bson_copy_to (opt->metadata, &(file->metadata)); } file->pos = 0; file->n = 0; RETURN (file); } void mongoc_gridfs_file_destroy (mongoc_gridfs_file_t *file) { ENTRY; if (!file) { EXIT; } if (file->page) { _mongoc_gridfs_file_page_destroy (file->page); } if (file->bson.len) { bson_destroy (&file->bson); } if (file->cursor) { mongoc_cursor_destroy (file->cursor); } if (file->files_id.value_type) { bson_value_destroy (&file->files_id); } if (file->md5) { bson_free (file->md5); } if (file->filename) { bson_free (file->filename); } if (file->content_type) { bson_free (file->content_type); } if (file->aliases.len) { bson_destroy (&file->aliases); } if (file->bson_aliases.len) { bson_destroy (&file->bson_aliases); } if (file->metadata.len) { bson_destroy (&file->metadata); } if (file->bson_metadata.len) { bson_destroy (&file->bson_metadata); } bson_free (file); EXIT; } /** readv against a gridfs file * timeout_msec is unused */ ssize_t mongoc_gridfs_file_readv ( mongoc_gridfs_file_t *file, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, uint32_t timeout_msec) { uint32_t bytes_read = 0; int32_t r; size_t i; uint32_t iov_pos; ENTRY; BSON_UNUSED (timeout_msec); BSON_ASSERT (file); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); /* Reading when positioned past the end does nothing */ if (mcommon_cmp_greater_equal_us (file->pos, file->length)) { return 0; } /* Try to get the current chunk */ if (!file->page && !_mongoc_gridfs_file_refresh_page (file)) { return -1; } for (i = 0; i < iovcnt; i++) { iov_pos = 0; for (;;) { r = _mongoc_gridfs_file_page_read ( file->page, (uint8_t *) iov[i].iov_base + iov_pos, (uint32_t) (iov[i].iov_len - iov_pos)); BSON_ASSERT (r >= 0); iov_pos += r; file->pos += r; bytes_read += r; if (iov_pos == iov[i].iov_len) { /* filled a bucket, keep going */ break; } else if (file->length == file->pos) { /* we're at the end of the file. So we're done */ RETURN (bytes_read); } else if (bytes_read >= min_bytes) { /* we need a new page, but we've read enough bytes to stop */ RETURN (bytes_read); } else if (!_mongoc_gridfs_file_refresh_page (file)) { return -1; } } } RETURN (bytes_read); } /** writev against a gridfs file * timeout_msec is unused */ ssize_t mongoc_gridfs_file_writev (mongoc_gridfs_file_t *file, const mongoc_iovec_t *iov, size_t iovcnt, uint32_t timeout_msec) { uint32_t bytes_written = 0; int32_t r; size_t i; uint32_t iov_pos; ENTRY; BSON_UNUSED (timeout_msec); BSON_ASSERT (file); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); /* Pull in the correct page */ if (!file->page && !_mongoc_gridfs_file_refresh_page (file)) { return -1; } /* When writing past the end-of-file, fill the gap with zeros */ if (mcommon_cmp_greater_us (file->pos, file->length) && !_mongoc_gridfs_file_extend (file)) { return -1; } for (i = 0; i < iovcnt; i++) { iov_pos = 0; for (;;) { if (!file->page && !_mongoc_gridfs_file_refresh_page (file)) { return -1; } /* write bytes until an iov is exhausted or the page is full */ r = _mongoc_gridfs_file_page_write ( file->page, (uint8_t *) iov[i].iov_base + iov_pos, (uint32_t) (iov[i].iov_len - iov_pos)); BSON_ASSERT (r >= 0); iov_pos += r; file->pos += r; bytes_written += r; file->length = BSON_MAX (file->length, (int64_t) file->pos); if (iov_pos == iov[i].iov_len) { /** filled a bucket, keep going */ break; } else { /** flush the buffer, the next pass through will bring in a new page */ if (!_mongoc_gridfs_file_flush_page (file)) { return -1; } } } } file->is_dirty = 1; RETURN (bytes_written); } /** * _mongoc_gridfs_file_extend: * * Extend a GridFS file to the current position pointer. Zeros will be * appended to the end of the file until file->length is even with * file->pos. * * If file->length >= file->pos, the function exits successfully with no * operation performed. * * Parameters: * @file: A mongoc_gridfs_file_t. * * Returns: * The number of zero bytes written, or -1 on failure. */ static ssize_t _mongoc_gridfs_file_extend (mongoc_gridfs_file_t *file) { ENTRY; BSON_ASSERT (file); if (mcommon_cmp_greater_equal_su (file->length, file->pos)) { RETURN (0); } const uint64_t target_length = file->pos; BSON_ASSERT (mcommon_in_range_signed (uint64_t, file->length)); const uint64_t diff = file->pos - (uint64_t) file->length; if (-1 == mongoc_gridfs_file_seek (file, 0, SEEK_END)) { RETURN (-1); } while (true) { if (!file->page && !_mongoc_gridfs_file_refresh_page (file)) { RETURN (-1); } /* Set bytes until we reach the limit or fill a page */ { const uint64_t len = target_length - file->pos; BSON_ASSERT (mcommon_in_range_unsigned (uint32_t, len)); file->pos += _mongoc_gridfs_file_page_memset0 (file->page, (uint32_t) len); } if (file->pos == target_length) { /* We're done */ break; } else if (!_mongoc_gridfs_file_flush_page (file)) { /* We tried to flush a full buffer, but an error occurred */ RETURN (-1); } } BSON_ASSERT (mcommon_in_range_unsigned (int64_t, target_length)); file->length = (int64_t) target_length; file->is_dirty = true; BSON_ASSERT (mcommon_in_range_unsigned (ssize_t, diff)); RETURN ((ssize_t) diff); } /** * _mongoc_gridfs_file_flush_page: * * Unconditionally flushes the file's current page to the database. * The page to flush is determined by page->n. * * Side Effects: * * On success, file->page is properly destroyed and set to NULL. * * Returns: * * True on success; false otherwise. */ static bool _mongoc_gridfs_file_flush_page (mongoc_gridfs_file_t *file) { bson_t *selector, *update; bool r; const uint8_t *buf; uint32_t len; ENTRY; BSON_ASSERT (file); BSON_ASSERT (file->page); buf = _mongoc_gridfs_file_page_get_data (file->page); len = _mongoc_gridfs_file_page_get_len (file->page); selector = bson_new (); bson_append_value (selector, "files_id", -1, &file->files_id); bson_append_int32 (selector, "n", -1, file->n); update = bson_sized_new (file->chunk_size + 100); bson_append_value (update, "files_id", -1, &file->files_id); bson_append_int32 (update, "n", -1, file->n); bson_append_binary (update, "data", -1, BSON_SUBTYPE_BINARY, buf, len); r = mongoc_collection_update (file->gridfs->chunks, MONGOC_UPDATE_UPSERT, selector, update, NULL, &file->error); bson_destroy (selector); bson_destroy (update); if (r) { _mongoc_gridfs_file_page_destroy (file->page); file->page = NULL; r = mongoc_gridfs_file_save (file); } RETURN (r); } /** * _mongoc_gridfs_file_keep_cursor: * * After a seek, decide if the next read should use the current cursor or * start a new query. * * Preconditions: * * file has a cursor and cursor range. * * Side Effects: * * None. */ static bool _mongoc_gridfs_file_keep_cursor (mongoc_gridfs_file_t *file) { uint32_t chunk_no; uint32_t chunks_per_batch; if (file->n < 0 || file->chunk_size <= 0) { return false; } chunk_no = (uint32_t) file->n; /* server returns roughly 4 MB batches by default */ chunks_per_batch = (4 * 1024 * 1024) / (uint32_t) file->chunk_size; return ( /* cursor is on or before the desired chunk */ file->cursor_range[0] <= chunk_no && /* chunk_no is before end of file */ chunk_no <= file->cursor_range[1] && /* desired chunk is in this batch or next one */ chunk_no < file->cursor_range[0] + 2 * chunks_per_batch); } static int64_t divide_round_up (int64_t num, int64_t denom) { return (num + denom - 1) / denom; } static void missing_chunk (mongoc_gridfs_file_t *file) { bson_set_error ( &file->error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, "missing chunk number %" PRId32, file->n); if (file->cursor) { mongoc_cursor_destroy (file->cursor); file->cursor = NULL; } } /** * _mongoc_gridfs_file_refresh_page: * * Refresh a GridFS file's underlying page. This recalculates the current * page number based on the file's stream position, then fetches that page * from the database. * * Note that this fetch is unconditional and the page is queried from the * database even if the current page covers the same theoretical chunk. * * * Side Effects: * * file->page is loaded with the appropriate buffer, fetched from the * database. If the file position is at the end of the file and on a new * chunk boundary, a new page is created. If the position is far past the * end of the file, _mongoc_gridfs_file_extend is responsible for creating * chunks to file the gap. * * file->n is set based on file->pos. file->error is set on error. */ static bool _mongoc_gridfs_file_refresh_page (mongoc_gridfs_file_t *file) { const uint8_t *data = NULL; uint32_t len = 0u; ENTRY; BSON_ASSERT (file); file->n = (int32_t) (file->pos / file->chunk_size); if (file->page) { _mongoc_gridfs_file_page_destroy (file->page); file->page = NULL; } /* if the file pointer is past the end of the current file (i.e. pointing to * a new chunk), we'll pass the page constructor a new empty page. */ const int64_t existing_chunks = divide_round_up (file->length, file->chunk_size); const int64_t required_chunks = divide_round_up (file->pos + 1, file->chunk_size); if (required_chunks > existing_chunks) { data = (uint8_t *) ""; len = 0; } else { /* if we have a cursor, but the cursor doesn't have the chunk we're going * to need, destroy it (we'll grab a new one immediately there after) */ if (file->cursor && !_mongoc_gridfs_file_keep_cursor (file)) { mongoc_cursor_destroy (file->cursor); file->cursor = NULL; } if (!file->cursor) { bson_t query; bson_init (&query); BSON_APPEND_VALUE (&query, "files_id", &file->files_id); bson_t child; BSON_APPEND_DOCUMENT_BEGIN (&query, "n", &child); BSON_APPEND_INT32 (&child, "$gte", file->n); bson_append_document_end (&query, &child); bson_t opts; bson_init (&opts); BSON_APPEND_DOCUMENT_BEGIN (&opts, "sort", &child); BSON_APPEND_INT32 (&child, "n", 1); bson_append_document_end (&opts, &child); BSON_APPEND_DOCUMENT_BEGIN (&opts, "projection", &child); BSON_APPEND_INT32 (&child, "n", 1); BSON_APPEND_INT32 (&child, "data", 1); BSON_APPEND_INT32 (&child, "_id", 0); bson_append_document_end (&opts, &child); /* find all chunks greater than or equal to our current file pos */ file->cursor = mongoc_collection_find_with_opts (file->gridfs->chunks, &query, &opts, NULL); file->cursor_range[0] = file->n; file->cursor_range[1] = (uint32_t) (file->length / file->chunk_size); bson_destroy (&query); bson_destroy (&opts); BSON_ASSERT (file->cursor); } const bson_t *chunk = NULL; /* we might have had a cursor before, then seeked ahead past a chunk. * iterate until we're on the right chunk */ while (mcommon_cmp_less_equal_us (file->cursor_range[0], file->n)) { if (!mongoc_cursor_next (file->cursor, &chunk)) { /* copy cursor error; if there's none, we're missing a chunk */ if (!mongoc_cursor_error (file->cursor, &file->error)) { missing_chunk (file); } RETURN (0); } file->cursor_range[0]++; } bson_iter_t iter; BSON_ASSERT (bson_iter_init (&iter, chunk)); /* grab out what we need from the chunk */ while (bson_iter_next (&iter)) { const char *const key = bson_iter_key (&iter); if (strcmp (key, "n") == 0) { if (file->n != bson_iter_int32 (&iter)) { missing_chunk (file); RETURN (0); } } else if (strcmp (key, "data") == 0) { bson_iter_binary (&iter, NULL, &len, &data); // If this not the last chunk, ensure length is equal to chunk size. bool is_last_chunk = ((file->n + 1) == existing_chunks); // If this is not the last chunk, error. if (!is_last_chunk && mcommon_cmp_not_equal_us (len, file->chunk_size)) { bson_set_error (&file->error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "corrupt chunk number %" PRId32 ": not equal to chunk size: %" PRId32, file->n, file->chunk_size); RETURN (0); } } else { /* Unexpected key. This should never happen */ RETURN (0); } } if (file->n != file->pos / file->chunk_size) { return 0; } } if (!data) { bson_set_error (&file->error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CHUNK_MISSING, "corrupt chunk number %" PRId32 ": no data", file->n); RETURN (0); } if (mcommon_cmp_greater_us (len, file->chunk_size)) { bson_set_error (&file->error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "corrupt chunk number %" PRId32 ": greater than chunk size: %" PRId32, file->n, file->chunk_size); RETURN (0); } file->page = _mongoc_gridfs_file_page_new (data, len, file->chunk_size); /* seek in the page towards wherever we're supposed to be */ RETURN (_mongoc_gridfs_file_page_seek (file->page, file->pos % file->chunk_size)); } /** * mongoc_gridfs_file_seek: * * Adjust the file position pointer in `file` by `delta`, starting from the * position `whence`. The `whence` argument is interpreted as in fseek(2): * * SEEK_SET Set the position relative to the start of the file. * SEEK_CUR Move `delta` from the current file position. * SEEK_END Move `delta` from the end-of-file. * * Parameters: * * @file: A mongoc_gridfs_file_t. * @delta: The amount to move. May be positive or negative. * @whence: One of SEEK_SET, SEEK_CUR or SEEK_END. * * Errors: * * [EINVAL] `whence` is not one of SEEK_SET, SEEK_CUR or SEEK_END. * [EINVAL] Resulting file position would be negative. * * Side Effects: * * On success, the file's underlying position pointer is set appropriately. * On failure, the file position is NOT changed and errno is set. * * Returns: * * 0 on success. * -1 on error, and errno set to indicate the error. */ int mongoc_gridfs_file_seek (mongoc_gridfs_file_t *file, int64_t delta, int whence) { int64_t offset; BSON_ASSERT (file); switch (whence) { case SEEK_SET: offset = delta; break; case SEEK_CUR: BSON_ASSERT (mcommon_in_range_unsigned (int64_t, file->pos)); offset = (int64_t) file->pos + delta; break; case SEEK_END: offset = file->length + delta; break; default: errno = EINVAL; return -1; } if (offset < 0) { errno = EINVAL; return -1; } if (offset / file->chunk_size != file->n) { /** no longer on the same page */ if (file->page) { if (_mongoc_gridfs_file_page_is_dirty (file->page)) { if (!_mongoc_gridfs_file_flush_page (file)) { return -1; } } else { _mongoc_gridfs_file_page_destroy (file->page); file->page = NULL; } } /** we'll pick up the seek when we fetch a page on the next action. We * lazily load */ } else if (file->page) { const int64_t n = offset % file->chunk_size; BSON_ASSERT (mcommon_in_range_signed (uint32_t, n)); BSON_ASSERT (_mongoc_gridfs_file_page_seek (file->page, (uint32_t) n)); } file->pos = (uint64_t) offset; BSON_ASSERT (mcommon_in_range_signed (uint64_t, file->chunk_size)); const uint64_t n = file->pos / (uint64_t) file->chunk_size; BSON_ASSERT (mcommon_in_range_unsigned (int32_t, n)); file->n = (int32_t) n; return 0; } uint64_t mongoc_gridfs_file_tell (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return file->pos; } bool mongoc_gridfs_file_error (mongoc_gridfs_file_t *file, bson_error_t *error) { BSON_ASSERT (file); BSON_ASSERT (error); if (BSON_UNLIKELY (file->error.domain)) { bson_set_error (error, file->error.domain, file->error.code, "%s", file->error.message); RETURN (true); } RETURN (false); } const bson_value_t * mongoc_gridfs_file_get_id (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return &file->files_id; } int64_t mongoc_gridfs_file_get_length (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return file->length; } int32_t mongoc_gridfs_file_get_chunk_size (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return file->chunk_size; } int64_t mongoc_gridfs_file_get_upload_date (mongoc_gridfs_file_t *file) { BSON_ASSERT (file); return file->upload_date; } bool mongoc_gridfs_file_remove (mongoc_gridfs_file_t *file, bson_error_t *error) { bson_t sel = BSON_INITIALIZER; bool ret = false; BSON_ASSERT (file); BSON_APPEND_VALUE (&sel, "_id", &file->files_id); if (!mongoc_collection_delete_one (file->gridfs->files, &sel, NULL, NULL, error)) { goto cleanup; } bson_reinit (&sel); BSON_APPEND_VALUE (&sel, "files_id", &file->files_id); if (!mongoc_collection_delete_many (file->gridfs->chunks, &sel, NULL, NULL, error)) { goto cleanup; } ret = true; cleanup: bson_destroy (&sel); return ret; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-file.h0000644000175100001660000000650214760300420023335 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_FILE_H #define MONGOC_GRIDFS_FILE_H #include #include #include BSON_BEGIN_DECLS #define MONGOC_GRIDFS_FILE_STR_HEADER(name) \ MONGOC_EXPORT (const char *) \ mongoc_gridfs_file_get_##name (mongoc_gridfs_file_t *file); \ MONGOC_EXPORT (void) \ mongoc_gridfs_file_set_##name (mongoc_gridfs_file_t *file, const char *str); #define MONGOC_GRIDFS_FILE_BSON_HEADER(name) \ MONGOC_EXPORT (const bson_t *) \ mongoc_gridfs_file_get_##name (mongoc_gridfs_file_t *file); \ MONGOC_EXPORT (void) \ mongoc_gridfs_file_set_##name (mongoc_gridfs_file_t *file, const bson_t *bson); typedef struct _mongoc_gridfs_file_t mongoc_gridfs_file_t; typedef struct _mongoc_gridfs_file_opt_t mongoc_gridfs_file_opt_t; struct _mongoc_gridfs_file_opt_t { const char *md5; const char *filename; const char *content_type; const bson_t *aliases; const bson_t *metadata; uint32_t chunk_size; }; MONGOC_GRIDFS_FILE_STR_HEADER (md5) MONGOC_GRIDFS_FILE_STR_HEADER (filename) MONGOC_GRIDFS_FILE_STR_HEADER (content_type) MONGOC_GRIDFS_FILE_BSON_HEADER (aliases) MONGOC_GRIDFS_FILE_BSON_HEADER (metadata) MONGOC_EXPORT (const bson_value_t *) mongoc_gridfs_file_get_id (mongoc_gridfs_file_t *file); MONGOC_EXPORT (int64_t) mongoc_gridfs_file_get_length (mongoc_gridfs_file_t *file); MONGOC_EXPORT (int32_t) mongoc_gridfs_file_get_chunk_size (mongoc_gridfs_file_t *file); MONGOC_EXPORT (int64_t) mongoc_gridfs_file_get_upload_date (mongoc_gridfs_file_t *file); MONGOC_EXPORT (ssize_t) mongoc_gridfs_file_writev (mongoc_gridfs_file_t *file, const mongoc_iovec_t *iov, size_t iovcnt, uint32_t timeout_msec); MONGOC_EXPORT (ssize_t) mongoc_gridfs_file_readv ( mongoc_gridfs_file_t *file, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, uint32_t timeout_msec); MONGOC_EXPORT (int) mongoc_gridfs_file_seek (mongoc_gridfs_file_t *file, int64_t delta, int whence); MONGOC_EXPORT (uint64_t) mongoc_gridfs_file_tell (mongoc_gridfs_file_t *file); MONGOC_EXPORT (bool) mongoc_gridfs_file_set_id (mongoc_gridfs_file_t *file, const bson_value_t *id, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_gridfs_file_save (mongoc_gridfs_file_t *file); MONGOC_EXPORT (void) mongoc_gridfs_file_destroy (mongoc_gridfs_file_t *file); MONGOC_EXPORT (bool) mongoc_gridfs_file_error (mongoc_gridfs_file_t *file, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_gridfs_file_remove (mongoc_gridfs_file_t *file, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_GRIDFS_FILE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs-private.h0000644000175100001660000000221214760300420024062 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_PRIVATE_H #define MONGOC_GRIDFS_PRIVATE_H #include #include #include #include BSON_BEGIN_DECLS struct _mongoc_gridfs_t { mongoc_client_t *client; mongoc_collection_t *files; mongoc_collection_t *chunks; }; mongoc_gridfs_t * _mongoc_gridfs_new (mongoc_client_t *client, const char *db, const char *prefix, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_GRIDFS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs.c0000644000175100001660000002704014760300420022413 0ustar /* * Copyright 2009-present MongoDB, 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. */ #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MONGOC_GRIDFS_STREAM_CHUNK 4096 /** * _mongoc_gridfs_ensure_index: * * ensure gridfs indexes * * Ensure fast searches for chunks via [ files_id, n ] * Ensure fast searches for files via [ filename ] */ static bool _mongoc_gridfs_ensure_index (mongoc_gridfs_t *gridfs, bson_error_t *error) { bson_t keys; bson_t opts; bool r; ENTRY; bson_init (&opts); BSON_APPEND_BOOL (&opts, "unique", true); bson_init (&keys); BSON_APPEND_INT32 (&keys, "files_id", 1); BSON_APPEND_INT32 (&keys, "n", 1); r = _mongoc_collection_create_index_if_not_exists (gridfs->chunks, &keys, &opts, error); bson_destroy (&opts); bson_destroy (&keys); if (!r) { RETURN (r); } bson_init (&keys); BSON_APPEND_INT32 (&keys, "filename", 1); BSON_APPEND_INT32 (&keys, "uploadDate", 1); r = _mongoc_collection_create_index_if_not_exists (gridfs->files, &keys, NULL, error); bson_destroy (&keys); if (!r) { RETURN (r); } RETURN (1); } mongoc_gridfs_t * _mongoc_gridfs_new (mongoc_client_t *client, const char *db, const char *prefix, bson_error_t *error) { mongoc_gridfs_t *gridfs; char buf[128]; bool r; uint32_t prefix_len; ENTRY; BSON_ASSERT_PARAM (client); BSON_ASSERT (db); if (!prefix) { prefix = "fs"; } /* make sure prefix is short enough to bucket the chunks and files * collections */ prefix_len = (uint32_t) strlen (prefix); BSON_ASSERT (prefix_len + sizeof (".chunks") < sizeof (buf)); gridfs = (mongoc_gridfs_t *) bson_malloc0 (sizeof *gridfs); gridfs->client = client; // Expect no truncation from above, checking no error occurred. int req = bson_snprintf (buf, sizeof (buf), "%s.chunks", prefix); BSON_ASSERT (req > 0); gridfs->chunks = mongoc_client_get_collection (client, db, buf); req = bson_snprintf (buf, sizeof (buf), "%s.files", prefix); BSON_ASSERT (req > 0); gridfs->files = mongoc_client_get_collection (client, db, buf); r = _mongoc_gridfs_ensure_index (gridfs, error); if (!r) { mongoc_gridfs_destroy (gridfs); RETURN (NULL); } RETURN (gridfs); } bool mongoc_gridfs_drop (mongoc_gridfs_t *gridfs, bson_error_t *error) { bool r; ENTRY; r = mongoc_collection_drop (gridfs->files, error); if (!r) { RETURN (0); } r = mongoc_collection_drop (gridfs->chunks, error); if (!r) { RETURN (0); } RETURN (1); } void mongoc_gridfs_destroy (mongoc_gridfs_t *gridfs) { ENTRY; if (!gridfs) { EXIT; } mongoc_collection_destroy (gridfs->files); mongoc_collection_destroy (gridfs->chunks); bson_free (gridfs); EXIT; } /** find all matching gridfs files */ mongoc_gridfs_file_list_t * mongoc_gridfs_find (mongoc_gridfs_t *gridfs, const bson_t *query) { return _mongoc_gridfs_file_list_new (gridfs, query, 0); } /** find a single gridfs file */ mongoc_gridfs_file_t * mongoc_gridfs_find_one (mongoc_gridfs_t *gridfs, const bson_t *query, bson_error_t *error) { mongoc_gridfs_file_list_t *list; mongoc_gridfs_file_t *file; ENTRY; list = _mongoc_gridfs_file_list_new (gridfs, query, 1); file = mongoc_gridfs_file_list_next (list); if (!mongoc_gridfs_file_list_error (list, error) && error) { /* no error, but an error out-pointer was provided - clear it */ memset (error, 0, sizeof (*error)); } mongoc_gridfs_file_list_destroy (list); RETURN (file); } /** find all matching gridfs files */ mongoc_gridfs_file_list_t * mongoc_gridfs_find_with_opts (mongoc_gridfs_t *gridfs, const bson_t *filter, const bson_t *opts) { return _mongoc_gridfs_file_list_new_with_opts (gridfs, filter, opts); } /** find a single gridfs file */ mongoc_gridfs_file_t * mongoc_gridfs_find_one_with_opts (mongoc_gridfs_t *gridfs, const bson_t *filter, const bson_t *opts, bson_error_t *error) { mongoc_gridfs_file_list_t *list; mongoc_gridfs_file_t *file; bson_t new_opts; ENTRY; bson_init (&new_opts); if (opts) { bson_copy_to_excluding_noinit (opts, &new_opts, "limit", (char *) NULL); } BSON_APPEND_INT32 (&new_opts, "limit", 1); list = _mongoc_gridfs_file_list_new_with_opts (gridfs, filter, &new_opts); file = mongoc_gridfs_file_list_next (list); if (!mongoc_gridfs_file_list_error (list, error) && error) { /* no error, but an error out-pointer was provided - clear it */ memset (error, 0, sizeof (*error)); } mongoc_gridfs_file_list_destroy (list); bson_destroy (&new_opts); RETURN (file); } /** find a single gridfs file by filename */ mongoc_gridfs_file_t * mongoc_gridfs_find_one_by_filename (mongoc_gridfs_t *gridfs, const char *filename, bson_error_t *error) { mongoc_gridfs_file_t *file; bson_t filter; bson_init (&filter); bson_append_utf8 (&filter, "filename", -1, filename, -1); file = mongoc_gridfs_find_one_with_opts (gridfs, &filter, NULL, error); bson_destroy (&filter); return file; } /** create a gridfs file from a stream * * The stream is fully consumed in creating the file */ mongoc_gridfs_file_t * mongoc_gridfs_create_file_from_stream (mongoc_gridfs_t *gridfs, mongoc_stream_t *stream, mongoc_gridfs_file_opt_t *opt) { mongoc_gridfs_file_t *file; ssize_t r; uint8_t buf[MONGOC_GRIDFS_STREAM_CHUNK]; mongoc_iovec_t iov; int timeout; ENTRY; BSON_ASSERT (gridfs); BSON_ASSERT (stream); iov.iov_base = (void *) buf; iov.iov_len = 0; file = _mongoc_gridfs_file_new (gridfs, opt); timeout = gridfs->client->cluster.sockettimeoutms; for (;;) { r = mongoc_stream_read (stream, iov.iov_base, MONGOC_GRIDFS_STREAM_CHUNK, 0, timeout); if (r > 0) { iov.iov_len = r; if (mongoc_gridfs_file_writev (file, &iov, 1, timeout) < 0) { MONGOC_ERROR ("%s", file->error.message); mongoc_gridfs_file_destroy (file); RETURN (NULL); } } else if (r == 0) { break; } else { MONGOC_ERROR ("Error reading from GridFS file source stream"); mongoc_gridfs_file_destroy (file); RETURN (NULL); } } mongoc_stream_failed (stream); if (-1 == mongoc_gridfs_file_seek (file, 0, SEEK_SET)) { MONGOC_ERROR ("%s", file->error.message); mongoc_gridfs_file_destroy (file); RETURN (NULL); } RETURN (file); } /** create an empty gridfs file */ mongoc_gridfs_file_t * mongoc_gridfs_create_file (mongoc_gridfs_t *gridfs, mongoc_gridfs_file_opt_t *opt) { mongoc_gridfs_file_t *file; ENTRY; BSON_ASSERT (gridfs); file = _mongoc_gridfs_file_new (gridfs, opt); RETURN (file); } /** accessor functions for collections */ mongoc_collection_t * mongoc_gridfs_get_files (mongoc_gridfs_t *gridfs) { BSON_ASSERT (gridfs); return gridfs->files; } mongoc_collection_t * mongoc_gridfs_get_chunks (mongoc_gridfs_t *gridfs) { BSON_ASSERT (gridfs); return gridfs->chunks; } bool mongoc_gridfs_remove_by_filename (mongoc_gridfs_t *gridfs, const char *filename, bson_error_t *error) { mongoc_bulk_operation_t *bulk_files = NULL; mongoc_bulk_operation_t *bulk_chunks = NULL; mongoc_cursor_t *cursor = NULL; bson_error_t files_error; bson_error_t chunks_error; const bson_t *doc; const char *key; char keybuf[16]; int count = 0; bool chunks_ret; bool files_ret; bool ret = false; bson_iter_t iter; bson_t *files_q = NULL; bson_t *chunks_q = NULL; bson_t find_filter = BSON_INITIALIZER; bson_t find_opts = BSON_INITIALIZER; bson_t find_opts_project; bson_t ar = BSON_INITIALIZER; bson_t opts = BSON_INITIALIZER; BSON_ASSERT (gridfs); if (!filename) { bson_set_error ( error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_INVALID_FILENAME, "A non-NULL filename must be specified."); return false; } /* * Find all files matching this filename. Hopefully just one, but not * strictly required! */ BSON_APPEND_UTF8 (&find_filter, "filename", filename); BSON_APPEND_DOCUMENT_BEGIN (&find_opts, "projection", &find_opts_project); BSON_APPEND_INT32 (&find_opts_project, "_id", 1); bson_append_document_end (&find_opts, &find_opts_project); cursor = _mongoc_cursor_find_new (gridfs->client, gridfs->files->ns, &find_filter, &find_opts, NULL /* user_prefs */, NULL /* default_prefs */, NULL /* read_concern */); BSON_ASSERT (cursor); while (mongoc_cursor_next (cursor, &doc)) { if (bson_iter_init_find (&iter, doc, "_id")) { const bson_value_t *value = bson_iter_value (&iter); bson_uint32_to_string (count, &key, keybuf, sizeof keybuf); BSON_APPEND_VALUE (&ar, key, value); } } if (mongoc_cursor_error (cursor, error)) { goto failure; } bson_append_bool (&opts, "ordered", 7, false); bulk_files = mongoc_collection_create_bulk_operation_with_opts (gridfs->files, &opts); bulk_chunks = mongoc_collection_create_bulk_operation_with_opts (gridfs->chunks, &opts); bson_destroy (&opts); files_q = BCON_NEW ("_id", "{", "$in", BCON_ARRAY (&ar), "}"); chunks_q = BCON_NEW ("files_id", "{", "$in", BCON_ARRAY (&ar), "}"); mongoc_bulk_operation_remove (bulk_files, files_q); mongoc_bulk_operation_remove (bulk_chunks, chunks_q); files_ret = mongoc_bulk_operation_execute (bulk_files, NULL, &files_error); chunks_ret = mongoc_bulk_operation_execute (bulk_chunks, NULL, &chunks_error); if (error) { if (!files_ret) { memcpy (error, &files_error, sizeof *error); } else if (!chunks_ret) { memcpy (error, &chunks_error, sizeof *error); } } ret = (files_ret && chunks_ret); failure: if (cursor) { mongoc_cursor_destroy (cursor); } if (bulk_files) { mongoc_bulk_operation_destroy (bulk_files); } if (bulk_chunks) { mongoc_bulk_operation_destroy (bulk_chunks); } bson_destroy (&find_filter); bson_destroy (&find_opts); bson_destroy (&ar); if (files_q) { bson_destroy (files_q); } if (chunks_q) { bson_destroy (chunks_q); } return ret; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-gridfs.h0000644000175100001660000000602514760300420022420 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_GRIDFS_H #define MONGOC_GRIDFS_H #include #include #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_gridfs_t mongoc_gridfs_t; MONGOC_EXPORT (mongoc_gridfs_file_t *) mongoc_gridfs_create_file_from_stream (mongoc_gridfs_t *gridfs, mongoc_stream_t *stream, mongoc_gridfs_file_opt_t *opt) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_gridfs_file_t *) mongoc_gridfs_create_file (mongoc_gridfs_t *gridfs, mongoc_gridfs_file_opt_t *opt) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_gridfs_file_list_t *) mongoc_gridfs_find (mongoc_gridfs_t *gridfs, const bson_t *query) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_gridfs_find_with_opts); MONGOC_EXPORT (mongoc_gridfs_file_t *) mongoc_gridfs_find_one (mongoc_gridfs_t *gridfs, const bson_t *query, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_gridfs_find_one_with_opts); MONGOC_EXPORT (mongoc_gridfs_file_list_t *) mongoc_gridfs_find_with_opts (mongoc_gridfs_t *gridfs, const bson_t *filter, const bson_t *opts) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_gridfs_file_t *) mongoc_gridfs_find_one_with_opts (mongoc_gridfs_t *gridfs, const bson_t *filter, const bson_t *opts, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_gridfs_file_t *) mongoc_gridfs_find_one_by_filename (mongoc_gridfs_t *gridfs, const char *filename, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_gridfs_drop (mongoc_gridfs_t *gridfs, bson_error_t *error); MONGOC_EXPORT (void) mongoc_gridfs_destroy (mongoc_gridfs_t *gridfs); MONGOC_EXPORT (mongoc_collection_t *) mongoc_gridfs_get_files (mongoc_gridfs_t *gridfs); MONGOC_EXPORT (mongoc_collection_t *) mongoc_gridfs_get_chunks (mongoc_gridfs_t *gridfs); MONGOC_EXPORT (bool) mongoc_gridfs_remove_by_filename (mongoc_gridfs_t *gridfs, const char *filename, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_GRIDFS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-handshake-compiler-private.h0000644000175100001660000000441714760300420026353 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_HANDSHAKE_COMPILER_PRIVATE_H #define MONGOC_HANDSHAKE_COMPILER_PRIVATE_H #include #include /* * Thanks to: * http://nadeausoftware.com/articles/2012/10/c_c_tip_how_detect_compiler_name_and_version_using_compiler_predefined_macros */ #if defined(__clang__) #define MONGOC_COMPILER "clang" #define MONGOC_COMPILER_VERSION __clang_version__ #elif defined(__ICC) || defined(__INTEL_COMPILER) #define MONGOC_COMPILER "ICC" #define MONGOC_COMPILER_VERSION __VERSION__ #elif defined(__GNUC__) || defined(__GNUG__) #define MONGOC_COMPILER "GCC" #define MONGOC_COMPILER_VERSION __VERSION__ #elif defined(__HP_cc) || defined(__HP_aCC) #define MONGOC_COMPILER "aCC" #define MONGOC_COMPILER_VERSION MONGOC_EVALUATE_STR (__HP_cc) #elif defined(__IBMC__) || defined(__IBMCPP__) #define MONGOC_COMPILER "xlc" #define MONGOC_COMPILER_VERSION __xlc__ #elif defined(_MSC_VER) #define MONGOC_COMPILER "MSVC" #define MONGOC_COMPILER_VERSION MONGOC_EVALUATE_STR (_MSC_VER) #elif defined(__PGI) #define MONGOC_COMPILER "Portland PGCC" #define MONGOC_COMPILER_VERSION \ MONGOC_EVALUATE_STR (__PGIC__) \ "." MONGOC_EVALUATE_STR (__PGIC_MINOR) "." MONGOC_EVALUATE_STR (__PGIC_PATCHLEVEL__) #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) #define MONGOC_COMPILER "Solaris Studio" #define MONGOC_COMPILER_VERSION MONGOC_EVALUATE_STR (__SUNPRO_C) #elif defined(__PCC__) /* Portable C Compiler. Version may not be available */ #define MONGOC_COMPILER "PCC" #else #define MONGOC_COMPILER MONGOC_EVALUATE_STR (MONGOC_CC) /* Not defining COMPILER_VERSION. We'll fall back to values set at * configure-time */ #endif #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-handshake-os-private.h0000644000175100001660000000541314760300420025157 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_HANDSHAKE_OS_PRIVATE #define MONGOC_HANDSHAKE_OS_PRIVATE /* Based on tables from * http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system */ #if defined(_WIN32) || defined(__CYGWIN__) #define MONGOC_OS_TYPE "Windows" #if defined(__CYGWIN__) #define MONGOC_OS_NAME "Cygwin" #else #define MONGOC_OS_NAME "Windows" #endif /* osx and iphone defines __APPLE__ and __MACH__, but not __unix__ */ #elif defined(__APPLE__) && defined(__MACH__) && !defined(__unix__) #define MONGOC_OS_TYPE "Darwin" #include #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR == 1 #define MONGOC_OS_NAME "iOS Simulator" #elif defined(TARGET_OS_IOS) && TARGET_OS_IOS == 1 #define MONGOC_OS_NAME "iOS" #elif defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1 #define MONGOC_OS_NAME "macOS" #elif defined(TARGET_OS_TV) && TARGET_OS_TV == 1 #define MONGOC_OS_NAME "tvOS" #elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 #define MONGOC_OS_NAME "watchOS" #else /* Fall back to uname () */ #endif /* Need to check if __unix is defined since sun and hpux always have __unix, * but not necessarily __unix__ defined. */ #elif defined(__unix__) || defined(__unix) #include #if defined(__linux__) #define MONGOC_OS_IS_LINUX #if defined(__ANDROID__) #define MONGOC_OS_TYPE "Linux (Android)" #else #define MONGOC_OS_TYPE "Linux" #endif /* Don't define OS_NAME. We'll scan the file system to determine distro. */ #elif defined(BSD) #define MONGOC_OS_TYPE "BSD" #if defined(__FreeBSD__) #define MONGOC_OS_NAME "FreeBSD" #elif defined(__NetBSD__) #define MONGOC_OS_NAME "NetBSD" #elif defined(__OpenBSD__) #define MONGOC_OS_NAME "OpenBSD" #elif defined(__DragonFly__) #define MONGOC_OS_NAME "DragonFlyBSD" #else /* Don't define OS_NAME. We'll use uname to figure it out. */ #endif #else #define MONGOC_OS_TYPE "Unix" #if defined(_AIX) #define MONGOC_OS_NAME "AIX" #elif defined(__sun) && defined(__SVR4) #define MONGOC_OS_NAME "Solaris" #elif defined(__hpux) #define MONGOC_OS_NAME "HP-UX" #else /* Don't set OS name. We'll just fall back to uname. */ #endif #endif #endif #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-handshake-private.h0000644000175100001660000001106614760300420024541 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_HANDSHAKE_PRIVATE_H #define MONGOC_HANDSHAKE_PRIVATE_H #include BSON_BEGIN_DECLS #define HANDSHAKE_FIELD "client" #define HANDSHAKE_PLATFORM_FIELD "platform" #define HANDSHAKE_MAX_SIZE 512 #define HANDSHAKE_OS_TYPE_MAX 32 #define HANDSHAKE_OS_NAME_MAX 32 #define HANDSHAKE_OS_VERSION_MAX 32 #define HANDSHAKE_OS_ARCHITECTURE_MAX 32 #define HANDSHAKE_DRIVER_NAME_MAX 64 #define HANDSHAKE_DRIVER_VERSION_MAX 32 #define HANDSHAKE_CMD_HELLO "hello" #define HANDSHAKE_RESPONSE_HELLO "helloOk" #define HANDSHAKE_CMD_LEGACY_HELLO "isMaster" #define HANDSHAKE_RESPONSE_LEGACY_HELLO "ismaster" /* platform has no fixed max size. It can just occupy the remaining * available space in the document. */ /* When adding a new field to mongoc-config.h.in, update this! */ typedef enum { /* The bit position (from the RHS) of each config flag. Do not reorder or change values. */ MONGOC_MD_FLAG_ENABLE_CRYPTO = 0, MONGOC_MD_FLAG_ENABLE_CRYPTO_CNG = 1, MONGOC_MD_FLAG_ENABLE_CRYPTO_COMMON_CRYPTO = 2, MONGOC_MD_FLAG_ENABLE_CRYPTO_LIBCRYPTO = 3, MONGOC_MD_FLAG_ENABLE_CRYPTO_SYSTEM_PROFILE = 4, MONGOC_MD_FLAG_ENABLE_SASL = 5, MONGOC_MD_FLAG_ENABLE_SSL = 6, MONGOC_MD_FLAG_ENABLE_SSL_OPENSSL = 7, MONGOC_MD_FLAG_ENABLE_SSL_SECURE_CHANNEL = 8, MONGOC_MD_FLAG_ENABLE_SSL_SECURE_TRANSPORT = 9, MONGOC_MD_FLAG_EXPERIMENTAL_FEATURES = 10, MONGOC_MD_FLAG_HAVE_SASL_CLIENT_DONE = 11, MONGOC_MD_FLAG_HAVE_WEAK_SYMBOLS = 12, MONGOC_MD_FLAG_NO_AUTOMATIC_GLOBALS = 13, MONGOC_MD_FLAG_ENABLE_SSL_LIBRESSL = 14, MONGOC_MD_FLAG_ENABLE_SASL_CYRUS = 15, MONGOC_MD_FLAG_ENABLE_SASL_SSPI = 16, MONGOC_MD_FLAG_HAVE_SOCKLEN = 17, MONGOC_MD_FLAG_ENABLE_COMPRESSION = 18, MONGOC_MD_FLAG_ENABLE_COMPRESSION_SNAPPY = 19, MONGOC_MD_FLAG_ENABLE_COMPRESSION_ZLIB = 20, MONGOC_MD_FLAG_ENABLE_SASL_GSSAPI_UNUSED = 21, /* CDRIVER-2654 removed this . */ MONGOC_MD_FLAG_ENABLE_RES_NSEARCH = 22, MONGOC_MD_FLAG_ENABLE_RES_NDESTROY = 23, MONGOC_MD_FLAG_ENABLE_RES_NCLOSE = 24, MONGOC_MD_FLAG_ENABLE_RES_SEARCH = 25, MONGOC_MD_FLAG_ENABLE_DNSAPI = 26, MONGOC_MD_FLAG_ENABLE_RDTSCP = 27, MONGOC_MD_FLAG_HAVE_SCHED_GETCPU = 28, MONGOC_MD_FLAG_ENABLE_SHM_COUNTERS = 29, MONGOC_MD_FLAG_TRACE = 30, MONGOC_MD_FLAG_ENABLE_ICU_UNUSED = 31, MONGOC_MD_FLAG_ENABLE_CLIENT_SIDE_ENCRYPTION = 32, MONGOC_MD_FLAG_ENABLE_MONGODB_AWS_AUTH = 33, MONGOC_MD_FLAG_ENABLE_SRV = 34, MONGOC_MD_FLAG_HAVE_BCRYPT_PBKDF2 = 35, /* Add additional config flags here, above LAST_MONGOC_MD_FLAG. */ LAST_MONGOC_MD_FLAG } mongoc_handshake_config_flag_bit_t; typedef enum { MONGOC_HANDSHAKE_ENV_NONE, MONGOC_HANDSHAKE_ENV_AWS, MONGOC_HANDSHAKE_ENV_VERCEL, MONGOC_HANDSHAKE_ENV_GCP, MONGOC_HANDSHAKE_ENV_AZURE } mongoc_handshake_env_t; typedef struct _optional_int32 { bool set; int32_t value; } optional_int32; typedef struct _mongoc_handshake_t { char *os_type; char *os_name; char *os_version; char *os_architecture; char *driver_name; char *driver_version; char *platform; char *compiler_info; char *flags; mongoc_handshake_env_t env; optional_int32 env_timeout_sec; optional_int32 env_memory_mb; char *env_region; bool frozen; } mongoc_handshake_t; void _mongoc_handshake_init (void); void _mongoc_handshake_cleanup (void); bson_t * _mongoc_handshake_build_doc_with_application (const char *application); void _mongoc_handshake_freeze (void); mongoc_handshake_t * _mongoc_handshake_get (void); bool _mongoc_handshake_appname_is_valid (const char *appname); typedef struct { bool scram_sha_256; bool scram_sha_1; } mongoc_handshake_sasl_supported_mechs_t; void _mongoc_handshake_append_sasl_supported_mechs (const mongoc_uri_t *uri, bson_t *hello); void _mongoc_handshake_parse_sasl_supported_mechs (const bson_t *hello, mongoc_handshake_sasl_supported_mechs_t *sasl_supported_mechs); BSON_END_DECLS #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-handshake.c0000644000175100001660000006004514760300420023065 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef _POSIX_VERSION #include #endif #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Global handshake data instance. Initialized at startup from mongoc_init * * Can be modified by calls to mongoc_handshake_data_append */ static mongoc_handshake_t gMongocHandshake; /* * Used for thread-safety in mongoc_handshake_data_append */ static bson_mutex_t gHandshakeLock; static void _set_bit (uint8_t *bf, uint32_t byte_count, uint32_t bit) { uint32_t byte = bit / 8; uint32_t bit_of_byte = (bit) % 8; /* byte 0 is the last location in bf. */ bf[(byte_count - 1) - byte] |= 1u << bit_of_byte; } /* returns a hex string for all config flag bits, which must be freed. */ char * _mongoc_handshake_get_config_hex_string (void) { const uint32_t byte_count = (LAST_MONGOC_MD_FLAG + 7) / 8; /* ceil (num_bits / 8) */ /* allocate enough bytes to fit all config bits. */ uint8_t *const bf = (uint8_t *) bson_malloc0 (byte_count); #ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL _set_bit (bf, byte_count, MONGOC_ENABLE_SSL_SECURE_CHANNEL); #endif #ifdef MONGOC_ENABLE_CRYPTO_CNG _set_bit (bf, byte_count, MONGOC_ENABLE_CRYPTO_CNG); #endif #ifdef MONGOC_HAVE_BCRYPT_PBKDF2 _set_bit (bf, byte_count, MONGOC_MD_FLAG_HAVE_BCRYPT_PBKDF2); #endif #ifdef MONGOC_ENABLE_SSL_SECURE_TRANSPORT _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SSL_SECURE_TRANSPORT); #endif #ifdef MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_CRYPTO_COMMON_CRYPTO); #endif #ifdef MONGOC_ENABLE_SSL_OPENSSL _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SSL_OPENSSL); #endif #ifdef MONGOC_ENABLE_CRYPTO_LIBCRYPTO _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_CRYPTO_LIBCRYPTO); #endif #ifdef MONGOC_ENABLE_SSL _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SSL); #endif #ifdef MONGOC_ENABLE_CRYPTO _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_CRYPTO); #endif #ifdef MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_CRYPTO_SYSTEM_PROFILE); #endif #ifdef MONGOC_ENABLE_SASL _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SASL); #endif #ifdef MONGOC_HAVE_SASL_CLIENT_DONE _set_bit (bf, byte_count, MONGOC_MD_FLAG_HAVE_SASL_CLIENT_DONE); #endif #ifdef MONGOC_NO_AUTOMATIC_GLOBALS _set_bit (bf, byte_count, MONGOC_MD_FLAG_NO_AUTOMATIC_GLOBALS); #endif #ifdef MONGOC_EXPERIMENTAL_FEATURES _set_bit (bf, byte_count, MONGOC_MD_FLAG_EXPERIMENTAL_FEATURES); #endif #ifdef MONGOC_ENABLE_SSL_LIBRESSL _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SSL_LIBRESSL); #endif #ifdef MONGOC_ENABLE_SASL_CYRUS _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SASL_CYRUS); #endif #ifdef MONGOC_ENABLE_SASL_SSPI _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SASL_SSPI); #endif #ifdef MONGOC_HAVE_SOCKLEN _set_bit (bf, byte_count, MONGOC_MD_FLAG_HAVE_SOCKLEN); #endif #ifdef MONGOC_ENABLE_COMPRESSION _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_COMPRESSION); #endif #ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_COMPRESSION_SNAPPY); #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZLIB _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_COMPRESSION_ZLIB); #endif #ifdef MONGOC_HAVE_RES_NSEARCH _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_RES_NSEARCH); #endif #ifdef MONGOC_HAVE_RES_NDESTROY _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_RES_NDESTROY); #endif #ifdef MONGOC_HAVE_RES_NCLOSE _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_RES_NCLOSE); #endif #ifdef MONGOC_HAVE_RES_SEARCH _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_RES_SEARCH); #endif #ifdef MONGOC_HAVE_DNSAPI _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_DNSAPI); #endif #ifdef MONGOC_HAVE_RDTSCP _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_RDTSCP); #endif #ifdef MONGOC_HAVE_SCHED_GETCPU _set_bit (bf, byte_count, MONGOC_MD_FLAG_HAVE_SCHED_GETCPU); #endif #ifdef MONGOC_ENABLE_SHM_COUNTERS _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SHM_COUNTERS); #endif if (MONGOC_TRACE_ENABLED) { _set_bit (bf, byte_count, MONGOC_MD_FLAG_TRACE); } #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_CLIENT_SIDE_ENCRYPTION); #endif #ifdef MONGOC_ENABLE_MONGODB_AWS_AUTH _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_MONGODB_AWS_AUTH); #endif if (MONGOC_SRV_ENABLED) { _set_bit (bf, byte_count, MONGOC_MD_FLAG_ENABLE_SRV); } mcommon_string_append_t append; mcommon_string_set_append (mcommon_string_new_with_capacity ("0x", 2, 2 + byte_count * 2), &append); for (uint32_t i = 0u; i < byte_count; i++) { mcommon_string_append_printf (&append, "%02x", bf[i]); } bson_free (bf); return mcommon_string_from_append_destroy_with_steal (&append); } static char * _get_os_type (void) { #ifdef MONGOC_OS_TYPE return bson_strndup (MONGOC_OS_TYPE, HANDSHAKE_OS_TYPE_MAX); #else return bson_strndup ("unknown", HANDSHAKE_OS_TYPE_MAX); #endif } static char * _get_os_architecture (void) { const char *ret = NULL; #ifdef _WIN32 SYSTEM_INFO system_info; DWORD arch; GetSystemInfo (&system_info); arch = system_info.wProcessorArchitecture; switch (arch) { case PROCESSOR_ARCHITECTURE_AMD64: ret = "x86_64"; break; case PROCESSOR_ARCHITECTURE_ARM: ret = "ARM"; break; case PROCESSOR_ARCHITECTURE_IA64: ret = "IA64"; break; case PROCESSOR_ARCHITECTURE_INTEL: ret = "x86"; break; case PROCESSOR_ARCHITECTURE_UNKNOWN: ret = "Unknown"; break; default: ret = "Other"; break; } #elif defined(_POSIX_VERSION) struct utsname system_info; if (uname (&system_info) >= 0) { ret = system_info.machine; } #endif if (ret) { return bson_strndup (ret, HANDSHAKE_OS_ARCHITECTURE_MAX); } return NULL; } #ifndef MONGOC_OS_IS_LINUX static char * _get_os_name (void) { #ifdef MONGOC_OS_NAME return bson_strndup (MONGOC_OS_NAME, HANDSHAKE_OS_NAME_MAX); #elif defined(_POSIX_VERSION) struct utsname system_info; if (uname (&system_info) >= 0) { return bson_strndup (system_info.sysname, HANDSHAKE_OS_NAME_MAX); } #endif return NULL; } static char * _get_os_version (void) { char *ret = bson_malloc (HANDSHAKE_OS_VERSION_MAX); bool found = false; #ifdef _WIN32 OSVERSIONINFO osvi; ZeroMemory (&osvi, sizeof (OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); #if defined(_MSC_VER) // CDRIVER-4263: GetVersionEx is deprecated. #pragma warning(suppress : 4996) const BOOL res = GetVersionEx (&osvi); #else const BOOL res = GetVersionEx (&osvi); #endif if (res) { // Truncation is OK. int req = bson_snprintf ( ret, HANDSHAKE_OS_VERSION_MAX, "%lu.%lu (%lu)", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); BSON_ASSERT (req > 0); found = true; } else { MONGOC_WARNING ("Error with GetVersionEx(): %lu", GetLastError ()); } #elif defined(_POSIX_VERSION) struct utsname system_info; if (uname (&system_info) >= 0) { bson_strncpy (ret, system_info.release, HANDSHAKE_OS_VERSION_MAX); found = true; } else { MONGOC_WARNING ("Error with uname(): %d", errno); } #endif if (!found) { bson_free (ret); ret = NULL; } return ret; } #endif static void _get_system_info (mongoc_handshake_t *handshake) { handshake->os_type = _get_os_type (); #ifdef MONGOC_OS_IS_LINUX _mongoc_linux_distro_scanner_get_distro (&handshake->os_name, &handshake->os_version); #else handshake->os_name = _get_os_name (); handshake->os_version = _get_os_version (); #endif handshake->os_architecture = _get_os_architecture (); } static void _free_system_info (mongoc_handshake_t *handshake) { bson_free (handshake->os_type); bson_free (handshake->os_name); bson_free (handshake->os_version); bson_free (handshake->os_architecture); } static void _get_driver_info (mongoc_handshake_t *handshake) { handshake->driver_name = bson_strndup ("mongoc", HANDSHAKE_DRIVER_NAME_MAX); handshake->driver_version = bson_strndup (MONGOC_VERSION_S, HANDSHAKE_DRIVER_VERSION_MAX); } static void _free_driver_info (mongoc_handshake_t *handshake) { bson_free (handshake->driver_name); bson_free (handshake->driver_version); } static void _set_platform_string (mongoc_handshake_t *handshake) { handshake->platform = bson_strdup (""); } static void _free_env_info (mongoc_handshake_t *handshake) { bson_free (handshake->env_region); } static void _get_env_info (mongoc_handshake_t *handshake) { char *aws_env = _mongoc_getenv ("AWS_EXECUTION_ENV"); char *aws_lambda = _mongoc_getenv ("AWS_LAMBDA_RUNTIME_API"); char *vercel_env = _mongoc_getenv ("VERCEL"); char *azure_env = _mongoc_getenv ("FUNCTIONS_WORKER_RUNTIME"); char *gcp_env = _mongoc_getenv ("K_SERVICE"); char *memory_str = NULL; char *timeout_str = NULL; char *region_str = NULL; bool is_aws = (aws_env && strlen (aws_env) && (aws_env == strstr (aws_env, "AWS_Lambda_"))) || (aws_lambda && strlen (aws_lambda)); bool is_vercel = vercel_env && strlen (vercel_env); bool is_azure = azure_env && strlen (azure_env); bool is_gcp = gcp_env && strlen (gcp_env); handshake->env = MONGOC_HANDSHAKE_ENV_NONE; handshake->env_region = NULL; handshake->env_memory_mb.set = false; handshake->env_timeout_sec.set = false; if ((is_aws || is_vercel) + is_azure + is_gcp != 1) { goto cleanup; } if (is_aws && !is_vercel) { handshake->env = MONGOC_HANDSHAKE_ENV_AWS; region_str = _mongoc_getenv ("AWS_REGION"); memory_str = _mongoc_getenv ("AWS_LAMBDA_FUNCTION_MEMORY_SIZE"); } else if (is_vercel) { handshake->env = MONGOC_HANDSHAKE_ENV_VERCEL; region_str = _mongoc_getenv ("VERCEL_REGION"); } else if (is_gcp) { handshake->env = MONGOC_HANDSHAKE_ENV_GCP; region_str = _mongoc_getenv ("FUNCTION_REGION"); memory_str = _mongoc_getenv ("FUNCTION_MEMORY_MB"); timeout_str = _mongoc_getenv ("FUNCTION_TIMEOUT_SEC"); } else if (is_azure) { handshake->env = MONGOC_HANDSHAKE_ENV_AZURE; } if (memory_str) { char *endptr; int64_t env_memory_mb = bson_ascii_strtoll (memory_str, &endptr, 10); bool parse_ok = endptr == memory_str + (strlen (memory_str)); bool in_range = mcommon_in_range_int32_t_signed (env_memory_mb); if (parse_ok && in_range) { handshake->env_memory_mb.set = true; handshake->env_memory_mb.value = (int32_t) env_memory_mb; } } if (timeout_str) { char *endptr; int64_t env_timeout_sec = bson_ascii_strtoll (timeout_str, &endptr, 10); bool parse_ok = endptr == timeout_str + (strlen (timeout_str)); bool in_range = mcommon_in_range_int32_t_signed (env_timeout_sec); if (parse_ok && in_range) { handshake->env_timeout_sec.set = true; handshake->env_timeout_sec.value = (int32_t) env_timeout_sec; } } if (region_str && strlen (region_str)) { handshake->env_region = bson_strdup (region_str); } cleanup: bson_free (aws_env); bson_free (aws_lambda); bson_free (vercel_env); bson_free (azure_env); bson_free (gcp_env); bson_free (memory_str); bson_free (timeout_str); bson_free (region_str); } static void _set_compiler_info (mongoc_handshake_t *handshake) { mcommon_string_append_t append; mcommon_string_new_as_append (&append); char *config_str = _mongoc_handshake_get_config_hex_string (); mcommon_string_append_printf (&append, "cfg=%s", config_str); bson_free (config_str); #ifdef _POSIX_VERSION mcommon_string_append_printf (&append, " posix=%ld", _POSIX_VERSION); #endif #ifdef __STDC_VERSION__ mcommon_string_append_printf (&append, " stdc=%ld", __STDC_VERSION__); #endif mcommon_string_append_printf (&append, " CC=%s", MONGOC_COMPILER); #ifdef MONGOC_COMPILER_VERSION mcommon_string_append_printf (&append, " %s", MONGOC_COMPILER_VERSION); #endif handshake->compiler_info = mcommon_string_from_append_destroy_with_steal (&append); } static void _set_flags (mongoc_handshake_t *handshake) { mcommon_string_append_t append; mcommon_string_new_as_append (&append); if (strlen (MONGOC_EVALUATE_STR (MONGOC_USER_SET_CFLAGS)) > 0) { mcommon_string_append_printf (&append, " CFLAGS=%s", MONGOC_EVALUATE_STR (MONGOC_USER_SET_CFLAGS)); } if (strlen (MONGOC_EVALUATE_STR (MONGOC_USER_SET_LDFLAGS)) > 0) { mcommon_string_append_printf (&append, " LDFLAGS=%s", MONGOC_EVALUATE_STR (MONGOC_USER_SET_LDFLAGS)); } handshake->flags = mcommon_string_from_append_destroy_with_steal (&append); } static void _free_platform_string (mongoc_handshake_t *handshake) { bson_free (handshake->platform); bson_free (handshake->compiler_info); bson_free (handshake->flags); } void _mongoc_handshake_init (void) { _get_system_info (_mongoc_handshake_get ()); _get_driver_info (_mongoc_handshake_get ()); _set_platform_string (_mongoc_handshake_get ()); _get_env_info (_mongoc_handshake_get ()); _set_compiler_info (_mongoc_handshake_get ()); _set_flags (_mongoc_handshake_get ()); _mongoc_handshake_get ()->frozen = false; bson_mutex_init (&gHandshakeLock); } void _mongoc_handshake_cleanup (void) { mongoc_handshake_t *h = _mongoc_handshake_get (); _free_system_info (h); _free_driver_info (h); _free_platform_string (h); _free_env_info (h); *h = (mongoc_handshake_t){0}; bson_mutex_destroy (&gHandshakeLock); } static void _append_platform_field (bson_t *doc, const char *platform, bool truncate) { char *compiler_info = _mongoc_handshake_get ()->compiler_info; char *flags = _mongoc_handshake_get ()->flags; const uint32_t overhead = (/* 1 byte for utf8 tag */ 1 + /* key size */ (int) strlen (HANDSHAKE_PLATFORM_FIELD) + 1 + /* 4 bytes for length of string */ 4 + /* NUL terminator */ 1); if (truncate && doc->len >= HANDSHAKE_MAX_SIZE - overhead) { return; } mcommon_string_append_t combined_platform; mcommon_string_set_append_with_limit (mcommon_string_new_with_capacity ("", 0, HANDSHAKE_MAX_SIZE - overhead), &combined_platform, truncate ? HANDSHAKE_MAX_SIZE - overhead - doc->len : UINT32_MAX - 1u); mcommon_string_append (&combined_platform, platform); mcommon_string_append_all_or_none (&combined_platform, compiler_info); mcommon_string_append_all_or_none (&combined_platform, flags); bson_append_utf8 (doc, HANDSHAKE_PLATFORM_FIELD, strlen (HANDSHAKE_PLATFORM_FIELD), mcommon_str_from_append (&combined_platform), mcommon_strlen_from_append (&combined_platform)); mcommon_string_from_append_destroy (&combined_platform); } static bool _get_subdoc_static (bson_t *doc, char *subdoc_name, bson_t *out) { bson_iter_t iter; if (bson_iter_init_find (&iter, doc, subdoc_name) && BSON_ITER_HOLDS_DOCUMENT (&iter)) { uint32_t len; const uint8_t *data; bson_iter_document (&iter, &len, &data); BSON_ASSERT (bson_init_static (out, data, len)); return true; } return false; } static bool _truncate_handshake (bson_t **doc) { if ((*doc)->len > HANDSHAKE_MAX_SIZE) { bson_t env_doc; if (_get_subdoc_static (*doc, "env", &env_doc)) { bson_t *new_env = bson_new (); bson_copy_to_including_noinit (&env_doc, new_env, "name", NULL); bson_t *new_doc = bson_new (); bson_copy_to_excluding_noinit (*doc, new_doc, "env", NULL); bson_append_document (new_doc, "env", -1, new_env); bson_destroy (new_env); bson_destroy (*doc); *doc = new_doc; } } if ((*doc)->len > HANDSHAKE_MAX_SIZE) { bson_t os_doc; if (_get_subdoc_static (*doc, "os", &os_doc)) { bson_t *new_os = bson_new (); bson_copy_to_including_noinit (&os_doc, new_os, "type", NULL); bson_t *new_doc = bson_new (); bson_copy_to_excluding_noinit (*doc, new_doc, "os", NULL); bson_append_document (new_doc, "os", -1, new_os); bson_destroy (new_os); bson_destroy (*doc); *doc = new_doc; } } if ((*doc)->len > HANDSHAKE_MAX_SIZE) { bson_t *new_doc = bson_new (); bson_copy_to_excluding_noinit (*doc, new_doc, "env", NULL); bson_destroy (*doc); *doc = new_doc; } const mongoc_handshake_t *md = _mongoc_handshake_get (); if ((*doc)->len > HANDSHAKE_MAX_SIZE && md->platform) { bson_t *new_doc = bson_new (); bson_copy_to_excluding_noinit (*doc, new_doc, "platform", NULL); _append_platform_field (new_doc, md->platform, true); bson_destroy (*doc); *doc = new_doc; } return (*doc)->len <= HANDSHAKE_MAX_SIZE; } /* * Return true if we build the document, and it's not too big * false if there's no way to prevent the doc from being too big. In this * case, the caller shouldn't include it with hello */ bson_t * _mongoc_handshake_build_doc_with_application (const char *appname) { const mongoc_handshake_t *md = _mongoc_handshake_get (); char *env_name = NULL; switch (md->env) { case MONGOC_HANDSHAKE_ENV_AWS: env_name = "aws.lambda"; break; case MONGOC_HANDSHAKE_ENV_GCP: env_name = "gcp.func"; break; case MONGOC_HANDSHAKE_ENV_AZURE: env_name = "azure.func"; break; case MONGOC_HANDSHAKE_ENV_VERCEL: env_name = "vercel"; break; case MONGOC_HANDSHAKE_ENV_NONE: env_name = NULL; break; default: break; } bson_t *doc = bson_new (); // Optimistically include all handshake data bsonBuildAppend ( *doc, if (appname, then (kv ("application", doc (kv ("name", cstr (appname)))))), kv ("driver", doc (kv ("name", cstr (md->driver_name)), kv ("version", cstr (md->driver_version)))), kv ("os", doc (kv ("type", cstr (md->os_type)), if (md->os_name, then (kv ("name", cstr (md->os_name)))), if (md->os_version, then (kv ("version", cstr (md->os_version)))), if (md->os_architecture, then (kv ("architecture", cstr (md->os_architecture)))))), if (env_name, then (kv ("env", doc (kv ("name", cstr (env_name)), if (md->env_timeout_sec.set, then (kv ("timeout_sec", int32 (md->env_timeout_sec.value)))), if (md->env_memory_mb.set, then (kv ("memory_mb", int32 (md->env_memory_mb.value)))), if (md->env_region, then (kv ("region", cstr (md->env_region))))))))); if (md->platform) { _append_platform_field (doc, md->platform, false); } if (_truncate_handshake (&doc)) { return doc; } else { bson_destroy (doc); return NULL; } } void _mongoc_handshake_freeze (void) { bson_mutex_lock (&gHandshakeLock); _mongoc_handshake_get ()->frozen = true; bson_mutex_unlock (&gHandshakeLock); } static void _mongoc_handshake_freeze_nolock (void) { _mongoc_handshake_get ()->frozen = true; } /* * free (*s) and make *s point to *s concated with suffix. * If *s is NULL it's treated like it's an empty string. */ static void _append_and_truncate (char **s, const char *suffix, size_t max_len) { char *old_str = *s; const size_t delim_len = strlen (" / "); BSON_ASSERT_PARAM (s); BSON_ASSERT_PARAM (suffix); const char *const prefix = old_str ? old_str : ""; const size_t required_space = strlen (prefix) + delim_len; if (max_len <= required_space) { /* the old string already takes the whole allotted space */ return; } const size_t space_for_suffix = max_len - required_space; BSON_ASSERT (mcommon_in_range_unsigned (int, space_for_suffix)); *s = bson_strdup_printf ("%s / %.*s", prefix, (int) space_for_suffix, suffix); BSON_ASSERT (strlen (*s) <= max_len); bson_free (old_str); } /* * Set some values in our global handshake struct. These values will be sent * to the server as part of the initial connection handshake (hello). * If this function is called more than once, or after we've connected to a * mongod, then it will do nothing and return false. It will return true if * it successfully sets the values. * * All arguments are optional. */ bool mongoc_handshake_data_append (const char *driver_name, const char *driver_version, const char *platform) { int platform_space; bson_mutex_lock (&gHandshakeLock); if (_mongoc_handshake_get ()->frozen) { bson_mutex_unlock (&gHandshakeLock); return false; } BSON_ASSERT (_mongoc_handshake_get ()->platform); /* allow practically any size for "platform", we'll trim it down in * _mongoc_handshake_build_doc_with_application */ platform_space = HANDSHAKE_MAX_SIZE - (int) strlen (_mongoc_handshake_get ()->platform); if (platform) { /* we check for an empty string as a special case to avoid an * unnecessary delimiter being added in front of the string by * _append_and_truncate */ if (_mongoc_handshake_get ()->platform[0] == '\0') { bson_free (_mongoc_handshake_get ()->platform); _mongoc_handshake_get ()->platform = bson_strdup_printf ("%.*s", platform_space, platform); } else { _append_and_truncate (&_mongoc_handshake_get ()->platform, platform, HANDSHAKE_MAX_SIZE); } } if (driver_name) { _append_and_truncate (&_mongoc_handshake_get ()->driver_name, driver_name, HANDSHAKE_DRIVER_NAME_MAX); } if (driver_version) { _append_and_truncate (&_mongoc_handshake_get ()->driver_version, driver_version, HANDSHAKE_DRIVER_VERSION_MAX); } _mongoc_handshake_freeze_nolock (); bson_mutex_unlock (&gHandshakeLock); return true; } mongoc_handshake_t * _mongoc_handshake_get (void) { return &gMongocHandshake; } bool _mongoc_handshake_appname_is_valid (const char *appname) { return strlen (appname) <= MONGOC_HANDSHAKE_APPNAME_MAX; } void _mongoc_handshake_append_sasl_supported_mechs (const mongoc_uri_t *uri, bson_t *cmd) { const char *username; char *db_user; username = mongoc_uri_get_username (uri); db_user = bson_strdup_printf ("%s.%s", mongoc_uri_get_auth_source (uri), username); bson_append_utf8 (cmd, "saslSupportedMechs", 18, db_user, -1); bson_free (db_user); } void _mongoc_handshake_parse_sasl_supported_mechs (const bson_t *hello, mongoc_handshake_sasl_supported_mechs_t *sasl_supported_mechs) { memset (sasl_supported_mechs, 0, sizeof (*sasl_supported_mechs)); bsonParse (*hello, find (keyWithType ("saslSupportedMechs", array), visitEach (case (when (strEqual ("SCRAM-SHA-256"), do (sasl_supported_mechs->scram_sha_256 = true)), when (strEqual ("SCRAM-SHA-1"), do (sasl_supported_mechs->scram_sha_1 = true)))))); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-handshake.h0000644000175100001660000000170614760300420023071 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_HANDSHAKE_H #define MONGOC_HANDSHAKE_H #include #include BSON_BEGIN_DECLS #define MONGOC_HANDSHAKE_APPNAME_MAX 128 MONGOC_EXPORT (bool) mongoc_handshake_data_append (const char *driver_name, const char *driver_version, const char *platform); BSON_END_DECLS #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-host-list-private.h0000644000175100001660000000357614760300420024550 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_HOST_LIST_PRIVATE_H #define MONGOC_HOST_LIST_PRIVATE_H #include BSON_BEGIN_DECLS void _mongoc_host_list_upsert (mongoc_host_list_t **list, const mongoc_host_list_t *new_host); mongoc_host_list_t * _mongoc_host_list_copy_all (const mongoc_host_list_t *src); bool _mongoc_host_list_from_string (mongoc_host_list_t *host_list, const char *host_and_port); bool _mongoc_host_list_from_string_with_err (mongoc_host_list_t *host_list, const char *host_and_port, bson_error_t *error); bool _mongoc_host_list_from_hostport_with_err (mongoc_host_list_t *host_list, const char *host, uint16_t port, bson_error_t *error); size_t _mongoc_host_list_length (const mongoc_host_list_t *list); bool _mongoc_host_list_compare_one (const mongoc_host_list_t *host_a, const mongoc_host_list_t *host_b); void _mongoc_host_list_remove_host (mongoc_host_list_t **phosts, const char *host, uint16_t port); void _mongoc_host_list_destroy_all (mongoc_host_list_t *host); bool _mongoc_host_list_contains_one (mongoc_host_list_t *host_list, mongoc_host_list_t *host); BSON_END_DECLS #endif /* MONGOC_HOST_LIST_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-host-list.c0000644000175100001660000002425314760300420023066 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include // PRIu16 #include /* strcasecmp on windows */ #include #include #include static mongoc_host_list_t * _mongoc_host_list_find_host_and_port (mongoc_host_list_t *hosts, const char *host_and_port) { mongoc_host_list_t *iter; LL_FOREACH (hosts, iter) { BSON_ASSERT (iter); if (strcasecmp (iter->host_and_port, host_and_port) == 0) { return iter; } } return NULL; } /* *-------------------------------------------------------------------------- * * _mongoc_host_list_upsert -- * * If new_host is not already in list, copy and add it to the end of list. * If *list == NULL, then it will be set to a new host. * * Returns: * Nothing. * *-------------------------------------------------------------------------- */ void _mongoc_host_list_upsert (mongoc_host_list_t **list, const mongoc_host_list_t *new_host) { mongoc_host_list_t *link = NULL; mongoc_host_list_t *next_link = NULL; BSON_ASSERT (list); if (!new_host) { return; } link = _mongoc_host_list_find_host_and_port (*list, new_host->host_and_port); if (!link) { link = bson_malloc0 (sizeof (mongoc_host_list_t)); LL_APPEND (*list, link); } else { /* Make sure linking is preserved when copying data into final. */ next_link = link->next; } memcpy (link, new_host, sizeof (mongoc_host_list_t)); link->next = next_link; } /* Duplicates a host list. */ mongoc_host_list_t * _mongoc_host_list_copy_all (const mongoc_host_list_t *src) { mongoc_host_list_t *tail = NULL; const mongoc_host_list_t *src_iter; mongoc_host_list_t *head = NULL; LL_FOREACH (src, src_iter) { tail = bson_malloc0 (sizeof (mongoc_host_list_t)); memcpy (tail, src_iter, sizeof (mongoc_host_list_t)); LL_PREPEND (head, tail); } return head; } size_t _mongoc_host_list_length (const mongoc_host_list_t *list) { const mongoc_host_list_t *tmp; size_t counter = 0u; tmp = list; while (tmp) { tmp = tmp->next; counter++; } return counter; } /* *-------------------------------------------------------------------------- * * _mongoc_host_list_compare_one -- * * Check two hosts have the same domain (case-insensitive), port, * and address family. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool _mongoc_host_list_compare_one (const mongoc_host_list_t *host_a, const mongoc_host_list_t *host_b) { return (0 == strcasecmp (host_a->host_and_port, host_b->host_and_port) && host_a->family == host_b->family); } bool _mongoc_host_list_contains_one (mongoc_host_list_t *host_list, mongoc_host_list_t *host) { return NULL != _mongoc_host_list_find_host_and_port (host_list, host->host_and_port); } /* *-------------------------------------------------------------------------- * * _mongoc_host_list_destroy_all -- * * Destroy whole linked list of hosts. * *-------------------------------------------------------------------------- */ void _mongoc_host_list_destroy_all (mongoc_host_list_t *host) { mongoc_host_list_t *tmp; while (host) { tmp = host->next; bson_free (host); host = tmp; } } /* *-------------------------------------------------------------------------- * * _mongoc_host_list_from_string -- * * Populate a mongoc_host_list_t from a fully qualified address * *-------------------------------------------------------------------------- */ bool _mongoc_host_list_from_string (mongoc_host_list_t *link_, const char *address) { bson_error_t error = {0}; bool r = _mongoc_host_list_from_string_with_err (link_, address, &error); if (!r) { MONGOC_ERROR ("Could not parse address %s: %s", address, error.message); return false; } return true; } bool _mongoc_host_list_from_string_with_err (mongoc_host_list_t *link_, const char *address, bson_error_t *error) { char *close_bracket; char *sport; uint16_t port; char *host; bool ret; bool ipv6 = false; close_bracket = strchr (address, ']'); /* if this is an ipv6 address. */ if (close_bracket) { /* if present, the port should immediately follow after ] */ sport = strchr (close_bracket, ':'); if (sport > close_bracket + 1) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "If present, port should immediately follow the \"]\"" "in an IPv6 address"); return false; } /* otherwise ] should be the last char. */ if (!sport && *(close_bracket + 1) != '\0') { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "If port is not supplied, \"[\" should be the last" "character"); return false; } if (*address != '[') { bson_set_error ( error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Missing matching bracket \"[\""); return false; } ipv6 = true; } /* otherwise, just find the first : */ else { sport = strchr (address, ':'); } /* like "example.com:27019" or "[fe80::1]:27019", but not "[fe80::1]" */ if (sport) { if (sport == address) { /* bad address like ":27017" */ bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Bad address, \":\" should not be first character"); return false; } if (!mongoc_parse_port (&port, sport + 1)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Port could not be parsed"); return false; } /* if this is an ipv6 address, strip the [ and ] */ if (ipv6) { host = bson_strndup (address + 1, close_bracket - address - 1); } else { host = bson_strndup (address, sport - address); } } else { /* if this is an ipv6 address, strip the [ and ] */ if (ipv6) { host = bson_strndup (address + 1, close_bracket - address - 1); } else { host = bson_strdup (address); } port = MONGOC_DEFAULT_PORT; } ret = _mongoc_host_list_from_hostport_with_err (link_, host, port, error); bson_free (host); return ret; } bool _mongoc_host_list_from_hostport_with_err (mongoc_host_list_t *link_, const char *host, uint16_t port, bson_error_t *error) { BSON_ASSERT (host); BSON_ASSERT (link_); size_t host_len = strlen (host); *link_ = (mongoc_host_list_t){ .next = NULL, .port = port, }; if (host_len == 0) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "Empty hostname in URI"); return false; } if (host_len > BSON_HOST_NAME_MAX) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "Hostname provided in URI is too long, max is %d chars", BSON_HOST_NAME_MAX); return false; } bson_strncpy (link_->host, host, host_len + 1); /* like "fe80::1" or "::1" */ if (strchr (host, ':')) { link_->family = AF_INET6; // Check that IPv6 literal is two less than the max to account for `[` and // `]` added below. if (host_len > BSON_HOST_NAME_MAX - 2) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "IPv6 literal provided in URI is too long, max is %d chars", BSON_HOST_NAME_MAX - 2); return false; } mongoc_lowercase (link_->host, link_->host); int req = bson_snprintf (link_->host_and_port, sizeof link_->host_and_port, "[%s]:%" PRIu16, link_->host, link_->port); BSON_ASSERT (mcommon_in_range_size_t_signed (req)); // Use `<`, not `<=` to account for NULL byte. BSON_ASSERT ((size_t) req < sizeof link_->host_and_port); } else if (strchr (host, '/') && strstr (host, ".sock")) { link_->family = AF_UNIX; bson_strncpy (link_->host_and_port, link_->host, host_len + 1); } else { /* This is either an IPv4 or hostname. */ link_->family = AF_UNSPEC; mongoc_lowercase (link_->host, link_->host); int req = bson_snprintf (link_->host_and_port, sizeof link_->host_and_port, "%s:%" PRIu16, link_->host, link_->port); BSON_ASSERT (mcommon_in_range_size_t_signed (req)); // Use `<`, not `<=` to account for NULL byte. BSON_ASSERT ((size_t) req < sizeof link_->host_and_port); } return true; } void _mongoc_host_list_remove_host (mongoc_host_list_t **hosts, const char *host, uint16_t port) { mongoc_host_list_t *current; mongoc_host_list_t *prev = NULL; for (current = *hosts; current; prev = current, current = current->next) { if ((current->port == port) && (strcmp (current->host, host) == 0)) { /* Node found, unlink. */ if (prev) { prev->next = current->next; } else { /* No previous, unlinking at head. */ *hosts = current->next; } bson_free (current); break; } } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-host-list.h0000644000175100001660000000222014760300420023061 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_HOST_LIST_H #define MONGOC_HOST_LIST_H #include BSON_BEGIN_DECLS #ifdef _POSIX_HOST_NAME_MAX #define BSON_HOST_NAME_MAX _POSIX_HOST_NAME_MAX #else #define BSON_HOST_NAME_MAX 255 #endif typedef struct _mongoc_host_list_t mongoc_host_list_t; struct _mongoc_host_list_t { mongoc_host_list_t *next; char host[BSON_HOST_NAME_MAX + 1]; char host_and_port[BSON_HOST_NAME_MAX + 7]; uint16_t port; int family; void *padding[4]; }; BSON_END_DECLS #endif /* MONGOC_HOST_LIST_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-http-private.h0000644000175100001660000000612214760300420023567 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #ifndef MONGOC_HTTP_PRIVATE_H #define MONGOC_HTTP_PRIVATE_H typedef struct { const char *host; int port; const char *method; const char *path; const char *extra_headers; const char *body; int body_len; } mongoc_http_request_t; typedef struct { int status; char *headers; int headers_len; char *body; int body_len; } mongoc_http_response_t; void _mongoc_http_request_init (mongoc_http_request_t *request); void _mongoc_http_response_init (mongoc_http_response_t *response); void _mongoc_http_response_cleanup (mongoc_http_response_t *response); /** * @brief Render the HTTP request head based on the given HTTP parameters. * * @param append Destination for the HTTP request head, as an mcommon_string_append_t initialized with * mcommon_string_set_append(). * @param req The request to render (required) * * @note The request body (if applicable) is not included in the resulting * string. */ void _mongoc_http_render_request_head (mcommon_string_append_t *append, const mongoc_http_request_t *req); /** * @brief Convenience function to send an HTTP request and receive an HTTP * response. * * This function only speaks HTTP 1.0, and does not maintain a persistent * connection. It does not handle 3xx redirects nor 1xx information. * * @param req The request to send. Uses the "host" attribute to determine the * HTTP peer. * @param timeout_ms A timeout for the request, in milliseconds * @param use_tls Whether the connection should use TLS. * @param ssl_opts Options to control TLS (Required only if 'use_tls' is true) * @param res Output parameter for the response. Must be uninitialized. * Required. This object must later be destroyed with * _mongoc_http_response_cleanup. * @param error An output parameter for any possible errors. These are errors * related to the HTTP transmission, and unrelated to any HTTP response. * (Optional) * @return true Upon success * @return false Otherwise, and sets "error" * * For more transport control, the HTTP request head content can be manually * rendered using @ref _mongo_http_render_request_head. */ bool _mongoc_http_send (mongoc_http_request_t const *req, int timeout_ms, bool use_tls, mongoc_ssl_opt_t *ssl_opts, mongoc_http_response_t *res, bson_error_t *error); #endif /* MONGOC_HTTP_PRIVATE */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-http.c0000644000175100001660000002173514760300420022121 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include void _mongoc_http_request_init (mongoc_http_request_t *request) { memset (request, 0, sizeof (*request)); } void _mongoc_http_response_init (mongoc_http_response_t *response) { memset (response, 0, sizeof (*response)); } void _mongoc_http_response_cleanup (mongoc_http_response_t *response) { if (!response) { return; } bson_free (response->headers); bson_free (response->body); } void _mongoc_http_render_request_head (mcommon_string_append_t *append, const mongoc_http_request_t *req) { BSON_ASSERT_PARAM (req); mcommon_string_append_printf (append, "%s ", req->method); // Default paths if (!req->path) { // Top path: mcommon_string_append (append, "/"); } else if (req->path[0] != '/') { // Path MUST be prefixed with a separator mcommon_string_append (append, "/"); mcommon_string_append (append, req->path); } else { // Just copy the path mcommon_string_append (append, req->path); } mcommon_string_append (append, " HTTP/1.0\r\n"); /* Always add Host header. */ mcommon_string_append_printf (append, "Host: %s:%d\r\n", req->host, req->port); /* Always add Connection: close header to ensure server closes connection. */ mcommon_string_append (append, "Connection: close\r\n"); /* Add Content-Length if body is included. */ if (req->body_len) { mcommon_string_append_printf (append, "Content-Length: %d\r\n", req->body_len); } // Add any extra headers if (req->extra_headers) { mcommon_string_append (append, req->extra_headers); } // Final terminator mcommon_string_append (append, "\r\n"); } static int32_t _mongoc_http_msec_remaining (mcd_timer timer) { const int64_t msec = mcd_get_milliseconds (mcd_timer_remaining (timer)); BSON_ASSERT (mcommon_in_range_signed (int32_t, msec)); return (int32_t) msec; } bool _mongoc_http_send (const mongoc_http_request_t *req, int timeout_ms, bool use_tls, mongoc_ssl_opt_t *ssl_opts, mongoc_http_response_t *res, bson_error_t *error) { mongoc_stream_t *stream = NULL; mongoc_host_list_t host_list; bool ret = false; mongoc_iovec_t iovec; char *path = NULL; mongoc_buffer_t http_response_buf; char *http_response_str; char *ptr; const char *header_delimiter = "\r\n\r\n"; const mcd_timer timer = mcd_timer_expire_after (mcd_milliseconds (timeout_ms)); mcommon_string_append_t http_request; mcommon_string_new_as_append (&http_request); memset (res, 0, sizeof (*res)); _mongoc_buffer_init (&http_response_buf, NULL, 0, NULL, NULL); if (!_mongoc_host_list_from_hostport_with_err (&host_list, req->host, (uint16_t) req->port, error)) { goto fail; } stream = mongoc_client_connect_tcp ( // +1 to prevent passing zero as a timeout _mongoc_http_msec_remaining (timer) + 1, &host_list, error); if (!stream) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to connect to: %s", req->host); goto fail; } #ifndef MONGOC_ENABLE_SSL if (use_tls) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to connect to %s: libmongoc not built with TLS support", req->host); goto fail; } #else if (use_tls) { mongoc_stream_t *tls_stream; BSON_ASSERT (ssl_opts); tls_stream = mongoc_stream_tls_new_with_hostname (stream, req->host, ssl_opts, true); if (!tls_stream) { bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed create TLS stream to: %s", req->host); goto fail; } stream = tls_stream; if (!mongoc_stream_tls_handshake_block (stream, req->host, _mongoc_http_msec_remaining (timer), error)) { goto fail; } } #endif if (!req->path) { path = bson_strdup ("/"); } else if (req->path[0] != '/') { path = bson_strdup_printf ("/%s", req->path); } else { path = bson_strdup (req->path); } _mongoc_http_render_request_head (&http_request, req); iovec.iov_base = mcommon_str_from_append (&http_request); iovec.iov_len = mcommon_strlen_from_append (&http_request); if (!_mongoc_stream_writev_full (stream, &iovec, 1, _mongoc_http_msec_remaining (timer), error)) { goto fail; } if (req->body && req->body_len) { iovec.iov_base = (void *) req->body; iovec.iov_len = req->body_len; if (!_mongoc_stream_writev_full (stream, &iovec, 1, _mongoc_http_msec_remaining (timer), error)) { goto fail; } } /* Read until connection close. */ while (1) { const ssize_t bytes_read = _mongoc_buffer_try_append_from_stream ( &http_response_buf, stream, 1024 * 32, _mongoc_http_msec_remaining (timer)); if (mongoc_stream_should_retry (stream)) { continue; } if (bytes_read <= 0) { break; } if (http_response_buf.len > 1024 * 1024 * 8) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "HTTP response message is too large"); goto fail; } } if (mongoc_stream_timed_out (stream)) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Timeout reading from stream"); goto fail; } if (http_response_buf.len == 0) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "No response received"); goto fail; } http_response_str = (char *) http_response_buf.data; const char *const resp_end_ptr = http_response_str + http_response_buf.len; const char *proto_leader_10 = "HTTP/1.0 "; const char *proto_leader_11 = "HTTP/1.1 "; ptr = strstr (http_response_str, proto_leader_10); if (!ptr) { ptr = strstr (http_response_str, proto_leader_11); } if (!ptr) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "No HTTP version leader in HTTP response. Expected '%s' or '%s'", proto_leader_10, proto_leader_11); goto fail; } /* Both protocol leaders have the same length. */ ptr += strlen (proto_leader_10); ssize_t remain = resp_end_ptr - ptr; if (remain < 4) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Short read in HTTP response"); goto fail; } char status_buf[4] = {0}; memcpy (status_buf, ptr, 3); char *status_endptr; res->status = strtol (status_buf, &status_endptr, 10); if (status_endptr != status_buf + 3) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Invalid HTTP response status string %*.s", 4, status_buf); goto fail; } /* Find the end of the headers. */ ptr = strstr (http_response_str, header_delimiter); if (NULL == ptr) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Error occurred reading response: end of headers not found"); goto fail; } const size_t headers_len = (size_t) (ptr - http_response_str); BSON_ASSERT (mcommon_in_range_unsigned (int, headers_len)); const size_t body_len = http_response_buf.len - headers_len - strlen (header_delimiter); BSON_ASSERT (mcommon_in_range_unsigned (int, body_len)); res->headers_len = (int) headers_len; res->headers = bson_strndup (http_response_str, (size_t) headers_len); res->body_len = (int) body_len; /* Add a NULL character in case caller assumes NULL terminated. */ res->body = bson_malloc0 (body_len + 1u); memcpy (res->body, ptr + strlen (header_delimiter), body_len); ret = true; fail: mongoc_stream_destroy (stream); mcommon_string_from_append_destroy (&http_request); _mongoc_buffer_destroy (&http_response_buf); bson_free (path); return ret; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-index.c0000644000175100001660000000504614760300420022246 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "gridfs_index" static mongoc_index_opt_t gMongocIndexOptDefault = { 1, /* is_initialized */ 0, /* background */ 0, /* unique */ NULL, /* name */ 0, /* drop_dups */ 0, /* sparse */ -1, /* expire_after_seconds */ -1, /* v */ NULL, /* weights */ NULL, /* default_language */ NULL, /* language_override */ NULL, /* mongoc_index_opt_geo_t geo_options */ NULL, /* mongoc_index_opt_storage_t storage_options */ NULL, /* partial_filter_expression */ NULL, /* collation */ {NULL} /* struct padding */ }; static mongoc_index_opt_geo_t gMongocIndexOptGeoDefault = { 26, /* twod_sphere_version */ -90, /* twod_bits_precision */ 90, /* twod_location_min */ -1, /* twod_location_max */ 2, /* haystack_bucket_size */ {NULL} /* struct padding */ }; static mongoc_index_opt_wt_t gMongocIndexOptWTDefault = { {MONGOC_INDEX_STORAGE_OPT_WIREDTIGER}, /* mongoc_index_opt_storage_t */ "", /* config_str */ {NULL} /* struct padding */ }; const mongoc_index_opt_t * mongoc_index_opt_get_default (void) { return &gMongocIndexOptDefault; } const mongoc_index_opt_geo_t * mongoc_index_opt_geo_get_default (void) { return &gMongocIndexOptGeoDefault; } const mongoc_index_opt_wt_t * mongoc_index_opt_wt_get_default (void) { return &gMongocIndexOptWTDefault; } void mongoc_index_opt_init (mongoc_index_opt_t *opt) { BSON_ASSERT (opt); memcpy (opt, &gMongocIndexOptDefault, sizeof *opt); } void mongoc_index_opt_geo_init (mongoc_index_opt_geo_t *opt) { BSON_ASSERT (opt); memcpy (opt, &gMongocIndexOptGeoDefault, sizeof *opt); } void mongoc_index_opt_wt_init (mongoc_index_opt_wt_t *opt) { BSON_ASSERT (opt); memcpy (opt, &gMongocIndexOptWTDefault, sizeof *opt); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-index.h0000644000175100001660000000445614760300420022257 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_INDEX_H #define MONGOC_INDEX_H #include #include BSON_BEGIN_DECLS typedef struct { uint8_t twod_sphere_version; uint8_t twod_bits_precision; double twod_location_min; double twod_location_max; double haystack_bucket_size; uint8_t *padding[32]; } mongoc_index_opt_geo_t; typedef struct { int type; } mongoc_index_opt_storage_t; typedef enum { MONGOC_INDEX_STORAGE_OPT_MMAPV1, MONGOC_INDEX_STORAGE_OPT_WIREDTIGER, } mongoc_index_storage_opt_type_t; typedef struct { mongoc_index_opt_storage_t base; const char *config_str; void *padding[8]; } mongoc_index_opt_wt_t; typedef struct { bool is_initialized; bool background; bool unique; const char *name; bool drop_dups; bool sparse; int32_t expire_after_seconds; int32_t v; const bson_t *weights; const char *default_language; const char *language_override; mongoc_index_opt_geo_t *geo_options; mongoc_index_opt_storage_t *storage_options; const bson_t *partial_filter_expression; const bson_t *collation; void *padding[4]; } mongoc_index_opt_t; MONGOC_EXPORT (const mongoc_index_opt_t *) mongoc_index_opt_get_default (void) BSON_GNUC_PURE; MONGOC_EXPORT (const mongoc_index_opt_geo_t *) mongoc_index_opt_geo_get_default (void) BSON_GNUC_PURE; MONGOC_EXPORT (const mongoc_index_opt_wt_t *) mongoc_index_opt_wt_get_default (void) BSON_GNUC_PURE; MONGOC_EXPORT (void) mongoc_index_opt_init (mongoc_index_opt_t *opt); MONGOC_EXPORT (void) mongoc_index_opt_geo_init (mongoc_index_opt_geo_t *opt); MONGOC_EXPORT (void) mongoc_index_opt_wt_init (mongoc_index_opt_wt_t *opt); BSON_END_DECLS #endif /* MONGOC_INDEX_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-init.c0000644000175100001660000001225114760300420022076 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #elif defined(MONGOC_ENABLE_SSL_LIBRESSL) #include #endif #include #include #if defined(MONGOC_ENABLE_CRYPTO_CNG) #include #include #endif #ifdef MONGOC_ENABLE_MONGODB_AWS_AUTH #include #endif #ifdef MONGOC_ENABLE_OCSP_OPENSSL #include #endif #ifndef MONGOC_NO_AUTOMATIC_GLOBALS #pragma message("Configure the driver with ENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF.\ Automatic cleanup is deprecated and will be removed in version 2.0.") #endif #ifdef MONGOC_ENABLE_SASL_CYRUS #include #include // _mongoc_cyrus_verifyfile_cb static void * mongoc_cyrus_mutex_alloc (void) { bson_mutex_t *mutex; mutex = (bson_mutex_t *) bson_malloc0 (sizeof (bson_mutex_t)); bson_mutex_init (mutex); return (void *) mutex; } static int mongoc_cyrus_mutex_lock (void *mutex) { bson_mutex_lock ((bson_mutex_t *) mutex); return SASL_OK; } static int mongoc_cyrus_mutex_unlock (void *mutex) { bson_mutex_unlock ((bson_mutex_t *) mutex); return SASL_OK; } static void mongoc_cyrus_mutex_free (void *mutex) { bson_mutex_destroy ((bson_mutex_t *) mutex); bson_free (mutex); } #endif /* MONGOC_ENABLE_SASL_CYRUS */ static BSON_ONCE_FUN (_mongoc_do_init) { #ifdef MONGOC_ENABLE_SASL_CYRUS int status; #endif #ifdef MONGOC_ENABLE_SSL_OPENSSL _mongoc_openssl_init (); #elif defined(MONGOC_ENABLE_SSL_LIBRESSL) tls_init (); #endif #ifdef MONGOC_ENABLE_SASL_CYRUS /* The following functions should not use tracing, as they may be invoked * before mongoc_log_set_handler() can complete. */ sasl_set_mutex ( mongoc_cyrus_mutex_alloc, mongoc_cyrus_mutex_lock, mongoc_cyrus_mutex_unlock, mongoc_cyrus_mutex_free); MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_BEGIN sasl_callback_t callbacks[] = {// Include callback to disable loading plugins. {SASL_CB_VERIFYFILE, SASL_CALLBACK_FN (_mongoc_cyrus_verifyfile_cb), NULL}, {SASL_CB_LIST_END}}; MC_DISABLE_CAST_FUNCTION_TYPE_STRICT_WARNING_END status = sasl_client_init (callbacks); BSON_ASSERT (status == SASL_OK); #endif _mongoc_counters_init (); #ifdef _WIN32 { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD (2, 2); err = WSAStartup (wVersionRequested, &wsaData); /* check the version perhaps? */ BSON_ASSERT (err == 0); } #endif #if defined(MONGOC_ENABLE_CRYPTO_CNG) mongoc_crypto_cng_init (); #endif _mongoc_handshake_init (); #if defined(MONGOC_ENABLE_MONGODB_AWS_AUTH) kms_message_init (); _mongoc_aws_credentials_cache_init (); #endif #if defined(MONGOC_ENABLE_OCSP_OPENSSL) _mongoc_ocsp_cache_init (); #endif BSON_ONCE_RETURN; } void mongoc_init (void) { static bson_once_t once = BSON_ONCE_INIT; bson_once (&once, _mongoc_do_init); } static BSON_ONCE_FUN (_mongoc_do_cleanup) { #ifdef MONGOC_ENABLE_SSL_OPENSSL _mongoc_openssl_cleanup (); #endif #ifdef MONGOC_ENABLE_SASL_CYRUS #ifdef MONGOC_HAVE_SASL_CLIENT_DONE sasl_client_done (); #else /* fall back to deprecated function */ sasl_done (); #endif #endif #ifdef _WIN32 WSACleanup (); #endif #if defined(MONGOC_ENABLE_CRYPTO_CNG) mongoc_crypto_cng_cleanup (); #endif _mongoc_counters_cleanup (); _mongoc_handshake_cleanup (); #if defined(MONGOC_ENABLE_MONGODB_AWS_AUTH) kms_message_cleanup (); _mongoc_aws_credentials_cache_cleanup (); #endif #if defined(MONGOC_ENABLE_OCSP_OPENSSL) _mongoc_ocsp_cache_cleanup (); #endif BSON_ONCE_RETURN; } void mongoc_cleanup (void) { static bson_once_t once = BSON_ONCE_INIT; bson_once (&once, _mongoc_do_cleanup); } /* * On GCC, just use __attribute__((constructor)) to perform initialization * automatically for the application. */ #if defined(__GNUC__) && !defined(MONGOC_NO_AUTOMATIC_GLOBALS) static void _mongoc_init_ctor (void) __attribute__ ((constructor)); static void _mongoc_init_ctor (void) { mongoc_init (); } static void _mongoc_init_dtor (void) __attribute__ ((destructor)); static void _mongoc_init_dtor (void) { bson_mem_restore_vtable (); mongoc_cleanup (); } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-init.h0000644000175100001660000000157614760300420022113 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_INIT_H #define MONGOC_INIT_H #include #include BSON_BEGIN_DECLS MONGOC_EXPORT (void) mongoc_init (void); MONGOC_EXPORT (void) mongoc_cleanup (void); BSON_END_DECLS #endif /* MONGOC_INIT_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-interrupt-private.h0000644000175100001660000000372014760300420024645 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_INTERRUPTIBLE_PRIVATE_H #define MONGOC_STREAM_INTERRUPTIBLE_PRIVATE_H #include /* Creates a stream to use to interrupt calls to mongoc_stream_poll. * * The expected use is to cancel in-progress hello commands (especially for * awaitable hello). A hello command may not respond for a long time, so * reading the reply may block on mongoc_stream_poll until data is readable. To * interrupt mongoc_stream_poll, a stream retrieved by * _mongoc_interrupt_get_stream can be added to the call of poll. Any other * thread can call _mongoc_interrupt_interrupt to write to that stream. */ typedef struct _mongoc_interrupt_t mongoc_interrupt_t; mongoc_interrupt_t * _mongoc_interrupt_new (uint32_t timeout_ms); /* Interrupt the stream. An in progress poll for POLLIN should return. */ bool _mongoc_interrupt_interrupt (mongoc_interrupt_t *interrupt); /* Returns a socket stream, that can be polled alongside other * socket streams. */ mongoc_stream_t * _mongoc_interrupt_get_stream (mongoc_interrupt_t *interrupt); /* Flushes queued data on an interrupt. * * This is not guaranteed to flush all data, but it does not block. */ bool _mongoc_interrupt_flush (mongoc_interrupt_t *interrupt); void _mongoc_interrupt_destroy (mongoc_interrupt_t *interrupt); #endif /* MONGOC_STREAM_INTERRUPTIBLE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-interrupt.c0000644000175100001660000002132114760300420023165 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include /* The interrupt stream is implemented in two ways. * On POSIX, this uses the self-pipe trick. * On Windows, this uses a pair of TCP sockets. */ struct _mongoc_interrupt_t { bson_mutex_t mutex; union { /* For POSIX. pipe_fds[0] is the read end and pipe_fds[1] is the write * end. */ int pipe_fds[2]; /* For Windows */ struct { mongoc_socket_t *read; mongoc_socket_t *write; } socket_pair; } impl; mongoc_stream_t *stream; }; mongoc_stream_t * _mongoc_interrupt_get_stream (mongoc_interrupt_t *interrupt) { return interrupt->stream; } static void _log_errno (char *prefix, int _errno) { char buf[128] = {0}; bson_strerror_r (_errno, buf, sizeof (buf)); MONGOC_ERROR ("%s: (%d) %s", prefix, _errno, buf); } #ifdef _WIN32 /* TCP socket pair implementation. */ mongoc_interrupt_t * _mongoc_interrupt_new (uint32_t timeout_ms) { mongoc_interrupt_t *interrupt; mongoc_socket_t *listen_socket = NULL; mongoc_socket_t *interrupt_socket = NULL; struct sockaddr_storage server_addr; mongoc_socklen_t sock_len; int ret; bool success = false; struct sockaddr_in server_addr_in = {0}; ENTRY; interrupt = (mongoc_interrupt_t *) bson_malloc0 (sizeof *interrupt); bson_mutex_init (&interrupt->mutex); /* Inspired by cpython's implementation of socketpair. */ listen_socket = mongoc_socket_new (AF_INET, SOCK_STREAM, 0); if (!listen_socket) { MONGOC_ERROR ("socket creation failed"); GOTO (fail); } memset (&server_addr_in, 0, sizeof (server_addr_in)); server_addr_in.sin_family = AF_INET; server_addr_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); ret = mongoc_socket_bind (listen_socket, (struct sockaddr *) &server_addr_in, sizeof (server_addr_in)); if (ret == -1) { _log_errno ("bind failed", mongoc_socket_errno (listen_socket)); GOTO (fail); } ret = mongoc_socket_listen (listen_socket, 1); if (ret == -1) { _log_errno ("listen failed", mongoc_socket_errno (listen_socket)); GOTO (fail); } sock_len = sizeof (server_addr); ret = mongoc_socket_getsockname (listen_socket, (struct sockaddr *) &server_addr, &sock_len); if (-1 == ret) { _log_errno ("getsockname failed", mongoc_socket_errno (listen_socket)); GOTO (fail); } interrupt->impl.socket_pair.read = mongoc_socket_new (server_addr.ss_family, SOCK_STREAM, 0); if (!interrupt->impl.socket_pair.read) { MONGOC_ERROR ("socket creation failed"); GOTO (fail); } /* Begin non-blocking connect. */ ret = mongoc_socket_connect (interrupt->impl.socket_pair.read, (struct sockaddr *) &server_addr, sock_len, 0); if (ret == -1 && !MONGOC_ERRNO_IS_AGAIN (mongoc_socket_errno (interrupt->impl.socket_pair.read))) { _log_errno ("connect failed", mongoc_socket_errno (interrupt->impl.socket_pair.read)); GOTO (fail); } interrupt->impl.socket_pair.write = mongoc_socket_accept (listen_socket, bson_get_monotonic_time () + timeout_ms * 1000); if (!interrupt->impl.socket_pair.write) { _log_errno ("accept failed", mongoc_socket_errno (listen_socket)); GOTO (fail); } /* Create an unowned socket. interrupt_socket has 0 for the pid, so it will * be considered unowned. */ interrupt_socket = bson_malloc0 (sizeof (mongoc_socket_t)); interrupt_socket->sd = interrupt->impl.socket_pair.read->sd; /* Creating the stream takes ownership of the mongoc_socket_t. */ interrupt->stream = mongoc_stream_socket_new (interrupt_socket); success = true; fail: mongoc_socket_destroy (listen_socket); if (!success) { _mongoc_interrupt_destroy (interrupt); interrupt = NULL; } RETURN (interrupt); } void _mongoc_interrupt_destroy (mongoc_interrupt_t *interrupt) { if (!interrupt) { return; } bson_mutex_destroy (&interrupt->mutex); mongoc_socket_destroy (interrupt->impl.socket_pair.read); mongoc_socket_destroy (interrupt->impl.socket_pair.write); mongoc_stream_destroy (interrupt->stream); bson_free (interrupt); } bool _mongoc_interrupt_flush (mongoc_interrupt_t *interrupt) { uint8_t buf[1]; while (true) { if (-1 == mongoc_socket_recv (interrupt->impl.socket_pair.read, buf, sizeof (buf), 0, 0)) { if (MONGOC_ERRNO_IS_AGAIN (errno)) { /* Nothing left to read. */ return true; } else { /* Unexpected error. */ _log_errno ("interrupt recv failed", mongoc_socket_errno (interrupt->impl.socket_pair.read)); return false; } } } /* Should never be reached. */ BSON_ASSERT (false); } bool _mongoc_interrupt_interrupt (mongoc_interrupt_t *interrupt) { bson_mutex_lock (&interrupt->mutex); if (mongoc_socket_send (interrupt->impl.socket_pair.write, "!", 1, 0) == -1 && !MONGOC_ERRNO_IS_AGAIN (errno)) { _log_errno ("interrupt send failed", mongoc_socket_errno (interrupt->impl.socket_pair.write)); bson_mutex_unlock (&interrupt->mutex); return false; } bson_mutex_unlock (&interrupt->mutex); return true; } #else /* Pipe implementation. */ /* Set non-blocking and close on exec. */ static bool _set_pipe_flags (int pipe_fd) { int flags; flags = fcntl (pipe_fd, F_GETFL); if (-1 == fcntl (pipe_fd, F_SETFL, (flags | O_NONBLOCK))) { return false; } #ifdef FD_CLOEXEC flags = fcntl (pipe_fd, F_GETFD); if (-1 == fcntl (pipe_fd, F_SETFD, (flags | FD_CLOEXEC))) { return false; } #endif return true; } mongoc_interrupt_t * _mongoc_interrupt_new (uint32_t timeout_ms) { mongoc_interrupt_t *interrupt; mongoc_socket_t *interrupt_socket = NULL; bool success = false; ENTRY; BSON_UNUSED (timeout_ms); interrupt = (mongoc_interrupt_t *) bson_malloc0 (sizeof *interrupt); bson_mutex_init (&interrupt->mutex); if (0 != pipe (interrupt->impl.pipe_fds)) { _log_errno ("pipe creation failed", errno); GOTO (fail); } /* Make the pipe non-blocking and close-on-exec. */ if (!_set_pipe_flags (interrupt->impl.pipe_fds[0]) || !_set_pipe_flags (interrupt->impl.pipe_fds[1])) { _log_errno ("unable to configure pipes", errno); } /* Create an unowned socket. interrupt_socket has 0 for the pid, so it will * be considered unowned. */ interrupt_socket = bson_malloc0 (sizeof (mongoc_socket_t)); interrupt_socket->sd = interrupt->impl.pipe_fds[0]; /* Creating the stream takes ownership of the mongoc_socket_t. */ interrupt->stream = mongoc_stream_socket_new (interrupt_socket); success = true; fail: if (!success) { _mongoc_interrupt_destroy (interrupt); interrupt = NULL; } RETURN (interrupt); } bool _mongoc_interrupt_flush (mongoc_interrupt_t *interrupt) { char c; while (true) { if (read (interrupt->impl.pipe_fds[0], &c, 1) == -1) { if (MONGOC_ERRNO_IS_AGAIN (errno)) { /* Nothing left to read. */ return true; } else { /* Unexpected error. */ MONGOC_ERROR ("failed to read from pipe: %d", errno); return false; } } } BSON_UNREACHABLE ("reached unreachable code"); } bool _mongoc_interrupt_interrupt (mongoc_interrupt_t *interrupt) { bson_mutex_lock (&interrupt->mutex); if (write (interrupt->impl.pipe_fds[1], "!", 1) == -1 && !MONGOC_ERRNO_IS_AGAIN (errno)) { MONGOC_ERROR ("failed to write to pipe: %d", errno); bson_mutex_unlock (&interrupt->mutex); return false; } bson_mutex_unlock (&interrupt->mutex); return true; } void _mongoc_interrupt_destroy (mongoc_interrupt_t *interrupt) { if (!interrupt) { return; } bson_mutex_destroy (&interrupt->mutex); if (interrupt->impl.pipe_fds[0]) { close (interrupt->impl.pipe_fds[0]); } if (interrupt->impl.pipe_fds[1]) { close (interrupt->impl.pipe_fds[1]); } mongoc_stream_destroy (interrupt->stream); bson_free (interrupt); } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-iovec.h0000644000175100001660000000240014760300420022240 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_IOVEC_H #define MONGOC_IOVEC_H #include #ifdef _WIN32 #include #else #include #endif BSON_BEGIN_DECLS #ifdef _WIN32 typedef struct { size_t iov_len; char *iov_base; } mongoc_iovec_t; BSON_STATIC_ASSERT2 (sizeof_iovect_t, sizeof (mongoc_iovec_t) == sizeof (WSABUF)); BSON_STATIC_ASSERT2 (offsetof_iovec_base, offsetof (mongoc_iovec_t, iov_base) == offsetof (WSABUF, buf)); BSON_STATIC_ASSERT2 (offsetof_iovec_len, offsetof (mongoc_iovec_t, iov_len) == offsetof (WSABUF, len)); #else typedef struct iovec mongoc_iovec_t; #endif BSON_END_DECLS #endif /* MONGOC_IOVEC_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-libressl-private.h0000644000175100001660000000213114760300420024423 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_LIBRESSL_PRIVATE_H #define MONGOC_LIBRESSL_PRIVATE_H #include #include #include #include BSON_BEGIN_DECLS bool mongoc_libressl_setup_ca (mongoc_stream_tls_libressl_t *libressl, mongoc_ssl_opt_t *opt); bool mongoc_libressl_setup_certificate (mongoc_stream_tls_libressl_t *libressl, mongoc_ssl_opt_t *opt); BSON_END_DECLS #endif /* MONGOC_LIBRESSL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-libressl.c0000644000175100001660000000365214760300420022757 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_LIBRESSL #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-libressl" bool mongoc_libressl_setup_certificate (mongoc_stream_tls_libressl_t *libressl, mongoc_ssl_opt_t *opt) { uint8_t *file; size_t file_len; if (!opt->pem_file) { return false; } file = tls_load_file (opt->pem_file, &file_len, (char *) opt->pem_pwd); if (!file) { MONGOC_ERROR ("Cannot load private key: '%s'", opt->pem_file); return false; } if (tls_config_set_keypair_mem (libressl->config, file, file_len, file, file_len) == -1) { MONGOC_ERROR ("%s", tls_config_error (libressl->config)); return false; } return true; } bool mongoc_libressl_setup_ca (mongoc_stream_tls_libressl_t *libressl, mongoc_ssl_opt_t *opt) { if (opt->ca_file) { tls_config_set_ca_file (libressl->config, opt->ca_file); } if (opt->ca_dir) { tls_config_set_ca_path (libressl->config, opt->ca_dir); } return true; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-linux-distro-scanner-private.h0000644000175100001660000000330514760300420026700 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_LINUX_DISTRO_SCANNER_PRIVATE_H #define MONGOC_LINUX_DISTRO_SCANNER_PRIVATE_H #include #ifdef MONGOC_OS_IS_LINUX BSON_BEGIN_DECLS bool _mongoc_linux_distro_scanner_get_distro (char **name, char **version); /* These functions are exposed so we can test them separately. */ void _mongoc_linux_distro_scanner_read_key_value_file (const char *path, const char *name_key, ssize_t name_key_len, char **name, const char *version_key, ssize_t version_key_len, char **version); void _mongoc_linux_distro_scanner_read_generic_release_file (const char **paths, char **name, char **version); void _mongoc_linux_distro_scanner_split_line_by_release (const char *line, ssize_t line_len, char **name, char **version); BSON_END_DECLS #endif #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-linux-distro-scanner.c0000644000175100001660000002425314760300420025230 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_OS_IS_LINUX #include #include #include #include #include #include #include #include #include #define LINE_BUFFER_SIZE 1024 /* * fgets() wrapper which removes '\n' at the end of the string * Return 0 on failure or EOF. */ static size_t _fgets_wrapper (char *buffer, size_t buffer_size, FILE *f) { char *fgets_res; size_t len; fgets_res = fgets (buffer, buffer_size, f); if (!fgets_res) { /* Didn't read anything. Empty file or error. */ if (ferror (f)) { TRACE ("fgets() failed with error %d", errno); } return 0; } /* Chop off trailing \n */ len = strlen (buffer); if (len > 0 && buffer[len - 1] == '\n') { buffer[len - 1] = '\0'; len--; } else if (len == buffer_size - 1) { /* We read buffer_size bytes without hitting a newline * therefore the line is super long, so we say this file is invalid. * This is important since if we are in this situation, the NEXT call to * fgets() will keep reading where we left off. * * This protects us from files like: * aaaaa...DISTRIB_ID=nasal demons */ TRACE ("Found line of length %zu, bailing out", len); return 0; } return len; } static void _process_line (const char *name_key, size_t name_key_len, char **name, const char *version_key, size_t version_key_len, char **version, const char *line, size_t line_len) { size_t key_len; const char *equal_sign; const char *value; const char *needle = "="; size_t value_len = 0; ENTRY; /* Figure out where = is. Everything before is the key, * and everything after is the value */ equal_sign = strstr (line, needle); if (equal_sign == NULL) { TRACE ("Encountered malformed line: %s", line); /* This line is malformed/incomplete, so skip it */ EXIT; } /* Should never happen since we null terminated this line */ BSON_ASSERT (equal_sign < line + line_len); key_len = equal_sign - line; value = equal_sign + strlen (needle); value_len = strlen (value); if (value_len > 2 && value[0] == '"' && value[value_len - 1] == '"') { value_len -= 2; value++; } /* If we find two copies of either key, the *name == NULL check will fail * so we will just keep the first value encountered. */ if (name_key_len == key_len && strncmp (line, name_key, key_len) == 0 && !(*name)) { *name = bson_strndup (value, value_len); TRACE ("Found name: %s", *name); } else if (version_key_len == key_len && strncmp (line, version_key, key_len) == 0 && !(*version)) { *version = bson_strndup (value, value_len); TRACE ("Found version: %s", *version); } EXIT; } /* * Parse a file of the form: * KEY=VALUE * Looking for name_key and version_key, and storing * their values into *name and *version. * The values in *name and *version must be freed with bson_free. */ void _mongoc_linux_distro_scanner_read_key_value_file (const char *path, const char *name_key, ssize_t name_key_len, char **name, const char *version_key, ssize_t version_key_len, char **version) { const int max_lines = 100; int lines_read = 0; char buffer[LINE_BUFFER_SIZE]; size_t buflen; FILE *f; ENTRY; *name = NULL; *version = NULL; if (name_key_len < 0) { name_key_len = strlen (name_key); } if (version_key_len < 0) { version_key_len = strlen (version_key); } if (access (path, R_OK)) { TRACE ("No permission to read from %s: errno: %d", path, errno); EXIT; } f = fopen (path, "r"); if (!f) { TRACE ("fopen failed on %s: %d", path, errno); EXIT; } while (lines_read < max_lines) { buflen = _fgets_wrapper (buffer, sizeof (buffer), f); if (buflen == 0) { /* Error or eof */ break; } _process_line (name_key, name_key_len, name, version_key, version_key_len, version, buffer, buflen); if (*version && *name) { /* No point in reading any more */ break; } lines_read++; } fclose (f); EXIT; } /* * Find the first string in a list which is a valid file. Assumes * passed in list is NULL terminated! */ const char * _get_first_existing (const char **paths) { const char **p = &paths[0]; ENTRY; for (; *p != NULL; p++) { if (access (*p, F_OK)) { /* Just doesn't exist */ continue; } if (access (*p, R_OK)) { TRACE ("file %s exists, but cannot be read: error %d", *p, errno); continue; } RETURN (*p); } RETURN (NULL); } /* * Given a line of text, split it by the word "release." For example: * Ubuntu release 14.04 => * *name = Ubuntu * *version = 14.04 * If the word "release" isn't found then we put the whole string into *name * (even if the string is empty). */ void _mongoc_linux_distro_scanner_split_line_by_release (const char *line, ssize_t line_len, char **name, char **version) { const char *needle_loc; const char *const needle = " release "; const char *version_string; *name = NULL; *version = NULL; if (line_len < 0) { line_len = strlen (line); } needle_loc = strstr (line, needle); if (!needle_loc) { *name = bson_strdup (line); return; } else if (needle_loc == line) { /* The file starts with the word " release " * This file is weird enough we will just abandon it. */ return; } *name = bson_strndup (line, needle_loc - line); version_string = needle_loc + strlen (needle); if (version_string == line + line_len) { /* Weird. The file just ended with "release " */ return; } *version = bson_strdup (version_string); } /* * Search for a *-release file, and read its contents. */ void _mongoc_linux_distro_scanner_read_generic_release_file (const char **paths, char **name, char **version) { const char *path; size_t buflen; char buffer[LINE_BUFFER_SIZE]; FILE *f; ENTRY; *name = NULL; *version = NULL; path = _get_first_existing (paths); if (!path) { EXIT; } f = fopen (path, "r"); if (!f) { TRACE ("Found %s exists and readable but couldn't open: %d", path, errno); EXIT; } /* Read the first line of the file, look for the word "release" */ buflen = _fgets_wrapper (buffer, sizeof (buffer), f); if (buflen > 0) { TRACE ("Trying to split buffer with contents %s", buffer); /* Try splitting the string. If we can't it'll store everything in * *name. */ _mongoc_linux_distro_scanner_split_line_by_release (buffer, buflen, name, version); } fclose (f); EXIT; } static void _get_kernel_version_from_uname (char **version) { struct utsname system_info; if (uname (&system_info) >= 0) { *version = bson_strdup_printf ("kernel %s", system_info.release); } else { *version = NULL; } } /* * Some boilerplate logic that tries to set *name and *version to new_name * and new_version if it's not already set. Values of new_name and new_version * should not be used after this call. */ static bool _set_name_and_version_if_needed (char **name, char **version, char *new_name, char *new_version) { if (new_name && !(*name)) { *name = new_name; } else { bson_free (new_name); } if (new_version && !(*version)) { *version = new_version; } else { bson_free (new_version); } return (*name) && (*version); } bool _mongoc_linux_distro_scanner_get_distro (char **name, char **version) { /* In case we decide to try looking up name/version again */ char *new_name; char *new_version; const char *generic_release_paths[] = { "/etc/redhat-release", "/etc/novell-release", "/etc/gentoo-release", "/etc/SuSE-release", "/etc/SUSE-release", "/etc/sles-release", "/etc/debian_release", "/etc/slackware-version", "/etc/centos-release", NULL, }; ENTRY; *name = NULL; *version = NULL; _mongoc_linux_distro_scanner_read_key_value_file ("/etc/os-release", "NAME", -1, name, "VERSION_ID", -1, version); if (*name && *version) { RETURN (true); } _mongoc_linux_distro_scanner_read_key_value_file ( "/etc/lsb-release", "DISTRIB_ID", -1, &new_name, "DISTRIB_RELEASE", -1, &new_version); if (_set_name_and_version_if_needed (name, version, new_name, new_version)) { RETURN (true); } /* Try to read from a generic release file */ _mongoc_linux_distro_scanner_read_generic_release_file (generic_release_paths, &new_name, &new_version); if (_set_name_and_version_if_needed (name, version, new_name, new_version)) { RETURN (true); } if (*version == NULL) { _get_kernel_version_from_uname (version); } if (*name && *version) { RETURN (true); } bson_free (*name); bson_free (*version); *name = NULL; *version = NULL; RETURN (false); } #else /* ensure the translation unit is not empty */ extern int mongoc_os_is_not_linux; #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-list-private.h0000644000175100001660000000235714760300420023571 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_LIST_H #define MONGOC_LIST_H #include BSON_BEGIN_DECLS typedef struct _mongoc_list_t mongoc_list_t; struct _mongoc_list_t { mongoc_list_t *next; void *data; }; mongoc_list_t * _mongoc_list_append (mongoc_list_t *list, void *data); mongoc_list_t * _mongoc_list_prepend (mongoc_list_t *list, void *data); mongoc_list_t * _mongoc_list_remove (mongoc_list_t *list, void *data); void _mongoc_list_foreach (mongoc_list_t *list, void (*func) (void *data, void *user_data), void *user_data); void _mongoc_list_destroy (mongoc_list_t *list); BSON_END_DECLS #endif /* MONGOC_LIST_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-list.c0000644000175100001660000000600214760300420022103 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include /** * mongoc_list_append: * @list: A list to append to, or NULL. * @data: Data to append to @list. * * Appends a new link onto the linked list. * * Returns: @list or a new list if @list is NULL. */ mongoc_list_t * _mongoc_list_append (mongoc_list_t *list, void *data) { mongoc_list_t *item; mongoc_list_t *iter; item = (mongoc_list_t *) bson_malloc0 (sizeof *item); item->data = (void *) data; if (!list) { return item; } for (iter = list; iter->next; iter = iter->next) { } iter->next = item; return list; } /** * mongoc_list_prepend: * @list: A mongoc_list_t or NULL. * @data: data to prepend to the list. * * Prepends to @list a new link containing @data. * * Returns: A new link containing data with @list following. */ mongoc_list_t * _mongoc_list_prepend (mongoc_list_t *list, void *data) { mongoc_list_t *item; item = (mongoc_list_t *) bson_malloc0 (sizeof *item); item->data = (void *) data; item->next = list; return item; } /** * mongoc_list_remove: * @list: A mongoc_list_t. * @data: Data to remove from @list. * * Removes the link containing @data from @list. * * Returns: @list with the link containing @data removed. */ mongoc_list_t * _mongoc_list_remove (mongoc_list_t *list, void *data) { mongoc_list_t *iter; mongoc_list_t *prev = NULL; mongoc_list_t *ret = list; BSON_ASSERT (list); for (iter = list; iter; iter = iter->next) { if (iter->data == data) { if (iter != list) { prev->next = iter->next; } else { ret = iter->next; } bson_free (iter); break; } prev = iter; } return ret; } /** * mongoc_list_foreach: * @list: A mongoc_list_t or NULL. * @func: A func to call for each link in @list. * @user_data: User data for @func. * * Calls @func for each item in @list. */ void _mongoc_list_foreach (mongoc_list_t *list, void (*func) (void *data, void *user_data), void *user_data) { mongoc_list_t *iter; BSON_ASSERT (func); for (iter = list; iter; iter = iter->next) { func (iter->data, user_data); } } /** * mongoc_list_destroy: * @list: A mongoc_list_t. * * Destroys @list and releases any resources. */ void _mongoc_list_destroy (mongoc_list_t *list) { mongoc_list_t *tmp = list; while (list) { tmp = list->next; bson_free (list); list = tmp; } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-log-and-monitor-private.c0000644000175100001660000001031414760300420025607 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include /** * @brief Initializes the contents of a just-allocated mongoc_log_and_monitor_instance_t * * Captures default structured log options from the environment */ void mongoc_log_and_monitor_instance_init (mongoc_log_and_monitor_instance_t *new_instance) { BSON_ASSERT_PARAM (new_instance); mongoc_log_and_monitor_instance_set_apm_callbacks (new_instance, NULL, NULL); /* This apm_mutex currently only provides explicit exclusion for heartbeat events. It was introduced along with * background monitoring threads, to retain compatibility with existing code and with the SDAM spec guarantee: * * "Events and log messages MUST be published in the order that their corresponding changes are processed in the * driver. Events MUST NOT be published concurrently for the same topology ID or server ID, but MAY be published * concurrently for differing topology IDs and server IDs." * * We may want to re-examine the scope of this mutex. It's broader than necessary for strict compliance (per-pool * rather than per-server) and it's unclear that this always provides the necessary exclusion between different event * types on the same server. */ bson_mutex_init (&new_instance->apm_mutex); mongoc_structured_log_opts_t *structured_log_opts = mongoc_structured_log_opts_new (); new_instance->structured_log = mongoc_structured_log_instance_new (structured_log_opts); mongoc_structured_log_opts_destroy (structured_log_opts); } /** * @brief Destroy the contents of a mongoc_log_and_monitor_instance_t * * Does not try to free the outer memory allocation; it will be part of another object. * There must not be any other threads using the instance concurrently. */ void mongoc_log_and_monitor_instance_destroy_contents (mongoc_log_and_monitor_instance_t *instance) { BSON_ASSERT_PARAM (instance); BSON_ASSERT (instance->structured_log); mongoc_structured_log_instance_destroy (instance->structured_log); instance->structured_log = NULL; bson_mutex_destroy (&instance->apm_mutex); } /** * @brief Set the APM callbacks in a mongoc_log_and_monitor_instance_t * * There must not be any other threads using the instance concurrently. * In single threaded mode, this is only valid on the thread that owns the * client. In pooled mode, it's only valid prior to the first client init. */ void mongoc_log_and_monitor_instance_set_apm_callbacks (mongoc_log_and_monitor_instance_t *instance, const mongoc_apm_callbacks_t *callbacks, void *context) { BSON_ASSERT_PARAM (instance); instance->apm_callbacks = callbacks ? *callbacks : (mongoc_apm_callbacks_t){0}; instance->apm_context = context; } /** * @brief Set the structured log options in a mongoc_log_and_monitor_instance_t * * Replace the instance's structured logging options. Options are copied. * * There must not be any other threads using the instance concurrently. * In single threaded mode, this is only valid on the thread that owns the * client. In pooled mode, it's only valid prior to the first client init. */ void mongoc_log_and_monitor_instance_set_structured_log_opts (mongoc_log_and_monitor_instance_t *instance, const mongoc_structured_log_opts_t *opts) { BSON_ASSERT_PARAM (instance); mongoc_structured_log_instance_destroy (instance->structured_log); instance->structured_log = mongoc_structured_log_instance_new (opts); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-log-and-monitor-private.h0000644000175100001660000000405214760300420025616 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_LOG_AND_MONITOR_PRIVATE_H #define MONGOC_LOG_AND_MONITOR_PRIVATE_H #include #include struct mongoc_structured_log_instance_t; struct mongoc_structured_log_opts_t; /* * @brief Logging and monitoring instance * * Includes APM callbacks, APM callback context, and the structured logging instance. * * It's owned by mongoc_topology_t on behalf of client/pool and borrowed by topology_description methods. */ typedef struct _mongoc_log_and_monitor_instance_t { bson_mutex_t apm_mutex; mongoc_apm_callbacks_t apm_callbacks; void *apm_context; struct mongoc_structured_log_instance_t *structured_log; } mongoc_log_and_monitor_instance_t; void mongoc_log_and_monitor_instance_init (mongoc_log_and_monitor_instance_t *new_instance); void mongoc_log_and_monitor_instance_destroy_contents (mongoc_log_and_monitor_instance_t *instance); void mongoc_log_and_monitor_instance_set_apm_callbacks (mongoc_log_and_monitor_instance_t *instance, const mongoc_apm_callbacks_t *callbacks, void *context); void mongoc_log_and_monitor_instance_set_structured_log_opts (mongoc_log_and_monitor_instance_t *instance, const struct mongoc_structured_log_opts_t *opts); #endif /* MONGOC_LOG_AND_MONITOR_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-log-private.h0000644000175100001660000000267614760300420023403 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_LOG_PRIVATE_H #define MONGOC_LOG_PRIVATE_H #include /* just for testing */ void _mongoc_log_get_handler (mongoc_log_func_t *log_func, void **user_data); bool _mongoc_log_trace_is_enabled (void); void mongoc_log_trace_bytes (const char *domain, const uint8_t *_b, size_t _l); void mongoc_log_trace_iovec (const char *domain, const mongoc_iovec_t *_iov, size_t _iovcnt); #define STOP_LOGGING_CHECK \ if (1) { \ if (!gLogFunc || !_mongoc_log_trace_is_enabled ()) { \ return; \ } \ } else \ (void) 0 #endif /* MONGOC_LOG_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-log.c0000644000175100001660000001764314760300420021726 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if defined(__linux__) #include #elif defined(_WIN32) #include #elif defined(__APPLE__) #include #include #elif defined(__FreeBSD__) #include #elif defined(__NetBSD__) #include #else #include #endif #include #include #include #include #include #include static bson_once_t once = BSON_ONCE_INIT; static bson_mutex_t gLogMutex; static mongoc_log_func_t gLogFunc = mongoc_log_default_handler; bool gLogTrace = MONGOC_TRACE_ENABLED; static void *gLogData; static BSON_ONCE_FUN (_mongoc_ensure_mutex_once) { bson_mutex_init (&gLogMutex); BSON_ONCE_RETURN; } void mongoc_log_set_handler (mongoc_log_func_t log_func, void *user_data) { bson_once (&once, &_mongoc_ensure_mutex_once); bson_mutex_lock (&gLogMutex); gLogFunc = log_func; gLogData = user_data; bson_mutex_unlock (&gLogMutex); } bool _mongoc_log_trace_is_enabled (void) { return gLogTrace && MONGOC_TRACE_ENABLED; } void mongoc_log_trace_enable (void) { /* Enable trace logging if-and-only-if tracing is enabled at configure-time, * otherwise tracing remains disabled. */ gLogTrace = MONGOC_TRACE_ENABLED; } void mongoc_log_trace_disable (void) { gLogTrace = false; } /* just for testing */ void _mongoc_log_get_handler (mongoc_log_func_t *log_func, void **user_data) { *log_func = gLogFunc; *user_data = gLogData; } void mongoc_log (mongoc_log_level_t log_level, const char *log_domain, const char *format, ...) { va_list args; char *message; int stop_logging; bson_once (&once, &_mongoc_ensure_mutex_once); stop_logging = !gLogFunc; stop_logging = stop_logging || (log_level == MONGOC_LOG_LEVEL_TRACE && !_mongoc_log_trace_is_enabled ()); if (stop_logging) { return; } BSON_ASSERT (format); va_start (args, format); message = bson_strdupv_printf (format, args); va_end (args); bson_mutex_lock (&gLogMutex); gLogFunc (log_level, log_domain, message, gLogData); bson_mutex_unlock (&gLogMutex); bson_free (message); } const char * mongoc_log_level_str (mongoc_log_level_t log_level) { switch (log_level) { case MONGOC_LOG_LEVEL_ERROR: return "ERROR"; case MONGOC_LOG_LEVEL_CRITICAL: return "CRITICAL"; case MONGOC_LOG_LEVEL_WARNING: return "WARNING"; case MONGOC_LOG_LEVEL_MESSAGE: return "MESSAGE"; case MONGOC_LOG_LEVEL_INFO: return "INFO"; case MONGOC_LOG_LEVEL_DEBUG: return "DEBUG"; case MONGOC_LOG_LEVEL_TRACE: return "TRACE"; default: return "UNKNOWN"; } } void mongoc_log_default_handler (mongoc_log_level_t log_level, const char *log_domain, const char *message, void *user_data) { struct timeval tv; struct tm tt; time_t t; FILE *stream; char nowstr[32]; int pid; BSON_UNUSED (user_data); bson_gettimeofday (&tv); t = tv.tv_sec; #ifdef _WIN32 #ifdef _MSC_VER localtime_s (&tt, &t); #else tt = *(localtime (&t)); #endif #else localtime_r (&t, &tt); #endif strftime (nowstr, sizeof nowstr, "%Y/%m/%d %H:%M:%S", &tt); switch (log_level) { case MONGOC_LOG_LEVEL_ERROR: case MONGOC_LOG_LEVEL_CRITICAL: case MONGOC_LOG_LEVEL_WARNING: stream = stderr; break; case MONGOC_LOG_LEVEL_MESSAGE: case MONGOC_LOG_LEVEL_INFO: case MONGOC_LOG_LEVEL_DEBUG: case MONGOC_LOG_LEVEL_TRACE: default: stream = stdout; } #ifdef __linux__ pid = syscall (SYS_gettid); #elif defined(_WIN32) pid = (int) _getpid (); #elif defined(__FreeBSD__) long tid; thr_self (&tid); pid = (int) tid; #elif defined(__OpenBSD__) pid = (int) getthrid (); #elif defined(__NetBSD__) pid = (int) _lwp_self (); #elif defined(__APPLE__) #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 // libc on macOS < 10.7 does not support `pthread_threadid_np` mach_port_t tid = pthread_mach_thread_np (pthread_self ()); pid = (int) tid; #else uint64_t tid; pthread_threadid_np (0, &tid); pid = (int) tid; #endif #else pid = (int) getpid (); #endif fprintf (stream, "%s.%04" PRId64 ": [%5d]: %8s: %12s: %s\n", nowstr, (int64_t) (tv.tv_usec / 1000), pid, mongoc_log_level_str (log_level), log_domain, message); } void mongoc_log_trace_bytes (const char *domain, const uint8_t *_b, size_t _l) { STOP_LOGGING_CHECK; mcommon_string_append_t str, astr; mcommon_string_new_as_append (&str); mcommon_string_new_as_append (&astr); size_t _i; for (_i = 0u; _i < _l; _i++) { const uint8_t _v = *(_b + _i); const size_t rem = _i % 16u; if (rem == 0u) { mcommon_string_append_printf (&str, "%05zx: ", _i); } mcommon_string_append_printf (&str, " %02x", _v); if (isprint (_v)) { mcommon_string_append_printf (&astr, " %c", _v); } else { mcommon_string_append (&astr, " ."); } if (rem == 15u) { mongoc_log ( MONGOC_LOG_LEVEL_TRACE, domain, "%s %s", mcommon_str_from_append (&str), mcommon_str_from_append (&astr)); mcommon_string_from_append_clear (&str); mcommon_string_from_append_clear (&astr); } else if (rem == 7u) { mcommon_string_append (&str, " "); mcommon_string_append (&astr, " "); } } if (_i != 16u) { mongoc_log ( MONGOC_LOG_LEVEL_TRACE, domain, "%-56s %s", mcommon_str_from_append (&str), mcommon_str_from_append (&astr)); } mcommon_string_from_append_destroy (&str); mcommon_string_from_append_destroy (&astr); } void mongoc_log_trace_iovec (const char *domain, const mongoc_iovec_t *_iov, size_t _iovcnt) { const char *_b; unsigned _i = 0; unsigned _j = 0; unsigned _k = 0; size_t _l = 0; uint8_t _v; STOP_LOGGING_CHECK; for (_i = 0; _i < _iovcnt; _i++) { _l += _iov[_i].iov_len; } _i = 0; mcommon_string_append_t str, astr; mcommon_string_new_as_append (&str); mcommon_string_new_as_append (&astr); for (_j = 0; _j < _iovcnt; _j++) { _b = (char *) _iov[_j].iov_base; _l = _iov[_j].iov_len; for (_k = 0; _k < _l; _k++, _i++) { _v = *(_b + _k); if ((_i % 16) == 0) { mcommon_string_append_printf (&str, "%05x: ", _i); } mcommon_string_append_printf (&str, " %02x", _v); if (isprint (_v)) { mcommon_string_append_printf (&astr, " %c", _v); } else { mcommon_string_append (&astr, " ."); } if ((_i % 16) == 15) { mongoc_log (MONGOC_LOG_LEVEL_TRACE, domain, "%s %s", mcommon_str_from_append (&str), mcommon_str_from_append (&astr)); mcommon_string_from_append_clear (&str); mcommon_string_from_append_clear (&astr); } else if ((_i % 16) == 7) { mcommon_string_append (&str, " "); mcommon_string_append (&astr, " "); } } } if (_i != 16) { mongoc_log ( MONGOC_LOG_LEVEL_TRACE, domain, "%-56s %s", mcommon_str_from_append (&str), mcommon_str_from_append (&astr)); } mcommon_string_from_append_destroy (&str); mcommon_string_from_append_destroy (&astr); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-log.h0000644000175100001660000000745014760300420021726 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_LOG_H #define MONGOC_LOG_H #include #include BSON_BEGIN_DECLS #ifndef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "mongoc" #endif #define MONGOC_ERROR(...) mongoc_log (MONGOC_LOG_LEVEL_ERROR, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_CRITICAL(...) mongoc_log (MONGOC_LOG_LEVEL_CRITICAL, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_WARNING(...) mongoc_log (MONGOC_LOG_LEVEL_WARNING, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_MESSAGE(...) mongoc_log (MONGOC_LOG_LEVEL_MESSAGE, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_INFO(...) mongoc_log (MONGOC_LOG_LEVEL_INFO, MONGOC_LOG_DOMAIN, __VA_ARGS__) #define MONGOC_DEBUG(...) mongoc_log (MONGOC_LOG_LEVEL_DEBUG, MONGOC_LOG_DOMAIN, __VA_ARGS__) typedef enum { MONGOC_LOG_LEVEL_ERROR, MONGOC_LOG_LEVEL_CRITICAL, MONGOC_LOG_LEVEL_WARNING, MONGOC_LOG_LEVEL_MESSAGE, MONGOC_LOG_LEVEL_INFO, MONGOC_LOG_LEVEL_DEBUG, MONGOC_LOG_LEVEL_TRACE, } mongoc_log_level_t; /** * mongoc_log_func_t: * @log_level: The level of the log message. * @log_domain: The domain of the log message, such as "client". * @message: The message generated. * @user_data: User data provided to mongoc_log_set_handler(). * * This function prototype can be used to set a custom log handler for the * libmongoc library. This is useful if you would like to show them in a * user interface or alternate storage. */ typedef void (*mongoc_log_func_t) (mongoc_log_level_t log_level, const char *log_domain, const char *message, void *user_data); /** * mongoc_log_set_handler: * @log_func: A function to handle log messages. * @user_data: User data for @log_func. * * Sets the function to be called to handle logging. */ MONGOC_EXPORT (void) mongoc_log_set_handler (mongoc_log_func_t log_func, void *user_data); /** * mongoc_log: * @log_level: The log level. * @log_domain: The log domain (such as "client"). * @format: The format string for the log message. * * Logs a message using the currently configured logger. * * This method will hold a logging lock to prevent concurrent calls to the * logging infrastructure. It is important that your configured log function * does not re-enter the logging system or deadlock will occur. * */ MONGOC_EXPORT (void) mongoc_log (mongoc_log_level_t log_level, const char *log_domain, const char *format, ...) BSON_GNUC_PRINTF (3, 4); MONGOC_EXPORT (void) mongoc_log_default_handler (mongoc_log_level_t log_level, const char *log_domain, const char *message, void *user_data); /** * mongoc_log_level_str: * @log_level: The log level. * * Returns: The string representation of log_level */ MONGOC_EXPORT (const char *) mongoc_log_level_str (mongoc_log_level_t log_level); /** * mongoc_log_trace_enable: * * Enables tracing at runtime (if it has been enabled at compile time). */ MONGOC_EXPORT (void) mongoc_log_trace_enable (void); /** * mongoc_log_trace_disable: * * Disables tracing at runtime (if it has been enabled at compile time). */ MONGOC_EXPORT (void) mongoc_log_trace_disable (void); BSON_END_DECLS #endif /* MONGOC_LOG_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-macros.h0000644000175100001660000000335614760300420022432 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_MACROS_H #define MONGOC_MACROS_H /* Decorate public functions: * - if MONGOC_STATIC, we're compiling a static libmongoc or a program * that uses libmongoc as a static library. Don't decorate functions * - else if MONGOC_COMPILATION, we're compiling a shared libmongoc, * mark public functions for export from the shared lib. * - else, we're compiling a program that uses libmongoc as a shared library, * mark public functions as DLL imports for Microsoft Visual C. */ #ifdef _MSC_VER /* * Microsoft Visual C */ #ifdef MONGOC_STATIC #define MONGOC_API #elif defined(MONGOC_COMPILATION) #define MONGOC_API __declspec (dllexport) #else #define MONGOC_API __declspec (dllimport) #endif #define MONGOC_CALL __cdecl #elif defined(__GNUC__) /* * GCC */ #ifdef MONGOC_STATIC #define MONGOC_API #elif defined(MONGOC_COMPILATION) #define MONGOC_API __attribute__ ((visibility ("default"))) #else #define MONGOC_API #endif #define MONGOC_CALL #else /* * Other compilers */ #define MONGOC_API #define MONGOC_CALL #endif #define MONGOC_EXPORT(type) MONGOC_API type MONGOC_CALL #endif /* MONGOC_MACROS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-matcher-op-private.h0000644000175100001660000000653314760300420024655 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_MATCHER_OP_PRIVATE_H #define MONGOC_MATCHER_OP_PRIVATE_H #include BSON_BEGIN_DECLS typedef union _mongoc_matcher_op_t mongoc_matcher_op_t; typedef struct _mongoc_matcher_op_base_t mongoc_matcher_op_base_t; typedef struct _mongoc_matcher_op_logical_t mongoc_matcher_op_logical_t; typedef struct _mongoc_matcher_op_compare_t mongoc_matcher_op_compare_t; typedef struct _mongoc_matcher_op_exists_t mongoc_matcher_op_exists_t; typedef struct _mongoc_matcher_op_type_t mongoc_matcher_op_type_t; typedef struct _mongoc_matcher_op_not_t mongoc_matcher_op_not_t; typedef enum { MONGOC_MATCHER_OPCODE_EQ, MONGOC_MATCHER_OPCODE_GT, MONGOC_MATCHER_OPCODE_GTE, MONGOC_MATCHER_OPCODE_IN, MONGOC_MATCHER_OPCODE_LT, MONGOC_MATCHER_OPCODE_LTE, MONGOC_MATCHER_OPCODE_NE, MONGOC_MATCHER_OPCODE_NIN, MONGOC_MATCHER_OPCODE_OR, MONGOC_MATCHER_OPCODE_AND, MONGOC_MATCHER_OPCODE_NOT, MONGOC_MATCHER_OPCODE_NOR, MONGOC_MATCHER_OPCODE_EXISTS, MONGOC_MATCHER_OPCODE_TYPE, } mongoc_matcher_opcode_t; struct _mongoc_matcher_op_base_t { mongoc_matcher_opcode_t opcode; }; struct _mongoc_matcher_op_logical_t { mongoc_matcher_op_base_t base; mongoc_matcher_op_t *left; mongoc_matcher_op_t *right; }; struct _mongoc_matcher_op_compare_t { mongoc_matcher_op_base_t base; char *path; bson_iter_t iter; }; struct _mongoc_matcher_op_exists_t { mongoc_matcher_op_base_t base; char *path; bool exists; }; struct _mongoc_matcher_op_type_t { mongoc_matcher_op_base_t base; bson_type_t type; char *path; }; struct _mongoc_matcher_op_not_t { mongoc_matcher_op_base_t base; mongoc_matcher_op_t *child; char *path; }; union _mongoc_matcher_op_t { mongoc_matcher_op_base_t base; mongoc_matcher_op_logical_t logical; mongoc_matcher_op_compare_t compare; mongoc_matcher_op_exists_t exists; mongoc_matcher_op_type_t type; mongoc_matcher_op_not_t not_; }; mongoc_matcher_op_t * _mongoc_matcher_op_logical_new (mongoc_matcher_opcode_t opcode, mongoc_matcher_op_t *left, mongoc_matcher_op_t *right); mongoc_matcher_op_t * _mongoc_matcher_op_compare_new (mongoc_matcher_opcode_t opcode, const char *path, const bson_iter_t *iter); mongoc_matcher_op_t * _mongoc_matcher_op_exists_new (const char *path, bool exists); mongoc_matcher_op_t * _mongoc_matcher_op_type_new (const char *path, bson_type_t type); mongoc_matcher_op_t * _mongoc_matcher_op_not_new (const char *path, mongoc_matcher_op_t *child); bool _mongoc_matcher_op_match (mongoc_matcher_op_t *op, const bson_t *bson); void _mongoc_matcher_op_destroy (mongoc_matcher_op_t *op); void _mongoc_matcher_op_to_bson (mongoc_matcher_op_t *op, bson_t *bson); BSON_END_DECLS #endif /* MONGOC_MATCHER_OP_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-matcher-op.c0000644000175100001660000010223414760300420023173 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_exists_new -- * * Create a new op for checking {$exists: bool}. * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_exists_new (const char *path, /* IN */ bool exists) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (path); op = BSON_ALIGNED_ALLOC0 (mongoc_matcher_op_t); op->exists.base.opcode = MONGOC_MATCHER_OPCODE_EXISTS; op->exists.path = bson_strdup (path); op->exists.exists = exists; return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_type_new -- * * Create a new op for checking {$type: int}. * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_type_new (const char *path, /* IN */ bson_type_t type) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (path); BSON_ASSERT (type); op = BSON_ALIGNED_ALLOC0 (mongoc_matcher_op_t); op->type.base.opcode = MONGOC_MATCHER_OPCODE_TYPE; op->type.path = bson_strdup (path); op->type.type = type; return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_logical_new -- * * Create a new op for checking any of: * * {$or: []} * {$nor: []} * {$and: []} * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_logical_new (mongoc_matcher_opcode_t opcode, /* IN */ mongoc_matcher_op_t *left, /* IN */ mongoc_matcher_op_t *right) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (left); BSON_ASSERT ((opcode >= MONGOC_MATCHER_OPCODE_OR) && (opcode <= MONGOC_MATCHER_OPCODE_NOR)); op = BSON_ALIGNED_ALLOC0 (mongoc_matcher_op_t); op->logical.base.opcode = opcode; op->logical.left = left; op->logical.right = right; return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_compare_new -- * * Create a new op for checking any of: * * {"abc": "def"} * {$gt: {...} * {$gte: {...} * {$lt: {...} * {$lte: {...} * {$ne: {...} * {$in: [...]} * {$nin: [...]} * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_compare_new (mongoc_matcher_opcode_t opcode, /* IN */ const char *path, /* IN */ const bson_iter_t *iter) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (path); BSON_ASSERT (iter); op = BSON_ALIGNED_ALLOC0 (mongoc_matcher_op_t); op->compare.base.opcode = opcode; op->compare.path = bson_strdup (path); memcpy (&op->compare.iter, iter, sizeof *iter); return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_not_new -- * * Create a new op for checking {$not: {...}} * * Returns: * A newly allocated mongoc_matcher_op_t that should be freed with * _mongoc_matcher_op_destroy(). * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_matcher_op_t * _mongoc_matcher_op_not_new (const char *path, /* IN */ mongoc_matcher_op_t *child) /* IN */ { mongoc_matcher_op_t *op; BSON_ASSERT (path); BSON_ASSERT (child); op = BSON_ALIGNED_ALLOC0 (mongoc_matcher_op_t); op->not_.base.opcode = MONGOC_MATCHER_OPCODE_NOT; op->not_.path = bson_strdup (path); op->not_.child = child; return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_destroy -- * * Free a mongoc_matcher_op_t structure and all children structures. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void _mongoc_matcher_op_destroy (mongoc_matcher_op_t *op) /* IN */ { BSON_ASSERT (op); switch (op->base.opcode) { case MONGOC_MATCHER_OPCODE_EQ: case MONGOC_MATCHER_OPCODE_GT: case MONGOC_MATCHER_OPCODE_GTE: case MONGOC_MATCHER_OPCODE_IN: case MONGOC_MATCHER_OPCODE_LT: case MONGOC_MATCHER_OPCODE_LTE: case MONGOC_MATCHER_OPCODE_NE: case MONGOC_MATCHER_OPCODE_NIN: bson_free (op->compare.path); break; case MONGOC_MATCHER_OPCODE_OR: case MONGOC_MATCHER_OPCODE_AND: case MONGOC_MATCHER_OPCODE_NOR: if (op->logical.left) _mongoc_matcher_op_destroy (op->logical.left); if (op->logical.right) _mongoc_matcher_op_destroy (op->logical.right); break; case MONGOC_MATCHER_OPCODE_NOT: _mongoc_matcher_op_destroy (op->not_.child); bson_free (op->not_.path); break; case MONGOC_MATCHER_OPCODE_EXISTS: bson_free (op->exists.path); break; case MONGOC_MATCHER_OPCODE_TYPE: bson_free (op->type.path); break; default: break; } bson_free (op); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_exists_match -- * * Checks to see if @bson matches @exists requirements. The * {$exists: bool} query can be either true or fase so we must * handle false as "not exists". * * Returns: * true if the field exists and the spec expected it. * true if the field does not exist and the spec expected it to not * exist. * Otherwise, false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_exists_match (mongoc_matcher_op_exists_t *exists, /* IN */ const bson_t *bson) /* IN */ { bson_iter_t iter; bson_iter_t desc; bool found; BSON_ASSERT (exists); BSON_ASSERT (bson); found = (bson_iter_init (&iter, bson) && bson_iter_find_descendant (&iter, exists->path, &desc)); return (found == exists->exists); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_type_match -- * * Checks if @bson matches the {$type: ...} op. * * Returns: * true if the requested field was found and the type matched * the requested type. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_type_match (mongoc_matcher_op_type_t *type, /* IN */ const bson_t *bson) /* IN */ { bson_iter_t iter; bson_iter_t desc; BSON_ASSERT (type); BSON_ASSERT (bson); if (bson_iter_init (&iter, bson) && bson_iter_find_descendant (&iter, type->path, &desc)) { return (bson_iter_type (&iter) == type->type); } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_not_match -- * * Checks if the {$not: ...} expression matches by negating the * child expression. * * Returns: * true if the child expression returned false. * Otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_not_match (mongoc_matcher_op_not_t *not_, /* IN */ const bson_t *bson) /* IN */ { BSON_ASSERT (not_); BSON_ASSERT (bson); return !_mongoc_matcher_op_match (not_->child, bson); } #define _TYPE_CODE(l, r) ((((int) (l)) << 8) | ((int) (r))) #define _NATIVE_COMPARE(op, t1, t2) (bson_iter##t2 (iter) op bson_iter##t1 (compare_iter)) #define _EQ_COMPARE(t1, t2) _NATIVE_COMPARE (==, t1, t2) #define _NE_COMPARE(t1, t2) _NATIVE_COMPARE (!=, t1, t2) #define _GT_COMPARE(t1, t2) _NATIVE_COMPARE (>, t1, t2) #define _GTE_COMPARE(t1, t2) _NATIVE_COMPARE (>=, t1, t2) #define _LT_COMPARE(t1, t2) _NATIVE_COMPARE (<, t1, t2) #define _LTE_COMPARE(t1, t2) _NATIVE_COMPARE (<=, t1, t2) /* *-------------------------------------------------------------------------- * * _mongoc_matcher_iter_eq_match -- * * Performs equality match for all types on either left or right * side of the equation. * * We try to default to what the compiler would do for comparing * things like integers. Therefore, we just have MACRO'tized * everything so that the compiler sees the native values. (Such * as (double == int64). * * The _TYPE_CODE() stuff allows us to shove the type of the left * and the right into a single integer and then do a jump table * with a switch/case for all our supported types. * * I imagine a bunch more of these will need to be added, so feel * free to submit patches. * * Returns: * true if the equality match succeeded. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_iter_eq_match (bson_iter_t *compare_iter, /* IN */ bson_iter_t *iter) /* IN */ { int code; BSON_ASSERT (compare_iter); BSON_ASSERT (iter); code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _EQ_COMPARE (_double, _double); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _EQ_COMPARE (_double, _bool); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _EQ_COMPARE (_double, _int32); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _EQ_COMPARE (_double, _int64); /* UTF8 on Left Side */ case _TYPE_CODE (BSON_TYPE_UTF8, BSON_TYPE_UTF8): { uint32_t llen; uint32_t rlen; const char *lstr; const char *rstr; lstr = bson_iter_utf8 (compare_iter, &llen); rstr = bson_iter_utf8 (iter, &rlen); return ((llen == rlen) && (0 == memcmp (lstr, rstr, llen))); } /* Int32 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _EQ_COMPARE (_int32, _double); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_BOOL): return _EQ_COMPARE (_int32, _bool); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT32): return _EQ_COMPARE (_int32, _int32); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT64): return _EQ_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _EQ_COMPARE (_int64, _double); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_BOOL): return _EQ_COMPARE (_int64, _bool); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT32): return _EQ_COMPARE (_int64, _int32); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT64): return _EQ_COMPARE (_int64, _int64); /* Null on Left Side */ case _TYPE_CODE (BSON_TYPE_NULL, BSON_TYPE_NULL): case _TYPE_CODE (BSON_TYPE_NULL, BSON_TYPE_UNDEFINED): return true; case _TYPE_CODE (BSON_TYPE_ARRAY, BSON_TYPE_ARRAY): { bson_iter_t left_array; bson_iter_t right_array; BSON_ASSERT (bson_iter_recurse (compare_iter, &left_array)); BSON_ASSERT (bson_iter_recurse (iter, &right_array)); while (true) { bool left_has_next = bson_iter_next (&left_array); bool right_has_next = bson_iter_next (&right_array); if (left_has_next != right_has_next) { /* different lengths */ return false; } if (!left_has_next) { /* finished */ return true; } if (!_mongoc_matcher_iter_eq_match (&left_array, &right_array)) { return false; } } } case _TYPE_CODE (BSON_TYPE_DOCUMENT, BSON_TYPE_DOCUMENT): { uint32_t llen; uint32_t rlen; const uint8_t *ldoc; const uint8_t *rdoc; bson_iter_document (compare_iter, &llen, &ldoc); bson_iter_document (iter, &rlen, &rdoc); return ((llen == rlen) && (0 == memcmp (ldoc, rdoc, llen))); } default: return false; } } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_eq_match -- * * Performs equality match for all types on either left or right * side of the equation. * * Returns: * true if the equality match succeeded. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_eq_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { BSON_ASSERT (compare); BSON_ASSERT (iter); return _mongoc_matcher_iter_eq_match (&compare->iter, iter); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_gt_match -- * * Perform {$gt: ...} match using @compare. * * In general, we try to default to what the compiler would do * for comparison between different types. * * Returns: * true if the document field was > the spec value. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_gt_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { int code; bson_iter_t *compare_iter = &compare->iter; BSON_ASSERT (compare); BSON_ASSERT (iter); code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _GT_COMPARE (_double, _double); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _GT_COMPARE (_double, _bool); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _GT_COMPARE (_double, _int32); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _GT_COMPARE (_double, _int64); /* Int32 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _GT_COMPARE (_int32, _double); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_BOOL): return _GT_COMPARE (_int32, _bool); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT32): return _GT_COMPARE (_int32, _int32); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT64): return _GT_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _GT_COMPARE (_int64, _double); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_BOOL): return _GT_COMPARE (_int64, _bool); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT32): return _GT_COMPARE (_int64, _int32); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT64): return _GT_COMPARE (_int64, _int64); default: MONGOC_WARNING ( "Implement for (Type(%d) > Type(%d))", (int) bson_iter_type (compare_iter), (int) bson_iter_type (iter)); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_gte_match -- * * Perform a match of {"path": {"$gte": value}}. * * Returns: * true if the spec matches, otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_gte_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { bson_iter_t *compare_iter; int code; BSON_ASSERT (compare); BSON_ASSERT (iter); compare_iter = &compare->iter; code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _GTE_COMPARE (_double, _double); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _GTE_COMPARE (_double, _bool); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _GTE_COMPARE (_double, _int32); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _GTE_COMPARE (_double, _int64); /* Int32 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _GTE_COMPARE (_int32, _double); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_BOOL): return _GTE_COMPARE (_int32, _bool); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT32): return _GTE_COMPARE (_int32, _int32); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT64): return _GTE_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _GTE_COMPARE (_int64, _double); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_BOOL): return _GTE_COMPARE (_int64, _bool); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT32): return _GTE_COMPARE (_int64, _int32); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT64): return _GTE_COMPARE (_int64, _int64); default: MONGOC_WARNING ( "Implement for (Type(%d) >= Type(%d))", (int) bson_iter_type (compare_iter), (int) bson_iter_type (iter)); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_in_match -- * * Checks the spec {"path": {"$in": [value1, value2, ...]}}. * * Returns: * true if the spec matched, otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_in_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { mongoc_matcher_op_compare_t op; op.base.opcode = MONGOC_MATCHER_OPCODE_EQ; op.path = compare->path; if (!BSON_ITER_HOLDS_ARRAY (&compare->iter) || !bson_iter_recurse (&compare->iter, &op.iter)) { return false; } while (bson_iter_next (&op.iter)) { if (_mongoc_matcher_op_eq_match (&op, iter)) { return true; } } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_lt_match -- * * Perform a {"path": "$lt": {value}} match. * * Returns: * true if the spec matched, otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_lt_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { bson_iter_t *compare_iter; int code; BSON_ASSERT (compare); BSON_ASSERT (iter); compare_iter = &compare->iter; code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _LT_COMPARE (_double, _double); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _LT_COMPARE (_double, _bool); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _LT_COMPARE (_double, _int32); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _LT_COMPARE (_double, _int64); /* Int32 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _LT_COMPARE (_int32, _double); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_BOOL): return _LT_COMPARE (_int32, _bool); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT32): return _LT_COMPARE (_int32, _int32); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT64): return _LT_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _LT_COMPARE (_int64, _double); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_BOOL): return _LT_COMPARE (_int64, _bool); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT32): return _LT_COMPARE (_int64, _int32); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT64): return _LT_COMPARE (_int64, _int64); default: MONGOC_WARNING ( "Implement for (Type(%d) < Type(%d))", (int) bson_iter_type (compare_iter), (int) bson_iter_type (iter)); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_lte_match -- * * Perform a {"$path": {"$lte": value}} match. * * Returns: * true if the spec matched, otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_lte_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { bson_iter_t *compare_iter; int code; BSON_ASSERT (compare); BSON_ASSERT (iter); compare_iter = &compare->iter; code = _TYPE_CODE (bson_iter_type (compare_iter), bson_iter_type (iter)); switch (code) { /* Double on Left Side */ case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_DOUBLE): return _LTE_COMPARE (_double, _double); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_BOOL): return _LTE_COMPARE (_double, _bool); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT32): return _LTE_COMPARE (_double, _int32); case _TYPE_CODE (BSON_TYPE_DOUBLE, BSON_TYPE_INT64): return _LTE_COMPARE (_double, _int64); /* Int32 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_DOUBLE): return _LTE_COMPARE (_int32, _double); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_BOOL): return _LTE_COMPARE (_int32, _bool); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT32): return _LTE_COMPARE (_int32, _int32); case _TYPE_CODE (BSON_TYPE_INT32, BSON_TYPE_INT64): return _LTE_COMPARE (_int32, _int64); /* Int64 on Left Side */ case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_DOUBLE): return _LTE_COMPARE (_int64, _double); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_BOOL): return _LTE_COMPARE (_int64, _bool); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT32): return _LTE_COMPARE (_int64, _int32); case _TYPE_CODE (BSON_TYPE_INT64, BSON_TYPE_INT64): return _LTE_COMPARE (_int64, _int64); default: MONGOC_WARNING ( "Implement for (Type(%d) <= Type(%d))", (int) bson_iter_type (compare_iter), (int) bson_iter_type (iter)); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_ne_match -- * * Perform a {"path": {"$ne": value}} match. * * Returns: * true if the field "path" was not found or the value is not-equal * to value. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_ne_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { return !_mongoc_matcher_op_eq_match (compare, iter); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_nin_match -- * * Perform a {"path": {"$nin": value}} match. * * Returns: * true if value was not found in the array at "path". * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_nin_match (mongoc_matcher_op_compare_t *compare, /* IN */ bson_iter_t *iter) /* IN */ { return !_mongoc_matcher_op_in_match (compare, iter); } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_compare_match -- * * Dispatch function for mongoc_matcher_op_compare_t operations * to perform a match. * * Returns: * Opcode dependent. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_compare_match (mongoc_matcher_op_compare_t *compare, /* IN */ const bson_t *bson) /* IN */ { bson_iter_t tmp; bson_iter_t iter; BSON_ASSERT (compare); BSON_ASSERT (bson); if (strchr (compare->path, '.')) { if (!bson_iter_init (&tmp, bson) || !bson_iter_find_descendant (&tmp, compare->path, &iter)) { return false; } } else if (!bson_iter_init_find (&iter, bson, compare->path)) { return false; } switch ((int) compare->base.opcode) { case MONGOC_MATCHER_OPCODE_EQ: return _mongoc_matcher_op_eq_match (compare, &iter); case MONGOC_MATCHER_OPCODE_GT: return _mongoc_matcher_op_gt_match (compare, &iter); case MONGOC_MATCHER_OPCODE_GTE: return _mongoc_matcher_op_gte_match (compare, &iter); case MONGOC_MATCHER_OPCODE_IN: return _mongoc_matcher_op_in_match (compare, &iter); case MONGOC_MATCHER_OPCODE_LT: return _mongoc_matcher_op_lt_match (compare, &iter); case MONGOC_MATCHER_OPCODE_LTE: return _mongoc_matcher_op_lte_match (compare, &iter); case MONGOC_MATCHER_OPCODE_NE: return _mongoc_matcher_op_ne_match (compare, &iter); case MONGOC_MATCHER_OPCODE_NIN: return _mongoc_matcher_op_nin_match (compare, &iter); default: BSON_ASSERT (false); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_logical_match -- * * Dispatch function for mongoc_matcher_op_logical_t operations * to perform a match. * * Returns: * Opcode specific. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_matcher_op_logical_match (mongoc_matcher_op_logical_t *logical, /* IN */ const bson_t *bson) /* IN */ { BSON_ASSERT (logical); BSON_ASSERT (bson); switch ((int) logical->base.opcode) { case MONGOC_MATCHER_OPCODE_OR: return (_mongoc_matcher_op_match (logical->left, bson) || _mongoc_matcher_op_match (logical->right, bson)); case MONGOC_MATCHER_OPCODE_AND: return (_mongoc_matcher_op_match (logical->left, bson) && _mongoc_matcher_op_match (logical->right, bson)); case MONGOC_MATCHER_OPCODE_NOR: return !(_mongoc_matcher_op_match (logical->left, bson) || _mongoc_matcher_op_match (logical->right, bson)); default: BSON_ASSERT (false); break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_match -- * * Dispatch function for all operation types to perform a match. * * Returns: * Opcode specific. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool _mongoc_matcher_op_match (mongoc_matcher_op_t *op, /* IN */ const bson_t *bson) /* IN */ { BSON_ASSERT (op); BSON_ASSERT (bson); switch (op->base.opcode) { case MONGOC_MATCHER_OPCODE_EQ: case MONGOC_MATCHER_OPCODE_GT: case MONGOC_MATCHER_OPCODE_GTE: case MONGOC_MATCHER_OPCODE_IN: case MONGOC_MATCHER_OPCODE_LT: case MONGOC_MATCHER_OPCODE_LTE: case MONGOC_MATCHER_OPCODE_NE: case MONGOC_MATCHER_OPCODE_NIN: return _mongoc_matcher_op_compare_match (&op->compare, bson); case MONGOC_MATCHER_OPCODE_OR: case MONGOC_MATCHER_OPCODE_AND: case MONGOC_MATCHER_OPCODE_NOR: return _mongoc_matcher_op_logical_match (&op->logical, bson); case MONGOC_MATCHER_OPCODE_NOT: return _mongoc_matcher_op_not_match (&op->not_, bson); case MONGOC_MATCHER_OPCODE_EXISTS: return _mongoc_matcher_op_exists_match (&op->exists, bson); case MONGOC_MATCHER_OPCODE_TYPE: return _mongoc_matcher_op_type_match (&op->type, bson); default: break; } return false; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_op_to_bson -- * * Convert the optree specified by @op to a bson document similar * to what the query would have been. This is not perfectly the * same, and so should not be used as such. * * Returns: * None. * * Side effects: * @bson is appended to, and therefore must be initialized before * calling this function. * *-------------------------------------------------------------------------- */ void _mongoc_matcher_op_to_bson (mongoc_matcher_op_t *op, /* IN */ bson_t *bson) /* IN */ { const char *str; bson_t child; bson_t child2; BSON_ASSERT (op); BSON_ASSERT (bson); switch (op->base.opcode) { case MONGOC_MATCHER_OPCODE_EQ: (void) bson_append_iter (bson, op->compare.path, -1, &op->compare.iter); break; case MONGOC_MATCHER_OPCODE_GT: case MONGOC_MATCHER_OPCODE_GTE: case MONGOC_MATCHER_OPCODE_IN: case MONGOC_MATCHER_OPCODE_LT: case MONGOC_MATCHER_OPCODE_LTE: case MONGOC_MATCHER_OPCODE_NE: case MONGOC_MATCHER_OPCODE_NIN: switch ((int) op->base.opcode) { case MONGOC_MATCHER_OPCODE_GT: str = "$gt"; break; case MONGOC_MATCHER_OPCODE_GTE: str = "$gte"; break; case MONGOC_MATCHER_OPCODE_IN: str = "$in"; break; case MONGOC_MATCHER_OPCODE_LT: str = "$lt"; break; case MONGOC_MATCHER_OPCODE_LTE: str = "$lte"; break; case MONGOC_MATCHER_OPCODE_NE: str = "$ne"; break; case MONGOC_MATCHER_OPCODE_NIN: str = "$nin"; break; default: str = "???"; break; } if (bson_append_document_begin (bson, op->compare.path, -1, &child)) { (void) bson_append_iter (&child, str, -1, &op->compare.iter); bson_append_document_end (bson, &child); } break; case MONGOC_MATCHER_OPCODE_OR: case MONGOC_MATCHER_OPCODE_AND: case MONGOC_MATCHER_OPCODE_NOR: if (op->base.opcode == MONGOC_MATCHER_OPCODE_OR) { str = "$or"; } else if (op->base.opcode == MONGOC_MATCHER_OPCODE_AND) { str = "$and"; } else if (op->base.opcode == MONGOC_MATCHER_OPCODE_NOR) { str = "$nor"; } else { BSON_ASSERT (false); str = NULL; } { bson_array_builder_t *bab; bson_append_array_builder_begin (bson, str, -1, &bab); bson_array_builder_append_document_begin (bab, &child2); _mongoc_matcher_op_to_bson (op->logical.left, &child2); bson_array_builder_append_document_end (bab, &child2); if (op->logical.right) { bson_array_builder_append_document_begin (bab, &child2); _mongoc_matcher_op_to_bson (op->logical.right, &child2); bson_array_builder_append_document_end (bab, &child2); } bson_append_array_builder_end (bson, bab); } break; case MONGOC_MATCHER_OPCODE_NOT: bson_append_document_begin (bson, op->not_.path, -1, &child); bson_append_document_begin (&child, "$not", 4, &child2); _mongoc_matcher_op_to_bson (op->not_.child, &child2); bson_append_document_end (&child, &child2); bson_append_document_end (bson, &child); break; case MONGOC_MATCHER_OPCODE_EXISTS: BSON_APPEND_BOOL (bson, "$exists", op->exists.exists); break; case MONGOC_MATCHER_OPCODE_TYPE: BSON_APPEND_INT32 (bson, "$type", (int) op->type.type); break; default: BSON_ASSERT (false); break; } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-matcher-private.h0000644000175100001660000000164614760300420024241 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_MATCHER_PRIVATE_H #define MONGOC_MATCHER_PRIVATE_H #include #include BSON_BEGIN_DECLS struct _mongoc_matcher_t { bson_t query; mongoc_matcher_op_t *optree; }; BSON_END_DECLS #endif /* MONGOC_MATCHER_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-matcher.c0000644000175100001660000002610414760300420022560 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include static mongoc_matcher_op_t * _mongoc_matcher_parse_logical (mongoc_matcher_opcode_t opcode, bson_iter_t *iter, bool is_root, bson_error_t *error); /* *-------------------------------------------------------------------------- * * _mongoc_matcher_parse_compare -- * * Parse a compare spec such as $gt or $in. * * See the following link for more information. * * https://www.mongodb.com/docs/manual/reference/operator/query/ * * Returns: * A newly allocated mongoc_matcher_op_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ static mongoc_matcher_op_t * _mongoc_matcher_parse_compare (bson_iter_t *iter, /* IN */ const char *path, /* IN */ bson_error_t *error) /* OUT */ { const char *key; mongoc_matcher_op_t *op = NULL, *op_child; bson_iter_t child; BSON_ASSERT (iter); BSON_ASSERT (path); if (bson_iter_type (iter) == BSON_TYPE_DOCUMENT) { if (!bson_iter_recurse (iter, &child) || !bson_iter_next (&child)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Document contains no operations."); return NULL; } key = bson_iter_key (&child); if (key[0] != '$') { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_EQ, path, iter); } else if (strcmp (key, "$not") == 0) { if (!(op_child = _mongoc_matcher_parse_compare (&child, path, error))) { return NULL; } op = _mongoc_matcher_op_not_new (path, op_child); } else if (strcmp (key, "$gt") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_GT, path, &child); } else if (strcmp (key, "$gte") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_GTE, path, &child); } else if (strcmp (key, "$in") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_IN, path, &child); } else if (strcmp (key, "$lt") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_LT, path, &child); } else if (strcmp (key, "$lte") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_LTE, path, &child); } else if (strcmp (key, "$ne") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_NE, path, &child); } else if (strcmp (key, "$nin") == 0) { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_NIN, path, &child); } else if (strcmp (key, "$exists") == 0) { op = _mongoc_matcher_op_exists_new (path, bson_iter_bool (&child)); } else if (strcmp (key, "$type") == 0) { op = _mongoc_matcher_op_type_new (path, bson_iter_type (&child)); } else { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Invalid operator \"%s\"", key); return NULL; } } else { op = _mongoc_matcher_op_compare_new (MONGOC_MATCHER_OPCODE_EQ, path, iter); } BSON_ASSERT (op); return op; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_parse -- * * Parse a query spec observed by the current key of @iter. * * Returns: * A newly allocated mongoc_matcher_op_t if successful; otherwise * NULL an @error is set. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ static mongoc_matcher_op_t * _mongoc_matcher_parse (bson_iter_t *iter, /* IN */ bson_error_t *error) /* OUT */ { bson_iter_t child; const char *key; BSON_ASSERT (iter); key = bson_iter_key (iter); if (*key != '$') { return _mongoc_matcher_parse_compare (iter, key, error); } else { BSON_ASSERT (bson_iter_type (iter) == BSON_TYPE_ARRAY); if (!bson_iter_recurse (iter, &child)) { bson_set_error ( error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Invalid value for operator \"%s\"", key); return NULL; } if (strcmp (key, "$or") == 0) { return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_OR, &child, false, error); } else if (strcmp (key, "$and") == 0) { return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_AND, &child, false, error); } else if (strcmp (key, "$nor") == 0) { return _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_NOR, &child, false, error); } } bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Invalid operator \"%s\"", key); return NULL; } /* *-------------------------------------------------------------------------- * * _mongoc_matcher_parse_logical -- * * Parse a query spec containing a logical operator such as * $or, $and, $not, and $nor. * * See the following link for more information. * * https://www.mongodb.com/docs/manual/reference/operator/query/ * * Returns: * A newly allocated mongoc_matcher_op_t if successful; otherwise * NULL and @error is set. * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ static mongoc_matcher_op_t * _mongoc_matcher_parse_logical (mongoc_matcher_opcode_t opcode, /* IN */ bson_iter_t *iter, /* IN */ bool is_root, /* IN */ bson_error_t *error) /* OUT */ { mongoc_matcher_op_t *left; mongoc_matcher_op_t *right; mongoc_matcher_op_t *more; mongoc_matcher_op_t *more_wrap; bson_iter_t child; BSON_ASSERT (opcode); BSON_ASSERT (iter); BSON_ASSERT (iter); if (!bson_iter_next (iter)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Invalid logical operator."); return NULL; } if (is_root) { if (!(left = _mongoc_matcher_parse (iter, error))) { return NULL; } } else { if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Expected document in value."); return NULL; } if (!bson_iter_recurse (iter, &child)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "corrupt BSON"); return NULL; } if (!bson_iter_next (&child)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "corrupt BSON"); return NULL; } if (!(left = _mongoc_matcher_parse (&child, error))) { return NULL; } } if (!bson_iter_next (iter)) { return left; } if (is_root) { if (!(right = _mongoc_matcher_parse (iter, error))) { return NULL; } } else { if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_set_error (error, MONGOC_ERROR_MATCHER, MONGOC_ERROR_MATCHER_INVALID, "Expected document in value."); return NULL; } if (!bson_iter_recurse (iter, &child)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "bson_iter_recurse failed."); return NULL; } if (!bson_iter_next (&child)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "corrupt BSON"); return NULL; } if (!(right = _mongoc_matcher_parse (&child, error))) { return NULL; } } more = _mongoc_matcher_parse_logical (opcode, iter, is_root, error); if (more) { more_wrap = _mongoc_matcher_op_logical_new (opcode, right, more); return _mongoc_matcher_op_logical_new (opcode, left, more_wrap); } return _mongoc_matcher_op_logical_new (opcode, left, right); } /* *-------------------------------------------------------------------------- * * mongoc_matcher_new -- * * Create a new mongoc_matcher_t using the query specification * provided in @query. * * This will build an operation tree that can be applied to arbitrary * bson documents using mongoc_matcher_match(). * * Returns: * A newly allocated mongoc_matcher_t if successful; otherwise NULL * and @error is set. * * The mongoc_matcher_t should be freed with * mongoc_matcher_destroy(). * * Side effects: * @error may be set. * *-------------------------------------------------------------------------- */ mongoc_matcher_t * mongoc_matcher_new (const bson_t *query, /* IN */ bson_error_t *error) /* OUT */ { mongoc_matcher_op_t *op; mongoc_matcher_t *matcher; bson_iter_t iter; BSON_ASSERT (query); matcher = BSON_ALIGNED_ALLOC0 (mongoc_matcher_t); bson_copy_to (query, &matcher->query); if (!bson_iter_init (&iter, &matcher->query)) { goto failure; } if (!(op = _mongoc_matcher_parse_logical (MONGOC_MATCHER_OPCODE_AND, &iter, true, error))) { goto failure; } matcher->optree = op; return matcher; failure: bson_destroy (&matcher->query); bson_free (matcher); return NULL; } /* *-------------------------------------------------------------------------- * * mongoc_matcher_match -- * * Checks to see if @bson matches the query specified when creating * @matcher. * * Returns: * TRUE if @bson matched the query, otherwise FALSE. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool mongoc_matcher_match (const mongoc_matcher_t *matcher, /* IN */ const bson_t *document) /* IN */ { BSON_ASSERT (matcher); BSON_ASSERT (matcher->optree); BSON_ASSERT (document); return _mongoc_matcher_op_match (matcher->optree, document); } /* *-------------------------------------------------------------------------- * * mongoc_matcher_destroy -- * * Release all resources associated with @matcher. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_matcher_destroy (mongoc_matcher_t *matcher) /* IN */ { BSON_ASSERT (matcher); _mongoc_matcher_op_destroy (matcher->optree); bson_destroy (&matcher->query); bson_free (matcher); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-matcher.h0000644000175100001660000000232314760300420022562 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_MATCHER_H #define MONGOC_MATCHER_H #include #include BSON_BEGIN_DECLS typedef struct _mongoc_matcher_t mongoc_matcher_t; MONGOC_EXPORT (mongoc_matcher_t *) mongoc_matcher_new (const bson_t *query, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED; MONGOC_EXPORT (bool) mongoc_matcher_match (const mongoc_matcher_t *matcher, const bson_t *document) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (void) mongoc_matcher_destroy (mongoc_matcher_t *matcher) BSON_GNUC_DEPRECATED; BSON_END_DECLS #endif /* MONGOC_MATCHER_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-memcmp-private.h0000644000175100001660000000213014760300420024061 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_MEMCMP_PRIVATE_H #define MONGOC_MEMCMP_PRIVATE_H #include #include /* WARNING: mongoc_memcmp() must be used to verify if two secret keys * are equal, in constant time. * It returns 0 if the keys are equal, and -1 if they differ. * This function is not designed for lexicographical comparisons. */ int mongoc_memcmp (const void *const b1, const void *const b2, size_t len); #endif /* MONGOC_MEMCMP_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-memcmp.c0000644000175100001660000000206114760300420022407 0ustar /* * Copyright (c) 2013-2015 * Frank Denis * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include int mongoc_memcmp (const void *const b1, const void *const b2, size_t len) { const unsigned char *p1 = b1, *p2 = b2; int ret = 0; for (; len > 0; len--) { ret |= *p1++ ^ *p2++; } return ret ? 1 : 0; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-ocsp-cache-private.h0000644000175100001660000000317114760300420024616 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_OCSP_CACHE_PRIVATE_H #define MONGOC_OCSP_CACHE_PRIVATE_H #include #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #ifdef MONGOC_ENABLE_OCSP_OPENSSL #include void _mongoc_ocsp_cache_init (void); void _mongoc_ocsp_cache_set_resp ( OCSP_CERTID *id, int cert_status, int reason, ASN1_GENERALIZEDTIME *this_update, ASN1_GENERALIZEDTIME *next_update); int _mongoc_ocsp_cache_length (void); bool _mongoc_ocsp_cache_get_status (OCSP_CERTID *id, int *cert_status, int *reason, ASN1_GENERALIZEDTIME **this_update, ASN1_GENERALIZEDTIME **next_update); void _mongoc_ocsp_cache_cleanup (void); #endif /* MONGOC_ENABLE_OCSP_OPENSSL */ #endif /* MONGOC_ENABLE_SSL_OPENSSL */ /* ensure the translation unit is not empty */ extern int no_mongoc_ocsp_cache; #endif /* MONGO_C_DRIVER_MONGOC_OCSP_CACHE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-ocsp-cache.c0000644000175100001660000001303314760300420023137 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_OCSP_OPENSSL #include #include #include #include typedef struct _cache_entry_list_t { struct _cache_entry_list_t *next; OCSP_CERTID *id; int cert_status, reason; ASN1_GENERALIZEDTIME *this_update, *next_update; } cache_entry_list_t; static cache_entry_list_t *cache; static bson_mutex_t ocsp_cache_mutex; void _mongoc_ocsp_cache_init (void) { bson_mutex_init (&ocsp_cache_mutex); } static int cache_cmp (cache_entry_list_t *out, OCSP_CERTID *id) { ENTRY; if (!out || !out->id || !id) RETURN (1); RETURN (OCSP_id_cmp (out->id, id)); } static cache_entry_list_t * get_cache_entry (OCSP_CERTID *id) { cache_entry_list_t *iter = NULL; ENTRY; LL_SEARCH (cache, iter, id, cache_cmp); RETURN (iter); } #define REPLACE_ASN1_TIME(_old, _new) \ do { \ if ((_new)) { \ if ((_old)) \ ASN1_GENERALIZEDTIME_free ((_old)); \ (_old) = ASN1_item_dup (ASN1_ITEM_rptr (ASN1_TIME), (_new)); \ } \ } while (0) static void update_entry (cache_entry_list_t *entry, int cert_status, int reason, ASN1_GENERALIZEDTIME *this_update, ASN1_GENERALIZEDTIME *next_update) { ENTRY; REPLACE_ASN1_TIME (entry->next_update, next_update); REPLACE_ASN1_TIME (entry->this_update, this_update); entry->cert_status = cert_status; entry->reason = reason; } #if OPENSSL_VERSION_NUMBER >= 0x10101000L static int _cmp_time (ASN1_TIME *a, ASN1_TIME *b) { return ASN1_TIME_compare (a, b); } #else static int _cmp_time (ASN1_TIME *a, ASN1_TIME *b) { /* For older OpenSSL, always report that "a" is before "b". I.e. do not * replace the entry. * If a driver would accept a stapled OCSP response and that response has a * later nextUpdate than the response already in the cache, drivers SHOULD * replace the older entry in the cache with the fresher response. */ return -1; } #endif void _mongoc_ocsp_cache_set_resp ( OCSP_CERTID *id, int cert_status, int reason, ASN1_GENERALIZEDTIME *this_update, ASN1_GENERALIZEDTIME *next_update) { cache_entry_list_t *entry = NULL; ENTRY; bson_mutex_lock (&ocsp_cache_mutex); if (!(entry = get_cache_entry (id))) { entry = bson_malloc0 (sizeof (cache_entry_list_t)); entry->id = OCSP_CERTID_dup (id); LL_APPEND (cache, entry); update_entry (entry, cert_status, reason, this_update, next_update); } else if (next_update && _cmp_time (next_update, entry->next_update) == 1) { update_entry (entry, cert_status, reason, this_update, next_update); } else { /* Do nothing; our next_update is at a later date */ } bson_mutex_unlock (&ocsp_cache_mutex); } int _mongoc_ocsp_cache_length (void) { cache_entry_list_t *iter; int counter; bson_mutex_lock (&ocsp_cache_mutex); LL_COUNT (cache, iter, counter); bson_mutex_unlock (&ocsp_cache_mutex); RETURN (counter); } static void cache_entry_destroy (cache_entry_list_t *entry) { OCSP_CERTID_free (entry->id); ASN1_GENERALIZEDTIME_free (entry->this_update); ASN1_GENERALIZEDTIME_free (entry->next_update); bson_free (entry); } bool _mongoc_ocsp_cache_get_status (OCSP_CERTID *id, int *cert_status, int *reason, ASN1_GENERALIZEDTIME **this_update, ASN1_GENERALIZEDTIME **next_update) { cache_entry_list_t *entry = NULL; bool ret = false; ENTRY; bson_mutex_lock (&ocsp_cache_mutex); if (!(entry = get_cache_entry (id))) { GOTO (done); } if (entry->this_update && entry->next_update && !OCSP_check_validity (entry->this_update, entry->next_update, 0L, -1L)) { LL_DELETE (cache, entry); cache_entry_destroy (entry); GOTO (done); } BSON_ASSERT_PARAM (cert_status); BSON_ASSERT_PARAM (reason); BSON_ASSERT_PARAM (this_update); BSON_ASSERT_PARAM (next_update); *cert_status = entry->cert_status; *reason = entry->reason; *this_update = entry->this_update; *next_update = entry->next_update; ret = true; done: bson_mutex_unlock (&ocsp_cache_mutex); RETURN (ret); } void _mongoc_ocsp_cache_cleanup (void) { cache_entry_list_t *iter = NULL; cache_entry_list_t *next = NULL; ENTRY; bson_mutex_lock (&ocsp_cache_mutex); for (iter = cache; iter != NULL; iter = next) { next = iter->next; cache_entry_destroy (iter); } cache = NULL; bson_mutex_unlock (&ocsp_cache_mutex); bson_mutex_destroy (&ocsp_cache_mutex); } #endif /* MONGOC_ENABLE_OCSP_OPENSSL */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-opcode.c0000644000175100001660000000260214760300420022403 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include // Document and ensure consistency between equivalent macros in mcd-rpc and // libmongoc. BSON_STATIC_ASSERT (MONGOC_OP_CODE_COMPRESSED == MONGOC_OPCODE_COMPRESSED); BSON_STATIC_ASSERT (MONGOC_OP_CODE_MSG == MONGOC_OPCODE_MSG); BSON_STATIC_ASSERT (MONGOC_OP_CODE_REPLY == MONGOC_OPCODE_REPLY); BSON_STATIC_ASSERT (MONGOC_OP_CODE_UPDATE == MONGOC_OPCODE_UPDATE); BSON_STATIC_ASSERT (MONGOC_OP_CODE_INSERT == MONGOC_OPCODE_INSERT); BSON_STATIC_ASSERT (MONGOC_OP_CODE_QUERY == MONGOC_OPCODE_QUERY); BSON_STATIC_ASSERT (MONGOC_OP_CODE_GET_MORE == MONGOC_OPCODE_GET_MORE); BSON_STATIC_ASSERT (MONGOC_OP_CODE_DELETE == MONGOC_OPCODE_DELETE); BSON_STATIC_ASSERT (MONGOC_OP_CODE_KILL_CURSORS == MONGOC_OPCODE_KILL_CURSORS); mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-opcode.h0000644000175100001660000000212314760300420022406 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_OPCODE_H #define MONGOC_OPCODE_H #include BSON_BEGIN_DECLS typedef enum { MONGOC_OPCODE_REPLY = 1, MONGOC_OPCODE_UPDATE = 2001, MONGOC_OPCODE_INSERT = 2002, MONGOC_OPCODE_QUERY = 2004, MONGOC_OPCODE_GET_MORE = 2005, MONGOC_OPCODE_DELETE = 2006, MONGOC_OPCODE_KILL_CURSORS = 2007, MONGOC_OPCODE_COMPRESSED = 2012, MONGOC_OPCODE_MSG = 2013, } mongoc_opcode_t; BSON_END_DECLS #endif /* MONGOC_OPCODE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-openssl-private.h0000644000175100001660000000314214760300420024272 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_OPENSSL_PRIVATE_H #define MONGOC_OPENSSL_PRIVATE_H #include #include #include #include #include #include #if (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_OCSP) && !defined(LIBRESSL_VERSION_NUMBER) #define MONGOC_ENABLE_OCSP_OPENSSL #endif BSON_BEGIN_DECLS bool _mongoc_openssl_check_peer_hostname (SSL *ssl, const char *host, bool allow_invalid_hostname); SSL_CTX * _mongoc_openssl_ctx_new (mongoc_ssl_opt_t *opt); char * _mongoc_openssl_extract_subject (const char *filename, const char *passphrase); void _mongoc_openssl_init (void); void _mongoc_openssl_cleanup (void); #ifdef MONGOC_ENABLE_OCSP_OPENSSL int _mongoc_ocsp_tlsext_status (SSL *ssl, mongoc_openssl_ocsp_opt_t *opts); #endif bool _mongoc_tlsfeature_has_status_request (const uint8_t *data, int length); BSON_END_DECLS #endif /* MONGOC_OPENSSL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-openssl.c0000644000175100001660000010037214760300420022620 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_OCSP_OPENSSL #include #endif #ifdef _WIN32 #include #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L static bson_mutex_t *gMongocOpenSslThreadLocks; static void _mongoc_openssl_thread_startup (void); static void _mongoc_openssl_thread_cleanup (void); #endif #ifndef MONGOC_HAVE_ASN1_STRING_GET0_DATA #define ASN1_STRING_get0_data ASN1_STRING_data #endif static int tlsfeature_nid; /** * _mongoc_openssl_init: * * initialization function for SSL * * This needs to get called early on and is not threadsafe. Called by * mongoc_init. */ void _mongoc_openssl_init (void) { SSL_CTX *ctx; SSL_library_init (); SSL_load_error_strings (); #if OPENSSL_VERSION_NUMBER < 0x30000000L // See: // https://www.openssl.org/docs/man3.0/man7/migration_guide.html#Deprecated-function-mappings ERR_load_BIO_strings (); #endif OpenSSL_add_all_algorithms (); #if OPENSSL_VERSION_NUMBER < 0x10100000L _mongoc_openssl_thread_startup (); #endif ctx = SSL_CTX_new (SSLv23_method ()); if (!ctx) { MONGOC_ERROR ("Failed to initialize OpenSSL."); } #ifdef NID_tlsfeature tlsfeature_nid = NID_tlsfeature; #else /* TLS versions before 1.1.0 did not define the TLS Feature extension. */ tlsfeature_nid = OBJ_create ("1.3.6.1.5.5.7.1.24", "tlsfeature", "TLS Feature"); #endif SSL_CTX_free (ctx); } void _mongoc_openssl_cleanup (void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L _mongoc_openssl_thread_cleanup (); #endif } static int _mongoc_openssl_password_cb (char *buf, int num, int rwflag, void *user_data) { char *pass = (char *) user_data; int pass_len = (int) strlen (pass); BSON_UNUSED (rwflag); if (num < pass_len + 1) { return 0; } bson_strncpy (buf, pass, num); return pass_len; } #ifdef _WIN32 bool _mongoc_openssl_import_cert_store (LPWSTR store_name, DWORD dwFlags, X509_STORE *openssl_store) { PCCERT_CONTEXT cert = NULL; HCERTSTORE cert_store; cert_store = CertOpenStore (CERT_STORE_PROV_SYSTEM, /* provider */ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, /* certificate encoding */ 0, /* unused */ dwFlags, /* dwFlags */ store_name); /* system store name. "My" or "Root" */ if (cert_store == NULL) { LPTSTR msg = NULL; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError (), LANG_NEUTRAL, (LPTSTR) &msg, 0, NULL); MONGOC_ERROR ("Can't open CA store: 0x%.8X: '%s'", GetLastError (), msg); LocalFree (msg); return false; } while ((cert = CertEnumCertificatesInStore (cert_store, cert)) != NULL) { X509 *x509Obj = d2i_X509 (NULL, (const unsigned char **) &cert->pbCertEncoded, cert->cbCertEncoded); if (x509Obj == NULL) { MONGOC_WARNING ("Error parsing X509 object from Windows certificate store"); continue; } X509_STORE_add_cert (openssl_store, x509Obj); X509_free (x509Obj); } CertCloseStore (cert_store, 0); return true; } bool _mongoc_openssl_import_cert_stores (SSL_CTX *context) { bool retval; X509_STORE *store = SSL_CTX_get_cert_store (context); if (!store) { MONGOC_WARNING ("no X509 store found for SSL context while loading " "system certificates"); return false; } retval = _mongoc_openssl_import_cert_store (L"root", CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG, store); retval &= _mongoc_openssl_import_cert_store (L"CA", CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG, store); return retval; } #endif #if OPENSSL_VERSION_NUMBER > 0x10002000L bool _mongoc_openssl_check_peer_hostname (SSL *ssl, const char *host, bool allow_invalid_hostname) { X509 *peer = NULL; if (allow_invalid_hostname) { return true; } peer = SSL_get_peer_certificate (ssl); if (peer && (X509_check_host (peer, host, 0, 0, NULL) == 1 || X509_check_ip_asc (peer, host, 0) == 1)) { X509_free (peer); return true; } if (peer) { X509_free (peer); } return false; } #else /** mongoc_openssl_hostcheck * * rfc 6125 match a given hostname against a given pattern * * Patterns come from DNS common names or subjectAltNames. * * This code is meant to implement RFC 6125 6.4.[1-3] * */ static bool _mongoc_openssl_hostcheck (const char *pattern, const char *hostname) { const char *pattern_label_end; const char *pattern_wildcard; const char *hostname_label_end; size_t prefixlen; size_t suffixlen; TRACE ("Comparing '%s' == '%s'", pattern, hostname); pattern_wildcard = strchr (pattern, '*'); if (pattern_wildcard == NULL) { return strcasecmp (pattern, hostname) == 0; } pattern_label_end = strchr (pattern, '.'); /* Bail out on wildcarding in a couple of situations: * o we don't have 2 dots - we're not going to wildcard root tlds * o the wildcard isn't in the left most group (separated by dots) * o the pattern is embedded in an A-label or U-label */ if (pattern_label_end == NULL || strchr (pattern_label_end + 1, '.') == NULL || pattern_wildcard > pattern_label_end || strncasecmp (pattern, "xn--", 4) == 0) { return strcasecmp (pattern, hostname) == 0; } hostname_label_end = strchr (hostname, '.'); /* we know we have a dot in the pattern, we need one in the hostname */ if (hostname_label_end == NULL || strcasecmp (pattern_label_end, hostname_label_end)) { return 0; } /* The wildcard must match at least one character, so the left part of the * hostname is at least as large as the left part of the pattern. */ if ((hostname_label_end - hostname) < (pattern_label_end - pattern)) { return 0; } /* If the left prefix group before the star matches and right of the star * matches... we have a wildcard match */ prefixlen = pattern_wildcard - pattern; suffixlen = pattern_label_end - (pattern_wildcard + 1); return strncasecmp (pattern, hostname, prefixlen) == 0 && strncasecmp (pattern_wildcard + 1, hostname_label_end - suffixlen, suffixlen) == 0; } /** check if a provided cert matches a passed hostname */ bool _mongoc_openssl_check_peer_hostname (SSL *ssl, const char *host, bool allow_invalid_hostname) { X509 *peer; X509_NAME *subject_name; X509_NAME_ENTRY *entry; ASN1_STRING *entry_data; int length; int idx; int r = 0; long verify_status; size_t addrlen = 0; unsigned char addr4[sizeof (struct in_addr)]; unsigned char addr6[sizeof (struct in6_addr)]; int i; int n_sans = -1; int target = GEN_DNS; STACK_OF (GENERAL_NAME) *sans = NULL; ENTRY; BSON_ASSERT (ssl); BSON_ASSERT (host); if (allow_invalid_hostname) { RETURN (true); } /** if the host looks like an IP address, match that, otherwise we assume we * have a DNS name */ if (inet_pton (AF_INET, host, &addr4)) { target = GEN_IPADD; addrlen = sizeof addr4; } else if (inet_pton (AF_INET6, host, &addr6)) { target = GEN_IPADD; addrlen = sizeof addr6; } peer = SSL_get_peer_certificate (ssl); if (!peer) { MONGOC_WARNING ("SSL Certification verification failed: %s", ERR_error_string (ERR_get_error (), NULL)); RETURN (false); } verify_status = SSL_get_verify_result (ssl); if (verify_status == X509_V_OK) { /* gets a stack of alt names that we can iterate through */ sans = (STACK_OF (GENERAL_NAME) *) X509_get_ext_d2i ((X509 *) peer, NID_subject_alt_name, NULL, NULL); if (sans) { n_sans = sk_GENERAL_NAME_num (sans); /* loop through the stack, or until we find a match */ for (i = 0; i < n_sans && !r; i++) { const GENERAL_NAME *name = sk_GENERAL_NAME_value (sans, i); /* skip entries that can't apply, I.e. IP entries if we've got a * DNS host */ if (name->type == target) { const char *check; check = (const char *) ASN1_STRING_get0_data (name->d.ia5); length = ASN1_STRING_length (name->d.ia5); switch (target) { case GEN_DNS: /* check that we don't have an embedded null byte */ if ((length == bson_strnlen (check, length)) && _mongoc_openssl_hostcheck (check, host)) { r = 1; } break; case GEN_IPADD: if (length == addrlen) { if (length == sizeof addr6 && !memcmp (check, &addr6, length)) { r = 1; } else if (length == sizeof addr4 && !memcmp (check, &addr4, length)) { r = 1; } } break; default: BSON_ASSERT (0); break; } } } GENERAL_NAMES_free (sans); } else { subject_name = X509_get_subject_name (peer); if (subject_name) { i = -1; /* skip to the last common name */ while ((idx = X509_NAME_get_index_by_NID (subject_name, NID_commonName, i)) >= 0) { i = idx; } if (i >= 0) { entry = X509_NAME_get_entry (subject_name, i); entry_data = X509_NAME_ENTRY_get_data (entry); if (entry_data) { char *check; /* TODO: I've heard tell that old versions of SSL crap out * when calling ASN1_STRING_to_UTF8 on already utf8 data. * Check up on that */ length = ASN1_STRING_to_UTF8 ((unsigned char **) &check, entry_data); if (length >= 0) { /* check for embedded nulls */ if ((length == bson_strnlen (check, length)) && _mongoc_openssl_hostcheck (check, host)) { r = 1; } OPENSSL_free (check); } } } } } } X509_free (peer); RETURN (r); } #endif /* OPENSSL_VERSION_NUMBER */ static bool _mongoc_openssl_setup_ca (SSL_CTX *ctx, const char *cert, const char *cert_dir) { BSON_ASSERT (ctx); BSON_ASSERT (cert || cert_dir); if (!SSL_CTX_load_verify_locations (ctx, cert, cert_dir)) { MONGOC_ERROR ("Cannot load Certificate Authorities from '%s' and '%s'", cert, cert_dir); return 0; } return 1; } static bool _mongoc_openssl_setup_crl (SSL_CTX *ctx, const char *crlfile) { X509_STORE *store; X509_LOOKUP *lookup; int status; store = SSL_CTX_get_cert_store (ctx); X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK); lookup = X509_STORE_add_lookup (store, X509_LOOKUP_file ()); status = X509_load_crl_file (lookup, crlfile, X509_FILETYPE_PEM); return status != 0; } static bool _mongoc_openssl_setup_pem_file (SSL_CTX *ctx, const char *pem_file, const char *password) { if (!SSL_CTX_use_certificate_chain_file (ctx, pem_file)) { MONGOC_ERROR ("Cannot find certificate in '%s'", pem_file); return 0; } if (password) { SSL_CTX_set_default_passwd_cb_userdata (ctx, (void *) password); SSL_CTX_set_default_passwd_cb (ctx, _mongoc_openssl_password_cb); } if (!(SSL_CTX_use_PrivateKey_file (ctx, pem_file, SSL_FILETYPE_PEM))) { MONGOC_ERROR ("Cannot find private key in: '%s'", pem_file); return 0; } if (!(SSL_CTX_check_private_key (ctx))) { MONGOC_ERROR ("Cannot load private key: '%s'", pem_file); return 0; } return 1; } #ifdef MONGOC_ENABLE_OCSP_OPENSSL static X509 * _get_issuer (X509 *cert, STACK_OF (X509) * chain) { X509 *issuer = NULL, *candidate = NULL; X509_NAME *issuer_name = NULL, *candidate_name = NULL; int i; issuer_name = X509_get_issuer_name (cert); for (i = 0; i < sk_X509_num (chain) && issuer == NULL; i++) { candidate = sk_X509_value (chain, i); candidate_name = X509_get_subject_name (candidate); if (0 == X509_NAME_cmp (candidate_name, issuer_name)) { issuer = candidate; } } RETURN (issuer); } #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL 1.1.0+ has conveniences that we polyfill in older OpenSSL versions. */ STACK_OF (X509) * _get_verified_chain (SSL *ssl) { return SSL_get0_verified_chain (ssl); } void _free_verified_chain (STACK_OF (X509) * verified_chain) { BSON_UNUSED (verified_chain); /* _get_verified_chain does not return a copy. Do nothing. */ return; } const STACK_OF (X509_EXTENSION) * _get_extensions (const X509 *cert) { return X509_get0_extensions (cert); } #else /* Polyfill functionality for pre 1.1.0 OpenSSL */ STACK_OF (X509) * _get_verified_chain (SSL *ssl) { X509_STORE *store = NULL; X509 *peer = NULL; STACK_OF (X509) *peer_chain = NULL; X509_STORE_CTX *store_ctx = NULL; STACK_OF (X509) *verified_chain = NULL; /* Get the certificate the server presented. */ peer = SSL_get_peer_certificate (ssl); /* Get the chain of certificates the server presented. This is not a verified * chain. */ peer_chain = SSL_get_peer_cert_chain (ssl); store = SSL_CTX_get_cert_store (SSL_get_SSL_CTX (ssl)); store_ctx = X509_STORE_CTX_new (); if (!X509_STORE_CTX_init (store_ctx, store, peer, peer_chain)) { MONGOC_ERROR ("failed to initialize X509 store"); goto fail; } if (X509_verify_cert (store_ctx) <= 0) { MONGOC_ERROR ("failed to obtain verified chain"); goto fail; } verified_chain = X509_STORE_CTX_get1_chain (store_ctx); fail: X509_free (peer); X509_STORE_CTX_free (store_ctx); return verified_chain; } /* On OpenSSL < 1.1.0, this chain isn't attached to the SSL session, so we need * it to dispose of itself. */ void _free_verified_chain (STACK_OF (X509) * verified_chain) { if (!verified_chain) { return; } sk_X509_pop_free (verified_chain, X509_free); } const STACK_OF (X509_EXTENSION) * _get_extensions (const X509 *cert) { return cert->cert_info->extensions; } #endif /* OPENSSL_VERSION_NUMBER */ #define TLSFEATURE_STATUS_REQUEST 5 /* Check a tlsfeature extension contents for a status_request. * * Parse just enough of a DER encoded data to check if a SEQUENCE of INTEGER * contains the status_request extension (5). There are only five tlsfeature * extension types, so this only handles the case that the sequence's length is * representable in one byte, and that each integer is representable in one * byte. */ bool _mongoc_tlsfeature_has_status_request (const uint8_t *data, int length) { int i; /* Expect a sequence type, with a sequence length representable in one byte. */ if (length < 3 || data[0] != 0x30 || data[1] >= 127) { MONGOC_ERROR ("malformed tlsfeature extension sequence"); return false; } for (i = 2; i < length; i += 3) { /* Expect an integer, representable in one byte. */ if (length < i + 3 || data[i] != 0x02 || data[i + 1] != 1) { MONGOC_ERROR ("malformed tlsfeature extension integer"); return false; } if (data[i + 2] == TLSFEATURE_STATUS_REQUEST) { TRACE ("%s", "found status request in tlsfeature extension"); return true; } } return false; } /* Check that the certificate has a tlsfeature extension with status_request. */ bool _get_must_staple (X509 *cert) { const STACK_OF (X509_EXTENSION) *exts = NULL; X509_EXTENSION *ext; ASN1_STRING *ext_data; int idx; exts = _get_extensions (cert); if (!exts) { TRACE ("%s", "certificate extensions not found"); return false; } idx = X509v3_get_ext_by_NID (exts, tlsfeature_nid, -1); if (-1 == idx) { TRACE ("%s", "tlsfeature extension not found"); return false; } ext = sk_X509_EXTENSION_value (exts, idx); ext_data = X509_EXTENSION_get_data (ext); /* Data is a DER encoded sequence of integers. */ return _mongoc_tlsfeature_has_status_request (ASN1_STRING_get0_data (ext_data), ASN1_STRING_length (ext_data)); } #define ERR_STR (ERR_error_string (ERR_get_error (), NULL)) #define MONGOC_OCSP_REQUEST_TIMEOUT_MS 5000 static OCSP_RESPONSE * _contact_ocsp_responder (OCSP_CERTID *id, X509 *peer, mongoc_ssl_opt_t *ssl_opts, int *ocsp_uri_count) { STACK_OF (OPENSSL_STRING) *url_stack = NULL; OPENSSL_STRING url = NULL, host = NULL, path = NULL, port = NULL; OCSP_REQUEST *req = NULL; const unsigned char *resp_data; OCSP_RESPONSE *resp = NULL; int i, ssl; url_stack = X509_get1_ocsp (peer); *ocsp_uri_count = sk_OPENSSL_STRING_num (url_stack); for (i = 0; i < *ocsp_uri_count && !resp; i++) { unsigned char *request_der = NULL; int request_der_len; mongoc_http_request_t http_req; mongoc_http_response_t http_res; bson_error_t error; _mongoc_http_request_init (&http_req); _mongoc_http_response_init (&http_res); url = sk_OPENSSL_STRING_value (url_stack, i); TRACE ("Contacting OCSP responder '%s'", url); /* splits the given url into its host, port and path components */ if (!OCSP_parse_url (url, &host, &port, &path, &ssl)) { MONGOC_DEBUG ("Could not parse URL"); GOTO (retry); } if (!(req = OCSP_REQUEST_new ())) { MONGOC_DEBUG ("Could not create new OCSP request"); GOTO (retry); } /* add the cert ID to the OCSP request object */ if (!id || !OCSP_request_add0_id (req, OCSP_CERTID_dup (id))) { MONGOC_DEBUG ("Could not add cert ID to the OCSP request object"); GOTO (retry); } /* add nonce to OCSP request object */ if (!OCSP_request_add1_nonce (req, 0 /* use random nonce */, -1)) { MONGOC_DEBUG ("Could not add nonce to OCSP request object"); GOTO (retry); } request_der_len = i2d_OCSP_REQUEST (req, &request_der); if (request_der_len < 0) { MONGOC_DEBUG ("Could not encode OCSP request"); GOTO (retry); } http_req.method = "POST"; http_req.extra_headers = "Content-Type: application/ocsp-request\r\n"; http_req.host = host; http_req.path = path; http_req.port = (int) bson_ascii_strtoll (port, NULL, 10); http_req.body = (const char *) request_der; http_req.body_len = request_der_len; if (!_mongoc_http_send (&http_req, MONGOC_OCSP_REQUEST_TIMEOUT_MS, ssl != 0, ssl_opts, &http_res, &error)) { MONGOC_DEBUG ("Could not send HTTP request: %s", error.message); GOTO (retry); } resp_data = (const unsigned char *) http_res.body; if (http_res.body_len == 0 || !d2i_OCSP_RESPONSE (&resp, &resp_data, http_res.body_len)) { MONGOC_DEBUG ("Could not parse OCSP response from HTTP response"); MONGOC_DEBUG ("Response headers: %s", http_res.headers); GOTO (retry); } retry: if (host) OPENSSL_free (host); if (port) OPENSSL_free (port); if (path) OPENSSL_free (path); if (req) OCSP_REQUEST_free (req); if (request_der) OPENSSL_free (request_der); _mongoc_http_response_cleanup (&http_res); } if (url_stack) X509_email_free (url_stack); RETURN (resp); } #define SOFT_FAIL(...) ((stapled_response) ? MONGOC_ERROR (__VA_ARGS__) : MONGOC_DEBUG (__VA_ARGS__)) #define X509_CHECK_SUCCESS 1 #define OCSP_VERIFY_SUCCESS 1 int _mongoc_ocsp_tlsext_status (SSL *ssl, mongoc_openssl_ocsp_opt_t *opts) { enum { OCSP_CB_ERROR = -1, OCSP_CB_REVOKED, OCSP_CB_SUCCESS } ret; bool stapled_response = true; bool must_staple; OCSP_RESPONSE *resp = NULL; OCSP_BASICRESP *basic = NULL; X509_STORE *store = NULL; X509 *peer = NULL, *issuer = NULL; STACK_OF (X509) *cert_chain = NULL; const unsigned char *resp_data = NULL; unsigned char *mutable_resp_data = NULL; int cert_status, reason, len, status; OCSP_CERTID *id = NULL; ASN1_GENERALIZEDTIME *produced_at = NULL, *this_update = NULL, *next_update = NULL; int ocsp_uri_count = 0; if (opts->weak_cert_validation) { return OCSP_CB_SUCCESS; } if (!(peer = SSL_get_peer_certificate (ssl))) { MONGOC_ERROR ("No certificate was presented by the peer"); ret = OCSP_CB_ERROR; GOTO (done); } /* Get a STACK_OF(X509) certs forming the cert chain of the peer, including * the peer's cert */ if (!(cert_chain = _get_verified_chain (ssl))) { MONGOC_ERROR ("Unable to obtain verified chain"); ret = OCSP_CB_REVOKED; GOTO (done); } if (!(issuer = _get_issuer (peer, cert_chain))) { MONGOC_ERROR ("Could not get issuer from peer cert"); ret = OCSP_CB_ERROR; GOTO (done); } if (!(id = OCSP_cert_to_id (NULL /* SHA1 */, peer, issuer))) { MONGOC_ERROR ("Could not obtain a valid OCSP_CERTID for peer"); ret = OCSP_CB_ERROR; GOTO (done); } if (_mongoc_ocsp_cache_get_status (id, &cert_status, &reason, &this_update, &next_update)) { GOTO (validate); } /* Get the stapled OCSP response returned by the server */ len = SSL_get_tlsext_status_ocsp_resp (ssl, &mutable_resp_data); resp_data = mutable_resp_data; stapled_response = !!resp_data; if (stapled_response) { /* obtain an OCSP_RESPONSE object from the OCSP response */ if (!d2i_OCSP_RESPONSE (&resp, &resp_data, len)) { MONGOC_ERROR ("Failed to parse OCSP response"); ret = OCSP_CB_ERROR; GOTO (done); } } else { TRACE ("%s", "Server does not contain a stapled response"); must_staple = _get_must_staple (peer); if (must_staple) { MONGOC_ERROR ("Server must contain a stapled response"); ret = OCSP_CB_REVOKED; GOTO (done); } if (opts->disable_endpoint_check || !(resp = _contact_ocsp_responder (id, peer, &opts->ssl_opts, &ocsp_uri_count))) { if (ocsp_uri_count > 0) { /* Only log a soft failure if there were OCSP responders listed in * the certificate. */ MONGOC_DEBUG ("Soft-fail: No OCSP responder could be reached"); } ret = OCSP_CB_SUCCESS; GOTO (done); } } TRACE ("%s", "Validating OCSP response"); /* Validate the OCSP response status of the OCSP_RESPONSE object */ status = OCSP_response_status (resp); if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { SOFT_FAIL ("OCSP response error %d %s", status, OCSP_response_status_str (status)); ret = OCSP_CB_ERROR; GOTO (done); } TRACE ("%s", "OCSP response status successful"); /* Get the OCSP_BASICRESP structure contained in OCSP_RESPONSE object for the * peer cert */ basic = OCSP_response_get1_basic (resp); if (!basic) { SOFT_FAIL ("Could not find BasicOCSPResponse: %s", ERR_STR); ret = OCSP_CB_ERROR; GOTO (done); } store = SSL_CTX_get_cert_store (SSL_get_SSL_CTX (ssl)); /* * checks that the basic response message is correctly signed and that the * signer certificate can be validated. * 1. The function first verifies the signer cert of the response is in the * given cert chain. * 2. Next, the function verifies the signature of the basic response. * 3. Finally, the function validates the signer cert, constructing the * validation path via the untrusted cert chain. * * cert_chain has already been verified. Use OCSP_TRUSTOTHER so the signer * certificate can be considered verified if it is in cert_chain. */ if (OCSP_basic_verify (basic, cert_chain, store, OCSP_TRUSTOTHER) != OCSP_VERIFY_SUCCESS) { SOFT_FAIL ("OCSP response failed verification: %s", ERR_STR); ret = OCSP_CB_ERROR; GOTO (done); } /* searches the basic response for an OCSP response for the given cert ID */ if (!OCSP_resp_find_status (basic, id, &cert_status, &reason, &produced_at, &this_update, &next_update)) { SOFT_FAIL ("No OCSP response found for the peer certificate"); ret = OCSP_CB_ERROR; GOTO (done); } /* checks the validity of this_update and next_update values */ if (!OCSP_check_validity (this_update, next_update, 0L, -1L)) { SOFT_FAIL ("OCSP response has expired: %s", ERR_STR); ret = OCSP_CB_ERROR; GOTO (done); } validate: switch (cert_status) { case V_OCSP_CERTSTATUS_GOOD: TRACE ("%s", "OCSP Certificate Status: Good"); _mongoc_ocsp_cache_set_resp (id, cert_status, reason, this_update, next_update); break; case V_OCSP_CERTSTATUS_REVOKED: MONGOC_ERROR ("OCSP Certificate Status: Revoked. Reason: %s", OCSP_crl_reason_str (reason)); ret = OCSP_CB_REVOKED; _mongoc_ocsp_cache_set_resp (id, cert_status, reason, this_update, next_update); GOTO (done); default: MONGOC_DEBUG ("OCSP Certificate Status: Unknown"); break; } /* Validate hostname matches cert */ if (!_mongoc_openssl_check_peer_hostname (ssl, opts->host, opts->allow_invalid_hostname)) { ret = OCSP_CB_REVOKED; GOTO (done); } ret = OCSP_CB_SUCCESS; done: if (ret == OCSP_CB_ERROR && !stapled_response) { ret = OCSP_CB_SUCCESS; } if (basic) OCSP_BASICRESP_free (basic); if (resp) OCSP_RESPONSE_free (resp); if (id) OCSP_CERTID_free (id); if (peer) X509_free (peer); if (cert_chain) _free_verified_chain (cert_chain); RETURN (ret); } #endif /* MONGOC_ENABLE_OCSP_OPENSSL */ /** * _mongoc_openssl_ctx_new: * * Create a new ssl context declaratively * * The opt.pem_pwd parameter, if passed, must exist for the life of this * context object (for storing and loading the associated pem file) */ SSL_CTX * _mongoc_openssl_ctx_new (mongoc_ssl_opt_t *opt) { SSL_CTX *ctx = NULL; int ssl_ctx_options = 0; /* * Ensure we are initialized. This is safe to call multiple times. */ mongoc_init (); ctx = SSL_CTX_new (SSLv23_method ()); BSON_ASSERT (ctx); /* SSL_OP_ALL - Activate all bug workaround options, to support buggy client * SSL's. */ ssl_ctx_options |= SSL_OP_ALL; /* SSL_OP_NO_SSLv2 - Disable SSL v2 support */ ssl_ctx_options |= SSL_OP_NO_SSLv2; /* Disable compression, if we can. * OpenSSL 0.9.x added compression support which was always enabled when built * against zlib * OpenSSL 1.0.0 added the ability to disable it, while keeping it enabled by * default * OpenSSL 1.1.0 disabled it by default. */ #if OPENSSL_VERSION_NUMBER >= 0x10000000L ssl_ctx_options |= SSL_OP_NO_COMPRESSION; #endif /* man SSL_get_options says: "SSL_OP_NO_RENEGOTIATION options were added in * OpenSSL 1.1.1". */ #ifdef SSL_OP_NO_RENEGOTIATION ssl_ctx_options |= SSL_OP_NO_RENEGOTIATION; #endif SSL_CTX_set_options (ctx, ssl_ctx_options); /* only defined in special build, using: * --enable-system-crypto-profile (autotools) * -DENABLE_CRYPTO_SYSTEM_PROFILE:BOOL=ON (cmake) */ #ifndef MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE /* HIGH - Enable strong ciphers * !EXPORT - Disable export ciphers (40/56 bit) * !aNULL - Disable anonymous auth ciphers * @STRENGTH - Sort ciphers based on strength */ SSL_CTX_set_cipher_list (ctx, "HIGH:!EXPORT:!aNULL@STRENGTH"); #endif /* If renegotiation is needed, don't return from recv() or send() until it's * successful. * Note: this is for blocking sockets only. */ SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY); /* Load my private keys to present to the server */ if (opt->pem_file && !_mongoc_openssl_setup_pem_file (ctx, opt->pem_file, opt->pem_pwd)) { SSL_CTX_free (ctx); return NULL; } /* Load in my Certificate Authority, to verify the server against * If none provided, fallback to the distro defaults */ if (opt->ca_file || opt->ca_dir) { if (!_mongoc_openssl_setup_ca (ctx, opt->ca_file, opt->ca_dir)) { SSL_CTX_free (ctx); return NULL; } } else { /* If the server certificate is issued by known CA we trust it by default */ #ifdef _WIN32 _mongoc_openssl_import_cert_stores (ctx); #else SSL_CTX_set_default_verify_paths (ctx); #endif } /* Load my revocation list, to verify the server against */ if (opt->crl_file && !_mongoc_openssl_setup_crl (ctx, opt->crl_file)) { SSL_CTX_free (ctx); return NULL; } if (opt->weak_cert_validation) { SSL_CTX_set_verify (ctx, SSL_VERIFY_NONE, NULL); } else { SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, NULL); } return ctx; } char * _mongoc_openssl_extract_subject (const char *filename, const char *passphrase) { X509_NAME *subject = NULL; X509 *cert = NULL; BIO *certbio = NULL; BIO *strbio = NULL; char *str = NULL; int ret; BSON_UNUSED (passphrase); if (!filename) { return NULL; } certbio = BIO_new (BIO_s_file ()); strbio = BIO_new (BIO_s_mem ()); BSON_ASSERT (certbio); BSON_ASSERT (strbio); if (BIO_read_filename (certbio, filename) && (cert = PEM_read_bio_X509 (certbio, NULL, 0, NULL))) { if ((subject = X509_get_subject_name (cert))) { ret = X509_NAME_print_ex (strbio, subject, 0, XN_FLAG_RFC2253); if ((ret > 0) && (ret < INT_MAX)) { str = (char *) bson_malloc (ret + 2); BIO_gets (strbio, str, ret + 1); str[ret] = '\0'; } } } if (cert) { X509_free (cert); } if (certbio) { BIO_free (certbio); } if (strbio) { BIO_free (strbio); } return str; } #if OPENSSL_VERSION_NUMBER < 0x10100000L #ifdef _WIN32 static unsigned long _mongoc_openssl_thread_id_callback (void) { unsigned long ret; ret = (unsigned long) GetCurrentThreadId (); return ret; } #else static unsigned long _mongoc_openssl_thread_id_callback (void) { unsigned long ret; ret = (unsigned long) pthread_self (); return ret; } #endif static void _mongoc_openssl_thread_locking_callback (int mode, int type, const char *file, int line) { if (mode & CRYPTO_LOCK) { bson_mutex_lock (&gMongocOpenSslThreadLocks[type]); } else { bson_mutex_unlock (&gMongocOpenSslThreadLocks[type]); } } static void _mongoc_openssl_thread_startup (void) { int i; gMongocOpenSslThreadLocks = (bson_mutex_t *) OPENSSL_malloc (CRYPTO_num_locks () * sizeof (bson_mutex_t)); for (i = 0; i < CRYPTO_num_locks (); i++) { bson_mutex_init (&gMongocOpenSslThreadLocks[i]); } if (!CRYPTO_get_locking_callback ()) { CRYPTO_set_locking_callback (_mongoc_openssl_thread_locking_callback); CRYPTO_set_id_callback (_mongoc_openssl_thread_id_callback); } } static void _mongoc_openssl_thread_cleanup (void) { int i; if (CRYPTO_get_locking_callback () == _mongoc_openssl_thread_locking_callback) { CRYPTO_set_locking_callback (NULL); } if (CRYPTO_get_id_callback () == _mongoc_openssl_thread_id_callback) { CRYPTO_set_id_callback (NULL); } for (i = 0; i < CRYPTO_num_locks (); i++) { bson_mutex_destroy (&gMongocOpenSslThreadLocks[i]); } OPENSSL_free (gMongocOpenSslThreadLocks); } #endif #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-optional.c0000644000175100001660000000234414760300420022762 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include void mongoc_optional_init (mongoc_optional_t *opt) { opt->is_set = false; opt->value = false; } bool mongoc_optional_is_set (const mongoc_optional_t *opt) { BSON_ASSERT (opt); return opt->is_set; } bool mongoc_optional_value (const mongoc_optional_t *opt) { BSON_ASSERT (opt); return opt->value; } void mongoc_optional_set_value (mongoc_optional_t *opt, bool val) { BSON_ASSERT (opt); opt->value = val; opt->is_set = true; } void mongoc_optional_copy (const mongoc_optional_t *source, mongoc_optional_t *copy) { copy->value = source->value; copy->is_set = source->is_set; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-optional.h0000644000175100001660000000242014760300420022762 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_OPTIONAL_H #define MONGOC_OPTIONAL_H #include #include BSON_BEGIN_DECLS typedef struct { bool value; bool is_set; } mongoc_optional_t; MONGOC_EXPORT (void) mongoc_optional_init (mongoc_optional_t *opt); MONGOC_EXPORT (bool) mongoc_optional_is_set (const mongoc_optional_t *opt); MONGOC_EXPORT (bool) mongoc_optional_value (const mongoc_optional_t *opt); MONGOC_EXPORT (void) mongoc_optional_set_value (mongoc_optional_t *opt, bool val); MONGOC_EXPORT (void) mongoc_optional_copy (const mongoc_optional_t *source, mongoc_optional_t *copy); BSON_END_DECLS #endif /* MONGOC_OPTIONAL_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-opts-helpers-private.h0000644000175100001660000000762414760300420025245 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #ifndef LIBMONGOC_MONGOC_OPTS_HELPERS_H #define LIBMONGOC_MONGOC_OPTS_HELPERS_H #define _mongoc_convert_session_id _mongoc_client_session_from_iter typedef struct _mongoc_timestamp_t { uint32_t timestamp; uint32_t increment; } mongoc_timestamp_t; bool _mongoc_timestamp_empty (mongoc_timestamp_t *timestamp); void _mongoc_timestamp_set (mongoc_timestamp_t *dst, mongoc_timestamp_t *src); void _mongoc_timestamp_set_from_bson (mongoc_timestamp_t *timestamp, bson_iter_t *iter); void _mongoc_timestamp_append (mongoc_timestamp_t *timestamp, bson_t *bson, char *key); void _mongoc_timestamp_clear (mongoc_timestamp_t *timestamp); bool _mongoc_convert_document (mongoc_client_t *client, const bson_iter_t *iter, bson_t *doc, bson_error_t *error); bool _mongoc_convert_array (mongoc_client_t *client, const bson_iter_t *iter, bson_t *doc, bson_error_t *error); bool _mongoc_convert_int64_positive (mongoc_client_t *client, const bson_iter_t *iter, int64_t *num, bson_error_t *error); bool _mongoc_convert_int32_t (mongoc_client_t *client, const bson_iter_t *iter, int32_t *num, bson_error_t *error); bool _mongoc_convert_int32_positive (mongoc_client_t *client, const bson_iter_t *iter, int32_t *num, bson_error_t *error); bool _mongoc_convert_bool (mongoc_client_t *client, const bson_iter_t *iter, bool *flag, bson_error_t *error); bool _mongoc_convert_bson_value_t (mongoc_client_t *client, const bson_iter_t *iter, bson_value_t *value, bson_error_t *error); bool _mongoc_convert_timestamp (mongoc_client_t *client, const bson_iter_t *iter, mongoc_timestamp_t *timestamp, bson_error_t *error); bool _mongoc_convert_utf8 (mongoc_client_t *client, const bson_iter_t *iter, const char **comment, bson_error_t *error); bool _mongoc_convert_validate_flags (mongoc_client_t *client, const bson_iter_t *iter, bson_validate_flags_t *flags, bson_error_t *error); bool _mongoc_convert_mongoc_write_bypass_document_validation_t (mongoc_client_t *client, const bson_iter_t *iter, bool *bdv, bson_error_t *error); bool _mongoc_convert_write_concern (mongoc_client_t *client, const bson_iter_t *iter, mongoc_write_concern_t **wc, bson_error_t *error); bool _mongoc_convert_server_id (mongoc_client_t *client, const bson_iter_t *iter, uint32_t *server_id, bson_error_t *error); bool _mongoc_convert_read_concern (mongoc_client_t *client, const bson_iter_t *iter, mongoc_read_concern_t **rc, bson_error_t *error); bool _mongoc_convert_hint (mongoc_client_t *client, const bson_iter_t *iter, bson_value_t *value, bson_error_t *error); #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-opts-helpers.c0000644000175100001660000002412514760300420023563 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #define BSON_ERR(...) \ do { \ bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, __VA_ARGS__); \ return false; \ } while (0) #define CONVERSION_ERR(...) \ do { \ bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, __VA_ARGS__); \ return false; \ } while (0) bool _mongoc_timestamp_empty (mongoc_timestamp_t *timestamp) { return (timestamp->timestamp == 0 && timestamp->increment == 0); } void _mongoc_timestamp_set (mongoc_timestamp_t *dst, mongoc_timestamp_t *src) { dst->timestamp = src->timestamp; dst->increment = src->increment; } void _mongoc_timestamp_set_from_bson (mongoc_timestamp_t *timestamp, bson_iter_t *iter) { bson_iter_timestamp (iter, &(timestamp->timestamp), &(timestamp->increment)); } void _mongoc_timestamp_append (mongoc_timestamp_t *timestamp, bson_t *bson, char *key) { const size_t len = strlen (key); BSON_ASSERT (mcommon_in_range_unsigned (int, len)); bson_append_timestamp (bson, key, (int) len, timestamp->timestamp, timestamp->increment); } void _mongoc_timestamp_clear (mongoc_timestamp_t *timestamp) { timestamp->timestamp = 0; timestamp->increment = 0; } bool _mongoc_convert_document (mongoc_client_t *client, const bson_iter_t *iter, bson_t *doc, bson_error_t *error) { uint32_t len; const uint8_t *data; bson_t value; BSON_UNUSED (client); if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { CONVERSION_ERR ("Invalid field \"%s\" in opts, should contain document," " not %s", bson_iter_key (iter), _mongoc_bson_type_to_str (bson_iter_type (iter))); } bson_iter_document (iter, &len, &data); if (!bson_init_static (&value, data, len)) { BSON_ERR ("Corrupt BSON in field \"%s\" in opts", bson_iter_key (iter)); } bson_destroy (doc); bson_copy_to (&value, doc); return true; } bool _mongoc_convert_array (mongoc_client_t *client, const bson_iter_t *iter, bson_t *doc, bson_error_t *error) { uint32_t len; const uint8_t *data; bson_t value; BSON_UNUSED (client); if (!BSON_ITER_HOLDS_ARRAY (iter)) { CONVERSION_ERR ("Invalid field \"%s\" in opts, should contain array," " not %s", bson_iter_key (iter), _mongoc_bson_type_to_str (bson_iter_type (iter))); } bson_iter_array (iter, &len, &data); if (!bson_init_static (&value, data, len)) { BSON_ERR ("Corrupt BSON in field \"%s\" in opts", bson_iter_key (iter)); } bson_destroy (doc); bson_copy_to (&value, doc); return true; } bool _mongoc_convert_int64_positive (mongoc_client_t *client, const bson_iter_t *iter, int64_t *num, bson_error_t *error) { int64_t i; BSON_UNUSED (client); if (!BSON_ITER_HOLDS_NUMBER (iter)) { CONVERSION_ERR ("Invalid field \"%s\" in opts, should contain number," " not %s", bson_iter_key (iter), _mongoc_bson_type_to_str (bson_iter_type (iter))); } i = bson_iter_as_int64 (iter); if (i <= 0) { CONVERSION_ERR ("Invalid field \"%s\" in opts, should be greater than 0," " not %" PRId64, bson_iter_key (iter), i); } *num = bson_iter_as_int64 (iter); return true; } bool _mongoc_convert_int32_t (mongoc_client_t *client, const bson_iter_t *iter, int32_t *num, bson_error_t *error) { int64_t i; BSON_UNUSED (client); if (!BSON_ITER_HOLDS_NUMBER (iter)) { CONVERSION_ERR ("Invalid field \"%s\" in opts", bson_iter_key (iter)); } i = bson_iter_as_int64 (iter); if (i > INT32_MAX || i < INT32_MIN) { CONVERSION_ERR ("Invalid field \"%s\" in opts: %" PRId64 " out of range for int32", bson_iter_key (iter), i); } *num = (int32_t) i; return true; } bool _mongoc_convert_int32_positive (mongoc_client_t *client, const bson_iter_t *iter, int32_t *num, bson_error_t *error) { int32_t i; if (!_mongoc_convert_int32_t (client, iter, &i, error)) { return false; } if (i <= 0) { CONVERSION_ERR ("Invalid field \"%s\" in opts, should be greater than 0, not %d", bson_iter_key (iter), i); } *num = i; return true; } bool _mongoc_convert_bool (mongoc_client_t *client, const bson_iter_t *iter, bool *flag, bson_error_t *error) { BSON_UNUSED (client); if (BSON_ITER_HOLDS_BOOL (iter)) { *flag = bson_iter_bool (iter); return true; } CONVERSION_ERR ("Invalid field \"%s\" in opts, should contain bool," " not %s", bson_iter_key (iter), _mongoc_bson_type_to_str (bson_iter_type (iter))); } bool _mongoc_convert_bson_value_t (mongoc_client_t *client, const bson_iter_t *iter, bson_value_t *value, bson_error_t *error) { BSON_UNUSED (client); BSON_UNUSED (error); bson_value_copy (bson_iter_value ((bson_iter_t *) iter), value); return true; } bool _mongoc_convert_timestamp (mongoc_client_t *client, const bson_iter_t *iter, mongoc_timestamp_t *timestamp, bson_error_t *error) { BSON_UNUSED (client); BSON_UNUSED (error); bson_iter_timestamp (iter, ×tamp->timestamp, ×tamp->increment); return true; } bool _mongoc_convert_utf8 (mongoc_client_t *client, const bson_iter_t *iter, const char **str, bson_error_t *error) { BSON_UNUSED (client); if (BSON_ITER_HOLDS_UTF8 (iter)) { *str = bson_iter_utf8 (iter, NULL); return true; } CONVERSION_ERR ("Invalid field \"%s\" in opts, should contain string," " not %s", bson_iter_key (iter), _mongoc_bson_type_to_str (bson_iter_type (iter))); } bool _mongoc_convert_validate_flags (mongoc_client_t *client, const bson_iter_t *iter, bson_validate_flags_t *flags, bson_error_t *error) { BSON_UNUSED (client); if (BSON_ITER_HOLDS_BOOL (iter)) { if (!bson_iter_as_bool (iter)) { *flags = BSON_VALIDATE_NONE; return true; } else { /* validate: false is ok but validate: true is prohibited */ CONVERSION_ERR ("Invalid option \"%s\": true, must be a bitwise-OR of" " bson_validate_flags_t values.", bson_iter_key (iter)); } } else if (BSON_ITER_HOLDS_INT32 (iter)) { if (bson_iter_int32 (iter) <= 0x1F) { *flags = (bson_validate_flags_t) bson_iter_int32 (iter); return true; } else { CONVERSION_ERR ("Invalid field \"%s\" in opts, must be a bitwise-OR of" " bson_validate_flags_t values.", bson_iter_key (iter)); } } CONVERSION_ERR ("Invalid type for option \"%s\": \"%s\"." " \"%s\" must be a boolean or a bitwise-OR of" " bson_validate_flags_t values.", bson_iter_key (iter), _mongoc_bson_type_to_str (bson_iter_type (iter)), bson_iter_key (iter)); } bool _mongoc_convert_write_concern (mongoc_client_t *client, const bson_iter_t *iter, mongoc_write_concern_t **wc, bson_error_t *error) { mongoc_write_concern_t *tmp; BSON_UNUSED (client); tmp = _mongoc_write_concern_new_from_iter (iter, error); if (tmp) { *wc = tmp; return true; } return false; } bool _mongoc_convert_server_id (mongoc_client_t *client, const bson_iter_t *iter, uint32_t *server_id, bson_error_t *error) { int64_t tmp; BSON_UNUSED (client); if (!BSON_ITER_HOLDS_INT (iter)) { CONVERSION_ERR ("The serverId option must be an integer"); } tmp = bson_iter_as_int64 (iter); if (tmp <= 0) { CONVERSION_ERR ("The serverId option must be >= 1"); } *server_id = (uint32_t) tmp; return true; } bool _mongoc_convert_read_concern (mongoc_client_t *client, const bson_iter_t *iter, mongoc_read_concern_t **rc, bson_error_t *error) { BSON_UNUSED (client); *rc = _mongoc_read_concern_new_from_iter (iter, error); if (!*rc) { return false; } return true; } bool _mongoc_convert_hint (mongoc_client_t *client, const bson_iter_t *iter, bson_value_t *value, bson_error_t *error) { BSON_UNUSED (client); if (BSON_ITER_HOLDS_UTF8 (iter) || BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_value_copy (bson_iter_value ((bson_iter_t *) iter), value); return true; } CONVERSION_ERR ("The hint option must be a string or document"); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-opts-private.h0000644000175100001660000003010114760300420023567 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_OPTS_H #define MONGOC_OPTS_H #include #include #include #include /************************************************** * * Generated by build/generate-opts.py. * * DO NOT EDIT THIS FILE. * *************************************************/ /* clang-format off */ typedef struct _mongoc_crud_opts_t { mongoc_write_concern_t *writeConcern; bool write_concern_owned; mongoc_client_session_t *client_session; bson_validate_flags_t validate; bson_value_t comment; } mongoc_crud_opts_t; typedef struct _mongoc_update_opts_t { mongoc_crud_opts_t crud; bool bypass; bson_t collation; bson_value_t hint; bool upsert; bson_t let; } mongoc_update_opts_t; typedef struct _mongoc_insert_one_opts_t { mongoc_crud_opts_t crud; bool bypass; bson_t extra; } mongoc_insert_one_opts_t; typedef struct _mongoc_insert_many_opts_t { mongoc_crud_opts_t crud; bool ordered; bool bypass; bson_t extra; } mongoc_insert_many_opts_t; typedef struct _mongoc_delete_opts_t { mongoc_crud_opts_t crud; bson_t collation; bson_value_t hint; bson_t let; } mongoc_delete_opts_t; typedef struct _mongoc_delete_one_opts_t { mongoc_delete_opts_t delete; bson_t extra; } mongoc_delete_one_opts_t; typedef struct _mongoc_delete_many_opts_t { mongoc_delete_opts_t delete; bson_t extra; } mongoc_delete_many_opts_t; typedef struct _mongoc_update_one_opts_t { mongoc_update_opts_t update; bson_t arrayFilters; bson_t sort; bson_t extra; } mongoc_update_one_opts_t; typedef struct _mongoc_update_many_opts_t { mongoc_update_opts_t update; bson_t arrayFilters; bson_t extra; } mongoc_update_many_opts_t; typedef struct _mongoc_replace_one_opts_t { mongoc_update_opts_t update; bson_t sort; bson_t extra; } mongoc_replace_one_opts_t; typedef struct _mongoc_bulk_opts_t { mongoc_write_concern_t *writeConcern; bool write_concern_owned; bool ordered; mongoc_client_session_t *client_session; bson_t let; bson_value_t comment; bson_t extra; } mongoc_bulk_opts_t; typedef struct _mongoc_bulk_insert_opts_t { bson_validate_flags_t validate; bson_t extra; } mongoc_bulk_insert_opts_t; typedef struct _mongoc_bulk_update_opts_t { bson_validate_flags_t validate; bson_t collation; bson_value_t hint; bool upsert; bool multi; } mongoc_bulk_update_opts_t; typedef struct _mongoc_bulk_update_one_opts_t { mongoc_bulk_update_opts_t update; bson_t sort; bson_t arrayFilters; bson_t extra; } mongoc_bulk_update_one_opts_t; typedef struct _mongoc_bulk_update_many_opts_t { mongoc_bulk_update_opts_t update; bson_t arrayFilters; bson_t extra; } mongoc_bulk_update_many_opts_t; typedef struct _mongoc_bulk_replace_one_opts_t { mongoc_bulk_update_opts_t update; bson_t sort; bson_t extra; } mongoc_bulk_replace_one_opts_t; typedef struct _mongoc_bulk_remove_opts_t { bson_t collation; bson_value_t hint; int32_t limit; } mongoc_bulk_remove_opts_t; typedef struct _mongoc_bulk_remove_one_opts_t { mongoc_bulk_remove_opts_t remove; bson_t extra; } mongoc_bulk_remove_one_opts_t; typedef struct _mongoc_bulk_remove_many_opts_t { mongoc_bulk_remove_opts_t remove; bson_t extra; } mongoc_bulk_remove_many_opts_t; typedef struct _mongoc_change_stream_opts_t { int32_t batchSize; bson_t resumeAfter; bson_t startAfter; mongoc_timestamp_t startAtOperationTime; int64_t maxAwaitTimeMS; const char *fullDocument; const char *fullDocumentBeforeChange; bool showExpandedEvents; bson_value_t comment; bson_t extra; } mongoc_change_stream_opts_t; typedef struct _mongoc_create_index_opts_t { mongoc_write_concern_t *writeConcern; bool write_concern_owned; mongoc_client_session_t *client_session; bson_t extra; } mongoc_create_index_opts_t; typedef struct _mongoc_read_write_opts_t { bson_t readConcern; mongoc_write_concern_t *writeConcern; bool write_concern_owned; mongoc_client_session_t *client_session; bson_t collation; uint32_t serverId; bson_t extra; } mongoc_read_write_opts_t; typedef struct _mongoc_gridfs_bucket_opts_t { const char *bucketName; int32_t chunkSizeBytes; mongoc_write_concern_t *writeConcern; bool write_concern_owned; mongoc_read_concern_t *readConcern; bson_t extra; } mongoc_gridfs_bucket_opts_t; typedef struct _mongoc_gridfs_bucket_upload_opts_t { int32_t chunkSizeBytes; bson_t metadata; bson_t extra; } mongoc_gridfs_bucket_upload_opts_t; typedef struct _mongoc_aggregate_opts_t { mongoc_read_concern_t *readConcern; mongoc_write_concern_t *writeConcern; bool write_concern_owned; mongoc_client_session_t *client_session; bool bypass; bson_t collation; uint32_t serverId; int32_t batchSize; bool batchSize_is_set; bson_t let; bson_value_t comment; bson_value_t hint; bson_t extra; } mongoc_aggregate_opts_t; typedef struct _mongoc_find_and_modify_appended_opts_t { mongoc_write_concern_t *writeConcern; bool write_concern_owned; mongoc_client_session_t *client_session; bson_value_t hint; bson_t let; bson_value_t comment; bson_t extra; } mongoc_find_and_modify_appended_opts_t; typedef struct _mongoc_count_document_opts_t { bson_t readConcern; mongoc_client_session_t *client_session; bson_t collation; uint32_t serverId; bson_value_t skip; bson_value_t limit; bson_value_t comment; bson_value_t hint; bson_t extra; } mongoc_count_document_opts_t; bool _mongoc_insert_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_insert_one_opts_t *mongoc_insert_one_opts, bson_error_t *error); void _mongoc_insert_one_opts_cleanup (mongoc_insert_one_opts_t *mongoc_insert_one_opts); bool _mongoc_insert_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_insert_many_opts_t *mongoc_insert_many_opts, bson_error_t *error); void _mongoc_insert_many_opts_cleanup (mongoc_insert_many_opts_t *mongoc_insert_many_opts); bool _mongoc_delete_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_delete_one_opts_t *mongoc_delete_one_opts, bson_error_t *error); void _mongoc_delete_one_opts_cleanup (mongoc_delete_one_opts_t *mongoc_delete_one_opts); bool _mongoc_delete_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_delete_many_opts_t *mongoc_delete_many_opts, bson_error_t *error); void _mongoc_delete_many_opts_cleanup (mongoc_delete_many_opts_t *mongoc_delete_many_opts); bool _mongoc_update_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_update_one_opts_t *mongoc_update_one_opts, bson_error_t *error); void _mongoc_update_one_opts_cleanup (mongoc_update_one_opts_t *mongoc_update_one_opts); bool _mongoc_update_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_update_many_opts_t *mongoc_update_many_opts, bson_error_t *error); void _mongoc_update_many_opts_cleanup (mongoc_update_many_opts_t *mongoc_update_many_opts); bool _mongoc_replace_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_replace_one_opts_t *mongoc_replace_one_opts, bson_error_t *error); void _mongoc_replace_one_opts_cleanup (mongoc_replace_one_opts_t *mongoc_replace_one_opts); bool _mongoc_bulk_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_opts_t *mongoc_bulk_opts, bson_error_t *error); void _mongoc_bulk_opts_cleanup (mongoc_bulk_opts_t *mongoc_bulk_opts); bool _mongoc_bulk_insert_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_insert_opts_t *mongoc_bulk_insert_opts, bson_error_t *error); void _mongoc_bulk_insert_opts_cleanup (mongoc_bulk_insert_opts_t *mongoc_bulk_insert_opts); bool _mongoc_bulk_update_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_update_one_opts_t *mongoc_bulk_update_one_opts, bson_error_t *error); void _mongoc_bulk_update_one_opts_cleanup (mongoc_bulk_update_one_opts_t *mongoc_bulk_update_one_opts); bool _mongoc_bulk_update_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_update_many_opts_t *mongoc_bulk_update_many_opts, bson_error_t *error); void _mongoc_bulk_update_many_opts_cleanup (mongoc_bulk_update_many_opts_t *mongoc_bulk_update_many_opts); bool _mongoc_bulk_replace_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_replace_one_opts_t *mongoc_bulk_replace_one_opts, bson_error_t *error); void _mongoc_bulk_replace_one_opts_cleanup (mongoc_bulk_replace_one_opts_t *mongoc_bulk_replace_one_opts); bool _mongoc_bulk_remove_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_remove_one_opts_t *mongoc_bulk_remove_one_opts, bson_error_t *error); void _mongoc_bulk_remove_one_opts_cleanup (mongoc_bulk_remove_one_opts_t *mongoc_bulk_remove_one_opts); bool _mongoc_bulk_remove_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_remove_many_opts_t *mongoc_bulk_remove_many_opts, bson_error_t *error); void _mongoc_bulk_remove_many_opts_cleanup (mongoc_bulk_remove_many_opts_t *mongoc_bulk_remove_many_opts); bool _mongoc_change_stream_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_change_stream_opts_t *mongoc_change_stream_opts, bson_error_t *error); void _mongoc_change_stream_opts_cleanup (mongoc_change_stream_opts_t *mongoc_change_stream_opts); bool _mongoc_create_index_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_create_index_opts_t *mongoc_create_index_opts, bson_error_t *error); void _mongoc_create_index_opts_cleanup (mongoc_create_index_opts_t *mongoc_create_index_opts); bool _mongoc_read_write_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_read_write_opts_t *mongoc_read_write_opts, bson_error_t *error); void _mongoc_read_write_opts_cleanup (mongoc_read_write_opts_t *mongoc_read_write_opts); bool _mongoc_gridfs_bucket_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_gridfs_bucket_opts_t *mongoc_gridfs_bucket_opts, bson_error_t *error); void _mongoc_gridfs_bucket_opts_cleanup (mongoc_gridfs_bucket_opts_t *mongoc_gridfs_bucket_opts); bool _mongoc_gridfs_bucket_upload_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_gridfs_bucket_upload_opts_t *mongoc_gridfs_bucket_upload_opts, bson_error_t *error); void _mongoc_gridfs_bucket_upload_opts_cleanup (mongoc_gridfs_bucket_upload_opts_t *mongoc_gridfs_bucket_upload_opts); bool _mongoc_aggregate_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_aggregate_opts_t *mongoc_aggregate_opts, bson_error_t *error); void _mongoc_aggregate_opts_cleanup (mongoc_aggregate_opts_t *mongoc_aggregate_opts); bool _mongoc_find_and_modify_appended_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_find_and_modify_appended_opts_t *mongoc_find_and_modify_appended_opts, bson_error_t *error); void _mongoc_find_and_modify_appended_opts_cleanup (mongoc_find_and_modify_appended_opts_t *mongoc_find_and_modify_appended_opts); bool _mongoc_count_document_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_count_document_opts_t *mongoc_count_document_opts, bson_error_t *error); void _mongoc_count_document_opts_cleanup (mongoc_count_document_opts_t *mongoc_count_document_opts); #endif /* MONGOC_OPTS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-opts.c0000644000175100001660000023233714760300420022131 0ustar #include #include #include #include #include /************************************************** * * Generated by build/generate-opts.py. * * DO NOT EDIT THIS FILE. * *************************************************/ /* clang-format off */ bool _mongoc_insert_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_insert_one_opts_t *mongoc_insert_one_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_insert_one_opts->crud.writeConcern = NULL; mongoc_insert_one_opts->crud.write_concern_owned = false; mongoc_insert_one_opts->crud.client_session = NULL; mongoc_insert_one_opts->crud.validate = _mongoc_default_insert_vflags; memset (&mongoc_insert_one_opts->crud.comment, 0, sizeof (bson_value_t)); mongoc_insert_one_opts->bypass = false; bson_init (&mongoc_insert_one_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_insert_one_opts->crud.writeConcern, error)) { return false; } mongoc_insert_one_opts->crud.write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_insert_one_opts->crud.client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_insert_one_opts->crud.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_insert_one_opts->crud.comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_insert_one_opts->bypass, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_insert_one_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_insert_one_opts_cleanup (mongoc_insert_one_opts_t *mongoc_insert_one_opts) { if (mongoc_insert_one_opts->crud.write_concern_owned) { mongoc_write_concern_destroy (mongoc_insert_one_opts->crud.writeConcern); } bson_value_destroy (&mongoc_insert_one_opts->crud.comment); bson_destroy (&mongoc_insert_one_opts->extra); } bool _mongoc_insert_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_insert_many_opts_t *mongoc_insert_many_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_insert_many_opts->crud.writeConcern = NULL; mongoc_insert_many_opts->crud.write_concern_owned = false; mongoc_insert_many_opts->crud.client_session = NULL; mongoc_insert_many_opts->crud.validate = _mongoc_default_insert_vflags; memset (&mongoc_insert_many_opts->crud.comment, 0, sizeof (bson_value_t)); mongoc_insert_many_opts->ordered = true; mongoc_insert_many_opts->bypass = false; bson_init (&mongoc_insert_many_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_insert_many_opts->crud.writeConcern, error)) { return false; } mongoc_insert_many_opts->crud.write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_insert_many_opts->crud.client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_insert_many_opts->crud.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_insert_many_opts->crud.comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "ordered")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_insert_many_opts->ordered, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_insert_many_opts->bypass, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_insert_many_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_insert_many_opts_cleanup (mongoc_insert_many_opts_t *mongoc_insert_many_opts) { if (mongoc_insert_many_opts->crud.write_concern_owned) { mongoc_write_concern_destroy (mongoc_insert_many_opts->crud.writeConcern); } bson_value_destroy (&mongoc_insert_many_opts->crud.comment); bson_destroy (&mongoc_insert_many_opts->extra); } bool _mongoc_delete_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_delete_one_opts_t *mongoc_delete_one_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_delete_one_opts->delete.crud.writeConcern = NULL; mongoc_delete_one_opts->delete.crud.write_concern_owned = false; mongoc_delete_one_opts->delete.crud.client_session = NULL; mongoc_delete_one_opts->delete.crud.validate = BSON_VALIDATE_NONE; memset (&mongoc_delete_one_opts->delete.crud.comment, 0, sizeof (bson_value_t)); bson_init (&mongoc_delete_one_opts->delete.collation); memset (&mongoc_delete_one_opts->delete.hint, 0, sizeof (bson_value_t)); bson_init (&mongoc_delete_one_opts->delete.let); bson_init (&mongoc_delete_one_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_delete_one_opts->delete.crud.writeConcern, error)) { return false; } mongoc_delete_one_opts->delete.crud.write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_delete_one_opts->delete.crud.client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_delete_one_opts->delete.crud.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_delete_one_opts->delete.crud.comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_delete_one_opts->delete.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_delete_one_opts->delete.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "let")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_delete_one_opts->delete.let, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_delete_one_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_delete_one_opts_cleanup (mongoc_delete_one_opts_t *mongoc_delete_one_opts) { if (mongoc_delete_one_opts->delete.crud.write_concern_owned) { mongoc_write_concern_destroy (mongoc_delete_one_opts->delete.crud.writeConcern); } bson_value_destroy (&mongoc_delete_one_opts->delete.crud.comment); bson_destroy (&mongoc_delete_one_opts->delete.collation); bson_value_destroy (&mongoc_delete_one_opts->delete.hint); bson_destroy (&mongoc_delete_one_opts->delete.let); bson_destroy (&mongoc_delete_one_opts->extra); } bool _mongoc_delete_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_delete_many_opts_t *mongoc_delete_many_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_delete_many_opts->delete.crud.writeConcern = NULL; mongoc_delete_many_opts->delete.crud.write_concern_owned = false; mongoc_delete_many_opts->delete.crud.client_session = NULL; mongoc_delete_many_opts->delete.crud.validate = BSON_VALIDATE_NONE; memset (&mongoc_delete_many_opts->delete.crud.comment, 0, sizeof (bson_value_t)); bson_init (&mongoc_delete_many_opts->delete.collation); memset (&mongoc_delete_many_opts->delete.hint, 0, sizeof (bson_value_t)); bson_init (&mongoc_delete_many_opts->delete.let); bson_init (&mongoc_delete_many_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_delete_many_opts->delete.crud.writeConcern, error)) { return false; } mongoc_delete_many_opts->delete.crud.write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_delete_many_opts->delete.crud.client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_delete_many_opts->delete.crud.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_delete_many_opts->delete.crud.comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_delete_many_opts->delete.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_delete_many_opts->delete.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "let")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_delete_many_opts->delete.let, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_delete_many_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_delete_many_opts_cleanup (mongoc_delete_many_opts_t *mongoc_delete_many_opts) { if (mongoc_delete_many_opts->delete.crud.write_concern_owned) { mongoc_write_concern_destroy (mongoc_delete_many_opts->delete.crud.writeConcern); } bson_value_destroy (&mongoc_delete_many_opts->delete.crud.comment); bson_destroy (&mongoc_delete_many_opts->delete.collation); bson_value_destroy (&mongoc_delete_many_opts->delete.hint); bson_destroy (&mongoc_delete_many_opts->delete.let); bson_destroy (&mongoc_delete_many_opts->extra); } bool _mongoc_update_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_update_one_opts_t *mongoc_update_one_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_update_one_opts->update.crud.writeConcern = NULL; mongoc_update_one_opts->update.crud.write_concern_owned = false; mongoc_update_one_opts->update.crud.client_session = NULL; mongoc_update_one_opts->update.crud.validate = _mongoc_default_update_vflags; memset (&mongoc_update_one_opts->update.crud.comment, 0, sizeof (bson_value_t)); mongoc_update_one_opts->update.bypass = false; bson_init (&mongoc_update_one_opts->update.collation); memset (&mongoc_update_one_opts->update.hint, 0, sizeof (bson_value_t)); mongoc_update_one_opts->update.upsert = false; bson_init (&mongoc_update_one_opts->update.let); bson_init (&mongoc_update_one_opts->arrayFilters); bson_init (&mongoc_update_one_opts->sort); bson_init (&mongoc_update_one_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_update_one_opts->update.crud.writeConcern, error)) { return false; } mongoc_update_one_opts->update.crud.write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_update_one_opts->update.crud.client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_update_one_opts->update.crud.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_update_one_opts->update.crud.comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_update_one_opts->update.bypass, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_update_one_opts->update.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_update_one_opts->update.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "upsert")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_update_one_opts->update.upsert, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "let")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_update_one_opts->update.let, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) { if (!_mongoc_convert_array ( client, &iter, &mongoc_update_one_opts->arrayFilters, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "sort")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_update_one_opts->sort, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_update_one_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_update_one_opts_cleanup (mongoc_update_one_opts_t *mongoc_update_one_opts) { if (mongoc_update_one_opts->update.crud.write_concern_owned) { mongoc_write_concern_destroy (mongoc_update_one_opts->update.crud.writeConcern); } bson_value_destroy (&mongoc_update_one_opts->update.crud.comment); bson_destroy (&mongoc_update_one_opts->update.collation); bson_value_destroy (&mongoc_update_one_opts->update.hint); bson_destroy (&mongoc_update_one_opts->update.let); bson_destroy (&mongoc_update_one_opts->arrayFilters); bson_destroy (&mongoc_update_one_opts->sort); bson_destroy (&mongoc_update_one_opts->extra); } bool _mongoc_update_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_update_many_opts_t *mongoc_update_many_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_update_many_opts->update.crud.writeConcern = NULL; mongoc_update_many_opts->update.crud.write_concern_owned = false; mongoc_update_many_opts->update.crud.client_session = NULL; mongoc_update_many_opts->update.crud.validate = _mongoc_default_update_vflags; memset (&mongoc_update_many_opts->update.crud.comment, 0, sizeof (bson_value_t)); mongoc_update_many_opts->update.bypass = false; bson_init (&mongoc_update_many_opts->update.collation); memset (&mongoc_update_many_opts->update.hint, 0, sizeof (bson_value_t)); mongoc_update_many_opts->update.upsert = false; bson_init (&mongoc_update_many_opts->update.let); bson_init (&mongoc_update_many_opts->arrayFilters); bson_init (&mongoc_update_many_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_update_many_opts->update.crud.writeConcern, error)) { return false; } mongoc_update_many_opts->update.crud.write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_update_many_opts->update.crud.client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_update_many_opts->update.crud.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_update_many_opts->update.crud.comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_update_many_opts->update.bypass, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_update_many_opts->update.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_update_many_opts->update.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "upsert")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_update_many_opts->update.upsert, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "let")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_update_many_opts->update.let, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) { if (!_mongoc_convert_array ( client, &iter, &mongoc_update_many_opts->arrayFilters, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_update_many_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_update_many_opts_cleanup (mongoc_update_many_opts_t *mongoc_update_many_opts) { if (mongoc_update_many_opts->update.crud.write_concern_owned) { mongoc_write_concern_destroy (mongoc_update_many_opts->update.crud.writeConcern); } bson_value_destroy (&mongoc_update_many_opts->update.crud.comment); bson_destroy (&mongoc_update_many_opts->update.collation); bson_value_destroy (&mongoc_update_many_opts->update.hint); bson_destroy (&mongoc_update_many_opts->update.let); bson_destroy (&mongoc_update_many_opts->arrayFilters); bson_destroy (&mongoc_update_many_opts->extra); } bool _mongoc_replace_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_replace_one_opts_t *mongoc_replace_one_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_replace_one_opts->update.crud.writeConcern = NULL; mongoc_replace_one_opts->update.crud.write_concern_owned = false; mongoc_replace_one_opts->update.crud.client_session = NULL; mongoc_replace_one_opts->update.crud.validate = _mongoc_default_replace_vflags; memset (&mongoc_replace_one_opts->update.crud.comment, 0, sizeof (bson_value_t)); mongoc_replace_one_opts->update.bypass = false; bson_init (&mongoc_replace_one_opts->update.collation); memset (&mongoc_replace_one_opts->update.hint, 0, sizeof (bson_value_t)); mongoc_replace_one_opts->update.upsert = false; bson_init (&mongoc_replace_one_opts->update.let); bson_init (&mongoc_replace_one_opts->sort); bson_init (&mongoc_replace_one_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_replace_one_opts->update.crud.writeConcern, error)) { return false; } mongoc_replace_one_opts->update.crud.write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_replace_one_opts->update.crud.client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_replace_one_opts->update.crud.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_replace_one_opts->update.crud.comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_replace_one_opts->update.bypass, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_replace_one_opts->update.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_replace_one_opts->update.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "upsert")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_replace_one_opts->update.upsert, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "let")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_replace_one_opts->update.let, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "sort")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_replace_one_opts->sort, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_replace_one_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_replace_one_opts_cleanup (mongoc_replace_one_opts_t *mongoc_replace_one_opts) { if (mongoc_replace_one_opts->update.crud.write_concern_owned) { mongoc_write_concern_destroy (mongoc_replace_one_opts->update.crud.writeConcern); } bson_value_destroy (&mongoc_replace_one_opts->update.crud.comment); bson_destroy (&mongoc_replace_one_opts->update.collation); bson_value_destroy (&mongoc_replace_one_opts->update.hint); bson_destroy (&mongoc_replace_one_opts->update.let); bson_destroy (&mongoc_replace_one_opts->sort); bson_destroy (&mongoc_replace_one_opts->extra); } bool _mongoc_bulk_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_opts_t *mongoc_bulk_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_bulk_opts->writeConcern = NULL; mongoc_bulk_opts->write_concern_owned = false; mongoc_bulk_opts->ordered = true; mongoc_bulk_opts->client_session = NULL; bson_init (&mongoc_bulk_opts->let); memset (&mongoc_bulk_opts->comment, 0, sizeof (bson_value_t)); bson_init (&mongoc_bulk_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_bulk_opts->writeConcern, error)) { return false; } mongoc_bulk_opts->write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "ordered")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_bulk_opts->ordered, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_bulk_opts->client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "let")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_bulk_opts->let, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_bulk_opts->comment, error)) { return false; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid option '%s'", bson_iter_key (&iter)); return false; } } return true; } void _mongoc_bulk_opts_cleanup (mongoc_bulk_opts_t *mongoc_bulk_opts) { if (mongoc_bulk_opts->write_concern_owned) { mongoc_write_concern_destroy (mongoc_bulk_opts->writeConcern); } bson_destroy (&mongoc_bulk_opts->let); bson_value_destroy (&mongoc_bulk_opts->comment); bson_destroy (&mongoc_bulk_opts->extra); } bool _mongoc_bulk_insert_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_insert_opts_t *mongoc_bulk_insert_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_bulk_insert_opts->validate = _mongoc_default_insert_vflags; bson_init (&mongoc_bulk_insert_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_bulk_insert_opts->validate, error)) { return false; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid option '%s'", bson_iter_key (&iter)); return false; } } return true; } void _mongoc_bulk_insert_opts_cleanup (mongoc_bulk_insert_opts_t *mongoc_bulk_insert_opts) { bson_destroy (&mongoc_bulk_insert_opts->extra); } bool _mongoc_bulk_update_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_update_one_opts_t *mongoc_bulk_update_one_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_bulk_update_one_opts->update.validate = _mongoc_default_update_vflags; bson_init (&mongoc_bulk_update_one_opts->update.collation); memset (&mongoc_bulk_update_one_opts->update.hint, 0, sizeof (bson_value_t)); mongoc_bulk_update_one_opts->update.upsert = false; mongoc_bulk_update_one_opts->update.multi = false; bson_init (&mongoc_bulk_update_one_opts->sort); bson_init (&mongoc_bulk_update_one_opts->arrayFilters); bson_init (&mongoc_bulk_update_one_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_bulk_update_one_opts->update.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_bulk_update_one_opts->update.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_bulk_update_one_opts->update.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "upsert")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_bulk_update_one_opts->update.upsert, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "multi")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_bulk_update_one_opts->update.multi, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "sort")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_bulk_update_one_opts->sort, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) { if (!_mongoc_convert_array ( client, &iter, &mongoc_bulk_update_one_opts->arrayFilters, error)) { return false; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid option '%s'", bson_iter_key (&iter)); return false; } } return true; } void _mongoc_bulk_update_one_opts_cleanup (mongoc_bulk_update_one_opts_t *mongoc_bulk_update_one_opts) { bson_destroy (&mongoc_bulk_update_one_opts->update.collation); bson_value_destroy (&mongoc_bulk_update_one_opts->update.hint); bson_destroy (&mongoc_bulk_update_one_opts->sort); bson_destroy (&mongoc_bulk_update_one_opts->arrayFilters); bson_destroy (&mongoc_bulk_update_one_opts->extra); } bool _mongoc_bulk_update_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_update_many_opts_t *mongoc_bulk_update_many_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_bulk_update_many_opts->update.validate = _mongoc_default_update_vflags; bson_init (&mongoc_bulk_update_many_opts->update.collation); memset (&mongoc_bulk_update_many_opts->update.hint, 0, sizeof (bson_value_t)); mongoc_bulk_update_many_opts->update.upsert = false; mongoc_bulk_update_many_opts->update.multi = true; bson_init (&mongoc_bulk_update_many_opts->arrayFilters); bson_init (&mongoc_bulk_update_many_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_bulk_update_many_opts->update.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_bulk_update_many_opts->update.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_bulk_update_many_opts->update.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "upsert")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_bulk_update_many_opts->update.upsert, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "multi")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_bulk_update_many_opts->update.multi, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "arrayFilters")) { if (!_mongoc_convert_array ( client, &iter, &mongoc_bulk_update_many_opts->arrayFilters, error)) { return false; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid option '%s'", bson_iter_key (&iter)); return false; } } return true; } void _mongoc_bulk_update_many_opts_cleanup (mongoc_bulk_update_many_opts_t *mongoc_bulk_update_many_opts) { bson_destroy (&mongoc_bulk_update_many_opts->update.collation); bson_value_destroy (&mongoc_bulk_update_many_opts->update.hint); bson_destroy (&mongoc_bulk_update_many_opts->arrayFilters); bson_destroy (&mongoc_bulk_update_many_opts->extra); } bool _mongoc_bulk_replace_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_replace_one_opts_t *mongoc_bulk_replace_one_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_bulk_replace_one_opts->update.validate = _mongoc_default_replace_vflags; bson_init (&mongoc_bulk_replace_one_opts->update.collation); memset (&mongoc_bulk_replace_one_opts->update.hint, 0, sizeof (bson_value_t)); mongoc_bulk_replace_one_opts->update.upsert = false; mongoc_bulk_replace_one_opts->update.multi = false; bson_init (&mongoc_bulk_replace_one_opts->sort); bson_init (&mongoc_bulk_replace_one_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "validate")) { if (!_mongoc_convert_validate_flags ( client, &iter, &mongoc_bulk_replace_one_opts->update.validate, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_bulk_replace_one_opts->update.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_bulk_replace_one_opts->update.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "upsert")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_bulk_replace_one_opts->update.upsert, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "multi")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_bulk_replace_one_opts->update.multi, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "sort")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_bulk_replace_one_opts->sort, error)) { return false; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid option '%s'", bson_iter_key (&iter)); return false; } } return true; } void _mongoc_bulk_replace_one_opts_cleanup (mongoc_bulk_replace_one_opts_t *mongoc_bulk_replace_one_opts) { bson_destroy (&mongoc_bulk_replace_one_opts->update.collation); bson_value_destroy (&mongoc_bulk_replace_one_opts->update.hint); bson_destroy (&mongoc_bulk_replace_one_opts->sort); bson_destroy (&mongoc_bulk_replace_one_opts->extra); } bool _mongoc_bulk_remove_one_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_remove_one_opts_t *mongoc_bulk_remove_one_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. bson_init (&mongoc_bulk_remove_one_opts->remove.collation); memset (&mongoc_bulk_remove_one_opts->remove.hint, 0, sizeof (bson_value_t)); mongoc_bulk_remove_one_opts->remove.limit = 1; bson_init (&mongoc_bulk_remove_one_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_bulk_remove_one_opts->remove.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_bulk_remove_one_opts->remove.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "limit")) { if (!_mongoc_convert_int32_t ( client, &iter, &mongoc_bulk_remove_one_opts->remove.limit, error)) { return false; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid option '%s'", bson_iter_key (&iter)); return false; } } return true; } void _mongoc_bulk_remove_one_opts_cleanup (mongoc_bulk_remove_one_opts_t *mongoc_bulk_remove_one_opts) { bson_destroy (&mongoc_bulk_remove_one_opts->remove.collation); bson_value_destroy (&mongoc_bulk_remove_one_opts->remove.hint); bson_destroy (&mongoc_bulk_remove_one_opts->extra); } bool _mongoc_bulk_remove_many_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_bulk_remove_many_opts_t *mongoc_bulk_remove_many_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. bson_init (&mongoc_bulk_remove_many_opts->remove.collation); memset (&mongoc_bulk_remove_many_opts->remove.hint, 0, sizeof (bson_value_t)); mongoc_bulk_remove_many_opts->remove.limit = 0; bson_init (&mongoc_bulk_remove_many_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_bulk_remove_many_opts->remove.collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_bulk_remove_many_opts->remove.hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "limit")) { if (!_mongoc_convert_int32_t ( client, &iter, &mongoc_bulk_remove_many_opts->remove.limit, error)) { return false; } } else { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid option '%s'", bson_iter_key (&iter)); return false; } } return true; } void _mongoc_bulk_remove_many_opts_cleanup (mongoc_bulk_remove_many_opts_t *mongoc_bulk_remove_many_opts) { bson_destroy (&mongoc_bulk_remove_many_opts->remove.collation); bson_value_destroy (&mongoc_bulk_remove_many_opts->remove.hint); bson_destroy (&mongoc_bulk_remove_many_opts->extra); } bool _mongoc_change_stream_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_change_stream_opts_t *mongoc_change_stream_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_change_stream_opts->batchSize = 0; bson_init (&mongoc_change_stream_opts->resumeAfter); bson_init (&mongoc_change_stream_opts->startAfter); memset (&mongoc_change_stream_opts->startAtOperationTime, 0, sizeof (mongoc_timestamp_t)); mongoc_change_stream_opts->maxAwaitTimeMS = 0; mongoc_change_stream_opts->fullDocument = NULL; mongoc_change_stream_opts->fullDocumentBeforeChange = NULL; mongoc_change_stream_opts->showExpandedEvents = false; memset (&mongoc_change_stream_opts->comment, 0, sizeof (bson_value_t)); bson_init (&mongoc_change_stream_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "batchSize")) { if (!_mongoc_convert_int32_t ( client, &iter, &mongoc_change_stream_opts->batchSize, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "resumeAfter")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_change_stream_opts->resumeAfter, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "startAfter")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_change_stream_opts->startAfter, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "startAtOperationTime")) { if (!_mongoc_convert_timestamp ( client, &iter, &mongoc_change_stream_opts->startAtOperationTime, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "maxAwaitTimeMS")) { if (!_mongoc_convert_int64_positive ( client, &iter, &mongoc_change_stream_opts->maxAwaitTimeMS, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "fullDocument")) { if (!_mongoc_convert_utf8 ( client, &iter, &mongoc_change_stream_opts->fullDocument, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "fullDocumentBeforeChange")) { if (!_mongoc_convert_utf8 ( client, &iter, &mongoc_change_stream_opts->fullDocumentBeforeChange, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "showExpandedEvents")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_change_stream_opts->showExpandedEvents, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_change_stream_opts->comment, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_change_stream_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_change_stream_opts_cleanup (mongoc_change_stream_opts_t *mongoc_change_stream_opts) { bson_destroy (&mongoc_change_stream_opts->resumeAfter); bson_destroy (&mongoc_change_stream_opts->startAfter); bson_value_destroy (&mongoc_change_stream_opts->comment); bson_destroy (&mongoc_change_stream_opts->extra); } bool _mongoc_create_index_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_create_index_opts_t *mongoc_create_index_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_create_index_opts->writeConcern = NULL; mongoc_create_index_opts->write_concern_owned = false; mongoc_create_index_opts->client_session = NULL; bson_init (&mongoc_create_index_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_create_index_opts->writeConcern, error)) { return false; } mongoc_create_index_opts->write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_create_index_opts->client_session, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_create_index_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_create_index_opts_cleanup (mongoc_create_index_opts_t *mongoc_create_index_opts) { if (mongoc_create_index_opts->write_concern_owned) { mongoc_write_concern_destroy (mongoc_create_index_opts->writeConcern); } bson_destroy (&mongoc_create_index_opts->extra); } bool _mongoc_read_write_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_read_write_opts_t *mongoc_read_write_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. bson_init (&mongoc_read_write_opts->readConcern); mongoc_read_write_opts->writeConcern = NULL; mongoc_read_write_opts->write_concern_owned = false; mongoc_read_write_opts->client_session = NULL; bson_init (&mongoc_read_write_opts->collation); mongoc_read_write_opts->serverId = 0; bson_init (&mongoc_read_write_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "readConcern")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_read_write_opts->readConcern, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_read_write_opts->writeConcern, error)) { return false; } mongoc_read_write_opts->write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_read_write_opts->client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_read_write_opts->collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "serverId")) { if (!_mongoc_convert_server_id ( client, &iter, &mongoc_read_write_opts->serverId, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_read_write_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_read_write_opts_cleanup (mongoc_read_write_opts_t *mongoc_read_write_opts) { bson_destroy (&mongoc_read_write_opts->readConcern); if (mongoc_read_write_opts->write_concern_owned) { mongoc_write_concern_destroy (mongoc_read_write_opts->writeConcern); } bson_destroy (&mongoc_read_write_opts->collation); bson_destroy (&mongoc_read_write_opts->extra); } bool _mongoc_gridfs_bucket_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_gridfs_bucket_opts_t *mongoc_gridfs_bucket_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_gridfs_bucket_opts->bucketName = "fs"; mongoc_gridfs_bucket_opts->chunkSizeBytes = 261120; mongoc_gridfs_bucket_opts->writeConcern = NULL; mongoc_gridfs_bucket_opts->write_concern_owned = false; mongoc_gridfs_bucket_opts->readConcern = NULL; bson_init (&mongoc_gridfs_bucket_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "bucketName")) { if (!_mongoc_convert_utf8 ( client, &iter, &mongoc_gridfs_bucket_opts->bucketName, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "chunkSizeBytes")) { if (!_mongoc_convert_int32_positive ( client, &iter, &mongoc_gridfs_bucket_opts->chunkSizeBytes, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_gridfs_bucket_opts->writeConcern, error)) { return false; } mongoc_gridfs_bucket_opts->write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "readConcern")) { if (!_mongoc_convert_read_concern ( client, &iter, &mongoc_gridfs_bucket_opts->readConcern, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_gridfs_bucket_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_gridfs_bucket_opts_cleanup (mongoc_gridfs_bucket_opts_t *mongoc_gridfs_bucket_opts) { if (mongoc_gridfs_bucket_opts->write_concern_owned) { mongoc_write_concern_destroy (mongoc_gridfs_bucket_opts->writeConcern); } mongoc_read_concern_destroy (mongoc_gridfs_bucket_opts->readConcern); bson_destroy (&mongoc_gridfs_bucket_opts->extra); } bool _mongoc_gridfs_bucket_upload_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_gridfs_bucket_upload_opts_t *mongoc_gridfs_bucket_upload_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_gridfs_bucket_upload_opts->chunkSizeBytes = 0; bson_init (&mongoc_gridfs_bucket_upload_opts->metadata); bson_init (&mongoc_gridfs_bucket_upload_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "chunkSizeBytes")) { if (!_mongoc_convert_int32_positive ( client, &iter, &mongoc_gridfs_bucket_upload_opts->chunkSizeBytes, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "metadata")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_gridfs_bucket_upload_opts->metadata, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_gridfs_bucket_upload_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_gridfs_bucket_upload_opts_cleanup (mongoc_gridfs_bucket_upload_opts_t *mongoc_gridfs_bucket_upload_opts) { bson_destroy (&mongoc_gridfs_bucket_upload_opts->metadata); bson_destroy (&mongoc_gridfs_bucket_upload_opts->extra); } bool _mongoc_aggregate_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_aggregate_opts_t *mongoc_aggregate_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_aggregate_opts->readConcern = NULL; mongoc_aggregate_opts->writeConcern = NULL; mongoc_aggregate_opts->write_concern_owned = false; mongoc_aggregate_opts->client_session = NULL; mongoc_aggregate_opts->bypass = false; bson_init (&mongoc_aggregate_opts->collation); mongoc_aggregate_opts->serverId = 0; mongoc_aggregate_opts->batchSize = 0; mongoc_aggregate_opts->batchSize_is_set = false; bson_init (&mongoc_aggregate_opts->let); memset (&mongoc_aggregate_opts->comment, 0, sizeof (bson_value_t)); memset (&mongoc_aggregate_opts->hint, 0, sizeof (bson_value_t)); bson_init (&mongoc_aggregate_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "readConcern")) { if (!_mongoc_convert_read_concern ( client, &iter, &mongoc_aggregate_opts->readConcern, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_aggregate_opts->writeConcern, error)) { return false; } mongoc_aggregate_opts->write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_aggregate_opts->client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "bypassDocumentValidation")) { if (!_mongoc_convert_bool ( client, &iter, &mongoc_aggregate_opts->bypass, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_aggregate_opts->collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "serverId")) { if (!_mongoc_convert_server_id ( client, &iter, &mongoc_aggregate_opts->serverId, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "batchSize")) { if (!_mongoc_convert_int32_t ( client, &iter, &mongoc_aggregate_opts->batchSize, error)) { return false; } mongoc_aggregate_opts->batchSize_is_set = true; } else if (!strcmp (bson_iter_key (&iter), "let")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_aggregate_opts->let, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_aggregate_opts->comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_aggregate_opts->hint, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_aggregate_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_aggregate_opts_cleanup (mongoc_aggregate_opts_t *mongoc_aggregate_opts) { mongoc_read_concern_destroy (mongoc_aggregate_opts->readConcern); if (mongoc_aggregate_opts->write_concern_owned) { mongoc_write_concern_destroy (mongoc_aggregate_opts->writeConcern); } bson_destroy (&mongoc_aggregate_opts->collation); bson_destroy (&mongoc_aggregate_opts->let); bson_value_destroy (&mongoc_aggregate_opts->comment); bson_value_destroy (&mongoc_aggregate_opts->hint); bson_destroy (&mongoc_aggregate_opts->extra); } bool _mongoc_find_and_modify_appended_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_find_and_modify_appended_opts_t *mongoc_find_and_modify_appended_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. mongoc_find_and_modify_appended_opts->writeConcern = NULL; mongoc_find_and_modify_appended_opts->write_concern_owned = false; mongoc_find_and_modify_appended_opts->client_session = NULL; memset (&mongoc_find_and_modify_appended_opts->hint, 0, sizeof (bson_value_t)); bson_init (&mongoc_find_and_modify_appended_opts->let); memset (&mongoc_find_and_modify_appended_opts->comment, 0, sizeof (bson_value_t)); bson_init (&mongoc_find_and_modify_appended_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "writeConcern")) { if (!_mongoc_convert_write_concern ( client, &iter, &mongoc_find_and_modify_appended_opts->writeConcern, error)) { return false; } mongoc_find_and_modify_appended_opts->write_concern_owned = true; } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_find_and_modify_appended_opts->client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_find_and_modify_appended_opts->hint, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "let")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_find_and_modify_appended_opts->let, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_find_and_modify_appended_opts->comment, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_find_and_modify_appended_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_find_and_modify_appended_opts_cleanup (mongoc_find_and_modify_appended_opts_t *mongoc_find_and_modify_appended_opts) { if (mongoc_find_and_modify_appended_opts->write_concern_owned) { mongoc_write_concern_destroy (mongoc_find_and_modify_appended_opts->writeConcern); } bson_value_destroy (&mongoc_find_and_modify_appended_opts->hint); bson_destroy (&mongoc_find_and_modify_appended_opts->let); bson_value_destroy (&mongoc_find_and_modify_appended_opts->comment); bson_destroy (&mongoc_find_and_modify_appended_opts->extra); } bool _mongoc_count_document_opts_parse ( mongoc_client_t *client, const bson_t *opts, mongoc_count_document_opts_t *mongoc_count_document_opts, bson_error_t *error) { bson_iter_t iter; BSON_ASSERT (client || true); // client may be NULL. bson_init (&mongoc_count_document_opts->readConcern); mongoc_count_document_opts->client_session = NULL; bson_init (&mongoc_count_document_opts->collation); mongoc_count_document_opts->serverId = 0; memset (&mongoc_count_document_opts->skip, 0, sizeof (bson_value_t)); memset (&mongoc_count_document_opts->limit, 0, sizeof (bson_value_t)); memset (&mongoc_count_document_opts->comment, 0, sizeof (bson_value_t)); memset (&mongoc_count_document_opts->hint, 0, sizeof (bson_value_t)); bson_init (&mongoc_count_document_opts->extra); if (!opts) { return true; } if (!bson_iter_init (&iter, opts)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_key (&iter), "readConcern")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_count_document_opts->readConcern, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "sessionId")) { if (!_mongoc_convert_session_id ( client, &iter, &mongoc_count_document_opts->client_session, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "collation")) { if (!_mongoc_convert_document ( client, &iter, &mongoc_count_document_opts->collation, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "serverId")) { if (!_mongoc_convert_server_id ( client, &iter, &mongoc_count_document_opts->serverId, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "skip")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_count_document_opts->skip, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "limit")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_count_document_opts->limit, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "comment")) { if (!_mongoc_convert_bson_value_t ( client, &iter, &mongoc_count_document_opts->comment, error)) { return false; } } else if (!strcmp (bson_iter_key (&iter), "hint")) { if (!_mongoc_convert_hint ( client, &iter, &mongoc_count_document_opts->hint, error)) { return false; } } else { /* unrecognized values are copied to "extra" */ if (!BSON_APPEND_VALUE ( &mongoc_count_document_opts->extra, bson_iter_key (&iter), bson_iter_value (&iter))) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Invalid 'opts' parameter."); return false; } } } return true; } void _mongoc_count_document_opts_cleanup (mongoc_count_document_opts_t *mongoc_count_document_opts) { bson_destroy (&mongoc_count_document_opts->readConcern); bson_destroy (&mongoc_count_document_opts->collation); bson_value_destroy (&mongoc_count_document_opts->skip); bson_value_destroy (&mongoc_count_document_opts->limit); bson_value_destroy (&mongoc_count_document_opts->comment); bson_value_destroy (&mongoc_count_document_opts->hint); bson_destroy (&mongoc_count_document_opts->extra); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-prelude.h0000644000175100001660000000133114760300420022575 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(MONGOC_INSIDE) && !defined(MONGOC_COMPILATION) #error "Only can be included directly." #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-queue-private.h0000644000175100001660000000310714760300420023734 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_QUEUE_PRIVATE_H #define MONGOC_QUEUE_PRIVATE_H #include #include BSON_BEGIN_DECLS #define MONGOC_QUEUE_INITIALIZER \ { \ NULL, NULL \ } typedef struct _mongoc_queue_t mongoc_queue_t; typedef struct _mongoc_queue_item_t mongoc_queue_item_t; struct _mongoc_queue_t { mongoc_queue_item_t *head; mongoc_queue_item_t *tail; uint32_t length; }; struct _mongoc_queue_item_t { mongoc_queue_item_t *next; void *data; }; void _mongoc_queue_init (mongoc_queue_t *queue); void * _mongoc_queue_pop_head (mongoc_queue_t *queue); void * _mongoc_queue_pop_tail (mongoc_queue_t *queue); void _mongoc_queue_push_head (mongoc_queue_t *queue, void *data); void _mongoc_queue_push_tail (mongoc_queue_t *queue, void *data); uint32_t _mongoc_queue_get_length (const mongoc_queue_t *queue); BSON_END_DECLS #endif /* MONGOC_QUEUE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-queue.c0000644000175100001660000000513714760300420022264 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include void _mongoc_queue_init (mongoc_queue_t *queue) { BSON_ASSERT (queue); memset (queue, 0, sizeof *queue); } void _mongoc_queue_push_head (mongoc_queue_t *queue, void *data) { mongoc_queue_item_t *item; BSON_ASSERT (queue); BSON_ASSERT (data); item = (mongoc_queue_item_t *) bson_malloc0 (sizeof *item); item->next = queue->head; item->data = data; queue->head = item; if (!queue->tail) { queue->tail = item; } queue->length++; } void _mongoc_queue_push_tail (mongoc_queue_t *queue, void *data) { mongoc_queue_item_t *item; BSON_ASSERT (queue); BSON_ASSERT (data); item = (mongoc_queue_item_t *) bson_malloc0 (sizeof *item); item->data = data; if (queue->tail) { queue->tail->next = item; } else { queue->head = item; } queue->tail = item; queue->length++; } void * _mongoc_queue_pop_head (mongoc_queue_t *queue) { mongoc_queue_item_t *item; void *data = NULL; BSON_ASSERT (queue); if ((item = queue->head)) { if (!item->next) { queue->tail = NULL; } queue->head = item->next; data = item->data; bson_free (item); queue->length--; } return data; } void * _mongoc_queue_pop_tail (mongoc_queue_t *queue) { mongoc_queue_item_t *item; void *data = NULL; BSON_ASSERT (queue); if (queue->length == 0) { return NULL; } data = queue->tail->data; if (queue->length == 1) { bson_free (queue->tail); queue->head = queue->tail = NULL; } else { /* find item pointing at tail */ for (item = queue->head; item; item = item->next) { if (item->next == queue->tail) { item->next = NULL; bson_free (queue->tail); queue->tail = item; break; } } } queue->length--; return data; } uint32_t _mongoc_queue_get_length (const mongoc_queue_t *queue) { BSON_ASSERT (queue); return queue->length; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-rand-cng.c0000644000175100001660000000333514760300420022627 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL #include #include #include #include #include #include #define NT_SUCCESS(Status) (((NTSTATUS) (Status)) >= 0) #define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L) int _mongoc_rand_bytes (uint8_t *buf, int num) { static BCRYPT_ALG_HANDLE algorithm = 0; NTSTATUS status = 0; if (!algorithm) { status = BCryptOpenAlgorithmProvider (&algorithm, BCRYPT_RNG_ALGORITHM, NULL, 0); if (!NT_SUCCESS (status)) { MONGOC_ERROR ("BCryptOpenAlgorithmProvider(): %ld", status); return 0; } } status = BCryptGenRandom (algorithm, buf, num, 0); if (NT_SUCCESS (status)) { return 1; } MONGOC_ERROR ("BCryptGenRandom(): %ld", status); return 0; } void mongoc_rand_seed (const void *buf, int num) { /* N/A - OS Does not need entropy seed */ } void mongoc_rand_add (const void *buf, int num, double entropy) { /* N/A - OS Does not need entropy seed */ } int mongoc_rand_status (void) { return 1; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-rand-common-crypto.c0000644000175100001660000000240114760300420024657 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO #include #include #include #include /* rumour has it this wasn't in standard Security.h in ~10.8 */ #include int _mongoc_rand_bytes (uint8_t *buf, int num) { return !SecRandomCopyBytes (kSecRandomDefault, num, buf); } void mongoc_rand_seed (const void *buf, int num) { /* No such thing in Common Crypto */ } void mongoc_rand_add (const void *buf, int num, double entropy) { /* No such thing in Common Crypto */ } int mongoc_rand_status (void) { return 1; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-rand-openssl.c0000644000175100001660000000320214760300420023534 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_CRYPTO_LIBCRYPTO #include #include #include #include #include int _mongoc_rand_bytes (uint8_t *buf, int num) { #if OPENSSL_VERSION_NUMBER < 0x10101000L /* Versions of OpenSSL before 1.1.1 can potentially produce the same random * sequences in processes with the same PID. Rather than attempt to detect * PID changes (useful for parent/child forking but not if PIDs wrap), mix * the current time into the generator's state. * See also: https://wiki.openssl.org/index.php/Random_fork-safety */ struct timeval tv; bson_gettimeofday (&tv); RAND_add (&tv, sizeof (tv), 0.0); #endif return RAND_bytes (buf, num); } void mongoc_rand_seed (const void *buf, int num) { RAND_seed (buf, num); } void mongoc_rand_add (const void *buf, int num, double entropy) { RAND_add (buf, num, entropy); } int mongoc_rand_status (void) { return RAND_status (); } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-rand-private.h0000644000175100001660000000151714760300420023537 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_RAND_PRIVATE_H #define MONGOC_RAND_PRIVATE_H #include BSON_BEGIN_DECLS int _mongoc_rand_bytes (uint8_t *buf, int num); BSON_END_DECLS #endif /* MONGOC_RAND_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-rand.h0000644000175100001660000000175314760300420022071 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_RAND_H #define MONGOC_RAND_H #include #include BSON_BEGIN_DECLS MONGOC_EXPORT (void) mongoc_rand_seed (const void *buf, int num); MONGOC_EXPORT (void) mongoc_rand_add (const void *buf, int num, double entropy); MONGOC_EXPORT (int) mongoc_rand_status (void); BSON_END_DECLS #endif /* MONGOC_RAND_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-read-concern-private.h0000644000175100001660000000217014760300420025147 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_READ_CONCERN_PRIVATE_H #define MONGOC_READ_CONCERN_PRIVATE_H #include #include BSON_BEGIN_DECLS struct _mongoc_read_concern_t { char *level; bool frozen; bson_t compiled; }; const bson_t * _mongoc_read_concern_get_bson (mongoc_read_concern_t *read_concern); mongoc_read_concern_t * _mongoc_read_concern_new_from_iter (const bson_iter_t *iter, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_READ_CONCERN_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-read-concern.c0000644000175100001660000001327414760300420023501 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include static void _mongoc_read_concern_freeze (mongoc_read_concern_t *read_concern); /** * mongoc_read_concern_new: * * Create a new mongoc_read_concern_t. * * Returns: A newly allocated mongoc_read_concern_t. This should be freed * with mongoc_read_concern_destroy(). */ mongoc_read_concern_t * mongoc_read_concern_new (void) { mongoc_read_concern_t *read_concern; read_concern = BSON_ALIGNED_ALLOC0 (mongoc_read_concern_t); bson_init (&read_concern->compiled); return read_concern; } mongoc_read_concern_t * mongoc_read_concern_copy (const mongoc_read_concern_t *read_concern) { mongoc_read_concern_t *ret = NULL; if (read_concern) { ret = mongoc_read_concern_new (); ret->level = bson_strdup (read_concern->level); } return ret; } /** * mongoc_read_concern_destroy: * @read_concern: A mongoc_read_concern_t. * * Releases a mongoc_read_concern_t and all associated memory. */ void mongoc_read_concern_destroy (mongoc_read_concern_t *read_concern) { if (read_concern) { bson_destroy (&read_concern->compiled); bson_free (read_concern->level); bson_free (read_concern); } } const char * mongoc_read_concern_get_level (const mongoc_read_concern_t *read_concern) { BSON_ASSERT (read_concern); return read_concern->level; } /** * mongoc_read_concern_set_level: * @read_concern: A mongoc_read_concern_t. * @level: The read concern level * * Sets the read concern level. Any string is supported for future compatibility * but MongoDB 3.2 only accepts "local" and "majority", aka: * - MONGOC_READ_CONCERN_LEVEL_LOCAL * - MONGOC_READ_CONCERN_LEVEL_MAJORITY * MongoDB 3.4 added * - MONGOC_READ_CONCERN_LEVEL_LINEARIZABLE * * See the MongoDB docs for more information on readConcernLevel */ bool mongoc_read_concern_set_level (mongoc_read_concern_t *read_concern, const char *level) { BSON_ASSERT (read_concern); bson_free (read_concern->level); read_concern->level = bson_strdup (level); read_concern->frozen = false; return true; } /** * mongoc_read_concern_append: * @read_concern: (in): A mongoc_read_concern_t. * @opts: (out): A pointer to a bson document. * * Appends a read_concern document to command options to send to * a server. * * Returns true on success, false on failure. * */ bool mongoc_read_concern_append (mongoc_read_concern_t *read_concern, bson_t *command) { BSON_ASSERT (read_concern); if (!read_concern->level) { return true; } if (!bson_append_document (command, "readConcern", 11, _mongoc_read_concern_get_bson (read_concern))) { MONGOC_ERROR ("Could not append readConcern to command."); return false; } return true; } /** * mongoc_read_concern_is_default: * @read_concern: A const mongoc_read_concern_t. * * Returns true when read_concern has not been modified. */ bool mongoc_read_concern_is_default (const mongoc_read_concern_t *read_concern) { return !read_concern || !read_concern->level; } /** * mongoc_read_concern_get_bson: * @read_concern: A mongoc_read_concern_t. * * This is an internal function. * * Returns: A bson_t representing the read concern, which is owned by the * mongoc_read_concern_t instance and should not be modified or freed. */ const bson_t * _mongoc_read_concern_get_bson (mongoc_read_concern_t *read_concern) { if (!read_concern->frozen) { _mongoc_read_concern_freeze (read_concern); } return &read_concern->compiled; } /** * _mongoc_read_concern_new_from_iter: * * Create a new mongoc_read_concern_t from an iterator positioned on * a "readConcern" document. * * Returns: A newly allocated mongoc_read_concern_t. This should be freed * with mongoc_read_concern_destroy(). */ mongoc_read_concern_t * _mongoc_read_concern_new_from_iter (const bson_iter_t *iter, bson_error_t *error) { bson_iter_t inner; mongoc_read_concern_t *read_concern; BSON_ASSERT (iter); read_concern = mongoc_read_concern_new (); if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { goto fail; } BSON_ASSERT (bson_iter_recurse (iter, &inner)); if (!bson_iter_find (&inner, "level") || !BSON_ITER_HOLDS_UTF8 (&inner)) { goto fail; } mongoc_read_concern_set_level (read_concern, bson_iter_utf8 (&inner, NULL)); return read_concern; fail: bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid readConcern"); mongoc_read_concern_destroy (read_concern); return NULL; } /** * mongoc_read_concern_freeze: * @read_concern: A mongoc_read_concern_t. * * This is an internal function. * * Encodes the read concern into a bson_t, which may then be returned by * mongoc_read_concern_get_bson(). */ static void _mongoc_read_concern_freeze (mongoc_read_concern_t *read_concern) { bson_t *compiled; BSON_ASSERT (read_concern); compiled = &read_concern->compiled; read_concern->frozen = true; bson_reinit (compiled); if (read_concern->level) { BSON_APPEND_UTF8 (compiled, "level", read_concern->level); } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-read-concern.h0000644000175100001660000000356414760300420023507 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_READ_CONCERN_H #define MONGOC_READ_CONCERN_H #include #include BSON_BEGIN_DECLS #define MONGOC_READ_CONCERN_LEVEL_AVAILABLE "available" #define MONGOC_READ_CONCERN_LEVEL_LOCAL "local" #define MONGOC_READ_CONCERN_LEVEL_MAJORITY "majority" #define MONGOC_READ_CONCERN_LEVEL_LINEARIZABLE "linearizable" #define MONGOC_READ_CONCERN_LEVEL_SNAPSHOT "snapshot" typedef struct _mongoc_read_concern_t mongoc_read_concern_t; MONGOC_EXPORT (mongoc_read_concern_t *) mongoc_read_concern_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_read_concern_t *) mongoc_read_concern_copy (const mongoc_read_concern_t *read_concern) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_read_concern_destroy (mongoc_read_concern_t *read_concern); MONGOC_EXPORT (const char *) mongoc_read_concern_get_level (const mongoc_read_concern_t *read_concern); MONGOC_EXPORT (bool) mongoc_read_concern_set_level (mongoc_read_concern_t *read_concern, const char *level); MONGOC_EXPORT (bool) mongoc_read_concern_append (mongoc_read_concern_t *read_concern, bson_t *doc); MONGOC_EXPORT (bool) mongoc_read_concern_is_default (const mongoc_read_concern_t *read_concern); BSON_END_DECLS #endif /* MONGOC_READ_CONCERN_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-read-prefs-private.h0000644000175100001660000000452714760300420024647 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_READ_PREFS_PRIVATE_H #define MONGOC_READ_PREFS_PRIVATE_H #include #include #include BSON_BEGIN_DECLS struct _mongoc_read_prefs_t { mongoc_read_mode_t mode; bson_t tags; int64_t max_staleness_seconds; bson_t hedge; }; typedef struct _mongoc_assemble_query_result_t { bson_t *assembled_query; bool query_owned; int32_t flags; } mongoc_assemble_query_result_t; #define ASSEMBLE_QUERY_RESULT_INIT \ { \ NULL, false, MONGOC_QUERY_NONE \ } const char * _mongoc_read_mode_as_str (mongoc_read_mode_t mode); void assemble_query (const mongoc_read_prefs_t *read_prefs, const mongoc_server_stream_t *server_stream, const bson_t *query_bson, int32_t initial_flags, mongoc_assemble_query_result_t *result); void assemble_query_result_cleanup (mongoc_assemble_query_result_t *result); bool _mongoc_read_prefs_validate (const mongoc_read_prefs_t *read_prefs, bson_error_t *error); typedef enum { MONGOC_READ_PREFS_CONTENT_FLAG_MODE = (1 << 0), MONGOC_READ_PREFS_CONTENT_FLAG_TAGS = (1 << 1), MONGOC_READ_PREFS_CONTENT_FLAG_MAX_STALENESS_SECONDS = (1 << 2), MONGOC_READ_PREFS_CONTENT_FLAG_HEDGE = (1 << 3), } mongoc_read_prefs_content_flags_t; bool mongoc_read_prefs_append_contents_to_bson (const mongoc_read_prefs_t *read_prefs, bson_t *bson, mongoc_read_prefs_content_flags_t flags); #define IS_PREF_PRIMARY(_pref) (!(_pref) || ((_pref)->mode == MONGOC_READ_PRIMARY)) BSON_END_DECLS #endif /* MONGOC_READ_PREFS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-read-prefs.c0000644000175100001660000003102614760300420023164 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include mongoc_read_prefs_t * mongoc_read_prefs_new (mongoc_read_mode_t mode) { mongoc_read_prefs_t *read_prefs; read_prefs = BSON_ALIGNED_ALLOC0 (mongoc_read_prefs_t); read_prefs->mode = mode; bson_init (&read_prefs->tags); read_prefs->max_staleness_seconds = MONGOC_NO_MAX_STALENESS; bson_init (&read_prefs->hedge); return read_prefs; } mongoc_read_mode_t mongoc_read_prefs_get_mode (const mongoc_read_prefs_t *read_prefs) { return read_prefs ? read_prefs->mode : MONGOC_READ_PRIMARY; } void mongoc_read_prefs_set_mode (mongoc_read_prefs_t *read_prefs, mongoc_read_mode_t mode) { BSON_ASSERT (read_prefs); BSON_ASSERT (mode <= MONGOC_READ_NEAREST); read_prefs->mode = mode; } const bson_t * mongoc_read_prefs_get_tags (const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (read_prefs); return &read_prefs->tags; } void mongoc_read_prefs_set_tags (mongoc_read_prefs_t *read_prefs, const bson_t *tags) { BSON_ASSERT (read_prefs); bson_destroy (&read_prefs->tags); if (tags) { bson_copy_to (tags, &read_prefs->tags); } else { bson_init (&read_prefs->tags); } } void mongoc_read_prefs_add_tag (mongoc_read_prefs_t *read_prefs, const bson_t *tag) { bson_t empty = BSON_INITIALIZER; char str[16]; int key; BSON_ASSERT (read_prefs); key = bson_count_keys (&read_prefs->tags); // Expect no truncation. int req = bson_snprintf (str, sizeof str, "%d", key); BSON_ASSERT (mcommon_cmp_less_su (req, sizeof str)); if (tag) { bson_append_document (&read_prefs->tags, str, -1, tag); } else { bson_append_document (&read_prefs->tags, str, -1, &empty); } bson_destroy (&empty); } int64_t mongoc_read_prefs_get_max_staleness_seconds (const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (read_prefs); return read_prefs->max_staleness_seconds; } void mongoc_read_prefs_set_max_staleness_seconds (mongoc_read_prefs_t *read_prefs, int64_t max_staleness_seconds) { BSON_ASSERT (read_prefs); read_prefs->max_staleness_seconds = max_staleness_seconds; } const bson_t * mongoc_read_prefs_get_hedge (const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (read_prefs); return &read_prefs->hedge; } void mongoc_read_prefs_set_hedge (mongoc_read_prefs_t *read_prefs, const bson_t *hedge) { BSON_ASSERT (read_prefs); bson_destroy (&read_prefs->hedge); if (hedge) { bson_copy_to (hedge, &read_prefs->hedge); } else { bson_init (&read_prefs->hedge); } } bool mongoc_read_prefs_is_valid (const mongoc_read_prefs_t *read_prefs) { BSON_ASSERT (read_prefs); /* * Tags, maxStalenessSeconds, and hedge are not supported with PRIMARY mode. */ if (read_prefs->mode == MONGOC_READ_PRIMARY) { if (!bson_empty (&read_prefs->tags) || read_prefs->max_staleness_seconds != MONGOC_NO_MAX_STALENESS || !bson_empty (&read_prefs->hedge)) { return false; } } if (read_prefs->max_staleness_seconds != MONGOC_NO_MAX_STALENESS && read_prefs->max_staleness_seconds <= 0) { return false; } return true; } void mongoc_read_prefs_destroy (mongoc_read_prefs_t *read_prefs) { if (read_prefs) { bson_destroy (&read_prefs->tags); bson_destroy (&read_prefs->hedge); bson_free (read_prefs); } } mongoc_read_prefs_t * mongoc_read_prefs_copy (const mongoc_read_prefs_t *read_prefs) { mongoc_read_prefs_t *ret = NULL; if (read_prefs) { ret = mongoc_read_prefs_new (read_prefs->mode); bson_destroy (&ret->tags); bson_copy_to (&read_prefs->tags, &ret->tags); ret->max_staleness_seconds = read_prefs->max_staleness_seconds; bson_destroy (&ret->hedge); bson_copy_to (&read_prefs->hedge, &ret->hedge); } return ret; } const char * _mongoc_read_mode_as_str (mongoc_read_mode_t mode) { switch (mode) { case MONGOC_READ_PRIMARY: return "primary"; case MONGOC_READ_PRIMARY_PREFERRED: return "primaryPreferred"; case MONGOC_READ_SECONDARY: return "secondary"; case MONGOC_READ_SECONDARY_PREFERRED: return "secondaryPreferred"; case MONGOC_READ_NEAREST: return "nearest"; default: return ""; } } /* Update result with the read prefs, following Server Selection Spec. * The driver must have discovered the server is a mongos. */ static void _apply_read_preferences_mongos (const mongoc_read_prefs_t *read_prefs, const bson_t *query_bson, mongoc_assemble_query_result_t *result /* OUT */) { mongoc_read_mode_t mode; const bson_t *tags = NULL; bson_t child; int64_t max_staleness_seconds = MONGOC_NO_MAX_STALENESS; const bson_t *hedge = NULL; mode = mongoc_read_prefs_get_mode (read_prefs); if (read_prefs) { max_staleness_seconds = mongoc_read_prefs_get_max_staleness_seconds (read_prefs); tags = mongoc_read_prefs_get_tags (read_prefs); hedge = mongoc_read_prefs_get_hedge (read_prefs); } /* Server Selection Spec says: * * For mode 'primary', drivers MUST NOT set the secondaryOk wire protocol * flag and MUST NOT use $readPreference * * For mode 'secondary', drivers MUST set the secondaryOk wire protocol flag * and MUST also use $readPreference * * For mode 'primaryPreferred', drivers MUST set the secondaryOk wire * protocol flag and MUST also use $readPreference * * For mode 'secondaryPreferred', drivers MUST set the secondaryOk wire * protocol flag. If the read preference contains a non-empty tag_sets * parameter, maxStalenessSeconds is a positive integer, or the hedge * parameter is non-empty, drivers MUST use $readPreference; otherwise, * drivers MUST NOT use $readPreference * * For mode 'nearest', drivers MUST set the secondaryOk wire protocol flag * and MUST also use $readPreference */ if (mode == MONGOC_READ_SECONDARY_PREFERRED && (bson_empty0 (tags) && max_staleness_seconds <= 0 && bson_empty0 (hedge))) { result->flags |= MONGOC_QUERY_SECONDARY_OK; } else if (mode != MONGOC_READ_PRIMARY) { result->flags |= MONGOC_QUERY_SECONDARY_OK; /* Server Selection Spec: "When any $ modifier is used, including the * $readPreference modifier, the query MUST be provided using the $query * modifier". * * This applies to commands, too. */ result->assembled_query = bson_new (); result->query_owned = true; if (bson_has_field (query_bson, "$query")) { bson_concat (result->assembled_query, query_bson); } else { bson_append_document (result->assembled_query, "$query", 6, query_bson); } bson_append_document_begin (result->assembled_query, "$readPreference", 15, &child); mongoc_read_prefs_append_contents_to_bson ( read_prefs, &child, MONGOC_READ_PREFS_CONTENT_FLAG_MODE | MONGOC_READ_PREFS_CONTENT_FLAG_TAGS | MONGOC_READ_PREFS_CONTENT_FLAG_MAX_STALENESS_SECONDS | MONGOC_READ_PREFS_CONTENT_FLAG_HEDGE); bson_append_document_end (result->assembled_query, &child); } } bool mongoc_read_prefs_append_contents_to_bson (const mongoc_read_prefs_t *read_prefs, bson_t *bson, mongoc_read_prefs_content_flags_t flags) { BSON_OPTIONAL_PARAM (read_prefs); BSON_ASSERT_PARAM (bson); if (flags & MONGOC_READ_PREFS_CONTENT_FLAG_MODE) { // 'mode' will be Primary when read_prefs==NULL. mongoc_read_mode_t mode = mongoc_read_prefs_get_mode (read_prefs); const char *mode_str = _mongoc_read_mode_as_str (mode); if (!BSON_APPEND_UTF8 (bson, "mode", mode_str)) { return false; } } if (read_prefs) { // Other content is only available for non-NULL read_prefs int64_t max_staleness_seconds = mongoc_read_prefs_get_max_staleness_seconds (read_prefs); const bson_t *hedge = mongoc_read_prefs_get_hedge (read_prefs); const bson_t *tags = mongoc_read_prefs_get_tags (read_prefs); if ((flags & MONGOC_READ_PREFS_CONTENT_FLAG_TAGS) && !bson_empty (tags) && !BSON_APPEND_ARRAY (bson, "tags", tags)) { return false; } if ((flags & MONGOC_READ_PREFS_CONTENT_FLAG_MAX_STALENESS_SECONDS) && max_staleness_seconds != MONGOC_NO_MAX_STALENESS && !BSON_APPEND_INT64 (bson, "maxStalenessSeconds", max_staleness_seconds)) { return false; } if ((flags & MONGOC_READ_PREFS_CONTENT_FLAG_HEDGE) && !bson_empty (hedge) && !BSON_APPEND_DOCUMENT (bson, "hedge", hedge)) { return false; } } return true; } /* *-------------------------------------------------------------------------- * * assemble_query -- * * Update @result based on @read_prefs, following the Server Selection * Spec. * * Side effects: * Sets @result->assembled_query and @result->flags. * * Note: * This function, the mongoc_assemble_query_result_t struct, and all * related functions are only used for find operations with OP_QUERY. * Remove them once we have implemented exhaust cursors with OP_MSG in * the server, and all previous server versions are EOL. * *-------------------------------------------------------------------------- */ void assemble_query (const mongoc_read_prefs_t *read_prefs, const mongoc_server_stream_t *server_stream, const bson_t *query_bson, int32_t initial_flags, mongoc_assemble_query_result_t *result /* OUT */) { mongoc_server_description_type_t server_type; ENTRY; BSON_ASSERT (server_stream); BSON_ASSERT (query_bson); BSON_ASSERT (result); /* default values */ result->assembled_query = (bson_t *) query_bson; result->query_owned = false; result->flags = initial_flags; server_type = server_stream->sd->type; switch (server_stream->topology_type) { case MONGOC_TOPOLOGY_SINGLE: if (server_type == MONGOC_SERVER_MONGOS) { _apply_read_preferences_mongos (read_prefs, query_bson, result); } else { /* Server Selection Spec: for topology type single and server types * besides mongos, "clients MUST always set the secondaryOk wire * protocol flag on reads to ensure that any server type can handle the * request." */ result->flags |= MONGOC_OP_QUERY_FLAG_SECONDARY_OK; } break; case MONGOC_TOPOLOGY_RS_NO_PRIMARY: case MONGOC_TOPOLOGY_RS_WITH_PRIMARY: /* Server Selection Spec: for RS topology types, "For all read * preferences modes except primary, clients MUST set the secondaryOk wire * protocol flag to ensure that any suitable server can handle the * request. Clients MUST NOT set the secondaryOk wire protocol flag if * the read preference mode is primary. */ if (read_prefs && read_prefs->mode != MONGOC_READ_PRIMARY) { result->flags |= MONGOC_OP_QUERY_FLAG_SECONDARY_OK; } break; case MONGOC_TOPOLOGY_SHARDED: case MONGOC_TOPOLOGY_LOAD_BALANCED: _apply_read_preferences_mongos (read_prefs, query_bson, result); break; case MONGOC_TOPOLOGY_UNKNOWN: case MONGOC_TOPOLOGY_DESCRIPTION_TYPES: default: /* must not call _apply_read_preferences with unknown topology type */ BSON_ASSERT (false); } EXIT; } void assemble_query_result_cleanup (mongoc_assemble_query_result_t *result) { ENTRY; BSON_ASSERT (result); if (result->query_owned) { bson_destroy (result->assembled_query); } EXIT; } bool _mongoc_read_prefs_validate (const mongoc_read_prefs_t *read_prefs, bson_error_t *error) { if (read_prefs && !mongoc_read_prefs_is_valid (read_prefs)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid mongoc_read_prefs_t"); return false; } return true; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-read-prefs.h0000644000175100001660000000566014760300420023176 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_READ_PREFS_H #define MONGOC_READ_PREFS_H #include #include #include BSON_BEGIN_DECLS #define MONGOC_NO_MAX_STALENESS -1 #define MONGOC_SMALLEST_MAX_STALENESS_SECONDS 90 typedef struct _mongoc_read_prefs_t mongoc_read_prefs_t; typedef enum { /** Represents $readPreference.mode of 'primary' */ MONGOC_READ_PRIMARY = (1 << 0), /** Represents $readPreference.mode of 'secondary' */ MONGOC_READ_SECONDARY = (1 << 1), /** Represents $readPreference.mode of 'primaryPreferred' */ MONGOC_READ_PRIMARY_PREFERRED = (1 << 2) | MONGOC_READ_PRIMARY, /** Represents $readPreference.mode of 'secondaryPreferred' */ MONGOC_READ_SECONDARY_PREFERRED = (1 << 2) | MONGOC_READ_SECONDARY, /** Represents $readPreference.mode of 'nearest' */ MONGOC_READ_NEAREST = (1 << 3) | MONGOC_READ_SECONDARY, } mongoc_read_mode_t; MONGOC_EXPORT (mongoc_read_prefs_t *) mongoc_read_prefs_new (mongoc_read_mode_t read_mode) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_read_prefs_t *) mongoc_read_prefs_copy (const mongoc_read_prefs_t *read_prefs) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_read_prefs_destroy (mongoc_read_prefs_t *read_prefs); MONGOC_EXPORT (mongoc_read_mode_t) mongoc_read_prefs_get_mode (const mongoc_read_prefs_t *read_prefs); MONGOC_EXPORT (void) mongoc_read_prefs_set_mode (mongoc_read_prefs_t *read_prefs, mongoc_read_mode_t mode); MONGOC_EXPORT (const bson_t *) mongoc_read_prefs_get_tags (const mongoc_read_prefs_t *read_prefs); MONGOC_EXPORT (void) mongoc_read_prefs_set_tags (mongoc_read_prefs_t *read_prefs, const bson_t *tags); MONGOC_EXPORT (void) mongoc_read_prefs_add_tag (mongoc_read_prefs_t *read_prefs, const bson_t *tag); MONGOC_EXPORT (int64_t) mongoc_read_prefs_get_max_staleness_seconds (const mongoc_read_prefs_t *read_prefs); MONGOC_EXPORT (void) mongoc_read_prefs_set_max_staleness_seconds (mongoc_read_prefs_t *read_prefs, int64_t max_staleness_seconds); MONGOC_EXPORT (const bson_t *) mongoc_read_prefs_get_hedge (const mongoc_read_prefs_t *read_prefs); MONGOC_EXPORT (void) mongoc_read_prefs_set_hedge (mongoc_read_prefs_t *read_prefs, const bson_t *hedge); MONGOC_EXPORT (bool) mongoc_read_prefs_is_valid (const mongoc_read_prefs_t *read_prefs); BSON_END_DECLS #endif /* MONGOC_READ_PREFS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-rpc-private.h0000644000175100001660000000270314760300420023375 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifndef MONGOC_RPC_PRIVATE_H #define MONGOC_RPC_PRIVATE_H #include #include #include #include #include BSON_BEGIN_DECLS bool mcd_rpc_message_get_body (const mcd_rpc_message *rpc, bson_t *reply); bool mcd_rpc_message_check_ok (mcd_rpc_message *rpc, int32_t error_api_version, bson_error_t *error /* OUT */, bson_t *error_doc /* OUT */); bool _mongoc_cmd_check_ok (const bson_t *doc, int32_t error_api_version, bson_error_t *error); bool _mongoc_cmd_check_ok_no_wce (const bson_t *doc, int32_t error_api_version, bson_error_t *error); void mcd_rpc_message_egress (const mcd_rpc_message *rpc); void mcd_rpc_message_ingress (const mcd_rpc_message *rpc); BSON_END_DECLS #endif /* MONGOC_RPC_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-rpc.c0000644000175100001660000003004514760300420021720 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include bool mcd_rpc_message_get_body (const mcd_rpc_message *rpc, bson_t *reply) { switch (mcd_rpc_header_get_op_code (rpc)) { case MONGOC_OP_CODE_MSG: { const size_t sections_count = mcd_rpc_op_msg_get_sections_count (rpc); // Look for section kind 0. for (size_t index = 0u; index < sections_count; ++index) { switch (mcd_rpc_op_msg_section_get_kind (rpc, index)) { case 0: { // Body. const uint8_t *const body = mcd_rpc_op_msg_section_get_body (rpc, index); const int32_t body_len = bson_iter_int32_unsafe (&(bson_iter_t){.raw = body}); return bson_init_static (reply, body, (size_t) body_len); } case 1: // Document Sequence. continue; default: // Validated by `mcd_rpc_message_from_data`. BSON_UNREACHABLE ("invalid OP_MSG section kind"); } } break; } case MONGOC_OP_CODE_REPLY: { if (mcd_rpc_op_reply_get_documents_len (rpc) < 1) { return false; } // Assume the first document in OP_REPLY is the body. const uint8_t *const body = mcd_rpc_op_reply_get_documents (rpc); return bson_init_static (reply, body, (size_t) bson_iter_int32_unsafe (&(bson_iter_t){.raw = body})); } default: break; } return false; } /* returns true if an error was found. */ static bool _parse_error_reply (const bson_t *doc, bool check_wce, uint32_t *code, const char **msg) { bson_iter_t iter; bool found_error = false; ENTRY; BSON_ASSERT (doc); BSON_ASSERT (code); *code = 0; /* The server only returns real error codes as int32. * But it may return as a double or int64 if a failpoint * based on how it is configured to error. */ if (bson_iter_init_find (&iter, doc, "code") && BSON_ITER_HOLDS_NUMBER (&iter)) { *code = (uint32_t) bson_iter_as_int64 (&iter); BSON_ASSERT (*code); found_error = true; } if (bson_iter_init_find (&iter, doc, "errmsg") && BSON_ITER_HOLDS_UTF8 (&iter)) { *msg = bson_iter_utf8 (&iter, NULL); found_error = true; } else if (bson_iter_init_find (&iter, doc, "$err") && BSON_ITER_HOLDS_UTF8 (&iter)) { *msg = bson_iter_utf8 (&iter, NULL); found_error = true; } if (found_error) { /* there was a command error */ RETURN (true); } if (check_wce) { /* check for a write concern error */ if (bson_iter_init_find (&iter, doc, "writeConcernError") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_iter_t child; BSON_ASSERT (bson_iter_recurse (&iter, &child)); if (bson_iter_find (&child, "code") && BSON_ITER_HOLDS_NUMBER (&child)) { *code = (uint32_t) bson_iter_as_int64 (&child); BSON_ASSERT (*code); found_error = true; } BSON_ASSERT (bson_iter_recurse (&iter, &child)); if (bson_iter_find (&child, "errmsg") && BSON_ITER_HOLDS_UTF8 (&child)) { *msg = bson_iter_utf8 (&child, NULL); found_error = true; } } } RETURN (found_error); } /* *-------------------------------------------------------------------------- * * _mongoc_cmd_check_ok -- * * Check if a server reply document is an error message. * Optionally fill out a bson_error_t from the server error. * Does *not* check for writeConcernError. * * Returns: * false if @doc is an error message, true otherwise. * * Side effects: * If @doc is an error reply and @error is not NULL, set its * domain, code, and message. * *-------------------------------------------------------------------------- */ bool _mongoc_cmd_check_ok (const bson_t *doc, int32_t error_api_version, bson_error_t *error) { mongoc_error_domain_t domain = error_api_version >= MONGOC_ERROR_API_VERSION_2 ? MONGOC_ERROR_SERVER : MONGOC_ERROR_QUERY; uint32_t code; bson_iter_t iter; const char *msg = "Unknown command error"; ENTRY; BSON_ASSERT (doc); if (bson_iter_init_find (&iter, doc, "ok") && bson_iter_as_bool (&iter)) { /* no error */ RETURN (true); } if (!_parse_error_reply (doc, false /* check_wce */, &code, &msg)) { RETURN (true); } if (code == MONGOC_ERROR_PROTOCOL_ERROR || code == 13390) { code = MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND; } else if (code == 0) { code = MONGOC_ERROR_QUERY_FAILURE; } bson_set_error (error, domain, code, "%s", msg); /* there was a command error */ RETURN (false); } /* *-------------------------------------------------------------------------- * * _mongoc_cmd_check_ok_no_wce -- * * Check if a server reply document is an error message. * Optionally fill out a bson_error_t from the server error. * If the response contains a writeConcernError, this is considered * an error and returns false. * * Returns: * false if @doc is an error message, true otherwise. * * Side effects: * If @doc is an error reply and @error is not NULL, set its * domain, code, and message. * *-------------------------------------------------------------------------- */ bool _mongoc_cmd_check_ok_no_wce (const bson_t *doc, int32_t error_api_version, bson_error_t *error) { mongoc_error_domain_t domain = error_api_version >= MONGOC_ERROR_API_VERSION_2 ? MONGOC_ERROR_SERVER : MONGOC_ERROR_QUERY; uint32_t code; const char *msg = "Unknown command error"; ENTRY; BSON_ASSERT (doc); if (!_parse_error_reply (doc, true /* check_wce */, &code, &msg)) { RETURN (true); } if (code == MONGOC_ERROR_PROTOCOL_ERROR || code == 13390) { code = MONGOC_ERROR_QUERY_COMMAND_NOT_FOUND; } else if (code == 0) { code = MONGOC_ERROR_QUERY_FAILURE; } bson_set_error (error, domain, code, "%s", msg); /* there was a command error */ RETURN (false); } /* helper function to parse error reply document to an OP_QUERY */ static void _mongoc_populate_query_error (const bson_t *doc, int32_t error_api_version, bson_error_t *error) { mongoc_error_domain_t domain = error_api_version >= MONGOC_ERROR_API_VERSION_2 ? MONGOC_ERROR_SERVER : MONGOC_ERROR_QUERY; uint32_t code = MONGOC_ERROR_QUERY_FAILURE; bson_iter_t iter; const char *msg = "Unknown query failure"; ENTRY; BSON_ASSERT (doc); if (bson_iter_init_find (&iter, doc, "code") && BSON_ITER_HOLDS_NUMBER (&iter)) { code = (uint32_t) bson_iter_as_int64 (&iter); BSON_ASSERT (code); } if (bson_iter_init_find (&iter, doc, "$err") && BSON_ITER_HOLDS_UTF8 (&iter)) { msg = bson_iter_utf8 (&iter, NULL); } bson_set_error (error, domain, code, "%s", msg); EXIT; } bool mcd_rpc_message_check_ok (mcd_rpc_message *rpc, int32_t error_api_version, bson_error_t *error /* OUT */, bson_t *error_doc /* OUT */) { BSON_ASSERT (rpc); ENTRY; if (mcd_rpc_header_get_op_code (rpc) != MONGOC_OP_CODE_REPLY) { bson_set_error ( error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "Received rpc other than OP_REPLY."); RETURN (false); } const int32_t flags = mcd_rpc_op_reply_get_response_flags (rpc); if (flags & MONGOC_OP_REPLY_RESPONSE_FLAG_QUERY_FAILURE) { bson_t body; if (mcd_rpc_message_get_body (rpc, &body)) { _mongoc_populate_query_error (&body, error_api_version, error); if (error_doc) { bson_destroy (error_doc); bson_copy_to (&body, error_doc); } bson_destroy (&body); } else { bson_set_error (error, MONGOC_ERROR_QUERY, MONGOC_ERROR_QUERY_FAILURE, "Unknown query failure."); } RETURN (false); } if (flags & MONGOC_OP_REPLY_RESPONSE_FLAG_CURSOR_NOT_FOUND) { bson_set_error ( error, MONGOC_ERROR_CURSOR, MONGOC_ERROR_CURSOR_INVALID_CURSOR, "The cursor is invalid or has expired."); RETURN (false); } RETURN (true); } void mcd_rpc_message_egress (const mcd_rpc_message *rpc) { // `mcd_rpc_message_egress` is expected to be called after // `mcd_rpc_message_to_iovecs`, which converts the opCode field to // little endian. int32_t op_code = mcd_rpc_header_get_op_code (rpc); op_code = bson_iter_int32_unsafe (&(bson_iter_t){.raw = (const uint8_t *) &op_code}); if (op_code == MONGOC_OP_CODE_COMPRESSED) { mongoc_counter_op_egress_compressed_inc (); mongoc_counter_op_egress_total_inc (); op_code = mcd_rpc_op_compressed_get_original_opcode (rpc); op_code = bson_iter_int32_unsafe (&(bson_iter_t){.raw = (const uint8_t *) &op_code}); } switch (op_code) { case MONGOC_OP_CODE_COMPRESSED: BSON_UNREACHABLE ("invalid opcode (double compression?!)"); break; case MONGOC_OP_CODE_MSG: mongoc_counter_op_egress_msg_inc (); mongoc_counter_op_egress_total_inc (); break; case MONGOC_OP_CODE_REPLY: BSON_UNREACHABLE ("unexpected OP_REPLY egress"); break; case MONGOC_OP_CODE_UPDATE: mongoc_counter_op_egress_update_inc (); mongoc_counter_op_egress_total_inc (); break; case MONGOC_OP_CODE_INSERT: mongoc_counter_op_egress_insert_inc (); mongoc_counter_op_egress_total_inc (); break; case MONGOC_OP_CODE_QUERY: mongoc_counter_op_egress_query_inc (); mongoc_counter_op_egress_total_inc (); break; case MONGOC_OP_CODE_GET_MORE: mongoc_counter_op_egress_getmore_inc (); mongoc_counter_op_egress_total_inc (); break; case MONGOC_OP_CODE_DELETE: mongoc_counter_op_egress_delete_inc (); mongoc_counter_op_egress_total_inc (); break; case MONGOC_OP_CODE_KILL_CURSORS: mongoc_counter_op_egress_killcursors_inc (); mongoc_counter_op_egress_total_inc (); break; default: BSON_UNREACHABLE ("invalid opcode"); } } void mcd_rpc_message_ingress (const mcd_rpc_message *rpc) { // `mcd_rpc_message_ingress` is expected be called after // `mcd_rpc_message_from_data`, which converts the opCode field to native // endian. int32_t op_code = mcd_rpc_header_get_op_code (rpc); if (op_code == MONGOC_OP_CODE_COMPRESSED) { mongoc_counter_op_ingress_compressed_inc (); mongoc_counter_op_ingress_total_inc (); op_code = mcd_rpc_op_compressed_get_original_opcode (rpc); } switch (op_code) { case MONGOC_OP_CODE_COMPRESSED: BSON_UNREACHABLE ("invalid opcode (double compression?!)"); break; case MONGOC_OP_CODE_MSG: mongoc_counter_op_ingress_msg_inc (); mongoc_counter_op_ingress_total_inc (); break; case MONGOC_OP_CODE_REPLY: mongoc_counter_op_ingress_reply_inc (); mongoc_counter_op_ingress_total_inc (); break; case MONGOC_OP_CODE_UPDATE: BSON_UNREACHABLE ("unexpected OP_UPDATE ingress"); break; case MONGOC_OP_CODE_INSERT: BSON_UNREACHABLE ("unexpected OP_INSERT ingress"); break; case MONGOC_OP_CODE_QUERY: BSON_UNREACHABLE ("unexpected OP_QUERY ingress"); break; case MONGOC_OP_CODE_GET_MORE: BSON_UNREACHABLE ("unexpected OP_GET_MORE ingress"); break; case MONGOC_OP_CODE_DELETE: BSON_UNREACHABLE ("unexpected OP_DELETE ingress"); break; case MONGOC_OP_CODE_KILL_CURSORS: BSON_UNREACHABLE ("unexpected OP_KILL_CURSORS ingress"); break; default: BSON_UNREACHABLE ("invalid opcode"); } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-sasl-private.h0000644000175100001660000000330014760300420023545 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SASL_PRIVATE_H #define MONGOC_SASL_PRIVATE_H #include #include #include #include #include BSON_BEGIN_DECLS typedef struct { char *user; char *pass; char *service_name; char *service_host; bool canonicalize_host_name; char *mechanism; } mongoc_sasl_t; void _mongoc_sasl_set_pass (mongoc_sasl_t *sasl, const char *pass); void _mongoc_sasl_set_user (mongoc_sasl_t *sasl, const char *user); void _mongoc_sasl_set_service_name (mongoc_sasl_t *sasl, const char *service_name); void _mongoc_sasl_set_service_host (mongoc_sasl_t *sasl, const char *service_host); void _mongoc_sasl_set_properties (mongoc_sasl_t *sasl, const mongoc_uri_t *uri); bool _mongoc_sasl_get_canonicalized_name (mongoc_stream_t *node_stream, /* IN */ char *name, /* OUT */ size_t namelen); /* IN */ BSON_END_DECLS #endif /* MONGOC_SASL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-sasl.c0000644000175100001660000001204114760300420022072 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SASL #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "SASL" void _mongoc_sasl_set_user (mongoc_sasl_t *sasl, const char *user) { BSON_ASSERT (sasl); bson_free (sasl->user); sasl->user = user ? bson_strdup (user) : NULL; } void _mongoc_sasl_set_pass (mongoc_sasl_t *sasl, const char *pass) { BSON_ASSERT (sasl); bson_free (sasl->pass); sasl->pass = pass ? bson_strdup (pass) : NULL; } void _mongoc_sasl_set_service_host (mongoc_sasl_t *sasl, const char *service_host) { BSON_ASSERT (sasl); bson_free (sasl->service_host); sasl->service_host = service_host ? bson_strdup (service_host) : NULL; } void _mongoc_sasl_set_service_name (mongoc_sasl_t *sasl, const char *service_name) { BSON_ASSERT (sasl); bson_free (sasl->service_name); sasl->service_name = service_name ? bson_strdup (service_name) : NULL; } void _mongoc_sasl_set_properties (mongoc_sasl_t *sasl, const mongoc_uri_t *uri) { const bson_t *options; bson_iter_t iter; bson_t properties; const char *service_name = NULL; bool canonicalize = false; _mongoc_sasl_set_pass (sasl, mongoc_uri_get_password (uri)); _mongoc_sasl_set_user (sasl, mongoc_uri_get_username (uri)); options = mongoc_uri_get_options (uri); if (!mongoc_uri_get_mechanism_properties (uri, &properties)) { bson_init (&properties); } if (bson_iter_init_find_case (&iter, options, MONGOC_URI_GSSAPISERVICENAME) && BSON_ITER_HOLDS_UTF8 (&iter)) { service_name = bson_iter_utf8 (&iter, NULL); } if (bson_iter_init_find_case (&iter, &properties, "SERVICE_NAME") && BSON_ITER_HOLDS_UTF8 (&iter)) { /* newer "authMechanismProperties" URI syntax takes precedence */ service_name = bson_iter_utf8 (&iter, NULL); } _mongoc_sasl_set_service_name (sasl, service_name); /* * Driver Authentication Spec: "Drivers MAY allow the user to request * canonicalization of the hostname. This might be required when the hosts * report different hostnames than what is used in the kerberos database. * The default is "false". * * Some underlying GSSAPI layers will do this for us, but can be disabled in * their config (krb.conf). * * See CDRIVER-323 for more information. */ if (bson_iter_init_find_case (&iter, options, MONGOC_URI_CANONICALIZEHOSTNAME) && BSON_ITER_HOLDS_BOOL (&iter)) { canonicalize = bson_iter_bool (&iter); } if (bson_iter_init_find_case (&iter, &properties, "CANONICALIZE_HOST_NAME") && BSON_ITER_HOLDS_UTF8 (&iter)) { /* newer "authMechanismProperties" URI syntax takes precedence */ canonicalize = !strcasecmp (bson_iter_utf8 (&iter, NULL), "true"); } sasl->canonicalize_host_name = canonicalize; bson_destroy (&properties); } /* *-------------------------------------------------------------------------- * * _mongoc_sasl_get_canonicalized_name -- * * Query the node to get the canonicalized name. This may happen if * the node has been accessed via an alias. * * The gssapi code will use this if canonicalizeHostname is true. * * Some underlying layers of krb might do this for us, but they can * be disabled in krb.conf. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool _mongoc_sasl_get_canonicalized_name (mongoc_stream_t *node_stream, /* IN */ char *name, /* OUT */ size_t namelen) /* OUT */ { mongoc_stream_t *stream; mongoc_socket_t *sock = NULL; char *canonicalized; ENTRY; BSON_ASSERT (node_stream); BSON_ASSERT (name); stream = mongoc_stream_get_root_stream (node_stream); BSON_ASSERT (stream); if (stream->type == MONGOC_STREAM_SOCKET) { sock = mongoc_stream_socket_get_socket ((mongoc_stream_socket_t *) stream); if (sock) { canonicalized = mongoc_socket_getnameinfo (sock); if (canonicalized) { // Truncation is OK. int req = bson_snprintf (name, namelen, "%s", canonicalized); BSON_ASSERT (req > 0); bson_free (canonicalized); RETURN (true); } } } RETURN (false); } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-scram-private.h0000644000175100001660000005307214760300420023723 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SCRAM_PRIVATE_H #define MONGOC_SCRAM_PRIVATE_H #include #include BSON_BEGIN_DECLS #define MONGOC_SCRAM_SHA_1_HASH_SIZE 20 #define MONGOC_SCRAM_SHA_256_HASH_SIZE 32 /* SCRAM-SHA-1 uses a hash size of 20, and SCRAM-SHA-256 uses a hash size * of 32. Stack allocations should be large enough for either. */ #define MONGOC_SCRAM_HASH_MAX_SIZE MONGOC_SCRAM_SHA_256_HASH_SIZE #define MONGOC_SCRAM_B64_ENCODED_SIZE(n) (2 * n) #define MONGOC_SCRAM_B64_HASH_MAX_SIZE MONGOC_SCRAM_B64_ENCODED_SIZE (MONGOC_SCRAM_HASH_MAX_SIZE) enum { /* It is unlikely that there will be more than 64 different user accounts * used in a single process */ MONGOC_SCRAM_CACHE_SIZE = 64, }; typedef struct _mongoc_scram_t { int step; char *user; char *pass; char hashed_password[MONGOC_SCRAM_HASH_MAX_SIZE]; uint8_t decoded_salt[MONGOC_SCRAM_B64_HASH_MAX_SIZE]; uint32_t iterations; uint8_t client_key[MONGOC_SCRAM_HASH_MAX_SIZE]; uint8_t server_key[MONGOC_SCRAM_HASH_MAX_SIZE]; uint8_t salted_password[MONGOC_SCRAM_HASH_MAX_SIZE]; char encoded_nonce[48]; int32_t encoded_nonce_len; uint8_t *auth_message; uint32_t auth_messagemax; uint32_t auth_messagelen; #ifdef MONGOC_ENABLE_CRYPTO mongoc_crypto_t crypto; #endif } mongoc_scram_t; #ifdef MONGOC_ENABLE_CRYPTO void _mongoc_scram_init (mongoc_scram_t *scram, mongoc_crypto_hash_algorithm_t algo); #endif void _mongoc_scram_set_pass (mongoc_scram_t *scram, const char *pass); void _mongoc_scram_set_user (mongoc_scram_t *scram, const char *user); void _mongoc_scram_set_server_key (mongoc_scram_t *scram, const uint8_t *server_key, size_t len); void _mongoc_scram_set_salted_password (mongoc_scram_t *scram, const uint8_t *salted_password, size_t len); void _mongoc_scram_destroy (mongoc_scram_t *scram); bool _mongoc_scram_step (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error); /* returns false if this string does not need SASLPrep. It returns true * conservatively, if str might need to be SASLPrep'ed. */ bool _mongoc_sasl_prep_required (const char *str); /* returns the output of SASLPrep as a new string which must be freed. Returns * null on error and sets err. */ char * _mongoc_sasl_prep (const char *in_utf8, bson_error_t *err); /* returns the byte length of the first UTF-8 code point in `s`. * _mongoc_utf8_char_length is exposed for testing */ size_t _mongoc_utf8_char_length (const char *s); /* returns the byte length of the UTF-8 string. Returns -1 if `s` is not a valid * UTF-8 string. * _mongoc_utf8_string_length is exposed for testing. */ ssize_t _mongoc_utf8_string_length (const char *s); /* returns the first Unicode code point in `c`. Returns 0 if length is 0. * `c` must be a valid UTF-8 string. * _mongoc_utf8_get_first_code_point is exposed for testing. */ uint32_t _mongoc_utf8_get_first_code_point (const char *c, size_t length); /* the tables below all come from RFC 3454. They are all range tables, with * value 2*n being the lower bound, and value 2*n + 1 being the upper bound. * Both bounds are exclusive. */ /* A.1 Unassigned code points in Unicode 3.2 * these characters are not allowed for SASLPrep */ static const uint32_t unassigned_codepoint_ranges[] = { 0x0221, 0x0221, 0x0234, 0x024F, 0x02AE, 0x02AF, 0x02EF, 0x02FF, 0x0350, 0x035F, 0x0370, 0x0373, 0x0376, 0x0379, 0x037B, 0x037D, 0x037F, 0x0383, 0x038B, 0x038B, 0x038D, 0x038D, 0x03A2, 0x03A2, 0x03CF, 0x03CF, 0x03F7, 0x03FF, 0x0487, 0x0487, 0x04CF, 0x04CF, 0x04F6, 0x04F7, 0x04FA, 0x04FF, 0x0510, 0x0530, 0x0557, 0x0558, 0x0560, 0x0560, 0x0588, 0x0588, 0x058B, 0x0590, 0x05A2, 0x05A2, 0x05BA, 0x05BA, 0x05C5, 0x05CF, 0x05EB, 0x05EF, 0x05F5, 0x060B, 0x060D, 0x061A, 0x061C, 0x061E, 0x0620, 0x0620, 0x063B, 0x063F, 0x0656, 0x065F, 0x06EE, 0x06EF, 0x06FF, 0x06FF, 0x070E, 0x070E, 0x072D, 0x072F, 0x074B, 0x077F, 0x07B2, 0x0900, 0x0904, 0x0904, 0x093A, 0x093B, 0x094E, 0x094F, 0x0955, 0x0957, 0x0971, 0x0980, 0x0984, 0x0984, 0x098D, 0x098E, 0x0991, 0x0992, 0x09A9, 0x09A9, 0x09B1, 0x09B1, 0x09B3, 0x09B5, 0x09BA, 0x09BB, 0x09BD, 0x09BD, 0x09C5, 0x09C6, 0x09C9, 0x09CA, 0x09CE, 0x09D6, 0x09D8, 0x09DB, 0x09DE, 0x09DE, 0x09E4, 0x09E5, 0x09FB, 0x0A01, 0x0A03, 0x0A04, 0x0A0B, 0x0A0E, 0x0A11, 0x0A12, 0x0A29, 0x0A29, 0x0A31, 0x0A31, 0x0A34, 0x0A34, 0x0A37, 0x0A37, 0x0A3A, 0x0A3B, 0x0A3D, 0x0A3D, 0x0A43, 0x0A46, 0x0A49, 0x0A4A, 0x0A4E, 0x0A58, 0x0A5D, 0x0A5D, 0x0A5F, 0x0A65, 0x0A75, 0x0A80, 0x0A84, 0x0A84, 0x0A8C, 0x0A8C, 0x0A8E, 0x0A8E, 0x0A92, 0x0A92, 0x0AA9, 0x0AA9, 0x0AB1, 0x0AB1, 0x0AB4, 0x0AB4, 0x0ABA, 0x0ABB, 0x0AC6, 0x0AC6, 0x0ACA, 0x0ACA, 0x0ACE, 0x0ACF, 0x0AD1, 0x0ADF, 0x0AE1, 0x0AE5, 0x0AF0, 0x0B00, 0x0B04, 0x0B04, 0x0B0D, 0x0B0E, 0x0B11, 0x0B12, 0x0B29, 0x0B29, 0x0B31, 0x0B31, 0x0B34, 0x0B35, 0x0B3A, 0x0B3B, 0x0B44, 0x0B46, 0x0B49, 0x0B4A, 0x0B4E, 0x0B55, 0x0B58, 0x0B5B, 0x0B5E, 0x0B5E, 0x0B62, 0x0B65, 0x0B71, 0x0B81, 0x0B84, 0x0B84, 0x0B8B, 0x0B8D, 0x0B91, 0x0B91, 0x0B96, 0x0B98, 0x0B9B, 0x0B9B, 0x0B9D, 0x0B9D, 0x0BA0, 0x0BA2, 0x0BA5, 0x0BA7, 0x0BAB, 0x0BAD, 0x0BB6, 0x0BB6, 0x0BBA, 0x0BBD, 0x0BC3, 0x0BC5, 0x0BC9, 0x0BC9, 0x0BCE, 0x0BD6, 0x0BD8, 0x0BE6, 0x0BF3, 0x0C00, 0x0C04, 0x0C04, 0x0C0D, 0x0C0D, 0x0C11, 0x0C11, 0x0C29, 0x0C29, 0x0C34, 0x0C34, 0x0C3A, 0x0C3D, 0x0C45, 0x0C45, 0x0C49, 0x0C49, 0x0C4E, 0x0C54, 0x0C57, 0x0C5F, 0x0C62, 0x0C65, 0x0C70, 0x0C81, 0x0C84, 0x0C84, 0x0C8D, 0x0C8D, 0x0C91, 0x0C91, 0x0CA9, 0x0CA9, 0x0CB4, 0x0CB4, 0x0CBA, 0x0CBD, 0x0CC5, 0x0CC5, 0x0CC9, 0x0CC9, 0x0CCE, 0x0CD4, 0x0CD7, 0x0CDD, 0x0CDF, 0x0CDF, 0x0CE2, 0x0CE5, 0x0CF0, 0x0D01, 0x0D04, 0x0D04, 0x0D0D, 0x0D0D, 0x0D11, 0x0D11, 0x0D29, 0x0D29, 0x0D3A, 0x0D3D, 0x0D44, 0x0D45, 0x0D49, 0x0D49, 0x0D4E, 0x0D56, 0x0D58, 0x0D5F, 0x0D62, 0x0D65, 0x0D70, 0x0D81, 0x0D84, 0x0D84, 0x0D97, 0x0D99, 0x0DB2, 0x0DB2, 0x0DBC, 0x0DBC, 0x0DBE, 0x0DBF, 0x0DC7, 0x0DC9, 0x0DCB, 0x0DCE, 0x0DD5, 0x0DD5, 0x0DD7, 0x0DD7, 0x0DE0, 0x0DF1, 0x0DF5, 0x0E00, 0x0E3B, 0x0E3E, 0x0E5C, 0x0E80, 0x0E83, 0x0E83, 0x0E85, 0x0E86, 0x0E89, 0x0E89, 0x0E8B, 0x0E8C, 0x0E8E, 0x0E93, 0x0E98, 0x0E98, 0x0EA0, 0x0EA0, 0x0EA4, 0x0EA4, 0x0EA6, 0x0EA6, 0x0EA8, 0x0EA9, 0x0EAC, 0x0EAC, 0x0EBA, 0x0EBA, 0x0EBE, 0x0EBF, 0x0EC5, 0x0EC5, 0x0EC7, 0x0EC7, 0x0ECE, 0x0ECF, 0x0EDA, 0x0EDB, 0x0EDE, 0x0EFF, 0x0F48, 0x0F48, 0x0F6B, 0x0F70, 0x0F8C, 0x0F8F, 0x0F98, 0x0F98, 0x0FBD, 0x0FBD, 0x0FCD, 0x0FCE, 0x0FD0, 0x0FFF, 0x1022, 0x1022, 0x1028, 0x1028, 0x102B, 0x102B, 0x1033, 0x1035, 0x103A, 0x103F, 0x105A, 0x109F, 0x10C6, 0x10CF, 0x10F9, 0x10FA, 0x10FC, 0x10FF, 0x115A, 0x115E, 0x11A3, 0x11A7, 0x11FA, 0x11FF, 0x1207, 0x1207, 0x1247, 0x1247, 0x1249, 0x1249, 0x124E, 0x124F, 0x1257, 0x1257, 0x1259, 0x1259, 0x125E, 0x125F, 0x1287, 0x1287, 0x1289, 0x1289, 0x128E, 0x128F, 0x12AF, 0x12AF, 0x12B1, 0x12B1, 0x12B6, 0x12B7, 0x12BF, 0x12BF, 0x12C1, 0x12C1, 0x12C6, 0x12C7, 0x12CF, 0x12CF, 0x12D7, 0x12D7, 0x12EF, 0x12EF, 0x130F, 0x130F, 0x1311, 0x1311, 0x1316, 0x1317, 0x131F, 0x131F, 0x1347, 0x1347, 0x135B, 0x1360, 0x137D, 0x139F, 0x13F5, 0x1400, 0x1677, 0x167F, 0x169D, 0x169F, 0x16F1, 0x16FF, 0x170D, 0x170D, 0x1715, 0x171F, 0x1737, 0x173F, 0x1754, 0x175F, 0x176D, 0x176D, 0x1771, 0x1771, 0x1774, 0x177F, 0x17DD, 0x17DF, 0x17EA, 0x17FF, 0x180F, 0x180F, 0x181A, 0x181F, 0x1878, 0x187F, 0x18AA, 0x1DFF, 0x1E9C, 0x1E9F, 0x1EFA, 0x1EFF, 0x1F16, 0x1F17, 0x1F1E, 0x1F1F, 0x1F46, 0x1F47, 0x1F4E, 0x1F4F, 0x1F58, 0x1F58, 0x1F5A, 0x1F5A, 0x1F5C, 0x1F5C, 0x1F5E, 0x1F5E, 0x1F7E, 0x1F7F, 0x1FB5, 0x1FB5, 0x1FC5, 0x1FC5, 0x1FD4, 0x1FD5, 0x1FDC, 0x1FDC, 0x1FF0, 0x1FF1, 0x1FF5, 0x1FF5, 0x1FFF, 0x1FFF, 0x2053, 0x2056, 0x2058, 0x205E, 0x2064, 0x2069, 0x2072, 0x2073, 0x208F, 0x209F, 0x20B2, 0x20CF, 0x20EB, 0x20FF, 0x213B, 0x213C, 0x214C, 0x2152, 0x2184, 0x218F, 0x23CF, 0x23FF, 0x2427, 0x243F, 0x244B, 0x245F, 0x24FF, 0x24FF, 0x2614, 0x2615, 0x2618, 0x2618, 0x267E, 0x267F, 0x268A, 0x2700, 0x2705, 0x2705, 0x270A, 0x270B, 0x2728, 0x2728, 0x274C, 0x274C, 0x274E, 0x274E, 0x2753, 0x2755, 0x2757, 0x2757, 0x275F, 0x2760, 0x2795, 0x2797, 0x27B0, 0x27B0, 0x27BF, 0x27CF, 0x27EC, 0x27EF, 0x2B00, 0x2E7F, 0x2E9A, 0x2E9A, 0x2EF4, 0x2EFF, 0x2FD6, 0x2FEF, 0x2FFC, 0x2FFF, 0x3040, 0x3040, 0x3097, 0x3098, 0x3100, 0x3104, 0x312D, 0x3130, 0x318F, 0x318F, 0x31B8, 0x31EF, 0x321D, 0x321F, 0x3244, 0x3250, 0x327C, 0x327E, 0x32CC, 0x32CF, 0x32FF, 0x32FF, 0x3377, 0x337A, 0x33DE, 0x33DF, 0x33FF, 0x33FF, 0x4DB6, 0x4DFF, 0x9FA6, 0x9FFF, 0xA48D, 0xA48F, 0xA4C7, 0xABFF, 0xD7A4, 0xD7FF, 0xFA2E, 0xFA2F, 0xFA6B, 0xFAFF, 0xFB07, 0xFB12, 0xFB18, 0xFB1C, 0xFB37, 0xFB37, 0xFB3D, 0xFB3D, 0xFB3F, 0xFB3F, 0xFB42, 0xFB42, 0xFB45, 0xFB45, 0xFBB2, 0xFBD2, 0xFD40, 0xFD4F, 0xFD90, 0xFD91, 0xFDC8, 0xFDCF, 0xFDFD, 0xFDFF, 0xFE10, 0xFE1F, 0xFE24, 0xFE2F, 0xFE47, 0xFE48, 0xFE53, 0xFE53, 0xFE67, 0xFE67, 0xFE6C, 0xFE6F, 0xFE75, 0xFE75, 0xFEFD, 0xFEFE, 0xFF00, 0xFF00, 0xFFBF, 0xFFC1, 0xFFC8, 0xFFC9, 0xFFD0, 0xFFD1, 0xFFD8, 0xFFD9, 0xFFDD, 0xFFDF, 0xFFE7, 0xFFE7, 0xFFEF, 0xFFF8, 0x10000, 0x102FF, 0x1031F, 0x1031F, 0x10324, 0x1032F, 0x1034B, 0x103FF, 0x10426, 0x10427, 0x1044E, 0x1CFFF, 0x1D0F6, 0x1D0FF, 0x1D127, 0x1D129, 0x1D1DE, 0x1D3FF, 0x1D455, 0x1D455, 0x1D49D, 0x1D49D, 0x1D4A0, 0x1D4A1, 0x1D4A3, 0x1D4A4, 0x1D4A7, 0x1D4A8, 0x1D4AD, 0x1D4AD, 0x1D4BA, 0x1D4BA, 0x1D4BC, 0x1D4BC, 0x1D4C1, 0x1D4C1, 0x1D4C4, 0x1D4C4, 0x1D506, 0x1D506, 0x1D50B, 0x1D50C, 0x1D515, 0x1D515, 0x1D51D, 0x1D51D, 0x1D53A, 0x1D53A, 0x1D53F, 0x1D53F, 0x1D545, 0x1D545, 0x1D547, 0x1D549, 0x1D551, 0x1D551, 0x1D6A4, 0x1D6A7, 0x1D7CA, 0x1D7CD, 0x1D800, 0x1FFFD, 0x2A6D7, 0x2F7FF, 0x2FA1E, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD, 0x50000, 0x5FFFD, 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD, 0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD, 0xE0000, 0xE0000, 0xE0002, 0xE001F, 0xE0080, 0xEFFFD}; /* * Table B.1 Commonly mapped to nothing * these are all of the characters that will be mapped to nothing. */ static const uint32_t commonly_mapped_to_nothing_ranges[] = {0x00AD, 0x00AD, 0x034F, 0x034F, 0x1806, 0x1806, 0x180B, 0x180D, 0x200B, 0x200D, 0x2060, 0x2060, 0xFE00, 0xFE0F, 0xFEFF, 0xFEFF}; /* * Table C.1.2 Non-ASCII space characters * these are all of the characters that will be mapped to the space character. * (0x0020) */ static const uint32_t non_ascii_space_character_ranges[] = { 0x00A0, 0x00A0, 0x1680, 0x1680, 0x2000, 0x200B, 0x202F, 0x202F, 0x205F, 0x205F, 0x3000, 0x3000}; /* * these are all of the characters that are "prohibited output" for SASLprep. * The tables that they come from are listed. */ static const uint32_t prohibited_output_ranges[] = { 0x0000, 0x001F, /* C.2.1 */ 0x007F, 0x00A0, /* C.1.2, C.2.1, C.2.2 */ 0x0340, 0x0341, /* C.8 */ 0x06DD, 0x06DD, /* C.2.2 */ 0x070F, 0x070F, /* C.2.2 */ 0x1680, 0x1680, /* C.1.2 */ 0x180E, 0x180E, /* C.2.2 */ 0x2000, 0x200F, /* C.1.2, C.2.2, C.8 */ 0x2028, 0x202F, /* C.1.2, C.2.2, C.8 */ 0x205F, 0x2063, /* C.1.2, C.2.2 */ 0x206A, 0x206F, /* C.2.2, C.8 */ 0x2FF0, 0x2FFB, /* C.7 */ 0x3000, 0x3000, /* C.1.2 */ 0xD800, 0xF8FF, /* C.3, C.5 */ 0xFDD0, 0xFDEF, /* C.4 */ 0xFEFF, 0xFEFF, /* C.2.2 */ 0xFFF9, 0xFFFF, /* C.2.2, C.4, C.6 */ 0x1D173, 0x1D17A, /* C.2.2 */ 0x1FFFE, 0x1FFFF, /* C.4 */ 0x2FFFE, 0x2FFFF, /* C.4 */ 0x3FFFE, 0x3FFFF, /* C.4 */ 0x4FFFE, 0x4FFFF, /* C.4 */ 0x5FFFE, 0x5FFFF, /* C.4 */ 0x6FFFE, 0x6FFFF, /* C.4 */ 0x7FFFE, 0x7FFFF, /* C.4 */ 0x8FFFE, 0x8FFFF, /* C.4 */ 0x9FFFE, 0x9FFFF, /* C.4 */ 0xAFFFE, 0xAFFFF, /* C.4 */ 0xBFFFE, 0xBFFFF, /* C.4 */ 0xCFFFE, 0xCFFFF, /* C.4 */ 0xDFFFE, 0xDFFFF, /* C.4 */ 0xE0001, 0xE0001, /* C.9 */ 0xE0020, 0xE007F, /* C.9 */ 0xEFFFE, 0xEFFFF, /* C.4 */ 0xF0000, 0xFFFFF, /* C.3, C.4 */ 0x100000, 0x10FFFF /* C.3, C.4 */ }; /* D.1 Characters with bidirectional property "R" or "AL" * any string that contains one of these characters cannot contain a character * with bidirectional property "L". */ static const uint32_t RandALCat_bidi_ranges[] = { 0x05BE, 0x05BE, 0x05C0, 0x05C0, 0x05C3, 0x05C3, 0x05D0, 0x05EA, 0x05F0, 0x05F4, 0x061B, 0x061B, 0x061F, 0x061F, 0x0621, 0x063A, 0x0640, 0x064A, 0x066D, 0x066F, 0x0671, 0x06D5, 0x06DD, 0x06DD, 0x06E5, 0x06E6, 0x06FA, 0x06FE, 0x0700, 0x070D, 0x0710, 0x0710, 0x0712, 0x072C, 0x0780, 0x07A5, 0x07B1, 0x07B1, 0x200F, 0x200F, 0xFB1D, 0xFB1D, 0xFB1F, 0xFB28, 0xFB2A, 0xFB36, 0xFB38, 0xFB3C, 0xFB3E, 0xFB3E, 0xFB40, 0xFB41, 0xFB43, 0xFB44, 0xFB46, 0xFBB1, 0xFBD3, 0xFD3D, 0xFD50, 0xFD8F, 0xFD92, 0xFDC7, 0xFDF0, 0xFDFC, 0xFE70, 0xFE74, 0xFE76, 0xFEFC}; /* D.2 Characters with bidirectional property "L" * any string that contains one of these characters cannot contain a character * with bidirectional property "R" or "AL". * */ static const uint32_t LCat_bidi_ranges[] = { 0x0041, 0x005A, 0x0061, 0x007A, 0x00AA, 0x00AA, 0x00B5, 0x00B5, 0x00BA, 0x00BA, 0x00C0, 0x00D6, 0x00D8, 0x00F6, 0x00F8, 0x0220, 0x0222, 0x0233, 0x0250, 0x02AD, 0x02B0, 0x02B8, 0x02BB, 0x02C1, 0x02D0, 0x02D1, 0x02E0, 0x02E4, 0x02EE, 0x02EE, 0x037A, 0x037A, 0x0386, 0x0386, 0x0388, 0x038A, 0x038C, 0x038C, 0x038E, 0x03A1, 0x03A3, 0x03CE, 0x03D0, 0x03F5, 0x0400, 0x0482, 0x048A, 0x04CE, 0x04D0, 0x04F5, 0x04F8, 0x04F9, 0x0500, 0x050F, 0x0531, 0x0556, 0x0559, 0x055F, 0x0561, 0x0587, 0x0589, 0x0589, 0x0903, 0x0903, 0x0905, 0x0939, 0x093D, 0x0940, 0x0949, 0x094C, 0x0950, 0x0950, 0x0958, 0x0961, 0x0964, 0x0970, 0x0982, 0x0983, 0x0985, 0x098C, 0x098F, 0x0990, 0x0993, 0x09A8, 0x09AA, 0x09B0, 0x09B2, 0x09B2, 0x09B6, 0x09B9, 0x09BE, 0x09C0, 0x09C7, 0x09C8, 0x09CB, 0x09CC, 0x09D7, 0x09D7, 0x09DC, 0x09DD, 0x09DF, 0x09E1, 0x09E6, 0x09F1, 0x09F4, 0x09FA, 0x0A05, 0x0A0A, 0x0A0F, 0x0A10, 0x0A13, 0x0A28, 0x0A2A, 0x0A30, 0x0A32, 0x0A33, 0x0A35, 0x0A36, 0x0A38, 0x0A39, 0x0A3E, 0x0A40, 0x0A59, 0x0A5C, 0x0A5E, 0x0A5E, 0x0A66, 0x0A6F, 0x0A72, 0x0A74, 0x0A83, 0x0A83, 0x0A85, 0x0A8B, 0x0A8D, 0x0A8D, 0x0A8F, 0x0A91, 0x0A93, 0x0AA8, 0x0AAA, 0x0AB0, 0x0AB2, 0x0AB3, 0x0AB5, 0x0AB9, 0x0ABD, 0x0AC0, 0x0AC9, 0x0AC9, 0x0ACB, 0x0ACC, 0x0AD0, 0x0AD0, 0x0AE0, 0x0AE0, 0x0AE6, 0x0AEF, 0x0B02, 0x0B03, 0x0B05, 0x0B0C, 0x0B0F, 0x0B10, 0x0B13, 0x0B28, 0x0B2A, 0x0B30, 0x0B32, 0x0B33, 0x0B36, 0x0B39, 0x0B3D, 0x0B3E, 0x0B40, 0x0B40, 0x0B47, 0x0B48, 0x0B4B, 0x0B4C, 0x0B57, 0x0B57, 0x0B5C, 0x0B5D, 0x0B5F, 0x0B61, 0x0B66, 0x0B70, 0x0B83, 0x0B83, 0x0B85, 0x0B8A, 0x0B8E, 0x0B90, 0x0B92, 0x0B95, 0x0B99, 0x0B9A, 0x0B9C, 0x0B9C, 0x0B9E, 0x0B9F, 0x0BA3, 0x0BA4, 0x0BA8, 0x0BAA, 0x0BAE, 0x0BB5, 0x0BB7, 0x0BB9, 0x0BBE, 0x0BBF, 0x0BC1, 0x0BC2, 0x0BC6, 0x0BC8, 0x0BCA, 0x0BCC, 0x0BD7, 0x0BD7, 0x0BE7, 0x0BF2, 0x0C01, 0x0C03, 0x0C05, 0x0C0C, 0x0C0E, 0x0C10, 0x0C12, 0x0C28, 0x0C2A, 0x0C33, 0x0C35, 0x0C39, 0x0C41, 0x0C44, 0x0C60, 0x0C61, 0x0C66, 0x0C6F, 0x0C82, 0x0C83, 0x0C85, 0x0C8C, 0x0C8E, 0x0C90, 0x0C92, 0x0CA8, 0x0CAA, 0x0CB3, 0x0CB5, 0x0CB9, 0x0CBE, 0x0CBE, 0x0CC0, 0x0CC4, 0x0CC7, 0x0CC8, 0x0CCA, 0x0CCB, 0x0CD5, 0x0CD6, 0x0CDE, 0x0CDE, 0x0CE0, 0x0CE1, 0x0CE6, 0x0CEF, 0x0D02, 0x0D03, 0x0D05, 0x0D0C, 0x0D0E, 0x0D10, 0x0D12, 0x0D28, 0x0D2A, 0x0D39, 0x0D3E, 0x0D40, 0x0D46, 0x0D48, 0x0D4A, 0x0D4C, 0x0D57, 0x0D57, 0x0D60, 0x0D61, 0x0D66, 0x0D6F, 0x0D82, 0x0D83, 0x0D85, 0x0D96, 0x0D9A, 0x0DB1, 0x0DB3, 0x0DBB, 0x0DBD, 0x0DBD, 0x0DC0, 0x0DC6, 0x0DCF, 0x0DD1, 0x0DD8, 0x0DDF, 0x0DF2, 0x0DF4, 0x0E01, 0x0E30, 0x0E32, 0x0E33, 0x0E40, 0x0E46, 0x0E4F, 0x0E5B, 0x0E81, 0x0E82, 0x0E84, 0x0E84, 0x0E87, 0x0E88, 0x0E8A, 0x0E8A, 0x0E8D, 0x0E8D, 0x0E94, 0x0E97, 0x0E99, 0x0E9F, 0x0EA1, 0x0EA3, 0x0EA5, 0x0EA5, 0x0EA7, 0x0EA7, 0x0EAA, 0x0EAB, 0x0EAD, 0x0EB0, 0x0EB2, 0x0EB3, 0x0EBD, 0x0EBD, 0x0EC0, 0x0EC4, 0x0EC6, 0x0EC6, 0x0ED0, 0x0ED9, 0x0EDC, 0x0EDD, 0x0F00, 0x0F17, 0x0F1A, 0x0F34, 0x0F36, 0x0F36, 0x0F38, 0x0F38, 0x0F3E, 0x0F47, 0x0F49, 0x0F6A, 0x0F7F, 0x0F7F, 0x0F85, 0x0F85, 0x0F88, 0x0F8B, 0x0FBE, 0x0FC5, 0x0FC7, 0x0FCC, 0x0FCF, 0x0FCF, 0x1000, 0x1021, 0x1023, 0x1027, 0x1029, 0x102A, 0x102C, 0x102C, 0x1031, 0x1031, 0x1038, 0x1038, 0x1040, 0x1057, 0x10A0, 0x10C5, 0x10D0, 0x10F8, 0x10FB, 0x10FB, 0x1100, 0x1159, 0x115F, 0x11A2, 0x11A8, 0x11F9, 0x1200, 0x1206, 0x1208, 0x1246, 0x1248, 0x1248, 0x124A, 0x124D, 0x1250, 0x1256, 0x1258, 0x1258, 0x125A, 0x125D, 0x1260, 0x1286, 0x1288, 0x1288, 0x128A, 0x128D, 0x1290, 0x12AE, 0x12B0, 0x12B0, 0x12B2, 0x12B5, 0x12B8, 0x12BE, 0x12C0, 0x12C0, 0x12C2, 0x12C5, 0x12C8, 0x12CE, 0x12D0, 0x12D6, 0x12D8, 0x12EE, 0x12F0, 0x130E, 0x1310, 0x1310, 0x1312, 0x1315, 0x1318, 0x131E, 0x1320, 0x1346, 0x1348, 0x135A, 0x1361, 0x137C, 0x13A0, 0x13F4, 0x1401, 0x1676, 0x1681, 0x169A, 0x16A0, 0x16F0, 0x1700, 0x170C, 0x170E, 0x1711, 0x1720, 0x1731, 0x1735, 0x1736, 0x1740, 0x1751, 0x1760, 0x176C, 0x176E, 0x1770, 0x1780, 0x17B6, 0x17BE, 0x17C5, 0x17C7, 0x17C8, 0x17D4, 0x17DA, 0x17DC, 0x17DC, 0x17E0, 0x17E9, 0x1810, 0x1819, 0x1820, 0x1877, 0x1880, 0x18A8, 0x1E00, 0x1E9B, 0x1EA0, 0x1EF9, 0x1F00, 0x1F15, 0x1F18, 0x1F1D, 0x1F20, 0x1F45, 0x1F48, 0x1F4D, 0x1F50, 0x1F57, 0x1F59, 0x1F59, 0x1F5B, 0x1F5B, 0x1F5D, 0x1F5D, 0x1F5F, 0x1F7D, 0x1F80, 0x1FB4, 0x1FB6, 0x1FBC, 0x1FBE, 0x1FBE, 0x1FC2, 0x1FC4, 0x1FC6, 0x1FCC, 0x1FD0, 0x1FD3, 0x1FD6, 0x1FDB, 0x1FE0, 0x1FEC, 0x1FF2, 0x1FF4, 0x1FF6, 0x1FFC, 0x200E, 0x200E, 0x2071, 0x2071, 0x207F, 0x207F, 0x2102, 0x2102, 0x2107, 0x2107, 0x210A, 0x2113, 0x2115, 0x2115, 0x2119, 0x211D, 0x2124, 0x2124, 0x2126, 0x2126, 0x2128, 0x2128, 0x212A, 0x212D, 0x212F, 0x2131, 0x2133, 0x2139, 0x213D, 0x213F, 0x2145, 0x2149, 0x2160, 0x2183, 0x2336, 0x237A, 0x2395, 0x2395, 0x249C, 0x24E9, 0x3005, 0x3007, 0x3021, 0x3029, 0x3031, 0x3035, 0x3038, 0x303C, 0x3041, 0x3096, 0x309D, 0x309F, 0x30A1, 0x30FA, 0x30FC, 0x30FF, 0x3105, 0x312C, 0x3131, 0x318E, 0x3190, 0x31B7, 0x31F0, 0x321C, 0x3220, 0x3243, 0x3260, 0x327B, 0x327F, 0x32B0, 0x32C0, 0x32CB, 0x32D0, 0x32FE, 0x3300, 0x3376, 0x337B, 0x33DD, 0x33E0, 0x33FE, 0x3400, 0x4DB5, 0x4E00, 0x9FA5, 0xA000, 0xA48C, 0xAC00, 0xD7A3, 0xD800, 0xFA2D, 0xFA30, 0xFA6A, 0xFB00, 0xFB06, 0xFB13, 0xFB17, 0xFF21, 0xFF3A, 0xFF41, 0xFF5A, 0xFF66, 0xFFBE, 0xFFC2, 0xFFC7, 0xFFCA, 0xFFCF, 0xFFD2, 0xFFD7, 0xFFDA, 0xFFDC, 0x10300, 0x1031E, 0x10320, 0x10323, 0x10330, 0x1034A, 0x10400, 0x10425, 0x10428, 0x1044D, 0x1D000, 0x1D0F5, 0x1D100, 0x1D126, 0x1D12A, 0x1D166, 0x1D16A, 0x1D172, 0x1D183, 0x1D184, 0x1D18C, 0x1D1A9, 0x1D1AE, 0x1D1DD, 0x1D400, 0x1D454, 0x1D456, 0x1D49C, 0x1D49E, 0x1D49F, 0x1D4A2, 0x1D4A2, 0x1D4A5, 0x1D4A6, 0x1D4A9, 0x1D4AC, 0x1D4AE, 0x1D4B9, 0x1D4BB, 0x1D4BB, 0x1D4BD, 0x1D4C0, 0x1D4C2, 0x1D4C3, 0x1D4C5, 0x1D505, 0x1D507, 0x1D50A, 0x1D50D, 0x1D514, 0x1D516, 0x1D51C, 0x1D51E, 0x1D539, 0x1D53B, 0x1D53E, 0x1D540, 0x1D544, 0x1D546, 0x1D546, 0x1D54A, 0x1D550, 0x1D552, 0x1D6A3, 0x1D6A8, 0x1D7C9, 0x20000, 0x2A6D6, 0x2F800, 0x2FA1D, 0xF0000, 0xFFFFD, 0x100000, 0x10FFFD}; BSON_END_DECLS #endif /* MONGOC_SCRAM_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-scram.c0000644000175100001660000012742214760300420022247 0ustar /* Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_CRYPTO #include #include #include #include #include #include #include #include #include #include #include #include typedef struct _mongoc_scram_cache_entry_t { /* book keeping */ bool taken; /* pre-secrets */ char hashed_password[MONGOC_SCRAM_HASH_MAX_SIZE]; uint8_t decoded_salt[MONGOC_SCRAM_B64_HASH_MAX_SIZE]; uint32_t iterations; /* secrets */ uint8_t client_key[MONGOC_SCRAM_HASH_MAX_SIZE]; uint8_t server_key[MONGOC_SCRAM_HASH_MAX_SIZE]; uint8_t salted_password[MONGOC_SCRAM_HASH_MAX_SIZE]; } mongoc_scram_cache_entry_t; #define MONGOC_SCRAM_SERVER_KEY "Server Key" #define MONGOC_SCRAM_CLIENT_KEY "Client Key" /* returns true if the first UTF-8 code point in `s` is valid. */ bool _mongoc_utf8_first_code_point_is_valid (const char *c, size_t length); /* returns whether a character is between two limits (inclusive). */ bool _mongoc_utf8_code_unit_in_range (const uint8_t c, const uint8_t lower, const uint8_t upper); /* returns whether a codepoint exists in the specified table. The table format * is that the 2*n element is the lower bound and the 2*n + 1 is the upper bound * (both inclusive). */ bool _mongoc_utf8_code_point_is_in_table (uint32_t code, const uint32_t *table, size_t size); /* returns the byte length of the UTF-8 code point. Returns -1 if `c` is not a * valid UTF-8 code point. */ ssize_t _mongoc_utf8_code_point_length (uint32_t c); /* converts a Unicode code point to UTF-8 character. Returns how many bytes the * character converted is. Returns -1 if the code point is invalid. * char *out must be large enough to contain all of the code units written to * it. */ ssize_t _mongoc_utf8_code_point_to_str (uint32_t c, char *out); static bson_shared_mutex_t g_scram_cache_rwlock; static bson_once_t init_cache_once_control = BSON_ONCE_INIT; static bson_mutex_t clear_cache_lock; /* * Cache lookups are a linear search through this table. This table is a * constant size, which is small enough that lookup cost is insignificant. * * This can be refactored into a hashmap if the cache size needs to grow larger * in the future, but a linear lookup is currently fast enough and is much * simpler logic to reason about. */ static mongoc_scram_cache_entry_t g_scram_cache[MONGOC_SCRAM_CACHE_SIZE]; static void _mongoc_scram_cache_clear (void) { bson_mutex_lock (&clear_cache_lock); memset (g_scram_cache, 0, sizeof (g_scram_cache)); bson_mutex_unlock (&clear_cache_lock); } static BSON_ONCE_FUN (_mongoc_scram_cache_init) { bson_shared_mutex_init (&g_scram_cache_rwlock); bson_mutex_init (&clear_cache_lock); _mongoc_scram_cache_clear (); BSON_ONCE_RETURN; } static void _mongoc_scram_cache_init_once (void) { bson_once (&init_cache_once_control, _mongoc_scram_cache_init); } static int _scram_hash_size (mongoc_scram_t *scram) { if (scram->crypto.algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_1) { return MONGOC_SCRAM_SHA_1_HASH_SIZE; } else if (scram->crypto.algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_256) { return MONGOC_SCRAM_SHA_256_HASH_SIZE; } else { BSON_UNREACHABLE ("Unexpected crypto algorithm"); } } /* Copies the cache's secrets to scram */ static void _mongoc_scram_cache_apply_secrets (mongoc_scram_cache_entry_t *cache, mongoc_scram_t *scram) { BSON_ASSERT (cache); BSON_ASSERT (scram); memcpy (scram->client_key, cache->client_key, sizeof (scram->client_key)); memcpy (scram->server_key, cache->server_key, sizeof (scram->server_key)); memcpy (scram->salted_password, cache->salted_password, sizeof (scram->salted_password)); } void _mongoc_scram_cache_destroy (mongoc_scram_cache_entry_t *cache) { BSON_ASSERT (cache); bson_free (cache); } /* * Checks whether the cache contains scram's pre-secrets. * Populate `cache` with the values found in the global cache if found. */ static bool _mongoc_scram_cache_has_presecrets (mongoc_scram_cache_entry_t *cache /* out */, const mongoc_scram_t *scram) { bool cache_hit = false; BSON_ASSERT (cache); BSON_ASSERT (scram); _mongoc_scram_cache_init_once (); /* * - Take a read lock * - Search through g_scram_cache if the hashed_password, decoded_salt, and * iterations match an entry. * - If so, then return true * - Otherwise return false */ bson_shared_mutex_lock_shared (&g_scram_cache_rwlock); for (size_t i = 0; i < MONGOC_SCRAM_CACHE_SIZE; i++) { if (g_scram_cache[i].taken) { mongoc_scram_cache_entry_t *cache_entry = &g_scram_cache[i]; cache_hit = !strcmp (cache_entry->hashed_password, scram->hashed_password) && cache_entry->iterations == scram->iterations && !memcmp (cache_entry->decoded_salt, scram->decoded_salt, sizeof (cache_entry->decoded_salt)); if (cache_hit) { /* copy the found cache items into the 'cache' output parameter */ memcpy (cache->client_key, cache_entry->client_key, sizeof (cache->client_key)); memcpy (cache->server_key, cache_entry->server_key, sizeof (cache->server_key)); memcpy (cache->salted_password, cache_entry->salted_password, sizeof (cache->salted_password)); goto done; } } } done: bson_shared_mutex_unlock_shared (&g_scram_cache_rwlock); return cache_hit; } void _mongoc_scram_set_pass (mongoc_scram_t *scram, const char *pass) { BSON_ASSERT (scram); if (scram->pass) { bson_zero_free (scram->pass, strlen (scram->pass)); } scram->pass = pass ? bson_strdup (pass) : NULL; } void _mongoc_scram_set_user (mongoc_scram_t *scram, const char *user) { BSON_ASSERT (scram); bson_free (scram->user); scram->user = user ? bson_strdup (user) : NULL; } void _mongoc_scram_init (mongoc_scram_t *scram, mongoc_crypto_hash_algorithm_t algo) { BSON_ASSERT (scram); memset (scram, 0, sizeof *scram); mongoc_crypto_init (&scram->crypto, algo); } void _mongoc_scram_destroy (mongoc_scram_t *scram) { BSON_ASSERT (scram); bson_free (scram->user); if (scram->pass) { bson_zero_free (scram->pass, strlen (scram->pass)); } memset (scram->hashed_password, 0, sizeof (scram->hashed_password)); bson_free (scram->auth_message); memset (scram, 0, sizeof *scram); } static void _mongoc_scram_cache_insert (const mongoc_scram_t *scram) { bson_shared_mutex_lock (&g_scram_cache_rwlock); again: for (size_t i = 0; i < MONGOC_SCRAM_CACHE_SIZE; i++) { mongoc_scram_cache_entry_t *cache_entry = &g_scram_cache[i]; bool already_exists = !strcmp (cache_entry->hashed_password, scram->hashed_password) && cache_entry->iterations == scram->iterations && !memcmp (cache_entry->decoded_salt, scram->decoded_salt, sizeof (cache_entry->decoded_salt)) && !memcmp (cache_entry->client_key, scram->client_key, sizeof (cache_entry->client_key)) && !memcmp (cache_entry->server_key, scram->server_key, sizeof (cache_entry->server_key)) && !memcmp (cache_entry->salted_password, scram->salted_password, sizeof (cache_entry->salted_password)); if (already_exists) { /* cache entry already populated between read and write lock * acquisition, skipping */ break; } if (!cache_entry->taken) { /* found an empty slot */ memcpy (cache_entry->client_key, scram->client_key, sizeof (cache_entry->client_key)); memcpy (cache_entry->server_key, scram->server_key, sizeof (cache_entry->server_key)); memcpy (cache_entry->salted_password, scram->salted_password, sizeof (cache_entry->salted_password)); memcpy (cache_entry->decoded_salt, scram->decoded_salt, sizeof (cache_entry->decoded_salt)); memcpy (cache_entry->hashed_password, scram->hashed_password, sizeof (cache_entry->hashed_password)); cache_entry->iterations = scram->iterations; cache_entry->taken = true; break; } /* if cache is full, then invalidate the cache and insert again */ if (i == (MONGOC_SCRAM_CACHE_SIZE - 1)) { _mongoc_scram_cache_clear (); goto again; } } bson_shared_mutex_unlock (&g_scram_cache_rwlock); } /* Updates the cache with scram's last-used pre-secrets and secrets */ static void _mongoc_scram_update_cache (const mongoc_scram_t *scram) { mongoc_scram_cache_entry_t cache; bool found = _mongoc_scram_cache_has_presecrets (&cache, scram); if (!found) { /* cache miss, insert this as a new cache entry */ _mongoc_scram_cache_insert (scram); } } static bool _mongoc_scram_buf_write (const char *src, int32_t src_len, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen) { if (src_len < 0) { src_len = (int32_t) strlen (src); } if (*outbuflen + src_len >= outbufmax) { return false; } memcpy (outbuf + *outbuflen, src, src_len); *outbuflen += src_len; return true; } /* generate client-first-message: * n,a=authzid,n=encoded-username,r=client-nonce * * note that a= is optional, so we aren't dealing with that here */ static bool _mongoc_scram_start ( mongoc_scram_t *scram, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t nonce[24]; const char *ptr; bool rval = true; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); if (!scram->user) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: username is not set"); goto FAIL; } if (!scram->pass) { // Apply an empty string as a default. scram->pass = bson_strdup (""); } /* auth message is as big as the outbuf just because */ scram->auth_message = (uint8_t *) bson_malloc (outbufmax); scram->auth_messagemax = outbufmax; /* the server uses a 24 byte random nonce. so we do as well */ if (1 != _mongoc_rand_bytes (nonce, sizeof (nonce))) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not generate a cryptographically " "secure nonce in sasl step 1"); goto FAIL; } scram->encoded_nonce_len = mcommon_b64_ntop (nonce, sizeof (nonce), scram->encoded_nonce, sizeof (scram->encoded_nonce)); if (-1 == scram->encoded_nonce_len) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not encode nonce"); goto FAIL; } if (!_mongoc_scram_buf_write ("n,,n=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } for (ptr = scram->user; *ptr; ptr++) { /* RFC 5802 specifies that ',' and '=' and encoded as '=2C' and '=3D' * respectively in the user name */ switch (*ptr) { case ',': if (!_mongoc_scram_buf_write ("=2C", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; case '=': if (!_mongoc_scram_buf_write ("=3D", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; default: if (!_mongoc_scram_buf_write (ptr, 1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } break; } } if (!_mongoc_scram_buf_write (",r=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write (scram->encoded_nonce, scram->encoded_nonce_len, outbuf, outbufmax, outbuflen)) { goto BUFFER; } /* we have to keep track of the conversation to create a client proof later * on. This copies the message we're crafting from the 'n=' portion onwards * into a buffer we're managing */ if (!_mongoc_scram_buf_write ( (char *) outbuf + 3, *outbuflen - 3, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",", -1, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } goto CLEANUP; BUFFER_AUTH: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer auth message in sasl step1"); goto FAIL; BUFFER: bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer sasl step1"); goto FAIL; FAIL: rval = false; CLEANUP: return rval; } /* Compute the SCRAM step Hi() as defined in RFC5802 */ static bool _mongoc_scram_salt_password (mongoc_scram_t *scram, const char *password, uint32_t password_len, const uint8_t *salt, uint32_t salt_len, uint32_t iterations) { return mongoc_crypto_pbkdf (&scram->crypto, password, password_len, salt, salt_len, iterations, MONGOC_SCRAM_HASH_MAX_SIZE, (unsigned char *) scram->salted_password); } static bool _mongoc_scram_generate_client_proof (mongoc_scram_t *scram, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen) { uint8_t stored_key[MONGOC_SCRAM_HASH_MAX_SIZE]; uint8_t client_signature[MONGOC_SCRAM_HASH_MAX_SIZE]; unsigned char client_proof[MONGOC_SCRAM_HASH_MAX_SIZE]; int i; int r = 0; if (!*scram->client_key) { /* ClientKey := HMAC(saltedPassword, "Client Key") */ mongoc_crypto_hmac (&scram->crypto, scram->salted_password, _scram_hash_size (scram), (uint8_t *) MONGOC_SCRAM_CLIENT_KEY, (int) strlen (MONGOC_SCRAM_CLIENT_KEY), scram->client_key); } /* StoredKey := H(client_key) */ mongoc_crypto_hash (&scram->crypto, scram->client_key, (size_t) _scram_hash_size (scram), stored_key); /* ClientSignature := HMAC(StoredKey, AuthMessage) */ mongoc_crypto_hmac (&scram->crypto, stored_key, _scram_hash_size (scram), scram->auth_message, scram->auth_messagelen, client_signature); /* ClientProof := ClientKey XOR ClientSignature */ for (i = 0; i < _scram_hash_size (scram); i++) { client_proof[i] = scram->client_key[i] ^ client_signature[i]; } r = mcommon_b64_ntop (client_proof, _scram_hash_size (scram), (char *) outbuf + *outbuflen, outbufmax - *outbuflen); if (-1 == r) { return false; } *outbuflen += r; return true; } /* Parse server-first-message of the form: * r=client-nonce|server-nonce,s=user-salt,i=iteration-count * * Generate client-final-message of the form: * c=channel-binding(base64),r=client-nonce|server-nonce,p=client-proof */ static bool _mongoc_scram_step2 (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t *val_r = NULL; uint32_t val_r_len = 0u; uint8_t *val_s = NULL; uint32_t val_s_len = 0u; uint8_t *val_i = NULL; uint32_t val_i_len = 0u; uint8_t **current_val = NULL; uint32_t *current_val_len = NULL; char *tmp = NULL; char *hashed_password = NULL; uint8_t decoded_salt[MONGOC_SCRAM_B64_HASH_MAX_SIZE] = {0}; int32_t decoded_salt_len = 0; /* the decoded salt leaves four trailing bytes to add the int32 0x00000001 */ const int32_t expected_salt_length = _scram_hash_size (scram) - 4; bool rval = true; int iterations = 0; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); if (scram->crypto.algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_1) { /* Auth spec for SCRAM-SHA-1: "The password variable MUST be the mongodb * hashed variant. The mongo hashed variant is computed as hash = HEX( * MD5( UTF8( username + ':mongo:' + plain_text_password )))" */ tmp = bson_strdup_printf ("%s:mongo:%s", scram->user, scram->pass); hashed_password = _mongoc_hex_md5 (tmp); bson_zero_free (tmp, strlen (tmp)); } else if (scram->crypto.algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_256) { /* Auth spec for SCRAM-SHA-256: "Passwords MUST be prepared with SASLprep, * per RFC 5802. Passwords are used directly for key derivation; they * MUST NOT be digested as they are in SCRAM-SHA-1." */ hashed_password = _mongoc_sasl_prep (scram->pass, error); if (!hashed_password) { goto FAIL; } } else { BSON_ASSERT (false); } /* we need all of the incoming message for the final client proof */ if (!_mongoc_scram_buf_write ( (char *) inbuf, inbuflen, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",", -1, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } for (const uint8_t *ptr = inbuf; ptr < inbuf + inbuflen;) { switch (*ptr) { case 'r': current_val = &val_r; current_val_len = &val_r_len; break; case 's': current_val = &val_s; current_val_len = &val_s_len; break; case 'i': current_val = &val_i; current_val_len = &val_i_len; break; default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unknown key (%c) in sasl step 2", *ptr); goto FAIL; } ptr++; if (*ptr != '=') { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid parse state in sasl step 2"); goto FAIL; } ptr++; const uint8_t *const next_comma = (const uint8_t *) memchr (ptr, ',', (inbuf + inbuflen) - ptr); if (next_comma) { *current_val_len = (uint32_t) (next_comma - ptr); } else { *current_val_len = (uint32_t) ((inbuf + inbuflen) - ptr); } *current_val = (uint8_t *) bson_malloc (*current_val_len + 1); memcpy (*current_val, ptr, *current_val_len); (*current_val)[*current_val_len] = '\0'; if (next_comma) { ptr = next_comma + 1; } else { break; } } if (!val_r) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no r param in sasl step 2"); goto FAIL; } if (!val_s) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no s param in sasl step 2"); goto FAIL; } if (!val_i) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no i param in sasl step 2"); goto FAIL; } /* verify our nonce */ if (mcommon_cmp_less_us (val_r_len, scram->encoded_nonce_len) || mongoc_memcmp (val_r, scram->encoded_nonce, scram->encoded_nonce_len)) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: client nonce not repeated in sasl step 2"); } *outbuflen = 0; if (!_mongoc_scram_buf_write ("c=biws,r=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write ((char *) val_r, val_r_len, outbuf, outbufmax, outbuflen)) { goto BUFFER; } if (!_mongoc_scram_buf_write ( (char *) outbuf, *outbuflen, scram->auth_message, scram->auth_messagemax, &scram->auth_messagelen)) { goto BUFFER_AUTH; } if (!_mongoc_scram_buf_write (",p=", -1, outbuf, outbufmax, outbuflen)) { goto BUFFER; } decoded_salt_len = mcommon_b64_pton ((char *) val_s, decoded_salt, sizeof (decoded_salt)); if (-1 == decoded_salt_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unable to decode salt in sasl step2"); goto FAIL; } if (expected_salt_length != decoded_salt_len) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid salt length of %d in sasl step2", decoded_salt_len); goto FAIL; } iterations = (int) bson_ascii_strtoll ((char *) val_i, &tmp, 10); /* tmp holds the location of the failed to parse character. So if it's * null, we got to the end of the string and didn't have a parse error */ if (*tmp) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unable to parse iterations in sasl step2"); goto FAIL; } if (iterations < 0) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: iterations is negative in sasl step2"); goto FAIL; } /* drivers MUST enforce a minimum iteration count of 4096 and MUST error if * the authentication conversation specifies a lower count. This mitigates * downgrade attacks by a man-in-the-middle attacker. */ if (iterations < 4096) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: iterations must be at least 4096"); goto FAIL; } /* Save the presecrets for caching */ if (hashed_password) { bson_strncpy (scram->hashed_password, hashed_password, sizeof (scram->hashed_password)); } scram->iterations = iterations; memcpy (scram->decoded_salt, decoded_salt, sizeof (scram->decoded_salt)); mongoc_scram_cache_entry_t cache; if (_mongoc_scram_cache_has_presecrets (&cache, scram)) { _mongoc_scram_cache_apply_secrets (&cache, scram); } if (!*scram->salted_password && !_mongoc_scram_salt_password (scram, hashed_password, (uint32_t) strlen (hashed_password), decoded_salt, decoded_salt_len, (uint32_t) iterations)) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: failed to salt password"); goto FAIL; } _mongoc_scram_generate_client_proof (scram, outbuf, outbufmax, outbuflen); goto CLEANUP; BUFFER_AUTH: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer auth message in sasl step2"); goto FAIL; BUFFER: bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not buffer sasl step2"); goto FAIL; FAIL: rval = false; CLEANUP: bson_free (val_r); bson_free (val_s); bson_free (val_i); if (hashed_password) { bson_zero_free (hashed_password, strlen (hashed_password)); } return rval; } static bool _mongoc_scram_verify_server_signature (mongoc_scram_t *scram, uint8_t *verification, uint32_t len) { char encoded_server_signature[MONGOC_SCRAM_B64_HASH_MAX_SIZE]; int32_t encoded_server_signature_len; uint8_t server_signature[MONGOC_SCRAM_HASH_MAX_SIZE]; if (!*scram->server_key) { const size_t key_len = strlen (MONGOC_SCRAM_SERVER_KEY); BSON_ASSERT (mcommon_in_range_unsigned (int, key_len)); /* ServerKey := HMAC(SaltedPassword, "Server Key") */ mongoc_crypto_hmac (&scram->crypto, scram->salted_password, _scram_hash_size (scram), (uint8_t *) MONGOC_SCRAM_SERVER_KEY, (int) key_len, scram->server_key); } /* ServerSignature := HMAC(ServerKey, AuthMessage) */ mongoc_crypto_hmac (&scram->crypto, scram->server_key, _scram_hash_size (scram), scram->auth_message, scram->auth_messagelen, server_signature); encoded_server_signature_len = mcommon_b64_ntop ( server_signature, _scram_hash_size (scram), encoded_server_signature, sizeof (encoded_server_signature)); if (encoded_server_signature_len == -1) { return false; } return (len == encoded_server_signature_len) && (mongoc_memcmp (verification, encoded_server_signature, len) == 0); } static bool _mongoc_scram_step3 (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { uint8_t *val_e = NULL; uint32_t val_e_len = 0; uint8_t *val_v = NULL; uint32_t val_v_len = 0; uint8_t **current_val; uint32_t *current_val_len = 0; bool rval = true; BSON_ASSERT (scram); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); for (const uint8_t *ptr = inbuf; ptr < inbuf + inbuflen;) { switch (*ptr) { case 'e': current_val = &val_e; current_val_len = &val_e_len; break; case 'v': current_val = &val_v; current_val_len = &val_v_len; break; default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: unknown key (%c) in sasl step 3", *ptr); goto FAIL; } ptr++; if (*ptr != '=') { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: invalid parse state in sasl step 3"); goto FAIL; } ptr++; const uint8_t *const next_comma = (const uint8_t *) memchr (ptr, ',', (inbuf + inbuflen) - ptr); if (next_comma) { *current_val_len = (uint32_t) (next_comma - ptr); } else { *current_val_len = (uint32_t) ((inbuf + inbuflen) - ptr); } *current_val = (uint8_t *) bson_malloc (*current_val_len + 1); memcpy (*current_val, ptr, *current_val_len); (*current_val)[*current_val_len] = '\0'; if (next_comma) { ptr = next_comma + 1; } else { break; } } *outbuflen = 0; if (val_e) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: authentication failure in sasl step 3 : %s", val_e); goto FAIL; } if (!val_v) { bson_set_error ( error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: no v param in sasl step 3"); goto FAIL; } if (!_mongoc_scram_verify_server_signature (scram, val_v, val_v_len)) { bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, "SCRAM Failure: could not verify server signature in sasl step 3"); goto FAIL; } /* Update the cache if authentication succeeds */ _mongoc_scram_update_cache (scram); goto CLEANUP; FAIL: rval = false; CLEANUP: bson_free (val_e); bson_free (val_v); return rval; } bool _mongoc_scram_step (mongoc_scram_t *scram, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { BSON_ASSERT (scram); BSON_ASSERT (inbuf); BSON_ASSERT (outbuf); BSON_ASSERT (outbuflen); scram->step++; switch (scram->step) { case 1: return _mongoc_scram_start (scram, outbuf, outbufmax, outbuflen, error); case 2: return _mongoc_scram_step2 (scram, inbuf, inbuflen, outbuf, outbufmax, outbuflen, error); case 3: return _mongoc_scram_step3 (scram, inbuf, inbuflen, outbuf, outbufmax, outbuflen, error); default: bson_set_error (error, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_NOT_DONE, "SCRAM Failure: maximum steps detected"); return false; } } bool _mongoc_sasl_prep_required (const char *str) { BSON_ASSERT_PARAM (str); unsigned char c; while (*str) { c = (unsigned char) *str; /* characters below 32 contain all of the control characters. * characters above 127 are multibyte UTF-8 characters. * character 127 is the DEL character. */ if (c < 32 || c >= 127) { return true; } str++; } return false; } char * _mongoc_sasl_prep_impl (const char *name, const char *in_utf8, bson_error_t *err) { BSON_ASSERT_PARAM (name); BSON_ASSERT_PARAM (in_utf8); uint32_t *utf8_codepoints; ssize_t num_chars; uint8_t *out_utf8; #define SASL_PREP_ERR_RETURN(msg) \ do { \ bson_set_error (err, MONGOC_ERROR_SCRAM, MONGOC_ERROR_SCRAM_PROTOCOL_ERROR, (msg), name); \ return NULL; \ } while (0) /* 1. convert str to Unicode codepoints. */ /* preflight to get the destination length. */ num_chars = _mongoc_utf8_string_length (in_utf8); if (num_chars == -1) { SASL_PREP_ERR_RETURN ("could not calculate UTF-8 length of %s"); } /* convert to unicode. */ BSON_ASSERT (mcommon_cmp_less_equal_su (num_chars, SIZE_MAX / sizeof (uint32_t) - 1u)); utf8_codepoints = bson_malloc (sizeof (uint32_t) * ((size_t) num_chars + 1u)); /* add one for trailing 0 value. */ const char *c = in_utf8; for (size_t i = 0; i < num_chars; ++i) { const size_t utf8_char_length = _mongoc_utf8_char_length (c); utf8_codepoints[i] = _mongoc_utf8_get_first_code_point (c, utf8_char_length); c += utf8_char_length; } utf8_codepoints[num_chars] = '\0'; /* 2. perform SASLPREP */ // the steps below come directly from RFC 3454: 2. Preparation Overview. // a. Map - For each character in the input, check if it has a mapping (using // the tables) and, if so, replace it with its mapping. // because we will have to map some characters to nothing, we'll use two // pointers: one for reading the original characters (i) and one for writing // the new characters (curr). i will always be >= curr. size_t curr = 0; for (size_t i = 0; i < num_chars; ++i) { if (_mongoc_utf8_code_point_is_in_table (utf8_codepoints[i], non_ascii_space_character_ranges, sizeof (non_ascii_space_character_ranges) / sizeof (uint32_t))) utf8_codepoints[curr++] = 0x0020; else if (_mongoc_utf8_code_point_is_in_table (utf8_codepoints[i], commonly_mapped_to_nothing_ranges, sizeof (commonly_mapped_to_nothing_ranges) / sizeof (uint32_t))) { // effectively skip over the character because we don't increment curr. } else utf8_codepoints[curr++] = utf8_codepoints[i]; } utf8_codepoints[curr] = '\0'; num_chars = curr; // b. Normalize - normalize the result of step `a` using Unicode // normalization. // this is an optional step for stringprep, but Unicode normalization with // form KC is required for SASLPrep. // in order to do this, we must first convert back to UTF-8. // preflight for length size_t utf8_pre_norm_len = 0; for (size_t i = 0; i < num_chars; ++i) { const ssize_t len = _mongoc_utf8_code_point_length (utf8_codepoints[i]); if (len == -1) { bson_free (utf8_codepoints); SASL_PREP_ERR_RETURN ("invalid Unicode code point in %s"); } else { utf8_pre_norm_len += len; } } char *utf8_pre_norm = (char *) bson_malloc (sizeof (char) * (utf8_pre_norm_len + 1)); char *loc = utf8_pre_norm; for (size_t i = 0; i < num_chars; ++i) { const ssize_t utf8_char_length = _mongoc_utf8_code_point_to_str (utf8_codepoints[i], loc); if (utf8_char_length == -1) { bson_free (utf8_pre_norm); bson_free (utf8_codepoints); SASL_PREP_ERR_RETURN ("invalid Unicode code point in %s"); } loc += utf8_char_length; } *loc = '\0'; out_utf8 = (uint8_t *) utf8proc_NFKC ((utf8proc_uint8_t *) utf8_pre_norm); // the last two steps are both checks for characters that should not be // allowed. Because the normalization step is guarenteed to not create any // characters that will cause an error, we will use the utf8_codepoints // codepoints to check (pre-normalization) as to avoid converting back and // forth from UTF-8 to unicode codepoints. // c. Prohibit -- Check for any characters // that are not allowed in the output. If any are found, return an error. for (size_t i = 0; i < num_chars; ++i) { if (_mongoc_utf8_code_point_is_in_table ( utf8_codepoints[i], prohibited_output_ranges, sizeof (prohibited_output_ranges) / sizeof (uint32_t)) || _mongoc_utf8_code_point_is_in_table (utf8_codepoints[i], unassigned_codepoint_ranges, sizeof (unassigned_codepoint_ranges) / sizeof (uint32_t))) { bson_free (out_utf8); bson_free (utf8_pre_norm); bson_free (utf8_codepoints); SASL_PREP_ERR_RETURN ("prohibited character included in %s"); } } // d. Check bidi -- Possibly check for right-to-left characters, and if // any are found, make sure that the whole string satisfies the // requirements for bidirectional strings. If the string does not // satisfy the requirements for bidirectional strings, return an // error. // note: bidi stands for directional (text). Most characters are displayed // left to right but some are displayed right to left. The requirements are // as follows: // 1. If a string contains any RandALCat character, it can't contain an LCat // character // 2. If it contains an RandALCat character, there must be an RandALCat // character at the beginning and the end of the string (does not have to be // the same character) bool contains_LCat = false; bool contains_RandALCar = false; for (size_t i = 0; i < num_chars; ++i) { if (_mongoc_utf8_code_point_is_in_table ( utf8_codepoints[i], LCat_bidi_ranges, sizeof (LCat_bidi_ranges) / sizeof (uint32_t))) { contains_LCat = true; } if (_mongoc_utf8_code_point_is_in_table ( utf8_codepoints[i], RandALCat_bidi_ranges, sizeof (RandALCat_bidi_ranges) / sizeof (uint32_t))) contains_RandALCar = true; } if ( // requirement 1 (contains_RandALCar && contains_LCat) || // requirement 2 (contains_RandALCar && (!_mongoc_utf8_code_point_is_in_table ( utf8_codepoints[0], RandALCat_bidi_ranges, sizeof (RandALCat_bidi_ranges) / sizeof (uint32_t)) || !_mongoc_utf8_code_point_is_in_table (utf8_codepoints[num_chars - 1], RandALCat_bidi_ranges, sizeof (RandALCat_bidi_ranges) / sizeof (uint32_t))))) { bson_free (out_utf8); bson_free (utf8_pre_norm); bson_free (utf8_codepoints); SASL_PREP_ERR_RETURN ("%s does not meet bidirectional requirements"); } bson_free (utf8_pre_norm); bson_free (utf8_codepoints); return (char *) out_utf8; #undef SASL_PREP_ERR_RETURN } char * _mongoc_sasl_prep (const char *in_utf8, bson_error_t *err) { if (_mongoc_sasl_prep_required (in_utf8)) { return _mongoc_sasl_prep_impl ("password", in_utf8, err); } return bson_strdup (in_utf8); } size_t _mongoc_utf8_char_length (const char *s) { BSON_ASSERT_PARAM (s); uint8_t *c = (uint8_t *) s; // UTF-8 characters are either 1, 2, 3, or 4 bytes and the character length // can be determined by the first byte if ((*c & UINT8_C (0x80)) == 0) return 1u; else if ((*c & UINT8_C (0xe0)) == UINT8_C (0xc0)) return 2u; else if ((*c & UINT8_C (0xf0)) == UINT8_C (0xe0)) return 3u; else if ((*c & UINT8_C (0xf8)) == UINT8_C (0xf0)) return 4u; else return 1u; } ssize_t _mongoc_utf8_string_length (const char *s) { BSON_ASSERT_PARAM (s); const uint8_t *c = (uint8_t *) s; ssize_t str_length = 0; while (*c) { const size_t utf8_char_length = _mongoc_utf8_char_length ((char *) c); if (!_mongoc_utf8_first_code_point_is_valid ((char *) c, utf8_char_length)) return -1; str_length++; c += utf8_char_length; } return str_length; } bool _mongoc_utf8_first_code_point_is_valid (const char *c, size_t length) { BSON_ASSERT_PARAM (c); uint8_t *temp_c = (uint8_t *) c; // Referenced table here: // https://lemire.me/blog/2018/05/09/how-quickly-can-you-check-that-a-string-is-valid-unicode-utf-8/ switch (length) { case 1: return _mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0x00), UINT8_C (0x7F)); case 2: return _mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0xC2), UINT8_C (0xDF)) && _mongoc_utf8_code_unit_in_range (temp_c[1], UINT8_C (0x80), UINT8_C (0xBF)); case 3: // Four options, separated by || return (_mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0xE0), UINT8_C (0xE0)) && _mongoc_utf8_code_unit_in_range (temp_c[1], UINT8_C (0xA0), UINT8_C (0xBF)) && _mongoc_utf8_code_unit_in_range (temp_c[2], UINT8_C (0x80), UINT8_C (0xBF))) || (_mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0xE1), UINT8_C (0xEC)) && _mongoc_utf8_code_unit_in_range (temp_c[1], UINT8_C (0x80), UINT8_C (0xBF)) && _mongoc_utf8_code_unit_in_range (temp_c[2], UINT8_C (0x80), UINT8_C (0xBF))) || (_mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0xED), UINT8_C (0xED)) && _mongoc_utf8_code_unit_in_range (temp_c[1], UINT8_C (0x80), UINT8_C (0x9F)) && _mongoc_utf8_code_unit_in_range (temp_c[2], UINT8_C (0x80), UINT8_C (0xBF))) || (_mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0xEE), UINT8_C (0xEF)) && _mongoc_utf8_code_unit_in_range (temp_c[1], UINT8_C (0x80), UINT8_C (0xBF)) && _mongoc_utf8_code_unit_in_range (temp_c[2], UINT8_C (0x80), UINT8_C (0xBF))); case 4: // Three options, separated by || return (_mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0xF0), UINT8_C (0xF0)) && _mongoc_utf8_code_unit_in_range (temp_c[1], UINT8_C (0x90), UINT8_C (0xBF)) && _mongoc_utf8_code_unit_in_range (temp_c[2], UINT8_C (0x80), UINT8_C (0xBF)) && _mongoc_utf8_code_unit_in_range (temp_c[3], UINT8_C (0x80), UINT8_C (0xBF))) || (_mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0xF1), UINT8_C (0xF3)) && _mongoc_utf8_code_unit_in_range (temp_c[1], UINT8_C (0x80), UINT8_C (0xBF)) && _mongoc_utf8_code_unit_in_range (temp_c[2], UINT8_C (0x80), UINT8_C (0xBF)) && _mongoc_utf8_code_unit_in_range (temp_c[3], UINT8_C (0x80), UINT8_C (0xBF))) || (_mongoc_utf8_code_unit_in_range (temp_c[0], UINT8_C (0xF4), UINT8_C (0xF4)) && _mongoc_utf8_code_unit_in_range (temp_c[1], UINT8_C (0x80), UINT8_C (0x8F)) && _mongoc_utf8_code_unit_in_range (temp_c[2], UINT8_C (0x80), UINT8_C (0xBF)) && _mongoc_utf8_code_unit_in_range (temp_c[3], UINT8_C (0x80), UINT8_C (0xBF))); default: return true; } } bool _mongoc_utf8_code_unit_in_range (const uint8_t c, const uint8_t lower, const uint8_t upper) { return (c >= lower && c <= upper); } bool _mongoc_utf8_code_point_is_in_table (uint32_t code, const uint32_t *table, size_t size) { BSON_ASSERT_PARAM (table); // all tables have size / 2 ranges for (size_t i = 0; i < size; i += 2) { if (code >= table[i] && code <= table[i + 1]) return true; } return false; } uint32_t _mongoc_utf8_get_first_code_point (const char *c, size_t length) { BSON_ASSERT_PARAM (c); uint8_t *temp_c = (uint8_t *) c; switch (length) { case 1: return (uint32_t) temp_c[0]; case 2: return (uint32_t) (((temp_c[0] & UINT8_C (0x1f)) << 6) | (temp_c[1] & UINT8_C (0x3f))); case 3: return (uint32_t) (((temp_c[0] & UINT8_C (0x0f)) << 12) | ((temp_c[1] & UINT8_C (0x3f)) << 6) | (temp_c[2] & UINT8_C (0x3f))); case 4: return (uint32_t) (((temp_c[0] & UINT8_C (0x07)) << 18) | ((temp_c[1] & UINT8_C (0x3f)) << 12) | ((temp_c[2] & UINT8_C (0x3f)) << 6) | (temp_c[3] & UINT8_C (0x3f))); default: return 0; } } ssize_t _mongoc_utf8_code_point_to_str (uint32_t c, char *out) { BSON_ASSERT_PARAM (out); uint8_t *ptr = (uint8_t *) out; if (c <= UINT8_C (0x7F)) { // Plain ASCII ptr[0] = (uint8_t) c; return 1; } else if (c <= 0x07FF) { // 2-byte unicode ptr[0] = (uint8_t) (((c >> 6) & UINT8_C (0x1F)) | UINT8_C (0xC0)); ptr[1] = (uint8_t) (((c >> 0) & UINT8_C (0x3F)) | UINT8_C (0x80)); return 2; } else if (c <= 0xFFFF) { // 3-byte unicode ptr[0] = (uint8_t) (((c >> 12) & UINT8_C (0x0F)) | UINT8_C (0xE0)); ptr[1] = (uint8_t) (((c >> 6) & UINT8_C (0x3F)) | UINT8_C (0x80)); ptr[2] = (uint8_t) ((c & UINT8_C (0x3F)) | UINT8_C (0x80)); return 3; } else if (c <= 0x10FFFF) { // 4-byte unicode ptr[0] = (uint8_t) (((c >> 18) & UINT8_C (0x07)) | UINT8_C (0xF0)); ptr[1] = (uint8_t) (((c >> 12) & UINT8_C (0x3F)) | UINT8_C (0x80)); ptr[2] = (uint8_t) (((c >> 6) & UINT8_C (0x3F)) | UINT8_C (0x80)); ptr[3] = (uint8_t) ((c & UINT8_C (0x3F)) | UINT8_C (0x80)); return 4; } else { return -1; } } ssize_t _mongoc_utf8_code_point_length (uint32_t c) { if (c <= UINT8_C (0x7F)) return 1; else if (c <= 0x07FF) return 2; else if (c <= 0xFFFF) return 3; else if (c <= 0x10FFFF) return 4; else return -1; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-secure-channel-private.h0000644000175100001660000000515414760300420025510 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SECURE_CHANNEL_PRIVATE_H #define MONGOC_SECURE_CHANNEL_PRIVATE_H #include #include #include #include #define SECURITY_WIN32 #include #include #include BSON_BEGIN_DECLS char * _mongoc_secure_channel_extract_subject (const char *filename, const char *passphrase); bool mongoc_secure_channel_setup_ca (mongoc_stream_tls_secure_channel_t *secure_channel, mongoc_ssl_opt_t *opt); bool mongoc_secure_channel_setup_crl (mongoc_stream_tls_secure_channel_t *secure_channel, mongoc_ssl_opt_t *opt); ssize_t mongoc_secure_channel_read (mongoc_stream_tls_t *tls, void *data, size_t data_length); ssize_t mongoc_secure_channel_write (mongoc_stream_tls_t *tls, const void *data, size_t data_length); PCCERT_CONTEXT mongoc_secure_channel_setup_certificate (mongoc_stream_tls_secure_channel_t *secure_channel, mongoc_ssl_opt_t *opt); /* it may require 16k + some overhead to hold one decryptable block of data - do * what cURL does, add 1k */ #define MONGOC_SCHANNEL_BUFFER_INIT_SIZE (17 * 1024) void _mongoc_secure_channel_init_sec_buffer (SecBuffer *buffer, unsigned long buf_type, void *buf_data_ptr, unsigned long buf_byte_size); void _mongoc_secure_channel_init_sec_buffer_desc (SecBufferDesc *desc, SecBuffer *buffer_array, unsigned long buffer_count); void mongoc_secure_channel_realloc_buf (size_t *size, uint8_t **buf, size_t new_size); bool mongoc_secure_channel_handshake_step_1 (mongoc_stream_tls_t *tls, char *hostname, bson_error_t *error); bool mongoc_secure_channel_handshake_step_2 (mongoc_stream_tls_t *tls, char *hostname, bson_error_t *error); bool mongoc_secure_channel_handshake_step_3 (mongoc_stream_tls_t *tls, char *hostname, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_SECURE_CHANNEL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-secure-channel.c0000644000175100001660000010747314760300420024042 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-secure-channel" /* mingw doesn't define this */ #ifndef SECBUFFER_ALERT #define SECBUFFER_ALERT 17 #endif PCCERT_CONTEXT mongoc_secure_channel_setup_certificate_from_file (const char *filename) { char *pem; FILE *file; bool success; HCRYPTKEY hKey; long pem_length; HCRYPTPROV provider; CERT_BLOB public_blob; const char *pem_public; const char *pem_private; LPBYTE blob_private = NULL; PCCERT_CONTEXT cert = NULL; DWORD blob_private_len = 0; DWORD encrypted_private_len = 0; LPBYTE encrypted_private = NULL; file = fopen (filename, "rb"); if (!file) { MONGOC_ERROR ("Couldn't open file '%s'", filename); return false; } fseek (file, 0, SEEK_END); pem_length = ftell (file); fseek (file, 0, SEEK_SET); if (pem_length < 1) { MONGOC_ERROR ("Couldn't determine file size of '%s'", filename); return false; } pem = (char *) bson_malloc0 (pem_length); fread ((void *) pem, 1, pem_length, file); fclose (file); pem_public = strstr (pem, "-----BEGIN CERTIFICATE-----"); pem_private = strstr (pem, "-----BEGIN ENCRYPTED PRIVATE KEY-----"); if (pem_private) { MONGOC_ERROR ("Detected unsupported encrypted private key"); goto fail; } pem_private = strstr (pem, "-----BEGIN RSA PRIVATE KEY-----"); if (!pem_private) { pem_private = strstr (pem, "-----BEGIN PRIVATE KEY-----"); } if (!pem_private) { MONGOC_ERROR ("Can't find private key in '%s'", filename); goto fail; } public_blob.cbData = (DWORD) strlen (pem_public); public_blob.pbData = (BYTE *) pem_public; /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380264%28v=vs.85%29.aspx */ CryptQueryObject (CERT_QUERY_OBJECT_BLOB, /* dwObjectType, blob or file */ &public_blob, /* pvObject, Unicode filename */ CERT_QUERY_CONTENT_FLAG_ALL, /* dwExpectedContentTypeFlags */ CERT_QUERY_FORMAT_FLAG_ALL, /* dwExpectedFormatTypeFlags */ 0, /* dwFlags, reserved for "future use" */ NULL, /* pdwMsgAndCertEncodingType, OUT, unused */ NULL, /* pdwContentType (dwExpectedContentTypeFlags), OUT, unused */ NULL, /* pdwFormatType (dwExpectedFormatTypeFlags,), OUT, unused */ NULL, /* phCertStore, OUT, HCERTSTORE.., unused, for now */ NULL, /* phMsg, OUT, HCRYPTMSG, only for PKC7, unused */ (const void **) &cert /* ppvContext, OUT, the Certificate Context */ ); if (!cert) { MONGOC_ERROR ("Failed to extract public key from '%s'. Error 0x%.8X", filename, (unsigned int) GetLastError ()); goto fail; } /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380285%28v=vs.85%29.aspx */ success = CryptStringToBinaryA (pem_private, /* pszString */ 0, /* cchString */ CRYPT_STRING_BASE64HEADER, /* dwFlags */ NULL, /* pbBinary */ &encrypted_private_len, /* pcBinary, IN/OUT */ NULL, /* pdwSkip */ NULL); /* pdwFlags */ if (!success) { MONGOC_ERROR ("Failed to convert base64 private key. Error 0x%.8X", (unsigned int) GetLastError ()); goto fail; } encrypted_private = (LPBYTE) bson_malloc0 (encrypted_private_len); success = CryptStringToBinaryA ( pem_private, 0, CRYPT_STRING_BASE64HEADER, encrypted_private, &encrypted_private_len, NULL, NULL); if (!success) { MONGOC_ERROR ("Failed to convert base64 private key. Error 0x%.8X", (unsigned int) GetLastError ()); goto fail; } /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa379912%28v=vs.85%29.aspx */ success = CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, /* dwCertEncodingType */ PKCS_RSA_PRIVATE_KEY, /* lpszStructType */ encrypted_private, /* pbEncoded */ encrypted_private_len, /* cbEncoded */ 0, /* dwFlags */ NULL, /* pDecodePara */ NULL, /* pvStructInfo */ &blob_private_len); /* pcbStructInfo */ if (!success) { LPTSTR msg = NULL; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError (), LANG_NEUTRAL, (LPTSTR) &msg, 0, NULL); MONGOC_ERROR ("Failed to parse private key. %s (0x%.8X)", msg, (unsigned int) GetLastError ()); LocalFree (msg); goto fail; } blob_private = (LPBYTE) bson_malloc0 (blob_private_len); success = CryptDecodeObjectEx (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, encrypted_private, encrypted_private_len, 0, NULL, blob_private, &blob_private_len); if (!success) { MONGOC_ERROR ("Failed to parse private key. Error 0x%.8X", (unsigned int) GetLastError ()); goto fail; } /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886%28v=vs.85%29.aspx */ success = CryptAcquireContext (&provider, /* phProv */ NULL, /* pszContainer */ MS_ENHANCED_PROV, /* pszProvider */ PROV_RSA_FULL, /* dwProvType */ CRYPT_VERIFYCONTEXT); /* dwFlags */ if (!success) { MONGOC_ERROR ("CryptAcquireContext failed with error 0x%.8X", (unsigned int) GetLastError ()); goto fail; } /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380207%28v=vs.85%29.aspx */ success = CryptImportKey (provider, /* hProv */ blob_private, /* pbData */ blob_private_len, /* dwDataLen */ 0, /* hPubKey */ 0, /* dwFlags */ &hKey); /* phKey, OUT */ if (!success) { MONGOC_ERROR ("CryptImportKey for private key failed with error 0x%.8X", (unsigned int) GetLastError ()); goto fail; } /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa376573%28v=vs.85%29.aspx */ success = CertSetCertificateContextProperty (cert, /* pCertContext */ CERT_KEY_PROV_HANDLE_PROP_ID, /* dwPropId */ 0, /* dwFlags */ (const void *) provider); /* pvData */ if (success) { TRACE ("%s", "Successfully loaded client certificate"); return cert; } MONGOC_ERROR ("Can't associate private key with public key: 0x%.8X", (unsigned int) GetLastError ()); fail: SecureZeroMemory (pem, pem_length); bson_free (pem); if (encrypted_private) { SecureZeroMemory (encrypted_private, encrypted_private_len); bson_free (encrypted_private); } if (blob_private) { SecureZeroMemory (blob_private, blob_private_len); bson_free (blob_private); } return NULL; } PCCERT_CONTEXT mongoc_secure_channel_setup_certificate (mongoc_stream_tls_secure_channel_t *secure_channel, mongoc_ssl_opt_t *opt) { return mongoc_secure_channel_setup_certificate_from_file (opt->pem_file); } static void _bson_append_szoid (mcommon_string_append_t *retval, PCCERT_CONTEXT cert, const char *label, void *oid) { DWORD oid_len = CertGetNameString (cert, CERT_NAME_ATTR_TYPE, 0, oid, NULL, 0); if (oid_len > 1) { char *tmp = bson_malloc0 (oid_len); CertGetNameString (cert, CERT_NAME_ATTR_TYPE, 0, oid, tmp, oid_len); mcommon_string_append_printf (retval, "%s%s", label, tmp); bson_free (tmp); } } char * _mongoc_secure_channel_extract_subject (const char *filename, const char *passphrase) { PCCERT_CONTEXT cert; cert = mongoc_secure_channel_setup_certificate_from_file (filename); if (!cert) { return NULL; } mcommon_string_append_t retval; mcommon_string_new_as_append (&retval); _bson_append_szoid (&retval, cert, "C=", szOID_COUNTRY_NAME); _bson_append_szoid (&retval, cert, ",ST=", szOID_STATE_OR_PROVINCE_NAME); _bson_append_szoid (&retval, cert, ",L=", szOID_LOCALITY_NAME); _bson_append_szoid (&retval, cert, ",O=", szOID_ORGANIZATION_NAME); _bson_append_szoid (&retval, cert, ",OU=", szOID_ORGANIZATIONAL_UNIT_NAME); _bson_append_szoid (&retval, cert, ",CN=", szOID_COMMON_NAME); _bson_append_szoid (&retval, cert, ",STREET=", szOID_STREET_ADDRESS); return mcommon_string_from_append_destroy_with_steal (&retval); } bool mongoc_secure_channel_setup_ca (mongoc_stream_tls_secure_channel_t *secure_channel, mongoc_ssl_opt_t *opt) { FILE *file; long length; const char *pem_key; HCERTSTORE cert_store = NULL; PCCERT_CONTEXT cert = NULL; DWORD encrypted_cert_len = 0; LPBYTE encrypted_cert = NULL; file = fopen (opt->ca_file, "rb"); if (!file) { MONGOC_ERROR ("Couldn't open file '%s'", opt->ca_file); return false; } fseek (file, 0, SEEK_END); length = ftell (file); fseek (file, 0, SEEK_SET); if (length < 1) { MONGOC_WARNING ("Couldn't determine file size of '%s'", opt->ca_file); return false; } pem_key = (const char *) bson_malloc0 (length); fread ((void *) pem_key, 1, length, file); fclose (file); /* If we have private keys or other fuzz, seek to the good stuff */ pem_key = strstr (pem_key, "-----BEGIN CERTIFICATE-----"); /*printf ("%s\n", pem_key);*/ if (!pem_key) { MONGOC_WARNING ("Couldn't find certificate in '%s'", opt->ca_file); return false; } if (!CryptStringToBinaryA (pem_key, 0, CRYPT_STRING_BASE64HEADER, NULL, &encrypted_cert_len, NULL, NULL)) { MONGOC_ERROR ("Failed to convert BASE64 public key. Error 0x%.8X", (unsigned int) GetLastError ()); return false; } encrypted_cert = (LPBYTE) LocalAlloc (0, encrypted_cert_len); if (!CryptStringToBinaryA (pem_key, 0, CRYPT_STRING_BASE64HEADER, encrypted_cert, &encrypted_cert_len, NULL, NULL)) { MONGOC_ERROR ("Failed to convert BASE64 public key. Error 0x%.8X", (unsigned int) GetLastError ()); return false; } cert = CertCreateCertificateContext (X509_ASN_ENCODING, encrypted_cert, encrypted_cert_len); if (!cert) { MONGOC_WARNING ("Could not convert certificate"); return false; } cert_store = CertOpenStore (CERT_STORE_PROV_SYSTEM, /* provider */ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, /* certificate encoding */ 0, /* unused */ CERT_SYSTEM_STORE_LOCAL_MACHINE, /* dwFlags */ L"Root"); /* system store name. "My" or "Root" */ if (cert_store == NULL) { MONGOC_ERROR ("Error opening certificate store"); return false; } if (CertAddCertificateContextToStore (cert_store, cert, CERT_STORE_ADD_USE_EXISTING, NULL)) { TRACE ("%s", "Added the certificate !"); CertCloseStore (cert_store, 0); return true; } MONGOC_WARNING ("Failed adding the cert"); CertCloseStore (cert_store, 0); return false; } bool mongoc_secure_channel_setup_crl (mongoc_stream_tls_secure_channel_t *secure_channel, mongoc_ssl_opt_t *opt) { HCERTSTORE cert_store = NULL; PCCERT_CONTEXT cert = NULL; LPWSTR str; int chars; chars = MultiByteToWideChar (CP_ACP, 0, opt->crl_file, -1, NULL, 0); if (chars < 1) { MONGOC_WARNING ("Can't determine opt->crl_file length"); return false; } str = (LPWSTR) bson_malloc0 (chars * sizeof (*str)); MultiByteToWideChar (CP_ACP, 0, opt->crl_file, -1, str, chars); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa380264%28v=vs.85%29.aspx */ CryptQueryObject (CERT_QUERY_OBJECT_FILE, /* dwObjectType, blob or file */ str, /* pvObject, Unicode filename */ CERT_QUERY_CONTENT_FLAG_CRL, /* dwExpectedContentTypeFlags */ CERT_QUERY_FORMAT_FLAG_ALL, /* dwExpectedFormatTypeFlags */ 0, /* dwFlags, reserved for "future use" */ NULL, /* pdwMsgAndCertEncodingType, OUT, unused */ NULL, /* pdwContentType (dwExpectedContentTypeFlags), OUT, unused */ NULL, /* pdwFormatType (dwExpectedFormatTypeFlags,), OUT, unused */ NULL, /* phCertStore, OUT, HCERTSTORE.., unused, for now */ NULL, /* phMsg, OUT, HCRYPTMSG, only for PKC7, unused */ (const void **) &cert /* ppvContext, OUT, the Certificate Context */ ); bson_free (str); if (!cert) { MONGOC_WARNING ("Can't extract CRL from '%s'", opt->crl_file); return false; } cert_store = CertOpenStore (CERT_STORE_PROV_SYSTEM, /* provider */ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, /* certificate encoding */ 0, /* unused */ CERT_SYSTEM_STORE_LOCAL_MACHINE, /* dwFlags */ L"Root"); /* system store name. "My" or "Root" */ if (cert_store == NULL) { MONGOC_ERROR ("Error opening certificate store"); CertFreeCertificateContext (cert); return false; } if (CertAddCertificateContextToStore (cert_store, cert, CERT_STORE_ADD_USE_EXISTING, NULL)) { TRACE ("%s", "Added the certificate !"); CertFreeCertificateContext (cert); CertCloseStore (cert_store, 0); return true; } MONGOC_WARNING ("Failed adding the cert"); CertFreeCertificateContext (cert); CertCloseStore (cert_store, 0); return false; } ssize_t mongoc_secure_channel_read (mongoc_stream_tls_t *tls, void *data, size_t data_length) { BSON_ASSERT_PARAM (tls); if (BSON_UNLIKELY (!mcommon_in_range_signed (int32_t, tls->timeout_msec))) { // CDRIVER-4589 MONGOC_ERROR ("timeout_msec value %" PRId64 " exceeds supported 32-bit range", tls->timeout_msec); return -1; } errno = 0; TRACE ("Wanting to read: %zu, timeout is %" PRId64, data_length, tls->timeout_msec); /* 4th argument is minimum bytes, while the data_length is the * size of the buffer. We are totally fine with just one TLS record (few *bytes) **/ const ssize_t length = mongoc_stream_read (tls->base_stream, data, data_length, 0, (int32_t) tls->timeout_msec); TRACE ("Got %zd", length); if (length > 0) { return length; } return 0; } ssize_t mongoc_secure_channel_write (mongoc_stream_tls_t *tls, const void *data, size_t data_length) { BSON_ASSERT_PARAM (tls); if (BSON_UNLIKELY (!mcommon_in_range_signed (int32_t, tls->timeout_msec))) { // CDRIVER-4589 MONGOC_ERROR ("timeout_msec value %" PRId64 " exceeds supported 32-bit range", tls->timeout_msec); return -1; } errno = 0; TRACE ("Wanting to write: %zu", data_length); const ssize_t length = mongoc_stream_write (tls->base_stream, (void *) data, data_length, (int32_t) tls->timeout_msec); TRACE ("Wrote: %zd", length); return length; } void mongoc_secure_channel_realloc_buf (size_t *size, uint8_t **buf, size_t new_size) { *size = bson_next_power_of_two (new_size); *buf = bson_realloc (*buf, *size); } /** * The follow functions comes from one of my favorite project, cURL! * Thank you so much for having gone through the Secure Channel pain for me. * * * Copyright (C) 2012 - 2015, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Based upon the PolarSSL implementation in polarssl.c and polarssl.h: * Copyright (C) 2010, 2011, Hoi-Ho Chan, * * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * Thanks for code and inspiration! */ void _mongoc_secure_channel_init_sec_buffer (SecBuffer *buffer, unsigned long buf_type, void *buf_data_ptr, unsigned long buf_byte_size) { buffer->cbBuffer = buf_byte_size; buffer->BufferType = buf_type; buffer->pvBuffer = buf_data_ptr; } void _mongoc_secure_channel_init_sec_buffer_desc (SecBufferDesc *desc, SecBuffer *buffer_array, unsigned long buffer_count) { desc->ulVersion = SECBUFFER_VERSION; desc->pBuffers = buffer_array; desc->cBuffers = buffer_count; } #define MONGOC_LOG_AND_SET_ERROR(ERROR, DOMAIN, CODE, ...) \ do { \ MONGOC_ERROR (__VA_ARGS__); \ bson_set_error (ERROR, DOMAIN, CODE, __VA_ARGS__); \ } while (0) bool mongoc_secure_channel_handshake_step_1 (mongoc_stream_tls_t *tls, char *hostname, bson_error_t *error) { SecBuffer outbuf; ssize_t written = -1; SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; TRACE ("SSL/TLS connection with '%s' (step 1/3)", hostname); /* setup output buffer */ _mongoc_secure_channel_init_sec_buffer (&outbuf, SECBUFFER_EMPTY, NULL, 0); _mongoc_secure_channel_init_sec_buffer_desc (&outbuf_desc, &outbuf, 1); /* setup request flags */ secure_channel->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* allocate memory for the security context handle */ secure_channel->ctxt = (mongoc_secure_channel_ctxt *) bson_malloc0 (sizeof (mongoc_secure_channel_ctxt)); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ sspi_status = InitializeSecurityContext (&secure_channel->cred->cred_handle, /* phCredential */ NULL, /* phContext */ hostname, /* pszTargetName */ secure_channel->req_flags, /* fContextReq */ 0, /* Reserved1, must be 0 */ 0, /* TargetDataRep, unused */ NULL, /* pInput */ 0, /* Reserved2, must be 0 */ &secure_channel->ctxt->ctxt_handle, /* phNewContext OUT param */ &outbuf_desc, /* pOutput OUT param */ &secure_channel->ret_flags, /* pfContextAttr OUT param */ &secure_channel->ctxt->time_stamp /* ptsExpiry OUT param */ ); if (sspi_status != SEC_I_CONTINUE_NEEDED) { MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "initial InitializeSecurityContext failed: %ld", sspi_status); return false; } TRACE ("sending initial handshake data: sending %lu bytes...", outbuf.cbBuffer); /* send initial handshake data which is now stored in output buffer */ written = mongoc_secure_channel_write (tls, outbuf.pvBuffer, outbuf.cbBuffer); FreeContextBuffer (outbuf.pvBuffer); if (outbuf.cbBuffer != (size_t) written) { MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "failed to send initial handshake data: " "sent %zd of %lu bytes", written, outbuf.cbBuffer); return false; } TRACE ("sent initial handshake data: sent %zd bytes", written); secure_channel->recv_unrecoverable_err = 0; secure_channel->recv_sspi_close_notify = false; secure_channel->recv_connection_closed = false; /* continue to second handshake step */ secure_channel->connecting_state = ssl_connect_2; return true; } bool mongoc_secure_channel_handshake_step_2 (mongoc_stream_tls_t *tls, char *hostname, bson_error_t *error) { mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; SECURITY_STATUS sspi_status = SEC_E_OK; ssize_t nread = -1, written = -1; SecBufferDesc outbuf_desc; SecBufferDesc inbuf_desc; SecBuffer outbuf[3]; SecBuffer inbuf[2]; bool doread; int i; doread = (secure_channel->connecting_state != ssl_connect_2_writing) ? true : false; TRACE ("%s", "SSL/TLS connection with endpoint (step 2/3)"); if (!secure_channel->cred || !secure_channel->ctxt) { MONGOC_LOG_AND_SET_ERROR ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "required TLS credentials or context not provided"); return false; } /* grow the buffer if necessary */ if (secure_channel->encdata_length == secure_channel->encdata_offset) { mongoc_secure_channel_realloc_buf ( &secure_channel->encdata_length, &secure_channel->encdata_buffer, secure_channel->encdata_length + 1); } for (;;) { if (doread) { /* read encrypted handshake data from socket */ nread = mongoc_secure_channel_read (tls, (char *) (secure_channel->encdata_buffer + secure_channel->encdata_offset), secure_channel->encdata_length - secure_channel->encdata_offset); if (!nread) { if (MONGOC_ERRNO_IS_AGAIN (errno)) { if (secure_channel->connecting_state != ssl_connect_2_writing) { secure_channel->connecting_state = ssl_connect_2_reading; } TRACE ("%s", "failed to receive handshake, need more data"); return true; } MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "failed to receive handshake, SSL/TLS connection failed"); return false; } /* increase encrypted data buffer offset */ secure_channel->encdata_offset += nread; } TRACE ("encrypted data buffer: offset %d length %d", (int) secure_channel->encdata_offset, (int) secure_channel->encdata_length); /* setup input buffers */ _mongoc_secure_channel_init_sec_buffer (&inbuf[0], SECBUFFER_TOKEN, bson_malloc (secure_channel->encdata_offset), (unsigned long) (secure_channel->encdata_offset & (size_t) 0xFFFFFFFFUL)); _mongoc_secure_channel_init_sec_buffer (&inbuf[1], SECBUFFER_EMPTY, NULL, 0); _mongoc_secure_channel_init_sec_buffer_desc (&inbuf_desc, inbuf, 2); /* setup output buffers */ _mongoc_secure_channel_init_sec_buffer (&outbuf[0], SECBUFFER_TOKEN, NULL, 0); _mongoc_secure_channel_init_sec_buffer (&outbuf[1], SECBUFFER_ALERT, NULL, 0); _mongoc_secure_channel_init_sec_buffer (&outbuf[2], SECBUFFER_EMPTY, NULL, 0); _mongoc_secure_channel_init_sec_buffer_desc (&outbuf_desc, outbuf, 3); if (inbuf[0].pvBuffer == NULL) { MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "unable to allocate memory"); return false; } /* copy received handshake data into input buffer */ memcpy (inbuf[0].pvBuffer, secure_channel->encdata_buffer, secure_channel->encdata_offset); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ sspi_status = InitializeSecurityContext (&secure_channel->cred->cred_handle, &secure_channel->ctxt->ctxt_handle, hostname, secure_channel->req_flags, 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &secure_channel->ret_flags, &secure_channel->ctxt->time_stamp); /* free buffer for received handshake data */ bson_free (inbuf[0].pvBuffer); /* check if the handshake was incomplete */ if (sspi_status == SEC_E_INCOMPLETE_MESSAGE) { secure_channel->connecting_state = ssl_connect_2_reading; TRACE ("%s", "received incomplete message, need more data"); return true; } /* If the server has requested a client certificate, attempt to continue * the handshake without one. This will allow connections to servers which * request a client certificate but do not require it. */ if (sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && !(secure_channel->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { secure_channel->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; secure_channel->connecting_state = ssl_connect_2_writing; TRACE ("%s", "A client certificate has been requested"); return true; } /* check if the handshake needs to be continued */ if (sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) { for (i = 0; i < 3; i++) { /* search for handshake tokens that need to be send */ if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { TRACE ("sending next handshake data: sending %lu bytes...", outbuf[i].cbBuffer); /* send handshake token to server */ written = mongoc_secure_channel_write (tls, outbuf[i].pvBuffer, outbuf[i].cbBuffer); if (outbuf[i].cbBuffer != (size_t) written) { MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "failed to send next handshake data: " "sent %zd of %lu bytes", written, outbuf[i].cbBuffer); return false; } } /* free obsolete buffer */ if (outbuf[i].pvBuffer != NULL) { FreeContextBuffer (outbuf[i].pvBuffer); } } } else { switch (sspi_status) { case SEC_E_WRONG_PRINCIPAL: MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "SSL Certification verification failed: hostname " "doesn't match certificate"); break; case SEC_E_UNTRUSTED_ROOT: MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "SSL Certification verification failed: Untrusted " "root certificate"); break; case SEC_E_CERT_EXPIRED: MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "SSL Certification verification failed: certificate " "has expired"); break; case CRYPT_E_NO_REVOCATION_CHECK: MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "SSL Certification verification failed: certificate " "does not include revocation check."); break; case SEC_E_INSUFFICIENT_MEMORY: case SEC_E_INTERNAL_ERROR: case SEC_E_INVALID_HANDLE: case SEC_E_INVALID_TOKEN: case SEC_E_LOGON_DENIED: case SEC_E_NO_AUTHENTICATING_AUTHORITY: case SEC_E_NO_CREDENTIALS: case SEC_E_TARGET_UNKNOWN: case SEC_E_UNSUPPORTED_FUNCTION: #ifdef SEC_E_APPLICATION_PROTOCOL_MISMATCH /* Not available in VS2010 */ case SEC_E_APPLICATION_PROTOCOL_MISMATCH: #endif default: { LPTSTR msg = NULL; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError (), LANG_NEUTRAL, (LPTSTR) &msg, 0, NULL); MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to initialize security context, error code: " "0x%04X%04X: %s", (unsigned int) (sspi_status >> 16) & 0xffff, (unsigned int) sspi_status & 0xffff, msg); LocalFree (msg); } } return false; } /* check if there was additional remaining encrypted data */ if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { TRACE ("encrypted data length: %lu", inbuf[1].cbBuffer); /* * There are two cases where we could be getting extra data here: * 1) If we're renegotiating a connection and the handshake is already * complete (from the server perspective), it can encrypted app data * (not handshake data) in an extra buffer at this point. * 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a * connection and this extra data is part of the handshake. * We should process the data immediately; waiting for the socket to * be ready may fail since the server is done sending handshake data. */ /* check if the remaining data is less than the total amount * and therefore begins after the already processed data */ if (secure_channel->encdata_offset > inbuf[1].cbBuffer) { memmove (secure_channel->encdata_buffer, (secure_channel->encdata_buffer + secure_channel->encdata_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer); secure_channel->encdata_offset = inbuf[1].cbBuffer; if (sspi_status == SEC_I_CONTINUE_NEEDED) { doread = FALSE; continue; } } } else { secure_channel->encdata_offset = 0; } break; } /* check if the handshake needs to be continued */ if (sspi_status == SEC_I_CONTINUE_NEEDED) { secure_channel->connecting_state = ssl_connect_2_reading; return true; } /* check if the handshake is complete */ if (sspi_status == SEC_E_OK) { secure_channel->connecting_state = ssl_connect_3; TRACE ("%s", "SSL/TLS handshake complete"); } return true; } bool mongoc_secure_channel_handshake_step_3 (mongoc_stream_tls_t *tls, char *hostname, bson_error_t *error) { mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; BSON_ASSERT (ssl_connect_3 == secure_channel->connecting_state); TRACE ("SSL/TLS connection with %s (step 3/3)", hostname); if (!secure_channel->cred) { MONGOC_LOG_AND_SET_ERROR ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "required TLS credentials not provided"); return false; } /* check if the required context attributes are met */ if (secure_channel->ret_flags != secure_channel->req_flags) { MONGOC_LOG_AND_SET_ERROR (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed handshake"); return false; } secure_channel->connecting_state = ssl_connect_done; return true; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-secure-transport-private.h0000644000175100001660000000316514760300420026134 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SECURE_TRANSPORT_PRIVATE_H #define MONGOC_SECURE_TRANSPORT_PRIVATE_H #include #include #include #include BSON_BEGIN_DECLS char * _mongoc_cfstringref_to_cstring (CFStringRef ref); char * _mongoc_secure_transport_extract_subject (const char *filename, const char *passphrase); OSStatus mongoc_secure_transport_write (SSLConnectionRef connection, const void *data, size_t *data_length); OSStatus mongoc_secure_transport_read (SSLConnectionRef connection, void *data, size_t *data_length); bool mongoc_secure_transport_setup_ca (mongoc_stream_tls_secure_transport_t *secure_transport, mongoc_ssl_opt_t *opt); bool mongoc_secure_transport_setup_certificate (mongoc_stream_tls_secure_transport_t *secure_transport, mongoc_ssl_opt_t *opt); void CFReleaseSafe (CFTypeRef cf); BSON_END_DECLS #endif /* MONGOC_SECURE_TRANSPORT_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-secure-transport.c0000644000175100001660000003466014760300420024463 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_SECURE_TRANSPORT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Jailbreak Darwin Private API */ /* * An alternative to using SecIdentityCreate is to use * SecIdentityCreateWithCertificate with a temporary keychain. However, doing so * leads to memory bugs. Unfortunately, using this private API seems to be the * best solution. */ SecIdentityRef SecIdentityCreate (CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey); #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-secure_transport" char * _mongoc_cfstringref_to_cstring (CFStringRef str) { CFIndex length; CFStringEncoding encoding; CFIndex max_size; char *cs; if (!str) { return NULL; } if (CFGetTypeID (str) != CFStringGetTypeID ()) { return NULL; } length = CFStringGetLength (str); encoding = kCFStringEncodingASCII; max_size = CFStringGetMaximumSizeForEncoding (length, encoding) + 1; cs = bson_malloc ((size_t) max_size); if (CFStringGetCString (str, cs, max_size, encoding)) { return cs; } bson_free (cs); return NULL; } static void _bson_append_cftyperef (mcommon_string_append_t *retval, const char *label, CFTypeRef str) { char *cs; if (str) { cs = _mongoc_cfstringref_to_cstring (str); if (cs) { mcommon_string_append_printf (retval, "%s%s", label, cs); bson_free (cs); } else { mcommon_string_append_printf (retval, "%s(null)", label); } } } CFTypeRef _mongoc_secure_transport_dict_get (CFArrayRef values, CFStringRef label) { if (!values || CFGetTypeID (values) != CFArrayGetTypeID ()) { return NULL; } for (CFIndex i = 0; i < CFArrayGetCount (values); ++i) { CFStringRef item_label; CFDictionaryRef item = CFArrayGetValueAtIndex (values, i); if (CFGetTypeID (item) != CFDictionaryGetTypeID ()) { continue; } item_label = CFDictionaryGetValue (item, kSecPropertyKeyLabel); if (item_label && CFStringCompare (item_label, label, 0) == kCFCompareEqualTo) { return CFDictionaryGetValue (item, kSecPropertyKeyValue); } } return NULL; } char * _mongoc_secure_transport_RFC2253_from_cert (SecCertificateRef cert) { CFTypeRef value; CFTypeRef subject_name; CFDictionaryRef cert_dict; cert_dict = SecCertificateCopyValues (cert, NULL, NULL); if (!cert_dict) { return NULL; } subject_name = CFDictionaryGetValue (cert_dict, kSecOIDX509V1SubjectName); if (!subject_name) { CFRelease (cert_dict); return NULL; } subject_name = CFDictionaryGetValue (subject_name, kSecPropertyKeyValue); if (!subject_name) { CFRelease (cert_dict); return NULL; } mcommon_string_append_t retval; mcommon_string_new_as_append (&retval); value = _mongoc_secure_transport_dict_get (subject_name, kSecOIDCountryName); _bson_append_cftyperef (&retval, "C=", value); value = _mongoc_secure_transport_dict_get (subject_name, kSecOIDStateProvinceName); _bson_append_cftyperef (&retval, ",ST=", value); value = _mongoc_secure_transport_dict_get (subject_name, kSecOIDLocalityName); _bson_append_cftyperef (&retval, ",L=", value); value = _mongoc_secure_transport_dict_get (subject_name, kSecOIDOrganizationName); _bson_append_cftyperef (&retval, ",O=", value); value = _mongoc_secure_transport_dict_get (subject_name, kSecOIDOrganizationalUnitName); if (value) { /* Can be either one unit name, or array of unit names */ if (CFGetTypeID (value) == CFStringGetTypeID ()) { _bson_append_cftyperef (&retval, ",OU=", value); } else if (CFGetTypeID (value) == CFArrayGetTypeID ()) { CFIndex len = CFArrayGetCount (value); if (len > 0) { _bson_append_cftyperef (&retval, ",OU=", CFArrayGetValueAtIndex (value, 0)); } if (len > 1) { _bson_append_cftyperef (&retval, ",", CFArrayGetValueAtIndex (value, 1)); } if (len > 2) { _bson_append_cftyperef (&retval, ",", CFArrayGetValueAtIndex (value, 2)); } } } value = _mongoc_secure_transport_dict_get (subject_name, kSecOIDCommonName); _bson_append_cftyperef (&retval, ",CN=", value); value = _mongoc_secure_transport_dict_get (subject_name, kSecOIDStreetAddress); _bson_append_cftyperef (&retval, ",STREET", value); CFRelease (cert_dict); return mcommon_string_from_append_destroy_with_steal (&retval); } static void safe_release (CFTypeRef ref) { if (ref) { CFRelease (ref); } } bool _mongoc_secure_transport_import_pem (const char *filename, const char *passphrase, CFArrayRef *items, SecExternalItemType *type) { SecExternalFormat format = kSecFormatPEMSequence; SecItemImportExportKeyParameters params = {0}; SecTransformRef sec_transform = NULL; CFReadStreamRef read_stream = NULL; CFDataRef dataref = NULL; CFErrorRef error = NULL; CFURLRef url = NULL; OSStatus res; bool r = false; if (!filename) { TRACE ("%s", "No certificate provided"); return false; } params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; params.flags = 0; params.passphrase = NULL; params.alertTitle = NULL; params.alertPrompt = NULL; params.accessRef = NULL; params.keyUsage = NULL; params.keyAttributes = NULL; if (passphrase) { params.passphrase = CFStringCreateWithCString (kCFAllocatorDefault, passphrase, kCFStringEncodingUTF8); } url = CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault, (const UInt8 *) filename, strlen (filename), false); read_stream = CFReadStreamCreateWithFile (kCFAllocatorDefault, url); if (!CFReadStreamOpen (read_stream)) { MONGOC_ERROR ("Cannot find certificate in '%s', error reading file", filename); goto done; } sec_transform = SecTransformCreateReadTransformWithReadStream (read_stream); dataref = SecTransformExecute (sec_transform, &error); if (error) { CFStringRef str = CFErrorCopyDescription (error); MONGOC_ERROR ( "Failed importing PEM '%s': %s", filename, CFStringGetCStringPtr (str, CFStringGetFastestEncoding (str))); CFRelease (str); goto done; } res = SecItemImport (dataref, CFSTR (".pem"), &format, type, 0, ¶ms, NULL, items); if (res) { MONGOC_ERROR ("Failed importing PEM '%s' (code: %d)", filename, res); goto done; } r = true; done: safe_release (dataref); safe_release (sec_transform); safe_release (read_stream); safe_release (url); safe_release (params.passphrase); return r; } char * _mongoc_secure_transport_extract_subject (const char *filename, const char *passphrase) { bool success; char *retval = NULL; CFArrayRef items = NULL; SecExternalItemType type = kSecItemTypeCertificate; success = _mongoc_secure_transport_import_pem (filename, passphrase, &items, &type); if (!success) { return NULL; } if (type == kSecItemTypeAggregate) { for (CFIndex i = 0; i < CFArrayGetCount (items); ++i) { CFTypeID item_id = CFGetTypeID (CFArrayGetValueAtIndex (items, i)); if (item_id == SecCertificateGetTypeID ()) { retval = _mongoc_secure_transport_RFC2253_from_cert ((SecCertificateRef) CFArrayGetValueAtIndex (items, i)); break; } } } else if (type == kSecItemTypeCertificate) { retval = _mongoc_secure_transport_RFC2253_from_cert ((SecCertificateRef) items); } if (items) { CFRelease (items); } return retval; } static const char * SecExternalItemType_to_string (SecExternalItemType value) { switch (value) { case kSecItemTypeUnknown: return "kSecItemTypeUnknown"; case kSecItemTypePrivateKey: return "kSecItemTypePrivateKey"; case kSecItemTypePublicKey: return "kSecItemTypePublicKey"; case kSecItemTypeSessionKey: return "kSecItemTypeSessionKey"; case kSecItemTypeCertificate: return "kSecItemTypeCertificate"; case kSecItemTypeAggregate: return "kSecItemTypeAggregate"; default: return "Unknown"; } } bool mongoc_secure_transport_setup_certificate (mongoc_stream_tls_secure_transport_t *secure_transport, mongoc_ssl_opt_t *opt) { bool success; CFArrayRef items; SecIdentityRef id; SecKeyRef key = NULL; SecCertificateRef cert = NULL; SecExternalItemType type = kSecItemTypeCertificate; if (!opt->pem_file) { TRACE ("%s", "No private key provided, the server won't be able to verify us"); return false; } success = _mongoc_secure_transport_import_pem (opt->pem_file, opt->pem_pwd, &items, &type); if (!success) { /* caller will log an error */ return false; } if (type != kSecItemTypeAggregate) { MONGOC_ERROR ("Cannot work with keys of type %s (%" PRIu32 "). Type is not supported", SecExternalItemType_to_string (type), type); CFRelease (items); return false; } for (CFIndex i = 0; i < CFArrayGetCount (items); ++i) { CFTypeID item_id = CFGetTypeID (CFArrayGetValueAtIndex (items, i)); if (item_id == SecCertificateGetTypeID ()) { cert = (SecCertificateRef) CFArrayGetValueAtIndex (items, i); } else if (item_id == SecKeyGetTypeID ()) { key = (SecKeyRef) CFArrayGetValueAtIndex (items, i); } } if (!cert || !key) { MONGOC_ERROR ("Couldn't find valid private key"); CFRelease (items); return false; } id = SecIdentityCreate (kCFAllocatorDefault, cert, key); secure_transport->my_cert = CFArrayCreateMutable (kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks); CFArrayAppendValue (secure_transport->my_cert, id); CFArrayAppendValue (secure_transport->my_cert, cert); CFRelease (id); /* * Secure Transport assumes the following: * * The certificate references remain valid for the lifetime of the * session. * * The identity specified in certRefs[0] is capable of signing. */ success = !SSLSetCertificate (secure_transport->ssl_ctx_ref, secure_transport->my_cert); TRACE ("Setting client certificate %s", success ? "succeeded" : "failed"); CFRelease (items); return success; } bool mongoc_secure_transport_setup_ca (mongoc_stream_tls_secure_transport_t *secure_transport, mongoc_ssl_opt_t *opt) { CFArrayRef items; SecExternalItemType type = kSecItemTypeCertificate; bool success; if (!opt->ca_file) { TRACE ("%s", "No CA provided, using defaults"); return false; } success = _mongoc_secure_transport_import_pem (opt->ca_file, NULL, &items, &type); if (!success) { MONGOC_ERROR ("Cannot load Certificate Authorities from file \'%s\'", opt->ca_file); return false; } if (type == kSecItemTypeAggregate) { CFMutableArrayRef anchors = CFArrayCreateMutable (kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); for (CFIndex i = 0; i < CFArrayGetCount (items); ++i) { CFTypeID item_id = CFGetTypeID (CFArrayGetValueAtIndex (items, i)); if (item_id == SecCertificateGetTypeID ()) { CFArrayAppendValue (anchors, CFArrayGetValueAtIndex (items, i)); } } secure_transport->anchors = anchors; CFRelease (items); } else if (type == kSecItemTypeCertificate) { secure_transport->anchors = items; } else { CFRelease (items); } /* This should be SSLSetCertificateAuthorities But the /TLS/ tests fail * when it is */ success = !SSLSetTrustedRoots (secure_transport->ssl_ctx_ref, secure_transport->anchors, true); TRACE ("Setting certificate authority %s (%s)", success ? "succeeded" : "failed", opt->ca_file); return success; } OSStatus mongoc_secure_transport_read (SSLConnectionRef connection, void *data, size_t *data_length) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) connection; ssize_t length; ENTRY; errno = 0; /* 4 arguments is *min_bytes* -- This is not a negotiation. * Secure Transport wants all or nothing. We must continue reading until * we get this amount, or timeout */ length = mongoc_stream_read (tls->base_stream, data, *data_length, *data_length, tls->timeout_msec); if (length > 0) { *data_length = length; RETURN (noErr); } if (length == 0) { RETURN (errSSLClosedGraceful); } switch (errno) { case ENOENT: RETURN (errSSLClosedGraceful); break; case ECONNRESET: RETURN (errSSLClosedAbort); break; case EAGAIN: RETURN (errSSLWouldBlock); break; default: RETURN (-36); /* ioErr */ break; } } OSStatus mongoc_secure_transport_write (SSLConnectionRef connection, const void *data, size_t *data_length) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) connection; ssize_t length; ENTRY; errno = 0; length = mongoc_stream_write (tls->base_stream, (void *) data, *data_length, tls->timeout_msec); if (length >= 0) { *data_length = length; RETURN (noErr); } switch (errno) { case EAGAIN: RETURN (errSSLWouldBlock); default: RETURN (-36); /* ioErr */ } } void CFReleaseSafe (CFTypeRef cf) { if (cf != NULL) { CFRelease (cf); } } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-api-private.h0000644000175100001660000000165114760300420024667 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SERVER_API_PRIVATE_H #define MONGOC_SERVER_API_PRIVATE_H #include struct _mongoc_server_api_t { mongoc_server_api_version_t version; mongoc_optional_t strict; mongoc_optional_t deprecation_errors; }; #endif /* MONGOC_SERVER_API_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-api.c0000644000175100001660000000530614760300420023213 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include const char * mongoc_server_api_version_to_string (mongoc_server_api_version_t version) { switch (version) { case MONGOC_SERVER_API_V1: return "1"; default: return NULL; } } bool mongoc_server_api_version_from_string (const char *version, mongoc_server_api_version_t *out) { if (strcmp (version, "1") == 0) { *out = MONGOC_SERVER_API_V1; return true; } return false; } mongoc_server_api_t * mongoc_server_api_new (mongoc_server_api_version_t version) { mongoc_server_api_t *api; api = (mongoc_server_api_t *) bson_malloc0 (sizeof (mongoc_server_api_t)); api->version = version; mongoc_optional_init (&api->strict); mongoc_optional_init (&api->deprecation_errors); return api; } mongoc_server_api_t * mongoc_server_api_copy (const mongoc_server_api_t *api) { mongoc_server_api_t *copy; if (!api) { return NULL; } copy = (mongoc_server_api_t *) bson_malloc0 (sizeof (mongoc_server_api_t)); copy->version = api->version; mongoc_optional_copy (&api->strict, ©->strict); mongoc_optional_copy (&api->deprecation_errors, ©->deprecation_errors); return copy; } void mongoc_server_api_destroy (mongoc_server_api_t *api) { if (!api) { return; } bson_free (api); } void mongoc_server_api_strict (mongoc_server_api_t *api, bool strict) { BSON_ASSERT (api); mongoc_optional_set_value (&api->strict, strict); } void mongoc_server_api_deprecation_errors (mongoc_server_api_t *api, bool deprecation_errors) { BSON_ASSERT (api); mongoc_optional_set_value (&api->deprecation_errors, deprecation_errors); } const mongoc_optional_t * mongoc_server_api_get_deprecation_errors (const mongoc_server_api_t *api) { BSON_ASSERT (api); return &api->deprecation_errors; } const mongoc_optional_t * mongoc_server_api_get_strict (const mongoc_server_api_t *api) { BSON_ASSERT (api); return &api->strict; } mongoc_server_api_version_t mongoc_server_api_get_version (const mongoc_server_api_t *api) { BSON_ASSERT (api); return api->version; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-api.h0000644000175100001660000000402614760300420023216 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SERVER_API_H #define MONGOC_SERVER_API_H #include #include #include BSON_BEGIN_DECLS typedef enum { MONGOC_SERVER_API_V1 } mongoc_server_api_version_t; typedef struct _mongoc_server_api_t mongoc_server_api_t; MONGOC_EXPORT (const char *) mongoc_server_api_version_to_string (mongoc_server_api_version_t version); MONGOC_EXPORT (bool) mongoc_server_api_version_from_string (const char *version, mongoc_server_api_version_t *out); MONGOC_EXPORT (mongoc_server_api_t *) mongoc_server_api_new (mongoc_server_api_version_t version) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_server_api_t *) mongoc_server_api_copy (const mongoc_server_api_t *api) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_server_api_destroy (mongoc_server_api_t *api); MONGOC_EXPORT (void) mongoc_server_api_strict (mongoc_server_api_t *api, bool strict); MONGOC_EXPORT (void) mongoc_server_api_deprecation_errors (mongoc_server_api_t *api, bool deprecation_errors); MONGOC_EXPORT (const mongoc_optional_t *) mongoc_server_api_get_deprecation_errors (const mongoc_server_api_t *api); MONGOC_EXPORT (const mongoc_optional_t *) mongoc_server_api_get_strict (const mongoc_server_api_t *api); MONGOC_EXPORT (mongoc_server_api_version_t) mongoc_server_api_get_version (const mongoc_server_api_t *api); BSON_END_DECLS #endif /* MONGOC_SERVER_API_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-description-private.h0000644000175100001660000002076414760300420026447 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SERVER_DESCRIPTION_PRIVATE_H #define MONGOC_SERVER_DESCRIPTION_PRIVATE_H #include #include #include #define MONGOC_DEFAULT_WIRE_VERSION 0 #define MONGOC_DEFAULT_WRITE_BATCH_SIZE 1000 #define MONGOC_DEFAULT_BSON_OBJ_SIZE 16 * 1024 * 1024 #define MONGOC_DEFAULT_MAX_MSG_SIZE 48000000 /* This is slightly out-of-spec as of the current version of the spec (1.0.0), * but SPEC-1397 plans to amend "Size limits and Wire Protocol Considerations" * to say that drivers MAY split with a reduced maxBsonObjectSize or * maxMessageSizeBytes * depending on the implementation. It is less invasive for libmongoc to split * OP_MSG payload type 1 with a reduced maxMessageSizeBytes and convert it to a * payload type 0 * rather than split a payload type 0 with a reduced maxBsonObjectSize. */ #define MONGOC_REDUCED_MAX_MSG_SIZE_FOR_FLE 2097152 #define MONGOC_NO_SESSIONS -1 #define MONGOC_IDLE_WRITE_PERIOD_MS 10 * 1000 /* represent a server or topology with no replica set config version */ #define MONGOC_NO_SET_VERSION -1 #define MONGOC_RTT_UNSET -1 #define MONGOC_NO_SERVER_CONNECTION_ID -1 typedef enum { MONGOC_SERVER_UNKNOWN, MONGOC_SERVER_STANDALONE, MONGOC_SERVER_MONGOS, MONGOC_SERVER_POSSIBLE_PRIMARY, MONGOC_SERVER_RS_PRIMARY, MONGOC_SERVER_RS_SECONDARY, MONGOC_SERVER_RS_ARBITER, MONGOC_SERVER_RS_OTHER, MONGOC_SERVER_RS_GHOST, MONGOC_SERVER_LOAD_BALANCER, MONGOC_SERVER_DESCRIPTION_TYPES, } mongoc_server_description_type_t; struct _mongoc_server_description_t { uint32_t id; mongoc_host_list_t host; int64_t round_trip_time_msec; int64_t last_update_time_usec; bson_t last_hello_response; bool has_hello_response; bool hello_ok; bool opened; const char *connection_address; /* SDAM dictates storing me/hosts/passives/arbiters after being "normalized * to lower-case" Instead, they are stored in the casing they are received, * but compared case insensitively. This should be addressed in CDRIVER-3527. */ const char *me; const char *set_name; bson_error_t error; mongoc_server_description_type_t type; int32_t min_wire_version; int32_t max_wire_version; int32_t max_msg_size; int32_t max_bson_obj_size; int32_t max_write_batch_size; int64_t session_timeout_minutes; /* hosts, passives, and arbiters are stored as a BSON array, but compared * case insensitively. This should be improved in CDRIVER-3527. */ bson_t hosts; bson_t passives; bson_t arbiters; bson_t tags; const char *current_primary; int64_t set_version; bson_oid_t election_id; int64_t last_write_date_ms; bson_t compressors; bson_t topology_version; /* The generation is incremented every time connections to this server should be invalidated. This happens when: 1. a monitor receives a network error 2. an app thread receives any network error before completing a handshake 3. an app thread receives a non-timeout network error after the handshake 4. an app thread receives a "not primary" or "node is recovering" error from a pre-4.2 server. */ /* generation only applies to a server description tied to a connection. * It represents the generation number for this connection. */ uint32_t generation; /* _generation_map_ stores all generations for all service IDs associated * with this server. _generation_map_ is only accessed on the server * description for monitoring. In non-load-balanced mode, there are no * service IDs. The only server generation is mapped from kZeroObjectId */ mongoc_generation_map_t *_generation_map_; bson_oid_t service_id; int64_t server_connection_id; }; /** Get a mutable pointer to the server's generation map */ static BSON_INLINE mongoc_generation_map_t * mc_tpl_sd_generation_map (mongoc_server_description_t *sd) { return sd->_generation_map_; } /** Get a const pointer to the server's generation map */ static BSON_INLINE const mongoc_generation_map_t * mc_tpl_sd_generation_map_const (const mongoc_server_description_t *sd) { return sd->_generation_map_; } /** * @brief Increment the generation number on the given server for the associated * service ID. */ static BSON_INLINE void mc_tpl_sd_increment_generation (mongoc_server_description_t *sd, const bson_oid_t *service_id) { mongoc_generation_map_increment (mc_tpl_sd_generation_map (sd), service_id); } /** * @brief Get the generation number of the given server description for the * associated service ID. */ static BSON_INLINE uint32_t mc_tpl_sd_get_generation (const mongoc_server_description_t *sd, const bson_oid_t *service_id) { return mongoc_generation_map_get (mc_tpl_sd_generation_map_const (sd), service_id); } void mongoc_server_description_init (mongoc_server_description_t *sd, const char *address, uint32_t id); bool mongoc_server_description_has_rs_member (const mongoc_server_description_t *description, const char *address); bool mongoc_server_description_has_set_version (const mongoc_server_description_t *description); bool mongoc_server_description_has_election_id (const mongoc_server_description_t *description); void mongoc_server_description_cleanup (mongoc_server_description_t *sd); void mongoc_server_description_reset (mongoc_server_description_t *sd); void mongoc_server_description_set_state (mongoc_server_description_t *description, mongoc_server_description_type_t type); void mongoc_server_description_set_set_version (mongoc_server_description_t *description, int64_t set_version); void mongoc_server_description_set_election_id (mongoc_server_description_t *description, const bson_oid_t *election_id); void mongoc_server_description_update_rtt (mongoc_server_description_t *server, int64_t rtt_msec); void mongoc_server_description_handle_hello (mongoc_server_description_t *sd, const bson_t *hello_response, int64_t rtt_msec, const bson_error_t *error /* IN */); void mongoc_server_description_filter_stale (const mongoc_server_description_t **sds, size_t sds_len, const mongoc_server_description_t *primary, int64_t heartbeat_frequency_ms, const mongoc_read_prefs_t *read_prefs); void mongoc_server_description_filter_tags (const mongoc_server_description_t **descriptions, size_t description_len, const mongoc_read_prefs_t *read_prefs); /* Compares server descriptions following the "Server Description Equality" * rules. Not all fields are considered. */ bool _mongoc_server_description_equal (const mongoc_server_description_t *sd1, const mongoc_server_description_t *sd2); int mongoc_server_description_topology_version_cmp (const bson_t *tv1, const bson_t *tv2); void mongoc_server_description_set_topology_version (mongoc_server_description_t *sd, const bson_t *tv); bool mongoc_server_description_has_service_id (const mongoc_server_description_t *description); typedef enum { MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_SERVER_HOST = (1 << 0), MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_SERVER_PORT = (1 << 1), MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_SERVER_CONNECTION_ID = (1 << 2), MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_SERVICE_ID = (1 << 3), MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_TYPE = (1 << 4), MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_ADDRESS = (1 << 5), } mongoc_server_description_content_flags_t; bool mongoc_server_description_append_contents_to_bson (const mongoc_server_description_t *sd, bson_t *bson, mongoc_server_description_content_flags_t flags); #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-description.c0000644000175100001660000012376014760300420024772 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ALPHA 0.2 static bool _match_tag_set (const mongoc_server_description_t *sd, bson_iter_t *tag_set_iter); /* Destroy allocated resources within @description, but don't free it */ void mongoc_server_description_cleanup (mongoc_server_description_t *sd) { BSON_ASSERT (sd); bson_destroy (&sd->last_hello_response); bson_destroy (&sd->hosts); bson_destroy (&sd->passives); bson_destroy (&sd->arbiters); bson_destroy (&sd->tags); bson_destroy (&sd->compressors); bson_destroy (&sd->topology_version); mongoc_generation_map_destroy (sd->_generation_map_); } /* Reset fields inside this sd, but keep same id, host information, RTT, generation, topology version, and leave hello in empty inited state */ void mongoc_server_description_reset (mongoc_server_description_t *sd) { BSON_ASSERT (sd); memset (&sd->error, 0, sizeof sd->error); sd->set_name = NULL; sd->type = MONGOC_SERVER_UNKNOWN; sd->min_wire_version = MONGOC_DEFAULT_WIRE_VERSION; sd->max_wire_version = MONGOC_DEFAULT_WIRE_VERSION; sd->max_msg_size = MONGOC_DEFAULT_MAX_MSG_SIZE; sd->max_bson_obj_size = MONGOC_DEFAULT_BSON_OBJ_SIZE; sd->max_write_batch_size = MONGOC_DEFAULT_WRITE_BATCH_SIZE; sd->session_timeout_minutes = MONGOC_NO_SESSIONS; sd->last_write_date_ms = -1; sd->hello_ok = false; /* always leave last hello in an init-ed state until we destroy sd */ bson_destroy (&sd->last_hello_response); bson_init (&sd->last_hello_response); sd->has_hello_response = false; sd->last_update_time_usec = bson_get_monotonic_time (); bson_destroy (&sd->hosts); bson_destroy (&sd->passives); bson_destroy (&sd->arbiters); bson_destroy (&sd->tags); bson_destroy (&sd->compressors); bson_init (&sd->hosts); bson_init (&sd->passives); bson_init (&sd->arbiters); bson_init (&sd->tags); bson_init (&sd->compressors); sd->me = NULL; sd->current_primary = NULL; sd->set_version = MONGOC_NO_SET_VERSION; mcommon_oid_set_zero (&sd->election_id); mcommon_oid_set_zero (&sd->service_id); sd->server_connection_id = MONGOC_NO_SERVER_CONNECTION_ID; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_init -- * * Initialize a new server_description_t. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_server_description_init (mongoc_server_description_t *sd, const char *address, uint32_t id) { ENTRY; BSON_ASSERT (sd); BSON_ASSERT (address); sd->id = id; sd->type = MONGOC_SERVER_UNKNOWN; sd->round_trip_time_msec = MONGOC_RTT_UNSET; sd->generation = 0; sd->opened = false; sd->_generation_map_ = mongoc_generation_map_new (); if (!_mongoc_host_list_from_string (&sd->host, address)) { MONGOC_WARNING ("Failed to parse uri for %s", address); return; } sd->connection_address = sd->host.host_and_port; bson_init (&sd->last_hello_response); bson_init (&sd->hosts); bson_init (&sd->passives); bson_init (&sd->arbiters); bson_init (&sd->tags); bson_init (&sd->compressors); bson_init (&sd->topology_version); mongoc_server_description_reset (sd); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_destroy -- * * Destroy allocated resources within @description and free * @description. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_server_description_destroy (mongoc_server_description_t *description) { ENTRY; if (!description) { EXIT; } mongoc_server_description_cleanup (description); bson_free (description); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_has_rs_member -- * * Return true if this address is included in server's list of rs * members, false otherwise. * * Returns: * true, false * * Side effects: * None * *-------------------------------------------------------------------------- */ bool mongoc_server_description_has_rs_member (const mongoc_server_description_t *server, const char *address) { bson_iter_t member_iter; const bson_t *rs_members[3]; int i; if (server->type != MONGOC_SERVER_UNKNOWN) { rs_members[0] = &server->hosts; rs_members[1] = &server->arbiters; rs_members[2] = &server->passives; for (i = 0; i < 3; i++) { BSON_ASSERT (bson_iter_init (&member_iter, rs_members[i])); while (bson_iter_next (&member_iter)) { if (strcasecmp (address, bson_iter_utf8 (&member_iter, NULL)) == 0) { return true; } } } } return false; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_has_set_version -- * * Did this server's hello response have a "setVersion" field? * * Returns: * True if the server description's setVersion is set. * *-------------------------------------------------------------------------- */ bool mongoc_server_description_has_set_version (const mongoc_server_description_t *description) { return description->set_version != MONGOC_NO_SET_VERSION; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_has_election_id -- * * Did this server's hello response have an "electionId" field? * * Returns: * True if the server description's electionId is set. * *-------------------------------------------------------------------------- */ bool mongoc_server_description_has_election_id (const mongoc_server_description_t *description) { return !mcommon_oid_is_zero (&description->election_id); } /* *-------------------------------------------------------------------------- * * mongoc_server_description_id -- * * Get the id of this server. * * Returns: * Server's id. * *-------------------------------------------------------------------------- */ uint32_t mongoc_server_description_id (const mongoc_server_description_t *description) { return description->id; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_host -- * * Return a reference to the host associated with this server description. * * Returns: * This server description's host, a mongoc_host_list_t * you must * not modify or free. * *-------------------------------------------------------------------------- */ mongoc_host_list_t * mongoc_server_description_host (const mongoc_server_description_t *description) { return &((mongoc_server_description_t *) description)->host; } int64_t mongoc_server_description_last_update_time (const mongoc_server_description_t *description) { return description->last_update_time_usec; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_round_trip_time -- * * Get the round trip time of this server, which is the client's * measurement of the duration of a "hello" command. * * Returns: * The server's round trip time in milliseconds. * *-------------------------------------------------------------------------- */ int64_t mongoc_server_description_round_trip_time (const mongoc_server_description_t *description) { return description->round_trip_time_msec; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_type -- * * Get this server's type, one of the types defined in the Server * Discovery And Monitoring Spec. * * Returns: * A string. * *-------------------------------------------------------------------------- */ const char * mongoc_server_description_type (const mongoc_server_description_t *description) { switch (description->type) { case MONGOC_SERVER_UNKNOWN: return "Unknown"; case MONGOC_SERVER_STANDALONE: return "Standalone"; case MONGOC_SERVER_MONGOS: return "Mongos"; case MONGOC_SERVER_POSSIBLE_PRIMARY: return "PossiblePrimary"; case MONGOC_SERVER_RS_PRIMARY: return "RSPrimary"; case MONGOC_SERVER_RS_SECONDARY: return "RSSecondary"; case MONGOC_SERVER_RS_ARBITER: return "RSArbiter"; case MONGOC_SERVER_RS_OTHER: return "RSOther"; case MONGOC_SERVER_RS_GHOST: return "RSGhost"; case MONGOC_SERVER_LOAD_BALANCER: return "LoadBalancer"; case MONGOC_SERVER_DESCRIPTION_TYPES: default: MONGOC_ERROR ("Invalid mongoc_server_description_t type"); return "Invalid"; } } /* *-------------------------------------------------------------------------- * * mongoc_server_description_hello_response -- * * Return this server's most recent "hello" command response. * * Returns: * A reference to a BSON document, owned by the server description. * *-------------------------------------------------------------------------- */ const bson_t * mongoc_server_description_hello_response (const mongoc_server_description_t *description) { return &description->last_hello_response; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_ismaster -- * * Return this server's most recent "hello" command response. * * Returns: * A reference to a BSON document, owned by the server description. * *-------------------------------------------------------------------------- */ const bson_t * mongoc_server_description_ismaster (const mongoc_server_description_t *description) { return mongoc_server_description_hello_response (description); } /* *-------------------------------------------------------------------------- * * mongoc_server_description_set_state -- * * Set the server description's server type. * *-------------------------------------------------------------------------- */ void mongoc_server_description_set_state (mongoc_server_description_t *description, mongoc_server_description_type_t type) { description->type = type; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_set_set_version -- * * Set the replica set version of this server. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_server_description_set_set_version (mongoc_server_description_t *description, int64_t set_version) { description->set_version = set_version; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_set_election_id -- * * Set the election_id of this server. Copies the given ObjectId or, * if it is NULL, zeroes description's election_id. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_server_description_set_election_id (mongoc_server_description_t *description, const bson_oid_t *election_id) { if (election_id) { bson_oid_copy_unsafe (election_id, &description->election_id); } else { mcommon_oid_set_zero (&description->election_id); } } /* *------------------------------------------------------------------------- * * mongoc_server_description_update_rtt -- * * Calculate this server's rtt calculation using an exponentially- * weighted moving average formula. * * Side effects: * None. * * If rtt_msec is MONGOC_RTT_UNSET, the value is not updated. * *------------------------------------------------------------------------- */ void mongoc_server_description_update_rtt (mongoc_server_description_t *server, int64_t rtt_msec) { if (rtt_msec == MONGOC_RTT_UNSET) { return; } if (server->round_trip_time_msec == MONGOC_RTT_UNSET) { server->round_trip_time_msec = rtt_msec; } else { server->round_trip_time_msec = (int64_t) (ALPHA * rtt_msec + (1 - ALPHA) * server->round_trip_time_msec); } } static void _mongoc_server_description_set_error (mongoc_server_description_t *sd, const bson_error_t *error) { if (error && error->code) { memcpy (&sd->error, error, sizeof (bson_error_t)); } else { bson_set_error (&sd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "unknown error calling hello"); } /* Server Discovery and Monitoring Spec: if the server type changes from a * known type to Unknown its RTT is set to null. */ sd->round_trip_time_msec = MONGOC_RTT_UNSET; } /* *------------------------------------------------------------------------- * * Called during SDAM, from topology description's hello handler, or * when handshaking a connection in _mongoc_cluster_stream_for_server. * * If @hello_response is empty, @error must say why hello failed. * *------------------------------------------------------------------------- */ void mongoc_server_description_handle_hello (mongoc_server_description_t *sd, const bson_t *hello_response, int64_t rtt_msec, const bson_error_t *error /* IN */) { bson_iter_t iter; bson_iter_t child; bool is_primary = false; bool is_shard = false; bool is_secondary = false; bool is_arbiter = false; bool is_replicaset = false; bool is_hidden = false; const uint8_t *bytes; uint32_t len; int num_keys = 0; ENTRY; BSON_ASSERT (sd); mongoc_server_description_reset (sd); if (!hello_response) { _mongoc_server_description_set_error (sd, error); EXIT; } bson_destroy (&sd->last_hello_response); bsonBuild (sd->last_hello_response, insert (*hello_response, not(key ("speculativeAuthenticate")))); sd->has_hello_response = true; /* Only reinitialize the topology version if we have a hello response. * Resetting a server description should not effect the topology version. */ bson_reinit (&sd->topology_version); BSON_ASSERT (bson_iter_init (&iter, &sd->last_hello_response)); while (bson_iter_next (&iter)) { num_keys++; if (strcmp ("ok", bson_iter_key (&iter)) == 0) { if (!bson_iter_as_bool (&iter)) { /* it doesn't really matter what error API we use. the code and * domain will be overwritten. */ (void) _mongoc_cmd_check_ok (hello_response, MONGOC_ERROR_API_VERSION_2, &sd->error); /* TODO CDRIVER-3696: this is an existing bug. If this is handling * a hello reply that is NOT from a handshake, this should not * be considered an auth error. */ /* hello response returned ok: 0. According to auth spec: "If the * hello of the MongoDB Handshake fails with an error, drivers * MUST treat this an authentication error." */ sd->error.domain = MONGOC_ERROR_CLIENT; sd->error.code = MONGOC_ERROR_CLIENT_AUTHENTICATE; GOTO (authfailure); } } else if (strcmp ("isWritablePrimary", bson_iter_key (&iter)) == 0 || strcmp (HANDSHAKE_RESPONSE_LEGACY_HELLO, bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_BOOL (&iter)) GOTO (typefailure); is_primary = bson_iter_bool (&iter); } else if (strcmp ("helloOk", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_BOOL (&iter)) GOTO (typefailure); sd->hello_ok = bson_iter_bool (&iter); } else if (strcmp ("me", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) GOTO (typefailure); sd->me = bson_iter_utf8 (&iter, NULL); } else if (strcmp ("maxMessageSizeBytes", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_INT32 (&iter)) GOTO (typefailure); sd->max_msg_size = bson_iter_int32 (&iter); } else if (strcmp ("maxBsonObjectSize", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_INT32 (&iter)) GOTO (typefailure); sd->max_bson_obj_size = bson_iter_int32 (&iter); } else if (strcmp ("maxWriteBatchSize", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_INT32 (&iter)) GOTO (typefailure); sd->max_write_batch_size = bson_iter_int32 (&iter); } else if (strcmp ("logicalSessionTimeoutMinutes", bson_iter_key (&iter)) == 0) { if (BSON_ITER_HOLDS_NUMBER (&iter)) { sd->session_timeout_minutes = bson_iter_as_int64 (&iter); } else if (BSON_ITER_HOLDS_NULL (&iter)) { /* this arises executing standard JSON tests */ sd->session_timeout_minutes = MONGOC_NO_SESSIONS; } else { GOTO (typefailure); } } else if (strcmp ("minWireVersion", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_INT32 (&iter)) GOTO (typefailure); sd->min_wire_version = bson_iter_int32 (&iter); } else if (strcmp ("maxWireVersion", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_INT32 (&iter)) GOTO (typefailure); sd->max_wire_version = bson_iter_int32 (&iter); } else if (strcmp ("msg", bson_iter_key (&iter)) == 0) { const char *msg; if (!BSON_ITER_HOLDS_UTF8 (&iter)) GOTO (typefailure); msg = bson_iter_utf8 (&iter, NULL); if (msg && 0 == strcmp (msg, "isdbgrid")) { is_shard = true; } } else if (strcmp ("setName", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) GOTO (typefailure); sd->set_name = bson_iter_utf8 (&iter, NULL); } else if (strcmp ("setVersion", bson_iter_key (&iter)) == 0) { mongoc_server_description_set_set_version (sd, bson_iter_as_int64 (&iter)); } else if (strcmp ("electionId", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_OID (&iter)) GOTO (typefailure); mongoc_server_description_set_election_id (sd, bson_iter_oid (&iter)); } else if (strcmp ("secondary", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_BOOL (&iter)) GOTO (typefailure); is_secondary = bson_iter_bool (&iter); } else if (strcmp ("hosts", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_ARRAY (&iter)) GOTO (typefailure); bson_iter_array (&iter, &len, &bytes); bson_destroy (&sd->hosts); BSON_ASSERT (bson_init_static (&sd->hosts, bytes, len)); } else if (strcmp ("passives", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_ARRAY (&iter)) GOTO (typefailure); bson_iter_array (&iter, &len, &bytes); bson_destroy (&sd->passives); BSON_ASSERT (bson_init_static (&sd->passives, bytes, len)); } else if (strcmp ("arbiters", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_ARRAY (&iter)) GOTO (typefailure); bson_iter_array (&iter, &len, &bytes); bson_destroy (&sd->arbiters); BSON_ASSERT (bson_init_static (&sd->arbiters, bytes, len)); } else if (strcmp ("primary", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_UTF8 (&iter)) GOTO (typefailure); sd->current_primary = bson_iter_utf8 (&iter, NULL); } else if (strcmp ("arbiterOnly", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_BOOL (&iter)) GOTO (typefailure); is_arbiter = bson_iter_bool (&iter); } else if (strcmp ("isreplicaset", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_BOOL (&iter)) GOTO (typefailure); is_replicaset = bson_iter_bool (&iter); } else if (strcmp ("tags", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) GOTO (typefailure); bson_iter_document (&iter, &len, &bytes); bson_destroy (&sd->tags); BSON_ASSERT (bson_init_static (&sd->tags, bytes, len)); } else if (strcmp ("hidden", bson_iter_key (&iter)) == 0) { is_hidden = bson_iter_bool (&iter); } else if (strcmp ("lastWrite", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_DOCUMENT (&iter) || !bson_iter_recurse (&iter, &child) || !bson_iter_find (&child, "lastWriteDate") || !BSON_ITER_HOLDS_DATE_TIME (&child)) { GOTO (typefailure); } sd->last_write_date_ms = bson_iter_date_time (&child); } else if (strcmp ("compression", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_ARRAY (&iter)) GOTO (typefailure); bson_iter_array (&iter, &len, &bytes); bson_destroy (&sd->compressors); BSON_ASSERT (bson_init_static (&sd->compressors, bytes, len)); } else if (strcmp ("topologyVersion", bson_iter_key (&iter)) == 0) { bson_t incoming_topology_version; if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) { GOTO (typefailure); } bson_iter_document (&iter, &len, &bytes); BSON_ASSERT (bson_init_static (&incoming_topology_version, bytes, len)); mongoc_server_description_set_topology_version (sd, &incoming_topology_version); bson_destroy (&incoming_topology_version); } else if (strcmp ("serviceId", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_OID (&iter)) GOTO (typefailure); bson_oid_copy_unsafe (bson_iter_oid (&iter), &sd->service_id); } else if (strcmp ("connectionId", bson_iter_key (&iter)) == 0) { if (!BSON_ITER_HOLDS_NUMBER (&iter)) GOTO (typefailure); sd->server_connection_id = bson_iter_as_int64 (&iter); } } if (is_shard) { sd->type = MONGOC_SERVER_MONGOS; } else if (sd->set_name) { if (is_hidden) { sd->type = MONGOC_SERVER_RS_OTHER; } else if (is_primary) { sd->type = MONGOC_SERVER_RS_PRIMARY; } else if (is_secondary) { sd->type = MONGOC_SERVER_RS_SECONDARY; } else if (is_arbiter) { sd->type = MONGOC_SERVER_RS_ARBITER; } else { sd->type = MONGOC_SERVER_RS_OTHER; } } else if (is_replicaset) { sd->type = MONGOC_SERVER_RS_GHOST; } else if (num_keys > 0) { sd->type = MONGOC_SERVER_STANDALONE; } else { sd->type = MONGOC_SERVER_UNKNOWN; } if (!num_keys) { /* empty reply means hello failed */ _mongoc_server_description_set_error (sd, error); } mongoc_server_description_update_rtt (sd, rtt_msec); EXIT; typefailure: bson_set_error (&sd->error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_INVALID_TYPE, "unexpected type %s for field %s in hello response", _mongoc_bson_type_to_str (bson_iter_type (&iter)), bson_iter_key (&iter)); authfailure: sd->type = MONGOC_SERVER_UNKNOWN; sd->round_trip_time_msec = MONGOC_RTT_UNSET; EXIT; } /* *------------------------------------------------------------------------- * * mongoc_server_description_new_copy -- * * A copy of a server description that you must destroy, or NULL. * *------------------------------------------------------------------------- */ mongoc_server_description_t * mongoc_server_description_new_copy (const mongoc_server_description_t *description) { #define COPY_FIELD(FIELD) \ if (1) { \ copy->FIELD = description->FIELD; \ } else \ (void) 0 #define COPY_BSON_FIELD(FIELD) \ if (1) { \ bson_copy_to (&description->FIELD, ©->FIELD); \ } else \ (void) 0 // COPY_INTERNAL_BSON_FIELD copies a `bson_t` that references data in `last_hello_response`. #define COPY_INTERNAL_BSON_FIELD(FIELD) \ if (1) { \ if (!bson_empty (&description->FIELD)) { \ ptrdiff_t offset = bson_get_data (&description->FIELD) - bson_get_data (&description->last_hello_response); \ MONGOC_DEBUG_ASSERT (offset >= 0); \ const uint8_t *data = bson_get_data (©->last_hello_response) + offset; \ uint32_t len = description->FIELD.len; \ MONGOC_DEBUG_ASSERT (offset + len <= copy->last_hello_response.len); \ bson_init_static (©->FIELD, data, len); \ } else { \ bson_init (©->FIELD); \ } \ } else \ (void) 0 // COPY_INTERNAL_STRING_FIELD copies a `const char*` that references data in `last_hello_response`. #define COPY_INTERNAL_STRING_FIELD(FIELD) \ if (1) { \ if (description->FIELD) { \ ptrdiff_t offset = (char *) description->FIELD - (char *) bson_get_data (&description->last_hello_response); \ MONGOC_DEBUG_ASSERT (offset >= 0); \ copy->FIELD = (char *) bson_get_data (©->last_hello_response) + offset; \ MONGOC_DEBUG_ASSERT (offset + strlen (description->FIELD) <= copy->last_hello_response.len); \ } else { \ copy->FIELD = NULL; \ } \ } else \ (void) 0 if (!description) { return NULL; } mongoc_server_description_t *copy = BSON_ALIGNED_ALLOC (mongoc_server_description_t); COPY_FIELD (id); COPY_FIELD (host); COPY_FIELD (round_trip_time_msec); COPY_FIELD (last_update_time_usec); COPY_BSON_FIELD (last_hello_response); COPY_FIELD (has_hello_response); COPY_FIELD (hello_ok); copy->connection_address = copy->host.host_and_port; COPY_INTERNAL_STRING_FIELD (me); COPY_FIELD (opened); COPY_INTERNAL_STRING_FIELD (set_name); COPY_FIELD (error); COPY_FIELD (type); COPY_FIELD (min_wire_version); COPY_FIELD (max_wire_version); COPY_FIELD (max_msg_size); COPY_FIELD (max_bson_obj_size); COPY_FIELD (max_write_batch_size); COPY_FIELD (session_timeout_minutes); COPY_INTERNAL_BSON_FIELD (hosts); COPY_INTERNAL_BSON_FIELD (passives); COPY_INTERNAL_BSON_FIELD (arbiters); COPY_INTERNAL_BSON_FIELD (tags); COPY_INTERNAL_STRING_FIELD (current_primary); COPY_FIELD (set_version); COPY_FIELD (election_id); COPY_FIELD (last_write_date_ms); COPY_INTERNAL_BSON_FIELD (compressors); // `topology_version` does not refer to data in `last_hello_response`. It needs to outlive `last_hello_response`. COPY_BSON_FIELD (topology_version); COPY_FIELD (generation); copy->_generation_map_ = mongoc_generation_map_copy (mc_tpl_sd_generation_map_const (description)); COPY_FIELD (service_id); COPY_FIELD (server_connection_id); #undef COPY_INTERNAL_STRING_FIELD #undef COPY_INTERNAL_BSON_FIELD #undef COPY_BSON_FIELD #undef COPY_FIELD return copy; } /* *------------------------------------------------------------------------- * * mongoc_server_description_filter_stale -- * * Estimate servers' staleness according to the Server Selection Spec. * Determines the number of eligible servers, and sets any servers that * are too stale to NULL in the descriptions set. * *------------------------------------------------------------------------- */ void mongoc_server_description_filter_stale (const mongoc_server_description_t **sds, size_t sds_len, const mongoc_server_description_t *primary, int64_t heartbeat_frequency_ms, const mongoc_read_prefs_t *read_prefs) { int64_t max_staleness_seconds; size_t i; int64_t heartbeat_frequency_usec; int64_t max_last_write_date_usec; int64_t staleness_usec; int64_t max_staleness_usec; if (!read_prefs) { /* NULL read_prefs is PRIMARY, no maxStalenessSeconds to filter by */ return; } max_staleness_seconds = mongoc_read_prefs_get_max_staleness_seconds (read_prefs); if (max_staleness_seconds == MONGOC_NO_MAX_STALENESS) { return; } BSON_ASSERT (max_staleness_seconds > 0); max_staleness_usec = max_staleness_seconds * 1000 * 1000; heartbeat_frequency_usec = heartbeat_frequency_ms * 1000; if (primary) { for (i = 0; i < sds_len; i++) { if (!sds[i] || sds[i]->type != MONGOC_SERVER_RS_SECONDARY) { continue; } /* See max-staleness.rst for explanation of these formulae. */ staleness_usec = primary->last_write_date_ms * 1000 + (sds[i]->last_update_time_usec - primary->last_update_time_usec) - sds[i]->last_write_date_ms * 1000 + heartbeat_frequency_usec; if (staleness_usec > max_staleness_usec) { TRACE ("Rejected stale RSSecondary [%s]", sds[i]->host.host_and_port); sds[i] = NULL; } } } else { /* find max last_write_date */ max_last_write_date_usec = 0; for (i = 0; i < sds_len; i++) { if (sds[i] && sds[i]->type == MONGOC_SERVER_RS_SECONDARY) { max_last_write_date_usec = BSON_MAX (max_last_write_date_usec, sds[i]->last_write_date_ms * 1000); } } /* use max last_write_date to estimate each secondary's staleness */ for (i = 0; i < sds_len; i++) { if (!sds[i] || sds[i]->type != MONGOC_SERVER_RS_SECONDARY) { continue; } staleness_usec = max_last_write_date_usec - sds[i]->last_write_date_ms * 1000 + heartbeat_frequency_usec; if (staleness_usec > max_staleness_usec) { TRACE ("Rejected stale RSSecondary [%s]", sds[i]->host.host_and_port); sds[i] = NULL; } } } } /* *------------------------------------------------------------------------- * * mongoc_server_description_filter_tags -- * * Given a set of server descriptions, set to NULL any that don't * match the read preference's tag sets. * * https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.md#tag_sets * *------------------------------------------------------------------------- */ void mongoc_server_description_filter_tags (const mongoc_server_description_t **descriptions, size_t description_len, const mongoc_read_prefs_t *read_prefs) { const bson_t *rp_tags; bson_iter_t rp_tagset_iter; bson_iter_t tag_set_iter; bool *sd_matched = NULL; bool found; size_t i; if (!read_prefs) { /* NULL read_prefs is PRIMARY, no tags to filter by */ return; } rp_tags = mongoc_read_prefs_get_tags (read_prefs); if (bson_count_keys (rp_tags) == 0) { /* no tags to filter by */ return; } sd_matched = (bool *) bson_malloc0 (sizeof (bool) * description_len); bson_iter_init (&rp_tagset_iter, rp_tags); /* for each read preference tag set */ while (bson_iter_next (&rp_tagset_iter)) { found = false; for (i = 0; i < description_len; i++) { if (!descriptions[i]) { /* NULLed earlier in mongoc_topology_description_suitable_servers */ continue; } BSON_ASSERT (bson_iter_recurse (&rp_tagset_iter, &tag_set_iter)); sd_matched[i] = _match_tag_set (descriptions[i], &tag_set_iter); if (sd_matched[i]) { found = true; } } if (found) { for (i = 0; i < description_len; i++) { if (!sd_matched[i] && descriptions[i]) { TRACE ("Rejected [%s] [%s], doesn't match tags", mongoc_server_description_type (descriptions[i]), descriptions[i]->host.host_and_port); descriptions[i] = NULL; } } goto CLEANUP; } } /* tried each */ for (i = 0; i < description_len; i++) { if (!sd_matched[i]) { TRACE ("Rejected [%s] [%s], reached end of tags array without match", mongoc_server_description_type (descriptions[i]), descriptions[i]->host.host_and_port); descriptions[i] = NULL; } } CLEANUP: bson_free (sd_matched); } /* *------------------------------------------------------------------------- * * _match_tag_set -- * * Check if a server's tags match one tag set, like * {'tag1': 'value1', 'tag2': 'value2'}. * *------------------------------------------------------------------------- */ static bool _match_tag_set (const mongoc_server_description_t *sd, bson_iter_t *tag_set_iter) { bson_iter_t sd_iter; uint32_t read_pref_tag_len; uint32_t sd_len; const char *read_pref_tag; const char *read_pref_val; const char *server_val; while (bson_iter_next (tag_set_iter)) { /* one {'tag': 'value'} pair from the read preference's tag set */ read_pref_tag = bson_iter_key (tag_set_iter); read_pref_val = bson_iter_utf8 (tag_set_iter, &read_pref_tag_len); if (bson_iter_init_find (&sd_iter, &sd->tags, read_pref_tag)) { /* The server has this tag - does it have the right value? */ server_val = bson_iter_utf8 (&sd_iter, &sd_len); if (sd_len != read_pref_tag_len || memcmp (read_pref_val, server_val, read_pref_tag_len)) { /* If the values don't match, no match */ return false; } } else { /* If the server description doesn't have that key, no match */ return false; } } return true; } /* *-------------------------------------------------------------------------- * * mongoc_server_description_compressor_id -- * * Get the compressor id if compression was negotiated. * * Returns: * The compressor ID, or -1 if none was negotiated. * *-------------------------------------------------------------------------- */ int32_t mongoc_server_description_compressor_id (const mongoc_server_description_t *description) { int id; bson_iter_t iter; BSON_ASSERT (bson_iter_init (&iter, &description->compressors)); while (bson_iter_next (&iter)) { id = mongoc_compressor_name_to_id (bson_iter_utf8 (&iter, NULL)); if (id != -1) { return id; } } return -1; } /* Returns true if either or both is NULL. out is 1 if exactly one NULL, 0 if * both NULL */ typedef int (*strcmp_fn) (const char *, const char *); static int _nullable_cmp (const char *a, const char *b, strcmp_fn cmp_fn) { if (!a && b) { return 1; } if (a && !b) { return 1; } if (!a && !b) { return 0; } /* Both not NULL. */ return cmp_fn (a, b); } static int _nullable_strcasecmp (const char *a, const char *b) { return _nullable_cmp (a, b, strcasecmp); } static int _nullable_strcmp (const char *a, const char *b) { return _nullable_cmp (a, b, strcmp); } bool _mongoc_server_description_equal (const mongoc_server_description_t *sd1, const mongoc_server_description_t *sd2) { if (sd1->type != sd2->type) { return false; } if (sd1->min_wire_version != sd2->min_wire_version) { return false; } if (sd1->max_wire_version != sd2->max_wire_version) { return false; } if (0 != _nullable_strcasecmp (sd1->me, sd2->me)) { return false; } /* CDRIVER-3527: The hosts/passives/arbiters checks should really be a set * comparison of case insensitive hostnames. */ if (!bson_equal (&sd1->hosts, &sd2->hosts)) { return false; } if (!bson_equal (&sd1->passives, &sd2->passives)) { return false; } if (!bson_equal (&sd1->arbiters, &sd2->arbiters)) { return false; } if (!bson_equal (&sd1->tags, &sd2->tags)) { return false; } if (0 != _nullable_strcmp (sd1->set_name, sd2->set_name)) { return false; } if (sd1->set_version != sd2->set_version) { return false; } if (!bson_oid_equal (&sd1->election_id, &sd2->election_id)) { return false; } if (0 != _nullable_strcasecmp (sd1->current_primary, sd2->current_primary)) { return false; } if (sd1->session_timeout_minutes != sd2->session_timeout_minutes) { return false; } if (sd1->error.domain != sd2->error.domain || sd1->error.code != sd2->error.code || 0 != strncmp (sd1->error.message, sd2->error.message, BSON_ERROR_BUFFER_SIZE)) { return false; } if (!bson_equal (&sd1->topology_version, &sd2->topology_version)) { return false; } return true; } int mongoc_server_description_topology_version_cmp (const bson_t *tv1, const bson_t *tv2) { const bson_oid_t *pid1; const bson_oid_t *pid2; int64_t counter1; int64_t counter2; bson_iter_t iter; BSON_ASSERT (tv1); BSON_ASSERT (tv2); if (bson_empty (tv1) || bson_empty (tv2)) { return -1; } if (!bson_iter_init_find (&iter, tv1, "processId") || !BSON_ITER_HOLDS_OID (&iter)) { return -1; } pid1 = bson_iter_oid (&iter); if (!bson_iter_init_find (&iter, tv2, "processId") || !BSON_ITER_HOLDS_OID (&iter)) { return -1; } pid2 = bson_iter_oid (&iter); if (0 != bson_oid_compare (pid1, pid2)) { /* Assume greater. */ return -1; } if (!bson_iter_init_find (&iter, tv1, "counter") || !BSON_ITER_HOLDS_INT (&iter)) { return -1; } counter1 = bson_iter_as_int64 (&iter); if (!bson_iter_init_find (&iter, tv2, "counter") || !BSON_ITER_HOLDS_INT (&iter)) { return -1; } counter2 = bson_iter_as_int64 (&iter); if (counter1 < counter2) { return -1; } else if (counter1 > counter2) { return 1; } return 0; } void mongoc_server_description_set_topology_version (mongoc_server_description_t *sd, const bson_t *tv) { BSON_ASSERT (tv); bson_destroy (&sd->topology_version); bson_copy_to (tv, &sd->topology_version); } bool mongoc_server_description_has_service_id (const mongoc_server_description_t *description) { return !mcommon_oid_is_zero (&description->service_id); } bool mongoc_server_description_append_contents_to_bson (const mongoc_server_description_t *sd, bson_t *bson, mongoc_server_description_content_flags_t flags) { BSON_ASSERT_PARAM (sd); BSON_ASSERT_PARAM (bson); if ((flags & MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_SERVER_HOST) && !BSON_APPEND_UTF8 (bson, "serverHost", sd->host.host)) { return false; } if ((flags & MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_SERVER_PORT) && !BSON_APPEND_INT32 (bson, "serverPort", sd->host.port)) { return false; } if ((flags & MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_ADDRESS) && !BSON_APPEND_UTF8 (bson, "address", sd->host.host_and_port)) { return false; } if (flags & MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_SERVER_CONNECTION_ID) { int64_t server_connection_id = sd->server_connection_id; if (MONGOC_NO_SERVER_CONNECTION_ID != server_connection_id) { if (!BSON_APPEND_INT64 (bson, "serverConnectionId", server_connection_id)) { return false; } } } if (flags & MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_SERVICE_ID) { if (mongoc_server_description_has_service_id (sd)) { char str[25]; bson_oid_to_string (&sd->service_id, str); if (!BSON_APPEND_UTF8 (bson, "serviceId", str)) { return false; } } } if ((flags & MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_TYPE) && !BSON_APPEND_UTF8 (bson, "type", mongoc_server_description_type (sd))) { return false; } return true; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-description.h0000644000175100001660000000425314760300420024772 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SERVER_DESCRIPTION_H #define MONGOC_SERVER_DESCRIPTION_H #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_server_description_t mongoc_server_description_t; MONGOC_EXPORT (void) mongoc_server_description_destroy (mongoc_server_description_t *description); MONGOC_EXPORT (mongoc_server_description_t *) mongoc_server_description_new_copy (const mongoc_server_description_t *description) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (uint32_t) mongoc_server_description_id (const mongoc_server_description_t *description); MONGOC_EXPORT (mongoc_host_list_t *) mongoc_server_description_host (const mongoc_server_description_t *description); MONGOC_EXPORT (int64_t) mongoc_server_description_last_update_time (const mongoc_server_description_t *description); MONGOC_EXPORT (int64_t) mongoc_server_description_round_trip_time (const mongoc_server_description_t *description); MONGOC_EXPORT (const char *) mongoc_server_description_type (const mongoc_server_description_t *description); MONGOC_EXPORT (const bson_t *) mongoc_server_description_hello_response (const mongoc_server_description_t *description); MONGOC_EXPORT (const bson_t *) mongoc_server_description_ismaster (const mongoc_server_description_t *description) BSON_GNUC_DEPRECATED_FOR (mongoc_server_description_hello_response); MONGOC_EXPORT (int32_t) mongoc_server_description_compressor_id (const mongoc_server_description_t *description); BSON_END_DECLS #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-monitor-private.h0000644000175100001660000000366314760300420025612 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SERVER_MONITOR_PRIVATE_H #define MONGOC_SERVER_MONITOR_PRIVATE_H #include #include #include /* For background monitoring of a single server. */ typedef enum { MONGOC_SERVER_MONITORING_AUTO = 0, MONGOC_SERVER_MONITORING_POLL, MONGOC_SERVER_MONITORING_STREAM } mongoc_server_monitoring_mode_t; typedef struct _mongoc_server_monitor_t mongoc_server_monitor_t; mongoc_server_monitor_t * mongoc_server_monitor_new (mongoc_topology_t *topology, mongoc_topology_description_t *td, mongoc_server_description_t *init_description); void mongoc_server_monitor_request_cancel (mongoc_server_monitor_t *server_monitor); void mongoc_server_monitor_request_scan (mongoc_server_monitor_t *server_monitor); bool mongoc_server_monitor_request_shutdown (mongoc_server_monitor_t *server_monitor); void mongoc_server_monitor_wait_for_shutdown (mongoc_server_monitor_t *server_monitor); void mongoc_server_monitor_destroy (mongoc_server_monitor_t *server_monitor); void mongoc_server_monitor_run (mongoc_server_monitor_t *server_monitor); void mongoc_server_monitor_run_as_rtt (mongoc_server_monitor_t *server_monitor); #endif /* MONGOC_SERVER_MONITOR_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-monitor.c0000644000175100001660000014505314760300420024135 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "monitor" typedef enum { MONGOC_THREAD_OFF = 0, MONGOC_THREAD_RUNNING, MONGOC_THREAD_SHUTTING_DOWN, MONGOC_THREAD_JOINABLE } thread_state_t; /* Use a signed and wide return type for timeouts as long as you can. Cast only * when you know what you're doing with it. */ static int64_t _now_us (void) { return bson_get_monotonic_time (); } static int64_t _now_ms (void) { return _now_us () / 1000; } struct _mongoc_server_monitor_t { mongoc_topology_t *topology; bson_thread_t thread; /* State accessed from multiple threads. */ struct { bson_mutex_t mutex; mongoc_cond_t cond; thread_state_t state; bool scan_requested; bool cancel_requested; } shared; /* Default time to sleep between hello checks (reduced when a scan is * requested) */ int64_t heartbeat_frequency_ms; /* The minimum time to sleep between hello checks. */ int64_t min_heartbeat_frequency_ms; int64_t connect_timeout_ms; bool use_tls; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t *ssl_opts; #endif mongoc_uri_t *uri; /* A custom initiator may be set if a user provides overrides to create a * stream. */ mongoc_stream_initiator_t initiator; void *initiator_context; int32_t request_id; mongoc_stream_t *stream; bool more_to_come; mongoc_server_description_t *description; uint32_t server_id; bool is_rtt; mongoc_server_monitoring_mode_t mode; }; static BSON_GNUC_PRINTF (3, 4) void _server_monitor_log (mongoc_server_monitor_t *server_monitor, mongoc_log_level_t level, const char *format, ...) { va_list ap; char *msg; va_start (ap, format); msg = bson_strdupv_printf (format, ap); va_end (ap); mongoc_log (level, MONGOC_LOG_DOMAIN, "[%s%s] %s", server_monitor->description->host.host_and_port, server_monitor->is_rtt ? "-RTT" : "", msg); bson_free (msg); } #define MONITOR_LOG(sm, ...) \ do { \ if (MONGOC_TRACE_ENABLED) { \ _server_monitor_log (sm, MONGOC_LOG_LEVEL_TRACE, __VA_ARGS__); \ } \ } while (0) /* TODO CDRIVER-3710 use MONGOC_LOG_LEVEL_ERROR */ #define MONITOR_LOG_ERROR(sm, ...) _server_monitor_log (sm, MONGOC_LOG_LEVEL_DEBUG, __VA_ARGS__) /* TODO CDRIVER-3710 use MONGOC_LOG_LEVEL_WARNING */ #define MONITOR_LOG_WARNING(sm, ...) _server_monitor_log (sm, MONGOC_LOG_LEVEL_DEBUG, __VA_ARGS__) static void _server_monitor_heartbeat_started (mongoc_server_monitor_t *server_monitor, bool awaited) { mongoc_apm_server_heartbeat_started_t event; mongoc_log_and_monitor_instance_t *log_and_monitor = &server_monitor->topology->log_and_monitor; { mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (server_monitor)->topology); bson_oid_t topology_id; bson_oid_copy (&td.ptr->topology_id, &topology_id); mc_tpld_drop_ref (&td); mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Server heartbeat started", oid ("topologyId", &topology_id), server_description (server_monitor->description, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID), boolean ("awaited", awaited)); } MONGOC_DEBUG_ASSERT (!mcommon_mutex_is_locked (&log_and_monitor->apm_mutex)); if (!log_and_monitor->apm_callbacks.server_heartbeat_started) { return; } event.host = &server_monitor->description->host; event.context = log_and_monitor->apm_context; MONITOR_LOG (server_monitor, "%s heartbeat started", awaited ? "awaitable" : "regular"); event.awaited = awaited; bson_mutex_lock (&log_and_monitor->apm_mutex); log_and_monitor->apm_callbacks.server_heartbeat_started (&event); bson_mutex_unlock (&log_and_monitor->apm_mutex); } static void _server_monitor_heartbeat_succeeded (mongoc_server_monitor_t *server_monitor, const bson_t *reply, int64_t duration_usec, bool awaited) { mongoc_apm_server_heartbeat_succeeded_t event; mongoc_log_and_monitor_instance_t *log_and_monitor = &server_monitor->topology->log_and_monitor; { mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (server_monitor)->topology); bson_oid_t topology_id; bson_oid_copy (&td.ptr->topology_id, &topology_id); mc_tpld_drop_ref (&td); mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Server heartbeat succeeded", oid ("topologyId", &topology_id), server_description (server_monitor->description, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID), boolean ("awaited", awaited), monotonic_time_duration (duration_usec), bson_as_json ("reply", reply)); } if (!log_and_monitor->apm_callbacks.server_heartbeat_succeeded) { return; } event.host = &server_monitor->description->host; event.context = log_and_monitor->apm_context; event.reply = reply; event.duration_usec = duration_usec; MONITOR_LOG (server_monitor, "%s heartbeat succeeded", awaited ? "awaitable" : "regular"); event.awaited = awaited; bson_mutex_lock (&log_and_monitor->apm_mutex); log_and_monitor->apm_callbacks.server_heartbeat_succeeded (&event); bson_mutex_unlock (&log_and_monitor->apm_mutex); } static void _server_monitor_heartbeat_failed (mongoc_server_monitor_t *server_monitor, const bson_error_t *error, int64_t duration_usec, bool awaited) { mongoc_apm_server_heartbeat_failed_t event; mongoc_log_and_monitor_instance_t *log_and_monitor = &server_monitor->topology->log_and_monitor; { mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (server_monitor)->topology); bson_oid_t topology_id; bson_oid_copy (&td.ptr->topology_id, &topology_id); mc_tpld_drop_ref (&td); mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Server heartbeat failed", oid ("topologyId", &topology_id), server_description (server_monitor->description, SERVER_HOST, SERVER_PORT, SERVER_CONNECTION_ID), boolean ("awaited", awaited), monotonic_time_duration (duration_usec), error ("failure", error)); } if (!log_and_monitor->apm_callbacks.server_heartbeat_failed) { return; } event.host = &server_monitor->description->host; event.context = log_and_monitor->apm_context; event.error = error; event.duration_usec = duration_usec; MONITOR_LOG (server_monitor, "%s heartbeat failed", awaited ? "awaitable" : "regular"); event.awaited = awaited; bson_mutex_lock (&log_and_monitor->apm_mutex); log_and_monitor->apm_callbacks.server_heartbeat_failed (&event); bson_mutex_unlock (&log_and_monitor->apm_mutex); } static void _server_monitor_append_cluster_time (mongoc_server_monitor_t *server_monitor, bson_t *cmd) { mc_shared_tpld td = mc_tpld_take_ref (BSON_ASSERT_PTR_INLINE (server_monitor)->topology); /* Cluster time is updated on every reply. */ if (!bson_empty (&td.ptr->cluster_time)) { bson_append_document (cmd, "$clusterTime", 12, &td.ptr->cluster_time); } mc_tpld_drop_ref (&td); } static int32_t _int32_from_le (const void *data) { BSON_ASSERT_PARAM (data); return bson_iter_int32_unsafe (&(bson_iter_t){.raw = data}); } static bool _server_monitor_send_and_recv_hello_opmsg (mongoc_server_monitor_t *server_monitor, const bson_t *cmd, bson_t *reply, bson_error_t *error) { bool ret = false; mcd_rpc_message *const rpc = mcd_rpc_message_new (); mongoc_buffer_t buffer; _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); void *decompressed_data = NULL; size_t decompressed_data_len = 0u; /* First, let's construct and send our OP_MSG: */ { int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (rpc, 0); message_length += mcd_rpc_header_set_request_id (rpc, server_monitor->request_id++); message_length += mcd_rpc_header_set_response_to (rpc, 0); message_length += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_MSG); mcd_rpc_op_msg_set_sections_count (rpc, 1u); message_length += mcd_rpc_op_msg_set_flag_bits (rpc, MONGOC_OP_MSG_FLAG_NONE); message_length += mcd_rpc_op_msg_section_set_kind (rpc, 0u, 0); message_length += mcd_rpc_op_msg_section_set_body (rpc, 0u, bson_get_data (cmd)); mcd_rpc_message_set_length (rpc, message_length); } size_t num_iovecs = 0u; mongoc_iovec_t *const iovecs = mcd_rpc_message_to_iovecs (rpc, &num_iovecs); BSON_ASSERT (iovecs); MONITOR_LOG (server_monitor, "sending with timeout %" PRId64, server_monitor->connect_timeout_ms); mcd_rpc_message_egress (rpc); if (!_mongoc_stream_writev_full ( server_monitor->stream, iovecs, num_iovecs, server_monitor->connect_timeout_ms, error)) { MONITOR_LOG_ERROR (server_monitor, "failed to write polling hello: %s", error->message); goto fail; } /* Done sending! Now, receive the reply: */ if (!_mongoc_buffer_append_from_stream ( &buffer, server_monitor->stream, sizeof (int32_t), server_monitor->connect_timeout_ms, error)) { goto fail; } const int32_t message_length = _int32_from_le (buffer.data); // msgHeader consists of four int32 fields. const int32_t message_header_length = 4u * sizeof (int32_t); if (message_length < message_header_length) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server: message length"); goto fail; } const size_t remaining_bytes = (size_t) message_length - sizeof (int32_t); if (!_mongoc_buffer_append_from_stream ( &buffer, server_monitor->stream, remaining_bytes, server_monitor->connect_timeout_ms, error)) { goto fail; } mcd_rpc_message_reset (rpc); if (!mcd_rpc_message_from_data_in_place (rpc, buffer.data, buffer.len, NULL)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server: malformed message"); goto fail; } mcd_rpc_message_ingress (rpc); if (!mcd_rpc_message_decompress_if_necessary (rpc, &decompressed_data, &decompressed_data_len)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server: decompression failure"); goto fail; } bson_t body; if (!mcd_rpc_message_get_body (rpc, &body)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server: malformed body"); goto fail; } bson_copy_to (&body, reply); bson_destroy (&body); ret = true; fail: if (!ret) { bson_init (reply); } bson_free (decompressed_data); _mongoc_buffer_destroy (&buffer); bson_free (iovecs); mcd_rpc_message_destroy (rpc); return ret; } static bool _server_monitor_send_and_recv_opquery (mongoc_server_monitor_t *server_monitor, const bson_t *cmd, bson_t *reply, bson_error_t *error) { bool ret = false; mcd_rpc_message *const rpc = mcd_rpc_message_new (); size_t num_iovecs = 0u; mongoc_iovec_t *iovecs = NULL; mongoc_buffer_t buffer; _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); void *decompressed_data = NULL; size_t decompressed_data_len = 0u; { int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (rpc, 0); message_length += mcd_rpc_header_set_request_id (rpc, server_monitor->request_id++); message_length += mcd_rpc_header_set_response_to (rpc, 0); message_length += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_QUERY); message_length += mcd_rpc_op_query_set_flags (rpc, MONGOC_OP_QUERY_FLAG_SECONDARY_OK); message_length += mcd_rpc_op_query_set_full_collection_name (rpc, "admin.$cmd"); message_length += mcd_rpc_op_query_set_number_to_skip (rpc, 0); message_length += mcd_rpc_op_query_set_number_to_return (rpc, -1); message_length += mcd_rpc_op_query_set_query (rpc, bson_get_data (cmd)); mcd_rpc_message_set_length (rpc, message_length); } iovecs = mcd_rpc_message_to_iovecs (rpc, &num_iovecs); BSON_ASSERT (iovecs); mcd_rpc_message_egress (rpc); if (!_mongoc_stream_writev_full ( server_monitor->stream, iovecs, num_iovecs, server_monitor->connect_timeout_ms, error)) { goto fail; } if (!_mongoc_buffer_append_from_stream ( &buffer, server_monitor->stream, sizeof (int32_t), server_monitor->connect_timeout_ms, error)) { goto fail; } const int32_t message_length = _int32_from_le (buffer.data); // msgHeader consists of four int32 fields. const int32_t message_header_length = 4u * sizeof (int32_t); if (message_length < message_header_length) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server: message length"); goto fail; } const size_t remaining_bytes = (size_t) message_length - sizeof (int32_t); if (!_mongoc_buffer_append_from_stream ( &buffer, server_monitor->stream, remaining_bytes, server_monitor->connect_timeout_ms, error)) { goto fail; } mcd_rpc_message_reset (rpc); if (!mcd_rpc_message_from_data_in_place (rpc, buffer.data, buffer.len, NULL)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server: malformed message"); goto fail; } mcd_rpc_message_ingress (rpc); if (!mcd_rpc_message_decompress_if_necessary (rpc, &decompressed_data, &decompressed_data_len)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server: decompression failure"); goto fail; } bson_t body; if (!mcd_rpc_message_get_body (rpc, &body)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "invalid reply from server: malformed body"); goto fail; } bson_copy_to (&body, reply); bson_destroy (&body); ret = true; fail: if (!ret) { bson_init (reply); } bson_free (decompressed_data); _mongoc_buffer_destroy (&buffer); bson_free (iovecs); mcd_rpc_message_destroy (rpc); return ret; } static bool _server_monitor_send_and_recv (mongoc_server_monitor_t *server_monitor, bson_t *cmd, bson_t *reply, bson_error_t *error) { if (mongoc_topology_uses_server_api (server_monitor->topology) || mongoc_topology_uses_loadbalanced (server_monitor->topology)) { /* OP_MSG requires a "db" parameter: */ bson_append_utf8 (cmd, "$db", 3, "admin", 5); return _server_monitor_send_and_recv_hello_opmsg (server_monitor, cmd, reply, error); } else { return _server_monitor_send_and_recv_opquery (server_monitor, cmd, reply, error); } } static bool _server_monitor_polling_hello (mongoc_server_monitor_t *server_monitor, bool hello_ok, bson_t *hello_response, bson_error_t *error) { bson_t cmd; const bson_t *hello; bool ret; hello = _mongoc_topology_scanner_get_monitoring_cmd (server_monitor->topology->scanner, hello_ok); bson_copy_to (hello, &cmd); _server_monitor_append_cluster_time (server_monitor, &cmd); ret = _server_monitor_send_and_recv (server_monitor, &cmd, hello_response, error); bson_destroy (&cmd); return ret; } static bool _server_monitor_awaitable_hello_send (mongoc_server_monitor_t *server_monitor, bson_t *cmd, bson_error_t *error) { bool ret = false; mcd_rpc_message *const rpc = mcd_rpc_message_new (); { int32_t message_length = 0; message_length += mcd_rpc_header_set_message_length (rpc, 0); message_length += mcd_rpc_header_set_request_id (rpc, server_monitor->request_id++); message_length += mcd_rpc_header_set_response_to (rpc, 0); message_length += mcd_rpc_header_set_op_code (rpc, MONGOC_OP_CODE_MSG); mcd_rpc_op_msg_set_sections_count (rpc, 1); message_length += mcd_rpc_op_msg_set_flag_bits (rpc, MONGOC_OP_MSG_FLAG_EXHAUST_ALLOWED); message_length += mcd_rpc_op_msg_section_set_kind (rpc, 0u, 0); message_length += mcd_rpc_op_msg_section_set_body (rpc, 0u, bson_get_data (cmd)); mcd_rpc_message_set_length (rpc, message_length); } size_t num_iovecs; mongoc_iovec_t *const iovecs = mcd_rpc_message_to_iovecs (rpc, &num_iovecs); BSON_ASSERT (iovecs); MONITOR_LOG (server_monitor, "sending with timeout %" PRId64, server_monitor->connect_timeout_ms); mcd_rpc_message_egress (rpc); if (!_mongoc_stream_writev_full ( server_monitor->stream, iovecs, num_iovecs, server_monitor->connect_timeout_ms, error)) { MONITOR_LOG_ERROR (server_monitor, "failed to write awaitable hello: %s", error->message); goto done; } ret = true; done: bson_free (iovecs); mcd_rpc_message_destroy (rpc); return ret; } /* Poll the server monitor stream for reading. Allows cancellation. * * Called only from server monitor thread. * Locks server monitor mutex. * Returns true if stream is readable. False on error or cancellation. * On cancellation, no error is set, but cancelled is set to true. */ static bool _server_monitor_poll_with_interrupt (mongoc_server_monitor_t *server_monitor, int64_t expire_at_ms, bool *cancelled, bson_error_t *error) { /* How many milliseconds we should poll for on each tick. * On every tick, check whether the awaitable hello was cancelled. */ const int32_t monitor_tick_ms = MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS; int64_t timeleft_ms; while ((timeleft_ms = expire_at_ms - _now_ms ()) > 0) { ssize_t ret; mongoc_stream_poll_t poller[1]; MONITOR_LOG (server_monitor, "_server_monitor_poll_with_interrupt expires in: %" PRId64 "ms", timeleft_ms); poller[0].stream = server_monitor->stream; poller[0].events = POLLIN; /* POLLERR and POLLHUP are added in mongoc_socket_poll. */ poller[0].revents = 0; MONITOR_LOG (server_monitor, "polling for awaitable hello reply with timeleft_ms: %" PRId64, timeleft_ms); ret = mongoc_stream_poll (poller, 1, (int32_t) BSON_MIN (timeleft_ms, monitor_tick_ms)); if (ret == -1) { MONITOR_LOG (server_monitor, "mongoc_stream_poll error"); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "poll error"); return false; } if (poller[0].revents & (POLLERR | POLLHUP)) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "connection closed while polling"); return false; } /* Check for cancellation. */ bson_mutex_lock (&server_monitor->shared.mutex); *cancelled = server_monitor->shared.cancel_requested; server_monitor->shared.cancel_requested = false; bson_mutex_unlock (&server_monitor->shared.mutex); if (*cancelled) { MONITOR_LOG (server_monitor, "polling cancelled"); return false; } if (poller[0].revents & POLLIN) { MONITOR_LOG (server_monitor, "mongoc_stream_poll ready to read"); return true; } } bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "connection timeout while polling"); return false; } /* Calculate the timeout between the current time and an absolute expiration * time in milliseconds. * * Returns 0 and sets error if time expired. */ int64_t _get_timeout_ms (int64_t expire_at_ms, bson_error_t *error) { int64_t timeout_ms; timeout_ms = expire_at_ms - _now_ms (); if (timeout_ms <= 0) { bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "connection timed out reading message length"); return 0; } return timeout_ms; } /* Receive an awaitable hello reply. * * May be used to receive additional replies when moreToCome is set. * Called only from server monitor thread. * May lock server monitor mutex in functions that are called. * May block for up to heartbeatFrequencyMS + connectTimeoutMS waiting for * reply. * Returns true if a reply was received. False on error or cancellation. * On cancellation, no error is set, but cancelled is set to true. */ static bool _server_monitor_awaitable_hello_recv (mongoc_server_monitor_t *server_monitor, bson_t *hello_response, bool *cancelled, bson_error_t *error) { bool ret = false; int64_t timeout_ms; mcd_rpc_message *const rpc = mcd_rpc_message_new (); mongoc_buffer_t buffer; _mongoc_buffer_init (&buffer, NULL, 0, NULL, NULL); void *decompressed_data = NULL; size_t decompressed_data_len = 0u; const int64_t expire_at_ms = _now_ms () + server_monitor->heartbeat_frequency_ms + server_monitor->connect_timeout_ms; if (!_server_monitor_poll_with_interrupt (server_monitor, expire_at_ms, cancelled, error)) { GOTO (fail); } timeout_ms = _get_timeout_ms (expire_at_ms, error); if (timeout_ms == 0) { GOTO (fail); } MONITOR_LOG (server_monitor, "reading first 4 bytes with timeout: %" PRId64, timeout_ms); if (!_mongoc_buffer_append_from_stream ( &buffer, server_monitor->stream, sizeof (int32_t), (int32_t) timeout_ms, error)) { GOTO (fail); } const int32_t message_length = _int32_from_le (buffer.data); // msgHeader consists of four int32 fields. const int32_t message_header_length = 4u * sizeof (int32_t); if ((message_length < message_header_length) || (message_length > server_monitor->description->max_msg_size)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "message size %" PRId32 " is not within expected range 16-%" PRId32 " bytes", message_length, server_monitor->description->max_msg_size); GOTO (fail); } timeout_ms = _get_timeout_ms (expire_at_ms, error); if (timeout_ms == 0) { GOTO (fail); } const size_t remaining_bytes = (size_t) message_length - sizeof (int32_t); MONITOR_LOG (server_monitor, "reading remaining %zu bytes. Timeout %" PRId64, remaining_bytes, timeout_ms); if (!_mongoc_buffer_append_from_stream (&buffer, server_monitor->stream, remaining_bytes, timeout_ms, error)) { GOTO (fail); } if (!mcd_rpc_message_from_data_in_place (rpc, buffer.data, buffer.len, NULL)) { bson_set_error ( error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "malformed message from server"); GOTO (fail); } mcd_rpc_message_ingress (rpc); if (!mcd_rpc_message_decompress_if_necessary (rpc, &decompressed_data, &decompressed_data_len)) { bson_set_error (error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "decompression failure"); GOTO (fail); } bson_t body; if (!mcd_rpc_message_get_body (rpc, &body)) { bson_set_error ( error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_INVALID_REPLY, "malformed BSON payload from server"); GOTO (fail); } bson_copy_to (&body, hello_response); bson_destroy (&body); server_monitor->more_to_come = (mcd_rpc_op_msg_get_flag_bits (rpc) & MONGOC_OP_MSG_FLAG_MORE_TO_COME) != 0; ret = true; fail: if (!ret) { bson_init (hello_response); } bson_free (decompressed_data); _mongoc_buffer_destroy (&buffer); mcd_rpc_message_destroy (rpc); return ret; } /* Send and receive an awaitable hello. * * Called only from server monitor thread. * May lock server monitor mutex in functions that are called. * May block for up to heartbeatFrequencyMS waiting for reply. */ static bool _server_monitor_awaitable_hello (mongoc_server_monitor_t *server_monitor, const mongoc_server_description_t *description, bson_t *hello_response, bool *cancelled, bson_error_t *error) { bson_t cmd; const bson_t *hello; bool ret = false; hello = _mongoc_topology_scanner_get_monitoring_cmd (server_monitor->topology->scanner, description->hello_ok); bson_copy_to (hello, &cmd); _server_monitor_append_cluster_time (server_monitor, &cmd); bson_append_document (&cmd, "topologyVersion", 15, &description->topology_version); bson_append_int64 (&cmd, "maxAwaitTimeMS", 14, server_monitor->heartbeat_frequency_ms); bson_append_utf8 (&cmd, "$db", 3, "admin", 5); if (!_server_monitor_awaitable_hello_send (server_monitor, &cmd, error)) { GOTO (fail); } if (!_server_monitor_awaitable_hello_recv (server_monitor, hello_response, cancelled, error)) { bson_destroy (hello_response); GOTO (fail); } ret = true; fail: if (!ret) { bson_init (hello_response); } bson_destroy (&cmd); return ret; } /* Update the topology description with a reply or an error. * * Called only from server monitor thread. * Caller must hold no locks. * Locks server monitor mutex. */ static void _update_topology_description (mongoc_server_monitor_t *server_monitor, mongoc_server_description_t *description) { mongoc_topology_t *topology; bson_t *hello_response = NULL; mc_tpld_modification tdmod; topology = server_monitor->topology; if (description->has_hello_response) { hello_response = &description->last_hello_response; } if (hello_response) { _mongoc_topology_update_cluster_time (topology, hello_response); } if (mcommon_atomic_int_fetch (&topology->scanner_state, mcommon_memory_order_relaxed) == MONGOC_TOPOLOGY_SCANNER_SHUTTING_DOWN) { return; } tdmod = mc_tpld_modify_begin (topology); bson_mutex_lock (&server_monitor->shared.mutex); server_monitor->shared.scan_requested = false; bson_mutex_unlock (&server_monitor->shared.mutex); mongoc_topology_description_handle_hello (tdmod.new_td, &topology->log_and_monitor, server_monitor->server_id, hello_response, description->round_trip_time_msec, &description->error); /* Reconcile server monitors. */ _mongoc_topology_background_monitoring_reconcile (topology, tdmod.new_td); /* Wake threads performing server selection. */ mongoc_cond_broadcast (&server_monitor->topology->cond_client); mc_tpld_modify_commit (tdmod); } /* Get the mode enum based on the uri * * Called during server monitor creation */ static mongoc_server_monitoring_mode_t _server_monitor_get_mode_enum (mongoc_server_monitor_t *server_monitor) { const char *mode_str = mongoc_uri_get_server_monitoring_mode (server_monitor->uri); if (strcmp (mode_str, "poll") == 0) { return MONGOC_SERVER_MONITORING_POLL; } else if (strcmp (mode_str, "stream") == 0) { return MONGOC_SERVER_MONITORING_STREAM; } else { return MONGOC_SERVER_MONITORING_AUTO; } } /* Create a new server monitor. * * Called during reconcile. * Caller must hold topology lock. */ mongoc_server_monitor_t * mongoc_server_monitor_new (mongoc_topology_t *topology, mongoc_topology_description_t *td, mongoc_server_description_t *init_description) { mongoc_server_monitor_t *server_monitor = bson_malloc0 (sizeof (*server_monitor)); server_monitor->description = mongoc_server_description_new_copy (init_description); server_monitor->server_id = init_description->id; server_monitor->topology = topology; server_monitor->heartbeat_frequency_ms = td->heartbeat_msec; server_monitor->min_heartbeat_frequency_ms = topology->min_heartbeat_frequency_msec; server_monitor->connect_timeout_ms = topology->connect_timeout_msec; server_monitor->uri = mongoc_uri_copy (topology->uri); /* TODO CDRIVER-3682: Do not retrieve ssl opts from topology scanner. They * should be stored somewhere else. */ #ifdef MONGOC_ENABLE_SSL if (topology->scanner->ssl_opts) { server_monitor->ssl_opts = bson_malloc0 (sizeof (mongoc_ssl_opt_t)); _mongoc_ssl_opts_copy_to (topology->scanner->ssl_opts, server_monitor->ssl_opts, true); } #endif server_monitor->initiator = topology->scanner->initiator; server_monitor->initiator_context = topology->scanner->initiator_context; server_monitor->mode = _server_monitor_get_mode_enum (server_monitor); mongoc_cond_init (&server_monitor->shared.cond); bson_mutex_init (&server_monitor->shared.mutex); return server_monitor; } /* Creates a stream and performs the initial hello handshake. * * Called only by server monitor thread. * Returns true if both connection and handshake succeeds. * Returns false and sets error otherwise. * hello_response is always initialized. */ static bool _server_monitor_setup_connection (mongoc_server_monitor_t *server_monitor, bson_t *hello_response, int64_t *start_us, bson_error_t *error) { bson_t cmd = BSON_INITIALIZER; bool ret = false; ENTRY; BSON_ASSERT (!server_monitor->stream); bson_init (hello_response); server_monitor->more_to_come = false; /* Using an initiator isn't really necessary. Users can't set them on * pools. But it is used for tests. */ if (server_monitor->initiator) { server_monitor->stream = server_monitor->initiator ( server_monitor->uri, &server_monitor->description->host, server_monitor->initiator_context, error); } else { void *ssl_opts_void = NULL; void *openssl_ctx_void = NULL; #ifdef MONGOC_ENABLE_SSL ssl_opts_void = server_monitor->ssl_opts; #endif #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L openssl_ctx_void = server_monitor->topology->scanner->openssl_ctx; #endif server_monitor->stream = mongoc_client_connect (false, ssl_opts_void != NULL, ssl_opts_void, server_monitor->uri, &server_monitor->description->host, openssl_ctx_void, error); } if (!server_monitor->stream) { GOTO (fail); } /* Update the start time just before the handshake. */ *start_us = _now_us (); /* Perform handshake. */ bson_destroy (&cmd); _mongoc_topology_dup_handshake_cmd (server_monitor->topology, &cmd); _server_monitor_append_cluster_time (server_monitor, &cmd); bson_destroy (hello_response); ret = _server_monitor_send_and_recv (server_monitor, &cmd, hello_response, error); fail: bson_destroy (&cmd); RETURN (ret); } /** * @brief Perform a hello check on a server * * @param server_monitor The server monitor for this server. * @param previous_description The most recent view of the description of this * server. * @param cancelled Output parameter: Whether the monitor check is cancelled. * @return mongoc_server_description_t* The newly created updated server * description. * * @note May update the topology description associated with the server monitor. * * @note In case of error, returns a new server description with the error * information, but with no hello reply. */ static mongoc_server_description_t * _server_monitor_check_server (mongoc_server_monitor_t *server_monitor, const mongoc_server_description_t *previous_description, bool *cancelled) { bool ret = false; bson_error_t error; bson_t hello_response; int64_t duration_us; int64_t start_us; bool command_or_network_error = false; bool awaited = false; mongoc_server_description_t *description; mc_tpld_modification tdmod; ENTRY; *cancelled = false; memset (&error, 0, sizeof (bson_error_t)); description = BSON_ALIGNED_ALLOC0 (mongoc_server_description_t); mongoc_server_description_init ( description, server_monitor->description->connection_address, server_monitor->description->id); start_us = _now_us (); if (!server_monitor->stream) { MONITOR_LOG (server_monitor, "setting up connection"); awaited = false; _server_monitor_heartbeat_started (server_monitor, awaited); ret = _server_monitor_setup_connection (server_monitor, &hello_response, &start_us, &error); GOTO (exit); } if (server_monitor->more_to_come) { awaited = true; /* Publish a heartbeat started for each additional response read. */ _server_monitor_heartbeat_started (server_monitor, awaited); MONITOR_LOG (server_monitor, "more to come"); ret = _server_monitor_awaitable_hello_recv (server_monitor, &hello_response, cancelled, &error); GOTO (exit); } if (server_monitor->mode != MONGOC_SERVER_MONITORING_POLL && !bson_empty (&previous_description->topology_version) && (_mongoc_handshake_get ()->env == MONGOC_HANDSHAKE_ENV_NONE || server_monitor->mode == MONGOC_SERVER_MONITORING_STREAM)) { // Use stream monitoring if: // - serverMonitoringMode != "poll" // - Server supports stream monitoring (indicated by `topologyVersion`). // - ONE OF: // - Application is not in an FaaS environment (e.g. AWS Lambda). // - serverMonitoringMode == "stream" awaited = true; _server_monitor_heartbeat_started (server_monitor, awaited); MONITOR_LOG (server_monitor, "awaitable hello"); ret = _server_monitor_awaitable_hello (server_monitor, previous_description, &hello_response, cancelled, &error); GOTO (exit); } MONITOR_LOG (server_monitor, "polling hello"); awaited = false; _server_monitor_heartbeat_started (server_monitor, awaited); ret = _server_monitor_polling_hello (server_monitor, previous_description->hello_ok, &hello_response, &error); exit: duration_us = _now_us () - start_us; MONITOR_LOG (server_monitor, "server check duration (us): %" PRId64, duration_us); /* If ret is true, we have a reply. Check if "ok": 1. */ if (ret && _mongoc_cmd_check_ok (&hello_response, MONGOC_ERROR_API_VERSION_2, &error)) { int64_t rtt_ms = MONGOC_RTT_UNSET; /* rtt remains MONGOC_RTT_UNSET if awaited. */ if (!awaited) { rtt_ms = duration_us / 1000; } mongoc_server_description_handle_hello (description, &hello_response, rtt_ms, NULL); /* If the hello reply could not be parsed, consider this a command * error. */ if (description->error.code) { MONITOR_LOG_ERROR (server_monitor, "error parsing server reply: %s", description->error.message); command_or_network_error = true; _server_monitor_heartbeat_failed (server_monitor, &description->error, duration_us, awaited); } else { _server_monitor_heartbeat_succeeded (server_monitor, &hello_response, duration_us, awaited); } } else if (*cancelled) { MONITOR_LOG (server_monitor, "server monitor cancelled"); if (server_monitor->stream) { mongoc_stream_destroy (server_monitor->stream); } server_monitor->stream = NULL; server_monitor->more_to_come = false; _server_monitor_heartbeat_failed (server_monitor, &description->error, duration_us, awaited); } else { /* The hello reply had "ok":0 or a network error occurred. */ MONITOR_LOG_ERROR (server_monitor, "command or network error occurred: %s", error.message); command_or_network_error = true; mongoc_server_description_handle_hello (description, NULL, MONGOC_RTT_UNSET, &error); _server_monitor_heartbeat_failed (server_monitor, &description->error, duration_us, awaited); } if (command_or_network_error) { if (server_monitor->stream) { mongoc_stream_failed (server_monitor->stream); } server_monitor->stream = NULL; server_monitor->more_to_come = false; tdmod = mc_tpld_modify_begin (server_monitor->topology); /* clear_connection_pool() is a no-op if 'description->id' was already * removed. */ _mongoc_topology_description_clear_connection_pool ( tdmod.new_td, server_monitor->description->id, &server_monitor->description->service_id); mc_tpld_modify_commit (tdmod); } bson_destroy (&hello_response); return description; } /* Request scan of a single server. * * Locks server monitor mutex to deliver scan_requested. */ void mongoc_server_monitor_request_scan (mongoc_server_monitor_t *server_monitor) { MONITOR_LOG (server_monitor, "requesting scan"); bson_mutex_lock (&server_monitor->shared.mutex); server_monitor->shared.scan_requested = true; mongoc_cond_signal (&server_monitor->shared.cond); bson_mutex_unlock (&server_monitor->shared.mutex); } /* Request cancellation of an in progress awaitable hello. * * Called from app threads on network errors and during shutdown. * Locks server monitor mutex. */ void mongoc_server_monitor_request_cancel (mongoc_server_monitor_t *server_monitor) { MONITOR_LOG (server_monitor, "requesting cancel"); bson_mutex_lock (&server_monitor->shared.mutex); server_monitor->shared.cancel_requested = true; mongoc_cond_signal (&server_monitor->shared.cond); bson_mutex_unlock (&server_monitor->shared.mutex); } /* Wait for heartbeatFrequencyMS or minHeartbeatFrequencyMS if a scan is * requested. * * Locks server monitor mutex. */ void mongoc_server_monitor_wait (mongoc_server_monitor_t *server_monitor) { int64_t start_ms; int64_t scan_due_ms; start_ms = _now_ms (); scan_due_ms = start_ms + server_monitor->heartbeat_frequency_ms; bson_mutex_lock (&server_monitor->shared.mutex); while (true) { int64_t sleep_duration_ms; int cond_ret; if (server_monitor->shared.state != MONGOC_THREAD_RUNNING) { break; } if (server_monitor->shared.scan_requested) { server_monitor->shared.scan_requested = false; scan_due_ms = start_ms + server_monitor->min_heartbeat_frequency_ms; } sleep_duration_ms = scan_due_ms - _now_ms (); if (sleep_duration_ms <= 0) { break; } MONITOR_LOG (server_monitor, "sleeping for %" PRId64, sleep_duration_ms); cond_ret = mongoc_cond_timedwait (&server_monitor->shared.cond, &server_monitor->shared.mutex, sleep_duration_ms); if (mongo_cond_ret_is_timedout (cond_ret)) { break; } } bson_mutex_unlock (&server_monitor->shared.mutex); } /* The server monitor thread function. * * Server monitor must be in state MONGOC_THREAD_OFF. */ static BSON_THREAD_FUN (_server_monitor_thread, server_monitor_void) { mongoc_server_monitor_t *server_monitor; mongoc_server_description_t *description; mongoc_server_description_t *previous_description; server_monitor = (mongoc_server_monitor_t *) server_monitor_void; description = mongoc_server_description_new_copy (server_monitor->description); previous_description = NULL; while (true) { bool cancelled = false; bson_mutex_lock (&server_monitor->shared.mutex); if (server_monitor->shared.state != MONGOC_THREAD_RUNNING) { bson_mutex_unlock (&server_monitor->shared.mutex); break; } bson_mutex_unlock (&server_monitor->shared.mutex); mongoc_server_description_destroy (previous_description); previous_description = mongoc_server_description_new_copy (description); mongoc_server_description_destroy (description); description = _server_monitor_check_server (server_monitor, previous_description, &cancelled); if (cancelled) { mongoc_server_monitor_wait (server_monitor); continue; } _update_topology_description (server_monitor, description); /* Immediately proceed to the next check if the previous response was * successful and included the topologyVersion field. */ if (description->type != MONGOC_SERVER_UNKNOWN && !bson_empty (&description->topology_version)) { MONITOR_LOG (server_monitor, "immediately proceeding due to topologyVersion"); continue; } /* ... or the previous response included the moreToCome flag */ if (server_monitor->more_to_come) { MONITOR_LOG (server_monitor, "immediately proceeding due to moreToCome"); continue; } /* ... or the server has just transitioned to Unknown due to a network * error. */ if (_mongoc_error_is_network (&description->error) && previous_description->type != MONGOC_SERVER_UNKNOWN) { MONITOR_LOG (server_monitor, "immediately proceeding due to network error"); continue; } mongoc_server_monitor_wait (server_monitor); } bson_mutex_lock (&server_monitor->shared.mutex); server_monitor->shared.state = MONGOC_THREAD_JOINABLE; bson_mutex_unlock (&server_monitor->shared.mutex); mongoc_server_description_destroy (previous_description); mongoc_server_description_destroy (description); BSON_THREAD_RETURN; } static bool _server_monitor_ping_server (mongoc_server_monitor_t *server_monitor, bool hello_ok, int64_t *rtt_ms) { bool ret = false; int64_t start_us = _now_us (); bson_t hello_response; bson_error_t error; *rtt_ms = MONGOC_RTT_UNSET; if (!server_monitor->stream) { MONITOR_LOG (server_monitor, "rtt setting up connection"); ret = _server_monitor_setup_connection (server_monitor, &hello_response, &start_us, &error); bson_destroy (&hello_response); } if (server_monitor->stream) { MONITOR_LOG (server_monitor, "rtt polling hello"); ret = _server_monitor_polling_hello (server_monitor, hello_ok, &hello_response, &error); if (ret) { *rtt_ms = (_now_us () - start_us) / 1000; } bson_destroy (&hello_response); } return ret; } /* The RTT monitor thread function. * * Server monitor must be in state MONGOC_THREAD_OFF. */ static BSON_THREAD_FUN (_server_monitor_rtt_thread, server_monitor_void) { mongoc_server_monitor_t *server_monitor = server_monitor_void; while (true) { int64_t rtt_ms; bson_error_t error; bool hello_ok; bson_mutex_lock (&server_monitor->shared.mutex); if (server_monitor->shared.state != MONGOC_THREAD_RUNNING) { bson_mutex_unlock (&server_monitor->shared.mutex); break; } bson_mutex_unlock (&server_monitor->shared.mutex); { mc_shared_tpld td = mc_tpld_take_ref (server_monitor->topology); const mongoc_server_description_t *sd = mongoc_topology_description_server_by_id_const (td.ptr, server_monitor->description->id, &error); hello_ok = sd ? sd->hello_ok : false; mc_tpld_drop_ref (&td); } _server_monitor_ping_server (server_monitor, hello_ok, &rtt_ms); if (rtt_ms != MONGOC_RTT_UNSET) { mc_tpld_modification tdmod = mc_tpld_modify_begin (server_monitor->topology); mongoc_server_description_t *const mut_sd = mongoc_topology_description_server_by_id (tdmod.new_td, server_monitor->description->id, &error); if (mut_sd) { mongoc_server_description_update_rtt (mut_sd, rtt_ms); mc_tpld_modify_commit (tdmod); } else { /* If the server description has been removed, the RTT thread will * be terminated by background monitoring soon, so we have nothing * to do but wait until we are about to be stopped. */ mc_tpld_modify_drop (tdmod); } } mongoc_server_monitor_wait (server_monitor); } bson_mutex_lock (&server_monitor->shared.mutex); server_monitor->shared.state = MONGOC_THREAD_JOINABLE; bson_mutex_unlock (&server_monitor->shared.mutex); BSON_THREAD_RETURN; } void mongoc_server_monitor_run (mongoc_server_monitor_t *server_monitor) { bson_mutex_lock (&server_monitor->shared.mutex); if (server_monitor->shared.state == MONGOC_THREAD_OFF) { server_monitor->is_rtt = false; int ret = mcommon_thread_create (&server_monitor->thread, _server_monitor_thread, server_monitor); if (ret == 0) { server_monitor->shared.state = MONGOC_THREAD_RUNNING; } else { char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; char *errmsg = bson_strerror_r (ret, errmsg_buf, sizeof errmsg_buf); _server_monitor_log (server_monitor, MONGOC_LOG_LEVEL_ERROR, "Failed to start monitoring thread. This server " "may not be selectable. Error: %s", errmsg); } } bson_mutex_unlock (&server_monitor->shared.mutex); } void mongoc_server_monitor_run_as_rtt (mongoc_server_monitor_t *server_monitor) { bson_mutex_lock (&server_monitor->shared.mutex); if (server_monitor->shared.state == MONGOC_THREAD_OFF) { server_monitor->is_rtt = true; int ret = mcommon_thread_create (&server_monitor->thread, _server_monitor_rtt_thread, server_monitor); if (ret == 0) { server_monitor->shared.state = MONGOC_THREAD_RUNNING; } else { char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; char *errmsg = bson_strerror_r (ret, errmsg_buf, sizeof errmsg_buf); _server_monitor_log (server_monitor, MONGOC_LOG_LEVEL_ERROR, "Failed to start Round-Trip Time monitoring thread. Error: %s", errmsg); } } bson_mutex_unlock (&server_monitor->shared.mutex); } /* Request thread shutdown. * * Returns true if in state MONGOC_THREAD_OFF and the server monitor can be * safely destroyed. * Called during topology description reconcile. * Locks server monitor mutex. */ bool mongoc_server_monitor_request_shutdown (mongoc_server_monitor_t *server_monitor) { bool off = false; bson_mutex_lock (&server_monitor->shared.mutex); if (server_monitor->shared.state == MONGOC_THREAD_RUNNING) { server_monitor->shared.state = MONGOC_THREAD_SHUTTING_DOWN; } if (server_monitor->shared.state == MONGOC_THREAD_JOINABLE) { mcommon_thread_join (server_monitor->thread); server_monitor->shared.state = MONGOC_THREAD_OFF; } if (server_monitor->shared.state == MONGOC_THREAD_OFF) { off = true; } mongoc_cond_signal (&server_monitor->shared.cond); bson_mutex_unlock (&server_monitor->shared.mutex); /* Cancel an in-progress hello check. */ if (!off) { mongoc_server_monitor_request_cancel (server_monitor); } return off; } /* Request thread shutdown and block until the server monitor thread terminates. * * Called by one thread. * Locks the server monitor mutex. */ void mongoc_server_monitor_wait_for_shutdown (mongoc_server_monitor_t *server_monitor) { if (mongoc_server_monitor_request_shutdown (server_monitor)) { return; } /* Shutdown requested, but thread is not yet off. Wait. */ mcommon_thread_join (server_monitor->thread); bson_mutex_lock (&server_monitor->shared.mutex); server_monitor->shared.state = MONGOC_THREAD_OFF; bson_mutex_unlock (&server_monitor->shared.mutex); } /* Destroy a server monitor. * * Called only by one thread. * Caller must not hold server monitor lock. * Server monitor thread is in state MONGOC_THREAD_OFF. */ void mongoc_server_monitor_destroy (mongoc_server_monitor_t *server_monitor) { if (!server_monitor) { return; } /* Locking not necessary since this is only called by one thread, and server * monitor thread is no longer running. */ BSON_ASSERT (server_monitor->shared.state == MONGOC_THREAD_OFF); mongoc_server_description_destroy (server_monitor->description); mongoc_stream_destroy (server_monitor->stream); mongoc_uri_destroy (server_monitor->uri); mongoc_cond_destroy (&server_monitor->shared.cond); bson_mutex_destroy (&server_monitor->shared.mutex); #ifdef MONGOC_ENABLE_SSL if (server_monitor->ssl_opts) { _mongoc_ssl_opts_cleanup (server_monitor->ssl_opts, true); bson_free (server_monitor->ssl_opts); } #endif bson_free (server_monitor); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-stream-private.h0000644000175100001660000000417614760300420025416 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SERVER_STREAM_H #define MONGOC_SERVER_STREAM_H #include #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_server_stream_t { mongoc_topology_description_type_t topology_type; mongoc_server_description_t *sd; // owned bson_t cluster_time; // owned mongoc_stream_t *stream; // borrowed // If the stream was created in a way that may have overwritten the user's // readPreference, we need to know if server selection forced that change. bool must_use_primary; // True if this server stream was acquired during a retry attempt triggered // by a network error establishing an initial connection. Used to avoid // further retry attempts. bool retry_attempted; } mongoc_server_stream_t; mongoc_server_stream_t * mongoc_server_stream_new (const mongoc_topology_description_t *td, mongoc_server_description_t *sd, mongoc_stream_t *stream); int32_t mongoc_server_stream_max_bson_obj_size (mongoc_server_stream_t *server_stream); int32_t mongoc_server_stream_max_msg_size (mongoc_server_stream_t *server_stream); int32_t mongoc_server_stream_max_write_batch_size (mongoc_server_stream_t *server_stream); void mongoc_server_stream_cleanup (mongoc_server_stream_t *server_stream); BSON_END_DECLS #endif /* MONGOC_SERVER_STREAM_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-server-stream.c0000644000175100001660000000611114760300420023730 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "server-stream" mongoc_server_stream_t * mongoc_server_stream_new (const mongoc_topology_description_t *td, mongoc_server_description_t *sd, mongoc_stream_t *stream) { mongoc_server_stream_t *server_stream; BSON_ASSERT (sd); BSON_ASSERT (stream); server_stream = BSON_ALIGNED_ALLOC (mongoc_server_stream_t); server_stream->topology_type = td->type; bson_copy_to (&td->cluster_time, &server_stream->cluster_time); server_stream->sd = sd; /* becomes owned */ server_stream->stream = stream; /* merely borrowed */ server_stream->must_use_primary = false; server_stream->retry_attempted = false; return server_stream; } void mongoc_server_stream_cleanup (mongoc_server_stream_t *server_stream) { if (server_stream) { mongoc_server_description_destroy (server_stream->sd); bson_destroy (&server_stream->cluster_time); bson_free (server_stream); } } /* *-------------------------------------------------------------------------- * * mongoc_server_stream_max_bson_obj_size -- * * Return the max bson object size for the given server stream. * *-------------------------------------------------------------------------- */ int32_t mongoc_server_stream_max_bson_obj_size (mongoc_server_stream_t *server_stream) { return COALESCE (server_stream->sd->max_bson_obj_size, MONGOC_DEFAULT_BSON_OBJ_SIZE); } /* *-------------------------------------------------------------------------- * * mongoc_server_stream_max_msg_size -- * * Return the max message size for the given server stream. * *-------------------------------------------------------------------------- */ int32_t mongoc_server_stream_max_msg_size (mongoc_server_stream_t *server_stream) { return COALESCE (server_stream->sd->max_msg_size, MONGOC_DEFAULT_MAX_MSG_SIZE); } /* *-------------------------------------------------------------------------- * * mongoc_server_stream_max_write_batch_size -- * * Return the max write batch size for the given server stream. * *-------------------------------------------------------------------------- */ int32_t mongoc_server_stream_max_write_batch_size (mongoc_server_stream_t *server_stream) { return COALESCE (server_stream->sd->max_write_batch_size, MONGOC_DEFAULT_WRITE_BATCH_SIZE); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-set-private.h0000644000175100001660000000646514760300420023415 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SET_PRIVATE_H #define MONGOC_SET_PRIVATE_H #include BSON_BEGIN_DECLS typedef void (*mongoc_set_item_dtor) (void *item, void *ctx); /* return true to continue iteration, false to stop */ typedef bool (*mongoc_set_for_each_cb_t) (void *item, void *ctx); typedef bool (*mongoc_set_for_each_const_cb_t) (const void *item, void *ctx); typedef bool (*mongoc_set_for_each_with_id_cb_t) (uint32_t id, void *item, void *ctx); typedef bool (*mongoc_set_for_each_with_id_const_cb_t) (uint32_t id, const void *item, void *ctx); typedef struct { uint32_t id; void *item; } mongoc_set_item_t; typedef struct { mongoc_set_item_t *items; size_t items_len; size_t items_allocated; mongoc_set_item_dtor dtor; void *dtor_ctx; } mongoc_set_t; mongoc_set_t * mongoc_set_new (size_t nitems, mongoc_set_item_dtor dtor, void *dtor_ctx); void mongoc_set_add (mongoc_set_t *set, uint32_t id, void *item); void mongoc_set_rm (mongoc_set_t *set, uint32_t id); void * mongoc_set_get (mongoc_set_t *set, uint32_t id); static BSON_INLINE const void * mongoc_set_get_const (const mongoc_set_t *set, uint32_t id) { return mongoc_set_get ((mongoc_set_t *) set, id); } void * mongoc_set_get_item (mongoc_set_t *set, size_t idx); static BSON_INLINE const void * mongoc_set_get_item_const (const mongoc_set_t *set, size_t idx) { return mongoc_set_get_item ((mongoc_set_t *) set, idx); } void * mongoc_set_get_item_and_id (mongoc_set_t *set, size_t idx, uint32_t *id /* OUT */); static BSON_INLINE const void * mongoc_set_get_item_and_id_const (const mongoc_set_t *set, size_t idx, uint32_t *id) { return mongoc_set_get_item_and_id ((mongoc_set_t *) set, idx, id); } void mongoc_set_destroy (mongoc_set_t *set); /* loops over the set safe-ish. * * Caveats: * - you can add items at any iteration * - if you remove elements other than the one you're currently looking at, * you may see it later in the iteration */ void mongoc_set_for_each (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx); void mongoc_set_for_each_const (const mongoc_set_t *set, mongoc_set_for_each_const_cb_t cb, void *ctx); void mongoc_set_for_each_with_id (mongoc_set_t *set, mongoc_set_for_each_with_id_cb_t cb, void *ctx); void mongoc_set_for_each_with_id_const (const mongoc_set_t *set, mongoc_set_for_each_with_id_const_cb_t cb, void *ctx); /* first item in set for which "cb" returns true */ void * mongoc_set_find_item (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx); /* id of first item in set for which "cb" returns true, or 0. */ uint32_t mongoc_set_find_id (const mongoc_set_t *set, mongoc_set_for_each_const_cb_t cb, void *ctx); BSON_END_DECLS #endif /* MONGOC_SET_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-set.c0000644000175100001660000001504614760300420021733 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "set" mongoc_set_t * mongoc_set_new (size_t nitems, mongoc_set_item_dtor dtor, void *dtor_ctx) { mongoc_set_t *set = (mongoc_set_t *) bson_malloc (sizeof (*set)); set->items_allocated = BSON_MAX (nitems, 1); set->items = (mongoc_set_item_t *) bson_malloc (sizeof (*set->items) * set->items_allocated); set->items_len = 0; set->dtor = dtor; set->dtor_ctx = dtor_ctx; return set; } static int mongoc_set_id_cmp (const void *a_, const void *b_) { mongoc_set_item_t *a = (mongoc_set_item_t *) a_; mongoc_set_item_t *b = (mongoc_set_item_t *) b_; if (a->id == b->id) { return 0; } return a->id < b->id ? -1 : 1; } void mongoc_set_add (mongoc_set_t *set, uint32_t id, void *item) { if (set->items_len >= set->items_allocated) { set->items_allocated *= 2; set->items = (mongoc_set_item_t *) bson_realloc (set->items, sizeof (*set->items) * set->items_allocated); } set->items[set->items_len].id = id; set->items[set->items_len].item = item; set->items_len++; if (set->items_len > 1 && set->items[set->items_len - 2].id > id) { qsort (set->items, set->items_len, sizeof (*set->items), mongoc_set_id_cmp); } } void mongoc_set_rm (mongoc_set_t *set, uint32_t id) { const mongoc_set_item_t key = {.id = id}; mongoc_set_item_t *const ptr = (mongoc_set_item_t *) bsearch (&key, set->items, set->items_len, sizeof (key), mongoc_set_id_cmp); if (ptr) { if (set->dtor) { set->dtor (ptr->item, set->dtor_ctx); } const size_t index = (size_t) (ptr - set->items); if (index != set->items_len - 1u) { memmove (set->items + index, set->items + index + 1u, (set->items_len - (index + 1u)) * sizeof (key)); } set->items_len--; } } void * mongoc_set_get (mongoc_set_t *set, uint32_t id) { mongoc_set_item_t *ptr; mongoc_set_item_t key; key.id = id; ptr = (mongoc_set_item_t *) bsearch (&key, set->items, set->items_len, sizeof (key), mongoc_set_id_cmp); return ptr ? ptr->item : NULL; } void * mongoc_set_get_item (mongoc_set_t *set, size_t idx) { BSON_ASSERT (set); BSON_ASSERT (idx < set->items_len); return set->items[idx].item; } void * mongoc_set_get_item_and_id (mongoc_set_t *set, size_t idx, uint32_t *id /* OUT */) { BSON_ASSERT (set); BSON_ASSERT (id); BSON_ASSERT (idx < set->items_len); *id = set->items[idx].id; return set->items[idx].item; } void mongoc_set_destroy (mongoc_set_t *set) { if (set->dtor) { for (size_t i = 0u; i < set->items_len; i++) { set->dtor (set->items[i].item, set->dtor_ctx); } } bson_free (set->items); bson_free (set); } typedef struct { mongoc_set_for_each_cb_t cb; void *ctx; } _mongoc_set_for_each_helper_t; static bool _mongoc_set_for_each_helper (uint32_t id, void *item, void *ctx) { _mongoc_set_for_each_helper_t *helper = ctx; BSON_UNUSED (id); return helper->cb (item, helper->ctx); } void mongoc_set_for_each (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx) { _mongoc_set_for_each_helper_t helper = { .cb = cb, .ctx = ctx, }; mongoc_set_for_each_with_id (set, _mongoc_set_for_each_helper, &helper); } typedef struct { mongoc_set_for_each_const_cb_t cb; void *ctx; } _mongoc_set_for_each_const_helper_t; static bool _mongoc_set_for_each_const_helper (uint32_t id, const void *item, void *ctx) { _mongoc_set_for_each_const_helper_t *helper = ctx; BSON_UNUSED (id); return helper->cb (item, helper->ctx); } void mongoc_set_for_each_const (const mongoc_set_t *set, mongoc_set_for_each_const_cb_t cb, void *ctx) { _mongoc_set_for_each_const_helper_t helper = { .cb = cb, .ctx = ctx, }; mongoc_set_for_each_with_id_const (set, _mongoc_set_for_each_const_helper, &helper); } void mongoc_set_for_each_with_id (mongoc_set_t *set, mongoc_set_for_each_with_id_cb_t cb, void *ctx) { BSON_ASSERT_PARAM (set); BSON_ASSERT_PARAM (cb); BSON_ASSERT (ctx || true); BSON_ASSERT (mcommon_in_range_unsigned (uint32_t, set->items_len)); const uint32_t items_len = (uint32_t) set->items_len; /* prevent undefined behavior of memcpy(NULL) */ if (items_len == 0) { return; } mongoc_set_item_t *const old_set = bson_malloc (sizeof (*old_set) * items_len); memcpy (old_set, set->items, sizeof (*old_set) * items_len); for (uint32_t i = 0u; i < items_len; i++) { void *const item = old_set[i].item; if (!cb (i, item, ctx)) { break; } } bson_free (old_set); } void mongoc_set_for_each_with_id_const (const mongoc_set_t *set, mongoc_set_for_each_with_id_const_cb_t cb, void *ctx) { BSON_ASSERT_PARAM (set); BSON_ASSERT_PARAM (cb); BSON_ASSERT (ctx || true); BSON_ASSERT (mcommon_in_range_unsigned (uint32_t, set->items_len)); const uint32_t items_len = (uint32_t) set->items_len; /* prevent undefined behavior of memcpy(NULL) */ if (items_len == 0) { return; } mongoc_set_item_t *const old_set = bson_malloc (sizeof (*old_set) * items_len); memcpy (old_set, set->items, sizeof (*old_set) * items_len); for (uint32_t i = 0u; i < items_len; i++) { const void *const item = old_set[i].item; if (!cb (i, item, ctx)) { break; } } bson_free (old_set); } void * mongoc_set_find_item (mongoc_set_t *set, mongoc_set_for_each_cb_t cb, void *ctx) { for (size_t i = 0u; i < set->items_len; i++) { mongoc_set_item_t *const item = set->items + i; if (cb (item->item, ctx)) { return item; } } return NULL; } uint32_t mongoc_set_find_id (const mongoc_set_t *set, mongoc_set_for_each_const_cb_t cb, void *ctx) { for (size_t i = 0u; i < set->items_len; i++) { const mongoc_set_item_t *const item = set->items + i; if (cb (item->item, ctx)) { return item->id; } } return 0; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-shared-private.h0000644000175100001660000001611314760300420024057 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SHARED_H #define MONGOC_SHARED_H #include #include /** * @brief A ref-counted thread-safe shared pointer to arbitrary data. * * `shared_ptr` instances manage the lifetime of a pointed-to object when the * precise time to destroy that managed object is indeterminate, such as with * shared state in a multithreaded or asynchronous program. * * The pointed-to object of a shared_ptr instance can be accessed via * the `ptr` member of the shared_ptr object. Assigning-to the `ptr` member of * a shared_ptr is legal, and can be done to change the pointed-to object of a * shared_ptr without changing which object is being managed. This can be done * to return a pointer to a subobject of the managed object without giving * out a reference to the full managed object. * * A new managed object with a `shared_ptr` is created with * `mongoc_shared_ptr_create`, which starts with an initial shared reference * count of `1`. To take another reference to keep the managed object alive, * use `mongoc_shared_ptr_copy`. When one is done with a managed resource, the * shared reference should be dropped using `mongoc_shared_ptr_reset_null`. * * When an operation on a shared_ptr causes the reference count to drop to zero, * the deleter that was given to create that shared state will immediately be * invoked with the pointed-to-data. The deleter runs in the thread that * caused the reference count to drop, so be aware that resetting or assigning * a shared_ptr can execute unseen code: Refrain from holding locks while * resetting/assigning a shared pointer. */ typedef struct mongoc_shared_ptr { /** Pointed-to data */ void *ptr; /** Auxilary book-keeping. Do not touch. */ struct _mongoc_shared_ptr_aux *_aux; } mongoc_shared_ptr; /** * @brief A "null" pointer constant for a mongoc_shared_ptr. */ #define MONGOC_SHARED_PTR_NULL \ ((mongoc_shared_ptr){ \ .ptr = NULL, \ ._aux = NULL, \ }) /** * @brief Reassign a shared pointer to manage the given resource * * @param ptr The shared pointer that will be rebound * @param pointee The pointer that we will point to. * @param deleter A deleter for `pointee`, to be called when the refcount * reaches zero. * * @note Equivalent to: * * mongoc_shared_ptr_reset_null(ptr); * *ptr = mongoc_shared_ptr_create(pointee, deleter); */ extern void mongoc_shared_ptr_reset (mongoc_shared_ptr *ptr, void *pointee, void (*deleter) (void *)); /** * @brief Reassign the given shared pointer to manage the same resource as * 'from' * * If `dest` manages an existing object, the reference count of that managed * object will be decremented. If this causes its refcount to reach zero, then * the deleter function will be executed with the pointee. * * @param dest The shared pointer to change * @param from The shared pointer to take from * * @note Equivalent to: * * mongoc_shared_ptr_reset_null(dest); * *dest = mongoc_shared_ptr_copy(from); */ extern void mongoc_shared_ptr_assign (mongoc_shared_ptr *dest, mongoc_shared_ptr from); /** * @brief Reassign the given shared pointer to manage the same resource as * 'from' * * This atomic function is safe to call between threads when 'dest' may be * accessed simultaneously from another thread even if any of those accesses are * a write. However: Any potential reads *must* be done using * `mongoc_atomic_shared_ptr_load` and any potential writes *must* be done using * `mongoc_atomic_shared_ptr_store`. * * @param dest The shared pointer to change * @param from The shared pointer to take from * * Thread-safe equivalent of `mongoc_shared_ptr_assign` */ extern void mongoc_atomic_shared_ptr_store (mongoc_shared_ptr *dest, mongoc_shared_ptr from); /** * @brief Create a copy of the given shared pointer. Increases the reference * count on the object. * * @param ptr The pointer to copy from * @returns a new shared pointer that has the same pointee as ptr * * @note Must later reset/reassign the returned shared pointer */ extern mongoc_shared_ptr mongoc_shared_ptr_copy (mongoc_shared_ptr ptr); /** * @brief Like `mongoc_shared_ptr_copy`, but is thread-safe in case `*ptr` * may be accessed simultaneously from other threads even if any of those * accesses are writes. However: such potential writes *must* use * `mongoc_atomic_shared_ptr_store`. * * This is a thread-safe equivalent of `mongoc_shared_ptr_copy`. * * @note Must later reset/reassign the returned shared pointer */ extern mongoc_shared_ptr mongoc_atomic_shared_ptr_load (mongoc_shared_ptr const *ptr); /** * @brief Release the ownership of the given shared pointer. * * The shared pointer object and ptr->ptr will be reset to NULL, and the * reference count of the managed object will be decremented. * * If this causes the refcount to reach zero, then the deleter function will * be executed with the pointee. * * @param ptr The pointer to release and set to NULL * * @note This function is not thread safe if other threads may be * writing to `ptr` simultaneously. To do a thread-safe null-reset of a shared * pointer, use mongoc_atomic_shared_ptr_store() with a null * mongoc_shared_ptr as the 'from' argument */ extern void mongoc_shared_ptr_reset_null (mongoc_shared_ptr *ptr); /** * @brief Obtain the number of hard references to the resource managed by the * given shared pointer. This should only be used for diagnostic and assertive * purposes. * * @param ptr A non-null shared pointer to check * @return int A positive integer reference count */ extern int mongoc_shared_ptr_use_count (mongoc_shared_ptr ptr); /** * @brief Check whether the given shared pointer is managing a resource. * * @note The ptr.ptr MAY be NULL while the shared pointer is still managing * a resource. * * @return true If the pointer is managing a resource * @return false Otherwise */ static BSON_INLINE int mongoc_shared_ptr_is_null (mongoc_shared_ptr ptr) { return ptr._aux == 0; } /** * @brief Create a new shared pointer that manages the given resource, or NULL * * @param pointee The target of the pointer. Should be NULL or a dynamically * allocated data segment * @param deleter The deleter for the pointer. If `pointee` is non-NULL, * `deleter` must be non-NULL. This deleter will be called when the reference * count reaches zero. If should release the resources referred-to by `pointee`. */ extern mongoc_shared_ptr mongoc_shared_ptr_create (void *pointee, void (*deleter) (void *)); #endif /* MONGOC_SHARED_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-shared.c0000644000175100001660000001027414760300420022404 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include typedef struct _mongoc_shared_ptr_aux { int refcount; void (*deleter) (void *); void *managed; } _mongoc_shared_ptr_aux; static void _release_aux (_mongoc_shared_ptr_aux *aux) { aux->deleter (aux->managed); bson_free (aux); } static bson_shared_mutex_t g_shared_ptr_mtx; static bson_once_t g_shared_ptr_mtx_init_once = BSON_ONCE_INIT; static BSON_ONCE_FUN (_init_mtx) { bson_shared_mutex_init (&g_shared_ptr_mtx); BSON_ONCE_RETURN; } void mongoc_shared_ptr_reset (mongoc_shared_ptr *ptr, void *pointee, void (*deleter) (void *)) { BSON_ASSERT_PARAM (ptr); if (!mongoc_shared_ptr_is_null (*ptr)) { /* Release the old value of the pointer, possibly destroying it */ mongoc_shared_ptr_reset_null (ptr); } ptr->ptr = pointee; ptr->_aux = NULL; /* Take the new value */ if (pointee != NULL) { BSON_ASSERT (deleter != NULL); ptr->_aux = bson_malloc0 (sizeof (_mongoc_shared_ptr_aux)); ptr->_aux->deleter = deleter; ptr->_aux->refcount = 1; ptr->_aux->managed = pointee; } bson_once (&g_shared_ptr_mtx_init_once, _init_mtx); } void mongoc_shared_ptr_assign (mongoc_shared_ptr *dest, mongoc_shared_ptr from) { /* Copy from 'from' *first*, since this might be a self-assignment. */ mongoc_shared_ptr copied = mongoc_shared_ptr_copy (from); BSON_ASSERT_PARAM (dest); mongoc_shared_ptr_reset_null (dest); *dest = copied; } mongoc_shared_ptr mongoc_shared_ptr_create (void *pointee, void (*deleter) (void *)) { mongoc_shared_ptr ret = MONGOC_SHARED_PTR_NULL; mongoc_shared_ptr_reset (&ret, pointee, deleter); return ret; } void mongoc_atomic_shared_ptr_store (mongoc_shared_ptr *dest, mongoc_shared_ptr from) { mongoc_shared_ptr prev = MONGOC_SHARED_PTR_NULL; BSON_ASSERT_PARAM (dest); /* We are effectively "copying" the 'from' */ (void) mongoc_shared_ptr_copy (from); bson_shared_mutex_lock (&g_shared_ptr_mtx); /* Do the exchange. Quick! */ prev = *dest; *dest = from; bson_shared_mutex_unlock (&g_shared_ptr_mtx); /* Free the pointer that we just overwrote */ mongoc_shared_ptr_reset_null (&prev); } mongoc_shared_ptr mongoc_atomic_shared_ptr_load (mongoc_shared_ptr const *ptr) { mongoc_shared_ptr r; BSON_ASSERT_PARAM (ptr); bson_shared_mutex_lock_shared (&g_shared_ptr_mtx); r = mongoc_shared_ptr_copy (*ptr); bson_shared_mutex_unlock_shared (&g_shared_ptr_mtx); return r; } mongoc_shared_ptr mongoc_shared_ptr_copy (mongoc_shared_ptr ptr) { mongoc_shared_ptr ret = ptr; if (!mongoc_shared_ptr_is_null (ptr)) { mcommon_atomic_int_fetch_add (&ret._aux->refcount, 1, mcommon_memory_order_acquire); } return ret; } void mongoc_shared_ptr_reset_null (mongoc_shared_ptr *ptr) { int prevcount = 0; BSON_ASSERT_PARAM (ptr); if (mongoc_shared_ptr_is_null (*ptr)) { /* Already null. Okay. */ return; } /* Decrement the reference count by one */ prevcount = mcommon_atomic_int_fetch_sub (&ptr->_aux->refcount, 1, mcommon_memory_order_acq_rel); if (prevcount == 1) { /* We just decremented from one to zero, so this is the last instance. * Release the managed data. */ _release_aux (ptr->_aux); } ptr->_aux = NULL; ptr->ptr = NULL; } int mongoc_shared_ptr_use_count (mongoc_shared_ptr ptr) { BSON_ASSERT (!mongoc_shared_ptr_is_null (ptr) && "Unbound mongoc_shared_ptr given to mongoc_shared_ptr_use_count"); return mcommon_atomic_int_fetch (&ptr._aux->refcount, mcommon_memory_order_relaxed); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-sleep.h0000644000175100001660000000205414760300420022250 0ustar #include #ifndef MONGOC_SLEEP_H #define MONGOC_SLEEP_H #include #include BSON_BEGIN_DECLS /** * mongoc_usleep_func_t: * @usec: Number of microseconds to sleep for. * @user_data: User data provided to mongoc_client_set_usleep_impl(). */ typedef void (*mongoc_usleep_func_t) (int64_t usec, void *user_data); /** * mongoc_client_set_usleep_impl: * @usleep_func: A function to perform microsecond sleep. * * Sets the function to be called to perform sleep during scanning. * Returns the old function. * If old_user_data is not NULL, *old_user_data is set to the old user_data. * Not thread-safe. * Providing a `usleep_func` that does not sleep (e.g. coroutine suspension) is * not supported. Doing so is at the user's own risk. */ MONGOC_EXPORT (void) mongoc_client_set_usleep_impl (mongoc_client_t *client, mongoc_usleep_func_t usleep_func, void *user_data); MONGOC_EXPORT (void) mongoc_usleep_default_impl (int64_t usec, void *user_data); BSON_END_DECLS #endif /* MONGOC_SLEEP_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-socket-private.h0000644000175100001660000000201614760300420024076 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SOCKET_PRIVATE_H #define MONGOC_SOCKET_PRIVATE_H #include BSON_BEGIN_DECLS struct _mongoc_socket_t { #ifdef _WIN32 SOCKET sd; #else int sd; #endif int errno_; int domain; int pid; }; mongoc_socket_t * mongoc_socket_accept_ex (mongoc_socket_t *sock, int64_t expire_at, uint16_t *port); BSON_END_DECLS #endif /* MONGOC_SOCKET_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-socket.c0000644000175100001660000011112414760300420022422 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #endif #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "socket" #define OPERATION_EXPIRED(expire_at) ((expire_at >= 0) && (expire_at < (bson_get_monotonic_time ()))) /* either struct sockaddr or void, depending on platform */ typedef MONGOC_SOCKET_ARG2 mongoc_sockaddr_t; /* *-------------------------------------------------------------------------- * * _mongoc_socket_capture_errno -- * * Save the errno state for contextual use. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _mongoc_socket_capture_errno (mongoc_socket_t *sock) /* IN */ { #ifdef _WIN32 errno = sock->errno_ = WSAGetLastError (); #else sock->errno_ = errno; #endif TRACE ("setting errno: %d %s", sock->errno_, strerror (sock->errno_)); } /* *-------------------------------------------------------------------------- * * _mongoc_socket_setflags -- * * A helper to set socket flags. Sets to nonblocking mode. On * POSIX sets closeonexec. * * * Returns: * true if successful; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool #ifdef _WIN32 _mongoc_socket_setflags (SOCKET sd) #else _mongoc_socket_setflags (int sd) #endif { #ifdef _WIN32 u_long io_mode = 1; return (NO_ERROR == ioctlsocket (sd, FIONBIO, &io_mode)); #else int flags; flags = fcntl (sd, F_GETFL); if (-1 == fcntl (sd, F_SETFL, (flags | O_NONBLOCK))) { return false; } #ifdef FD_CLOEXEC flags = fcntl (sd, F_GETFD); if (-1 == fcntl (sd, F_SETFD, (flags | FD_CLOEXEC))) { return false; } #endif return true; #endif } /* *-------------------------------------------------------------------------- * * _mongoc_socket_wait -- * * A single socket poll helper. * * @events: in most cases should be POLLIN or POLLOUT. * * @expire_at should be an absolute time at which to expire using * the monotonic clock (bson_get_monotonic_time(), which is in * microseconds). Or zero to not block at all. Or -1 to block * forever. * * Returns: * true if an event matched. otherwise false. * a timeout will return false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_socket_wait (mongoc_socket_t *sock, /* IN */ int events, /* IN */ int64_t expire_at) /* IN */ { #ifdef _WIN32 fd_set read_fds; fd_set write_fds; fd_set error_fds; struct timeval timeout_tv; #else struct pollfd pfd; #endif int ret; int timeout; int64_t now; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (events); #ifdef _WIN32 FD_ZERO (&read_fds); FD_ZERO (&write_fds); FD_ZERO (&error_fds); if (events & POLLIN) { FD_SET (sock->sd, &read_fds); } if (events & POLLOUT) { FD_SET (sock->sd, &write_fds); } FD_SET (sock->sd, &error_fds); #else pfd.fd = sock->sd; pfd.events = events | POLLERR | POLLHUP; pfd.revents = 0; #endif now = bson_get_monotonic_time (); for (;;) { if (expire_at < 0) { timeout = -1; } else if (expire_at == 0) { timeout = 0; } else { timeout = (int) ((expire_at - now) / 1000L); if (timeout < 0) { timeout = 0; } } #ifdef _WIN32 if (timeout == -1) { /* not WSAPoll: daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken */ ret = select (0 /*unused*/, &read_fds, &write_fds, &error_fds, NULL); } else { timeout_tv.tv_sec = timeout / 1000; timeout_tv.tv_usec = (timeout % 1000) * 1000; ret = select (0 /*unused*/, &read_fds, &write_fds, &error_fds, &timeout_tv); } if (ret == SOCKET_ERROR) { _mongoc_socket_capture_errno (sock); ret = -1; } else if (FD_ISSET (sock->sd, &error_fds)) { errno = WSAECONNRESET; ret = -1; } #else ret = poll (&pfd, 1, timeout); #endif if (ret > 0) { /* Something happened, so return that */ #ifdef _WIN32 return (FD_ISSET (sock->sd, &read_fds) || FD_ISSET (sock->sd, &write_fds)); #else RETURN (0 != (pfd.revents & events)); #endif } else if (ret < 0) { /* poll itself failed */ TRACE ("errno is: %d", errno); if (MONGOC_ERRNO_IS_AGAIN (errno)) { if (OPERATION_EXPIRED (expire_at)) { _mongoc_socket_capture_errno (sock); RETURN (false); } else { continue; } } else { /* poll failed for some non-transient reason */ _mongoc_socket_capture_errno (sock); RETURN (false); } } else { /* ret == 0, poll timed out */ if (timeout) { mongoc_counter_streams_timeout_inc (); } #ifdef _WIN32 sock->errno_ = timeout ? WSAETIMEDOUT : EAGAIN; #else sock->errno_ = timeout ? ETIMEDOUT : EAGAIN; #endif RETURN (false); } } } /* *-------------------------------------------------------------------------- * * mongoc_socket_poll -- * * A multi-socket poll helper. * * @expire_at should be an absolute time at which to expire using * the monotonic clock (bson_get_monotonic_time(), which is in * microseconds). Or zero to not block at all. Or -1 to block * forever. * * Returns: * The number of sockets ready. * * Side effects: * None. * *-------------------------------------------------------------------------- */ ssize_t mongoc_socket_poll (mongoc_socket_poll_t *sds, /* IN */ size_t nsds, /* IN */ int32_t timeout) /* IN */ { #ifdef _WIN32 fd_set read_fds; fd_set write_fds; fd_set error_fds; struct timeval timeout_tv; #else struct pollfd *pfds; #endif int ret; ENTRY; BSON_ASSERT (sds); #ifdef _WIN32 FD_ZERO (&read_fds); FD_ZERO (&write_fds); FD_ZERO (&error_fds); for (size_t i = 0u; i < nsds; i++) { if (sds[i].events & POLLIN) { FD_SET (sds[i].socket->sd, &read_fds); } if (sds[i].events & POLLOUT) { FD_SET (sds[i].socket->sd, &write_fds); } FD_SET (sds[i].socket->sd, &error_fds); } timeout_tv.tv_sec = timeout / 1000; timeout_tv.tv_usec = (timeout % 1000) * 1000; /* not WSAPoll: daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken */ ret = select (0 /*unused*/, &read_fds, &write_fds, &error_fds, &timeout_tv); if (ret == SOCKET_ERROR) { errno = WSAGetLastError (); return -1; } for (size_t i = 0u; i < nsds; i++) { if (FD_ISSET (sds[i].socket->sd, &read_fds)) { sds[i].revents = POLLIN; } else if (FD_ISSET (sds[i].socket->sd, &write_fds)) { sds[i].revents = POLLOUT; } else if (FD_ISSET (sds[i].socket->sd, &error_fds)) { sds[i].revents = POLLHUP; } else { sds[i].revents = 0; } } #else pfds = (struct pollfd *) bson_malloc (sizeof (*pfds) * nsds); for (size_t i = 0u; i < nsds; i++) { pfds[i].fd = sds[i].socket->sd; pfds[i].events = sds[i].events | POLLERR | POLLHUP; pfds[i].revents = 0; } ret = poll (pfds, nsds, timeout); for (size_t i = 0u; i < nsds; i++) { sds[i].revents = pfds[i].revents; } bson_free (pfds); #endif return ret; } /* https://jira.mongodb.org/browse/CDRIVER-2176 */ #define MONGODB_KEEPALIVEINTVL 10 #define MONGODB_KEEPIDLE 120 #define MONGODB_KEEPALIVECNT 9 #ifdef _WIN32 static void _mongoc_socket_setkeepalive_windows (SOCKET sd) { struct tcp_keepalive keepalive; DWORD lpcbBytesReturned = 0; HKEY hKey; DWORD type; DWORD data; DWORD data_size = sizeof data; const char *reg_key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; keepalive.onoff = true; keepalive.keepalivetime = MONGODB_KEEPIDLE * 1000; keepalive.keepaliveinterval = MONGODB_KEEPALIVEINTVL * 1000; /* * Windows hardcodes probes to 10: * https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx * "On Windows Vista and later, the number of keep-alive probes (data * retransmissions) is set to 10 and cannot be changed." * * Note that win2k (and seeminly all versions thereafter) do not set the * registry value by default so there is no way to derive the default value * programmatically. It is however listed in the docs. A user can however * change the default value by setting the registry values. */ if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, reg_key, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) { /* https://technet.microsoft.com/en-us/library/cc957549.aspx */ DWORD default_keepalivetime = 7200000; /* 2 hours */ /* https://technet.microsoft.com/en-us/library/cc957548.aspx */ DWORD default_keepaliveinterval = 1000; /* 1 second */ if (RegQueryValueEx (hKey, "KeepAliveTime", NULL, &type, (LPBYTE) &data, &data_size) == ERROR_SUCCESS) { if (type == REG_DWORD && data < keepalive.keepalivetime) { keepalive.keepalivetime = data; } } else if (default_keepalivetime < keepalive.keepalivetime) { keepalive.keepalivetime = default_keepalivetime; } if (RegQueryValueEx (hKey, "KeepAliveInterval", NULL, &type, (LPBYTE) &data, &data_size) == ERROR_SUCCESS) { if (type == REG_DWORD && data < keepalive.keepaliveinterval) { keepalive.keepaliveinterval = data; } } else if (default_keepaliveinterval < keepalive.keepaliveinterval) { keepalive.keepaliveinterval = default_keepaliveinterval; } RegCloseKey (hKey); } if (WSAIoctl (sd, SIO_KEEPALIVE_VALS, &keepalive, sizeof keepalive, NULL, 0, &lpcbBytesReturned, NULL, NULL) == SOCKET_ERROR) { TRACE ("%s", "Could not set keepalive values"); } else { TRACE ("%s", "KeepAlive values updated"); TRACE ("KeepAliveTime: %lu", keepalive.keepalivetime); TRACE ("KeepAliveInterval: %lu", keepalive.keepaliveinterval); } } #else static const char * _mongoc_socket_sockopt_value_to_name (int value) { switch (value) { #ifdef TCP_KEEPIDLE case TCP_KEEPIDLE: return "TCP_KEEPIDLE"; #endif #ifdef TCP_KEEPALIVE case TCP_KEEPALIVE: return "TCP_KEEPALIVE"; #endif #ifdef TCP_KEEPINTVL case TCP_KEEPINTVL: return "TCP_KEEPINTVL"; #endif #ifdef TCP_KEEPCNT case TCP_KEEPCNT: return "TCP_KEEPCNT"; #endif default: MONGOC_WARNING ("Don't know what socketopt %d is", value); return "Unknown option name"; } } static void _mongoc_socket_set_sockopt_if_less (int sd, int name, int value) { int optval = 1; mongoc_socklen_t optlen; optlen = sizeof optval; if (getsockopt (sd, IPPROTO_TCP, name, (char *) &optval, &optlen)) { TRACE ("Getting '%s' failed, errno: %d", _mongoc_socket_sockopt_value_to_name (name), errno); } else { TRACE ("'%s' is %d, target value is %d", _mongoc_socket_sockopt_value_to_name (name), optval, value); if (optval > value) { optval = value; if (setsockopt (sd, IPPROTO_TCP, name, (char *) &optval, sizeof optval)) { TRACE ("Setting '%s' failed, errno: %d", _mongoc_socket_sockopt_value_to_name (name), errno); } else { TRACE ("'%s' value changed to %d", _mongoc_socket_sockopt_value_to_name (name), optval); } } } } static void _mongoc_socket_setkeepalive_nix (int sd) { #if defined(TCP_KEEPIDLE) _mongoc_socket_set_sockopt_if_less (sd, TCP_KEEPIDLE, MONGODB_KEEPIDLE); #elif defined(TCP_KEEPALIVE) _mongoc_socket_set_sockopt_if_less (sd, TCP_KEEPALIVE, MONGODB_KEEPIDLE); #else TRACE ("%s", "Neither TCP_KEEPIDLE nor TCP_KEEPALIVE available"); #endif #ifdef TCP_KEEPINTVL _mongoc_socket_set_sockopt_if_less (sd, TCP_KEEPINTVL, MONGODB_KEEPALIVEINTVL); #else TRACE ("%s", "TCP_KEEPINTVL not available"); #endif #ifdef TCP_KEEPCNT _mongoc_socket_set_sockopt_if_less (sd, TCP_KEEPCNT, MONGODB_KEEPALIVECNT); #else TRACE ("%s", "TCP_KEEPCNT not available"); #endif } #endif static void #ifdef _WIN32 _mongoc_socket_setkeepalive (SOCKET sd) /* IN */ #else _mongoc_socket_setkeepalive (int sd) /* IN */ #endif { #ifdef SO_KEEPALIVE int optval = 1; ENTRY; #ifdef SO_KEEPALIVE if (!setsockopt (sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &optval, sizeof optval)) { TRACE ("%s", "Setting SO_KEEPALIVE"); #ifdef _WIN32 _mongoc_socket_setkeepalive_windows (sd); #else _mongoc_socket_setkeepalive_nix (sd); #endif } else { TRACE ("%s", "Failed setting SO_KEEPALIVE"); } #else TRACE ("%s", "SO_KEEPALIVE not available"); #endif EXIT; #endif } static bool #ifdef _WIN32 _mongoc_socket_setnodelay (SOCKET sd) /* IN */ #else _mongoc_socket_setnodelay (int sd) /* IN */ #endif { #ifdef _WIN32 BOOL optval = 1; #else int optval = 1; #endif int ret; ENTRY; errno = 0; ret = setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char *) &optval, sizeof optval); #ifdef _WIN32 if (ret == SOCKET_ERROR) { MONGOC_WARNING ("WSAGetLastError(): %d", (int) WSAGetLastError ()); } #endif RETURN (ret == 0); } /* *-------------------------------------------------------------------------- * * mongoc_socket_errno -- * * Returns the last error on the socket. * * Returns: * An integer errno, or 0 on no error. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_errno (mongoc_socket_t *sock) /* IN */ { BSON_ASSERT (sock); TRACE ("Current errno: %d", sock->errno_); return sock->errno_; } /* *-------------------------------------------------------------------------- * * _mongoc_socket_errno_is_again -- * * Check to see if we should attempt to make further progress * based on the error of the last operation. * * Returns: * true if we should try again. otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_socket_errno_is_again (mongoc_socket_t *sock) /* IN */ { TRACE ("errno is: %d", sock->errno_); return MONGOC_ERRNO_IS_AGAIN (sock->errno_); } /* *-------------------------------------------------------------------------- * * mongoc_socket_accept -- * * Wrapper for BSD socket accept(). Handles portability between * BSD sockets and WinSock2 on Windows Vista and newer. * * Returns: * NULL upon failure to accept or timeout. * A newly allocated mongoc_socket_t on success. * * Side effects: * *port contains the client port number. * *-------------------------------------------------------------------------- */ mongoc_socket_t * mongoc_socket_accept (mongoc_socket_t *sock, /* IN */ int64_t expire_at) /* IN */ { return mongoc_socket_accept_ex (sock, expire_at, NULL); } /* *-------------------------------------------------------------------------- * * mongoc_socket_accept_ex -- * * Private synonym for mongoc_socket_accept, returning client port. * * Returns: * NULL upon failure to accept or timeout. * A newly allocated mongoc_socket_t on success. * * Side effects: * *port contains the client port number. * *-------------------------------------------------------------------------- */ mongoc_socket_t * mongoc_socket_accept_ex (mongoc_socket_t *sock, /* IN */ int64_t expire_at, /* IN */ uint16_t *port) /* OUT */ { mongoc_socket_t *client; struct sockaddr_storage addr = {0}; mongoc_socklen_t addrlen = sizeof addr; bool try_again = false; bool failed = false; #ifdef _WIN32 SOCKET sd; #else int sd; #endif ENTRY; BSON_ASSERT (sock); again: errno = 0; sd = accept (sock->sd, (mongoc_sockaddr_t *) &addr, &addrlen); _mongoc_socket_capture_errno (sock); #ifdef _WIN32 failed = (sd == INVALID_SOCKET); #else failed = (sd == -1); #endif try_again = (failed && _mongoc_socket_errno_is_again (sock)); if (failed && try_again) { if (_mongoc_socket_wait (sock, POLLIN, expire_at)) { GOTO (again); } RETURN (NULL); } else if (failed) { RETURN (NULL); } else if (!_mongoc_socket_setflags (sd)) { #ifdef _WIN32 closesocket (sd); #else close (sd); #endif RETURN (NULL); } client = (mongoc_socket_t *) bson_malloc0 (sizeof *client); client->sd = sd; if (port) { if (addr.ss_family == AF_INET) { struct sockaddr_in *tmp = (struct sockaddr_in *) &addr; *port = ntohs (tmp->sin_port); } else { struct sockaddr_in6 *tmp = (struct sockaddr_in6 *) &addr; *port = ntohs (tmp->sin6_port); } } if (!_mongoc_socket_setnodelay (client->sd)) { MONGOC_WARNING ("Failed to enable TCP_NODELAY."); } RETURN (client); } /* *-------------------------------------------------------------------------- * * mongo_socket_bind -- * * A wrapper around bind(). * * Returns: * 0 on success, -1 on failure and errno is set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_bind (mongoc_socket_t *sock, /* IN */ const struct sockaddr *addr, /* IN */ mongoc_socklen_t addrlen) /* IN */ { int ret; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (addr); BSON_ASSERT (addrlen); ret = bind (sock->sd, addr, addrlen); _mongoc_socket_capture_errno (sock); RETURN (ret); } int mongoc_socket_close (mongoc_socket_t *sock) /* IN */ { bool owned; ENTRY; BSON_ASSERT (sock); #ifdef _WIN32 owned = (sock->pid == (int) _getpid ()); if (sock->sd != INVALID_SOCKET) { if (owned) { shutdown (sock->sd, SD_BOTH); } if (0 == closesocket (sock->sd)) { sock->sd = INVALID_SOCKET; } else { _mongoc_socket_capture_errno (sock); RETURN (-1); } } RETURN (0); #else owned = (sock->pid == (int) getpid ()); if (sock->sd != -1) { if (owned) { shutdown (sock->sd, SHUT_RDWR); } if (0 == close (sock->sd)) { sock->sd = -1; } else { _mongoc_socket_capture_errno (sock); RETURN (-1); } } RETURN (0); #endif } /* *-------------------------------------------------------------------------- * * mongoc_socket_connect -- * * Performs a socket connection but will fail if @expire_at is * reached by the monotonic clock. * * Returns: * 0 if success, otherwise -1 and errno is set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_connect (mongoc_socket_t *sock, /* IN */ const struct sockaddr *addr, /* IN */ mongoc_socklen_t addrlen, /* IN */ int64_t expire_at) /* IN */ { bool try_again = false; bool failed = false; int ret; int optval; /* getsockopt parameter types vary, we check in CheckCompiler.m4 */ mongoc_socklen_t optlen = (mongoc_socklen_t) sizeof optval; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (addr); BSON_ASSERT (addrlen); ret = connect (sock->sd, addr, addrlen); #ifdef _WIN32 if (ret == SOCKET_ERROR) { #else if (ret == -1) { #endif _mongoc_socket_capture_errno (sock); failed = true; try_again = _mongoc_socket_errno_is_again (sock); } if (failed && try_again) { if (_mongoc_socket_wait (sock, POLLOUT, expire_at)) { optval = -1; ret = getsockopt (sock->sd, SOL_SOCKET, SO_ERROR, (char *) &optval, &optlen); if ((ret == 0) && (optval == 0)) { RETURN (0); } else { errno = sock->errno_ = optval; } } RETURN (-1); } else if (failed) { RETURN (-1); } else { RETURN (0); } } /* *-------------------------------------------------------------------------- * * mongoc_socket_destroy -- * * Cleanup after a mongoc_socket_t structure, possibly closing * underlying sockets. * * Returns: * None. * * Side effects: * @sock is freed and should be considered invalid. * *-------------------------------------------------------------------------- */ void mongoc_socket_destroy (mongoc_socket_t *sock) /* IN */ { if (sock) { mongoc_socket_close (sock); bson_free (sock); } } /* *-------------------------------------------------------------------------- * * mongoc_socket_listen -- * * Listen for incoming requests with a backlog up to @backlog. * * If @backlog is zero, a sensible default will be chosen. * * Returns: * true if successful; otherwise false. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_listen (mongoc_socket_t *sock, /* IN */ unsigned int backlog) /* IN */ { int ret; ENTRY; BSON_ASSERT (sock); if (backlog == 0) { backlog = 10; } ret = listen (sock->sd, backlog); _mongoc_socket_capture_errno (sock); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_socket_new -- * * Create a new socket and store the current process id on it. * * Free the result with mongoc_socket_destroy(). * * Returns: * A newly allocated socket. * NULL on failure. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_socket_t * mongoc_socket_new (int domain, /* IN */ int type, /* IN */ int protocol) /* IN */ { mongoc_socket_t *sock; #ifdef _WIN32 SOCKET sd; #else int sd; #endif #ifdef SO_NOSIGPIPE int on = 1; #endif ENTRY; sd = socket (domain, type, protocol); #ifdef _WIN32 if (sd == INVALID_SOCKET) { #else if (sd == -1) { #endif RETURN (NULL); } if (!_mongoc_socket_setflags (sd)) { GOTO (fail); } if (domain != AF_UNIX) { if (!_mongoc_socket_setnodelay (sd)) { MONGOC_WARNING ("Failed to enable TCP_NODELAY."); } _mongoc_socket_setkeepalive (sd); } /* Set SO_NOSIGPIPE, to ignore SIGPIPE on writes for platforms where setting MSG_NOSIGNAL on writes is not supported (primarily OSX). */ #ifdef SO_NOSIGPIPE setsockopt (sd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on)); #endif sock = (mongoc_socket_t *) bson_malloc0 (sizeof *sock); sock->sd = sd; sock->domain = domain; #ifdef _WIN32 sock->pid = (int) _getpid (); #else sock->pid = (int) getpid (); #endif RETURN (sock); fail: #ifdef _WIN32 closesocket (sd); #else close (sd); #endif RETURN (NULL); } /* *-------------------------------------------------------------------------- * * mongoc_socket_recv -- * * A portable wrapper around recv() that also respects an absolute * timeout. * * @expire_at is 0 for no blocking, -1 for infinite blocking, * or a time using the monotonic clock to expire. Calculate this * using bson_get_monotonic_time() + N_MICROSECONDS. * * Returns: * The number of bytes received on success. * 0 on end of stream. * -1 on failure. * * Side effects: * @buf will be read into. * *-------------------------------------------------------------------------- */ ssize_t mongoc_socket_recv (mongoc_socket_t *sock, /* IN */ void *buf, /* OUT */ size_t buflen, /* IN */ int flags, /* IN */ int64_t expire_at) /* IN */ { ssize_t ret = 0; bool failed = false; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (buf); BSON_ASSERT (buflen); again: sock->errno_ = 0; #ifdef _WIN32 ret = recv (sock->sd, (char *) buf, (int) buflen, flags); failed = (ret == SOCKET_ERROR); #else ret = recv (sock->sd, buf, buflen, flags); failed = (ret == -1); #endif if (failed) { _mongoc_socket_capture_errno (sock); if (_mongoc_socket_errno_is_again (sock) && _mongoc_socket_wait (sock, POLLIN, expire_at)) { GOTO (again); } } if (failed) { RETURN (-1); } mongoc_counter_streams_ingress_add (ret); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_socket_setsockopt -- * * A wrapper around setsockopt(). * * Returns: * 0 on success, -1 on failure. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_socket_setsockopt (mongoc_socket_t *sock, /* IN */ int level, /* IN */ int optname, /* IN */ const void *optval, /* IN */ mongoc_socklen_t optlen) /* IN */ { int ret; ENTRY; BSON_ASSERT (sock); ret = setsockopt (sock->sd, level, optname, optval, optlen); _mongoc_socket_capture_errno (sock); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_socket_send -- * * A simplified wrapper around mongoc_socket_sendv(). * * @expire_at is 0 for no blocking, -1 for infinite blocking, * or a time using the monotonic clock to expire. Calculate this * using bson_get_monotonic_time() + N_MICROSECONDS. * * Returns: * -1 on failure. number of bytes written on success. * * Side effects: * None. * *-------------------------------------------------------------------------- */ ssize_t mongoc_socket_send (mongoc_socket_t *sock, /* IN */ const void *buf, /* IN */ size_t buflen, /* IN */ int64_t expire_at) /* IN */ { mongoc_iovec_t iov; BSON_ASSERT (sock); BSON_ASSERT (buf); BSON_ASSERT (buflen); iov.iov_base = (void *) buf; iov.iov_len = buflen; return mongoc_socket_sendv (sock, &iov, 1, expire_at); } /* *-------------------------------------------------------------------------- * * _mongoc_socket_try_sendv_slow -- * * A slow variant of _mongoc_socket_try_sendv() that sends each * iovec entry one by one. This can happen if we hit EMSGSIZE * with sendmsg() on various POSIX systems or WSASend()+WSAEMSGSIZE * on Windows. * * Returns: * the number of bytes sent or -1 and errno is set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static ssize_t _mongoc_socket_try_sendv_slow (mongoc_socket_t *sock, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt) /* IN */ { ssize_t ret = 0; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); for (size_t i = 0u; i < iovcnt; i++) { #ifdef _WIN32 BSON_ASSERT (mcommon_in_range_unsigned (int, iov[i].iov_len)); const int wrote = send (sock->sd, iov[i].iov_base, (int) iov[i].iov_len, 0); if (wrote == SOCKET_ERROR) { #else const ssize_t wrote = send (sock->sd, iov[i].iov_base, iov[i].iov_len, 0); if (wrote == -1) { #endif _mongoc_socket_capture_errno (sock); if (!_mongoc_socket_errno_is_again (sock)) { RETURN (-1); } RETURN (ret ? ret : -1); } ret += wrote; if (mcommon_cmp_not_equal_su (wrote, iov[i].iov_len)) { RETURN (ret); } } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_socket_try_sendv -- * * Helper used by mongoc_socket_sendv() to try to write as many * bytes to the underlying socket until the socket buffer is full. * * This is performed in a non-blocking fashion. * * Returns: * -1 on failure. the number of bytes written on success. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static ssize_t _mongoc_socket_try_sendv (mongoc_socket_t *sock, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt) /* IN */ { #ifdef _WIN32 DWORD dwNumberofBytesSent = 0; int ret; #else struct msghdr msg; ssize_t ret; #endif ENTRY; BSON_ASSERT (sock); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); DUMP_IOVEC (sendbuf, iov, iovcnt); #ifdef _WIN32 BSON_ASSERT (mcommon_in_range_unsigned (unsigned_long, iovcnt)); ret = WSASend (sock->sd, (LPWSABUF) iov, (DWORD) iovcnt, &dwNumberofBytesSent, 0, NULL, NULL); TRACE ("WSASend sent: %lu (out of: %zu), ret: %d", dwNumberofBytesSent, iov->iov_len, ret); #else memset (&msg, 0, sizeof msg); msg.msg_iov = iov; msg.msg_iovlen = iovcnt; ret = sendmsg (sock->sd, &msg, #ifdef MSG_NOSIGNAL MSG_NOSIGNAL); #else 0); #endif TRACE ("Send %zd out of %zu bytes", ret, iov->iov_len); #endif #ifdef _WIN32 if (ret == SOCKET_ERROR) { #else if (ret == -1) { #endif _mongoc_socket_capture_errno (sock); /* * Check to see if we have sent an iovec too large for sendmsg to * complete. If so, we need to fallback to the slow path of multiple * send() commands. */ #ifdef _WIN32 if (mongoc_socket_errno (sock) == WSAEMSGSIZE) { #else if (mongoc_socket_errno (sock) == EMSGSIZE) { #endif RETURN (_mongoc_socket_try_sendv_slow (sock, iov, iovcnt)); } RETURN (-1); } #ifdef _WIN32 RETURN (dwNumberofBytesSent); #else RETURN (ret); #endif } /* *-------------------------------------------------------------------------- * * mongoc_socket_sendv -- * * A wrapper around using sendmsg() to send an iovec. * This also deals with the structure differences between * WSABUF and struct iovec. * * @expire_at is 0 for no blocking, -1 for infinite blocking, * or a time using the monotonic clock to expire. Calculate this * using bson_get_monotonic_time() + N_MICROSECONDS. * * Returns: * -1 on failure. * the number of bytes written on success. * * Side effects: * None. * *-------------------------------------------------------------------------- */ ssize_t mongoc_socket_sendv (mongoc_socket_t *sock, /* IN */ mongoc_iovec_t *in_iov, /* IN */ size_t iovcnt, /* IN */ int64_t expire_at) /* IN */ { ssize_t ret = 0; ssize_t sent; size_t cur = 0; mongoc_iovec_t *iov; ENTRY; BSON_ASSERT (sock); BSON_ASSERT (in_iov); BSON_ASSERT (iovcnt); iov = bson_malloc (sizeof (*iov) * iovcnt); memcpy (iov, in_iov, sizeof (*iov) * iovcnt); for (;;) { sent = _mongoc_socket_try_sendv (sock, &iov[cur], iovcnt - cur); TRACE ("Sent %zd (of %zu) out of iovcnt=%zu", sent, iov[cur].iov_len, iovcnt); /* * If we failed with anything other than EAGAIN or EWOULDBLOCK, * we should fail immediately as there is another issue with the * underlying socket. */ if (sent == -1) { if (!_mongoc_socket_errno_is_again (sock)) { ret = -1; GOTO (CLEANUP); } } /* * Update internal stream counters. */ if (sent > 0) { ret += sent; mongoc_counter_streams_egress_add (sent); /* * Subtract the sent amount from what we still need to send. */ while ((cur < iovcnt) && (sent >= (ssize_t) iov[cur].iov_len)) { TRACE ("still got bytes left: sent -= iov_len: %zd -= %zu", sent, iov[cur].iov_len); sent -= iov[cur++].iov_len; } /* * Check if that made us finish all of the iovecs. If so, we are done * sending data over the socket. */ if (cur == iovcnt) { TRACE ("%s", "Finished the iovecs"); break; } /* * Increment the current iovec buffer to its proper offset and adjust * the number of bytes to write. */ TRACE ("Seeked io_base+%zd", sent); TRACE ("Subtracting iov_len -= sent; %zu -= %zd", iov[cur].iov_len, sent); iov[cur].iov_base = ((char *) iov[cur].iov_base) + sent; iov[cur].iov_len -= sent; TRACE ("iov_len remaining %zu", iov[cur].iov_len); BSON_ASSERT (iovcnt - cur); BSON_ASSERT (iov[cur].iov_len); } else if (OPERATION_EXPIRED (expire_at)) { if (expire_at > 0) { mongoc_counter_streams_timeout_inc (); } GOTO (CLEANUP); } /* * Block on poll() until our desired condition is met. */ if (!_mongoc_socket_wait (sock, POLLOUT, expire_at)) { GOTO (CLEANUP); } } CLEANUP: bson_free (iov); RETURN (ret); } int mongoc_socket_getsockname (mongoc_socket_t *sock, /* IN */ struct sockaddr *addr, /* OUT */ mongoc_socklen_t *addrlen) /* INOUT */ { int ret; ENTRY; BSON_ASSERT (sock); ret = getsockname (sock->sd, addr, addrlen); _mongoc_socket_capture_errno (sock); RETURN (ret); } char * mongoc_socket_getnameinfo (mongoc_socket_t *sock) /* IN */ { /* getpeername parameter types vary, we check in CheckCompiler.m4 */ struct sockaddr_storage addr; mongoc_socklen_t len = (mongoc_socklen_t) sizeof addr; char *ret; char host[BSON_HOST_NAME_MAX + 1]; ENTRY; BSON_ASSERT (sock); if (getpeername (sock->sd, (struct sockaddr *) &addr, &len)) { RETURN (NULL); } if (getnameinfo ((struct sockaddr *) &addr, len, host, sizeof host, NULL, 0, 0)) { RETURN (NULL); } ret = bson_strdup (host); RETURN (ret); } bool mongoc_socket_check_closed (mongoc_socket_t *sock) /* IN */ { bool closed = false; char buf[1]; ssize_t r; if (_mongoc_socket_wait (sock, POLLIN, 0)) { sock->errno_ = 0; r = recv (sock->sd, buf, 1, MSG_PEEK); if (r < 0) { _mongoc_socket_capture_errno (sock); } if (r < 1) { closed = true; } } return closed; } /* * *-------------------------------------------------------------------------- * * mongoc_socket_inet_ntop -- * * Convert the ip from addrinfo into a c string. * * Returns: * The value is returned into 'buffer'. The memory has to be allocated * by the caller * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_socket_inet_ntop (struct addrinfo *rp, /* IN */ char *buf, /* INOUT */ size_t buflen) /* IN */ { void *ptr; char tmp[256]; int req; switch (rp->ai_family) { case AF_INET: ptr = &((struct sockaddr_in *) rp->ai_addr)->sin_addr; inet_ntop (rp->ai_family, ptr, tmp, sizeof (tmp)); // Truncation is OK. req = bson_snprintf (buf, buflen, "ipv4 %s", tmp); BSON_ASSERT (req > 0); break; case AF_INET6: ptr = &((struct sockaddr_in6 *) rp->ai_addr)->sin6_addr; inet_ntop (rp->ai_family, ptr, tmp, sizeof (tmp)); // Truncation is OK. req = bson_snprintf (buf, buflen, "ipv6 %s", tmp); BSON_ASSERT (req > 0); break; default: // Truncation is OK. req = bson_snprintf (buf, buflen, "unknown ip %d", rp->ai_family); BSON_ASSERT (req > 0); break; } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-socket.h0000644000175100001660000000624214760300420022433 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SOCKET_H #define MONGOC_SOCKET_H #include #include #include #ifdef _WIN32 #include #include #else #include #include #include #include #include #include #include #include #include #endif #if defined(_AIX) && !defined(MONGOC_HAVE_SS_FAMILY) #define ss_family __ss_family #endif #include BSON_BEGIN_DECLS typedef MONGOC_SOCKET_ARG3 mongoc_socklen_t; typedef struct _mongoc_socket_t mongoc_socket_t; typedef struct { mongoc_socket_t *socket; int events; int revents; } mongoc_socket_poll_t; MONGOC_EXPORT (mongoc_socket_t *) mongoc_socket_accept (mongoc_socket_t *sock, int64_t expire_at) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (int) mongoc_socket_bind (mongoc_socket_t *sock, const struct sockaddr *addr, mongoc_socklen_t addrlen); MONGOC_EXPORT (int) mongoc_socket_close (mongoc_socket_t *socket); MONGOC_EXPORT (int) mongoc_socket_connect (mongoc_socket_t *sock, const struct sockaddr *addr, mongoc_socklen_t addrlen, int64_t expire_at); MONGOC_EXPORT (char *) mongoc_socket_getnameinfo (mongoc_socket_t *sock) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_socket_destroy (mongoc_socket_t *sock); MONGOC_EXPORT (int) mongoc_socket_errno (mongoc_socket_t *sock); MONGOC_EXPORT (int) mongoc_socket_getsockname (mongoc_socket_t *sock, struct sockaddr *addr, mongoc_socklen_t *addrlen); MONGOC_EXPORT (int) mongoc_socket_listen (mongoc_socket_t *sock, unsigned int backlog); MONGOC_EXPORT (mongoc_socket_t *) mongoc_socket_new (int domain, int type, int protocol) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (ssize_t) mongoc_socket_recv (mongoc_socket_t *sock, void *buf, size_t buflen, int flags, int64_t expire_at); MONGOC_EXPORT (int) mongoc_socket_setsockopt (mongoc_socket_t *sock, int level, int optname, const void *optval, mongoc_socklen_t optlen); MONGOC_EXPORT (ssize_t) mongoc_socket_send (mongoc_socket_t *sock, const void *buf, size_t buflen, int64_t expire_at); MONGOC_EXPORT (ssize_t) mongoc_socket_sendv (mongoc_socket_t *sock, mongoc_iovec_t *iov, size_t iovcnt, int64_t expire_at); MONGOC_EXPORT (bool) mongoc_socket_check_closed (mongoc_socket_t *sock); MONGOC_EXPORT (void) mongoc_socket_inet_ntop (struct addrinfo *rp, char *buf, size_t buflen); MONGOC_EXPORT (ssize_t) mongoc_socket_poll (mongoc_socket_poll_t *sds, size_t nsds, int32_t timeout); BSON_END_DECLS #endif /* MONGOC_SOCKET_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-ssl-private.h0000644000175100001660000000375114760300420023416 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SSL_PRIVATE_H #define MONGOC_SSL_PRIVATE_H #include #include #include BSON_BEGIN_DECLS typedef struct { bool tls_disable_certificate_revocation_check; bool tls_disable_ocsp_endpoint_check; } _mongoc_internal_tls_opts_t; char * mongoc_ssl_extract_subject (const char *filename, const char *passphrase); void _mongoc_ssl_opts_from_uri (mongoc_ssl_opt_t *ssl_opt, _mongoc_internal_tls_opts_t *internal, mongoc_uri_t *uri); void _mongoc_ssl_opts_copy_to (const mongoc_ssl_opt_t *src, mongoc_ssl_opt_t *dst, bool copy_internal); bool _mongoc_ssl_opts_disable_certificate_revocation_check (const mongoc_ssl_opt_t *ssl_opt); bool _mongoc_ssl_opts_disable_ocsp_endpoint_check (const mongoc_ssl_opt_t *ssl_opt); void _mongoc_ssl_opts_cleanup (mongoc_ssl_opt_t *opt, bool free_internal); /* _mongoc_ssl_opts_from_bson is an internal helper for constructing an ssl_opt * from a BSON document. It is used to parse TLS options for the KMIP KMS * provider in CSFLE. * - ssl_opt must be a zero'd out ssl_opt struct. * - errmsg must be an initialized mcommon_string_append_t. * - Returns false on error and appends to errmsg. */ bool _mongoc_ssl_opts_from_bson (mongoc_ssl_opt_t *ssl_opt, const bson_t *bson, mcommon_string_append_t *errmsg); BSON_END_DECLS #endif /* MONGOC_SSL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-ssl.c0000644000175100001660000002035214760300420021735 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL #include #include #include #include #include #include #include #if defined(MONGOC_ENABLE_SSL_OPENSSL) #include #elif defined(MONGOC_ENABLE_SSL_LIBRESSL) #include #elif defined(MONGOC_ENABLE_SSL_SECURE_TRANSPORT) #include #elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL) #include #endif /* TODO: we could populate these from a config or something further down the * road for providing defaults */ #ifndef MONGOC_SSL_DEFAULT_TRUST_FILE #define MONGOC_SSL_DEFAULT_TRUST_FILE NULL #endif #ifndef MONGOC_SSL_DEFAULT_TRUST_DIR #define MONGOC_SSL_DEFAULT_TRUST_DIR NULL #endif static mongoc_ssl_opt_t gMongocSslOptDefault = { NULL, NULL, MONGOC_SSL_DEFAULT_TRUST_FILE, MONGOC_SSL_DEFAULT_TRUST_DIR, }; const mongoc_ssl_opt_t * mongoc_ssl_opt_get_default (void) { return &gMongocSslOptDefault; } char * mongoc_ssl_extract_subject (const char *filename, const char *passphrase) { char *retval; if (!filename) { MONGOC_ERROR ("No filename provided to extract subject from"); return NULL; } #ifdef _WIN32 if (_access (filename, 0) != 0) { #else if (access (filename, R_OK) != 0) { #endif MONGOC_ERROR ("Can't extract subject from unreadable file: '%s'", filename); return NULL; } #if defined(MONGOC_ENABLE_SSL_OPENSSL) retval = _mongoc_openssl_extract_subject (filename, passphrase); #elif defined(MONGOC_ENABLE_SSL_LIBRESSL) MONGOC_WARNING ("libtls doesn't support automatically extracting subject from " "certificate to use with authentication"); retval = NULL; #elif defined(MONGOC_ENABLE_SSL_SECURE_TRANSPORT) retval = _mongoc_secure_transport_extract_subject (filename, passphrase); #elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL) retval = _mongoc_secure_channel_extract_subject (filename, passphrase); #endif if (!retval) { MONGOC_ERROR ("Can't extract subject from file '%s'", filename); } return retval; } void _mongoc_ssl_opts_from_uri (mongoc_ssl_opt_t *ssl_opt, _mongoc_internal_tls_opts_t *internal, mongoc_uri_t *uri) { bool insecure = mongoc_uri_get_option_as_bool (uri, MONGOC_URI_TLSINSECURE, false); ssl_opt->pem_file = mongoc_uri_get_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, NULL); ssl_opt->pem_pwd = mongoc_uri_get_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD, NULL); ssl_opt->ca_file = mongoc_uri_get_option_as_utf8 (uri, MONGOC_URI_TLSCAFILE, NULL); ssl_opt->weak_cert_validation = mongoc_uri_get_option_as_bool (uri, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES, insecure); ssl_opt->allow_invalid_hostname = mongoc_uri_get_option_as_bool (uri, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES, insecure); ssl_opt->internal = internal; internal->tls_disable_certificate_revocation_check = mongoc_uri_get_option_as_bool (uri, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK, false); internal->tls_disable_ocsp_endpoint_check = mongoc_uri_get_option_as_bool (uri, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK, false); } void _mongoc_ssl_opts_copy_to (const mongoc_ssl_opt_t *src, mongoc_ssl_opt_t *dst, bool copy_internal) { BSON_ASSERT (src); BSON_ASSERT (dst); dst->pem_file = bson_strdup (src->pem_file); dst->pem_pwd = bson_strdup (src->pem_pwd); dst->ca_file = bson_strdup (src->ca_file); dst->ca_dir = bson_strdup (src->ca_dir); dst->crl_file = bson_strdup (src->crl_file); dst->weak_cert_validation = src->weak_cert_validation; dst->allow_invalid_hostname = src->allow_invalid_hostname; if (copy_internal) { dst->internal = NULL; if (src->internal) { dst->internal = bson_malloc (sizeof (_mongoc_internal_tls_opts_t)); memcpy (dst->internal, src->internal, sizeof (_mongoc_internal_tls_opts_t)); } } } void _mongoc_ssl_opts_cleanup (mongoc_ssl_opt_t *opt, bool free_internal) { bson_free ((char *) opt->pem_file); bson_free ((char *) opt->pem_pwd); bson_free ((char *) opt->ca_file); bson_free ((char *) opt->ca_dir); bson_free ((char *) opt->crl_file); if (free_internal) { bson_free (opt->internal); } } bool _mongoc_ssl_opts_disable_certificate_revocation_check (const mongoc_ssl_opt_t *ssl_opt) { if (!ssl_opt->internal) { return false; } return ((_mongoc_internal_tls_opts_t *) ssl_opt->internal)->tls_disable_certificate_revocation_check; } bool _mongoc_ssl_opts_disable_ocsp_endpoint_check (const mongoc_ssl_opt_t *ssl_opt) { if (!ssl_opt->internal) { return false; } return ((_mongoc_internal_tls_opts_t *) ssl_opt->internal)->tls_disable_ocsp_endpoint_check; } bool _mongoc_ssl_opts_from_bson (mongoc_ssl_opt_t *ssl_opt, const bson_t *bson, mcommon_string_append_t *errmsg) { bson_iter_t iter; if (ssl_opt->internal) { mcommon_string_append (errmsg, "SSL options must not have internal state set"); return false; } ssl_opt->internal = bson_malloc0 (sizeof (_mongoc_internal_tls_opts_t)); if (!bson_iter_init (&iter, bson)) { mcommon_string_append (errmsg, "error initializing iterator to BSON SSL options"); return false; } while (bson_iter_next (&iter)) { const char *key = bson_iter_key (&iter); if (BSON_ITER_HOLDS_UTF8 (&iter)) { if (0 == bson_strcasecmp (key, MONGOC_URI_TLSCERTIFICATEKEYFILE)) { ssl_opt->pem_file = bson_strdup (bson_iter_utf8 (&iter, NULL)); continue; } else if (0 == bson_strcasecmp (key, MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD)) { ssl_opt->pem_pwd = bson_strdup (bson_iter_utf8 (&iter, NULL)); continue; } else if (0 == bson_strcasecmp (key, MONGOC_URI_TLSCAFILE)) { ssl_opt->ca_file = bson_strdup (bson_iter_utf8 (&iter, NULL)); continue; } } if (BSON_ITER_HOLDS_BOOL (&iter)) { if (0 == bson_strcasecmp (key, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES)) { /* If MONGOC_URI_TLSINSECURE was parsed, weak_cert_validation must * remain true. */ ssl_opt->weak_cert_validation = ssl_opt->weak_cert_validation || bson_iter_bool (&iter); continue; } else if (0 == bson_strcasecmp (key, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES)) { /* If MONGOC_URI_TLSINSECURE was parsed, allow_invalid_hostname must * remain true. */ ssl_opt->allow_invalid_hostname = ssl_opt->allow_invalid_hostname || bson_iter_bool (&iter); continue; } else if (0 == bson_strcasecmp (key, MONGOC_URI_TLSINSECURE)) { if (bson_iter_bool (&iter)) { ssl_opt->weak_cert_validation = true; ssl_opt->allow_invalid_hostname = true; } continue; } else if (0 == bson_strcasecmp (key, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK)) { ((_mongoc_internal_tls_opts_t *) ssl_opt->internal)->tls_disable_certificate_revocation_check = bson_iter_bool (&iter); continue; } else if (0 == bson_strcasecmp (key, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK)) { ((_mongoc_internal_tls_opts_t *) ssl_opt->internal)->tls_disable_ocsp_endpoint_check = bson_iter_bool (&iter); continue; } } mcommon_string_append_printf ( errmsg, "unexpected %s option: %s", _mongoc_bson_type_to_str (bson_iter_type (&iter)), key); return false; } return true; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-ssl.h0000644000175100001660000000226514760300420021745 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SSL_H #define MONGOC_SSL_H #include #include BSON_BEGIN_DECLS typedef struct _mongoc_ssl_opt_t mongoc_ssl_opt_t; struct _mongoc_ssl_opt_t { const char *pem_file; const char *pem_pwd; const char *ca_file; const char *ca_dir; const char *crl_file; bool weak_cert_validation; bool allow_invalid_hostname; void *internal; void *padding[6]; }; MONGOC_EXPORT (const mongoc_ssl_opt_t *) mongoc_ssl_opt_get_default (void) BSON_GNUC_PURE; BSON_END_DECLS #endif /* MONGOC_SSL_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-sspi-private.h0000644000175100001660000000435714760300420023576 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_SSPI_PRIVATE_H #define MONGOC_SSPI_PRIVATE_H #include #include BSON_BEGIN_DECLS #define SECURITY_WIN32 1 /* Required for SSPI */ #include #include #include #include #define MONGOC_SSPI_AUTH_GSS_ERROR -1 #define MONGOC_SSPI_AUTH_GSS_COMPLETE 1 #define MONGOC_SSPI_AUTH_GSS_CONTINUE 0 typedef struct { mongoc_sasl_t sasl; CredHandle cred; CtxtHandle ctx; WCHAR *spn; SEC_CHAR *response; SEC_CHAR *username; ULONG flags; UCHAR haveCred; UCHAR haveCtx; ULONG qop; } mongoc_sspi_client_state_t; void _mongoc_sspi_set_gsserror (DWORD errCode, const SEC_CHAR *msg); void _mongoc_sspi_destroy_sspi_client_state (mongoc_sspi_client_state_t *state); int _mongoc_sspi_auth_sspi_client_init (WCHAR *service, ULONG flags, WCHAR *user, ULONG ulen, WCHAR *domain, ULONG dlen, WCHAR *password, ULONG plen, mongoc_sspi_client_state_t *state); int _mongoc_sspi_auth_sspi_client_step (mongoc_sspi_client_state_t *state, SEC_CHAR *challenge); int _mongoc_sspi_auth_sspi_client_unwrap (mongoc_sspi_client_state_t *state, SEC_CHAR *challenge); int _mongoc_sspi_auth_sspi_client_wrap ( mongoc_sspi_client_state_t *state, SEC_CHAR *data, SEC_CHAR *user, ULONG ulen, INT protect); BSON_END_DECLS #endif /* MONGOC_SSPI_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-sspi.c0000644000175100001660000003633414760300420022121 0ustar /* * Copyright 2009-present MongoDB, 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. * * This file originates from https://github.com/mongodb-labs/winkerberos */ #include #ifdef MONGOC_ENABLE_SASL_SSPI /* mingw doesn't define this */ #ifndef CRYPT_STRING_NOCRLF #define CRYPT_STRING_NOCRLF 0x40000000 #endif #include #include void _mongoc_sspi_destroy_sspi_client_state (mongoc_sspi_client_state_t *state) { if (state->haveCtx) { DeleteSecurityContext (&state->ctx); state->haveCtx = 0; } if (state->haveCred) { FreeCredentialsHandle (&state->cred); state->haveCred = 0; } if (state->spn != NULL) { bson_free (state->spn); state->spn = NULL; } if (state->response != NULL) { bson_free (state->response); state->response = NULL; } if (state->username != NULL) { bson_free (state->username); state->username = NULL; } } void _mongoc_sspi_set_gsserror (DWORD errCode, const SEC_CHAR *msg) { SEC_CHAR *err; DWORD status; DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; status = FormatMessageA (flags, NULL, errCode, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err, 0, NULL); if (status) { MONGOC_ERROR ("SSPI: %s: %s", msg, err); LocalFree (err); } else { MONGOC_ERROR ("SSPI: %s", msg); } } static SEC_CHAR * _mongoc_sspi_base64_encode (const SEC_CHAR *value, DWORD vlen) { SEC_CHAR *out = NULL; DWORD len; /* Get the correct size for the out buffer. */ if (CryptBinaryToStringA ((BYTE *) value, vlen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &len)) { out = (SEC_CHAR *) bson_malloc (sizeof (SEC_CHAR) * len); if (out) { /* Encode to the out buffer. */ if (CryptBinaryToStringA ((BYTE *) value, vlen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, out, &len)) { return out; } else { bson_free (out); } } } MONGOC_ERROR ("%s", "CryptBinaryToString failed."); return NULL; } static SEC_CHAR * _mongoc_sspi_base64_decode (const SEC_CHAR *value, DWORD *rlen) { SEC_CHAR *out = NULL; /* Get the correct size for the out buffer. */ if (CryptStringToBinaryA (value, 0, CRYPT_STRING_BASE64, NULL, rlen, NULL, NULL)) { out = (SEC_CHAR *) bson_malloc (sizeof (SEC_CHAR) * *rlen); if (out) { /* Decode to the out buffer. */ if (CryptStringToBinaryA (value, 0, CRYPT_STRING_BASE64, (BYTE *) out, rlen, NULL, NULL)) { return out; } else { bson_free (out); } } } MONGOC_ERROR ("%s", "CryptStringToBinary failed."); return NULL; } static CHAR * _mongoc_sspi_wide_to_utf8 (WCHAR *value) { CHAR *out; int len = WideCharToMultiByte (CP_UTF8, 0, value, -1, NULL, 0, NULL, NULL); if (len) { out = (CHAR *) bson_malloc (sizeof (CHAR) * len); if (WideCharToMultiByte (CP_UTF8, 0, value, -1, out, len, NULL, NULL)) { return out; } else { bson_free (out); } } _mongoc_sspi_set_gsserror (GetLastError (), "WideCharToMultiByte"); return NULL; } int _mongoc_sspi_auth_sspi_client_init (WCHAR *service, ULONG flags, WCHAR *user, ULONG ulen, WCHAR *domain, ULONG dlen, WCHAR *password, ULONG plen, mongoc_sspi_client_state_t *state) { SECURITY_STATUS status; SEC_WINNT_AUTH_IDENTITY_W authIdentity; TimeStamp ignored; state->response = NULL; state->username = NULL; state->qop = SECQOP_WRAP_NO_ENCRYPT; state->flags = flags; state->haveCred = 0; state->haveCtx = 0; state->spn = _wcsdup (service); if (state->spn == NULL) { return MONGOC_SSPI_AUTH_GSS_ERROR; } /* Convert RFC-2078 format to SPN */ if (!wcschr (state->spn, L'/')) { WCHAR *ptr = wcschr (state->spn, L'@'); if (ptr) { *ptr = L'/'; } } if (user) { authIdentity.User = user; authIdentity.UserLength = ulen; authIdentity.Domain = domain; authIdentity.DomainLength = dlen; authIdentity.Password = password; authIdentity.PasswordLength = plen; authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; } /* Note that the first parameter, pszPrincipal, appears to be * completely ignored in the Kerberos SSP. For more details see * https://github.com/mongodb-labs/winkerberos/issues/11. * */ status = AcquireCredentialsHandleW (/* Principal */ NULL, /* Security package name */ L"kerberos", /* Credentials Use */ SECPKG_CRED_OUTBOUND, /* LogonID (We don't use this) */ NULL, /* AuthData */ password ? &authIdentity : NULL, /* Always NULL */ NULL, /* Always NULL */ NULL, /* CredHandle */ &state->cred, /* Expiry (Required but unused by us) */ &ignored); if (status != SEC_E_OK) { _mongoc_sspi_set_gsserror (status, "AcquireCredentialsHandle"); return MONGOC_SSPI_AUTH_GSS_ERROR; } state->haveCred = 1; return MONGOC_SSPI_AUTH_GSS_COMPLETE; } int _mongoc_sspi_auth_sspi_client_step (mongoc_sspi_client_state_t *state, SEC_CHAR *challenge) { SecBufferDesc inbuf; SecBuffer inBufs[1]; SecBufferDesc outbuf; SecBuffer outBufs[1]; ULONG ignored; SECURITY_STATUS status = MONGOC_SSPI_AUTH_GSS_CONTINUE; DWORD len; if (state->response != NULL) { bson_free (state->response); state->response = NULL; } inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = inBufs; inBufs[0].pvBuffer = NULL; inBufs[0].cbBuffer = 0; inBufs[0].BufferType = SECBUFFER_TOKEN; if (state->haveCtx) { inBufs[0].pvBuffer = _mongoc_sspi_base64_decode (challenge, &len); if (!inBufs[0].pvBuffer) { return MONGOC_SSPI_AUTH_GSS_ERROR; } inBufs[0].cbBuffer = len; } outbuf.ulVersion = SECBUFFER_VERSION; outbuf.cBuffers = 1; outbuf.pBuffers = outBufs; outBufs[0].pvBuffer = NULL; outBufs[0].cbBuffer = 0; outBufs[0].BufferType = SECBUFFER_TOKEN; status = InitializeSecurityContextW (/* CredHandle */ &state->cred, /* CtxtHandle (NULL on first call) */ state->haveCtx ? &state->ctx : NULL, /* Service Principal Name */ state->spn, /* Flags */ ISC_REQ_ALLOCATE_MEMORY | state->flags, /* Always 0 */ 0, /* Target data representation */ SECURITY_NETWORK_DREP, /* Challenge (NULL on first call) */ state->haveCtx ? &inbuf : NULL, /* Always 0 */ 0, /* CtxtHandle (Set on first call) */ &state->ctx, /* Output */ &outbuf, /* Context attributes */ &ignored, /* Expiry (We don't use this) */ NULL); if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { _mongoc_sspi_set_gsserror (status, "InitializeSecurityContext"); status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } state->haveCtx = 1; if (outBufs[0].cbBuffer) { state->response = _mongoc_sspi_base64_encode (outBufs[0].pvBuffer, outBufs[0].cbBuffer); if (!state->response) { status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } } if (status == SEC_E_OK) { /* Get authenticated username. */ SecPkgContext_NamesW names; status = QueryContextAttributesW (&state->ctx, SECPKG_ATTR_NAMES, &names); if (status != SEC_E_OK) { _mongoc_sspi_set_gsserror (status, "QueryContextAttributesW"); status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } state->username = _mongoc_sspi_wide_to_utf8 (names.sUserName); if (state->username == NULL) { FreeContextBuffer (names.sUserName); status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } FreeContextBuffer (names.sUserName); status = MONGOC_SSPI_AUTH_GSS_COMPLETE; } else { status = MONGOC_SSPI_AUTH_GSS_CONTINUE; } done: if (inBufs[0].pvBuffer) { bson_free (inBufs[0].pvBuffer); } if (outBufs[0].pvBuffer) { FreeContextBuffer (outBufs[0].pvBuffer); } return status; } int _mongoc_sspi_auth_sspi_client_unwrap (mongoc_sspi_client_state_t *state, SEC_CHAR *challenge) { SECURITY_STATUS status; DWORD len; SecBuffer wrapBufs[2]; SecBufferDesc wrapBufDesc; wrapBufDesc.ulVersion = SECBUFFER_VERSION; wrapBufDesc.cBuffers = 2; wrapBufDesc.pBuffers = wrapBufs; if (state->response != NULL) { bson_free (state->response); state->response = NULL; state->qop = SECQOP_WRAP_NO_ENCRYPT; } if (!state->haveCtx) { return MONGOC_SSPI_AUTH_GSS_ERROR; } wrapBufs[0].pvBuffer = _mongoc_sspi_base64_decode (challenge, &len); if (!wrapBufs[0].pvBuffer) { return MONGOC_SSPI_AUTH_GSS_ERROR; } wrapBufs[0].cbBuffer = len; wrapBufs[0].BufferType = SECBUFFER_STREAM; wrapBufs[1].pvBuffer = NULL; wrapBufs[1].cbBuffer = 0; wrapBufs[1].BufferType = SECBUFFER_DATA; status = DecryptMessage (&state->ctx, &wrapBufDesc, 0, &state->qop); if (status == SEC_E_OK) { status = MONGOC_SSPI_AUTH_GSS_COMPLETE; } else { _mongoc_sspi_set_gsserror (status, "DecryptMessage"); status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } if (wrapBufs[1].cbBuffer) { state->response = _mongoc_sspi_base64_encode (wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); if (!state->response) { status = MONGOC_SSPI_AUTH_GSS_ERROR; } } done: if (wrapBufs[0].pvBuffer) { bson_free (wrapBufs[0].pvBuffer); } return status; } int _mongoc_sspi_auth_sspi_client_wrap ( mongoc_sspi_client_state_t *state, SEC_CHAR *data, SEC_CHAR *user, ULONG ulen, int protect) { SECURITY_STATUS status; SecPkgContext_Sizes sizes; SecBuffer wrapBufs[3]; SecBufferDesc wrapBufDesc; SEC_CHAR *decodedData = NULL; SEC_CHAR *inbuf; SIZE_T inbufSize; SEC_CHAR *outbuf; DWORD outbufSize; SEC_CHAR *plaintextMessage; ULONG plaintextMessageSize; if (state->response != NULL) { bson_free (state->response); state->response = NULL; } if (!state->haveCtx) { return MONGOC_SSPI_AUTH_GSS_ERROR; } status = QueryContextAttributes (&state->ctx, SECPKG_ATTR_SIZES, &sizes); if (status != SEC_E_OK) { _mongoc_sspi_set_gsserror (status, "QueryContextAttributes"); return MONGOC_SSPI_AUTH_GSS_ERROR; } if (user) { /* Length of user + 4 bytes for security layer (see below). */ plaintextMessageSize = ulen + 4; } else { decodedData = _mongoc_sspi_base64_decode (data, &plaintextMessageSize); if (!decodedData) { return MONGOC_SSPI_AUTH_GSS_ERROR; } } inbufSize = sizes.cbSecurityTrailer + plaintextMessageSize + sizes.cbBlockSize; inbuf = (SEC_CHAR *) bson_malloc (inbufSize); if (inbuf == NULL) { bson_free (decodedData); return MONGOC_SSPI_AUTH_GSS_ERROR; } plaintextMessage = inbuf + sizes.cbSecurityTrailer; if (user) { /* Authenticate the provided user. Unlike pykerberos, we don't * need any information from "data" to do that. * */ plaintextMessage[0] = 1; /* No security layer */ plaintextMessage[1] = 0; plaintextMessage[2] = 0; plaintextMessage[3] = 0; memcpy_s (plaintextMessage + 4, inbufSize - sizes.cbSecurityTrailer - 4, user, strlen (user)); } else { /* No user provided. Just rewrap data. */ memcpy_s (plaintextMessage, inbufSize - sizes.cbSecurityTrailer, decodedData, plaintextMessageSize); bson_free (decodedData); } wrapBufDesc.cBuffers = 3; wrapBufDesc.pBuffers = wrapBufs; wrapBufDesc.ulVersion = SECBUFFER_VERSION; wrapBufs[0].cbBuffer = sizes.cbSecurityTrailer; wrapBufs[0].BufferType = SECBUFFER_TOKEN; wrapBufs[0].pvBuffer = inbuf; wrapBufs[1].cbBuffer = (ULONG) plaintextMessageSize; wrapBufs[1].BufferType = SECBUFFER_DATA; wrapBufs[1].pvBuffer = inbuf + sizes.cbSecurityTrailer; wrapBufs[2].cbBuffer = sizes.cbBlockSize; wrapBufs[2].BufferType = SECBUFFER_PADDING; wrapBufs[2].pvBuffer = inbuf + (sizes.cbSecurityTrailer + plaintextMessageSize); status = EncryptMessage (&state->ctx, protect ? 0 : SECQOP_WRAP_NO_ENCRYPT, &wrapBufDesc, 0); if (status != SEC_E_OK) { bson_free (inbuf); _mongoc_sspi_set_gsserror (status, "EncryptMessage"); return MONGOC_SSPI_AUTH_GSS_ERROR; } outbufSize = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer; outbuf = (SEC_CHAR *) bson_malloc (sizeof (SEC_CHAR) * outbufSize); memcpy_s (outbuf, outbufSize, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer); memcpy_s ( outbuf + wrapBufs[0].cbBuffer, outbufSize - wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); memcpy_s (outbuf + wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer, outbufSize - wrapBufs[0].cbBuffer - wrapBufs[1].cbBuffer, wrapBufs[2].pvBuffer, wrapBufs[2].cbBuffer); state->response = _mongoc_sspi_base64_encode (outbuf, outbufSize); if (!state->response) { status = MONGOC_SSPI_AUTH_GSS_ERROR; } else { status = MONGOC_SSPI_AUTH_GSS_COMPLETE; } bson_free (inbuf); bson_free (outbuf); return status; } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-buffered.c0000644000175100001660000002267314760300420024217 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream" typedef struct { mongoc_stream_t stream; mongoc_stream_t *base_stream; mongoc_buffer_t buffer; } mongoc_stream_buffered_t; /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_destroy -- * * Clean up after a mongoc_stream_buffered_t. Free all allocated * resources and release the base stream. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ static void mongoc_stream_buffered_destroy (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *) stream; BSON_ASSERT (stream); mongoc_stream_destroy (buffered->base_stream); buffered->base_stream = NULL; _mongoc_buffer_destroy (&buffered->buffer); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_failed -- * * Called when a stream fails. Useful for streams that differnciate * between failure and cleanup. * Calls mongoc_stream_buffered_destroy() on the stream. * * Returns: * None. * * Side effects: * Everything. * *-------------------------------------------------------------------------- */ static void mongoc_stream_buffered_failed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_destroy (stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_close -- * * Close the underlying stream. The buffered content is still * valid. * * Returns: * The return value of mongoc_stream_close() on the underlying * stream. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int mongoc_stream_buffered_close (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *) stream; BSON_ASSERT (stream); return mongoc_stream_close (buffered->base_stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_flush -- * * Flushes the underlying stream. * * Returns: * The result of flush on the base stream. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int mongoc_stream_buffered_flush (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *) stream; BSON_ASSERT (buffered); return mongoc_stream_flush (buffered->base_stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_writev -- * * Write an iovec to the underlying stream. This write is not * buffered, it passes through to the base stream directly. * * timeout_msec should be the number of milliseconds to wait before * considering the writev as failed. * * Returns: * The number of bytes written or -1 on failure. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static ssize_t mongoc_stream_buffered_writev (mongoc_stream_t *stream, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt, /* IN */ int32_t timeout_msec) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *) stream; ssize_t ret; ENTRY; BSON_ASSERT (buffered); ret = mongoc_stream_writev (buffered->base_stream, iov, iovcnt, timeout_msec); RETURN (ret); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_readv -- * * Read from the underlying stream. The data will be buffered based * on the buffered streams target buffer size. * * When reading from the underlying stream, we read at least the * requested number of bytes, but try to also fill the stream to * the size of the underlying buffer. * * Note: * This isn't actually a huge savings since we never have more than * one reply waiting for us, but perhaps someday that will be * different. It should help for small replies, however that will * reduce our read() syscalls by 50%. * * Returns: * The number of bytes read or -1 on failure. * * Side effects: * iov[*]->iov_base buffers are filled. * *-------------------------------------------------------------------------- */ static ssize_t mongoc_stream_buffered_readv (mongoc_stream_t *stream, /* IN */ mongoc_iovec_t *iov, /* INOUT */ size_t iovcnt, /* IN */ size_t min_bytes, /* IN */ int32_t timeout_msec) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *) stream; bson_error_t error = {0}; size_t total_bytes = 0; size_t i; size_t off = 0; ENTRY; BSON_UNUSED (min_bytes); BSON_ASSERT (buffered); for (i = 0; i < iovcnt; i++) { total_bytes += iov[i].iov_len; } if (-1 == _mongoc_buffer_fill (&buffered->buffer, buffered->base_stream, total_bytes, timeout_msec, &error)) { MONGOC_WARNING ("%s", error.message); RETURN (-1); } BSON_ASSERT (buffered->buffer.len >= total_bytes); for (i = 0; i < iovcnt; i++) { memcpy (iov[i].iov_base, buffered->buffer.data + off, iov[i].iov_len); off += iov[i].iov_len; buffered->buffer.len -= iov[i].iov_len; } memmove (buffered->buffer.data, buffered->buffer.data + off, buffered->buffer.len); RETURN (total_bytes); } static mongoc_stream_t * _mongoc_stream_buffered_get_base_stream (mongoc_stream_t *stream) /* IN */ { return ((mongoc_stream_buffered_t *) stream)->base_stream; } static bool _mongoc_stream_buffered_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *) stream; BSON_ASSERT (stream); return mongoc_stream_check_closed (buffered->base_stream); } static bool _mongoc_stream_buffered_timed_out (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *) stream; BSON_ASSERT (stream); return mongoc_stream_timed_out (buffered->base_stream); } static bool _mongoc_stream_buffered_should_retry (mongoc_stream_t *stream) /* IN */ { mongoc_stream_buffered_t *buffered = (mongoc_stream_buffered_t *) stream; BSON_ASSERT (stream); return mongoc_stream_should_retry (buffered->base_stream); } /* *-------------------------------------------------------------------------- * * mongoc_stream_buffered_new -- * * Creates a new mongoc_stream_buffered_t. * * This stream will read from an underlying stream and try to read * more data than necessary. It can help lower the number of read() * or recv() syscalls performed. * * @base_stream is considered owned by the resulting stream after * calling this function. * * Returns: * A newly allocated mongoc_stream_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_buffered_new (mongoc_stream_t *base_stream, /* IN */ size_t buffer_size) /* IN */ { mongoc_stream_buffered_t *stream; BSON_ASSERT (base_stream); stream = (mongoc_stream_buffered_t *) bson_malloc0 (sizeof *stream); stream->stream.type = MONGOC_STREAM_BUFFERED; stream->stream.destroy = mongoc_stream_buffered_destroy; stream->stream.failed = mongoc_stream_buffered_failed; stream->stream.close = mongoc_stream_buffered_close; stream->stream.flush = mongoc_stream_buffered_flush; stream->stream.writev = mongoc_stream_buffered_writev; stream->stream.readv = mongoc_stream_buffered_readv; stream->stream.get_base_stream = _mongoc_stream_buffered_get_base_stream; stream->stream.check_closed = _mongoc_stream_buffered_check_closed; stream->stream.timed_out = _mongoc_stream_buffered_timed_out; stream->stream.should_retry = _mongoc_stream_buffered_should_retry; stream->base_stream = base_stream; _mongoc_buffer_init (&stream->buffer, NULL, buffer_size, NULL, NULL); mongoc_counter_streams_active_inc (); return (mongoc_stream_t *) stream; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-buffered.h0000644000175100001660000000177314760300420024222 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_BUFFERED_H #define MONGOC_STREAM_BUFFERED_H #include #include #include BSON_BEGIN_DECLS MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_buffered_new (mongoc_stream_t *base_stream, size_t buffer_size) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_STREAM_BUFFERED_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-file.c0000644000175100001660000001371014760300420023344 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifdef _WIN32 #include #include #endif #include #include #include #include #include /* * TODO: This does not respect timeouts or set O_NONBLOCK. * But that should be fine until it isn't :-) */ struct _mongoc_stream_file_t { mongoc_stream_t vtable; int fd; }; static int _mongoc_stream_file_close (mongoc_stream_t *stream) { mongoc_stream_file_t *file = (mongoc_stream_file_t *) stream; int ret; ENTRY; BSON_ASSERT (file); if (file->fd != -1) { #ifdef _WIN32 ret = _close (file->fd); #else ret = close (file->fd); #endif file->fd = -1; RETURN (ret); } RETURN (0); } static void _mongoc_stream_file_destroy (mongoc_stream_t *stream) { mongoc_stream_file_t *file = (mongoc_stream_file_t *) stream; ENTRY; BSON_ASSERT (file); if (file->fd) { _mongoc_stream_file_close (stream); } bson_free (file); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_stream_file_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_file_destroy (stream); EXIT; } static int _mongoc_stream_file_flush (mongoc_stream_t *stream) /* IN */ { mongoc_stream_file_t *file = (mongoc_stream_file_t *) stream; BSON_ASSERT (file); if (file->fd != -1) { #ifdef _WIN32 return _commit (file->fd); #else return fsync (file->fd); #endif } return 0; } static ssize_t _mongoc_stream_file_readv (mongoc_stream_t *stream, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt, /* IN */ size_t min_bytes, /* IN */ int32_t timeout_msec) /* IN */ { mongoc_stream_file_t *file = (mongoc_stream_file_t *) stream; ssize_t ret = 0; BSON_UNUSED (min_bytes); BSON_UNUSED (timeout_msec); #ifdef _WIN32 { ENTRY; for (size_t i = 0u; i < iovcnt; i++) { BSON_ASSERT (mcommon_in_range_unsigned (unsigned_int, iov[i].iov_len)); const int nread = _read (file->fd, iov[i].iov_base, (unsigned int) iov[i].iov_len); if (nread < 0) { ret = ret ? ret : -1; GOTO (done); } else if (nread == 0) { ret = ret ? ret : 0; GOTO (done); } else { ret += nread; if (nread != iov[i].iov_len) { ret = ret ? ret : -1; GOTO (done); } } } GOTO (done); } #else { ENTRY; BSON_ASSERT (mcommon_in_range_unsigned (int, iovcnt)); ret = readv (file->fd, iov, (int) iovcnt); GOTO (done); } #endif done: if (ret > 0) { mongoc_counter_streams_ingress_add (ret); } return ret; } static ssize_t _mongoc_stream_file_writev (mongoc_stream_t *stream, /* IN */ mongoc_iovec_t *iov, /* IN */ size_t iovcnt, /* IN */ int32_t timeout_msec) /* IN */ { mongoc_stream_file_t *file = (mongoc_stream_file_t *) stream; ssize_t ret = 0; BSON_UNUSED (timeout_msec); #ifdef _WIN32 { for (size_t i = 0; i < iovcnt; i++) { BSON_ASSERT (mcommon_in_range_unsigned (unsigned_int, iov[i].iov_len)); const int nwrite = _write (file->fd, iov[i].iov_base, (unsigned int) iov[i].iov_len); if (mcommon_cmp_not_equal_su (nwrite, iov[i].iov_len)) { ret = ret ? ret : -1; goto done; } ret += nwrite; } goto done; } #else { BSON_ASSERT (mcommon_in_range_unsigned (int, iovcnt)); ret = writev (file->fd, iov, (int) iovcnt); goto done; } #endif done: if (ret > 0) { mongoc_counter_streams_egress_add (ret); } return ret; } static bool _mongoc_stream_file_check_closed (mongoc_stream_t *stream) /* IN */ { BSON_UNUSED (stream); return false; } mongoc_stream_t * mongoc_stream_file_new (int fd) /* IN */ { mongoc_stream_file_t *stream; BSON_ASSERT (fd != -1); stream = (mongoc_stream_file_t *) bson_malloc0 (sizeof *stream); stream->vtable.type = MONGOC_STREAM_FILE; stream->vtable.close = _mongoc_stream_file_close; stream->vtable.destroy = _mongoc_stream_file_destroy; stream->vtable.failed = _mongoc_stream_file_failed; stream->vtable.flush = _mongoc_stream_file_flush; stream->vtable.readv = _mongoc_stream_file_readv; stream->vtable.writev = _mongoc_stream_file_writev; stream->vtable.check_closed = _mongoc_stream_file_check_closed; stream->fd = fd; mongoc_counter_streams_active_inc (); return (mongoc_stream_t *) stream; } mongoc_stream_t * mongoc_stream_file_new_for_path (const char *path, /* IN */ int flags, /* IN */ int mode) /* IN */ { int fd = -1; BSON_ASSERT (path); #ifdef _WIN32 if (_sopen_s (&fd, path, (flags | _O_BINARY), _SH_DENYNO, mode) != 0) { fd = -1; } #else fd = open (path, flags, mode); #endif if (fd == -1) { return NULL; } return mongoc_stream_file_new (fd); } int mongoc_stream_file_get_fd (mongoc_stream_file_t *stream) { BSON_ASSERT (stream); return stream->fd; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-file.h0000644000175100001660000000227414760300420023354 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_FILE_H #define MONGOC_STREAM_FILE_H #include #include BSON_BEGIN_DECLS typedef struct _mongoc_stream_file_t mongoc_stream_file_t; MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_file_new (int fd) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_file_new_for_path (const char *path, int flags, int mode) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (int) mongoc_stream_file_get_fd (mongoc_stream_file_t *stream); BSON_END_DECLS #endif /* MONGOC_STREAM_FILE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-gridfs-download-private.h0000644000175100001660000000210014760300420027154 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_GRIDFS_DOWNLOAD_PRIVATE_H #define MONGOC_STREAM_GRIDFS_DOWNLOAD_PRIVATE_H #include #include typedef struct { mongoc_stream_t stream; mongoc_gridfs_bucket_file_t *file; } mongoc_gridfs_download_stream_t; mongoc_stream_t * _mongoc_download_stream_gridfs_new (mongoc_gridfs_bucket_file_t *file); #endif /* MONGOC_STREAM_GRIDFS_DOWNLOAD_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-gridfs-download.c0000644000175100001660000000653014760300420025512 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-gridfs-download" static void _mongoc_download_stream_gridfs_destroy (mongoc_stream_t *stream) { mongoc_gridfs_download_stream_t *gridfs = (mongoc_gridfs_download_stream_t *) stream; ENTRY; BSON_ASSERT (stream); mongoc_stream_close (stream); _mongoc_gridfs_bucket_file_destroy (gridfs->file); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_download_stream_gridfs_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_download_stream_gridfs_destroy (stream); EXIT; } static int _mongoc_download_stream_gridfs_close (mongoc_stream_t *stream) { mongoc_gridfs_download_stream_t *gridfs = (mongoc_gridfs_download_stream_t *) stream; int ret = 0; ENTRY; BSON_ASSERT (stream); gridfs->file->finished = true; RETURN (ret); } static ssize_t _mongoc_download_stream_gridfs_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_gridfs_download_stream_t *gridfs = (mongoc_gridfs_download_stream_t *) stream; ssize_t ret = 0; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); (void) min_bytes; /* unused. */ (void) timeout_msec; /* unused. */ /* timeout_msec is unused by mongoc_gridfs_bucket_file_readv */ ret = _mongoc_gridfs_bucket_file_readv (gridfs->file, iov, iovcnt); mongoc_counter_streams_ingress_add (ret); RETURN (ret); } static bool _mongoc_download_stream_gridfs_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_gridfs_download_stream_t *gridfs = (mongoc_gridfs_download_stream_t *) stream; ENTRY; BSON_ASSERT (stream); RETURN (gridfs->file->finished); } mongoc_stream_t * _mongoc_download_stream_gridfs_new (mongoc_gridfs_bucket_file_t *file) { mongoc_gridfs_download_stream_t *stream; ENTRY; BSON_ASSERT (file); stream = (mongoc_gridfs_download_stream_t *) bson_malloc0 (sizeof *stream); stream->file = file; stream->stream.type = MONGOC_STREAM_GRIDFS_DOWNLOAD; stream->stream.destroy = _mongoc_download_stream_gridfs_destroy; stream->stream.failed = _mongoc_download_stream_gridfs_failed; stream->stream.close = _mongoc_download_stream_gridfs_close; stream->stream.readv = _mongoc_download_stream_gridfs_readv; stream->stream.check_closed = _mongoc_download_stream_gridfs_check_closed; mongoc_counter_streams_active_inc (); RETURN ((mongoc_stream_t *) stream); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-gridfs-upload-private.h0000644000175100001660000000206614760300420026644 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_GRIDFS_UPLOAD_PRIVATE_H #define MONGOC_STREAM_GRIDFS_UPLOAD_PRIVATE_H #include #include typedef struct { mongoc_stream_t stream; mongoc_gridfs_bucket_file_t *file; } mongoc_gridfs_upload_stream_t; mongoc_stream_t * _mongoc_upload_stream_gridfs_new (mongoc_gridfs_bucket_file_t *file); #endif /* MONGOC_STREAM_GRIDFS_UPLOAD_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-gridfs-upload.c0000644000175100001660000000635414760300420025173 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-gridfs-upload" static void _mongoc_upload_stream_gridfs_destroy (mongoc_stream_t *stream) { mongoc_gridfs_upload_stream_t *gridfs = (mongoc_gridfs_upload_stream_t *) stream; ENTRY; BSON_ASSERT (stream); mongoc_stream_close (stream); _mongoc_gridfs_bucket_file_destroy (gridfs->file); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_upload_stream_gridfs_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_upload_stream_gridfs_destroy (stream); EXIT; } static int _mongoc_upload_stream_gridfs_close (mongoc_stream_t *stream) { mongoc_gridfs_upload_stream_t *gridfs = (mongoc_gridfs_upload_stream_t *) stream; int ret = 0; ENTRY; BSON_ASSERT (stream); ret = _mongoc_gridfs_bucket_file_save (gridfs->file); RETURN (ret ? 0 : 1); } static ssize_t _mongoc_upload_stream_gridfs_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_gridfs_upload_stream_t *gridfs = (mongoc_gridfs_upload_stream_t *) stream; ssize_t ret = 0; ENTRY; BSON_ASSERT (stream); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); (void) timeout_msec; /* unused. */ ret = _mongoc_gridfs_bucket_file_writev (gridfs->file, iov, iovcnt); if (!ret) { RETURN (ret); } mongoc_counter_streams_egress_add (ret); RETURN (ret); } static bool _mongoc_upload_stream_gridfs_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_gridfs_upload_stream_t *gridfs = (mongoc_gridfs_upload_stream_t *) stream; ENTRY; BSON_ASSERT (stream); RETURN (gridfs->file->saved); } mongoc_stream_t * _mongoc_upload_stream_gridfs_new (mongoc_gridfs_bucket_file_t *file) { mongoc_gridfs_upload_stream_t *stream; ENTRY; BSON_ASSERT (file); stream = (mongoc_gridfs_upload_stream_t *) bson_malloc0 (sizeof *stream); stream->file = file; stream->stream.type = MONGOC_STREAM_GRIDFS_UPLOAD; stream->stream.destroy = _mongoc_upload_stream_gridfs_destroy; stream->stream.failed = _mongoc_upload_stream_gridfs_failed; stream->stream.close = _mongoc_upload_stream_gridfs_close; stream->stream.writev = _mongoc_upload_stream_gridfs_writev; stream->stream.check_closed = _mongoc_upload_stream_gridfs_check_closed; mongoc_counter_streams_active_inc (); RETURN ((mongoc_stream_t *) stream); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-gridfs.c0000644000175100001660000000772414760300420023713 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-gridfs" typedef struct { mongoc_stream_t stream; mongoc_gridfs_file_t *file; } mongoc_stream_gridfs_t; static void _mongoc_stream_gridfs_destroy (mongoc_stream_t *stream) { ENTRY; BSON_ASSERT (stream); mongoc_stream_close (stream); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_stream_gridfs_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_gridfs_destroy (stream); EXIT; } static int _mongoc_stream_gridfs_close (mongoc_stream_t *stream) { mongoc_stream_gridfs_t *gridfs = (mongoc_stream_gridfs_t *) stream; int ret = 0; ENTRY; BSON_ASSERT (stream); ret = mongoc_gridfs_file_save (gridfs->file); RETURN (ret); } static int _mongoc_stream_gridfs_flush (mongoc_stream_t *stream) { mongoc_stream_gridfs_t *gridfs = (mongoc_stream_gridfs_t *) stream; int ret = 0; ENTRY; BSON_ASSERT (stream); ret = mongoc_gridfs_file_save (gridfs->file); RETURN (ret); } static ssize_t _mongoc_stream_gridfs_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_gridfs_t *file = (mongoc_stream_gridfs_t *) stream; ssize_t ret = 0; ENTRY; BSON_UNUSED (timeout_msec); BSON_ASSERT (stream); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); /* timeout_msec is unused by mongoc_gridfs_file_readv */ ret = mongoc_gridfs_file_readv (file->file, iov, iovcnt, min_bytes, 0); mongoc_counter_streams_ingress_add (ret); RETURN (ret); } static ssize_t _mongoc_stream_gridfs_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_gridfs_t *file = (mongoc_stream_gridfs_t *) stream; ssize_t ret = 0; ENTRY; BSON_UNUSED (timeout_msec); BSON_ASSERT (stream); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); /* timeout_msec is unused by mongoc_gridfs_file_writev */ ret = mongoc_gridfs_file_writev (file->file, iov, iovcnt, 0); if (!ret) { RETURN (ret); } mongoc_counter_streams_egress_add (ret); RETURN (ret); } static bool _mongoc_stream_gridfs_check_closed (mongoc_stream_t *stream) /* IN */ { BSON_UNUSED (stream); return false; } mongoc_stream_t * mongoc_stream_gridfs_new (mongoc_gridfs_file_t *file) { mongoc_stream_gridfs_t *stream; ENTRY; BSON_ASSERT (file); stream = (mongoc_stream_gridfs_t *) bson_malloc0 (sizeof *stream); stream->file = file; stream->stream.type = MONGOC_STREAM_GRIDFS; stream->stream.destroy = _mongoc_stream_gridfs_destroy; stream->stream.failed = _mongoc_stream_gridfs_failed; stream->stream.close = _mongoc_stream_gridfs_close; stream->stream.flush = _mongoc_stream_gridfs_flush; stream->stream.writev = _mongoc_stream_gridfs_writev; stream->stream.readv = _mongoc_stream_gridfs_readv; stream->stream.check_closed = _mongoc_stream_gridfs_check_closed; mongoc_counter_streams_active_inc (); RETURN ((mongoc_stream_t *) stream); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-gridfs.h0000644000175100001660000000177714760300420023722 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_GRIDFS_H #define MONGOC_STREAM_GRIDFS_H #include #include #include #include BSON_BEGIN_DECLS MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_gridfs_new (mongoc_gridfs_file_t *file) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_STREAM_GRIDFS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-private.h0000644000175100001660000000253014760300420024102 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_PRIVATE_H #define MONGOC_STREAM_PRIVATE_H #include #include BSON_BEGIN_DECLS #define MONGOC_STREAM_SOCKET 1 #define MONGOC_STREAM_FILE 2 #define MONGOC_STREAM_BUFFERED 3 #define MONGOC_STREAM_GRIDFS 4 #define MONGOC_STREAM_TLS 5 #define MONGOC_STREAM_GRIDFS_UPLOAD 6 #define MONGOC_STREAM_GRIDFS_DOWNLOAD 7 bool mongoc_stream_wait (mongoc_stream_t *stream, int64_t expire_at); bool _mongoc_stream_writev_full ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int64_t timeout_msec, bson_error_t *error); mongoc_stream_t * mongoc_stream_get_root_stream (mongoc_stream_t *stream); BSON_END_DECLS #endif /* MONGOC_STREAM_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-socket.c0000644000175100001660000001655014760300420023722 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream" struct _mongoc_stream_socket_t { mongoc_stream_t vtable; mongoc_socket_t *sock; }; static BSON_INLINE int64_t get_expiration (int32_t timeout_msec) { if (timeout_msec < 0) { return -1; } else if (timeout_msec == 0) { return 0; } else { return (bson_get_monotonic_time () + ((int64_t) timeout_msec * 1000L)); } } static int _mongoc_stream_socket_close (mongoc_stream_t *stream) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; int ret; ENTRY; BSON_ASSERT (ss); if (ss->sock) { ret = mongoc_socket_close (ss->sock); RETURN (ret); } RETURN (0); } static void _mongoc_stream_socket_destroy (mongoc_stream_t *stream) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; ENTRY; BSON_ASSERT (ss); if (ss->sock) { mongoc_socket_destroy (ss->sock); ss->sock = NULL; } bson_free (ss); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_stream_socket_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_socket_destroy (stream); EXIT; } static int _mongoc_stream_socket_setsockopt ( mongoc_stream_t *stream, int level, int optname, void *optval, mongoc_socklen_t optlen) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; int ret; ENTRY; BSON_ASSERT (ss); BSON_ASSERT (ss->sock); ret = mongoc_socket_setsockopt (ss->sock, level, optname, optval, optlen); RETURN (ret); } static int _mongoc_stream_socket_flush (mongoc_stream_t *stream) { ENTRY; BSON_UNUSED (stream); RETURN (0); } static ssize_t _mongoc_stream_socket_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; int64_t expire_at; ssize_t ret = 0; ssize_t nread; size_t cur = 0; ENTRY; BSON_ASSERT (ss); BSON_ASSERT (ss->sock); expire_at = get_expiration (timeout_msec); /* * This isn't ideal, we should plumb through to recvmsg(), but we * don't actually use this in any way but to a single buffer * currently anyway, so should be just fine. */ for (;;) { nread = mongoc_socket_recv (ss->sock, iov[cur].iov_base, iov[cur].iov_len, 0, expire_at); if (nread <= 0) { if (ret >= (ssize_t) min_bytes) { RETURN (ret); } errno = mongoc_socket_errno (ss->sock); RETURN (-1); } ret += nread; while ((cur < iovcnt) && (nread >= (ssize_t) iov[cur].iov_len)) { nread -= iov[cur++].iov_len; } if (cur == iovcnt) { break; } if (ret >= (ssize_t) min_bytes) { RETURN (ret); } iov[cur].iov_base = ((char *) iov[cur].iov_base) + nread; iov[cur].iov_len -= nread; BSON_ASSERT (iovcnt - cur); BSON_ASSERT (iov[cur].iov_len); } RETURN (ret); } static ssize_t _mongoc_stream_socket_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; int64_t expire_at; ssize_t ret; ENTRY; if (ss->sock) { expire_at = get_expiration (timeout_msec); ret = mongoc_socket_sendv (ss->sock, iov, iovcnt, expire_at); errno = mongoc_socket_errno (ss->sock); RETURN (ret); } RETURN (-1); } static ssize_t _mongoc_stream_socket_poll (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout_msec) { ssize_t ret = -1; mongoc_socket_poll_t *sds; mongoc_stream_socket_t *ss; ENTRY; sds = (mongoc_socket_poll_t *) bson_malloc (sizeof (*sds) * nstreams); for (size_t i = 0u; i < nstreams; i++) { ss = (mongoc_stream_socket_t *) streams[i].stream; if (!ss->sock) { goto CLEANUP; } sds[i].socket = ss->sock; sds[i].events = streams[i].events; } ret = mongoc_socket_poll (sds, nstreams, timeout_msec); if (ret > 0) { for (size_t i = 0u; i < nstreams; i++) { streams[i].revents = sds[i].revents; } } CLEANUP: bson_free (sds); RETURN (ret); } mongoc_socket_t * mongoc_stream_socket_get_socket (mongoc_stream_socket_t *stream) /* IN */ { BSON_ASSERT (stream); return stream->sock; } static bool _mongoc_stream_socket_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; ENTRY; BSON_ASSERT (stream); if (ss->sock) { RETURN (mongoc_socket_check_closed (ss->sock)); } RETURN (true); } static bool _mongoc_stream_socket_timed_out (mongoc_stream_t *stream) /* IN */ { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; ENTRY; BSON_ASSERT (ss); BSON_ASSERT (ss->sock); RETURN (MONGOC_ERRNO_IS_TIMEDOUT (ss->sock->errno_)); } static bool _mongoc_stream_socket_should_retry (mongoc_stream_t *stream) /* IN */ { mongoc_stream_socket_t *ss = (mongoc_stream_socket_t *) stream; ENTRY; BSON_ASSERT (ss); BSON_ASSERT (ss->sock); RETURN (MONGOC_ERRNO_IS_AGAIN (ss->sock->errno_)); } /* *-------------------------------------------------------------------------- * * mongoc_stream_socket_new -- * * Create a new mongoc_stream_t using the mongoc_socket_t for * read and write underneath. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_socket_new (mongoc_socket_t *sock) /* IN */ { mongoc_stream_socket_t *stream; BSON_ASSERT (sock); stream = (mongoc_stream_socket_t *) bson_malloc0 (sizeof *stream); stream->vtable.type = MONGOC_STREAM_SOCKET; stream->vtable.close = _mongoc_stream_socket_close; stream->vtable.destroy = _mongoc_stream_socket_destroy; stream->vtable.failed = _mongoc_stream_socket_failed; stream->vtable.flush = _mongoc_stream_socket_flush; stream->vtable.readv = _mongoc_stream_socket_readv; stream->vtable.writev = _mongoc_stream_socket_writev; stream->vtable.setsockopt = _mongoc_stream_socket_setsockopt; stream->vtable.check_closed = _mongoc_stream_socket_check_closed; stream->vtable.timed_out = _mongoc_stream_socket_timed_out; stream->vtable.should_retry = _mongoc_stream_socket_should_retry; stream->vtable.poll = _mongoc_stream_socket_poll; stream->sock = sock; mongoc_counter_streams_active_inc (); return (mongoc_stream_t *) stream; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-socket.h0000644000175100001660000000221114760300420023714 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_SOCKET_H #define MONGOC_STREAM_SOCKET_H #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_stream_socket_t mongoc_stream_socket_t; MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_socket_new (mongoc_socket_t *socket) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_socket_t *) mongoc_stream_socket_get_socket (mongoc_stream_socket_t *stream); BSON_END_DECLS #endif /* MONGOC_STREAM_SOCKET_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-libressl-private.h0000644000175100001660000000213514760300420026520 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_LIBRESSL_PRIVATE_H #define MONGOC_STREAM_TLS_LIBRESSL_PRIVATE_H #ifdef MONGOC_ENABLE_SSL_LIBRESSL #include #include BSON_BEGIN_DECLS /** * mongoc_stream_tls_libressl_t: * * Private storage for LibreSSL Streams */ typedef struct { struct tls *ctx; struct tls_config *config; } mongoc_stream_tls_libressl_t; BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_LIBRESSL */ #endif /* MONGOC_STREAM_TLS_LIBRESSL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-libressl.c0000644000175100001660000003602014760300420025043 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_LIBRESSL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-tls-libressl" static void _mongoc_stream_tls_libressl_destroy (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; ENTRY; BSON_ASSERT (libressl); tls_close (libressl->ctx); tls_free (libressl->ctx); tls_config_free (libressl->config); mongoc_stream_destroy (tls->base_stream); bson_free (libressl); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_stream_tls_libressl_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_tls_libressl_destroy (stream); EXIT; } static int _mongoc_stream_tls_libressl_close (mongoc_stream_t *stream) { int ret = 0; mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; ENTRY; BSON_ASSERT (libressl); ret = mongoc_stream_close (tls->base_stream); RETURN (ret); } static int _mongoc_stream_tls_libressl_flush (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; ENTRY; BSON_ASSERT (libressl); RETURN (0); } static ssize_t _mongoc_stream_tls_libressl_write (mongoc_stream_t *stream, char *buf, size_t buf_len) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; mongoc_stream_poll_t poller; ssize_t total_write = 0; ssize_t ret; int64_t now; int64_t expire = 0; ENTRY; BSON_ASSERT (libressl); if (tls->timeout_msec >= 0) { expire = bson_get_monotonic_time () + (tls->timeout_msec * 1000UL); } do { poller.stream = stream; poller.revents = 0; poller.events = POLLOUT; ret = tls_write (libressl->ctx, buf, buf_len); if (ret == TLS_WANT_POLLIN) { poller.events = POLLIN; mongoc_stream_poll (&poller, 1, tls->timeout_msec); } else if (ret == TLS_WANT_POLLOUT) { poller.events = POLLOUT; mongoc_stream_poll (&poller, 1, tls->timeout_msec); } else if (ret < 0) { RETURN (total_write); } else { buf += ret; buf_len -= ret; total_write += ret; } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (ret == 0) { mongoc_counter_streams_timeout_inc (); break; } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000L; } } } while (buf_len > 0); RETURN (total_write); } /* This is copypasta from _mongoc_stream_tls_openssl_writev */ #define MONGOC_STREAM_TLS_BUFFER_SIZE 4096 static ssize_t _mongoc_stream_tls_libressl_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; char buf[MONGOC_STREAM_TLS_BUFFER_SIZE]; ssize_t ret = 0; ssize_t child_ret; size_t i; size_t iov_pos = 0; /* There's a bit of a dance to coalesce vectorized writes into * MONGOC_STREAM_TLS_BUFFER_SIZE'd writes to avoid lots of small tls * packets. * * The basic idea is that we want to combine writes in the buffer if they're * smaller than the buffer, flushing as it gets full. For larger writes, or * the last write in the iovec array, we want to ignore the buffer and just * write immediately. We take care of doing buffer writes by re-invoking * ourself with a single iovec_t, pointing at our stack buffer. */ char *buf_head = buf; char *buf_tail = buf; char *buf_end = buf + MONGOC_STREAM_TLS_BUFFER_SIZE; size_t bytes; char *to_write = NULL; size_t to_write_len; BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (libressl); ENTRY; tls->timeout_msec = timeout_msec; for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { if (buf_head != buf_tail || ((i + 1 < iovcnt) && ((buf_end - buf_tail) > (iov[i].iov_len - iov_pos)))) { /* If we have either of: * - buffered bytes already * - another iovec to send after this one and we don't have more * bytes to send than the size of the buffer. * * copy into the buffer */ bytes = BSON_MIN (iov[i].iov_len - iov_pos, buf_end - buf_tail); memcpy (buf_tail, (char *) iov[i].iov_base + iov_pos, bytes); buf_tail += bytes; iov_pos += bytes; if (buf_tail == buf_end) { /* If we're full, request send */ to_write = buf_head; to_write_len = buf_tail - buf_head; buf_tail = buf_head = buf; } } else { /* Didn't buffer, so just write it through */ to_write = (char *) iov[i].iov_base + iov_pos; to_write_len = iov[i].iov_len - iov_pos; iov_pos += to_write_len; } if (to_write) { /* We get here if we buffered some bytes and filled the buffer, or * if we didn't buffer and have to send out of the iovec */ child_ret = _mongoc_stream_tls_libressl_write (stream, to_write, to_write_len); if (child_ret < 0) { RETURN (ret); } ret += child_ret; if (child_ret < to_write_len) { /* we timed out, so send back what we could send */ RETURN (ret); } to_write = NULL; } } } if (buf_head != buf_tail) { /* If we have any bytes buffered, send */ child_ret = _mongoc_stream_tls_libressl_write (stream, buf_head, buf_tail - buf_head); if (child_ret < 0) { RETURN (child_ret); } ret += child_ret; } if (ret >= 0) { mongoc_counter_streams_egress_add (ret); } TRACE ("Returning %d", (int) ret); RETURN (ret); } /* This function is copypasta of _mongoc_stream_tls_openssl_readv */ static ssize_t _mongoc_stream_tls_libressl_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; ssize_t ret = 0; ssize_t read_ret; size_t i; size_t iov_pos = 0; int64_t now; int64_t expire = 0; mongoc_stream_poll_t poller; BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (libressl); ENTRY; tls->timeout_msec = timeout_msec; if (timeout_msec >= 0) { expire = bson_get_monotonic_time () + (timeout_msec * 1000UL); } for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { poller.stream = stream; poller.revents = 0; poller.events = POLLIN; read_ret = tls_read (libressl->ctx, (char *) iov[i].iov_base + iov_pos, (int) (iov[i].iov_len - iov_pos)); if (read_ret == TLS_WANT_POLLIN) { poller.events = POLLIN; mongoc_stream_poll (&poller, 1, tls->timeout_msec); } else if (read_ret == TLS_WANT_POLLOUT) { poller.events = POLLOUT; mongoc_stream_poll (&poller, 1, tls->timeout_msec); } else if (read_ret < 0) { RETURN (ret); } else { iov_pos += read_ret; ret += read_ret; } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (read_ret == 0) { mongoc_counter_streams_timeout_inc (); errno = ETIMEDOUT; RETURN (-1); } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000L; } } if (ret > 0 && (size_t) ret >= min_bytes) { mongoc_counter_streams_ingress_add (ret); RETURN (ret); } } } if (ret >= 0) { mongoc_counter_streams_ingress_add (ret); } RETURN (ret); } static int _mongoc_stream_tls_libressl_setsockopt ( mongoc_stream_t *stream, int level, int optname, void *optval, mongoc_socklen_t optlen) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; ENTRY; BSON_ASSERT (libressl); RETURN (mongoc_stream_setsockopt (tls->base_stream, level, optname, optval, optlen)); } static mongoc_stream_t * _mongoc_stream_tls_libressl_get_base_stream (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; ENTRY; BSON_ASSERT (libressl); RETURN (tls->base_stream); } static bool _mongoc_stream_tls_libressl_check_closed (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; ENTRY; BSON_ASSERT (libressl); RETURN (mongoc_stream_check_closed (tls->base_stream)); } bool mongoc_stream_tls_libressl_handshake (mongoc_stream_t *stream, const char *host, int *events, bson_error_t *error) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_libressl_t *libressl = (mongoc_stream_tls_libressl_t *) tls->ctx; int ret; ENTRY; BSON_ASSERT (libressl); ret = tls_handshake (libressl->ctx); if (ret == TLS_WANT_POLLIN) { *events = POLLIN; } else if (ret == TLS_WANT_POLLOUT) { *events = POLLOUT; } else if (ret < 0) { *events = 0; bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed: %s", tls_error (libressl->ctx)); RETURN (false); } else { RETURN (true); } RETURN (false); } static bool _mongoc_stream_tls_libressl_timed_out (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; ENTRY; RETURN (mongoc_stream_timed_out (tls->base_stream)); } static bool _mongoc_stream_tls_libressl_should_retry (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; ENTRY; RETURN (mongoc_stream_should_retry (tls->base_stream)); } mongoc_stream_t * mongoc_stream_tls_libressl_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) { mongoc_stream_tls_t *tls; mongoc_stream_tls_libressl_t *libressl; ENTRY; BSON_ASSERT (base_stream); BSON_ASSERT (opt); if (opt->crl_file) { MONGOC_ERROR ("Setting mongoc_ssl_opt_t.crl_file has no effect when built " "against libtls"); RETURN (false); } libressl = (mongoc_stream_tls_libressl_t *) bson_malloc0 (sizeof *libressl); tls = (mongoc_stream_tls_t *) bson_malloc0 (sizeof *tls); tls->parent.type = MONGOC_STREAM_TLS; tls->parent.destroy = _mongoc_stream_tls_libressl_destroy; tls->parent.failed = _mongoc_stream_tls_libressl_failed; tls->parent.close = _mongoc_stream_tls_libressl_close; tls->parent.flush = _mongoc_stream_tls_libressl_flush; tls->parent.writev = _mongoc_stream_tls_libressl_writev; tls->parent.readv = _mongoc_stream_tls_libressl_readv; tls->parent.setsockopt = _mongoc_stream_tls_libressl_setsockopt; tls->parent.get_base_stream = _mongoc_stream_tls_libressl_get_base_stream; tls->parent.check_closed = _mongoc_stream_tls_libressl_check_closed; tls->parent.timed_out = _mongoc_stream_tls_libressl_timed_out; tls->parent.should_retry = _mongoc_stream_tls_libressl_should_retry; memcpy (&tls->ssl_opts, opt, sizeof tls->ssl_opts); tls->handshake = mongoc_stream_tls_libressl_handshake; tls->ctx = (void *) libressl; tls->timeout_msec = -1; tls->base_stream = base_stream; libressl->ctx = client ? tls_client () : tls_server (); libressl->config = tls_config_new (); if (opt->weak_cert_validation) { tls_config_insecure_noverifycert (libressl->config); tls_config_insecure_noverifytime (libressl->config); } if (opt->allow_invalid_hostname) { tls_config_insecure_noverifyname (libressl->config); } tls_config_set_ciphers (libressl->config, "compat"); mongoc_libressl_setup_certificate (libressl, opt); mongoc_libressl_setup_ca (libressl, opt); { mongoc_stream_t *stream = base_stream; do { if (stream->type == MONGOC_STREAM_SOCKET) { int socket = mongoc_stream_socket_get_socket ((mongoc_stream_socket_t *) stream)->sd; if (tls_configure (libressl->ctx, libressl->config) == -1) { MONGOC_ERROR ("%s", tls_config_error (libressl->config)); RETURN (false); } if (tls_connect_socket (libressl->ctx, socket, host) == -1) { MONGOC_ERROR ("%s", tls_error (libressl->ctx)); RETURN (false); } break; } } while ((stream = mongoc_stream_get_base_stream (stream))); } mongoc_counter_streams_active_inc (); if (_mongoc_ssl_opts_disable_certificate_revocation_check (opt)) { MONGOC_ERROR ("Setting tlsDisableCertificateRevocationCheck has no " "effect when built against libtls"); } if (_mongoc_ssl_opts_disable_ocsp_endpoint_check (opt)) { MONGOC_ERROR ("Setting tlsDisableOCSPEndpointCheck has no effect when " "built against libtls"); } RETURN ((mongoc_stream_t *) tls); } #endif /* MONGOC_ENABLE_SSL_LIBRESSL */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-libressl.h0000644000175100001660000000215114760300420025046 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_LIBRESSL_H #define MONGOC_STREAM_TLS_LIBRESSL_H #ifdef MONGOC_ENABLE_SSL_LIBRESSL #include #include BSON_BEGIN_DECLS MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_tls_libressl_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) BSON_GNUC_DEPRECATED BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_LIBRESSL */ #endif /* MONGOC_STREAM_TLS_LIBRESSL_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-openssl-bio-private.h0000644000175100001660000000307114760300420027133 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_OPENSSL_BIO_PRIVATE_H #define MONGOC_STREAM_TLS_OPENSSL_BIO_PRIVATE_H #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #include #include #include BSON_BEGIN_DECLS BIO_METHOD * mongoc_stream_tls_openssl_bio_meth_new (void); void mongoc_stream_tls_openssl_bio_set_data (BIO *b, void *ptr); int mongoc_stream_tls_openssl_bio_create (BIO *b); int mongoc_stream_tls_openssl_bio_destroy (BIO *b); int mongoc_stream_tls_openssl_bio_read (BIO *b, char *buf, int len); int mongoc_stream_tls_openssl_bio_write (BIO *b, const char *buf, int len); long mongoc_stream_tls_openssl_bio_ctrl (BIO *b, int cmd, long num, void *ptr); int mongoc_stream_tls_openssl_bio_gets (BIO *b, char *buf, int len); int mongoc_stream_tls_openssl_bio_puts (BIO *b, const char *str); BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_OPENSSL */ #endif /* MONGOC_STREAM_TLS_OPENSSL_BIO_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-openssl-bio.c0000644000175100001660000002276714760300420025473 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-tls-openssl-bio" #if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) /* Magic vtable to make our BIO shim */ static BIO_METHOD gMongocStreamTlsOpenSslRawMethods = {BIO_TYPE_FILTER, "mongoc-stream-tls-glue", mongoc_stream_tls_openssl_bio_write, mongoc_stream_tls_openssl_bio_read, mongoc_stream_tls_openssl_bio_puts, mongoc_stream_tls_openssl_bio_gets, mongoc_stream_tls_openssl_bio_ctrl, mongoc_stream_tls_openssl_bio_create, mongoc_stream_tls_openssl_bio_destroy, NULL}; static void BIO_set_data (BIO *b, void *ptr) { b->ptr = ptr; } static void * BIO_get_data (BIO *b) { return b->ptr; } static void BIO_set_init (BIO *b, int init) { b->init = init; } BIO_METHOD * mongoc_stream_tls_openssl_bio_meth_new (void) { BIO_METHOD *meth = NULL; meth = &gMongocStreamTlsOpenSslRawMethods; return meth; } #else BIO_METHOD * mongoc_stream_tls_openssl_bio_meth_new (void) { BIO_METHOD *meth = NULL; meth = BIO_meth_new (BIO_TYPE_FILTER, "mongoc-stream-tls-glue"); if (meth) { BIO_meth_set_write (meth, mongoc_stream_tls_openssl_bio_write); BIO_meth_set_read (meth, mongoc_stream_tls_openssl_bio_read); BIO_meth_set_puts (meth, mongoc_stream_tls_openssl_bio_puts); BIO_meth_set_gets (meth, mongoc_stream_tls_openssl_bio_gets); BIO_meth_set_ctrl (meth, mongoc_stream_tls_openssl_bio_ctrl); BIO_meth_set_create (meth, mongoc_stream_tls_openssl_bio_create); BIO_meth_set_destroy (meth, mongoc_stream_tls_openssl_bio_destroy); } return meth; } #endif void mongoc_stream_tls_openssl_bio_set_data (BIO *b, void *ptr) { BIO_set_data (b, ptr); } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_bio_create -- * * BIO callback to create a new BIO instance. * * Returns: * 1 if successful. * * Side effects: * @b is initialized. * *-------------------------------------------------------------------------- */ int mongoc_stream_tls_openssl_bio_create (BIO *b) { BSON_ASSERT (b); BIO_set_init (b, 1); BIO_set_data (b, NULL); BIO_set_flags (b, 0); return 1; } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_bio_destroy -- * * Release resources associated with BIO. * * Returns: * 1 if successful. * * Side effects: * @b is destroyed. * *-------------------------------------------------------------------------- */ int mongoc_stream_tls_openssl_bio_destroy (BIO *b) { mongoc_stream_tls_t *tls; BSON_ASSERT (b); tls = (mongoc_stream_tls_t *) BIO_get_data (b); if (!tls) { return -1; } BIO_set_data (b, NULL); BIO_set_init (b, 0); BIO_set_flags (b, 0); ((mongoc_stream_tls_openssl_t *) tls->ctx)->bio = NULL; return 1; } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_bio_read -- * * Read from the underlying stream to BIO. * * Returns: * -1 on failure; otherwise the number of bytes read. * * Side effects: * @buf is filled with data read from underlying stream. * *-------------------------------------------------------------------------- */ int mongoc_stream_tls_openssl_bio_read (BIO *b, char *buf, int len) { mongoc_stream_tls_t *tls; mongoc_stream_tls_openssl_t *openssl; BSON_ASSERT (b); BSON_ASSERT (buf); ENTRY; tls = (mongoc_stream_tls_t *) BIO_get_data (b); if (!tls) { RETURN (-1); } if (len < 0) { RETURN (-1); } if (BSON_UNLIKELY (!mcommon_in_range_signed (int32_t, tls->timeout_msec))) { // CDRIVER-4589 MONGOC_ERROR ("timeout_msec value %" PRId64 " exceeds supported 32-bit range", tls->timeout_msec); return -1; } openssl = (mongoc_stream_tls_openssl_t *) tls->ctx; errno = 0; const ssize_t ret = mongoc_stream_read (tls->base_stream, buf, (size_t) len, 0, (int32_t) tls->timeout_msec); BIO_clear_retry_flags (b); if ((ret <= 0) && MONGOC_ERRNO_IS_AGAIN (errno)) { /* this BIO is not the same as "b", which openssl passed in to this func. * set its retry flag, which we check with BIO_should_retry in * mongoc-stream-tls-openssl.c */ BIO_set_retry_read (openssl->bio); } BSON_ASSERT (mcommon_in_range_signed (int, ret)); RETURN ((int) ret); } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_bio_write -- * * Write to the underlying stream on behalf of BIO. * * Returns: * -1 on failure; otherwise the number of bytes written. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_stream_tls_openssl_bio_write (BIO *b, const char *buf, int len) { mongoc_stream_tls_t *tls; mongoc_stream_tls_openssl_t *openssl; mongoc_iovec_t iov; ENTRY; BSON_ASSERT (b); BSON_ASSERT (buf); tls = (mongoc_stream_tls_t *) BIO_get_data (b); if (!tls) { RETURN (-1); } if (len < 0) { RETURN (-1); } openssl = (mongoc_stream_tls_openssl_t *) tls->ctx; iov.iov_base = (void *) buf; iov.iov_len = (size_t) len; if (BSON_UNLIKELY (!mcommon_in_range_signed (int32_t, tls->timeout_msec))) { // CDRIVER-4589 MONGOC_ERROR ("timeout_msec value %" PRId64 " exceeds supported 32-bit range", tls->timeout_msec); RETURN (-1); } errno = 0; TRACE ("mongoc_stream_writev is expected to write: %d", len); const ssize_t ret = mongoc_stream_writev (tls->base_stream, &iov, 1, (int32_t) tls->timeout_msec); BIO_clear_retry_flags (b); if (len > ret) { TRACE ("Returned short write: %zd of %d", ret, len); } else { TRACE ("Completed the %zd", ret); } if (ret <= 0 && MONGOC_ERRNO_IS_AGAIN (errno)) { /* this BIO is not the same as "b", which openssl passed in to this func. * set its retry flag, which we check with BIO_should_retry in * mongoc-stream-tls-openssl.c */ TRACE ("%s", "Requesting a retry"); BIO_set_retry_write (openssl->bio); } BSON_ASSERT (mcommon_in_range_signed (int, ret)); RETURN ((int) ret); } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_bio_ctrl -- * * Handle ctrl callback for BIO. * * Returns: * ioctl dependent. * * Side effects: * ioctl dependent. * *-------------------------------------------------------------------------- */ long mongoc_stream_tls_openssl_bio_ctrl (BIO *b, int cmd, long num, void *ptr) { BSON_UNUSED (b); BSON_UNUSED (num); BSON_UNUSED (ptr); switch (cmd) { case BIO_CTRL_FLUSH: return 1; default: return 0; } } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_bio_gets -- * * BIO callback for gets(). Not supported. * * Returns: * -1 always. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_stream_tls_openssl_bio_gets (BIO *b, char *buf, int len) { BSON_UNUSED (b); BSON_UNUSED (buf); BSON_UNUSED (len); return -1; } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_bio_puts -- * * BIO callback to perform puts(). Just calls the actual write * callback. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int mongoc_stream_tls_openssl_bio_puts (BIO *b, const char *str) { return mongoc_stream_tls_openssl_bio_write (b, str, (int) strlen (str)); } #endif /* MONGOC_ENABLE_SSL_OPENSSL */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-openssl-private.h0000644000175100001660000000374314760300420026372 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_OPENSSL_PRIVATE_H #define MONGOC_STREAM_TLS_OPENSSL_PRIVATE_H #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #include #include BSON_BEGIN_DECLS typedef struct { char *host; bool allow_invalid_hostname; bool weak_cert_validation; bool disable_endpoint_check; /* If reaching out to an OCSP responder requires TLS, * use the same TLS options that the user provided. */ mongoc_ssl_opt_t ssl_opts; } mongoc_openssl_ocsp_opt_t; void mongoc_openssl_ocsp_opt_destroy (void *ocsp_opt); /** * mongoc_stream_tls_openssl_t: * * Private storage for handling callbacks from mongoc_stream and BIO_* */ typedef struct { BIO *bio; BIO_METHOD *meth; SSL_CTX *ctx; mongoc_openssl_ocsp_opt_t *ocsp_opts; } mongoc_stream_tls_openssl_t; #if OPENSSL_VERSION_NUMBER >= 0x10100000L MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_tls_openssl_new_with_context (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client, SSL_CTX *ssl_ctx) BSON_GNUC_WARN_UNUSED_RESULT; #endif BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_OPENSSL */ #endif /* MONGOC_STREAM_TLS_OPENSSL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-openssl.c0000644000175100001660000006223414760300420024715 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-tls-openssl" #define MONGOC_STREAM_TLS_OPENSSL_BUFFER_SIZE 4096 #if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) static void BIO_meth_free (BIO_METHOD *meth) { /* Nothing to free pre OpenSSL 1.1.0 */ } #endif /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_openssl_destroy -- * * Cleanup after usage of a mongoc_stream_tls_openssl_t. Free all *allocated * resources and ensure connections are closed. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _mongoc_stream_tls_openssl_destroy (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_openssl_t *openssl = (mongoc_stream_tls_openssl_t *) tls->ctx; BSON_ASSERT (tls); BIO_free_all (openssl->bio); openssl->bio = NULL; BIO_meth_free (openssl->meth); openssl->meth = NULL; mongoc_stream_destroy (tls->base_stream); tls->base_stream = NULL; SSL_CTX_free (openssl->ctx); openssl->ctx = NULL; mongoc_openssl_ocsp_opt_destroy (openssl->ocsp_opts); openssl->ocsp_opts = NULL; bson_free (openssl); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_openssl_failed -- * * Called on stream failure. Same as _mongoc_stream_tls_openssl_destroy() * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _mongoc_stream_tls_openssl_failed (mongoc_stream_t *stream) { _mongoc_stream_tls_openssl_destroy (stream); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_openssl_close -- * * Close the underlying socket. * * Linus dictates that you should not check the result of close() * since there is a race condition with EAGAIN and a new file * descriptor being opened. * * Returns: * 0 on success; otherwise -1. * * Side effects: * The BIO fd is closed. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_openssl_close (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; int ret = 0; ENTRY; BSON_ASSERT (tls); ret = mongoc_stream_close (tls->base_stream); RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_openssl_flush -- * * Flush the underlying stream. * * Returns: * 0 if successful; otherwise -1. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_openssl_flush (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_openssl_t *openssl = (mongoc_stream_tls_openssl_t *) tls->ctx; BSON_ASSERT (openssl); return BIO_flush (openssl->bio); } static ssize_t _mongoc_stream_tls_openssl_write (mongoc_stream_tls_t *tls, char *buf, size_t buf_len) { mongoc_stream_tls_openssl_t *openssl = (mongoc_stream_tls_openssl_t *) tls->ctx; ssize_t ret; int64_t now; int64_t expire = 0; ENTRY; BSON_ASSERT (tls); BSON_ASSERT (buf); BSON_ASSERT (buf_len); if (tls->timeout_msec >= 0) { expire = bson_get_monotonic_time () + (tls->timeout_msec * 1000); } BSON_ASSERT (mcommon_in_range_unsigned (int, buf_len)); ret = BIO_write (openssl->bio, buf, (int) buf_len); if (ret <= 0) { return ret; } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (mcommon_cmp_less_su (ret, buf_len)) { mongoc_counter_streams_timeout_inc (); } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000; } } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_openssl_writev -- * * Write the iovec to the stream. This function will try to write * all of the bytes or fail. If the number of bytes is not equal * to the number requested, a failure or EOF has occurred. * * Returns: * -1 on failure, otherwise the number of bytes written. * * Side effects: * None. * * This function is copied as _mongoc_stream_tls_secure_transport_writev *-------------------------------------------------------------------------- */ static ssize_t _mongoc_stream_tls_openssl_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; char buf[MONGOC_STREAM_TLS_OPENSSL_BUFFER_SIZE]; ssize_t ret = 0; ssize_t child_ret; size_t i; size_t iov_pos = 0; /* There's a bit of a dance to coalesce vectorized writes into * MONGOC_STREAM_TLS_OPENSSL_BUFFER_SIZE'd writes to avoid lots of small tls * packets. * * The basic idea is that we want to combine writes in the buffer if they're * smaller than the buffer, flushing as it gets full. For larger writes, or * the last write in the iovec array, we want to ignore the buffer and just * write immediately. We take care of doing buffer writes by re-invoking * ourself with a single iovec_t, pointing at our stack buffer. */ char *buf_head = buf; char *buf_tail = buf; char *buf_end = buf + MONGOC_STREAM_TLS_OPENSSL_BUFFER_SIZE; size_t bytes; char *to_write = NULL; size_t to_write_len = 0u; BSON_ASSERT (tls); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); ENTRY; tls->timeout_msec = timeout_msec; for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { BSON_ASSERT (buf_end >= buf_tail); const size_t buf_remaining = (size_t) (buf_end - buf_tail); if (buf_head != buf_tail || ((i + 1 < iovcnt) && (buf_remaining > (iov[i].iov_len - iov_pos)))) { /* If we have either of: * - buffered bytes already * - another iovec to send after this one and we don't have more * bytes to send than the size of the buffer. * * copy into the buffer */ bytes = BSON_MIN (iov[i].iov_len - iov_pos, buf_remaining); memcpy (buf_tail, (char *) iov[i].iov_base + iov_pos, bytes); buf_tail += bytes; iov_pos += bytes; if (buf_tail == buf_end) { /* If we're full, request send */ to_write = buf_head; to_write_len = (size_t) (buf_tail - buf_head); buf_tail = buf_head = buf; } } else { /* Didn't buffer, so just write it through */ to_write = (char *) iov[i].iov_base + iov_pos; to_write_len = iov[i].iov_len - iov_pos; iov_pos += to_write_len; } if (to_write) { /* We get here if we buffered some bytes and filled the buffer, or * if we didn't buffer and have to send out of the iovec */ child_ret = _mongoc_stream_tls_openssl_write (tls, to_write, to_write_len); if (mcommon_cmp_not_equal_su (child_ret, to_write_len)) { TRACE ("Got child_ret: %zd while to_write_len is: %zu", child_ret, to_write_len); } if (child_ret < 0) { TRACE ("Returning what I had (%zd) as apposed to the error " "(%zd, errno:%d)", ret, child_ret, errno); RETURN (ret); } ret += child_ret; if (mcommon_cmp_less_su (child_ret, to_write_len)) { /* we timed out, so send back what we could send */ RETURN (ret); } to_write = NULL; } } } if (buf_head != buf_tail) { /* If we have any bytes buffered, send */ child_ret = _mongoc_stream_tls_openssl_write (tls, buf_head, buf_tail - buf_head); if (child_ret < 0) { RETURN (child_ret); } ret += child_ret; } if (ret >= 0) { mongoc_counter_streams_egress_add (ret); } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_openssl_readv -- * * Read from the stream into iov. This function will try to read * all of the bytes or fail. If the number of bytes is not equal * to the number requested, a failure or EOF has occurred. * * Returns: * -1 on failure, 0 on EOF, otherwise the number of bytes read. * * Side effects: * iov buffers will be written to. * * This function is copied as _mongoc_stream_tls_secure_transport_readv * *-------------------------------------------------------------------------- */ static ssize_t _mongoc_stream_tls_openssl_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_openssl_t *openssl = (mongoc_stream_tls_openssl_t *) tls->ctx; ssize_t ret = 0; size_t i; int read_ret; size_t iov_pos = 0; int64_t now; int64_t expire = 0; ENTRY; BSON_ASSERT (tls); BSON_ASSERT (iov); BSON_ASSERT (iovcnt); tls->timeout_msec = timeout_msec; if (timeout_msec >= 0) { expire = bson_get_monotonic_time () + (timeout_msec * 1000UL); } for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { read_ret = BIO_read (openssl->bio, (char *) iov[i].iov_base + iov_pos, (int) (iov[i].iov_len - iov_pos)); /* https://www.openssl.org/docs/crypto/BIO_should_retry.html: * * If BIO_should_retry() returns false then the precise "error * condition" depends on the BIO type that caused it and the return * code of the BIO operation. For example if a call to BIO_read() on a * socket BIO returns 0 and BIO_should_retry() is false then the cause * will be that the connection closed. */ if (read_ret < 0 || (read_ret == 0 && !BIO_should_retry (openssl->bio))) { return -1; } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (read_ret == 0) { mongoc_counter_streams_timeout_inc (); #ifdef _WIN32 errno = WSAETIMEDOUT; #else errno = ETIMEDOUT; #endif RETURN (-1); } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000L; } } ret += read_ret; if ((size_t) ret >= min_bytes) { mongoc_counter_streams_ingress_add (ret); RETURN (ret); } iov_pos += read_ret; } } if (ret >= 0) { mongoc_counter_streams_ingress_add (ret); } RETURN (ret); } /* *-------------------------------------------------------------------------- * * _mongoc_stream_tls_openssl_setsockopt -- * * Perform a setsockopt on the underlying stream. * * Returns: * -1 on failure, otherwise opt specific value. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static int _mongoc_stream_tls_openssl_setsockopt ( mongoc_stream_t *stream, int level, int optname, void *optval, mongoc_socklen_t optlen) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; BSON_ASSERT (tls); return mongoc_stream_setsockopt (tls->base_stream, level, optname, optval, optlen); } static mongoc_stream_t * _mongoc_stream_tls_openssl_get_base_stream (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; return tls->base_stream; } static bool _mongoc_stream_tls_openssl_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; BSON_ASSERT (stream); return mongoc_stream_check_closed (tls->base_stream); } static bool _mongoc_stream_tls_openssl_set_verify_cert_error (SSL *ssl, bson_error_t *error) { long verify_result; BSON_ASSERT_PARAM (ssl); BSON_ASSERT_PARAM (error); verify_result = SSL_get_verify_result (ssl); if (verify_result == X509_V_OK) { return false; } bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed: certificate verify failed (%ld): %s", verify_result, X509_verify_cert_error_string (verify_result)); return true; } /** * mongoc_stream_tls_openssl_handshake: */ static bool _mongoc_stream_tls_openssl_handshake (mongoc_stream_t *stream, const char *host, int *events, bson_error_t *error) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_openssl_t *openssl = (mongoc_stream_tls_openssl_t *) tls->ctx; SSL *ssl; BSON_ASSERT (tls); BSON_ASSERT (host); ENTRY; BIO_get_ssl (openssl->bio, &ssl); if (BIO_do_handshake (openssl->bio) == 1) { *events = 0; #ifdef MONGOC_ENABLE_OCSP_OPENSSL /* Validate OCSP */ if (openssl->ocsp_opts && 1 != _mongoc_ocsp_tlsext_status (ssl, openssl->ocsp_opts)) { bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed: Failed OCSP verification"); RETURN (false); } #endif if (_mongoc_openssl_check_peer_hostname (ssl, host, tls->ssl_opts.allow_invalid_hostname)) { RETURN (true); } /* Try to relay certificate failure reason from OpenSSL library if any. */ if (_mongoc_stream_tls_openssl_set_verify_cert_error (ssl, error)) { RETURN (false); } /* Otherwise, use simple error message. */ bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed: Failed certificate verification"); RETURN (false); } if (BIO_should_retry (openssl->bio)) { *events = BIO_should_read (openssl->bio) ? POLLIN : POLLOUT; RETURN (false); } if (!errno) { #ifdef _WIN32 errno = WSAETIMEDOUT; #else errno = ETIMEDOUT; #endif } *events = 0; /* Try to relay certificate failure reason from OpenSSL library if any. */ if (_mongoc_stream_tls_openssl_set_verify_cert_error (ssl, error)) { RETURN (false); } /* Otherwise, try to relay error info from OpenSSL. */ if (ERR_peek_error () != 0) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed: %s", ERR_error_string (ERR_get_error (), NULL)); RETURN (false); } /* Otherwise, use simple error info. */ { #ifdef _WIN32 LPTSTR msg = NULL; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, errno, /* WSAETIMEDOUT */ LANG_NEUTRAL, (LPTSTR) &msg, 0, NULL); #else const char *msg = strerror (errno); /* ETIMEDOUT */ #endif bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed: %s", msg); #ifdef _WIN32 LocalFree (msg); #endif } RETURN (false); } /* Callback to get the client provided SNI, if any * It is only called in SSL "server mode" (e.g. when using the Mock Server), * and we don't actually use the hostname for anything, just debug print it */ static int _mongoc_stream_tls_openssl_sni (SSL *ssl, int *ad, void *arg) { const char *hostname; BSON_UNUSED (ad); BSON_UNUSED (arg); if (ssl == NULL) { TRACE ("%s", "No SNI hostname provided"); return SSL_TLSEXT_ERR_NOACK; } hostname = SSL_get_servername (ssl, TLSEXT_NAMETYPE_host_name); /* This is intentionally debug since its only used by the mock test server */ MONGOC_DEBUG ("Got SNI: '%s'", hostname); return SSL_TLSEXT_ERR_OK; } static bool _mongoc_stream_tls_openssl_timed_out (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; ENTRY; RETURN (mongoc_stream_timed_out (tls->base_stream)); } static bool _mongoc_stream_tls_openssl_should_retry (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_openssl_t *openssl = (mongoc_stream_tls_openssl_t *) tls->ctx; ENTRY; if (BIO_should_retry (openssl->bio)) { RETURN (true); } RETURN (mongoc_stream_should_retry (tls->base_stream)); } /* Creates a new mongoc_stream_tls_openssl_t with ssl_ctx. */ static mongoc_stream_t * create_stream_with_ctx ( mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client, SSL_CTX *ssl_ctx) { mongoc_stream_tls_t *tls; mongoc_stream_tls_openssl_t *openssl; mongoc_openssl_ocsp_opt_t *ocsp_opts = NULL; BIO *bio_ssl = NULL; BIO *bio_mongoc_shim = NULL; BIO_METHOD *meth; SSL *ssl; BSON_ASSERT (base_stream); BSON_ASSERT (opt); ENTRY; if (!ssl_ctx) { RETURN (NULL); } bio_ssl = BIO_new_ssl (ssl_ctx, client); if (!bio_ssl) { SSL_CTX_free (ssl_ctx); RETURN (NULL); } BIO_get_ssl (bio_ssl, &ssl); #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) if (!opt->allow_invalid_hostname) { struct in_addr addr; struct in6_addr addr6; X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new (); X509_VERIFY_PARAM_set_hostflags (param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); if (inet_pton (AF_INET, host, &addr) || inet_pton (AF_INET6, host, &addr6)) { X509_VERIFY_PARAM_set1_ip_asc (param, host); } else { X509_VERIFY_PARAM_set1_host (param, host, 0); } SSL_set1_param (ssl, param); X509_VERIFY_PARAM_free (param); } #endif meth = mongoc_stream_tls_openssl_bio_meth_new (); bio_mongoc_shim = BIO_new (meth); if (!bio_mongoc_shim) { BIO_free_all (bio_ssl); BIO_meth_free (meth); SSL_CTX_free (ssl_ctx); RETURN (NULL); } /* Added in OpenSSL 0.9.8f, as a build time option */ #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (client) { /* Set the SNI hostname we are expecting certificate for */ SSL_set_tlsext_host_name (ssl, host); #endif } BIO_push (bio_ssl, bio_mongoc_shim); #ifdef MONGOC_ENABLE_OCSP_OPENSSL if (client && !opt->weak_cert_validation && !_mongoc_ssl_opts_disable_certificate_revocation_check (opt)) { /* Set the status_request extension on the SSL object. * Do not use SSL_CTX_set_tlsext_status_type, since that requires OpenSSL * 1.1.0. */ if (!SSL_set_tlsext_status_type (ssl, TLSEXT_STATUSTYPE_ocsp)) { MONGOC_ERROR ("cannot enable OCSP status request extension"); mongoc_openssl_ocsp_opt_destroy (ocsp_opts); BIO_free_all (bio_ssl); BIO_meth_free (meth); SSL_CTX_free (ssl_ctx); RETURN (NULL); } ocsp_opts = bson_malloc0 (sizeof (mongoc_openssl_ocsp_opt_t)); ocsp_opts->allow_invalid_hostname = opt->allow_invalid_hostname; ocsp_opts->weak_cert_validation = opt->weak_cert_validation; ocsp_opts->disable_endpoint_check = _mongoc_ssl_opts_disable_ocsp_endpoint_check (opt); ocsp_opts->host = bson_strdup (host); _mongoc_ssl_opts_copy_to (opt, &ocsp_opts->ssl_opts, true); } #endif /* MONGOC_ENABLE_OCSP_OPENSSL */ openssl = (mongoc_stream_tls_openssl_t *) bson_malloc0 (sizeof *openssl); openssl->bio = bio_ssl; openssl->meth = meth; openssl->ctx = ssl_ctx; openssl->ocsp_opts = ocsp_opts; tls = (mongoc_stream_tls_t *) bson_malloc0 (sizeof *tls); tls->parent.type = MONGOC_STREAM_TLS; tls->parent.destroy = _mongoc_stream_tls_openssl_destroy; tls->parent.failed = _mongoc_stream_tls_openssl_failed; tls->parent.close = _mongoc_stream_tls_openssl_close; tls->parent.flush = _mongoc_stream_tls_openssl_flush; tls->parent.writev = _mongoc_stream_tls_openssl_writev; tls->parent.readv = _mongoc_stream_tls_openssl_readv; tls->parent.setsockopt = _mongoc_stream_tls_openssl_setsockopt; tls->parent.get_base_stream = _mongoc_stream_tls_openssl_get_base_stream; tls->parent.check_closed = _mongoc_stream_tls_openssl_check_closed; tls->parent.timed_out = _mongoc_stream_tls_openssl_timed_out; tls->parent.should_retry = _mongoc_stream_tls_openssl_should_retry; memcpy (&tls->ssl_opts, opt, sizeof tls->ssl_opts); tls->handshake = _mongoc_stream_tls_openssl_handshake; tls->ctx = (void *) openssl; tls->timeout_msec = -1; tls->base_stream = base_stream; mongoc_stream_tls_openssl_bio_set_data (bio_mongoc_shim, tls); mongoc_counter_streams_active_inc (); RETURN ((mongoc_stream_t *) tls); } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_new -- * * Creates a new mongoc_stream_tls_openssl_t to communicate with a remote * server using a TLS stream. * * @base_stream should be a stream that will become owned by the * resulting tls stream. It will be used for raw I/O. * * Returns: * NULL on failure, otherwise a mongoc_stream_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) { SSL_CTX *ssl_ctx = _mongoc_openssl_ctx_new (opt); if (!ssl_ctx) { RETURN (NULL); } if (!client) { /* Only used by the Mock Server. * Set a callback to get the SNI, if provided */ SSL_CTX_set_tlsext_servername_callback (ssl_ctx, _mongoc_stream_tls_openssl_sni); } return create_stream_with_ctx (base_stream, host, opt, client, ssl_ctx); } #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_openssl_new_with_context -- * * Creates a new mongoc_stream_tls_openssl_t to communicate with a remote * server using a TLS stream, using an existing OpenSSL context. * * Only called by mongoc_stream_tls_new_with_hostname_and_openssl_context. * * @ssl_ctx is the shared OpenSSL context for the mongoc_client_t * associated with this function call. * * Returns: * NULL on failure, otherwise a mongoc_stream_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_tls_openssl_new_with_context ( mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client, SSL_CTX *ssl_ctx) { // `ssl_ctx` may be NULL if creating the context failed. Return NULL to signal failure. if (!ssl_ctx) { return NULL; } SSL_CTX_up_ref (ssl_ctx); return create_stream_with_ctx (base_stream, host, opt, client, ssl_ctx); } #endif void mongoc_openssl_ocsp_opt_destroy (void *ocsp_opt) { mongoc_openssl_ocsp_opt_t *casted; if (!ocsp_opt) { return; } casted = (mongoc_openssl_ocsp_opt_t *) ocsp_opt; bson_free (casted->host); _mongoc_ssl_opts_cleanup (&casted->ssl_opts, true); bson_free (ocsp_opt); } #endif /* MONGOC_ENABLE_SSL_OPENSSL */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-openssl.h0000644000175100001660000000211514760300420024712 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_OPENSSL_H #define MONGOC_STREAM_TLS_OPENSSL_H #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #include BSON_BEGIN_DECLS MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_tls_openssl_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_OPENSSL */ #endif /* MONGOC_STREAM_TLS_OPENSSL_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-private.h0000644000175100001660000000374514760300420024713 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_PRIVATE_H #define MONGOC_STREAM_TLS_PRIVATE_H #include #include #include #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #endif BSON_BEGIN_DECLS /** * mongoc_stream_tls_t: * * Overloaded mongoc_stream_t with additional TLS handshake and verification * callbacks. * */ struct _mongoc_stream_tls_t { mongoc_stream_t parent; /* The TLS stream wrapper */ mongoc_stream_t *base_stream; /* The underlying actual stream */ void *ctx; /* TLS lib specific configuration or wrappers */ int64_t timeout_msec; mongoc_ssl_opt_t ssl_opts; bool (*handshake) (mongoc_stream_t *stream, const char *host, int *events /* OUT*/, bson_error_t *error); }; #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_tls_new_with_hostname_and_openssl_context (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client, SSL_CTX *ssl_ctx) BSON_GNUC_WARN_UNUSED_RESULT; #endif BSON_END_DECLS #endif /* MONGOC_STREAM_TLS_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-secure-channel-private.h0000644000175100001660000000437714760300420027607 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_SECURE_CHANNEL_PRIVATE_H #define MONGOC_STREAM_TLS_SECURE_CHANNEL_PRIVATE_H #ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL #include /* Its mandatory to indicate to Windows who is compiling the code */ #define SECURITY_WIN32 #include BSON_BEGIN_DECLS /* enum for the nonblocking SSL connection state machine */ typedef enum { ssl_connect_1, ssl_connect_2, ssl_connect_2_reading, ssl_connect_2_writing, ssl_connect_3, ssl_connect_done } ssl_connect_state; /* Structs to store Schannel handles */ typedef struct { CredHandle cred_handle; TimeStamp time_stamp; } mongoc_secure_channel_cred; typedef struct { CtxtHandle ctxt_handle; TimeStamp time_stamp; } mongoc_secure_channel_ctxt; /** * mongoc_stream_tls_secure_channel_t: * * Private storage for Secure Channel Streams */ typedef struct { ssl_connect_state connecting_state; mongoc_secure_channel_cred *cred; mongoc_secure_channel_ctxt *ctxt; SecPkgContext_StreamSizes stream_sizes; size_t encdata_length, decdata_length; size_t encdata_offset, decdata_offset; unsigned char *encdata_buffer, *decdata_buffer; unsigned long req_flags, ret_flags; int recv_unrecoverable_err; /* _mongoc_stream_tls_secure_channel_read had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ } mongoc_stream_tls_secure_channel_t; BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_SECURE_CHANNEL */ #endif /* MONGOC_STREAM_TLS_SECURE_CHANNEL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-secure-channel.c0000644000175100001660000010427114760300420026124 0ustar /* * Copyright 2009-present MongoDB, 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. */ /** * Significant portion of this file, such as * _mongoc_stream_tls_secure_channel_write & *_mongoc_stream_tls_secure_channel_read * comes straight from one of my favorite projects, cURL! * Thank you so much for having gone through the Secure Channel pain for me. * * * Copyright (C) 2012 - 2015, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* * Based upon the PolarSSL implementation in polarssl.c and polarssl.h: * Copyright (C) 2010, 2011, Hoi-Ho Chan, * * Based upon the CyaSSL implementation in cyassl.c and cyassl.h: * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * Thanks for code and inspiration! */ #include #ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-tls-secure-channel" #define SECURITY_WIN32 #include #include #include /* mingw doesn't define these */ #ifndef SP_PROT_TLS1_1_CLIENT #define SP_PROT_TLS1_1_CLIENT 0x00000200 #endif #ifndef SP_PROT_TLS1_2_CLIENT #define SP_PROT_TLS1_2_CLIENT 0x00000800 #endif static void _mongoc_stream_tls_secure_channel_destroy (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_channel); /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx * Shutting Down an Schannel Connection */ TRACE ("%s", "shutting down SSL/TLS connection"); if (secure_channel->cred && secure_channel->ctxt) { SecBufferDesc BuffDesc; SecBuffer Buffer; SECURITY_STATUS sspi_status; SecBuffer outbuf; SecBufferDesc outbuf_desc; DWORD dwshut = SCHANNEL_SHUTDOWN; _mongoc_secure_channel_init_sec_buffer (&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof (dwshut)); _mongoc_secure_channel_init_sec_buffer_desc (&BuffDesc, &Buffer, 1); sspi_status = ApplyControlToken (&secure_channel->ctxt->ctxt_handle, &BuffDesc); if (sspi_status != SEC_E_OK) { MONGOC_ERROR ("ApplyControlToken failure: %ld", sspi_status); } /* setup output buffer */ _mongoc_secure_channel_init_sec_buffer (&outbuf, SECBUFFER_EMPTY, NULL, 0); _mongoc_secure_channel_init_sec_buffer_desc (&outbuf_desc, &outbuf, 1); sspi_status = InitializeSecurityContext (&secure_channel->cred->cred_handle, &secure_channel->ctxt->ctxt_handle, /*tls->hostname*/ NULL, secure_channel->req_flags, 0, 0, NULL, 0, &secure_channel->ctxt->ctxt_handle, &outbuf_desc, &secure_channel->ret_flags, &secure_channel->ctxt->time_stamp); if ((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { /* send close message which is in output buffer */ ssize_t written = mongoc_secure_channel_write (tls, outbuf.pvBuffer, outbuf.cbBuffer); FreeContextBuffer (outbuf.pvBuffer); if (outbuf.cbBuffer != (size_t) written) { TRACE ("failed to send close msg (wrote %zd out of %lu)", written, outbuf.cbBuffer); } } } /* free SSPI Schannel API security context handle */ if (secure_channel->ctxt) { TRACE ("%s", "clear security context handle"); DeleteSecurityContext (&secure_channel->ctxt->ctxt_handle); bson_free (secure_channel->ctxt); } /* free SSPI Schannel API credential handle */ if (secure_channel->cred) { /* decrement the reference counter of the credential/session handle */ /* if the handle was not cached and the refcount is zero */ TRACE ("%s", "clear credential handle"); FreeCredentialsHandle (&secure_channel->cred->cred_handle); bson_free (secure_channel->cred); } /* free internal buffer for received encrypted data */ if (secure_channel->encdata_buffer != NULL) { bson_free (secure_channel->encdata_buffer); secure_channel->encdata_length = 0; secure_channel->encdata_offset = 0; } /* free internal buffer for received decrypted data */ if (secure_channel->decdata_buffer != NULL) { bson_free (secure_channel->decdata_buffer); secure_channel->decdata_length = 0; secure_channel->decdata_offset = 0; } mongoc_stream_destroy (tls->base_stream); bson_free (secure_channel); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_stream_tls_secure_channel_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_tls_secure_channel_destroy (stream); EXIT; } static int _mongoc_stream_tls_secure_channel_close (mongoc_stream_t *stream) { int ret = 0; mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_channel); ret = mongoc_stream_close (tls->base_stream); RETURN (ret); } static int _mongoc_stream_tls_secure_channel_flush (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_channel); RETURN (0); } static ssize_t _mongoc_stream_tls_secure_channel_write (mongoc_stream_t *stream, char *buf, size_t buf_len) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ssize_t written = -1; size_t data_len = 0; unsigned char *data = NULL; SecBuffer outbuf[4]; SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; ENTRY; BSON_ASSERT (secure_channel); TRACE ("The entire buffer is: %zu", buf_len); /* check if the maximum stream sizes were queried */ if (secure_channel->stream_sizes.cbMaximumMessage == 0) { sspi_status = QueryContextAttributes ( &secure_channel->ctxt->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &secure_channel->stream_sizes); if (sspi_status != SEC_E_OK) { TRACE ("failing here: %d", (int) (__LINE__)); return -1; } } /* check if the buffer is longer than the maximum message length */ if (buf_len > secure_channel->stream_sizes.cbMaximumMessage) { TRACE ("SHRINKING buf_len from %zu to %lu", buf_len, secure_channel->stream_sizes.cbMaximumMessage); buf_len = secure_channel->stream_sizes.cbMaximumMessage; } /* calculate the complete message length and allocate a buffer for it */ data_len = secure_channel->stream_sizes.cbHeader + buf_len + secure_channel->stream_sizes.cbTrailer; data = (unsigned char *) bson_malloc (data_len); /* setup output buffers (header, data, trailer, empty) */ _mongoc_secure_channel_init_sec_buffer ( &outbuf[0], SECBUFFER_STREAM_HEADER, data, secure_channel->stream_sizes.cbHeader); _mongoc_secure_channel_init_sec_buffer (&outbuf[1], SECBUFFER_DATA, data + secure_channel->stream_sizes.cbHeader, (unsigned long) (buf_len & (size_t) 0xFFFFFFFFUL)); _mongoc_secure_channel_init_sec_buffer (&outbuf[2], SECBUFFER_STREAM_TRAILER, data + secure_channel->stream_sizes.cbHeader + buf_len, secure_channel->stream_sizes.cbTrailer); _mongoc_secure_channel_init_sec_buffer (&outbuf[3], SECBUFFER_EMPTY, NULL, 0); _mongoc_secure_channel_init_sec_buffer_desc (&outbuf_desc, outbuf, 4); /* copy data into output buffer */ memcpy (outbuf[1].pvBuffer, buf, buf_len); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ sspi_status = EncryptMessage (&secure_channel->ctxt->ctxt_handle, 0, &outbuf_desc, 0); /* check if the message was encrypted */ if (sspi_status == SEC_E_OK) { written = 0; /* send the encrypted message including header, data and trailer */ buf_len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; written = mongoc_secure_channel_write (tls, data, buf_len); } else { written = -1; } bson_free (data); if (buf_len == (size_t) written) { /* Encrypted message including header, data and trailer entirely sent. * The return value is the number of unencrypted bytes that were sent. */ written = outbuf[1].cbBuffer; } return written; } /* This is copypasta from _mongoc_stream_tls_openssl_writev */ #define MONGOC_STREAM_TLS_BUFFER_SIZE 4096 static ssize_t _mongoc_stream_tls_secure_channel_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; char buf[MONGOC_STREAM_TLS_BUFFER_SIZE]; ssize_t ret = 0; ssize_t child_ret; size_t i; size_t iov_pos = 0; /* There's a bit of a dance to coalesce vectorized writes into * MONGOC_STREAM_TLS_BUFFER_SIZE'd writes to avoid lots of small tls * packets. * * The basic idea is that we want to combine writes in the buffer if they're * smaller than the buffer, flushing as it gets full. For larger writes, or * the last write in the iovec array, we want to ignore the buffer and just * write immediately. We take care of doing buffer writes by re-invoking * ourself with a single iovec_t, pointing at our stack buffer. */ char *buf_head = buf; char *buf_tail = buf; char *buf_end = buf + MONGOC_STREAM_TLS_BUFFER_SIZE; size_t bytes; char *to_write = NULL; size_t to_write_len; BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (secure_channel); ENTRY; TRACE ("%s", "Trying to write to the server"); tls->timeout_msec = timeout_msec; TRACE ("count: %zu, 0th: %zu", iovcnt, iov[0].iov_len); for (i = 0; i < iovcnt; i++) { iov_pos = 0; TRACE ("iov %zu size: %zu", i, iov[i].iov_len); while (iov_pos < iov[i].iov_len) { BSON_ASSERT (buf_end >= buf_tail); const size_t buf_remaining = (size_t) (buf_end - buf_tail); if (buf_head != buf_tail || ((i + 1u < iovcnt) && (buf_remaining > (iov[i].iov_len - iov_pos)))) { /* If we have either of: * - buffered bytes already * - another iovec to send after this one and we don't have more * bytes to send than the size of the buffer. * * copy into the buffer */ bytes = BSON_MIN (iov[i].iov_len - iov_pos, buf_remaining); memcpy (buf_tail, (char *) iov[i].iov_base + iov_pos, bytes); buf_tail += bytes; iov_pos += bytes; if (buf_tail == buf_end) { /* If we're full, request send */ to_write = buf_head; to_write_len = buf_tail - buf_head; buf_tail = buf_head = buf; } } else { /* Didn't buffer, so just write it through */ to_write = (char *) iov[i].iov_base + iov_pos; to_write_len = iov[i].iov_len - iov_pos; iov_pos += to_write_len; } if (to_write) { /* We get here if we buffered some bytes and filled the buffer, or * if we didn't buffer and have to send out of the iovec */ child_ret = _mongoc_stream_tls_secure_channel_write (stream, to_write, to_write_len); TRACE ("Child0wrote: %zd, was supposed to write: %zu", child_ret, to_write_len); if (child_ret < 0) { RETURN (ret); } ret += child_ret; iov_pos -= to_write_len - child_ret; to_write = NULL; } } } if (buf_head != buf_tail) { /* If we have any bytes buffered, send */ child_ret = _mongoc_stream_tls_secure_channel_write (stream, buf_head, buf_tail - buf_head); TRACE ("Child1wrote: %zd, was supposed to write: %td", child_ret, buf_tail - buf_head); if (child_ret < 0) { RETURN (child_ret); } ret += child_ret; } if (ret >= 0) { mongoc_counter_streams_egress_add (ret); } TRACE ("Returning %d", (int) ret); RETURN (ret); } /* move up to "len" decrypted bytes to buf, return number of bytes */ static ssize_t _mongoc_stream_tls_secure_channel_debuf (mongoc_stream_tls_secure_channel_t *secure_channel, char *buf, size_t size) { size_t s = BSON_MIN (size, secure_channel->decdata_offset); memcpy (buf, secure_channel->decdata_buffer, s); memmove (secure_channel->decdata_buffer, secure_channel->decdata_buffer + s, secure_channel->decdata_offset - s); secure_channel->decdata_offset -= s; TRACE ("decrypted data returned %d", (int) s); TRACE ("decrypted data buffer: offset %d length %d", (int) secure_channel->decdata_offset, (int) secure_channel->decdata_length); return (ssize_t) s; } /* decrypt as many received bytes as possible to secure_channel.decdata_buf */ static void _mongoc_stream_tls_secure_channel_decrypt (mongoc_stream_tls_secure_channel_t *secure_channel) { size_t size = 0; size_t remaining; SecBuffer inbuf[4]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; TRACE ("encrypted data buffer: offset %d length %d", (int) secure_channel->encdata_offset, (int) secure_channel->encdata_length); /* decrypt loop */ while (secure_channel->encdata_offset > 0 && sspi_status == SEC_E_OK) { /* prepare data buffer for DecryptMessage call */ _mongoc_secure_channel_init_sec_buffer (&inbuf[0], SECBUFFER_DATA, secure_channel->encdata_buffer, (unsigned long) (secure_channel->encdata_offset & (size_t) 0xFFFFFFFFUL)); /* we need 3 more empty input buffers for possible output */ _mongoc_secure_channel_init_sec_buffer (&inbuf[1], SECBUFFER_EMPTY, NULL, 0); _mongoc_secure_channel_init_sec_buffer (&inbuf[2], SECBUFFER_EMPTY, NULL, 0); _mongoc_secure_channel_init_sec_buffer (&inbuf[3], SECBUFFER_EMPTY, NULL, 0); _mongoc_secure_channel_init_sec_buffer_desc (&inbuf_desc, inbuf, 4); /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */ sspi_status = DecryptMessage (&secure_channel->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); /* check if everything went fine (server may want to renegotiate * or shutdown the connection context) */ if (sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE || sspi_status == SEC_I_CONTEXT_EXPIRED) { /* check for successfully decrypted data, even before actual * renegotiation or shutdown of the connection context */ if (inbuf[1].BufferType == SECBUFFER_DATA) { TRACE ("decrypted data length: %lu", inbuf[1].cbBuffer); size = inbuf[1].cbBuffer; remaining = secure_channel->decdata_length - secure_channel->decdata_offset; if (remaining < size) { mongoc_secure_channel_realloc_buf ( &secure_channel->decdata_length, &secure_channel->decdata_buffer, size); } /* copy decrypted data to internal buffer */ if (size) { memcpy (secure_channel->decdata_buffer + secure_channel->decdata_offset, inbuf[1].pvBuffer, size); secure_channel->decdata_offset += size; } TRACE ("decrypted data added: %d", (int) size); TRACE ("decrypted data cached: offset %d length %d", (int) secure_channel->decdata_offset, (int) secure_channel->decdata_length); } /* check for remaining encrypted data */ if (inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) { TRACE ("encrypted data length: %lu", inbuf[3].cbBuffer); /* check if the remaining data is less than the total amount * and therefore begins after the already processed data */ if (secure_channel->encdata_offset > inbuf[3].cbBuffer) { /* move remaining encrypted data forward to the beginning of * buffer */ memmove (secure_channel->encdata_buffer, (secure_channel->encdata_buffer + secure_channel->encdata_offset) - inbuf[3].cbBuffer, inbuf[3].cbBuffer); secure_channel->encdata_offset = inbuf[3].cbBuffer; } TRACE ("encrypted data cached: offset %d length %d", (int) secure_channel->encdata_offset, (int) secure_channel->encdata_length); } else { /* reset encrypted buffer offset, because there is no data remaining */ secure_channel->encdata_offset = 0; } /* check if server wants to renegotiate the connection context */ if (sspi_status == SEC_I_RENEGOTIATE) { TRACE ("%s", "remote party requests renegotiation"); } /* check if the server closed the connection */ else if (sspi_status == SEC_I_CONTEXT_EXPIRED) { /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not * returned so we have to work around that in cleanup. */ secure_channel->recv_sspi_close_notify = true; if (!secure_channel->recv_connection_closed) { secure_channel->recv_connection_closed = true; TRACE ("%s", "server closed the connection"); } } } else if (sspi_status == SEC_E_INCOMPLETE_MESSAGE) { TRACE ("%s", "failed to decrypt data, need more data"); } else { TRACE ("failed to read data from server: %ld", sspi_status); secure_channel->recv_unrecoverable_err = true; } } TRACE ("encrypted data buffer: offset %d length %d", (int) secure_channel->encdata_offset, (int) secure_channel->encdata_length); TRACE ("decrypted data buffer: offset %d length %d", (int) secure_channel->decdata_offset, (int) secure_channel->decdata_length); } static ssize_t _mongoc_stream_tls_secure_channel_read (mongoc_stream_t *stream, char *buf, size_t len) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ssize_t size = 0; ssize_t nread; TRACE ("client wants to read %d bytes", (int) len); BSON_ASSERT (len > 0); /* * Our priority is to always return as much decrypted data to the caller as * possible, even if an error occurs. The state of the decrypted buffer must * always be valid. */ if (secure_channel->decdata_offset) { TRACE ("%s", "decrypted data is already available"); return _mongoc_stream_tls_secure_channel_debuf (secure_channel, buf, len); } /* is a complete encrypted block left from last network read? */ if (secure_channel->encdata_offset) { _mongoc_stream_tls_secure_channel_decrypt (secure_channel); if (secure_channel->decdata_offset) { return _mongoc_stream_tls_secure_channel_debuf (secure_channel, buf, len); } } /* keep these checks separated, for more detailed tracing */ if (secure_channel->recv_unrecoverable_err) { TRACE ("%s", "an unrecoverable error occurred in a prior call"); return -1; } if (secure_channel->recv_sspi_close_notify) { TRACE ("%s", "server indicated shutdown in a prior call"); return -1; } if (secure_channel->recv_connection_closed) { TRACE ("%s", "connection closed"); return -1; } size = secure_channel->encdata_length - secure_channel->encdata_offset; /* read encrypted data from socket. returns 0 on shutdown or error */ nread = mongoc_secure_channel_read ( tls, (char *) (secure_channel->encdata_buffer + secure_channel->encdata_offset), (size_t) size); if (!nread) { if (MONGOC_ERRNO_IS_AGAIN (errno)) { TRACE ("%s", "Try again"); return 0; } else { secure_channel->recv_connection_closed = true; TRACE ("reading failed: %d", errno); return -1; } } secure_channel->encdata_offset += (size_t) nread; TRACE ("encrypted data got %zd", nread); _mongoc_stream_tls_secure_channel_decrypt (secure_channel); return _mongoc_stream_tls_secure_channel_debuf (secure_channel, buf, len); } /* This function is copypasta of _mongoc_stream_tls_openssl_readv */ static ssize_t _mongoc_stream_tls_secure_channel_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ssize_t ret = 0; size_t i; size_t iov_pos = 0; int64_t now; int64_t expire = 0; BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (secure_channel); ENTRY; tls->timeout_msec = timeout_msec; if (timeout_msec >= 0) { expire = bson_get_monotonic_time () + (timeout_msec * 1000UL); } for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { ssize_t read_ret = _mongoc_stream_tls_secure_channel_read ( stream, (char *) iov[i].iov_base + iov_pos, (int) (iov[i].iov_len - iov_pos)); if (read_ret < 0) { RETURN (-1); } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (read_ret == 0) { mongoc_counter_streams_timeout_inc (); errno = ETIMEDOUT; RETURN (-1); } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000L; } } ret += read_ret; if ((size_t) ret >= min_bytes) { mongoc_counter_streams_ingress_add (ret); RETURN (ret); } iov_pos += read_ret; } } if (ret >= 0) { mongoc_counter_streams_ingress_add (ret); } RETURN (ret); } static int _mongoc_stream_tls_secure_channel_setsockopt ( mongoc_stream_t *stream, int level, int optname, void *optval, mongoc_socklen_t optlen) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_channel); RETURN (mongoc_stream_setsockopt (tls->base_stream, level, optname, optval, optlen)); } static mongoc_stream_t * _mongoc_stream_tls_secure_channel_get_base_stream (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_channel); RETURN (tls->base_stream); } static bool _mongoc_stream_tls_secure_channel_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_channel); RETURN (mongoc_stream_check_closed (tls->base_stream)); } bool mongoc_stream_tls_secure_channel_handshake (mongoc_stream_t *stream, const char *host, int *events, bson_error_t *error) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_channel_t *secure_channel = (mongoc_stream_tls_secure_channel_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_channel); if (error) { error->code = 0; } TRACE ("Getting ready for state: %d, timeout is %" PRId64, (int) secure_channel->connecting_state + 1, tls->timeout_msec); switch (secure_channel->connecting_state) { case ssl_connect_1: if (mongoc_secure_channel_handshake_step_1 (tls, (char *) host, error)) { TRACE ("%s", "Step#1 Worked!\n\n"); *events = POLLIN; RETURN (false); } else { TRACE ("%s", "Step#1 FAILED!"); } break; case ssl_connect_2: case ssl_connect_2_reading: case ssl_connect_2_writing: if (mongoc_secure_channel_handshake_step_2 (tls, (char *) host, error)) { if (secure_channel->connecting_state == ssl_connect_2_reading) { *events = POLLIN; } else { *events = POLLOUT; } RETURN (false); } else { TRACE ("%s", "Step#2 FAILED!"); } break; case ssl_connect_3: if (mongoc_secure_channel_handshake_step_3 (tls, (char *) host, error)) { TRACE ("%s", "Step#3 Worked!\n\n"); *events = POLLIN | POLLOUT; RETURN (false); } else { TRACE ("%s", "Step#3 FAILED!"); } break; case ssl_connect_done: TRACE ("%s", "Connect DONE!"); /* reset our connection state machine */ secure_channel->connecting_state = ssl_connect_1; RETURN (true); break; default: /* do nothing */ break; } *events = 0; if (error && !error->code) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed"); } RETURN (false); } static bool _mongoc_stream_tls_secure_channel_timed_out (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; ENTRY; RETURN (mongoc_stream_timed_out (tls->base_stream)); } static bool _mongoc_stream_tls_secure_channel_should_retry (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; ENTRY; RETURN (mongoc_stream_should_retry (tls->base_stream)); } mongoc_stream_t * mongoc_stream_tls_secure_channel_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) { SECURITY_STATUS sspi_status = SEC_E_OK; SCHANNEL_CRED schannel_cred; mongoc_stream_tls_t *tls; mongoc_stream_tls_secure_channel_t *secure_channel; PCCERT_CONTEXT cert = NULL; ENTRY; BSON_ASSERT (base_stream); BSON_ASSERT (opt); secure_channel = (mongoc_stream_tls_secure_channel_t *) bson_malloc0 (sizeof *secure_channel); secure_channel->decdata_buffer = bson_malloc (MONGOC_SCHANNEL_BUFFER_INIT_SIZE); secure_channel->decdata_length = MONGOC_SCHANNEL_BUFFER_INIT_SIZE; secure_channel->encdata_buffer = bson_malloc (MONGOC_SCHANNEL_BUFFER_INIT_SIZE); secure_channel->encdata_length = MONGOC_SCHANNEL_BUFFER_INIT_SIZE; tls = (mongoc_stream_tls_t *) bson_malloc0 (sizeof *tls); tls->parent.type = MONGOC_STREAM_TLS; tls->parent.destroy = _mongoc_stream_tls_secure_channel_destroy; tls->parent.failed = _mongoc_stream_tls_secure_channel_failed; tls->parent.close = _mongoc_stream_tls_secure_channel_close; tls->parent.flush = _mongoc_stream_tls_secure_channel_flush; tls->parent.writev = _mongoc_stream_tls_secure_channel_writev; tls->parent.readv = _mongoc_stream_tls_secure_channel_readv; tls->parent.setsockopt = _mongoc_stream_tls_secure_channel_setsockopt; tls->parent.get_base_stream = _mongoc_stream_tls_secure_channel_get_base_stream; tls->parent.check_closed = _mongoc_stream_tls_secure_channel_check_closed; tls->parent.timed_out = _mongoc_stream_tls_secure_channel_timed_out; tls->parent.should_retry = _mongoc_stream_tls_secure_channel_should_retry; memcpy (&tls->ssl_opts, opt, sizeof tls->ssl_opts); tls->handshake = mongoc_stream_tls_secure_channel_handshake; tls->ctx = (void *) secure_channel; tls->timeout_msec = -1; tls->base_stream = base_stream; TRACE ("%s", "SSL/TLS connection with endpoint AcquireCredentialsHandle"); /* setup Schannel API options */ memset (&schannel_cred, 0, sizeof (schannel_cred)); schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; /* SCHANNEL_CRED: * SCH_USE_STRONG_CRYPTO is not available in VS2010 * https://msdn.microsoft.com/en-us/library/windows/desktop/aa379810.aspx */ #ifdef SCH_USE_STRONG_CRYPTO schannel_cred.dwFlags = SCH_USE_STRONG_CRYPTO; #endif /* By default, enable soft failing. * A certificate with no revocation check is a soft failure. */ schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK; /* An offline OCSP responder / CRL distribution list is a soft failure. */ schannel_cred.dwFlags |= SCH_CRED_IGNORE_REVOCATION_OFFLINE; if (opt->weak_cert_validation) { schannel_cred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION; TRACE ("%s", "disabled server certificate checks"); } else { schannel_cred.dwFlags |= SCH_CRED_AUTO_CRED_VALIDATION; if (!_mongoc_ssl_opts_disable_certificate_revocation_check (opt)) { schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; TRACE ("%s", "enabled server certificate revocation checks"); } TRACE ("%s", "enabled server certificate checks"); } if (opt->allow_invalid_hostname) { schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; } if (opt->ca_file) { mongoc_secure_channel_setup_ca (secure_channel, opt); } if (opt->crl_file) { mongoc_secure_channel_setup_crl (secure_channel, opt); } if (opt->pem_file) { cert = mongoc_secure_channel_setup_certificate (secure_channel, opt); if (cert) { schannel_cred.cCreds = 1; schannel_cred.paCred = &cert; } } schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT; secure_channel->cred = (mongoc_secure_channel_cred *) bson_malloc0 (sizeof (mongoc_secure_channel_cred)); /* Example: * https://msdn.microsoft.com/en-us/library/windows/desktop/aa375454%28v=vs.85%29.aspx * AcquireCredentialsHandle: * https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */ sspi_status = AcquireCredentialsHandle (NULL, /* principal */ UNISP_NAME, /* security package */ SECPKG_CRED_OUTBOUND, /* we are preparing outbound connection */ NULL, /* Optional logon */ &schannel_cred, /* TLS "configuration", "auth data" */ NULL, /* unused */ NULL, /* unused */ &secure_channel->cred->cred_handle, /* credential OUT param */ &secure_channel->cred->time_stamp); /* certificate expiration time */ if (sspi_status != SEC_E_OK) { LPTSTR msg = NULL; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError (), LANG_NEUTRAL, (LPTSTR) &msg, 0, NULL); MONGOC_ERROR ("Failed to initialize security context, error code: 0x%04X%04X: '%s'", (unsigned int) (sspi_status >> 16) & 0xffff, (unsigned int) sspi_status & 0xffff, msg); LocalFree (msg); RETURN (NULL); } if (opt->ca_dir) { MONGOC_ERROR ("Setting mongoc_ssl_opt_t.ca_dir has no effect when built " "against Secure Channel"); } if (_mongoc_ssl_opts_disable_ocsp_endpoint_check (opt)) { MONGOC_ERROR ("Setting tlsDisableOCSPEndpointCheck has no effect when " "built against Secure Channel"); } mongoc_counter_streams_active_inc (); RETURN ((mongoc_stream_t *) tls); } #endif /* MONGOC_ENABLE_SSL_SECURE_CHANNEL */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-secure-channel.h0000644000175100001660000000216714760300420026132 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_SECURE_CHANNEL_H #define MONGOC_STREAM_TLS_SECURE_CHANNEL_H #ifdef MONGOC_ENABLE_SSL_SECURE_CHANNEL #include #include BSON_BEGIN_DECLS MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_tls_secure_channel_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_SECURE_CHANNEL */ #endif /* MONGOC_STREAM_TLS_SECURE_CHANNEL_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-secure-transport-private.h0000644000175100001660000000231414760300420030220 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_SECURE_TRANSPORT_PRIVATE_H #define MONGOC_STREAM_TLS_SECURE_TRANSPORT_PRIVATE_H #ifdef MONGOC_ENABLE_SSL_SECURE_TRANSPORT #include #include BSON_BEGIN_DECLS /** * mongoc_stream_tls_secure_transport_t: * * Private storage for Secure Transport Streams */ typedef struct { SSLContextRef ssl_ctx_ref; CFArrayRef anchors; CFMutableArrayRef my_cert; } mongoc_stream_tls_secure_transport_t; BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_SECURE_TRANSPORT */ #endif /* MONGOC_STREAM_TLS_SECURE_TRANSPORT_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-secure-transport.c0000644000175100001660000005343014760300420026550 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL_SECURE_TRANSPORT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-tls-secure_transport" static void _mongoc_stream_tls_secure_transport_destroy (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_transport); SSLClose (secure_transport->ssl_ctx_ref); CFRelease (secure_transport->ssl_ctx_ref); secure_transport->ssl_ctx_ref = NULL; /* SSLClose will do IO so destroy must come after */ mongoc_stream_destroy (tls->base_stream); if (secure_transport->anchors) { CFRelease (secure_transport->anchors); } if (secure_transport->my_cert) { CFRelease (secure_transport->my_cert); } bson_free (secure_transport); bson_free (stream); mongoc_counter_streams_active_dec (); mongoc_counter_streams_disposed_inc (); EXIT; } static void _mongoc_stream_tls_secure_transport_failed (mongoc_stream_t *stream) { ENTRY; _mongoc_stream_tls_secure_transport_destroy (stream); EXIT; } static int _mongoc_stream_tls_secure_transport_close (mongoc_stream_t *stream) { int ret = 0; mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_transport); ret = mongoc_stream_close (tls->base_stream); RETURN (ret); } static int _mongoc_stream_tls_secure_transport_flush (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_transport); RETURN (0); } static ssize_t _mongoc_stream_tls_secure_transport_write (mongoc_stream_t *stream, char *buf, size_t buf_len) { OSStatus status; mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ssize_t write_ret; int64_t now; int64_t expire = 0; ENTRY; BSON_ASSERT (secure_transport); if (tls->timeout_msec >= 0) { expire = bson_get_monotonic_time () + (tls->timeout_msec * 1000UL); } status = SSLWrite (secure_transport->ssl_ctx_ref, buf, buf_len, (size_t *) &write_ret); switch (status) { case errSSLWouldBlock: case noErr: break; case errSSLClosedAbort: errno = ECONNRESET; default: RETURN (-1); } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (write_ret < buf_len) { mongoc_counter_streams_timeout_inc (); } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000L; } } RETURN (write_ret); } /* This is copypasta from _mongoc_stream_tls_openssl_writev */ #define MONGOC_STREAM_TLS_BUFFER_SIZE 4096 static ssize_t _mongoc_stream_tls_secure_transport_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; char buf[MONGOC_STREAM_TLS_BUFFER_SIZE]; ssize_t ret = 0; ssize_t child_ret; size_t i; size_t iov_pos = 0; /* There's a bit of a dance to coalesce vectorized writes into * MONGOC_STREAM_TLS_BUFFER_SIZE'd writes to avoid lots of small tls * packets. * * The basic idea is that we want to combine writes in the buffer if they're * smaller than the buffer, flushing as it gets full. For larger writes, or * the last write in the iovec array, we want to ignore the buffer and just * write immediately. We take care of doing buffer writes by re-invoking * ourself with a single iovec_t, pointing at our stack buffer. */ char *buf_head = buf; char *buf_tail = buf; char *buf_end = buf + MONGOC_STREAM_TLS_BUFFER_SIZE; size_t bytes; char *to_write = NULL; size_t to_write_len; BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (secure_transport); ENTRY; tls->timeout_msec = timeout_msec; for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { if (buf_head != buf_tail || ((i + 1 < iovcnt) && ((buf_end - buf_tail) > (iov[i].iov_len - iov_pos)))) { /* If we have either of: * - buffered bytes already * - another iovec to send after this one and we don't have more * bytes to send than the size of the buffer. * * copy into the buffer */ bytes = BSON_MIN (iov[i].iov_len - iov_pos, buf_end - buf_tail); memcpy (buf_tail, (char *) iov[i].iov_base + iov_pos, bytes); buf_tail += bytes; iov_pos += bytes; if (buf_tail == buf_end) { /* If we're full, request send */ to_write = buf_head; to_write_len = buf_tail - buf_head; buf_tail = buf_head = buf; } } else { /* Didn't buffer, so just write it through */ to_write = (char *) iov[i].iov_base + iov_pos; to_write_len = iov[i].iov_len - iov_pos; iov_pos += to_write_len; } if (to_write) { /* We get here if we buffered some bytes and filled the buffer, or * if we didn't buffer and have to send out of the iovec */ child_ret = _mongoc_stream_tls_secure_transport_write (stream, to_write, to_write_len); if (child_ret < 0) { RETURN (ret); } ret += child_ret; if (child_ret < to_write_len) { /* we timed out, so send back what we could send */ RETURN (ret); } to_write = NULL; } } } if (buf_head != buf_tail) { /* If we have any bytes buffered, send */ child_ret = _mongoc_stream_tls_secure_transport_write (stream, buf_head, buf_tail - buf_head); if (child_ret < 0) { RETURN (child_ret); } ret += child_ret; } if (ret >= 0) { mongoc_counter_streams_egress_add (ret); } TRACE ("Returning %d", (int) ret); RETURN (ret); } /* This function is copypasta of _mongoc_stream_tls_openssl_readv */ static ssize_t _mongoc_stream_tls_secure_transport_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ssize_t ret = 0; size_t i; size_t read_ret; size_t iov_pos = 0; int64_t now; int64_t expire = 0; size_t to_read; size_t remaining_buf_size; size_t remaining_to_read; BSON_ASSERT (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (secure_transport); ENTRY; tls->timeout_msec = timeout_msec; if (timeout_msec >= 0) { expire = bson_get_monotonic_time () + (timeout_msec * 1000UL); } for (i = 0; i < iovcnt; i++) { iov_pos = 0; while (iov_pos < iov[i].iov_len) { remaining_buf_size = iov[i].iov_len - iov_pos; remaining_to_read = min_bytes - ret; /* The third argument passed to SSLRead is an all-or-nothing dataLength, which it will attempt to read until it succeeds or times out. If our buffer is larger than the message we expect to read, choose the smaller number of the two. */ if (remaining_to_read > 0 && remaining_to_read < remaining_buf_size) { to_read = remaining_to_read; } else { to_read = remaining_buf_size; } OSStatus status = SSLRead (secure_transport->ssl_ctx_ref, (char *) iov[i].iov_base + iov_pos, to_read, &read_ret); if (status != noErr) { RETURN (-1); } if (expire) { now = bson_get_monotonic_time (); if ((expire - now) < 0) { if (read_ret == 0) { mongoc_counter_streams_timeout_inc (); errno = ETIMEDOUT; RETURN (-1); } tls->timeout_msec = 0; } else { tls->timeout_msec = (expire - now) / 1000L; } } ret += read_ret; if ((size_t) ret >= min_bytes) { mongoc_counter_streams_ingress_add (ret); RETURN (ret); } iov_pos += read_ret; } } if (ret >= 0) { mongoc_counter_streams_ingress_add (ret); } RETURN (ret); } static int _mongoc_stream_tls_secure_transport_setsockopt ( mongoc_stream_t *stream, int level, int optname, void *optval, mongoc_socklen_t optlen) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_transport); RETURN (mongoc_stream_setsockopt (tls->base_stream, level, optname, optval, optlen)); } static mongoc_stream_t * _mongoc_stream_tls_secure_transport_get_base_stream (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_transport); RETURN (tls->base_stream); } static bool _mongoc_stream_tls_secure_transport_check_closed (mongoc_stream_t *stream) /* IN */ { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_transport); RETURN (mongoc_stream_check_closed (tls->base_stream)); } static void _set_error_from_osstatus (OSStatus status, const char *prefix, bson_error_t *error) { CFStringRef err; char *err_str; err = SecCopyErrorMessageString (status, NULL); err_str = _mongoc_cfstringref_to_cstring (err); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "%s: %s (%d)", prefix, err_str, status); bson_free (err_str); CFRelease (err); } /* Always returns a string that must be freed. */ static char * explain_trust_result (SecTrustRef trust, SecTrustResultType trust_result) { CFArrayRef cfprops = NULL; CFIndex count, i; mcommon_string_append_t reason; mcommon_string_new_as_append (&reason); switch (trust_result) { case kSecTrustResultDeny: mcommon_string_append (&reason, "Certificate trust denied"); break; case kSecTrustResultRecoverableTrustFailure: mcommon_string_append (&reason, "Certificate trust failure"); break; case kSecTrustResultFatalTrustFailure: mcommon_string_append (&reason, "Certificate trust fatal failure"); break; case kSecTrustResultInvalid: mcommon_string_append (&reason, "Certificate trust evaluation failure"); break; default: mcommon_string_append_printf (&reason, "Certificate trust failure #%d", (int) trust_result); break; } mcommon_string_append (&reason, ": "); cfprops = SecTrustCopyProperties (trust); /* This contains an array of dictionaries, each representing a cert in the * chain. Append the first failure reason found. */ if (!cfprops) { mcommon_string_append (&reason, "Unable to retreive cause for trust failure"); goto done; } count = CFArrayGetCount (cfprops); for (i = 0; i < count; ++i) { const void *elem = NULL; const void *reason_elem = NULL; char *reason_str; CFDictionaryRef dict; elem = CFArrayGetValueAtIndex (cfprops, i); if (CFGetTypeID (elem) != CFDictionaryGetTypeID ()) { mcommon_string_append (&reason, "Unable to parse cause for trust failure"); goto done; } dict = (CFDictionaryRef) elem; reason_elem = CFDictionaryGetValue (dict, kSecPropertyTypeError); if (!reason_elem) { continue; } if (CFGetTypeID (reason_elem) != CFStringGetTypeID ()) { mcommon_string_append (&reason, "Unable to parse trust failure error"); goto done; } reason_str = _mongoc_cfstringref_to_cstring (reason_elem); if (reason_str) { mcommon_string_append (&reason, reason_str); bson_free (reason_str); goto done; } else { mcommon_string_append (&reason, "Unable to express trust failure error"); goto done; } } mcommon_string_append (&reason, "No trust failure reason available"); done: CFReleaseSafe (cfprops); return mcommon_string_from_append_destroy_with_steal (&reason); } /* Returns a boolean indicating success. If false is returned, then an error is * set. */ static bool _verify_peer (mongoc_stream_t *stream, bson_error_t *error) { CFArrayRef policies = NULL; SecTrustRef trust = NULL; OSStatus status; CFMutableArrayRef policies_mutable = NULL; SecPolicyRef rev_policy = NULL; SecTrustResultType trust_result; mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; bool ret = false; status = SSLCopyPeerTrust (secure_transport->ssl_ctx_ref, &trust); if (status != noErr) { _set_error_from_osstatus (status, "Certificate validation errored", error); goto fail; } status = SecTrustCopyPolicies (trust, &policies); if (status != noErr) { _set_error_from_osstatus (status, "Certificate validation errored", error); goto fail; } /* Add explicit OCSP revocation policy. */ policies_mutable = CFArrayCreateMutableCopy (NULL, 0, policies); /* TODO: possibly disable endpoint checking by adding the flag * kSecRevocationNetworkAccessDisabled once the option * tlsDisableOCSPEndpointCheck is implemented. */ rev_policy = SecPolicyCreateRevocation (kSecRevocationOCSPMethod); CFArrayAppendValue (policies_mutable, rev_policy); status = SecTrustSetPolicies (trust, policies_mutable); if (status != noErr) { _set_error_from_osstatus (status, "Certificate validation errored", error); goto fail; } /* TODO: SecTrustEvaluate is blocking. When making Secure Transport's * handshake is made non-blocking in CDRIVER-2885, this will need to be * addressed. */ status = SecTrustEvaluate (trust, &trust_result); if (status != noErr) { _set_error_from_osstatus (status, "Certificate validation errored", error); goto fail; } if (trust_result != kSecTrustResultProceed && trust_result != kSecTrustResultUnspecified) { char *reason = explain_trust_result (trust, trust_result); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed (%s)", reason); bson_free (reason); goto fail; } ret = true; fail: CFReleaseSafe (trust); CFReleaseSafe (policies); CFReleaseSafe (policies_mutable); CFReleaseSafe (rev_policy); return ret; } bool mongoc_stream_tls_secure_transport_handshake (mongoc_stream_t *stream, const char *host, int *events, bson_error_t *error) { OSStatus ret = 0; mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; mongoc_stream_tls_secure_transport_t *secure_transport = (mongoc_stream_tls_secure_transport_t *) tls->ctx; ENTRY; BSON_ASSERT (secure_transport); ret = SSLHandshake (secure_transport->ssl_ctx_ref); if (ret == errSSLServerAuthCompleted) { if (!tls->ssl_opts.weak_cert_validation && !_verify_peer (stream, error)) { *events = 0; RETURN (false); } ret = errSSLWouldBlock; } if (ret == noErr) { RETURN (true); } if (ret == errSSLWouldBlock) { *events = POLLIN | POLLOUT; } else { *events = 0; _set_error_from_osstatus (ret, "TLS handshake failed", error); } RETURN (false); } static bool _mongoc_stream_tls_secure_channel_timed_out (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; ENTRY; RETURN (mongoc_stream_timed_out (tls->base_stream)); } static bool _mongoc_stream_tls_secure_channel_should_retry (mongoc_stream_t *stream) { mongoc_stream_tls_t *tls = (mongoc_stream_tls_t *) stream; ENTRY; RETURN (mongoc_stream_should_retry (tls->base_stream)); } mongoc_stream_t * mongoc_stream_tls_secure_transport_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) { mongoc_stream_tls_t *tls; mongoc_stream_tls_secure_transport_t *secure_transport; ENTRY; BSON_ASSERT (base_stream); BSON_ASSERT (opt); if (opt->ca_dir) { MONGOC_ERROR ("Setting mongoc_ssl_opt_t.ca_dir has no effect when built " "against Secure Transport"); RETURN (NULL); } if (opt->crl_file) { MONGOC_ERROR ("Setting mongoc_ssl_opt_t.crl_file has no effect when built " "against Secure Transport"); RETURN (NULL); } secure_transport = (mongoc_stream_tls_secure_transport_t *) bson_malloc0 (sizeof *secure_transport); tls = (mongoc_stream_tls_t *) bson_malloc0 (sizeof *tls); tls->parent.type = MONGOC_STREAM_TLS; tls->parent.destroy = _mongoc_stream_tls_secure_transport_destroy; tls->parent.failed = _mongoc_stream_tls_secure_transport_failed; tls->parent.close = _mongoc_stream_tls_secure_transport_close; tls->parent.flush = _mongoc_stream_tls_secure_transport_flush; tls->parent.writev = _mongoc_stream_tls_secure_transport_writev; tls->parent.readv = _mongoc_stream_tls_secure_transport_readv; tls->parent.setsockopt = _mongoc_stream_tls_secure_transport_setsockopt; tls->parent.get_base_stream = _mongoc_stream_tls_secure_transport_get_base_stream; tls->parent.check_closed = _mongoc_stream_tls_secure_transport_check_closed; tls->parent.timed_out = _mongoc_stream_tls_secure_channel_timed_out; tls->parent.should_retry = _mongoc_stream_tls_secure_channel_should_retry; memcpy (&tls->ssl_opts, opt, sizeof tls->ssl_opts); tls->handshake = mongoc_stream_tls_secure_transport_handshake; tls->ctx = (void *) secure_transport; tls->timeout_msec = -1; secure_transport->ssl_ctx_ref = SSLCreateContext (kCFAllocatorDefault, client ? kSSLClientSide : kSSLServerSide, kSSLStreamType); SSLSetIOFuncs (secure_transport->ssl_ctx_ref, mongoc_secure_transport_read, mongoc_secure_transport_write); SSLSetProtocolVersionMin (secure_transport->ssl_ctx_ref, kTLSProtocol1); if (opt->pem_file && !mongoc_secure_transport_setup_certificate (secure_transport, opt)) { mongoc_stream_destroy ((mongoc_stream_t *) tls); RETURN (NULL); } if (opt->ca_file && !mongoc_secure_transport_setup_ca (secure_transport, opt)) { mongoc_stream_destroy ((mongoc_stream_t *) tls); RETURN (NULL); } /* don't link base_stream to tls until we're sure we won't destroy tls */ tls->base_stream = base_stream; if (client) { /* This option has SSL_Handshake stop before it verifies peer cert. Set * this since we verify peer cert manually later. */ SSLSetSessionOption (secure_transport->ssl_ctx_ref, kSSLSessionOptionBreakOnServerAuth, true); } else if (!opt->allow_invalid_hostname) { /* used only in mock_server_t tests */ SSLSetClientSideAuthenticate (secure_transport->ssl_ctx_ref, kAlwaysAuthenticate); } if (!opt->allow_invalid_hostname) { SSLSetPeerDomainName (secure_transport->ssl_ctx_ref, host, strlen (host)); } SSLSetConnection (secure_transport->ssl_ctx_ref, tls); mongoc_counter_streams_active_inc (); if (_mongoc_ssl_opts_disable_certificate_revocation_check (opt)) { MONGOC_ERROR ("Setting tlsDisableCertificateRevocationCheck has no " "effect when built against Secure Transport"); } if (_mongoc_ssl_opts_disable_ocsp_endpoint_check (opt)) { MONGOC_ERROR ("Setting tlsDisableOCSPEndpointCheck has no effect when " "built against Secure Transport"); } RETURN ((mongoc_stream_t *) tls); } #endif /* MONGOC_ENABLE_SSL_SECURE_TRANSPORT */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls-secure-transport.h0000644000175100001660000000237014760300420026552 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_SECURE_TRANSPORT_H #define MONGOC_STREAM_TLS_SECURE_TRANSPORT_H #ifdef MONGOC_ENABLE_SSL_SECURE_TRANSPORT #include #include BSON_BEGIN_DECLS MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_tls_secure_transport_new (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_ENABLE_SSL_SECURE_TRANSPORT */ #endif /* MONGOC_STREAM_TLS_SECURE_TRANSPORT_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls.c0000644000175100001660000002065514760300420023235 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifdef MONGOC_ENABLE_SSL #include #include #include #include #include #include #include #include #if defined(MONGOC_ENABLE_SSL_OPENSSL) #include #include #elif defined(MONGOC_ENABLE_SSL_LIBRESSL) #include #include #elif defined(MONGOC_ENABLE_SSL_SECURE_TRANSPORT) #include #include #elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL) #include #include #endif #include #include // BEGIN_IGNORE_DEPRECATIONS #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream-tls" /** * mongoc_stream_tls_handshake: * * Performs TLS handshake dance */ bool mongoc_stream_tls_handshake ( mongoc_stream_t *stream, const char *host, int32_t timeout_msec, int *events, bson_error_t *error) { mongoc_stream_tls_t *stream_tls = (mongoc_stream_tls_t *) mongoc_stream_get_tls_stream (stream); BSON_ASSERT (stream_tls); BSON_ASSERT (stream_tls->handshake); stream_tls->timeout_msec = timeout_msec; return stream_tls->handshake (stream, host, events, error); } bool mongoc_stream_tls_handshake_block (mongoc_stream_t *stream, const char *host, int32_t timeout_msec, bson_error_t *error) { int events; ssize_t ret = 0; mongoc_stream_poll_t poller; int64_t expire = 0; if (timeout_msec >= 0) { expire = bson_get_monotonic_time () + (timeout_msec * 1000); } /* * error variables get re-used a lot. To prevent cross-contamination of error * messages, and still be able to provide a generic failure message when * mongoc_stream_tls_handshake fails without a specific reason, we need to * init * the error code to 0. */ if (error) { error->code = 0; } do { events = 0; if (mongoc_stream_tls_handshake (stream, host, timeout_msec, &events, error)) { return true; } if (events) { poller.stream = stream; poller.events = events; poller.revents = 0; if (expire >= 0) { const int64_t now = bson_get_monotonic_time (); const int64_t remaining = expire - now; if (remaining < 0) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake timed out."); return false; } else { const int64_t msec = remaining / 1000; BSON_ASSERT (mcommon_in_range_signed (int32_t, msec)); timeout_msec = (int32_t) msec; } } ret = mongoc_stream_poll (&poller, 1, timeout_msec); } } while (events && ret > 0); if (error && !error->code) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "TLS handshake failed."); } return false; } /** * Deprecated. Was never supposed to be part of the public API. * See mongoc_stream_tls_handshake. */ bool mongoc_stream_tls_do_handshake (mongoc_stream_t *stream, int32_t timeout_msec) { mongoc_stream_tls_t *stream_tls = (mongoc_stream_tls_t *) mongoc_stream_get_tls_stream (stream); BSON_UNUSED (timeout_msec); BSON_ASSERT (stream_tls); MONGOC_ERROR ("This function doesn't do anything. Please call " "mongoc_stream_tls_handshake()"); return false; } /** * Deprecated. Was never supposed to be part of the public API. * See mongoc_stream_tls_handshake. */ bool mongoc_stream_tls_check_cert (mongoc_stream_t *stream, const char *host) { mongoc_stream_tls_t *stream_tls = (mongoc_stream_tls_t *) mongoc_stream_get_tls_stream (stream); BSON_UNUSED (host); BSON_ASSERT (stream_tls); MONGOC_ERROR ("This function doesn't do anything. Please call " "mongoc_stream_tls_handshake()"); return false; } /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_new_with_hostname -- * * Creates a new mongoc_stream_tls_t to communicate with a remote * server using a TLS stream. * * @host the hostname we are connected to and to verify the * server certificate against * * @base_stream should be a stream that will become owned by the * resulting tls stream. It will be used for raw I/O. * * @trust_store_dir should be a path to the SSL cert db to use for * verifying trust of the remote server. * * Returns: * NULL on failure, otherwise a mongoc_stream_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_tls_new_with_hostname (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) { BSON_ASSERT (base_stream); /* !client is only used for testing, * when the streams are pretending to be the server */ if (!client || opt->weak_cert_validation) { opt->allow_invalid_hostname = true; } #ifndef _WIN32 /* Silly check for Unix Domain Sockets */ if (!host || (host[0] == '/' && !access (host, F_OK))) { opt->allow_invalid_hostname = true; } #endif #if defined(MONGOC_ENABLE_SSL_OPENSSL) return mongoc_stream_tls_openssl_new (base_stream, host, opt, client); #elif defined(MONGOC_ENABLE_SSL_LIBRESSL) BEGIN_IGNORE_DEPRECATIONS return mongoc_stream_tls_libressl_new (base_stream, host, opt, client); END_IGNORE_DEPRECATIONS #elif defined(MONGOC_ENABLE_SSL_SECURE_TRANSPORT) return mongoc_stream_tls_secure_transport_new (base_stream, host, opt, client); #elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL) return mongoc_stream_tls_secure_channel_new (base_stream, host, opt, client); #else #error "Don't know how to create TLS stream" #endif } #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L /* *-------------------------------------------------------------------------- * * mongoc_stream_tls_new_with_hostname_and_openssl_context -- * * Creates a new mongoc_stream_tls_t to communicate with a remote * server using a TLS stream, using an existing OpenSSL context. * * @ssl_ctx is the global OpenSSL context for the mongoc_client_t * associated with this function call. * * @host the hostname we are connected to and to verify the * server certificate against * * @base_stream should be a stream that will become owned by the * resulting tls stream. It will be used for raw I/O. * * Returns: * NULL on failure, otherwise a mongoc_stream_t. * * Side effects: * None. * *-------------------------------------------------------------------------- */ mongoc_stream_t * mongoc_stream_tls_new_with_hostname_and_openssl_context ( mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client, SSL_CTX *ssl_ctx) { BSON_ASSERT (base_stream); /* !client is only used for testing, * when the streams are pretending to be the server */ if (!client || opt->weak_cert_validation) { opt->allow_invalid_hostname = true; } #ifndef _WIN32 /* Silly check for Unix Domain Sockets */ if (!host || (host[0] == '/' && !access (host, F_OK))) { opt->allow_invalid_hostname = true; } #endif return mongoc_stream_tls_openssl_new_with_context (base_stream, host, opt, client, ssl_ctx); } #endif mongoc_stream_t * mongoc_stream_tls_new (mongoc_stream_t *base_stream, mongoc_ssl_opt_t *opt, int client) { return mongoc_stream_tls_new_with_hostname (base_stream, NULL, opt, client); } #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream-tls.h0000644000175100001660000000402514760300420023233 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_TLS_H #define MONGOC_STREAM_TLS_H #include #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_stream_tls_t mongoc_stream_tls_t; MONGOC_EXPORT (bool) mongoc_stream_tls_handshake ( mongoc_stream_t *stream, const char *host, int32_t timeout_msec, int *events, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_stream_tls_handshake_block (mongoc_stream_t *stream, const char *host, int32_t timeout_msec, bson_error_t *error); MONGOC_EXPORT (bool) mongoc_stream_tls_do_handshake (mongoc_stream_t *stream, int32_t timeout_msec) BSON_GNUC_DEPRECATED_FOR (mongoc_stream_tls_handshake); MONGOC_EXPORT (bool) mongoc_stream_tls_check_cert (mongoc_stream_t *stream, const char *host) BSON_GNUC_DEPRECATED_FOR (mongoc_stream_tls_handshake); MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_tls_new_with_hostname (mongoc_stream_t *base_stream, const char *host, mongoc_ssl_opt_t *opt, int client) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_tls_new (mongoc_stream_t *base_stream, mongoc_ssl_opt_t *opt, int client) BSON_GNUC_WARN_UNUSED_RESULT BSON_GNUC_DEPRECATED_FOR (mongoc_stream_tls_new_with_hostname); BSON_END_DECLS #endif /* MONGOC_STREAM_TLS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream.c0000644000175100001660000002430514760300420022431 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "stream" #ifndef MONGOC_DEFAULT_TIMEOUT_MSEC #define MONGOC_DEFAULT_TIMEOUT_MSEC (60L * 60L * 1000L) #endif /** * mongoc_stream_close: * @stream: A mongoc_stream_t. * * Closes the underlying file-descriptor used by @stream. * * Returns: 0 on success, -1 on failure. */ int mongoc_stream_close (mongoc_stream_t *stream) { int ret; ENTRY; BSON_ASSERT_PARAM (stream); BSON_ASSERT (stream->close); ret = stream->close (stream); RETURN (ret); } /** * mongoc_stream_failed: * @stream: A mongoc_stream_t. * * Frees any resources referenced by @stream, including the memory allocation * for @stream. * This handler is called upon stream failure, such as network errors, invalid * replies * or replicaset reconfigures deleting the stream */ void mongoc_stream_failed (mongoc_stream_t *stream) { ENTRY; BSON_ASSERT_PARAM (stream); if (stream->failed) { stream->failed (stream); } else { stream->destroy (stream); } EXIT; } /** * mongoc_stream_destroy: * @stream: A mongoc_stream_t. * * Frees any resources referenced by @stream, including the memory allocation * for @stream. */ void mongoc_stream_destroy (mongoc_stream_t *stream) { ENTRY; if (!stream) { EXIT; } BSON_ASSERT (stream->destroy); stream->destroy (stream); EXIT; } /** * mongoc_stream_flush: * @stream: A mongoc_stream_t. * * Flushes the data in the underlying stream to the transport. * * Returns: 0 on success, -1 on failure. */ int mongoc_stream_flush (mongoc_stream_t *stream) { BSON_ASSERT_PARAM (stream); return stream->flush (stream); } /** * mongoc_stream_writev: * @stream: A mongoc_stream_t. * @iov: An array of iovec to write to the stream. * @iovcnt: The number of elements in @iov. * * Writes an array of iovec buffers to the underlying stream. * * Returns: the number of bytes written, or -1 upon failure. */ ssize_t mongoc_stream_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec) { ssize_t ret; ENTRY; BSON_ASSERT_PARAM (stream); BSON_ASSERT_PARAM (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (stream->writev); // CDRIVER-4781: for backward compatibility. if (timeout_msec < 0) { timeout_msec = MONGOC_DEFAULT_TIMEOUT_MSEC; } DUMP_IOVEC (writev, iov, iovcnt); ret = stream->writev (stream, iov, iovcnt, timeout_msec); RETURN (ret); } /** * mongoc_stream_write: * @stream: A mongoc_stream_t. * @buf: A buffer to write. * @count: The number of bytes to write into @buf. * * Simplified access to mongoc_stream_writev(). Creates a single iovec * with the buffer provided. * * Returns: -1 on failure, otherwise the number of bytes written. */ ssize_t mongoc_stream_write (mongoc_stream_t *stream, void *buf, size_t count, int32_t timeout_msec) { mongoc_iovec_t iov; ssize_t ret; ENTRY; BSON_ASSERT_PARAM (stream); BSON_ASSERT_PARAM (buf); iov.iov_base = buf; iov.iov_len = count; BSON_ASSERT (stream->writev); ret = mongoc_stream_writev (stream, &iov, 1, timeout_msec); RETURN (ret); } /** * mongoc_stream_readv: * @stream: A mongoc_stream_t. * @iov: An array of iovec containing the location and sizes to read. * @iovcnt: the number of elements in @iov. * @min_bytes: the minimum number of bytes to return, or -1. * * Reads into the various buffers pointed to by @iov and associated * buffer lengths. * * If @min_bytes is specified, then at least min_bytes will be returned unless * eof is encountered. This may result in ETIMEDOUT * * Returns: the number of bytes read or -1 on failure. */ ssize_t mongoc_stream_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec) { ssize_t ret; ENTRY; BSON_ASSERT_PARAM (stream); BSON_ASSERT_PARAM (iov); BSON_ASSERT (iovcnt); BSON_ASSERT (stream->readv); ret = stream->readv (stream, iov, iovcnt, min_bytes, timeout_msec); if (ret >= 0) { DUMP_IOVEC (readv, iov, iovcnt); } RETURN (ret); } /** * mongoc_stream_read: * @stream: A mongoc_stream_t. * @buf: A buffer to write into. * @count: The number of bytes to write into @buf. * @min_bytes: The minimum number of bytes to receive * * Simplified access to mongoc_stream_readv(). Creates a single iovec * with the buffer provided. * * If @min_bytes is specified, then at least min_bytes will be returned unless * eof is encountered. This may result in ETIMEDOUT * * Returns: -1 on failure, otherwise the number of bytes read. */ ssize_t mongoc_stream_read (mongoc_stream_t *stream, void *buf, size_t count, size_t min_bytes, int32_t timeout_msec) { mongoc_iovec_t iov; ssize_t ret; ENTRY; BSON_ASSERT_PARAM (stream); BSON_ASSERT_PARAM (buf); iov.iov_base = buf; iov.iov_len = count; BSON_ASSERT (stream->readv); ret = mongoc_stream_readv (stream, &iov, 1, min_bytes, timeout_msec); RETURN (ret); } int mongoc_stream_setsockopt (mongoc_stream_t *stream, int level, int optname, void *optval, mongoc_socklen_t optlen) { BSON_ASSERT_PARAM (stream); if (stream->setsockopt) { return stream->setsockopt (stream, level, optname, optval, optlen); } return 0; } mongoc_stream_t * mongoc_stream_get_base_stream (mongoc_stream_t *stream) /* IN */ { BSON_ASSERT_PARAM (stream); if (stream->get_base_stream) { return stream->get_base_stream (stream); } return stream; } mongoc_stream_t * mongoc_stream_get_root_stream (mongoc_stream_t *stream) { BSON_ASSERT_PARAM (stream); while (stream->get_base_stream) { stream = stream->get_base_stream (stream); } return stream; } mongoc_stream_t * mongoc_stream_get_tls_stream (mongoc_stream_t *stream) /* IN */ { BSON_ASSERT_PARAM (stream); for (; stream && stream->type != MONGOC_STREAM_TLS; stream = stream->get_base_stream (stream)) ; return stream; } ssize_t mongoc_stream_poll (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout) { mongoc_stream_poll_t *poller = (mongoc_stream_poll_t *) bson_malloc (sizeof (*poller) * nstreams); int last_type = 0; ssize_t rval = -1; errno = 0; for (size_t i = 0u; i < nstreams; i++) { poller[i].stream = mongoc_stream_get_root_stream (streams[i].stream); poller[i].events = streams[i].events; poller[i].revents = 0; if (i == 0u) { last_type = poller[i].stream->type; } else if (last_type != poller[i].stream->type) { errno = EINVAL; goto CLEANUP; } } if (!poller[0].stream->poll) { errno = EINVAL; goto CLEANUP; } rval = poller[0].stream->poll (poller, nstreams, timeout); if (rval > 0) { for (size_t i = 0u; i < nstreams; i++) { streams[i].revents = poller[i].revents; } } CLEANUP: bson_free (poller); return rval; } bool mongoc_stream_check_closed (mongoc_stream_t *stream) { int ret; ENTRY; if (!stream) { return true; } ret = stream->check_closed (stream); RETURN (ret); } bool mongoc_stream_timed_out (mongoc_stream_t *stream) { ENTRY; BSON_ASSERT_PARAM (stream); /* for e.g. a file stream there is no timed_out function */ RETURN (stream->timed_out && stream->timed_out (stream)); } bool mongoc_stream_should_retry (mongoc_stream_t *stream) { ENTRY; BSON_ASSERT_PARAM (stream); /* for e.g. a file stream there is no should_retry function */ RETURN (stream->should_retry && stream->should_retry (stream)); } bool _mongoc_stream_writev_full ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int64_t timeout_msec, bson_error_t *error) { size_t total_bytes = 0; ssize_t r; ENTRY; for (size_t i = 0u; i < iovcnt; i++) { total_bytes += iov[i].iov_len; } if (BSON_UNLIKELY (!mcommon_in_range_signed (int32_t, timeout_msec))) { // CDRIVER-4589 bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "timeout_msec value %" PRId64 " exceeds supported 32-bit range", timeout_msec); RETURN (false); } r = mongoc_stream_writev (stream, iov, iovcnt, (int32_t) timeout_msec); TRACE ("writev returned: %zd", r); if (r < 0) { if (error) { char buf[128]; char *errstr; errstr = bson_strerror_r (errno, buf, sizeof (buf)); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failure during socket delivery: %s (%d)", errstr, errno); } RETURN (false); } if (mcommon_cmp_not_equal_su (r, total_bytes)) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failure to send all requested bytes (only sent: %" PRIu64 "/%zu in %" PRId64 "ms) during socket delivery", (uint64_t) r, total_bytes, timeout_msec); RETURN (false); } RETURN (true); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-stream.h0000644000175100001660000000646214760300420022442 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STREAM_H #define MONGOC_STREAM_H #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_stream_t mongoc_stream_t; typedef struct _mongoc_stream_poll_t { mongoc_stream_t *stream; int events; int revents; } mongoc_stream_poll_t; struct _mongoc_stream_t { int type; void (*destroy) (mongoc_stream_t *stream); int (*close) (mongoc_stream_t *stream); int (*flush) (mongoc_stream_t *stream); ssize_t (*writev) (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec); ssize_t (*readv) ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec); int (*setsockopt) (mongoc_stream_t *stream, int level, int optname, void *optval, mongoc_socklen_t optlen); mongoc_stream_t *(*get_base_stream) (mongoc_stream_t *stream); bool (*check_closed) (mongoc_stream_t *stream); ssize_t (*poll) (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout); void (*failed) (mongoc_stream_t *stream); bool (*timed_out) (mongoc_stream_t *stream); bool (*should_retry) (mongoc_stream_t *stream); void *padding[3]; }; MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_get_base_stream (mongoc_stream_t *stream); MONGOC_EXPORT (mongoc_stream_t *) mongoc_stream_get_tls_stream (mongoc_stream_t *stream); MONGOC_EXPORT (int) mongoc_stream_close (mongoc_stream_t *stream); MONGOC_EXPORT (void) mongoc_stream_destroy (mongoc_stream_t *stream); MONGOC_EXPORT (void) mongoc_stream_failed (mongoc_stream_t *stream); MONGOC_EXPORT (int) mongoc_stream_flush (mongoc_stream_t *stream); MONGOC_EXPORT (ssize_t) mongoc_stream_writev (mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, int32_t timeout_msec); MONGOC_EXPORT (ssize_t) mongoc_stream_write (mongoc_stream_t *stream, void *buf, size_t count, int32_t timeout_msec); MONGOC_EXPORT (ssize_t) mongoc_stream_readv ( mongoc_stream_t *stream, mongoc_iovec_t *iov, size_t iovcnt, size_t min_bytes, int32_t timeout_msec); MONGOC_EXPORT (ssize_t) mongoc_stream_read (mongoc_stream_t *stream, void *buf, size_t count, size_t min_bytes, int32_t timeout_msec); MONGOC_EXPORT (int) mongoc_stream_setsockopt (mongoc_stream_t *stream, int level, int optname, void *optval, mongoc_socklen_t optlen); MONGOC_EXPORT (bool) mongoc_stream_check_closed (mongoc_stream_t *stream); MONGOC_EXPORT (bool) mongoc_stream_timed_out (mongoc_stream_t *stream); MONGOC_EXPORT (bool) mongoc_stream_should_retry (mongoc_stream_t *stream); MONGOC_EXPORT (ssize_t) mongoc_stream_poll (mongoc_stream_poll_t *streams, size_t nstreams, int32_t timeout); BSON_END_DECLS #endif /* MONGOC_STREAM_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-structured-log-private.h0000644000175100001660000006614414760300420025605 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STRUCTURED_LOG_PRIVATE_H #define MONGOC_STRUCTURED_LOG_PRIVATE_H #include #include #include #include #include #include #include BSON_BEGIN_DECLS typedef struct mongoc_structured_log_instance_t mongoc_structured_log_instance_t; #define MONGOC_STRUCTURED_LOG_DEFAULT_LEVEL MONGOC_STRUCTURED_LOG_LEVEL_WARNING #define MONGOC_STRUCTURED_LOG_DEFAULT_MAX_DOCUMENT_LENGTH 1000 /** * @brief maximum possible value of the 'maximum document length' setting, enforced when reading settings from the * environment. * * Maximum document length applies to a single serialized JSON document within the log. * The overall log document, when serialized as BSON, will be subject to BSON_MAX_SIZE. * At a minimum we should leave room for BSON headers and for the JSON truncation marker ("..."). * Choose to leave a little more room, as it's more useful to truncate the huge document early * rather than fail in bson_append_utf8(). */ #define MONGOC_STRUCTURED_LOG_MAXIMUM_MAX_DOCUMENT_LENGTH ((uint32_t) BSON_MAX_SIZE - 4096u) /** * @brief Allocate a new instance of the structured logging system * @param opts Options, copied into the new instance. * * Must be paired with mongoc_structured_log_instance_destroy(). * * Once created, an instance has immutable settings. To change the handler * or the max level per component filters, the instance will be replaced. * One instance can be used by mongoc_structured_log() calls on multiple * threads concurrently. */ mongoc_structured_log_instance_t * mongoc_structured_log_instance_new (const mongoc_structured_log_opts_t *opts); /** * @brief Destroy an instance of the structured logging system. * * All threads must be finished using the mongoc_structured_log_instance_t * before it is destroyed. */ void mongoc_structured_log_instance_destroy (mongoc_structured_log_instance_t *instance); /** * @def mongoc_structured_log(instance, level, component, message, ...) * @brief Write to the libmongoc structured log. * * @param instance Structured log instance, as a mongoc_structured_log_instance_t* expression * @param level Log level, as a mongoc_structured_log_level_t expression * @param component Log component, as a mongoc_structured_log_component_t expression * @param message Log message, as a const char* expression * @param ... Optional list of log 'items' that specify additional information to include. * * The instance, level, component, and message expressions are always evaluated. * Any expressions in the optional items list are only evaluated if the log * hasn't been disabled by a component's maximum log level setting or by * unsetting the global structured log handler. * * Each log 'item' may represent a deferred operation that has minimal cost * unless mongoc_structured_log_entry_message_as_bson is actually invoked. * * Calls implementation functions _mongoc_structured_log_should_log() before * building the table of item information and _mongoc_structured_log_with_entry() * once the table is built. */ #define mongoc_structured_log(_structured_log_instance, _level, _component, ...) \ _bsonDSL_eval (_mongoc_structured_log_with_end_of_list ( \ _structured_log_instance, _level, _component, __VA_ARGS__, end_of_list ())) #define _mongoc_structured_log_with_end_of_list(_structured_log_instance, _level, _component, _message, ...) \ do { \ mongoc_structured_log_entry_t _entry = {.envelope.instance = (_structured_log_instance), \ .envelope.level = (_level), \ .envelope.component = (_component), \ .envelope.message = (_message)}; \ if (_mongoc_structured_log_should_log (&_entry.envelope)) { \ const mongoc_structured_log_builder_stage_t _builder[] = { \ _mongoc_structured_log_items_to_stages (__VA_ARGS__)}; \ _entry.builder = _builder; \ _mongoc_structured_log_with_entry (&_entry); \ } \ } while (0) #define _mongoc_structured_log_items_to_stages(...) \ _bsonDSL_mapMacro (_mongoc_structured_log_item_to_stages, ~, __VA_ARGS__) #define _mongoc_structured_log_flag_expr(_action, _constant, _counter) | (_constant##_##_action) #define _mongoc_structured_log_item_to_stages(_action, _constant, _counter) _mongoc_structured_log_item_##_action #define _mongoc_structured_log_item_end_of_list() {.func = NULL}, /** * @def utf8(key, value) * @brief Structured log item, referencing a NUL-terminated utf8 string value. * * @param key Key as a const char * expression, or NULL to skip this item. * @param value UTF8 value as a const char * expression, or NULL for a null value. */ #define _mongoc_structured_log_item_utf8(_key_or_null, _value_utf8) \ {.func = _mongoc_structured_log_append_utf8, .arg1.utf8 = (_key_or_null), .arg2.utf8 = (_value_utf8)}, /** * @def utf8_n(key, value, value_len) * @brief Structured log item, referencing a utf8 string value with explicit length. * * @param key Document key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value UTF8 value as a const char * expression, or NULL for a null value. May have embedded NUL bytes. * @param value_len UTF8 value length in bytes, as an int32_t expression. */ #define _mongoc_structured_log_item_utf8_n(_key_literal, _value_utf8, _value_len) \ _mongoc_structured_log_item_utf8_nn (_key_literal, strlen (_key_literal), _value_utf8, _value_len) /** * @def utf8_nn(key, key_len, value, value_len) * @brief Structured log item, referencing a utf8 string with explicit key and value lengths. * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param key_len UTF8 value length in bytes, as an int32_t expression. * @param value UTF8 value as a const char * expression, or NULL for a null value. May have embedded NUL bytes. * @param value_len UTF8 value length in bytes, as an int32_t expression. */ #define _mongoc_structured_log_item_utf8_nn(_key_or_null, _key_len, _value_utf8, _value_len) \ {.func = _mongoc_structured_log_append_utf8_n_stage0, .arg1.utf8 = (_key_or_null), .arg2.int32 = (_key_len)}, \ {.func = _mongoc_structured_log_append_utf8_n_stage1, .arg1.utf8 = (_value_utf8), .arg2.int32 = (_value_len)}, /** * @def int32(key, value) * @brief Structured log item, 32-bit integer * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value Value as an int32_t expression. */ #define _mongoc_structured_log_item_int32(_key_or_null, _value_int32) \ {.func = _mongoc_structured_log_append_int32, .arg1.utf8 = (_key_or_null), .arg2.int32 = (_value_int32)}, /** * @def int64(key, value) * @brief Structured log item, 64-bit integer * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value Value as an int64_t expression. */ #define _mongoc_structured_log_item_int64(_key_or_null, _value_int64) \ {.func = _mongoc_structured_log_append_int64, .arg1.utf8 = (_key_or_null), .arg2.int64 = (_value_int64)}, /** * @def double(key, value) * @brief Structured log item, double precision floating point * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value Value as a double expression. */ #define _mongoc_structured_log_item_double(_key_or_null, _value_double) \ {.func = _mongoc_structured_log_append_double, .arg1.utf8 = (_key_or_null), .arg2.double_value = (_value_double)}, /** * @def boolean(key, value) * @brief Structured log item, boolean * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value Value as a bool expression. */ #define _mongoc_structured_log_item_boolean(_key_or_null, _value_boolean) \ {.func = _mongoc_structured_log_append_boolean, .arg1.utf8 = (_key_or_null), .arg2.boolean = (_value_boolean)}, /** * @def error(key, value) * @brief Structured log item, bson_error_t document * * Serializes the fields of a bson_error_t as a subdocument with the indicated key. * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value Error as a const bson_error_t * expression, or NULL for a null value. */ #define _mongoc_structured_log_item_error(_key_or_null, _error_or_null) \ {.func = _mongoc_structured_log_append_error, .arg1.utf8 = (_key_or_null), .arg2.error = (_error_or_null)}, /** * @def read_prefs(key, value) * @brief Structured log item, mongoc_read_prefs_t document * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value Value as a const mongoc_read_prefs_t * expression. NULL is equivalent to Primary read preference. * */ #define _mongoc_structured_log_item_read_prefs(_key_or_null, _value_read_prefs) \ {.func = _mongoc_structured_log_append_read_prefs, \ .arg1.utf8 = (_key_or_null), \ .arg2.read_prefs = (_value_read_prefs)}, /** * @def oid(key, value) * @brief Structured log item, bson_oid_t * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value OID as a const bson_oid_t * expression, or NULL for a null value. */ #define _mongoc_structured_log_item_oid(_key_or_null, _value_oid) \ {.func = _mongoc_structured_log_append_oid, .arg1.utf8 = (_key_or_null), .arg2.oid = (_value_oid)}, /** * @def oid_as_hex(key, value) * @brief Structured log item, bson_oid_t converted to a hex string * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value OID to convert as a const bson_oid_t * expression, or NULL for a null value. */ #define _mongoc_structured_log_item_oid_as_hex(_key_or_null, _value_oid) \ {.func = _mongoc_structured_log_append_oid_as_hex, .arg1.utf8 = (_key_or_null), .arg2.oid = (_value_oid)}, /** * @def bson_as_json(key, value) * @brief Structured log item, bson_t converted to a JSON string * * Always uses relaxed extended JSON format, and the current applicable * maximum document length for structured logging. * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value BSON to convert as a const bson_t * expression, or NULL for a null value. */ #define _mongoc_structured_log_item_bson_as_json(_key_or_null, _value_bson) \ {.func = _mongoc_structured_log_append_bson_as_json, .arg1.utf8 = (_key_or_null), .arg2.bson = (_value_bson)}, /** * @def topology_description_as_json(key, value) * @brief Structured log item, mongoc_topology_description_t serialized into a json string * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param value Topology description as a const mongoc_topology_description_t * expression, or NULL for a null value. */ #define _mongoc_structured_log_item_topology_description_as_json(_key_or_null, _value_topology_description) \ {.func = _mongoc_structured_log_append_topology_description_as_json, \ .arg1.utf8 = (_key_or_null), \ .arg2.topology_description = (_value_topology_description)}, /** * @def topology_as_description_json(key, topology) * @brief Structured log item, current description from a mongoc_topology_t serialized into a json string * * @param key Key as a NUL-terminated const char * expression, or NULL to skip this item. * @param topology Topology as a const mongoc_topology_t * expression, or NULL for a null value. */ #define _mongoc_structured_log_item_topology_as_description_json(_key_or_null, _topology) \ {.func = _mongoc_structured_log_append_topology_as_description_json, \ .arg1.utf8 = (_key_or_null), \ .arg2.topology = (_topology)}, typedef enum { MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG_COMMAND = (1 << 0), MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG_DATABASE_NAME = (1 << 1), MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG_COMMAND_NAME = (1 << 2), MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG_OPERATION_ID = (1 << 3), } mongoc_structured_log_cmd_content_flags_t; /** * @def cmd(cmd, ...) * @brief Structured log item, mongoc_cmd_t fields with automatic redaction * * @param cmd Borrowed command reference, as a const mongo_cmd_t * expression. Required. * @param ... Fields to include. Order is not significant. Any of: COMMAND, DATABASE_NAME, COMMAND_NAME, OPERATION_ID. * */ #define _mongoc_structured_log_item_cmd(_cmd, ...) \ {.func = _mongoc_structured_log_append_cmd, \ .arg1.cmd = (_cmd), \ .arg2.cmd_flags = \ (0 _bsonDSL_mapMacro (_mongoc_structured_log_flag_expr, MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG, __VA_ARGS__))}, /** * @def cmd_reply(cmd, reply) * @brief Structured log item, command reply for mongoc_cmd_t with automatic redaction * * @param cmd Borrowed command reference, as a const mongo_cmd_t * expression. Required. * @param reply Borrowed reference to reply document, as a const bson_t * expression. Required. */ #define _mongoc_structured_log_item_cmd_reply(_cmd, _reply_bson) \ {.func = _mongoc_structured_log_append_cmd_reply, .arg1.cmd = (_cmd), .arg2.bson = (_reply_bson)}, /** * @def cmd_name_reply(cmd_name, reply) * @brief Structured log item, reply for named command with automatic redaction * * For cases where a mongo_cmd_t is not available; makes redaction decisions based * on command name but not body, so it's unsuitable for the "hello" reply. * * @param cmd_name Command name as a const char * expression. Required. * @param reply Borrowed reference to reply document, as a const bson_t * expression. Required. */ #define _mongoc_structured_log_item_cmd_name_reply(_cmd_name, _reply_bson) \ {.func = _mongoc_structured_log_append_cmd_name_reply, .arg1.utf8 = (_cmd_name), .arg2.bson = (_reply_bson)}, /** * @def cmd_failure(cmd, reply, error) * @brief Structured log item, failure for mongoc_cmd_t with automatic redaction * * The 'error' is examined to determine whether this is a client-side or server-side failure. * The command's name and body may influence the reply's redaction. * * @param cmd Borrowed command reference, as a const mongo_cmd_t * expression. Required. * @param reply Borrowed reference to reply document, as a const bson_t * expression. Required. * @param error Borrowed reference to a libmongoc error, as a const bson_error_t * expression. Required. */ #define _mongoc_structured_log_item_cmd_failure(_cmd, _reply_bson, _error) \ {.func = _mongoc_structured_log_append_cmd_failure_stage0, .arg1.cmd = (_cmd), .arg2.bson = (_reply_bson)}, \ {.func = _mongoc_structured_log_append_cmd_failure_stage1, .arg1.error = (_error)}, /** * @def cmd_name_failure(cmd_name, reply, error) * @brief Structured log item, failure for named command with automatic redaction * * For cases where a mongo_cmd_t is not available; makes redaction decisions based * on command name but not body, so it's unsuitable for "hello" errors. * * The 'error' is examined to determine whether this is a client-side or server-side failure. * The command's name and body may influence the reply's redaction. * * @param cmd_name Command name as a const char * expression. Required. * @param reply Borrowed reference to reply document, as a const bson_t * expression. Required. * @param error Borrowed reference to a libmongoc error, as a const bson_error_t * expression. Required. */ #define _mongoc_structured_log_item_cmd_name_failure(_cmd_name, _reply_bson, _error) \ {.func = _mongoc_structured_log_append_cmd_name_failure_stage0, \ .arg1.utf8 = (_cmd_name), \ .arg2.bson = (_reply_bson)}, \ {.func = _mongoc_structured_log_append_cmd_name_failure_stage1, .arg1.error = (_error)}, /** * @def server_description(sd, ...) * @brief Structured log item, mongoc_server_description_t fields * * @param sd Borrowed server description reference, as a const mongoc_server_description_t * expression. Required. * @param ... Fields to include. Order is not significant. Any of: TYPE, ADDRESS, SERVER_HOST, SERVER_PORT, * SERVER_CONNECTION_ID, SERVICE_ID. * */ #define _mongoc_structured_log_item_server_description(_server_description, ...) \ {.func = _mongoc_structured_log_append_server_description, \ .arg1.server_description = (_server_description), \ .arg2.server_description_flags = \ (0 _bsonDSL_mapMacro (_mongoc_structured_log_flag_expr, MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG, __VA_ARGS__))}, /** * @def monotonic_time_duration(duration) * @brief Structured log item, standard format for a duration in monotonic time. * @param duration Duration in microseconds, as an int64_t expression. */ #define _mongoc_structured_log_item_monotonic_time_duration(_duration) \ _mongoc_structured_log_item_double ("durationMS", (_duration) * 1e-3) typedef struct mongoc_structured_log_builder_stage_t mongoc_structured_log_builder_stage_t; typedef const mongoc_structured_log_builder_stage_t *(*mongoc_structured_log_builder_func_t) ( bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); struct mongoc_structured_log_builder_stage_t { // Why "stages" instead of a variable size argument list per item? // This approach keeps function pointers and other types of data // separated, reducing opportunities for malicious control flow. // Most items are one stage. Items that need more arguments can use // multiple consecutive stages, leaving the extra stages' function // pointers unused and set to placeholder values which can be checked. mongoc_structured_log_builder_func_t func; // NULL sentinel here union { const bson_error_t *error; const char *utf8; const mongoc_cmd_t *cmd; const mongoc_server_description_t *server_description; } arg1; union { bool boolean; const bson_error_t *error; const bson_oid_t *oid; const bson_t *bson; const char *utf8; const mongoc_read_prefs_t *read_prefs; const struct _mongoc_topology_description_t *topology_description; const struct _mongoc_topology_t *topology; double double_value; int32_t int32; int64_t int64; mongoc_error_content_flags_t error_flags; mongoc_server_description_content_flags_t server_description_flags; mongoc_structured_log_cmd_content_flags_t cmd_flags; } arg2; // Avoid adding an arg3, prefer to use additional stages }; typedef struct mongoc_structured_log_envelope_t { mongoc_structured_log_instance_t *instance; mongoc_structured_log_level_t level; mongoc_structured_log_component_t component; const char *message; } mongoc_structured_log_envelope_t; struct mongoc_structured_log_entry_t { mongoc_structured_log_envelope_t envelope; const mongoc_structured_log_builder_stage_t *builder; // Required }; void mongoc_structured_log_get_handler (const mongoc_structured_log_opts_t *opts, mongoc_structured_log_func_t *log_func, void **user_data); bool _mongoc_structured_log_should_log (const mongoc_structured_log_envelope_t *envelope); void _mongoc_structured_log_with_entry (const mongoc_structured_log_entry_t *entry); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_utf8 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_utf8_n_stage0 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_utf8_n_stage1 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_int32 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_int64 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_double (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_boolean (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_error (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_oid_as_hex (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_oid (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_bson_as_json (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_reply (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_name_reply (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_failure_stage0 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_failure_stage1 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_name_failure_stage0 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_name_failure_stage1 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_server_description (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_topology_description_as_json (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_topology_as_description_json (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_read_prefs (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts); BSON_END_DECLS #endif /* MONGOC_STRUCTURED_LOG_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-structured-log.c0000644000175100001660000012762114760300420024126 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #define STRUCTURED_LOG_COMPONENT_TABLE_SIZE (1 + (size_t) MONGOC_STRUCTURED_LOG_COMPONENT_CONNECTION) // Environment variables with default level for each log component static const char *gStructuredLogComponentEnvVars[] = { "MONGODB_LOG_COMMAND", "MONGODB_LOG_TOPOLOGY", "MONGODB_LOG_SERVER_SELECTION", "MONGODB_LOG_CONNECTION"}; // Canonical names for log components static const char *gStructuredLogComponentNames[] = {"command", "topology", "serverSelection", "connection"}; // Canonical names for log levels static const char *gStructuredLogLevelNames[] = { "Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Informational", "Debug", "Trace"}; // Additional valid names for log levels static const struct { const char *name; mongoc_structured_log_level_t level; } gStructuredLogLevelAliases[] = {{.name = "off", .level = (mongoc_structured_log_level_t) 0}, {.name = "warn", .level = MONGOC_STRUCTURED_LOG_LEVEL_WARNING}, {.name = "info", .level = MONGOC_STRUCTURED_LOG_LEVEL_INFO}}; // Shared mutable data for the default handler typedef struct mongoc_structured_log_default_handler_shared_t { bson_mutex_t mutex; FILE *stream; bool stream_fclose_on_destroy; } mongoc_structured_log_default_handler_shared_t; struct mongoc_structured_log_opts_t { mongoc_structured_log_func_t handler_func; void *handler_user_data; mongoc_structured_log_level_t max_level_per_component[STRUCTURED_LOG_COMPONENT_TABLE_SIZE]; uint32_t max_document_length; char *default_handler_path; }; struct mongoc_structured_log_instance_t { struct mongoc_structured_log_opts_t opts; // Immutable capture of log_opts, func != NULL mongoc_structured_log_default_handler_shared_t default_handler_shared; // Inner mutability }; bson_t * mongoc_structured_log_entry_message_as_bson (const mongoc_structured_log_entry_t *entry) { BSON_ASSERT_PARAM (entry); bson_t *bson = bson_new (); BSON_APPEND_UTF8 (bson, "message", entry->envelope.message); const mongoc_structured_log_builder_stage_t *stage = entry->builder; const mongoc_structured_log_opts_t *opts = &entry->envelope.instance->opts; while (stage->func) { stage = stage->func (bson, stage, opts); } return bson; } mongoc_structured_log_level_t mongoc_structured_log_entry_get_level (const mongoc_structured_log_entry_t *entry) { BSON_ASSERT_PARAM (entry); return entry->envelope.level; } mongoc_structured_log_component_t mongoc_structured_log_entry_get_component (const mongoc_structured_log_entry_t *entry) { BSON_ASSERT_PARAM (entry); return entry->envelope.component; } const char * mongoc_structured_log_entry_get_message_string (const mongoc_structured_log_entry_t *entry) { // Note that 'message' happens to have static lifetime right now (all messages are literals) // but our API only guarantees a lifetime that matches 'entry'. BSON_ASSERT_PARAM (entry); return entry->envelope.message; } mongoc_structured_log_level_t mongoc_structured_log_opts_get_max_level_for_component (const mongoc_structured_log_opts_t *opts, mongoc_structured_log_component_t component) { BSON_ASSERT_PARAM (opts); unsigned table_index = (unsigned) component; if (table_index < STRUCTURED_LOG_COMPONENT_TABLE_SIZE) { return opts->max_level_per_component[table_index]; } else { // As documented, unknown component enums return the lowest possible log level. return MONGOC_STRUCTURED_LOG_LEVEL_EMERGENCY; } } void mongoc_structured_log_opts_set_handler (mongoc_structured_log_opts_t *opts, mongoc_structured_log_func_t log_func, void *user_data) { BSON_ASSERT_PARAM (opts); opts->handler_func = log_func; opts->handler_user_data = user_data; } void mongoc_structured_log_get_handler (const mongoc_structured_log_opts_t *opts, mongoc_structured_log_func_t *log_func, void **user_data) { BSON_ASSERT_PARAM (opts); *log_func = opts->handler_func; *user_data = opts->handler_user_data; } bool mongoc_structured_log_opts_set_max_level_for_component (mongoc_structured_log_opts_t *opts, mongoc_structured_log_component_t component, mongoc_structured_log_level_t level) { BSON_ASSERT_PARAM (opts); if (level >= MONGOC_STRUCTURED_LOG_LEVEL_EMERGENCY && level <= MONGOC_STRUCTURED_LOG_LEVEL_TRACE) { unsigned table_index = (unsigned) component; if (table_index < STRUCTURED_LOG_COMPONENT_TABLE_SIZE) { opts->max_level_per_component[table_index] = level; return true; } } return false; } bool mongoc_structured_log_opts_set_max_level_for_all_components (mongoc_structured_log_opts_t *opts, mongoc_structured_log_level_t level) { BSON_ASSERT_PARAM (opts); for (int component = 0; component < STRUCTURED_LOG_COMPONENT_TABLE_SIZE; component++) { if (!mongoc_structured_log_opts_set_max_level_for_component ( opts, (mongoc_structured_log_component_t) component, level)) { // Fine to stop on the first error, always means 'level' is wrong and none of these will succeed. return false; } } return true; } bool _mongoc_structured_log_should_log (const mongoc_structured_log_envelope_t *envelope) { // Note that the instance's max_level_per_component table will also be // set to zeroes if logging is disabled. See mongoc_structured_log_instance_new. unsigned table_index = (unsigned) envelope->component; BSON_ASSERT (table_index < STRUCTURED_LOG_COMPONENT_TABLE_SIZE); return envelope->level <= envelope->instance->opts.max_level_per_component[table_index]; } void _mongoc_structured_log_with_entry (const mongoc_structured_log_entry_t *entry) { // By now, func is not allowed to be NULL. See mongoc_structured_log_instance_new. mongoc_structured_log_instance_t *instance = entry->envelope.instance; mongoc_structured_log_func_t func = instance->opts.handler_func; BSON_ASSERT (func); func (entry, instance->opts.handler_user_data); } static bool _mongoc_structured_log_get_log_level_from_env (const char *variable, mongoc_structured_log_level_t *out, int volatile *err_flag_atomic) { char *level = _mongoc_getenv (variable); if (!level) { return false; } bool result = mongoc_structured_log_get_named_level (level, out); if (!result) { // Only log the first instance of each error per process if (0 == mcommon_atomic_int_compare_exchange_strong (err_flag_atomic, 0, 1, mcommon_memory_order_seq_cst)) { MONGOC_WARNING ("Invalid log level '%s' read from environment variable %s. Ignoring it.", level, variable); } } bson_free (level); return result; } const char * mongoc_structured_log_get_level_name (mongoc_structured_log_level_t level) { unsigned table_index = (unsigned) level; const size_t table_size = sizeof gStructuredLogLevelNames / sizeof gStructuredLogLevelNames[0]; return table_index < table_size ? gStructuredLogLevelNames[table_index] : NULL; } bool mongoc_structured_log_get_named_level (const char *name, mongoc_structured_log_level_t *out) { BSON_ASSERT_PARAM (name); BSON_ASSERT_PARAM (out); // First check canonical names { const size_t table_size = sizeof gStructuredLogLevelNames / sizeof gStructuredLogLevelNames[0]; for (unsigned table_index = 0; table_index < table_size; table_index++) { if (!strcasecmp (name, gStructuredLogLevelNames[table_index])) { *out = (mongoc_structured_log_level_t) table_index; return true; } } } // Check additional acceptable names { const size_t table_size = sizeof gStructuredLogLevelAliases / sizeof gStructuredLogLevelAliases[0]; for (unsigned table_index = 0; table_index < table_size; table_index++) { const char *alias = gStructuredLogLevelAliases[table_index].name; mongoc_structured_log_level_t level = gStructuredLogLevelAliases[table_index].level; if (!strcasecmp (name, alias)) { *out = level; return true; } } } return false; } const char * mongoc_structured_log_get_component_name (mongoc_structured_log_component_t component) { unsigned table_index = (unsigned) component; const size_t table_size = sizeof gStructuredLogComponentNames / sizeof gStructuredLogComponentNames[0]; return table_index < table_size ? gStructuredLogComponentNames[table_index] : NULL; } bool mongoc_structured_log_get_named_component (const char *name, mongoc_structured_log_component_t *out) { BSON_ASSERT_PARAM (name); BSON_ASSERT_PARAM (out); const size_t table_size = sizeof gStructuredLogComponentNames / sizeof gStructuredLogComponentNames[0]; for (unsigned table_index = 0; table_index < table_size; table_index++) { if (!strcasecmp (name, gStructuredLogComponentNames[table_index])) { *out = (mongoc_structured_log_component_t) table_index; return true; } } return false; } size_t mongoc_structured_log_opts_get_max_document_length (const mongoc_structured_log_opts_t *opts) { return (size_t) opts->max_document_length; } bool mongoc_structured_log_opts_set_max_document_length (mongoc_structured_log_opts_t *opts, size_t max_document_length) { if (max_document_length <= (size_t) MONGOC_STRUCTURED_LOG_MAXIMUM_MAX_DOCUMENT_LENGTH) { opts->max_document_length = (uint32_t) max_document_length; return true; } else { return false; } } bool mongoc_structured_log_opts_set_max_document_length_from_env (mongoc_structured_log_opts_t *opts) { BSON_ASSERT_PARAM (opts); const char *variable = "MONGODB_LOG_MAX_DOCUMENT_LENGTH"; char *max_length_str = _mongoc_getenv (variable); if (!max_length_str) { return true; } bool result = false; if (!strcasecmp (max_length_str, "unlimited")) { BSON_ASSERT ( mongoc_structured_log_opts_set_max_document_length (opts, MONGOC_STRUCTURED_LOG_MAXIMUM_MAX_DOCUMENT_LENGTH)); result = true; } else { char *endptr; long int_value = strtol (max_length_str, &endptr, 10); if (int_value >= 0 && endptr != max_length_str && *endptr == '\0' && mcommon_in_range_signed (size_t, int_value) && mongoc_structured_log_opts_set_max_document_length (opts, (size_t) int_value)) { result = true; } } if (!result) { // Only log the first instance of each error per process static int err_flag_atomic; if (0 == mcommon_atomic_int_compare_exchange_strong (&err_flag_atomic, 0, 1, mcommon_memory_order_seq_cst)) { MONGOC_WARNING ( "Invalid length '%s' read from environment variable %s. Ignoring it.", max_length_str, variable); } } bson_free (max_length_str); return result; } bool mongoc_structured_log_opts_set_max_levels_from_env (mongoc_structured_log_opts_t *opts) { BSON_ASSERT_PARAM (opts); bool all_ok = true; mongoc_structured_log_level_t level; // Errors are not fatal by default; always reported by return value, and reported the first time only via a log // warning. static int err_flag_all_atomic; static int err_flag_per_component_atomic[STRUCTURED_LOG_COMPONENT_TABLE_SIZE]; if (_mongoc_structured_log_get_log_level_from_env ("MONGODB_LOG_ALL", &level, &err_flag_all_atomic)) { BSON_ASSERT (mongoc_structured_log_opts_set_max_level_for_all_components (opts, level)); } else { all_ok = false; } for (int component = 0; component < STRUCTURED_LOG_COMPONENT_TABLE_SIZE; component++) { if (_mongoc_structured_log_get_log_level_from_env ( gStructuredLogComponentEnvVars[component], &level, &err_flag_per_component_atomic[component])) { BSON_ASSERT (mongoc_structured_log_opts_set_max_level_for_component ( opts, (mongoc_structured_log_component_t) component, level)); } else { all_ok = false; } } return all_ok; } static void _mongoc_structured_log_default_handler_open_stream (mongoc_structured_log_default_handler_shared_t *shared, const char *path) { // shared->mutex must already be locked if (!path || !strcasecmp (path, "stderr")) { // Default or explicit stderr shared->stream = stderr; shared->stream_fclose_on_destroy = false; } else if (!strcasecmp (path, "stdout")) { shared->stream = stdout; shared->stream_fclose_on_destroy = false; } else { FILE *file = fopen (path, "a"); if (file) { shared->stream = file; shared->stream_fclose_on_destroy = true; } else { char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; const char *errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf); MONGOC_WARNING ("Failed to open log file '%s' with error: '%s'. Logging to stderr instead.", path, errmsg); shared->stream = stderr; shared->stream_fclose_on_destroy = false; } } } static FILE * _mongoc_structured_log_default_handler_get_stream (mongoc_structured_log_instance_t *instance) { // instance->default_handler_shared->mutex must already be locked { FILE *log_stream = instance->default_handler_shared.stream; if (log_stream) { return log_stream; } } _mongoc_structured_log_default_handler_open_stream (&instance->default_handler_shared, instance->opts.default_handler_path); { FILE *log_stream = instance->default_handler_shared.stream; BSON_ASSERT (log_stream); return log_stream; } } static void _mongoc_structured_log_default_handler (const mongoc_structured_log_entry_t *entry, void *user_data) { BSON_UNUSED (user_data); mongoc_structured_log_instance_t *instance = entry->envelope.instance; // We can serialize the message before taking the default_handler_shared mutex bson_t *bson_message = mongoc_structured_log_entry_message_as_bson (entry); char *json_message = bson_as_relaxed_extended_json (bson_message, NULL); bson_destroy (bson_message); const char *level_name = mongoc_structured_log_get_level_name (mongoc_structured_log_entry_get_level (entry)); const char *component_name = mongoc_structured_log_get_component_name (mongoc_structured_log_entry_get_component (entry)); bson_mutex_lock (&instance->default_handler_shared.mutex); fprintf (_mongoc_structured_log_default_handler_get_stream (instance), "MONGODB_LOG %s %s %s\n", level_name, component_name, json_message); bson_mutex_unlock (&instance->default_handler_shared.mutex); bson_free (json_message); } static void _mongoc_structured_log_no_handler (const mongoc_structured_log_entry_t *entry, void *user_data) { // Stub, for when logging is disabled. Only possible to call at MONGOC_STRUCTURED_LOG_LEVEL_EMERGENCY. BSON_UNUSED (entry); BSON_UNUSED (user_data); } mongoc_structured_log_opts_t * mongoc_structured_log_opts_new (void) { mongoc_structured_log_opts_t *opts = (mongoc_structured_log_opts_t *) bson_malloc0 (sizeof *opts); /* Capture default state from the environment now. * Note that error return values from mongoc_structured_log_opts_set_* must be ignored here. * If environment variables can't be parsed, warnings will be logged once but we must, by specification, * continue to provide structured logging using whatever valid or default settings remain. */ opts->default_handler_path = _mongoc_getenv ("MONGODB_LOG_PATH"); opts->max_document_length = MONGOC_STRUCTURED_LOG_DEFAULT_MAX_DOCUMENT_LENGTH; (void) mongoc_structured_log_opts_set_max_document_length_from_env (opts); (void) mongoc_structured_log_opts_set_max_level_for_all_components (opts, MONGOC_STRUCTURED_LOG_DEFAULT_LEVEL); (void) mongoc_structured_log_opts_set_max_levels_from_env (opts); // Set default handler. Its shared state is allocated later, as part of instance_t. mongoc_structured_log_opts_set_handler (opts, _mongoc_structured_log_default_handler, NULL); return opts; } void mongoc_structured_log_opts_destroy (mongoc_structured_log_opts_t *opts) { if (opts) { bson_free (opts->default_handler_path); bson_free (opts); } } mongoc_structured_log_instance_t * mongoc_structured_log_instance_new (const mongoc_structured_log_opts_t *opts) { /* Creating the instance captures an immutable copy of the options. * We also make a transformation that simplifies the critical path in * _mongoc_structured_log_should_log so that it only needs to check the * per-component table: In the instance, NULL handlers are no longer * allowed. If structured logging is disabled, the per-component table * will be set to the lowest possible levels and a stub handler function * is set in case of 'emergency' logs. * * 'opts' is optional; if NULL, structured logging is disabled. * (To request default options, you still need to use * mongoc_structured_log_opts_new) */ mongoc_structured_log_instance_t *instance = (mongoc_structured_log_instance_t *) bson_malloc0 (sizeof *instance); bson_mutex_init (&instance->default_handler_shared.mutex); if (opts) { instance->opts.default_handler_path = bson_strdup (opts->default_handler_path); instance->opts.max_document_length = opts->max_document_length; instance->opts.handler_func = opts->handler_func; instance->opts.handler_user_data = opts->handler_user_data; } if (instance->opts.handler_func) { if (opts) { memcpy (instance->opts.max_level_per_component, opts->max_level_per_component, sizeof instance->opts.max_level_per_component); } } else { // No handler; leave the max_level_per_component table zero'ed, and add a stub handler for emergency level only. instance->opts.handler_func = _mongoc_structured_log_no_handler; } return instance; } void mongoc_structured_log_instance_destroy (mongoc_structured_log_instance_t *instance) { if (instance) { bson_mutex_destroy (&instance->default_handler_shared.mutex); bson_free (instance->opts.default_handler_path); if (instance->default_handler_shared.stream_fclose_on_destroy) { fclose (instance->default_handler_shared.stream); } bson_free (instance); } } static mcommon_string_t * _mongoc_structured_log_append_json_truncation_marker (mcommon_string_append_t *append) { if (!mcommon_string_status_from_append (append)) { mcommon_string_append_t marker_append; mcommon_string_set_append (mcommon_string_from_append (append), &marker_append); mcommon_string_append (&marker_append, "..."); } // Guaranteed due to choice of MONGOC_STRUCTURED_LOG_MAXIMUM_MAX_DOCUMENT_LENGTH BSON_ASSERT (mcommon_strlen_from_append (append) <= (uint32_t) BSON_MAX_SIZE); return mcommon_string_from_append (append); } // Generic bson-to-json for documents that appear within a structured log message as truncated JSON static mcommon_string_t * _mongoc_structured_log_document_as_truncated_json (const bson_t *document, const mongoc_structured_log_opts_t *opts) { // Use the bson_t document length as an initial buffer capacity guess mcommon_string_append_t append; mcommon_string_set_append_with_limit ( mcommon_string_new_with_capacity ("", 0, document->len), &append, opts->max_document_length); if (mcommon_json_append_bson_document (&append, document, BSON_JSON_MODE_RELAXED, BSON_MAX_RECURSION)) { return _mongoc_structured_log_append_json_truncation_marker (&append); } else { mcommon_string_from_append_destroy (&append); return NULL; } } /** * @brief Specialized bson-to-json conversion for mongoc_cmd_t * @returns A new allocated mcommon_string_t, limited to the maximum document length from 'opts' plus the space for a * possible truncation marker. Returns NULL if an invalid BSON document is encountered. This is equivalent to * _mongoc_cmd_append_payload_as_array() combined with _mongoc_structured_log_document_as_truncated_json(), but it * avoids ever assembling a BSON representation of the complete logged JSON document. Each payload is serialized * separately using the mcommon_json_* functions. If we reach the maximum document length, unused portions of the input * command will not be read. */ static mcommon_string_t * _mongoc_structured_log_command_with_payloads_as_truncated_json (const mongoc_cmd_t *cmd, const mongoc_structured_log_opts_t *opts) { BSON_ASSERT_PARAM (cmd); BSON_ASSERT (!bson_empty0 (cmd->command)); BSON_ASSERT (cmd->payloads_count <= MONGOC_CMD_PAYLOADS_COUNT_MAX); // Use the bson length of the command itself as an initial buffer capacity guess. bool invalid_document = false; mcommon_string_append_t append; mcommon_string_set_append_with_limit ( mcommon_string_new_with_capacity ("", 0, cmd->command->len), &append, opts->max_document_length); if (!mcommon_string_append (&append, "{ ")) { goto done; } if (!mcommon_json_append_bson_values ( &append, cmd->command, BSON_JSON_MODE_RELAXED, true, BSON_MAX_RECURSION - 1u)) { invalid_document = true; goto done; } for (size_t i = 0; i < cmd->payloads_count; i++) { const char *field_name = cmd->payloads[i].identifier; BSON_ASSERT (field_name); // Each payload is an appended key containing a non-empty sequence of documents if (!mcommon_json_append_separator (&append) || !mcommon_json_append_key (&append, field_name, strlen (field_name)) || !mcommon_string_append (&append, "[ ")) { goto done; } const uint8_t *doc_begin = cmd->payloads[i].documents; BSON_ASSERT (doc_begin); const uint8_t *doc_end = doc_begin + cmd->payloads[i].size; BSON_ASSERT (doc_begin != doc_end); const uint8_t *doc_ptr = doc_begin; int32_t doc_len; while (doc_ptr + sizeof doc_len <= doc_end) { memcpy (&doc_len, doc_ptr, sizeof doc_len); doc_len = BSON_UINT32_FROM_LE (doc_len); bson_t doc; if (doc_len < 5 || (size_t) doc_len > (size_t) (doc_end - doc_ptr) || !bson_init_static (&doc, doc_ptr, (size_t) doc_len)) { invalid_document = true; goto done; } if (doc_ptr != doc_begin) { mcommon_json_append_separator (&append); } if (!mcommon_json_append_bson_document (&append, &doc, BSON_JSON_MODE_RELAXED, BSON_MAX_RECURSION - 2u)) { invalid_document = true; goto done; } doc_ptr += doc_len; } if (doc_ptr != doc_end) { invalid_document = true; goto done; } if (!mcommon_string_append (&append, " ]")) { goto done; } } mcommon_string_append (&append, " }"); done: if (invalid_document) { mcommon_string_from_append_destroy (&append); return NULL; } else { return _mongoc_structured_log_append_json_truncation_marker (&append); } } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_utf8 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const char *key_or_null = stage->arg1.utf8; if (key_or_null) { bson_append_utf8 (bson, key_or_null, -1, stage->arg2.utf8, -1); } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_utf8_n_stage0 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); BSON_ASSERT (stage[1].func == _mongoc_structured_log_append_utf8_n_stage1); const char *key_or_null = stage[0].arg1.utf8; int32_t key_len = stage[0].arg2.int32; const char *value = stage[1].arg1.utf8; int32_t value_len = stage[1].arg2.int32; if (key_or_null) { bson_append_utf8 (bson, key_or_null, key_len, value, value_len); } return stage + 2; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_utf8_n_stage1 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { // Never called, marks the second stage in a two-stage utf8_n BSON_UNUSED (bson); BSON_UNUSED (stage); BSON_UNUSED (opts); BSON_ASSERT (false); return NULL; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_int32 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const char *key_or_null = stage->arg1.utf8; if (key_or_null) { bson_append_int32 (bson, key_or_null, -1, stage->arg2.int32); } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_int64 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const char *key_or_null = stage->arg1.utf8; if (key_or_null) { bson_append_int64 (bson, key_or_null, -1, stage->arg2.int64); } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_double (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const char *key_or_null = stage->arg1.utf8; if (key_or_null) { bson_append_double (bson, key_or_null, -1, stage->arg2.double_value); } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_boolean (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const char *key_or_null = stage->arg1.utf8; if (key_or_null) { bson_append_bool (bson, key_or_null, -1, stage->arg2.boolean); } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_oid (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const char *key_or_null = stage->arg1.utf8; const bson_oid_t *oid_or_null = stage->arg2.oid; if (key_or_null) { if (oid_or_null) { bson_append_oid (bson, key_or_null, -1, oid_or_null); } else { bson_append_null (bson, key_or_null, -1); } } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_oid_as_hex (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const char *key_or_null = stage->arg1.utf8; const bson_oid_t *oid_or_null = stage->arg2.oid; if (key_or_null) { if (oid_or_null) { char str[25]; bson_oid_to_string (oid_or_null, str); bson_append_utf8 (bson, key_or_null, -1, str, 24); } else { bson_append_null (bson, key_or_null, -1); } } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_bson_as_json (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { const char *key_or_null = stage->arg1.utf8; const bson_t *bson_or_null = stage->arg2.bson; if (key_or_null) { if (bson_or_null) { mcommon_string_t *json = _mongoc_structured_log_document_as_truncated_json (bson_or_null, opts); if (json) { BSON_ASSERT (json->len <= (uint32_t) INT_MAX); bson_append_utf8 (bson, key_or_null, -1, json->str, (int) json->len); mcommon_string_destroy (json); } // If invalid BSON was found in the input, the key is not logged. } else { bson_append_null (bson, key_or_null, -1); } } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { const mongoc_cmd_t *cmd = stage->arg1.cmd; const mongoc_structured_log_cmd_content_flags_t flags = stage->arg2.cmd_flags; BSON_ASSERT (cmd); if (flags & MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG_DATABASE_NAME) { BSON_APPEND_UTF8 (bson, "databaseName", cmd->db_name); } if (flags & MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG_COMMAND_NAME) { BSON_APPEND_UTF8 (bson, "commandName", cmd->command_name); } if (flags & MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG_OPERATION_ID) { BSON_APPEND_INT64 (bson, "operationId", cmd->operation_id); } if (flags & MONGOC_STRUCTURED_LOG_CMD_CONTENT_FLAG_COMMAND) { if (mongoc_apm_is_sensitive_command_message (cmd->command_name, cmd->command)) { BSON_APPEND_UTF8 (bson, "command", "{}"); } else { mcommon_string_t *json = _mongoc_structured_log_command_with_payloads_as_truncated_json (cmd, opts); if (json) { const char *key = "command"; BSON_ASSERT (json->len <= (uint32_t) INT_MAX); bson_append_utf8 (bson, key, strlen (key), json->str, (int) json->len); mcommon_string_destroy (json); } // If invalid BSON was found in the input, the key is not logged. } } return stage + 1; } static void _mongoc_structured_log_append_redacted_cmd_reply (bson_t *bson, bool is_sensitive, const bson_t *reply, const mongoc_structured_log_opts_t *opts) { if (is_sensitive) { BSON_APPEND_UTF8 (bson, "reply", "{}"); } else { mcommon_string_t *json = _mongoc_structured_log_document_as_truncated_json (reply, opts); if (json) { const char *key = "reply"; BSON_ASSERT (json->len <= (uint32_t) INT_MAX); bson_append_utf8 (bson, key, strlen (key), json->str, (int) json->len); mcommon_string_destroy (json); } // If invalid BSON was found in the input, the key is not logged. } } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_reply (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { const mongoc_cmd_t *cmd = stage->arg1.cmd; const bson_t *reply = stage->arg2.bson; BSON_ASSERT (cmd); BSON_ASSERT (reply); bool is_sensitive = mongoc_apm_is_sensitive_command_message (cmd->command_name, cmd->command) || mongoc_apm_is_sensitive_command_message (cmd->command_name, reply); _mongoc_structured_log_append_redacted_cmd_reply (bson, is_sensitive, reply, opts); return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_name_reply (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { const char *cmd_name = stage->arg1.utf8; const bson_t *reply = stage->arg2.bson; BSON_ASSERT (cmd_name); BSON_ASSERT (reply); bool is_sensitive = mongoc_apm_is_sensitive_command_message (cmd_name, reply); _mongoc_structured_log_append_redacted_cmd_reply (bson, is_sensitive, reply, opts); return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_error (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { const char *key_or_null = stage->arg1.utf8; const bson_error_t *error_or_null = stage->arg2.error; if (key_or_null) { if (error_or_null) { bson_t child; if (BSON_APPEND_DOCUMENT_BEGIN (bson, key_or_null, &child)) { mongoc_error_append_contents_to_bson (error_or_null, &child, MONGOC_ERROR_CONTENT_FLAG_MESSAGE | MONGOC_ERROR_CONTENT_FLAG_CODE | MONGOC_ERROR_CONTENT_FLAG_DOMAIN); bson_append_document_end (bson, &child); } } else { bson_append_null (bson, key_or_null, -1); } } return stage + 1; } static void _mongoc_structured_log_append_redacted_cmd_failure (bson_t *bson, bool is_sensitive, const bson_t *reply, const bson_error_t *error) { bool is_server_side = error->domain == MONGOC_ERROR_SERVER || error->domain == MONGOC_ERROR_WRITE_CONCERN_ERROR; if (is_server_side) { if (is_sensitive) { // Redacted server-side message, must be a document with at most 'code', 'codeName', 'errorLabels' bson_t failure; bson_iter_t iter; if (BSON_APPEND_DOCUMENT_BEGIN (bson, "failure", &failure)) { bson_iter_init (&iter, reply); while (bson_iter_next (&iter)) { const char *key = bson_iter_key (&iter); if (!strcmp (key, "code") || !strcmp (key, "codeName") || !strcmp (key, "errorLabels")) { bson_append_iter (&failure, key, bson_iter_key_len (&iter), &iter); } } bson_append_document_end (bson, &failure); } } else { // Non-redacted server side message, pass through BSON_APPEND_DOCUMENT (bson, "failure", reply); } } else { /* Client-side errors converted directly from bson_error_t, never redacted. * In addition to the bson_error_t fields, client side errors may include errorLabels: * https://mongoc.org/libmongoc/current/errors.html#error-labels */ bson_t failure; if (BSON_APPEND_DOCUMENT_BEGIN (bson, "failure", &failure)) { mongoc_error_append_contents_to_bson (error, &failure, MONGOC_ERROR_CONTENT_FLAG_MESSAGE | MONGOC_ERROR_CONTENT_FLAG_CODE | MONGOC_ERROR_CONTENT_FLAG_DOMAIN); bson_iter_t iter; if (bson_iter_init_find (&iter, reply, "errorLabels")) { bson_append_iter (&failure, bson_iter_key (&iter), bson_iter_key_len (&iter), &iter); } bson_append_document_end (bson, &failure); } } } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_failure_stage0 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); BSON_ASSERT (stage[1].func == _mongoc_structured_log_append_cmd_failure_stage1); const mongoc_cmd_t *cmd = stage[0].arg1.cmd; const bson_t *reply = stage[0].arg2.bson; const bson_error_t *error = stage[1].arg1.error; BSON_ASSERT (cmd); BSON_ASSERT (reply); BSON_ASSERT (error); bool is_sensitive = mongoc_apm_is_sensitive_command_message (cmd->command_name, cmd->command) || mongoc_apm_is_sensitive_command_message (cmd->command_name, reply); _mongoc_structured_log_append_redacted_cmd_failure (bson, is_sensitive, reply, error); return stage + 2; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_failure_stage1 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { // Never called, marks the second stage in a two-stage cmd_failure BSON_UNUSED (bson); BSON_UNUSED (stage); BSON_UNUSED (opts); BSON_ASSERT (false); return NULL; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_name_failure_stage0 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); BSON_ASSERT (stage[1].func == _mongoc_structured_log_append_cmd_name_failure_stage1); const char *cmd_name = stage[0].arg1.utf8; const bson_t *reply = stage[0].arg2.bson; const bson_error_t *error = stage[1].arg1.error; BSON_ASSERT (cmd_name); BSON_ASSERT (reply); BSON_ASSERT (error); bool is_sensitive = mongoc_apm_is_sensitive_command_message (cmd_name, reply); _mongoc_structured_log_append_redacted_cmd_failure (bson, is_sensitive, reply, error); return stage + 2; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_cmd_name_failure_stage1 (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { // Never called, marks the second stage in a two-stage cmd_name_failure BSON_UNUSED (bson); BSON_UNUSED (stage); BSON_UNUSED (opts); BSON_ASSERT (false); return NULL; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_server_description (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const mongoc_server_description_t *sd = stage->arg1.server_description; const mongoc_server_description_content_flags_t flags = stage->arg2.server_description_flags; mongoc_server_description_append_contents_to_bson (sd, bson, flags); return stage + 1; } static mcommon_string_t * _mongoc_structured_log_topology_description_as_json (const mongoc_topology_description_t *td, const mongoc_structured_log_opts_t *opts) { const mongoc_topology_description_content_flags_t td_flags = MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_TYPE | MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_SET_NAME | MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_MAX_ELECTION_ID | MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_MAX_SET_VERSION | MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_SERVERS | MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_STALE | MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_COMPATIBLE | MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_COMPATIBILITY_ERROR | MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_LOGICAL_SESSION_TIMEOUT_MINUTES; const mongoc_server_description_content_flags_t server_flags = MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_TYPE | MONGOC_SERVER_DESCRIPTION_CONTENT_FLAG_ADDRESS; bson_t doc = BSON_INITIALIZER; mongoc_topology_description_append_contents_to_bson (td, &doc, td_flags, server_flags); mcommon_string_t *result = _mongoc_structured_log_document_as_truncated_json (&doc, opts); bson_destroy (&doc); return result; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_topology_as_description_json (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { const char *key_or_null = stage->arg1.utf8; const mongoc_topology_t *topology_or_null = stage->arg2.topology; if (key_or_null) { if (topology_or_null) { mc_shared_tpld td = mc_tpld_take_ref (topology_or_null); mcommon_string_t *json = _mongoc_structured_log_topology_description_as_json (td.ptr, opts); if (json) { BSON_ASSERT (json->len <= (uint32_t) INT_MAX); bson_append_utf8 (bson, key_or_null, -1, json->str, (int) json->len); mcommon_string_destroy (json); } mc_tpld_drop_ref (&td); } else { bson_append_null (bson, key_or_null, -1); } } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_topology_description_as_json (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { const char *key_or_null = stage->arg1.utf8; const mongoc_topology_description_t *topology_description_or_null = stage->arg2.topology_description; if (key_or_null) { if (topology_description_or_null) { mcommon_string_t *json = _mongoc_structured_log_topology_description_as_json (topology_description_or_null, opts); if (json) { BSON_ASSERT (json->len <= (uint32_t) INT_MAX); bson_append_utf8 (bson, key_or_null, -1, json->str, (int) json->len); mcommon_string_destroy (json); } } else { bson_append_null (bson, key_or_null, -1); } } return stage + 1; } const mongoc_structured_log_builder_stage_t * _mongoc_structured_log_append_read_prefs (bson_t *bson, const mongoc_structured_log_builder_stage_t *stage, const mongoc_structured_log_opts_t *opts) { BSON_UNUSED (opts); const char *key_or_null = stage->arg1.utf8; const mongoc_read_prefs_t *read_prefs = stage->arg2.read_prefs; if (key_or_null) { bson_t child; if (BSON_APPEND_DOCUMENT_BEGIN (bson, key_or_null, &child)) { mongoc_read_prefs_append_contents_to_bson ( read_prefs, &child, MONGOC_READ_PREFS_CONTENT_FLAG_MODE | MONGOC_READ_PREFS_CONTENT_FLAG_TAGS | MONGOC_READ_PREFS_CONTENT_FLAG_MAX_STALENESS_SECONDS | MONGOC_READ_PREFS_CONTENT_FLAG_HEDGE); bson_append_document_end (bson, &child); } } return stage + 1; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-structured-log.h0000644000175100001660000001053314760300420024124 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_STRUCTURED_LOG_H #define MONGOC_STRUCTURED_LOG_H #include #include BSON_BEGIN_DECLS typedef enum { MONGOC_STRUCTURED_LOG_LEVEL_EMERGENCY = 0, MONGOC_STRUCTURED_LOG_LEVEL_ALERT = 1, MONGOC_STRUCTURED_LOG_LEVEL_CRITICAL = 2, MONGOC_STRUCTURED_LOG_LEVEL_ERROR = 3, MONGOC_STRUCTURED_LOG_LEVEL_WARNING = 4, MONGOC_STRUCTURED_LOG_LEVEL_NOTICE = 5, MONGOC_STRUCTURED_LOG_LEVEL_INFO = 6, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG = 7, MONGOC_STRUCTURED_LOG_LEVEL_TRACE = 8, } mongoc_structured_log_level_t; typedef enum { MONGOC_STRUCTURED_LOG_COMPONENT_COMMAND = 0, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY = 1, MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION = 2, MONGOC_STRUCTURED_LOG_COMPONENT_CONNECTION = 3, } mongoc_structured_log_component_t; typedef struct mongoc_structured_log_entry_t mongoc_structured_log_entry_t; typedef struct mongoc_structured_log_opts_t mongoc_structured_log_opts_t; typedef void (*mongoc_structured_log_func_t) (const mongoc_structured_log_entry_t *entry, void *user_data); MONGOC_EXPORT (mongoc_structured_log_opts_t *) mongoc_structured_log_opts_new (void); MONGOC_EXPORT (void) mongoc_structured_log_opts_destroy (mongoc_structured_log_opts_t *opts); MONGOC_EXPORT (void) mongoc_structured_log_opts_set_handler (mongoc_structured_log_opts_t *opts, mongoc_structured_log_func_t log_func, void *user_data); MONGOC_EXPORT (bool) mongoc_structured_log_opts_set_max_level_for_component (mongoc_structured_log_opts_t *opts, mongoc_structured_log_component_t component, mongoc_structured_log_level_t level); MONGOC_EXPORT (bool) mongoc_structured_log_opts_set_max_level_for_all_components (mongoc_structured_log_opts_t *opts, mongoc_structured_log_level_t level); MONGOC_EXPORT (bool) mongoc_structured_log_opts_set_max_levels_from_env (mongoc_structured_log_opts_t *opts); MONGOC_EXPORT (mongoc_structured_log_level_t) mongoc_structured_log_opts_get_max_level_for_component (const mongoc_structured_log_opts_t *opts, mongoc_structured_log_component_t component); MONGOC_EXPORT (size_t) mongoc_structured_log_opts_get_max_document_length (const mongoc_structured_log_opts_t *opts); MONGOC_EXPORT (bool) mongoc_structured_log_opts_set_max_document_length_from_env (mongoc_structured_log_opts_t *opts); MONGOC_EXPORT (bool) mongoc_structured_log_opts_set_max_document_length (mongoc_structured_log_opts_t *opts, size_t max_document_length); MONGOC_EXPORT (bson_t *) mongoc_structured_log_entry_message_as_bson (const mongoc_structured_log_entry_t *entry); MONGOC_EXPORT (mongoc_structured_log_level_t) mongoc_structured_log_entry_get_level (const mongoc_structured_log_entry_t *entry); MONGOC_EXPORT (mongoc_structured_log_component_t) mongoc_structured_log_entry_get_component (const mongoc_structured_log_entry_t *entry); MONGOC_EXPORT (const char *) mongoc_structured_log_entry_get_message_string (const mongoc_structured_log_entry_t *entry); MONGOC_EXPORT (const char *) mongoc_structured_log_get_level_name (mongoc_structured_log_level_t level); MONGOC_EXPORT (bool) mongoc_structured_log_get_named_level (const char *name, mongoc_structured_log_level_t *out); MONGOC_EXPORT (const char *) mongoc_structured_log_get_component_name (mongoc_structured_log_component_t component); MONGOC_EXPORT (bool) mongoc_structured_log_get_named_component (const char *name, mongoc_structured_log_component_t *out); BSON_END_DECLS #endif /* MONGOC_STRUCTURED_LOG_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-thread-private.h0000644000175100001660000000543614760300420024066 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_THREAD_PRIVATE_H #define MONGOC_THREAD_PRIVATE_H #include #include #include #include #if defined(BSON_OS_UNIX) #define mongoc_cond_t pthread_cond_t #define mongoc_cond_broadcast pthread_cond_broadcast #define mongoc_cond_init(_n) pthread_cond_init ((_n), NULL) #if defined(MONGOC_ENABLE_DEBUG_ASSERTIONS) #define mongoc_cond_wait(cond, mutex) pthread_cond_wait (cond, &(mutex)->wrapped_mutex); #else #define mongoc_cond_wait pthread_cond_wait #endif #define mongoc_cond_signal pthread_cond_signal static BSON_INLINE int mongoc_cond_timedwait (pthread_cond_t *cond, bson_mutex_t *mutex, int64_t timeout_msec) { struct timespec to; struct timeval tv; int64_t msec; bson_gettimeofday (&tv); msec = ((int64_t) tv.tv_sec * 1000) + (tv.tv_usec / 1000) + timeout_msec; to.tv_sec = msec / 1000; to.tv_nsec = (msec % 1000) * 1000 * 1000; #if defined(MONGOC_ENABLE_DEBUG_ASSERTIONS) && defined(BSON_OS_UNIX) return pthread_cond_timedwait (cond, &mutex->wrapped_mutex, &to); #else return pthread_cond_timedwait (cond, mutex, &to); #endif } static BSON_INLINE bool mongo_cond_ret_is_timedout (int ret) { return ret == ETIMEDOUT; } #define mongoc_cond_destroy pthread_cond_destroy #else #define mongoc_cond_t CONDITION_VARIABLE #define mongoc_cond_init InitializeConditionVariable #define mongoc_cond_wait(_c, _m) mongoc_cond_timedwait ((_c), (_m), INFINITE) static BSON_INLINE int mongoc_cond_timedwait (mongoc_cond_t *cond, bson_mutex_t *mutex, int64_t timeout_msec) { int r; if (SleepConditionVariableCS (cond, mutex, (DWORD) timeout_msec)) { return 0; } else { r = GetLastError (); if (r == WAIT_TIMEOUT || r == ERROR_TIMEOUT) { return WSAETIMEDOUT; } else { return EINVAL; } } } static BSON_INLINE bool mongo_cond_ret_is_timedout (int ret) { return ret == WSAETIMEDOUT; } #define mongoc_cond_signal WakeConditionVariable #define mongoc_cond_broadcast WakeAllConditionVariable static BSON_INLINE int mongoc_cond_destroy (mongoc_cond_t *_ignored) { return 0; } #endif #endif /* MONGOC_THREAD_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-timeout-private.h0000644000175100001660000000244414760300420024301 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TIMEOUT_PRIVATE_H #define MONGOC_TIMEOUT_PRIVATE_H #include #include typedef struct _mongoc_timeout_t mongoc_timeout_t; mongoc_timeout_t * mongoc_timeout_new (void); mongoc_timeout_t * mongoc_timeout_new_timeout_int64 (int64_t timeout_ms); void mongoc_timeout_destroy (mongoc_timeout_t *timeout); mongoc_timeout_t * mongoc_timeout_copy (const mongoc_timeout_t *timeout); int64_t mongoc_timeout_get_timeout_ms (const mongoc_timeout_t *timeout); bool mongoc_timeout_set_timeout_ms (mongoc_timeout_t *timeout, int64_t timeout_ms); bool mongoc_timeout_is_set (const mongoc_timeout_t *timeout); #endif /* MONGOC_TIMEOUT_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-timeout.c0000644000175100001660000000424714760300420022627 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include struct _mongoc_timeout_t { bool is_set; int64_t timeout_ms; }; int64_t mongoc_timeout_get_timeout_ms (const mongoc_timeout_t *timeout) { BSON_ASSERT (timeout); BSON_ASSERT (timeout->is_set); return timeout->timeout_ms; } bool _mongoc_timeout_set_timeout_ms (mongoc_timeout_t *timeout, int64_t timeout_ms) { BSON_ASSERT (timeout); if (timeout_ms < 0) { MONGOC_ERROR ("timeout must not be negative"); return false; } timeout->timeout_ms = timeout_ms; timeout->is_set = true; return true; } bool mongoc_timeout_set_timeout_ms (mongoc_timeout_t *timeout, int64_t timeout_ms) { return _mongoc_timeout_set_timeout_ms (timeout, timeout_ms); } mongoc_timeout_t * mongoc_timeout_new (void) { return (mongoc_timeout_t *) bson_malloc0 (sizeof (mongoc_timeout_t)); } mongoc_timeout_t * mongoc_timeout_new_timeout_int64 (int64_t timeout_ms) { mongoc_timeout_t *timeout = mongoc_timeout_new (); if (_mongoc_timeout_set_timeout_ms (timeout, timeout_ms)) return timeout; mongoc_timeout_destroy (timeout); return NULL; } mongoc_timeout_t * mongoc_timeout_copy (const mongoc_timeout_t *timeout) { mongoc_timeout_t *copy = NULL; BSON_ASSERT (timeout); copy = mongoc_timeout_new (); copy->timeout_ms = timeout->timeout_ms; copy->is_set = timeout->is_set; return copy; } void mongoc_timeout_destroy (mongoc_timeout_t *timeout) { bson_free (timeout); } bool mongoc_timeout_is_set (const mongoc_timeout_t *timeout) { return timeout && timeout->is_set; } ././@LongLink0000000000000000000000000000014500000000000007755 Lustar mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring-private.hmongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring-private.0000644000175100001660000000264114760300420030616 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TOPOLOGY_BACKGROUND_MONITORING_PRIVATE_H #define MONGOC_TOPOLOGY_BACKGROUND_MONITORING_PRIVATE_H #include #include /* Methods of mongoc_topology_t for managing background monitoring. */ void _mongoc_topology_background_monitoring_start (mongoc_topology_t *topology); void _mongoc_topology_background_monitoring_reconcile (mongoc_topology_t *topology, mongoc_topology_description_t *td); void _mongoc_topology_background_monitoring_request_scan (mongoc_topology_t *topology); void _mongoc_topology_background_monitoring_stop (mongoc_topology_t *topology); void _mongoc_topology_background_monitoring_cancel_check (mongoc_topology_t *topology, uint32_t server_id); #endif /* MONGOC_TOPOLOGY_BACKGROUND_MONITORING_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-background-monitoring.c0000644000175100001660000003265614760300420027322 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #endif #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "monitor" static BSON_THREAD_FUN (srv_polling_run, topology_void) { mongoc_topology_t *topology; topology = topology_void; while (mcommon_atomic_int_fetch (&topology->scanner_state, mcommon_memory_order_relaxed) == MONGOC_TOPOLOGY_SCANNER_BG_RUNNING) { int64_t now_ms; int64_t scan_due_ms; int64_t sleep_duration_ms; /* This will check if a scan is due. */ if (!mongoc_topology_should_rescan_srv (topology)) { TRACE ("%s\n", "topology ineligible for SRV polling, stopping"); break; } mongoc_topology_rescan_srv (topology); /* Unlock and sleep until next scan is due, or until shutdown signalled. */ now_ms = bson_get_monotonic_time () / 1000; scan_due_ms = topology->srv_polling_last_scan_ms + _mongoc_topology_get_srv_polling_rescan_interval_ms (topology); sleep_duration_ms = scan_due_ms - now_ms; if (sleep_duration_ms > 0) { TRACE ("srv polling thread sleeping for %" PRId64 "ms", sleep_duration_ms); } /* Check for shutdown again here. mongoc_topology_rescan_srv unlocks the * topology srv_polling_mtx for the scan. The topology may have shut * down in that time. */ bson_mutex_lock (&topology->srv_polling_mtx); if (mcommon_atomic_int_fetch (&topology->scanner_state, mcommon_memory_order_relaxed) != MONGOC_TOPOLOGY_SCANNER_BG_RUNNING) { bson_mutex_unlock (&topology->srv_polling_mtx); break; } /* If shutting down, stop. */ mongoc_cond_timedwait (&topology->srv_polling_cond, &topology->srv_polling_mtx, sleep_duration_ms); bson_mutex_unlock (&topology->srv_polling_mtx); } BSON_THREAD_RETURN; } /* Create a server monitor if necessary. * * Called by monitor threads and application threads when reconciling the * topology description. */ static void _background_monitor_reconcile_server_monitor (mongoc_topology_t *topology, mongoc_topology_description_t *td, mongoc_server_description_t *sd) { mongoc_set_t *server_monitors = topology->server_monitors; mongoc_server_monitor_t *server_monitor = mongoc_set_get (server_monitors, sd->id); if (!server_monitor) { /* Add a new server monitor. */ server_monitor = mongoc_server_monitor_new (topology, td, sd); mongoc_server_monitor_run (server_monitor); mongoc_set_add (server_monitors, sd->id, server_monitor); } /* Check if an RTT monitor is needed. */ if (!bson_empty (&sd->topology_version)) { mongoc_set_t *rtt_monitors; mongoc_server_monitor_t *rtt_monitor; rtt_monitors = topology->rtt_monitors; rtt_monitor = mongoc_set_get (rtt_monitors, sd->id); if (!rtt_monitor) { rtt_monitor = mongoc_server_monitor_new (topology, td, sd); mongoc_server_monitor_run_as_rtt (rtt_monitor); mongoc_set_add (rtt_monitors, sd->id, rtt_monitor); } } return; } /* Start background monitoring. * * Called by an application thread popping a client from a pool. Safe to * call repeatedly. */ void _mongoc_topology_background_monitoring_start (mongoc_topology_t *topology) { mc_tpld_modification tdmod; int prev_state; BSON_ASSERT (!topology->single_threaded); if (!topology->valid) { return; } prev_state = mcommon_atomic_int_compare_exchange_strong (&topology->scanner_state, MONGOC_TOPOLOGY_SCANNER_OFF, MONGOC_TOPOLOGY_SCANNER_BG_RUNNING, mcommon_memory_order_relaxed); if (prev_state != MONGOC_TOPOLOGY_SCANNER_OFF) { /* The topology scanner is already running, or another thread is starting * it up now. */ return; } TRACE ("%s", "background monitoring starting"); tdmod = mc_tpld_modify_begin (topology); _mongoc_handshake_freeze (); _mongoc_topology_description_monitor_opening (tdmod.new_td, &topology->log_and_monitor); if (tdmod.new_td->type == MONGOC_TOPOLOGY_LOAD_BALANCED) { /* Do not proceed to start monitoring threads. */ TRACE ("%s", "disabling monitoring for load balanced topology"); } else { /* Reconcile to create the first server monitors. */ _mongoc_topology_background_monitoring_reconcile (topology, tdmod.new_td); /* Start SRV polling thread. */ if (mongoc_topology_should_rescan_srv (topology)) { int ret = mcommon_thread_create (&topology->srv_polling_thread, srv_polling_run, topology); if (ret == 0) { topology->is_srv_polling = true; } else { char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; char *errmsg = bson_strerror_r (ret, errmsg_buf, sizeof errmsg_buf); MONGOC_ERROR ("Failed to start SRV polling thread. SRV records " "will not be polled. Error: %s", errmsg); } } } mc_tpld_modify_commit (tdmod); } /* Remove server monitors that are no longer in the set of server descriptions. * * Called by monitor threads and application threads when reconciling the * topology description. */ static void _remove_orphaned_server_monitors (mongoc_set_t *server_monitors, mongoc_set_t *server_descriptions) { uint32_t *server_monitor_ids_to_remove; uint32_t n_server_monitor_ids_to_remove = 0; /* Signal shutdown to server monitors no longer in the topology description. */ server_monitor_ids_to_remove = bson_malloc0 (sizeof (uint32_t) * server_monitors->items_len); for (size_t i = 0u; i < server_monitors->items_len; i++) { mongoc_server_monitor_t *server_monitor; uint32_t id; server_monitor = mongoc_set_get_item_and_id (server_monitors, i, &id); if (!mongoc_set_get (server_descriptions, id)) { if (mongoc_server_monitor_request_shutdown (server_monitor)) { mongoc_server_monitor_wait_for_shutdown (server_monitor); mongoc_server_monitor_destroy (server_monitor); server_monitor_ids_to_remove[n_server_monitor_ids_to_remove] = id; n_server_monitor_ids_to_remove++; } } } /* Remove freed server monitors that have completed shutdown. */ for (uint32_t i = 0u; i < n_server_monitor_ids_to_remove; i++) { mongoc_set_rm (server_monitors, server_monitor_ids_to_remove[i]); } bson_free (server_monitor_ids_to_remove); } /* Reconcile the topology description with the set of server monitors. * * Called when the topology description is updated (via handshake, monitoring, * or invalidation). May be called by server monitor thread or an application * thread. * Locks server monitor mutexes. May join / remove server monitors that have * completed shutdown. */ void _mongoc_topology_background_monitoring_reconcile (mongoc_topology_t *topology, mongoc_topology_description_t *td) { mongoc_set_t *server_descriptions = mc_tpld_servers (td); BSON_ASSERT (!topology->single_threaded); if (mcommon_atomic_int_fetch (&topology->scanner_state, mcommon_memory_order_relaxed) != MONGOC_TOPOLOGY_SCANNER_BG_RUNNING) { return; } /* Add newly discovered server monitors, and update existing ones. */ for (size_t i = 0u; i < server_descriptions->items_len; i++) { mongoc_server_description_t *sd; sd = mongoc_set_get_item (server_descriptions, i); _background_monitor_reconcile_server_monitor (topology, td, sd); } _remove_orphaned_server_monitors (topology->server_monitors, server_descriptions); _remove_orphaned_server_monitors (topology->rtt_monitors, server_descriptions); } /* Request all server monitors to scan. * * Called from application threads (during server selection or "not primary" * errors). Locks server monitor mutexes to deliver scan_requested. */ void _mongoc_topology_background_monitoring_request_scan (mongoc_topology_t *topology) { mongoc_set_t *server_monitors; BSON_ASSERT (!topology->single_threaded); if (mcommon_atomic_int_fetch (&topology->scanner_state, mcommon_memory_order_relaxed) == MONGOC_TOPOLOGY_SCANNER_SHUTTING_DOWN) { return; } server_monitors = topology->server_monitors; for (size_t i = 0u; i < server_monitors->items_len; i++) { mongoc_server_monitor_t *server_monitor; uint32_t id; server_monitor = mongoc_set_get_item_and_id (server_monitors, i, &id); mongoc_server_monitor_request_scan (server_monitor); } } /* Stop, join, and destroy all server monitors. * * Called by application threads when destroying a client pool. * Locks server monitor mutexes to deliver shutdown. This function is * thread-safe. But in practice, it is only ever called by one application * thread (because mongoc_client_pool_destroy is not thread-safe). */ void _mongoc_topology_background_monitoring_stop (mongoc_topology_t *topology) { mongoc_server_monitor_t *server_monitor; BSON_ASSERT (!topology->single_threaded); if (mcommon_atomic_int_fetch (&topology->scanner_state, mcommon_memory_order_relaxed) != MONGOC_TOPOLOGY_SCANNER_BG_RUNNING) { return; } TRACE ("%s", "background monitoring stopping"); /* Tell the srv polling thread to stop */ bson_mutex_lock (&topology->srv_polling_mtx); mcommon_atomic_int_exchange ( &topology->scanner_state, MONGOC_TOPOLOGY_SCANNER_SHUTTING_DOWN, mcommon_memory_order_relaxed); if (topology->is_srv_polling) { /* Signal the srv poller to break out of waiting */ mongoc_cond_signal (&topology->srv_polling_cond); } bson_mutex_unlock (&topology->srv_polling_mtx); bson_mutex_lock (&topology->tpld_modification_mtx); const size_t n_srv_monitors = topology->server_monitors->items_len; const size_t n_rtt_monitors = topology->rtt_monitors->items_len; bson_mutex_unlock (&topology->tpld_modification_mtx); /* Signal all server monitors to shut down. */ for (size_t i = 0u; i < n_srv_monitors; i++) { server_monitor = mongoc_set_get_item (topology->server_monitors, i); mongoc_server_monitor_request_shutdown (server_monitor); } /* Signal all RTT monitors to shut down. */ for (size_t i = 0u; i < n_rtt_monitors; i++) { server_monitor = mongoc_set_get_item (topology->rtt_monitors, i); mongoc_server_monitor_request_shutdown (server_monitor); } for (size_t i = 0u; i < n_srv_monitors; i++) { /* Wait for the thread to shutdown. */ server_monitor = mongoc_set_get_item (topology->server_monitors, i); mongoc_server_monitor_wait_for_shutdown (server_monitor); mongoc_server_monitor_destroy (server_monitor); } for (size_t i = 0u; i < n_rtt_monitors; i++) { /* Wait for the thread to shutdown. */ server_monitor = mongoc_set_get_item (topology->rtt_monitors, i); mongoc_server_monitor_wait_for_shutdown (server_monitor); mongoc_server_monitor_destroy (server_monitor); } /* Wait for SRV polling thread. */ if (topology->is_srv_polling) { mcommon_thread_join (topology->srv_polling_thread); } /* Signal clients that are waiting on server selection to stop immediately, * as there will be no servers available. * This uses the tpld_modification_mtx as that is the mutex used with the * condition variable that will wait the waiting client threads. */ bson_mutex_lock (&topology->tpld_modification_mtx); mongoc_set_destroy (topology->server_monitors); mongoc_set_destroy (topology->rtt_monitors); topology->server_monitors = mongoc_set_new (1, NULL, NULL); topology->rtt_monitors = mongoc_set_new (1, NULL, NULL); mcommon_atomic_int_exchange (&topology->scanner_state, MONGOC_TOPOLOGY_SCANNER_OFF, mcommon_memory_order_relaxed); mongoc_cond_broadcast (&topology->cond_client); bson_mutex_unlock (&topology->tpld_modification_mtx); } /* Cancel an in-progress streaming hello for a specific server (if * applicable). * * Called from application threads on network errors. */ void _mongoc_topology_background_monitoring_cancel_check (mongoc_topology_t *topology, uint32_t server_id) { mongoc_server_monitor_t *server_monitor; server_monitor = mongoc_set_get (topology->server_monitors, server_id); if (!server_monitor) { /* Already removed. */ return; } mongoc_server_monitor_request_cancel (server_monitor); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-description-apm-private.h0000644000175100001660000000552714760300420027570 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TOPOLOGY_DESCRIPTION_APM_PRIVATE_H #define MONGOC_TOPOLOGY_DESCRIPTION_APM_PRIVATE_H #include #include #include /* Application Performance Monitoring for topology events, complies with the * SDAM Monitoring Spec: https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.md */ void _mongoc_topology_description_monitor_server_opening (const mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, mongoc_server_description_t *sd); void _mongoc_topology_description_monitor_server_changed (const mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *prev_sd, const mongoc_server_description_t *new_sd); void _mongoc_topology_description_monitor_server_closed (const mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *sd); /* td is not const: we set its "opened" flag here */ void _mongoc_topology_description_monitor_opening (mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor); void _mongoc_topology_description_monitor_changed (const mongoc_topology_description_t *prev_td, const mongoc_topology_description_t *new_td, const mongoc_log_and_monitor_instance_t *log_and_monitor); void _mongoc_topology_description_monitor_closed (const mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor); #endif /* MONGOC_TOPOLOGY_DESCRIPTION_APM_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-description-apm.c0000644000175100001660000002230214760300420026101 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include /* Application Performance Monitoring for topology events, complies with the * SDAM Monitoring Spec: https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.md */ /* ServerOpeningEvent */ void _mongoc_topology_description_monitor_server_opening (const mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, mongoc_server_description_t *sd) { /* Topology opening will be deferred until server selection, and * server opening must be deferred until topology opening. */ if (td->opened && !sd->opened) { sd->opened = true; mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Starting server monitoring", oid ("topologyId", &td->topology_id), server_description (sd, SERVER_HOST, SERVER_PORT)); if (log_and_monitor->apm_callbacks.server_opening) { mongoc_apm_server_opening_t event; bson_oid_copy (&td->topology_id, &event.topology_id); event.host = &sd->host; event.context = log_and_monitor->apm_context; log_and_monitor->apm_callbacks.server_opening (&event); } } } /* ServerDescriptionChangedEvent */ void _mongoc_topology_description_monitor_server_changed (const mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *prev_sd, const mongoc_server_description_t *new_sd) { if (log_and_monitor->apm_callbacks.server_changed) { mongoc_apm_server_changed_t event; /* address is same in previous and new sd */ bson_oid_copy (&td->topology_id, &event.topology_id); event.host = &new_sd->host; event.previous_description = prev_sd; event.new_description = new_sd; event.context = log_and_monitor->apm_context; log_and_monitor->apm_callbacks.server_changed (&event); } } /* ServerClosedEvent */ void _mongoc_topology_description_monitor_server_closed (const mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *sd) { if (!sd->opened) { return; } mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Stopped server monitoring", oid ("topologyId", &td->topology_id), server_description (sd, SERVER_HOST, SERVER_PORT)); if (log_and_monitor->apm_callbacks.server_closed) { mongoc_apm_server_closed_t event; bson_oid_copy (&td->topology_id, &event.topology_id); event.host = &sd->host; event.context = log_and_monitor->apm_context; log_and_monitor->apm_callbacks.server_closed (&event); } } /* Send TopologyOpeningEvent when first called on this topology description. * td is not const: we mark it as "opened" by the current log-and-monitor instance. */ void _mongoc_topology_description_monitor_opening (mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor) { if (td->opened) { return; } td->opened = true; // The initial 'previous' topology description, with Unknown type mongoc_topology_description_t *prev_td = BSON_ALIGNED_ALLOC0 (mongoc_topology_description_t); mongoc_topology_description_init (prev_td, td->heartbeat_msec); mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Starting topology monitoring", oid ("topologyId", &td->topology_id)); if (log_and_monitor->apm_callbacks.topology_opening) { mongoc_apm_topology_opening_t event; bson_oid_copy (&td->topology_id, &event.topology_id); event.context = log_and_monitor->apm_context; log_and_monitor->apm_callbacks.topology_opening (&event); } /* send initial description-changed event */ _mongoc_topology_description_monitor_changed (prev_td, td, log_and_monitor); for (size_t i = 0u; i < mc_tpld_servers (td)->items_len; i++) { mongoc_server_description_t *sd = mongoc_set_get_item (mc_tpld_servers (td), i); _mongoc_topology_description_monitor_server_opening (td, log_and_monitor, sd); } /* If this is a load balanced topology: * - update the one server description to be LoadBalancer * - emit a server changed event Unknown => LoadBalancer * - emit a topology changed event */ if (td->type == MONGOC_TOPOLOGY_LOAD_BALANCED) { mongoc_server_description_t *prev_sd; /* LoadBalanced deployments must have exactly one host listed. Otherwise, * an error would have occurred when constructing the topology. */ BSON_ASSERT (mc_tpld_servers (td)->items_len == 1); mongoc_server_description_t *sd = mongoc_set_get_item (mc_tpld_servers (td), 0); prev_sd = mongoc_server_description_new_copy (sd); BSON_ASSERT (prev_sd); mongoc_topology_description_cleanup (prev_td); _mongoc_topology_description_copy_to (td, prev_td); sd->type = MONGOC_SERVER_LOAD_BALANCER; _mongoc_topology_description_monitor_server_changed (td, log_and_monitor, prev_sd, sd); mongoc_server_description_destroy (prev_sd); _mongoc_topology_description_monitor_changed (prev_td, td, log_and_monitor); } if (prev_td) { mongoc_topology_description_cleanup (prev_td); bson_free (prev_td); } } /* TopologyDescriptionChangedEvent */ void _mongoc_topology_description_monitor_changed (const mongoc_topology_description_t *prev_td, const mongoc_topology_description_t *new_td, const mongoc_log_and_monitor_instance_t *log_and_monitor) { mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Topology description changed", oid ("topologyId", &new_td->topology_id), topology_description_as_json ("previousDescription", prev_td), topology_description_as_json ("newDescription", new_td)); if (log_and_monitor->apm_callbacks.topology_changed) { mongoc_apm_topology_changed_t event; /* callbacks, context, and id are the same in previous and new td */ bson_oid_copy (&new_td->topology_id, &event.topology_id); event.context = log_and_monitor->apm_context; event.previous_description = prev_td; event.new_description = new_td; log_and_monitor->apm_callbacks.topology_changed (&event); } } /* TopologyClosedEvent */ void _mongoc_topology_description_monitor_closed (const mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor) { // Expected preconditions for 'closed' events: // (mongoc_topology_destroy() carries out these transitions prior to close of monitoring.) BSON_ASSERT (td->type == MONGOC_TOPOLOGY_UNKNOWN); BSON_ASSERT (mc_tpld_servers_const (td)->items_len == 0); if (!td->opened) { return; } mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Stopped topology monitoring", oid ("topologyId", &td->topology_id)); if (log_and_monitor->apm_callbacks.topology_closed) { mongoc_apm_topology_closed_t event; bson_oid_copy (&td->topology_id, &event.topology_id); event.context = log_and_monitor->apm_context; log_and_monitor->apm_callbacks.topology_closed (&event); } } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-description-private.h0000644000175100001660000002174614760300420027016 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TOPOLOGY_DESCRIPTION_PRIVATE_H #define MONGOC_TOPOLOGY_DESCRIPTION_PRIVATE_H #include #include #include #include #include #include #include #include typedef enum { MONGOC_TOPOLOGY_UNKNOWN, MONGOC_TOPOLOGY_SHARDED, MONGOC_TOPOLOGY_RS_NO_PRIMARY, MONGOC_TOPOLOGY_RS_WITH_PRIMARY, MONGOC_TOPOLOGY_SINGLE, MONGOC_TOPOLOGY_LOAD_BALANCED, MONGOC_TOPOLOGY_DESCRIPTION_TYPES } mongoc_topology_description_type_t; struct _mongoc_topology_description_t { bson_oid_t topology_id; mongoc_topology_description_type_t type; int64_t heartbeat_msec; mongoc_set_t *_servers_; char *set_name; int64_t max_set_version; bson_oid_t max_election_id; bson_error_t compatibility_error; uint32_t max_server_id; int32_t max_hosts; /* srvMaxHosts */ bool stale; bool opened; unsigned int rand_seed; /* the greatest seen cluster time, for a MongoDB 3.6+ sharded cluster. * see Driver Sessions Spec. */ bson_t cluster_time; /* smallest seen logicalSessionTimeoutMinutes, or -1 if any server has no * logicalSessionTimeoutMinutes. see Server Discovery and Monitoring Spec */ int64_t session_timeout_minutes; }; typedef enum { MONGOC_SS_READ, MONGOC_SS_WRITE, MONGOC_SS_AGGREGATE_WITH_WRITE } mongoc_ss_optype_t; /** * @brief Contextual information for logging during server selection * * Required to support the "common fields" defined in the Server Selection Logging specification. * The 'operation' string is borrowed for the lifetime of the mongoc_ss_log_context_t. */ typedef struct _mongoc_ss_log_context_t { const char *operation; // Required int64_t operation_id; bool has_operation_id; } mongoc_ss_log_context_t; void mongoc_topology_description_init (mongoc_topology_description_t *description, int64_t heartbeat_msec); /** * @brief Get a pointer to the set of server descriptions in the topology * description. */ static BSON_INLINE mongoc_set_t * mc_tpld_servers (mongoc_topology_description_t *tpld) { BSON_ASSERT_PARAM (tpld); return tpld->_servers_; } static BSON_INLINE const mongoc_set_t * mc_tpld_servers_const (const mongoc_topology_description_t *tpld) { BSON_ASSERT_PARAM (tpld); return tpld->_servers_; } void _mongoc_topology_description_copy_to (const mongoc_topology_description_t *src, mongoc_topology_description_t *dst); void mongoc_topology_description_cleanup (mongoc_topology_description_t *description); void mongoc_topology_description_handle_hello (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, uint32_t server_id, const bson_t *hello_response, int64_t rtt_msec, const bson_error_t *error /* IN */); mongoc_server_description_t const * mongoc_topology_description_select (const mongoc_topology_description_t *description, mongoc_ss_optype_t optype, const mongoc_read_prefs_t *read_pref, bool *must_use_primary, const mongoc_deprioritized_servers_t *ds, int64_t local_threshold_ms); mongoc_server_description_t * mongoc_topology_description_server_by_id (mongoc_topology_description_t *description, uint32_t id, bson_error_t *error); const mongoc_server_description_t * mongoc_topology_description_server_by_id_const (const mongoc_topology_description_t *description, uint32_t id, bson_error_t *error); int32_t mongoc_topology_description_lowest_max_wire_version (const mongoc_topology_description_t *td); bool mongoc_topology_description_all_sds_have_write_date (const mongoc_topology_description_t *td); bool _mongoc_topology_description_validate_max_staleness (const mongoc_topology_description_t *td, int64_t max_staleness_seconds, bson_error_t *error); const mongoc_server_description_t * _mongoc_topology_description_has_primary (const mongoc_topology_description_t *description); void mongoc_topology_description_suitable_servers (mongoc_array_t *set, /* OUT */ mongoc_ss_optype_t optype, const mongoc_topology_description_t *topology, const mongoc_read_prefs_t *read_pref, bool *must_use_primary, const mongoc_deprioritized_servers_t *ds, int64_t local_threshold_ms); bool mongoc_topology_description_has_data_node (const mongoc_topology_description_t *td); void mongoc_topology_description_invalidate_server (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, uint32_t id, const bson_error_t *error /* IN */); bool mongoc_topology_description_add_server (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const char *server, uint32_t *id /* OUT */); void mongoc_topology_description_update_cluster_time (mongoc_topology_description_t *td, const bson_t *reply); void mongoc_topology_description_reconcile (mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, mongoc_host_list_t *host_list); /** * @brief Invalidate open connnections to a server. * * Pooled clients with open connections will discover the invalidation * the next time they fetch a stream to the server. * * @param td The topology description that will be updated. * @param server_id The ID of the server to invalidate. * @param service_id A service ID for load-balanced deployments. Use * kZeroObjectId if not applicable. * * @note Not applicable to single-threaded clients, which only maintain a * single connection per server and therefore have no connection pool. */ void _mongoc_topology_description_clear_connection_pool (mongoc_topology_description_t *td, uint32_t server_id, const bson_oid_t *service_id); void mongoc_deprioritized_servers_add_if_sharded (mongoc_deprioritized_servers_t *ds, mongoc_topology_description_type_t topology_type, const mongoc_server_description_t *sd); typedef enum { MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_TYPE = (1 << 0), MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_SET_NAME = (1 << 1), MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_MAX_ELECTION_ID = (1 << 2), MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_MAX_SET_VERSION = (1 << 3), MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_SERVERS = (1 << 4), MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_STALE = (1 << 5), MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_COMPATIBLE = (1 << 6), MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_COMPATIBILITY_ERROR = (1 << 7), MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_LOGICAL_SESSION_TIMEOUT_MINUTES = (1 << 8), } mongoc_topology_description_content_flags_t; bool mongoc_topology_description_append_contents_to_bson (const mongoc_topology_description_t *td, bson_t *bson, mongoc_topology_description_content_flags_t flags, mongoc_server_description_content_flags_t servers_flags); #endif /* MONGOC_TOPOLOGY_DESCRIPTION_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-description.c0000644000175100001660000026221714760300420025341 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static bool _is_data_node (const mongoc_server_description_t *sd) { switch (sd->type) { case MONGOC_SERVER_MONGOS: case MONGOC_SERVER_STANDALONE: case MONGOC_SERVER_RS_SECONDARY: case MONGOC_SERVER_RS_PRIMARY: case MONGOC_SERVER_LOAD_BALANCER: return true; case MONGOC_SERVER_RS_OTHER: case MONGOC_SERVER_RS_ARBITER: case MONGOC_SERVER_UNKNOWN: case MONGOC_SERVER_POSSIBLE_PRIMARY: case MONGOC_SERVER_RS_GHOST: case MONGOC_SERVER_DESCRIPTION_TYPES: default: return false; } } static void _mongoc_topology_server_dtor (void *server_, void *ctx_) { BSON_UNUSED (ctx_); mongoc_server_description_destroy ((mongoc_server_description_t *) server_); } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_init -- * * Initialize the given topology description * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_init (mongoc_topology_description_t *description, int64_t heartbeat_msec) { ENTRY; BSON_ASSERT (description); memset (description, 0, sizeof (*description)); bson_oid_init (&description->topology_id, NULL); description->type = MONGOC_TOPOLOGY_UNKNOWN; description->heartbeat_msec = heartbeat_msec; description->_servers_ = mongoc_set_new (8, _mongoc_topology_server_dtor, NULL); description->set_name = NULL; description->max_set_version = MONGOC_NO_SET_VERSION; description->stale = true; description->rand_seed = (unsigned int) bson_get_monotonic_time (); bson_init (&description->cluster_time); description->session_timeout_minutes = MONGOC_NO_SESSIONS; EXIT; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_copy_to -- * * Deep-copy @src to an uninitialized topology description @dst. * @dst must not already point to any allocated resources. Clean * up with mongoc_topology_description_cleanup. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void _mongoc_topology_description_copy_to (const mongoc_topology_description_t *src, mongoc_topology_description_t *dst) { size_t nitems; const mongoc_server_description_t *sd; uint32_t id; ENTRY; BSON_ASSERT (src); BSON_ASSERT (dst); bson_oid_copy (&src->topology_id, &dst->topology_id); bson_oid_copy (&src->max_election_id, &dst->max_election_id); dst->opened = src->opened; dst->type = src->type; dst->heartbeat_msec = src->heartbeat_msec; dst->rand_seed = src->rand_seed; nitems = bson_next_power_of_two (mc_tpld_servers_const (src)->items_len); dst->_servers_ = mongoc_set_new (nitems, _mongoc_topology_server_dtor, NULL); for (size_t i = 0u; i < mc_tpld_servers_const (src)->items_len; i++) { sd = mongoc_set_get_item_and_id_const (mc_tpld_servers_const (src), i, &id); mongoc_set_add (mc_tpld_servers (dst), id, mongoc_server_description_new_copy (sd)); } dst->set_name = bson_strdup (src->set_name); dst->max_set_version = src->max_set_version; memcpy (&dst->compatibility_error, &src->compatibility_error, sizeof (bson_error_t)); dst->max_server_id = src->max_server_id; dst->max_hosts = src->max_hosts; dst->stale = src->stale; bson_copy_to (&src->cluster_time, &dst->cluster_time); dst->session_timeout_minutes = src->session_timeout_minutes; EXIT; } /* *------------------------------------------------------------------------- * * mongoc_topology_description_new_copy -- * * Allocates a new topology description and deep-copies @description to it * using _mongoc_topology_description_copy_to. * * Returns: * A copy of a topology description that you must destroy with * mongoc_topology_description_destroy, or NULL if @description is NULL. * * Side effects: * None. * *------------------------------------------------------------------------- */ mongoc_topology_description_t * mongoc_topology_description_new_copy (const mongoc_topology_description_t *description) { mongoc_topology_description_t *copy; if (!description) { return NULL; } copy = BSON_ALIGNED_ALLOC0 (mongoc_topology_description_t); _mongoc_topology_description_copy_to (description, copy); return copy; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_cleanup -- * * Destroy allocated resources within @description but don't free it. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_cleanup (mongoc_topology_description_t *description) { ENTRY; BSON_ASSERT (description); if (mc_tpld_servers (description)) { mongoc_set_destroy (mc_tpld_servers (description)); } if (description->set_name) { bson_free (description->set_name); } bson_destroy (&description->cluster_time); EXIT; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_destroy -- * * Destroy allocated resources within @description and free * @description. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_destroy (mongoc_topology_description_t *description) { ENTRY; if (!description) { EXIT; } mongoc_topology_description_cleanup (description); bson_free (description); EXIT; } /* find the primary, then stop iterating */ static bool _mongoc_topology_description_has_primary_cb (const void *item, void *ctx /* OUT */) { const mongoc_server_description_t *server = item; const mongoc_server_description_t **primary = ctx; /* TODO should this include MONGOS? */ if (server->type == MONGOC_SERVER_RS_PRIMARY || server->type == MONGOC_SERVER_STANDALONE) { *primary = (mongoc_server_description_t *) item; return false; } return true; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_has_primary -- * * If topology has a primary, return it. * * Returns: * A pointer to the primary, or NULL. * * Side effects: * None * *-------------------------------------------------------------------------- */ const mongoc_server_description_t * _mongoc_topology_description_has_primary (const mongoc_topology_description_t *description) { mongoc_server_description_t *primary = NULL; mongoc_set_for_each_const ( mc_tpld_servers_const (description), _mongoc_topology_description_has_primary_cb, &primary); return primary; } /* *-------------------------------------------------------------------------- * * _mongoc_server_description_primary_is_not_stale -- * * Checks if a primary server is not stale by comparing the electionId and * setVersion. * * Returns: * True if the server's electionId is larger or the server's version is * later than the topology max version. * * Side effects: * None * *-------------------------------------------------------------------------- */ static bool _mongoc_server_description_primary_is_not_stale (mongoc_topology_description_t *td, const mongoc_server_description_t *sd) { /* initially max_set_version is -1 and max_election_id is zeroed */ return (bson_oid_compare (&sd->election_id, &td->max_election_id) > 0) || ((bson_oid_compare (&sd->election_id, &td->max_election_id) == 0) && sd->set_version >= td->max_set_version); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_later_election -- * * Check if we've seen a more recent election in the replica set * than this server has. * * Returns: * True if the topology description's max replica set version plus * election id is later than the server description's. * * Side effects: * None * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_description_later_election (mongoc_topology_description_t *td, const mongoc_server_description_t *sd) { /* initially max_set_version is -1 and max_election_id is zeroed */ return td->max_set_version > sd->set_version || (td->max_set_version == sd->set_version && bson_oid_compare (&td->max_election_id, &sd->election_id) > 0); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_set_max_set_version -- * * Remember that we've seen a new replica set version. Unconditionally * sets td->set_version to sd->set_version. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_set_max_set_version (mongoc_topology_description_t *td, const mongoc_server_description_t *sd) { td->max_set_version = sd->set_version; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_set_max_election_id -- * * Remember that we've seen a new election id. Unconditionally sets * td->max_election_id to sd->election_id. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_set_max_election_id (mongoc_topology_description_t *td, const mongoc_server_description_t *sd) { bson_oid_copy (&sd->election_id, &td->max_election_id); } static bool _mongoc_topology_description_server_is_candidate (mongoc_server_description_type_t desc_type, mongoc_read_mode_t read_mode, mongoc_topology_description_type_t topology_type) { switch ((int) topology_type) { case MONGOC_TOPOLOGY_SINGLE: switch ((int) desc_type) { case MONGOC_SERVER_STANDALONE: return true; default: return false; } case MONGOC_TOPOLOGY_RS_NO_PRIMARY: case MONGOC_TOPOLOGY_RS_WITH_PRIMARY: switch ((int) read_mode) { case MONGOC_READ_PRIMARY: switch ((int) desc_type) { case MONGOC_SERVER_RS_PRIMARY: return true; default: return false; } case MONGOC_READ_SECONDARY: switch ((int) desc_type) { case MONGOC_SERVER_RS_SECONDARY: return true; default: return false; } default: switch ((int) desc_type) { case MONGOC_SERVER_RS_PRIMARY: case MONGOC_SERVER_RS_SECONDARY: return true; default: return false; } } case MONGOC_TOPOLOGY_SHARDED: switch ((int) desc_type) { case MONGOC_SERVER_MONGOS: return true; default: return false; } /* Note, there is no call path that leads to the * MONGOC_TOPOLOGY_LOAD_BALANCED case. Server selection for load balanced * topologies bypasses this logic. This silences compiler warnings on * unhandled enum values. */ case MONGOC_TOPOLOGY_LOAD_BALANCED: return desc_type == MONGOC_SERVER_LOAD_BALANCER; default: return false; } } typedef struct _mongoc_suitable_data_t { mongoc_read_mode_t read_mode; mongoc_topology_description_type_t topology_type; const mongoc_server_description_t *primary; /* OUT */ const mongoc_server_description_t **candidates; /* OUT */ size_t candidates_len; /* OUT */ bool has_secondary; /* OUT */ } mongoc_suitable_data_t; static bool _mongoc_replica_set_read_suitable_cb (const void *item, void *ctx) { const mongoc_server_description_t *server = item; mongoc_suitable_data_t *data = (mongoc_suitable_data_t *) ctx; /* primary's used in staleness calculation, even with mode SECONDARY */ if (server->type == MONGOC_SERVER_RS_PRIMARY) { data->primary = server; } if (_mongoc_topology_description_server_is_candidate (server->type, data->read_mode, data->topology_type)) { if (server->type == MONGOC_SERVER_RS_PRIMARY) { if (data->read_mode == MONGOC_READ_PRIMARY || data->read_mode == MONGOC_READ_PRIMARY_PREFERRED) { /* we want a primary and we have one, done! */ return false; } } if (server->type == MONGOC_SERVER_RS_SECONDARY) { data->has_secondary = true; } /* add to our candidates */ data->candidates[data->candidates_len++] = server; } else { TRACE ("Rejected [%s] [%s] for mode [%s]", mongoc_server_description_type (server), server->host.host_and_port, _mongoc_read_mode_as_str (data->read_mode)); } return true; } /* if any mongos are candidates, add them to the candidates array */ static void _mongoc_try_mode_secondary (mongoc_array_t *set, /* OUT */ const mongoc_topology_description_t *topology, const mongoc_read_prefs_t *read_pref, bool *must_use_primary, const mongoc_deprioritized_servers_t *ds, int64_t local_threshold_ms) { mongoc_read_prefs_t *secondary; secondary = mongoc_read_prefs_copy (read_pref); mongoc_read_prefs_set_mode (secondary, MONGOC_READ_SECONDARY); mongoc_topology_description_suitable_servers ( set, MONGOC_SS_READ, topology, secondary, must_use_primary, ds, local_threshold_ms); mongoc_read_prefs_destroy (secondary); } static bool _mongoc_td_servers_to_candidates_array (const void *item, void *ctx) { BSON_ASSERT_PARAM (item); BSON_ASSERT_PARAM (ctx); const mongoc_server_description_t *const server = item; mongoc_suitable_data_t *const data = (mongoc_suitable_data_t *) ctx; data->candidates[data->candidates_len++] = server; return true; } // Server Selection Spec: If a list of deprioritized servers is provided, and // the topology is a sharded cluster, these servers should be selected only if // there are no other suitable servers. The server selection algorithm MUST // ignore the deprioritized servers if the topology is not a sharded cluster. static void _mongoc_filter_deprioritized_servers (mongoc_suitable_data_t *data, const mongoc_deprioritized_servers_t *ds) { BSON_ASSERT_PARAM (data); BSON_ASSERT_PARAM (ds); TRACE ("%s", "deprioritization: filtering list of candidates"); mongoc_array_t filtered_servers; _mongoc_array_init (&filtered_servers, sizeof (const mongoc_server_description_t *)); for (size_t idx = 0u; idx < data->candidates_len; ++idx) { mongoc_server_description_t const *const sd = data->candidates[idx]; if (!mongoc_deprioritized_servers_contains (ds, sd)) { TRACE ("deprioritization: - kept: %s (id: %" PRIu32 ")", sd->host.host_and_port, sd->id); _mongoc_array_append_val (&filtered_servers, sd); } else { TRACE ("deprioritization: - removed: %s (id: %" PRIu32 ")", sd->host.host_and_port, sd->id); } } if (filtered_servers.len == 0u) { TRACE ("%s", "deprioritization: reverted due to no other suitable servers"); _mongoc_array_destroy (&filtered_servers); } else if (filtered_servers.len == data->candidates_len) { TRACE ("%s", "deprioritization: none found in list of candidates"); _mongoc_array_destroy (&filtered_servers); } else { TRACE ("%s", "deprioritization: using filtered list of candidates"); data->candidates_len = filtered_servers.len; // `(void*)`: avoid MSVC error C4090: // 'function': different 'const' qualifiers memmove ((void *) data->candidates, filtered_servers.data, filtered_servers.len * filtered_servers.element_size); _mongoc_array_destroy (&filtered_servers); } } // Keep only suitable mongoses in the candidates array. static void _mongoc_filter_suitable_mongos (mongoc_suitable_data_t *data) { size_t idx = 0u; while (idx < data->candidates_len) { if (_mongoc_topology_description_server_is_candidate ( data->candidates[idx]->type, data->read_mode, data->topology_type)) { // All candidates in the latency window are suitable. ++idx; } else { // Remove from list using swap+pop. // Order doesn't matter; the list will be randomized in // mongoc_topology_description_select prior to server selection. data->candidates[idx] = data->candidates[--data->candidates_len]; } } } /* *------------------------------------------------------------------------- * * mongoc_topology_description_lowest_max_wire_version -- * * The topology's max wire version. * * Returns: * The minimum of all known servers' max wire versions, or INT32_MAX * if there are no known servers. * * Side effects: * None. * *------------------------------------------------------------------------- */ int32_t mongoc_topology_description_lowest_max_wire_version (const mongoc_topology_description_t *td) { int32_t ret = INT32_MAX; const mongoc_set_t *servers = mc_tpld_servers_const (td); for (size_t i = 0u; (size_t) i < servers->items_len; i++) { const mongoc_server_description_t *sd = mongoc_set_get_item_const (servers, i); if (sd->type != MONGOC_SERVER_UNKNOWN && sd->type != MONGOC_SERVER_POSSIBLE_PRIMARY && sd->max_wire_version < ret) { ret = sd->max_wire_version; } } return ret; } /* *------------------------------------------------------------------------- * * mongoc_topology_description_all_sds_have_write_date -- * * Whether the primary and all secondaries' server descriptions have * last_write_date_ms. * * Side effects: * None. * *------------------------------------------------------------------------- */ bool mongoc_topology_description_all_sds_have_write_date (const mongoc_topology_description_t *td) { for (size_t i = 0u; (size_t) i < mc_tpld_servers_const (td)->items_len; i++) { const mongoc_server_description_t *sd = mongoc_set_get_item_const (mc_tpld_servers_const (td), i); if (sd->last_write_date_ms <= 0 && (sd->type == MONGOC_SERVER_RS_PRIMARY || sd->type == MONGOC_SERVER_RS_SECONDARY)) { return false; } } return true; } /* *------------------------------------------------------------------------- * * _mongoc_topology_description_validate_max_staleness -- * * If the provided "maxStalenessSeconds" component of the read * preference is not valid for this topology, fill out @error and * return false. * * Side effects: * None. * *------------------------------------------------------------------------- */ bool _mongoc_topology_description_validate_max_staleness (const mongoc_topology_description_t *td, int64_t max_staleness_seconds, bson_error_t *error) { mongoc_topology_description_type_t td_type; /* Server Selection Spec: A driver MUST raise an error if the TopologyType * is ReplicaSetWithPrimary or ReplicaSetNoPrimary and either of these * conditions is false: * * maxStalenessSeconds * 1000 >= heartbeatFrequencyMS + idleWritePeriodMS * maxStalenessSeconds >= smallestMaxStalenessSeconds */ td_type = td->type; if (td_type != MONGOC_TOPOLOGY_RS_WITH_PRIMARY && td_type != MONGOC_TOPOLOGY_RS_NO_PRIMARY) { return true; } if (max_staleness_seconds * 1000 < td->heartbeat_msec + MONGOC_IDLE_WRITE_PERIOD_MS) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "maxStalenessSeconds is set to %" PRId64 ", it must be at least heartbeatFrequencyMS (%" PRId64 ") + server's idle write period (%d seconds)", max_staleness_seconds, td->heartbeat_msec, MONGOC_IDLE_WRITE_PERIOD_MS / 1000); return false; } if (max_staleness_seconds < MONGOC_SMALLEST_MAX_STALENESS_SECONDS) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "maxStalenessSeconds is set to %" PRId64 ", it must be at least %d seconds", max_staleness_seconds, MONGOC_SMALLEST_MAX_STALENESS_SECONDS); return false; } return true; } static bool _check_any_server_less_than_wire_version_13 (const void *sd_, void *any_too_old_) { const mongoc_server_description_t *sd = sd_; bool *any_too_old = any_too_old_; if (sd->type != MONGOC_SERVER_UNKNOWN && sd->max_wire_version < WIRE_VERSION_5_0) { *any_too_old = true; return false /* Stop searching */; } return true /* Keep searching */; } /** * @brief Calculate the read mode that we should be using, based on what was * requested and what is available in the topology. * * Per the CRUD spec, if the requested read mode is *not* primary, and *any* available * server in the topology has a wire version < server v5.0, we must override the * read mode preference with "primary." Server v5.0 indicates support on a * secondary server for using aggregate pipelines that contain writing stages * (i.e. '$out' and '$merge'). */ static bool _must_use_primary (const mongoc_topology_description_t *td, mongoc_ss_optype_t optype, mongoc_read_mode_t requested_read_mode) { if (requested_read_mode == MONGOC_READ_PRIMARY) { /* We never alter from a primary read mode. This early-return is just an * optimization to skip scanning for old servers, as we would end up * returning MONGOC_READ_PRIMARY regardless. */ return true; } switch (optype) { case MONGOC_SS_WRITE: /* We don't deal with write operations */ return false; case MONGOC_SS_READ: /* Maintain the requested read mode if it is a regular read operation */ return false; case MONGOC_SS_AGGREGATE_WITH_WRITE: { /* Check if any of the available servers are too old to support the * aggregate-with-write on a secondary server */ bool any_too_old = false; mongoc_set_for_each_const (mc_tpld_servers_const (td), _check_any_server_less_than_wire_version_13, &any_too_old); if (any_too_old) { /* Force the read preference back to reading from a primary server, as * one or more servers in the system may not support the operation */ return true; } /* We're okay to send an aggr-with-write to a secondary server, so permit * the caller's read mode preference */ return false; } default: BSON_UNREACHABLE ("Invalid mongoc_ss_optype_t for _must_use_primary()"); } } /* *------------------------------------------------------------------------- * * mongoc_topology_description_suitable_servers -- * * Fill out an array of servers matching the read preference and * localThresholdMS. * * Side effects: * None. * *------------------------------------------------------------------------- */ void mongoc_topology_description_suitable_servers (mongoc_array_t *set, /* OUT */ mongoc_ss_optype_t optype, const mongoc_topology_description_t *topology, const mongoc_read_prefs_t *read_pref, bool *must_use_primary, const mongoc_deprioritized_servers_t *ds, int64_t local_threshold_ms) { const mongoc_set_t *td_servers = mc_tpld_servers_const (topology); const mongoc_read_mode_t given_read_mode = mongoc_read_prefs_get_mode (read_pref); const bool override_use_primary = _must_use_primary (topology, optype, given_read_mode); mongoc_suitable_data_t data = { .primary = NULL, .topology_type = topology->type, .has_secondary = false, .candidates_len = 0, .candidates = bson_malloc0 (sizeof (mongoc_server_description_t *) * td_servers->items_len), }; /* The "effective" read mode is the read mode that we should behave for, and * depends on the user's provided read mode, the type of operation that the * user wishes to perform, and the server versions that we are talking to. * * If the operation is a write operation, read mode is irrelevant. * * If the operation is a regular read, we just use the caller's read mode. * * If the operation is an aggregate that contains writing stages, we need to * be more careful about selecting an appropriate server. */ data.read_mode = override_use_primary ? MONGOC_READ_PRIMARY : given_read_mode; if (must_use_primary) { /* The caller wants to know if we have overriden their read preference */ *must_use_primary = override_use_primary; } /* Single server -- * Either it is suitable or it isn't */ if (topology->type == MONGOC_TOPOLOGY_SINGLE) { const mongoc_server_description_t *server = mongoc_set_get_item_const (td_servers, 0); if (_mongoc_topology_description_server_is_candidate (server->type, data.read_mode, topology->type)) { _mongoc_array_append_val (set, server); } else { TRACE ("Rejected [%s] [%s] for read mode [%s] with topology type Single", mongoc_server_description_type (server), server->host.host_and_port, _mongoc_read_mode_as_str (data.read_mode)); } goto DONE; } /* Replica sets -- * Find suitable servers based on read mode */ if (topology->type == MONGOC_TOPOLOGY_RS_NO_PRIMARY || topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) { switch (optype) { case MONGOC_SS_AGGREGATE_WITH_WRITE: case MONGOC_SS_READ: { mongoc_set_for_each_const (td_servers, _mongoc_replica_set_read_suitable_cb, &data); if (data.read_mode == MONGOC_READ_PRIMARY) { if (data.primary) { _mongoc_array_append_val (set, data.primary); } goto DONE; } if (data.read_mode == MONGOC_READ_PRIMARY_PREFERRED && data.primary) { _mongoc_array_append_val (set, data.primary); goto DONE; } if (data.read_mode == MONGOC_READ_SECONDARY_PREFERRED) { /* try read_mode SECONDARY */ _mongoc_try_mode_secondary (set, topology, read_pref, must_use_primary, NULL, local_threshold_ms); /* otherwise fall back to primary */ if (!set->len && data.primary) { _mongoc_array_append_val (set, data.primary); } goto DONE; } if (data.read_mode == MONGOC_READ_SECONDARY) { for (size_t i = 0u; i < data.candidates_len; i++) { if (data.candidates[i] && data.candidates[i]->type != MONGOC_SERVER_RS_SECONDARY) { TRACE ("Rejected [%s] [%s] for mode [%s] with RS topology", mongoc_server_description_type (data.candidates[i]), data.candidates[i]->host.host_and_port, _mongoc_read_mode_as_str (data.read_mode)); data.candidates[i] = NULL; } } } /* mode is SECONDARY or NEAREST, filter by staleness and tags */ mongoc_server_description_filter_stale ( data.candidates, data.candidates_len, data.primary, topology->heartbeat_msec, read_pref); mongoc_server_description_filter_tags (data.candidates, data.candidates_len, read_pref); } break; case MONGOC_SS_WRITE: { if (topology->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) { mongoc_set_for_each_const (td_servers, _mongoc_topology_description_has_primary_cb, (void *) &data.primary); if (data.primary) { _mongoc_array_append_val (set, data.primary); goto DONE; } } } break; default: BSON_UNREACHABLE ("Invalid optype"); } } // Sharded clusters -- if (topology->type == MONGOC_TOPOLOGY_SHARDED) { mongoc_set_for_each_const (td_servers, _mongoc_td_servers_to_candidates_array, &data); if (ds) { _mongoc_filter_deprioritized_servers (&data, ds); } _mongoc_filter_suitable_mongos (&data); } /* Load balanced clusters -- * Always select the only server. */ if (topology->type == MONGOC_TOPOLOGY_LOAD_BALANCED) { const mongoc_server_description_t *server; BSON_ASSERT (td_servers->items_len == 1); server = mongoc_set_get_item_const (td_servers, 0); _mongoc_array_append_val (set, server); goto DONE; } /* Ways to get here: * - secondary read * - secondary preferred read * - primary_preferred and no primary read * - sharded anything * Find the nearest, then select within the window */ int64_t nearest = INT64_MAX; bool found = false; for (size_t i = 0u; i < data.candidates_len; i++) { if (data.candidates[i]) { nearest = BSON_MIN (nearest, data.candidates[i]->round_trip_time_msec); found = true; } } // No candidates remaining. if (!found) { goto DONE; } const int64_t rtt_limit = nearest + local_threshold_ms; for (size_t i = 0u; i < data.candidates_len; i++) { if (data.candidates[i] && (data.candidates[i]->round_trip_time_msec <= rtt_limit)) { _mongoc_array_append_val (set, data.candidates[i]); } } DONE: bson_free ((mongoc_server_description_t *) data.candidates); return; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_has_data_node -- * * Internal method: are any servers not Arbiter, Ghost, or Unknown? * *-------------------------------------------------------------------------- */ bool mongoc_topology_description_has_data_node (const mongoc_topology_description_t *td) { const mongoc_set_t *servers = mc_tpld_servers_const (td); for (size_t i = 0u; i < servers->items_len; i++) { const mongoc_server_description_t *sd = mongoc_set_get_item_const (servers, i); if (_is_data_node (sd)) { return true; } } return false; } /* *------------------------------------------------------------------------- * * mongoc_topology_description_select -- * * Return a server description of a node that is appropriate for * the given read preference and operation type. * * NOTE: this method simply attempts to select a server from the * current topology, it does not retry or trigger topology checks. * * Returns: * Selected server description, or NULL upon failure. * * Side effects: * None. * *------------------------------------------------------------------------- */ mongoc_server_description_t const * mongoc_topology_description_select (const mongoc_topology_description_t *topology, mongoc_ss_optype_t optype, const mongoc_read_prefs_t *read_pref, bool *must_use_primary, const mongoc_deprioritized_servers_t *ds, int64_t local_threshold_ms) { mongoc_array_t suitable_servers; ENTRY; if (topology->type == MONGOC_TOPOLOGY_SINGLE) { mongoc_server_description_t const *const sd = mongoc_set_get_item_const (mc_tpld_servers_const (topology), 0); if (optype == MONGOC_SS_AGGREGATE_WITH_WRITE && sd->type != MONGOC_SERVER_UNKNOWN && sd->max_wire_version < WIRE_VERSION_5_0) { /* The single server may be part of an unseen replica set that may not * support aggr-with-write operations on secondaries. Force the read * preference to use a primary. */ if (must_use_primary) { *must_use_primary = true; } } if (sd->has_hello_response) { RETURN (sd); } else { TRACE ("Topology type single, [%s] is down", sd->host.host_and_port); RETURN (NULL); } } _mongoc_array_init (&suitable_servers, sizeof (mongoc_server_description_t *)); mongoc_topology_description_suitable_servers ( &suitable_servers, optype, topology, read_pref, must_use_primary, ds, local_threshold_ms); mongoc_server_description_t const *sd = NULL; if (suitable_servers.len != 0) { const int rand_n = _mongoc_rand_simple ((unsigned *) &topology->rand_seed); sd = _mongoc_array_index (&suitable_servers, mongoc_server_description_t *, (size_t) rand_n % suitable_servers.len); } _mongoc_array_destroy (&suitable_servers); if (sd) { TRACE ("Topology type [%s], selected [%s] [%s]", mongoc_topology_description_type (topology), mongoc_server_description_type (sd), sd->host.host_and_port); } RETURN (sd); } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_server_by_id -- * * Get the server description for @id, if that server is present * in @description. Otherwise, return NULL and fill out optional * @error. * * NOTE: In most cases, caller should create a duplicate of the * returned server description. * * Returns: * A mongoc_server_description_t *, or NULL. * * Side effects: * Fills out optional @error if server not found. * *-------------------------------------------------------------------------- */ mongoc_server_description_t * mongoc_topology_description_server_by_id (mongoc_topology_description_t *description, uint32_t id, bson_error_t *error) { return (mongoc_server_description_t *) mongoc_topology_description_server_by_id_const (description, id, error); } const mongoc_server_description_t * mongoc_topology_description_server_by_id_const (const mongoc_topology_description_t *td, uint32_t id, bson_error_t *error) { const mongoc_server_description_t *sd; BSON_ASSERT_PARAM (td); sd = mongoc_set_get_const (mc_tpld_servers_const (td), id); if (!sd) { bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "Could not find description for node %u", id); } return sd; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_remove_server -- * * If present, remove this server from this topology description. * * Returns: * None. * * Side effects: * Removes the server description from topology and destroys it. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_remove_server (mongoc_topology_description_t *description, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { BSON_ASSERT (description); BSON_ASSERT (server); _mongoc_topology_description_monitor_server_closed (description, log_and_monitor, server); mongoc_set_rm (mc_tpld_servers (description), server->id); /* Check if removing server resulted in an empty set of servers */ if (mc_tpld_servers_const (description)->items_len == 0) { MONGOC_WARNING ("Last server removed from topology"); } } typedef struct _mongoc_address_and_id_t { const char *address; /* IN */ bool found; /* OUT */ uint32_t id; /* OUT */ } mongoc_address_and_id_t; /* find the given server and stop iterating */ static bool _mongoc_topology_description_has_server_cb (const void *item, void *ctx /* IN - OUT */) { const mongoc_server_description_t *server = item; mongoc_address_and_id_t *data = (mongoc_address_and_id_t *) ctx; if (strcasecmp (data->address, server->connection_address) == 0) { data->found = true; data->id = server->id; return false; } return true; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_has_set_version -- * * Whether @topology's max replica set version has been set. * * Returns: * True if the max setVersion was ever set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_description_has_set_version (mongoc_topology_description_t *td) { return td->max_set_version != MONGOC_NO_SET_VERSION; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_topology_has_server -- * * Return true if @server is in @topology. If so, place its id in * @id if given. * * Returns: * True if server is in topology, false otherwise. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_description_has_server (mongoc_topology_description_t *description, const char *address, uint32_t *id /* OUT */) { mongoc_address_and_id_t data; BSON_ASSERT (description); BSON_ASSERT (address); data.address = address; data.found = false; mongoc_set_for_each_const (mc_tpld_servers_const (description), _mongoc_topology_description_has_server_cb, &data); if (data.found && id) { *id = data.id; } return data.found; } typedef struct _mongoc_address_and_type_t { const char *address; mongoc_server_description_type_t type; } mongoc_address_and_type_t; static bool _mongoc_label_unknown_member_cb (void *item, void *ctx) { mongoc_server_description_t *server = (mongoc_server_description_t *) item; mongoc_address_and_type_t *data = (mongoc_address_and_type_t *) ctx; if (strcasecmp (server->connection_address, data->address) == 0 && server->type == MONGOC_SERVER_UNKNOWN) { mongoc_server_description_set_state (server, data->type); return false; } return true; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_label_unknown_member -- * * Find the server description with the given @address and if its * type is UNKNOWN, set its type to @type. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_label_unknown_member (mongoc_topology_description_t *description, const char *address, mongoc_server_description_type_t type) { mongoc_address_and_type_t data; BSON_ASSERT (description); BSON_ASSERT (address); data.type = type; data.address = address; mongoc_set_for_each (mc_tpld_servers (description), _mongoc_label_unknown_member_cb, &data); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_set_state -- * * Change the state of this cluster and unblock things waiting * on a change of topology type. * * Returns: * None. * * Side effects: * Unblocks anything waiting on this description to change states. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_set_state (mongoc_topology_description_t *description, mongoc_topology_description_type_t type) { description->type = type; } static void _update_rs_type (mongoc_topology_description_t *topology) { if (_mongoc_topology_description_has_primary (topology)) { _mongoc_topology_description_set_state (topology, MONGOC_TOPOLOGY_RS_WITH_PRIMARY); } else { _mongoc_topology_description_set_state (topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY); } } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_check_if_has_primary -- * * If there is a primary in topology, set topology * type to RS_WITH_PRIMARY, otherwise set it to * RS_NO_PRIMARY. * * Returns: * None. * * Side effects: * Changes the topology type. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_check_if_has_primary (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { BSON_UNUSED (server); BSON_UNUSED (log_and_monitor); _update_rs_type (topology); } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_invalidate_server -- * * Invalidate a server if a network error occurred while using it in * another part of the client. Server description is set to type * UNKNOWN, the error is recorded, and other parameters are reset to * defaults. Pass in the reason for invalidation in @error. * * @todo Try to remove this function when CDRIVER-3654 is complete. * It is only called when an application thread needs to mark a server Unknown. * But an application error is also tied to other behavior, and should also * consider the connection generation. This logic is captured in * _mongoc_topology_handle_app_error. This should not be called directly */ void mongoc_topology_description_invalidate_server (mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, uint32_t id, const bson_error_t *error /* IN */) { BSON_ASSERT (error); if (td->type == MONGOC_TOPOLOGY_LOAD_BALANCED) { /* Load balancers must never be marked unknown. */ return; } /* send NULL hello reply */ mongoc_topology_description_handle_hello (td, log_and_monitor, id, NULL, MONGOC_RTT_UNSET, error); } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_add_server -- * * Add the specified server to the cluster topology if it is not * already a member. If @id, place its id in @id. * * Return: * True if the server was added or already existed in the topology, * false if an error occurred. * * Side effects: * None. * *-------------------------------------------------------------------------- */ bool mongoc_topology_description_add_server (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const char *server, uint32_t *id /* OUT */) { uint32_t server_id; mongoc_server_description_t *description; BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server (topology, server, &server_id)) { /* TODO this might not be an accurate count in all cases */ server_id = ++topology->max_server_id; description = BSON_ALIGNED_ALLOC0 (mongoc_server_description_t); mongoc_server_description_init (description, server, server_id); mongoc_set_add (mc_tpld_servers (topology), server_id, description); /* Note that libmongoc defers topology 'opening' until server selection or background monitoring begins, * and server monitoring must correspondingly only be 'opened' after the API has seen topology monitoring open. * * If the topology is already opened, we will send server opening events immediately. * Otherwise this has no effect, and server opening events will be sent later by * _mongoc_topology_description_monitor_opening. */ _mongoc_topology_description_monitor_server_opening (topology, log_and_monitor, description); } if (id) { *id = server_id; } return true; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_update_cluster_time -- * * Drivers Session Spec: Drivers MUST examine responses to server commands to * see if they contain a top level field named $clusterTime formatted as * follows: * * { * ... * $clusterTime : { * clusterTime : , * signature : { * hash : , * keyId : * } * }, * ... * } * * Whenever a driver receives a clusterTime from a server it MUST compare it * to the current highest seen clusterTime for the cluster. If the new * clusterTime is higher than the highest seen clusterTime it MUST become * the new highest seen clusterTime. Two clusterTimes are compared using * only the BsonTimestamp value of the clusterTime embedded field (be sure to * include both the timestamp and the increment of the BsonTimestamp in the * comparison). The signature field does not participate in the comparison. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_update_cluster_time (mongoc_topology_description_t *td, const bson_t *reply) { bson_iter_t iter; bson_iter_t child; const uint8_t *data; uint32_t size; bson_t cluster_time; if (!reply || !bson_iter_init_find (&iter, reply, "$clusterTime")) { return; } if (!BSON_ITER_HOLDS_DOCUMENT (&iter) || !bson_iter_recurse (&iter, &child)) { MONGOC_ERROR ("Can't parse $clusterTime"); return; } bson_iter_document (&iter, &size, &data); BSON_ASSERT (bson_init_static (&cluster_time, data, (size_t) size)); if (bson_empty (&td->cluster_time) || _mongoc_cluster_time_greater (&cluster_time, &td->cluster_time)) { bson_destroy (&td->cluster_time); bson_copy_to (&cluster_time, &td->cluster_time); } } static void _mongoc_topology_description_add_new_servers (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { bson_iter_t member_iter; const bson_t *rs_members[3]; int i; rs_members[0] = &server->hosts; rs_members[1] = &server->arbiters; rs_members[2] = &server->passives; for (i = 0; i < 3; i++) { BSON_ASSERT (bson_iter_init (&member_iter, rs_members[i])); while (bson_iter_next (&member_iter)) { mongoc_topology_description_add_server (topology, log_and_monitor, bson_iter_utf8 (&member_iter, NULL), NULL); } } } typedef struct _mongoc_primary_and_topology_t { mongoc_topology_description_t *topology; const mongoc_server_description_t *primary; } mongoc_primary_and_topology_t; /* invalidate old primaries */ static bool _mongoc_topology_description_invalidate_primaries_cb (void *item, void *ctx) { mongoc_server_description_t *server = (mongoc_server_description_t *) item; mongoc_primary_and_topology_t *data = (mongoc_primary_and_topology_t *) ctx; if (server->id != data->primary->id && server->type == MONGOC_SERVER_RS_PRIMARY) { mongoc_server_description_set_state (server, MONGOC_SERVER_UNKNOWN); mongoc_server_description_set_set_version (server, MONGOC_NO_SET_VERSION); mongoc_server_description_set_election_id (server, NULL); mongoc_server_description_reset (server); } return true; } /* Remove and destroy all replica set members not in primary's hosts lists */ static void _mongoc_topology_description_remove_unreported_servers (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *primary) { mongoc_array_t to_remove; _mongoc_array_init (&to_remove, sizeof (mongoc_server_description_t *)); /* Accumulate servers to be removed - do this before calling * _mongoc_topology_description_remove_server, which could call * mongoc_server_description_cleanup on the primary itself if it * doesn't report its own connection_address in its hosts list. * See hosts_differ_from_seeds.json */ for (size_t i = 0u; i < mc_tpld_servers_const (topology)->items_len; i++) { const mongoc_server_description_t *member = mongoc_set_get_item_const (mc_tpld_servers_const (topology), i); const char *address = member->connection_address; if (!mongoc_server_description_has_rs_member (primary, address)) { _mongoc_array_append_val (&to_remove, member); } } /* now it's safe to call _mongoc_topology_description_remove_server, * even on the primary */ for (size_t i = 0u; i < to_remove.len; i++) { const mongoc_server_description_t *member = _mongoc_array_index (&to_remove, mongoc_server_description_t *, i); _mongoc_topology_description_remove_server (topology, log_and_monitor, member); } _mongoc_array_destroy (&to_remove); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_matches_me -- * * Server Discovery And Monitoring Spec: "Removal from the topology of * seed list members where the "me" property does not match the address * used to connect prevents clients from being able to select a server, * only to fail to re-select that server once the primary has responded. * * Returns: * True if "me" matches "connection_address". * * Side Effects: * None. * *-------------------------------------------------------------------------- */ static bool _mongoc_topology_description_matches_me (const mongoc_server_description_t *server) { BSON_ASSERT (server->connection_address); if (!server->me) { /* "me" is unknown: consider it a match */ return true; } return strcasecmp (server->connection_address, server->me) == 0; } /* *-------------------------------------------------------------------------- * * _mongoc_update_rs_from_primary -- * * First, determine that this is really the primary: * -If this node isn't in the cluster, do nothing. * -If the cluster's set name is null, set it to node's set name. * Otherwise if the cluster's set name is different from node's, * we found a rogue primary, so remove it from the cluster and * check the cluster for a primary, then return. * -If any of the members of cluster reports an address different * from node's, node cannot be the primary. * Now that we know this is the primary: * -If any hosts, passives, or arbiters in node's description aren't * in the cluster, add them as UNKNOWN servers. * -If the cluster has any servers that aren't in node's description, * remove and destroy them. * Finally, check the cluster for the new primary. * * Returns: * None. * * Side effects: * Changes to the cluster, possible removal of cluster nodes. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_rs_from_primary (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { mongoc_primary_and_topology_t data; bson_error_t error; BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server (topology, server->connection_address, NULL)) return; /* If server->set_name was null this function wouldn't be called from * mongoc_server_description_handle_hello(). static code analyzers however * don't know that so we check for it explicitly. */ if (server->set_name) { /* 'Server' can only be the primary if it has the right rs name */ if (!topology->set_name) { topology->set_name = bson_strdup (server->set_name); } else if (strcmp (topology->set_name, server->set_name) != 0) { _mongoc_topology_description_remove_server (topology, log_and_monitor, server); _update_rs_type (topology); return; } } if (server->max_wire_version >= WIRE_VERSION_6_0) { /* MongoDB 6.0+ */ if (_mongoc_server_description_primary_is_not_stale (topology, server)) { _mongoc_topology_description_set_max_election_id (topology, server); _mongoc_topology_description_set_max_set_version (topology, server); } else { bson_set_error ( &error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "member's setVersion or electionId is stale"); mongoc_topology_description_invalidate_server (topology, log_and_monitor, server->id, &error); _update_rs_type (topology); return; } } else { // old comparison rules, namely setVersion is checked before electionId if (mongoc_server_description_has_set_version (server) && mongoc_server_description_has_election_id (server)) { /* Server Discovery And Monitoring Spec: "The client remembers the * greatest electionId reported by a primary, and distrusts primaries * with lesser electionIds. This prevents the client from oscillating * between the old and new primary during a split-brain period." */ if (_mongoc_topology_description_later_election (topology, server)) { // stale primary code return: bson_set_error ( &error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "member's setVersion or electionId is stale"); mongoc_topology_description_invalidate_server (topology, log_and_monitor, server->id, &error); _update_rs_type (topology); return; } /* server's electionId >= topology's max electionId */ _mongoc_topology_description_set_max_election_id (topology, server); } if (mongoc_server_description_has_set_version (server) && (!_mongoc_topology_description_has_set_version (topology) || server->set_version > topology->max_set_version)) { _mongoc_topology_description_set_max_set_version (topology, server); } } /* 'Server' is the primary! Invalidate other primaries if found */ data.primary = server; data.topology = topology; mongoc_set_for_each (mc_tpld_servers (topology), _mongoc_topology_description_invalidate_primaries_cb, &data); /* Add to topology description any new servers primary knows about */ _mongoc_topology_description_add_new_servers (topology, log_and_monitor, server); /* Remove from topology description any servers primary doesn't know about */ _mongoc_topology_description_remove_unreported_servers (topology, log_and_monitor, server); /* Finally, set topology type */ _update_rs_type (topology); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_update_rs_without_primary -- * * Update cluster's information when there is no primary. * * Returns: * None. * * Side Effects: * Alters cluster state, may remove node from cluster. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_rs_without_primary (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server (topology, server->connection_address, NULL)) { return; } /* make sure we're talking about the same replica set */ if (server->set_name) { if (!topology->set_name) { topology->set_name = bson_strdup (server->set_name); } else if (strcmp (topology->set_name, server->set_name) != 0) { _mongoc_topology_description_remove_server (topology, log_and_monitor, server); return; } } /* Add new servers that this replica set member knows about */ _mongoc_topology_description_add_new_servers (topology, log_and_monitor, server); /* If this server thinks there is a primary, label it POSSIBLE_PRIMARY */ if (server->current_primary) { _mongoc_topology_description_label_unknown_member ( topology, server->current_primary, MONGOC_SERVER_POSSIBLE_PRIMARY); } if (!_mongoc_topology_description_matches_me (server)) { _mongoc_topology_description_remove_server (topology, log_and_monitor, server); return; } } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_update_rs_with_primary_from_member -- * * Update cluster's information when there is a primary, but the * update is coming from another replica set member. * * Returns: * None. * * Side Effects: * Alters cluster state. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_rs_with_primary_from_member ( mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server (topology, server->connection_address, NULL)) { return; } /* set_name should never be null here */ if (strcmp (topology->set_name, server->set_name) != 0) { _mongoc_topology_description_remove_server (topology, log_and_monitor, server); _update_rs_type (topology); return; } if (!_mongoc_topology_description_matches_me (server)) { _mongoc_topology_description_remove_server (topology, log_and_monitor, server); return; } /* If there is no primary, label server's current_primary as the * POSSIBLE_PRIMARY */ if (!_mongoc_topology_description_has_primary (topology) && server->current_primary) { _mongoc_topology_description_set_state (topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY); _mongoc_topology_description_label_unknown_member ( topology, server->current_primary, MONGOC_SERVER_POSSIBLE_PRIMARY); } } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_set_topology_type_to_sharded -- * * Sets topology's type to SHARDED. * * Returns: * None * * Side effects: * Alter's topology's type * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_set_topology_type_to_sharded (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { BSON_UNUSED (server); BSON_UNUSED (log_and_monitor); _mongoc_topology_description_set_state (topology, MONGOC_TOPOLOGY_SHARDED); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_transition_unknown_to_rs_no_primary -- * * Encapsulates transition from cluster state UNKNOWN to * RS_NO_PRIMARY. Sets the type to RS_NO_PRIMARY, * then updates the replica set accordingly. * * Returns: * None. * * Side effects: * Changes topology state. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_transition_unknown_to_rs_no_primary ( mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { _mongoc_topology_description_set_state (topology, MONGOC_TOPOLOGY_RS_NO_PRIMARY); _mongoc_topology_description_update_rs_without_primary (topology, log_and_monitor, server); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_remove_and_check_primary -- * * Remove the server and check if the topology still has a primary. * * Returns: * None. * * Side effects: * Removes server from topology and destroys it. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_remove_and_check_primary (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { _mongoc_topology_description_remove_server (topology, log_and_monitor, server); _update_rs_type (topology); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_update_unknown_with_standalone -- * * If the cluster doesn't contain this server, do nothing. * Otherwise, if the topology only has one seed, change its * type to SINGLE. If the topology has multiple seeds, it does not * include us, so remove this server and destroy it. * * Returns: * None. * * Side effects: * Changes the topology type, might remove server from topology. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_unknown_with_standalone (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server) { BSON_ASSERT (topology); BSON_ASSERT (server); if (!_mongoc_topology_description_has_server (topology, server->connection_address, NULL)) return; if (mc_tpld_servers_const (topology)->items_len > 1) { /* This cluster contains other servers, it cannot be a standalone. */ _mongoc_topology_description_remove_server (topology, log_and_monitor, server); } else { _mongoc_topology_description_set_state (topology, MONGOC_TOPOLOGY_SINGLE); } } /* *-------------------------------------------------------------------------- * * This table implements the 'ToplogyType' table outlined in the Server * Discovery and Monitoring spec. Each row represents a server type, * and each column represents the topology type. Given a current topology * type T and a newly-observed server type S, use the function at * state_transions[S][T] to transition to a new state. * * Rows should be read like so: * { server type for this row * UNKNOWN, * SHARDED, * RS_NO_PRIMARY, * RS_WITH_PRIMARY * } * *-------------------------------------------------------------------------- */ typedef void (*transition_t) (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, const mongoc_server_description_t *server); transition_t gSDAMTransitionTable[MONGOC_SERVER_DESCRIPTION_TYPES][MONGOC_TOPOLOGY_DESCRIPTION_TYPES] = { { /* UNKNOWN */ NULL, /* MONGOC_TOPOLOGY_UNKNOWN */ NULL, /* MONGOC_TOPOLOGY_SHARDED */ NULL, /* MONGOC_TOPOLOGY_RS_NO_PRIMARY */ _mongoc_topology_description_check_if_has_primary /* MONGOC_TOPOLOGY_RS_WITH_PRIMARY */ }, {/* STANDALONE */ _mongoc_topology_description_update_unknown_with_standalone, _mongoc_topology_description_remove_server, _mongoc_topology_description_remove_server, _mongoc_topology_description_remove_and_check_primary}, {/* MONGOS */ _mongoc_topology_description_set_topology_type_to_sharded, NULL, _mongoc_topology_description_remove_server, _mongoc_topology_description_remove_and_check_primary}, {/* POSSIBLE_PRIMARY */ NULL, NULL, NULL, NULL}, {/* PRIMARY */ _mongoc_topology_description_update_rs_from_primary, _mongoc_topology_description_remove_server, _mongoc_topology_description_update_rs_from_primary, _mongoc_topology_description_update_rs_from_primary}, {/* SECONDARY */ _mongoc_topology_description_transition_unknown_to_rs_no_primary, _mongoc_topology_description_remove_server, _mongoc_topology_description_update_rs_without_primary, _mongoc_topology_description_update_rs_with_primary_from_member}, {/* ARBITER */ _mongoc_topology_description_transition_unknown_to_rs_no_primary, _mongoc_topology_description_remove_server, _mongoc_topology_description_update_rs_without_primary, _mongoc_topology_description_update_rs_with_primary_from_member}, {/* RS_OTHER */ _mongoc_topology_description_transition_unknown_to_rs_no_primary, _mongoc_topology_description_remove_server, _mongoc_topology_description_update_rs_without_primary, _mongoc_topology_description_update_rs_with_primary_from_member}, {/* RS_GHOST */ NULL, _mongoc_topology_description_remove_server, NULL, _mongoc_topology_description_check_if_has_primary}}; /* *-------------------------------------------------------------------------- * * _tpld_type_str -- * * Get this topology's type, one of the types defined in the Server * Discovery And Monitoring Spec. * * Returns: * A string. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static const char * _tpld_type_str (mongoc_topology_description_type_t type) { switch (type) { case MONGOC_TOPOLOGY_UNKNOWN: return "Unknown"; case MONGOC_TOPOLOGY_SHARDED: return "Sharded"; case MONGOC_TOPOLOGY_RS_NO_PRIMARY: return "RSNoPrimary"; case MONGOC_TOPOLOGY_RS_WITH_PRIMARY: return "RSWithPrimary"; case MONGOC_TOPOLOGY_SINGLE: return "Single"; case MONGOC_TOPOLOGY_LOAD_BALANCED: return "LoadBalanced"; case MONGOC_TOPOLOGY_DESCRIPTION_TYPES: default: MONGOC_ERROR ("Invalid mongoc_topology_description_type_t type"); return "Invalid"; } } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_update_session_timeout -- * * Fill out td.session_timeout_minutes. * * Server Discovery and Monitoring Spec: "set logicalSessionTimeoutMinutes * to the smallest logicalSessionTimeoutMinutes value among all * ServerDescriptions of known ServerType. If any ServerDescription of * known ServerType has a null logicalSessionTimeoutMinutes, then * logicalSessionTimeoutMinutes MUST be set to null." * * -------------------------------------------------------------------------- */ static void _mongoc_topology_description_update_session_timeout (mongoc_topology_description_t *td) { mongoc_set_t *set; mongoc_server_description_t *sd; set = mc_tpld_servers (td); td->session_timeout_minutes = MONGOC_NO_SESSIONS; for (size_t i = 0; i < set->items_len; i++) { sd = (mongoc_server_description_t *) mongoc_set_get_item (set, i); if (!_is_data_node (sd)) { continue; } if (sd->session_timeout_minutes == MONGOC_NO_SESSIONS) { td->session_timeout_minutes = MONGOC_NO_SESSIONS; return; } else if (td->session_timeout_minutes == MONGOC_NO_SESSIONS) { td->session_timeout_minutes = sd->session_timeout_minutes; } else if (td->session_timeout_minutes > sd->session_timeout_minutes) { td->session_timeout_minutes = sd->session_timeout_minutes; } } } /* *-------------------------------------------------------------------------- * * _mongoc_topology_description_check_compatible -- * * Fill out td.compatibility_error if any server's wire versions do * not overlap with ours. Otherwise clear td.compatibility_error. * * If any server is incompatible, the topology as a whole is considered * incompatible. * *-------------------------------------------------------------------------- */ static void _mongoc_topology_description_check_compatible (mongoc_topology_description_t *td) { mongoc_set_t const *const servers = mc_tpld_servers_const (td); memset (&td->compatibility_error, 0, sizeof (bson_error_t)); for (size_t i = 0; i < servers->items_len; i++) { mongoc_server_description_t const *const sd = mongoc_set_get_item_const (servers, i); if (sd->type == MONGOC_SERVER_UNKNOWN || sd->type == MONGOC_SERVER_POSSIBLE_PRIMARY) { continue; } if (sd->min_wire_version > WIRE_VERSION_MAX) { bson_set_error (&td->compatibility_error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "Server at %s requires wire version %d," " but this version of libmongoc only supports up to %d", sd->host.host_and_port, sd->min_wire_version, WIRE_VERSION_MAX); } else if (sd->max_wire_version < WIRE_VERSION_MIN) { bson_set_error (&td->compatibility_error, MONGOC_ERROR_PROTOCOL, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "Server at %s reports wire version %d, but this" " version of libmongoc requires at least %d (MongoDB %s)", sd->host.host_and_port, sd->max_wire_version, WIRE_VERSION_MIN, _mongoc_wire_version_to_server_version (WIRE_VERSION_MIN)); } } } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_handle_hello -- * * Handle a hello. This is called by the background SDAM process, * and by client when performing a handshake or invalidating servers. * If there was an error calling hello, pass it in as @error. * *-------------------------------------------------------------------------- */ void mongoc_topology_description_handle_hello (mongoc_topology_description_t *topology, const mongoc_log_and_monitor_instance_t *log_and_monitor, uint32_t server_id, const bson_t *hello_response, int64_t rtt_msec, const bson_error_t *error /* IN */) { mongoc_topology_description_t *prev_td = NULL; mongoc_server_description_t *prev_sd = NULL; mongoc_server_description_t *sd; bson_iter_t iter; /* sd_changed is set if the server description meaningfully changed AND * callbacks are registered. */ bool sd_changed = false; BSON_ASSERT (topology); BSON_ASSERT (server_id != 0); sd = mongoc_topology_description_server_by_id (topology, server_id, NULL); if (!sd) { return; /* server already removed from topology */ } if (log_and_monitor->apm_callbacks.topology_changed) { prev_td = BSON_ALIGNED_ALLOC0 (mongoc_topology_description_t); _mongoc_topology_description_copy_to (topology, prev_td); } if (hello_response && bson_iter_init_find (&iter, hello_response, "topologyVersion") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_t incoming_topology_version; const uint8_t *bytes; uint32_t len; bson_iter_document (&iter, &len, &bytes); BSON_ASSERT (bson_init_static (&incoming_topology_version, bytes, len)); if (mongoc_server_description_topology_version_cmp (&sd->topology_version, &incoming_topology_version) == 1) { TRACE ("%s", "topology version is strictly less. Skipping."); if (prev_td) { mongoc_topology_description_cleanup (prev_td); bson_free (prev_td); } return; } } if (log_and_monitor->apm_callbacks.topology_changed || log_and_monitor->apm_callbacks.server_changed) { /* Only copy the previous server description if a monitoring callback is * registered. */ prev_sd = mongoc_server_description_new_copy (sd); } DUMP_BSON (hello_response); /* pass the current error in */ mongoc_server_description_handle_hello (sd, hello_response, rtt_msec, error); /* if the user specified a set_name in the connection string * and they are in topology type single, check that the set name * matches. */ if (topology->set_name && topology->type == MONGOC_TOPOLOGY_SINGLE) { bool wrong_set_name = false; bson_error_t set_name_err = {0}; if (!sd->set_name) { wrong_set_name = true; bson_set_error (&set_name_err, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "no reported set name, but expected '%s'", topology->set_name); } else if (0 != strcmp (sd->set_name, topology->set_name)) { wrong_set_name = true; bson_set_error (&set_name_err, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "reported set name '%s' does not match '%s'", sd->set_name, topology->set_name); } if (wrong_set_name) { /* Replace with unknown. */ TRACE ("%s", "wrong set name"); mongoc_server_description_handle_hello (sd, NULL, MONGOC_RTT_UNSET, &set_name_err); } } mongoc_topology_description_update_cluster_time (topology, hello_response); if (prev_sd) { sd_changed = !_mongoc_server_description_equal (prev_sd, sd); } if (sd_changed) { _mongoc_topology_description_monitor_server_changed (topology, log_and_monitor, prev_sd, sd); } if (gSDAMTransitionTable[sd->type][topology->type]) { TRACE ("Topology description %s handling server description %s", _tpld_type_str (topology->type), mongoc_server_description_type (sd)); gSDAMTransitionTable[sd->type][topology->type](topology, log_and_monitor, sd); } else { TRACE ("Topology description %s ignoring server description %s", _tpld_type_str (topology->type), mongoc_server_description_type (sd)); } _mongoc_topology_description_update_session_timeout (topology); /* Don't bother checking wire version compatibility if we already errored */ if (hello_response && (!error || !error->code)) { _mongoc_topology_description_check_compatible (topology); } /* If server description did not change, then neither did topology * description */ if (sd_changed) { _mongoc_topology_description_monitor_changed (prev_td, topology, log_and_monitor); } if (prev_td) { mongoc_topology_description_cleanup (prev_td); bson_free (prev_td); } mongoc_server_description_destroy (prev_sd); } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_has_readable_server -- * * SDAM Monitoring Spec: * "Determines if the topology has a readable server available." * * NOTE: this method should only be called by user code in an SDAM * Monitoring callback. * *-------------------------------------------------------------------------- */ bool mongoc_topology_description_has_readable_server (const mongoc_topology_description_t *td, const mongoc_read_prefs_t *prefs) { bson_error_t error; if (!mongoc_topology_compatible (td, NULL, &error)) { return false; } /* local threshold argument doesn't matter */ return mongoc_topology_description_select (td, MONGOC_SS_READ, prefs, NULL, NULL, 0) != NULL; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_has_writable_server -- * * SDAM Monitoring Spec: * "Determines if the topology has a writable server available." * * NOTE: this method should only be called by user code in an SDAM * Monitoring callback. * *-------------------------------------------------------------------------- */ bool mongoc_topology_description_has_writable_server (const mongoc_topology_description_t *td) { bson_error_t error; if (!mongoc_topology_compatible (td, NULL, &error)) { return false; } return mongoc_topology_description_select (td, MONGOC_SS_WRITE, NULL, NULL, NULL, 0) != NULL; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_type -- * * Get this topology's type, one of the types defined in the Server * Discovery And Monitoring Spec. * * NOTE: this method should only be called by user code in an SDAM * Monitoring callback. * * Returns: * A string. * *-------------------------------------------------------------------------- */ const char * mongoc_topology_description_type (const mongoc_topology_description_t *td) { switch (td->type) { case MONGOC_TOPOLOGY_UNKNOWN: return "Unknown"; case MONGOC_TOPOLOGY_SHARDED: return "Sharded"; case MONGOC_TOPOLOGY_RS_NO_PRIMARY: return "ReplicaSetNoPrimary"; case MONGOC_TOPOLOGY_RS_WITH_PRIMARY: return "ReplicaSetWithPrimary"; case MONGOC_TOPOLOGY_SINGLE: return "Single"; case MONGOC_TOPOLOGY_LOAD_BALANCED: return "LoadBalanced"; case MONGOC_TOPOLOGY_DESCRIPTION_TYPES: default: fprintf (stderr, "ERROR: Unknown topology type %d\n", (int) td->type); BSON_ASSERT (0); } return NULL; } /* *-------------------------------------------------------------------------- * * mongoc_topology_description_get_servers -- * * Fetch an array of server descriptions for all known servers in the * topology. * * Returns: * An array you must free with mongoc_server_descriptions_destroy_all. * *-------------------------------------------------------------------------- */ mongoc_server_description_t ** mongoc_topology_description_get_servers (const mongoc_topology_description_t *td, size_t *n /* OUT */) { const mongoc_set_t *const set = mc_tpld_servers_const (BSON_ASSERT_PTR_INLINE (td)); /* enough room for all descriptions, even if some are unknown */ mongoc_server_description_t **sds = bson_malloc0 (sizeof (mongoc_server_description_t *) * set->items_len); BSON_ASSERT_PARAM (n); *n = 0; for (size_t i = 0; i < set->items_len; ++i) { const mongoc_server_description_t *sd = mongoc_set_get_item_const (set, i); if (sd->type != MONGOC_SERVER_UNKNOWN) { sds[*n] = mongoc_server_description_new_copy (sd); ++(*n); } } return sds; } typedef struct { mongoc_host_list_t *host_list; size_t num_missing; } _count_num_hosts_to_remove_ctx_t; static bool _count_num_hosts_to_remove (void *sd_void, void *ctx_void) { mongoc_server_description_t *sd; _count_num_hosts_to_remove_ctx_t *ctx; mongoc_host_list_t *host_list; sd = sd_void; ctx = ctx_void; host_list = ctx->host_list; if (!_mongoc_host_list_contains_one (host_list, &sd->host)) { ++ctx->num_missing; } return true; } typedef struct { mongoc_host_list_t *host_list; mongoc_topology_description_t *td; const mongoc_log_and_monitor_instance_t *log_and_monitor; } _remove_if_not_in_host_list_ctx_t; static bool _remove_if_not_in_host_list_cb (void *sd_void, void *ctx_void) { _remove_if_not_in_host_list_ctx_t *ctx; mongoc_topology_description_t *td; mongoc_server_description_t *sd; mongoc_host_list_t *host_list; ctx = ctx_void; sd = sd_void; host_list = ctx->host_list; td = ctx->td; if (_mongoc_host_list_contains_one (host_list, &sd->host)) { return true; } _mongoc_topology_description_remove_server (td, ctx->log_and_monitor, sd); return true; } void mongoc_topology_description_reconcile (mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, mongoc_host_list_t *host_list) { mongoc_set_t *servers; size_t host_list_length; size_t num_missing; BSON_ASSERT_PARAM (td); servers = mc_tpld_servers (td); host_list_length = _mongoc_host_list_length (host_list); /* Avoid removing all servers in topology, even temporarily, by deferring * actual removal until after new hosts have been added. */ { _count_num_hosts_to_remove_ctx_t ctx; ctx.host_list = host_list; ctx.num_missing = 0u; mongoc_set_for_each (servers, _count_num_hosts_to_remove, &ctx); num_missing = ctx.num_missing; } /* Polling SRV Records for mongos Discovery Spec: If srvMaxHosts is zero or * greater than or equal to the number of valid hosts, each valid new host * MUST be added to the topology as Unknown. */ if (td->max_hosts == 0 || (size_t) td->max_hosts >= host_list_length) { mongoc_host_list_t *host; LL_FOREACH (host_list, host) { /* "add" is really an "upsert" */ mongoc_topology_description_add_server (td, log_and_monitor, host->host_and_port, NULL); } } /* Polling SRV Records for mongos Discovery Spec: If srvMaxHosts is greater * than zero and less than the number of valid hosts, valid new hosts MUST be * randomly selected and added to the topology as Unknown until the topology * has srvMaxHosts hosts. */ else { const size_t max_with_missing = td->max_hosts + num_missing; size_t idx = 0u; size_t hl_array_size = 0u; /* Polling SRV Records for mongos Discovery Spec: Drivers MUST use the * same randomization algorithm as they do for initial selection. * Do not limit size of results yet (pass host_list_length) as we want to * update any existing hosts in the topology, but add new hosts. */ const mongoc_host_list_t *const *hl_array = _mongoc_apply_srv_max_hosts (host_list, host_list_length, &hl_array_size); for (idx = 0u; servers->items_len < max_with_missing && idx < hl_array_size; ++idx) { const mongoc_host_list_t *const elem = hl_array[idx]; /* "add" is really an "upsert" */ mongoc_topology_description_add_server (td, log_and_monitor, elem->host_and_port, NULL); } /* There should not be a situation where all items in the valid host list * were traversed without the number of hosts in the topology reaching * srvMaxHosts. */ BSON_ASSERT (servers->items_len == max_with_missing); bson_free ((void *) hl_array); } /* Polling SRV Records for mongos Discovery Spec: For all verified host * names, as returned through the DNS SRV query, the driver MUST remove * all hosts that are part of the topology, but are no longer in the * returned set of valid hosts. */ { _remove_if_not_in_host_list_ctx_t ctx; ctx.host_list = host_list; ctx.td = td; ctx.log_and_monitor = log_and_monitor; mongoc_set_for_each (servers, _remove_if_not_in_host_list_cb, &ctx); } /* At this point, the number of hosts in the host list should not exceed * srvMaxHosts. */ BSON_ASSERT (td->max_hosts == 0 || servers->items_len <= (size_t) td->max_hosts); } void _mongoc_topology_description_clear_connection_pool (mongoc_topology_description_t *td, uint32_t server_id, const bson_oid_t *service_id) { mongoc_server_description_t *sd; bson_error_t error; BSON_ASSERT (service_id); sd = mongoc_topology_description_server_by_id (td, server_id, &error); if (!sd) { /* Server removed, ignore and ignore error. */ return; } TRACE ("clearing pool for server: %s", sd->host.host_and_port); mc_tpl_sd_increment_generation (sd, service_id); } void mongoc_deprioritized_servers_add_if_sharded (mongoc_deprioritized_servers_t *ds, mongoc_topology_description_type_t topology_type, const mongoc_server_description_t *sd) { // In a sharded cluster, the server on which the operation failed MUST // be provided to the server selection mechanism as a deprioritized // server. if (topology_type == MONGOC_TOPOLOGY_SHARDED) { TRACE ("deprioritization: add to list: %s (id: %" PRIu32 ")", sd->host.host_and_port, sd->id); mongoc_deprioritized_servers_add (ds, sd); } } bool mongoc_topology_description_append_contents_to_bson (const mongoc_topology_description_t *td, bson_t *bson, mongoc_topology_description_content_flags_t flags, mongoc_server_description_content_flags_t servers_flags) { // Follow the language-independent format from the SDAM spec. if ((flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_TYPE) && !BSON_APPEND_UTF8 (bson, "type", mongoc_topology_description_type (td))) { return false; } if ((flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_SET_NAME) && td->set_name && !BSON_APPEND_UTF8 (bson, "setName", td->set_name)) { return false; } if ((flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_MAX_ELECTION_ID) && !mcommon_oid_is_zero (&td->max_election_id) && !BSON_APPEND_OID (bson, "maxElectionId", &td->max_election_id)) { return false; } if ((flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_MAX_SET_VERSION) && MONGOC_NO_SET_VERSION != td->max_set_version && !BSON_APPEND_INT64 (bson, "maxSetVersion", td->max_set_version)) { return false; } if (flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_SERVERS) { const mongoc_set_t *const set = mc_tpld_servers_const (BSON_ASSERT_PTR_INLINE (td)); bson_array_builder_t *array; if (BSON_APPEND_ARRAY_BUILDER_BEGIN (bson, "servers", &array)) { bool ok = true; for (size_t i = 0; ok && i < set->items_len; i++) { const mongoc_server_description_t *sd = mongoc_set_get_item_const (set, i); bson_t child; if (!bson_array_builder_append_document_begin (array, &child)) { ok = false; } else { ok &= mongoc_server_description_append_contents_to_bson (sd, &child, servers_flags); ok &= bson_array_builder_append_document_end (array, &child); } } if (!bson_append_array_builder_end (bson, array) || !ok) { return false; } } else { return false; } } if ((flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_STALE) && !BSON_APPEND_BOOL (bson, "stale", td->stale)) { return false; } if ((flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_COMPATIBLE) && !BSON_APPEND_BOOL (bson, "compatible", td->compatibility_error.code == 0)) { return false; } if ((flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_COMPATIBILITY_ERROR) && 0 != td->compatibility_error.code && !BSON_APPEND_UTF8 (bson, "compatibilityError", td->compatibility_error.message)) { return false; } if ((flags & MONGOC_TOPOLOGY_DESCRIPTION_CONTENT_FLAG_LOGICAL_SESSION_TIMEOUT_MINUTES) && MONGOC_NO_SESSIONS != td->session_timeout_minutes && !BSON_APPEND_INT64 (bson, "logicalSessionTimeoutMinutes", td->session_timeout_minutes)) { return false; } return true; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-description.h0000644000175100001660000000351414760300420025337 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TOPOLOGY_DESCRIPTION_H #define MONGOC_TOPOLOGY_DESCRIPTION_H #include #include #include BSON_BEGIN_DECLS typedef struct _mongoc_topology_description_t mongoc_topology_description_t; MONGOC_EXPORT (void) mongoc_topology_description_destroy (mongoc_topology_description_t *description); MONGOC_EXPORT (mongoc_topology_description_t *) mongoc_topology_description_new_copy (const mongoc_topology_description_t *description) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (bool) mongoc_topology_description_has_readable_server (const mongoc_topology_description_t *td, const mongoc_read_prefs_t *prefs); MONGOC_EXPORT (bool) mongoc_topology_description_has_writable_server (const mongoc_topology_description_t *td); MONGOC_EXPORT (const char *) mongoc_topology_description_type (const mongoc_topology_description_t *td); MONGOC_EXPORT (mongoc_server_description_t **) mongoc_topology_description_get_servers (const mongoc_topology_description_t *td, size_t *n) BSON_GNUC_WARN_UNUSED_RESULT; BSON_END_DECLS #endif /* MONGOC_TOPOLOGY_DESCRIPTION_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-private.h0000644000175100001660000005663714760300420024504 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TOPOLOGY_PRIVATE_H #define MONGOC_TOPOLOGY_PRIVATE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #define MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS 500 #define MONGOC_TOPOLOGY_SOCKET_CHECK_INTERVAL_MS 5000 #define MONGOC_TOPOLOGY_COOLDOWN_MS 5000 #define MONGOC_TOPOLOGY_LOCAL_THRESHOLD_MS 15 #define MONGOC_TOPOLOGY_SERVER_SELECTION_TIMEOUT_MS 30000 #define MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_MULTI_THREADED 10000 #define MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_SINGLE_THREADED 60000 #define MONGOC_TOPOLOGY_MIN_RESCAN_SRV_INTERVAL_MS 60000 typedef enum { MONGOC_TOPOLOGY_SCANNER_OFF, MONGOC_TOPOLOGY_SCANNER_BG_RUNNING, MONGOC_TOPOLOGY_SCANNER_SHUTTING_DOWN } mongoc_topology_scanner_state_t; typedef enum mongoc_topology_cse_state_t { MONGOC_CSE_DISABLED, MONGOC_CSE_STARTING, MONGOC_CSE_ENABLED, } mongoc_topology_cse_state_t; struct _mongoc_background_monitor_t; struct _mongoc_client_pool_t; struct mongoc_structured_log_instance_t; typedef enum { MONGOC_RR_SRV, MONGOC_RR_TXT } mongoc_rr_type_t; typedef struct _mongoc_rr_data_t { /* Number of records returned by DNS. */ uint32_t count; /* Set to lowest TTL found when polling SRV records. */ uint32_t min_ttl; /* Set to the resulting host list when polling SRV records */ mongoc_host_list_t *hosts; /* Set to the TXT record when polling for TXT */ char *txt_record_opts; } mongoc_rr_data_t; struct _mongoc_topology_t; MONGOC_DECL_SPECIAL_TS_POOL (mongoc_server_session_t, mongoc_server_session_pool, struct _mongoc_topology_t, /* ctor/dtor/prune are defined in the new_with_params call */ NULL, NULL, NULL) typedef bool (*_mongoc_rr_resolver_fn) (const char *hostname, mongoc_rr_type_t rr_type, mongoc_rr_data_t *rr_data, size_t initial_buffer_size, bool prefer_tcp, bson_error_t *error); /** * @brief A reference-counted reference to a topology description. * * The referred-to topology description should be access via the `.ptr` member * of this object. */ typedef union mc_shared_tpld { /* Private: The reference-counted shared pointer that manages the topology * description. */ mongoc_shared_ptr _sptr_; /** The pointed-to topology description */ mongoc_topology_description_t const *ptr; } mc_shared_tpld; /** A null-pointer initializer for an `mc_shared_tpld` */ #define MC_SHARED_TPLD_NULL ((mc_shared_tpld){._sptr_ = MONGOC_SHARED_PTR_NULL}) typedef struct _mongoc_topology_t { /** * @brief The topology description. Do not access directly. Instead, use * mc_tpld_take_ref() */ mc_shared_tpld _shared_descr_; /* topology->uri is initialized as a copy of the client/pool's URI. * For a "mongodb+srv://" URI, topology->uri is then updated in * mongoc_topology_new() after initial seedlist discovery. */ mongoc_uri_t *uri; mongoc_topology_scanner_t *scanner; bool server_selection_try_once; int64_t last_scan; int64_t local_threshold_msec; int64_t connect_timeout_msec; int64_t server_selection_timeout_msec; /* defaults to 500ms, configurable by tests */ int64_t min_heartbeat_frequency_msec; /* Minimum of SRV record TTLs, but no lower than 60 seconds. * May be zero for non-SRV/non-MongoS topology. * DO NOT access directly: use the accessor methods to get/set the value. */ int64_t _atomic_srv_polling_rescan_interval_ms; int64_t srv_polling_last_scan_ms; /* For multi-threaded, srv polling occurs in a separate thread. */ bson_thread_t srv_polling_thread; bson_mutex_t srv_polling_mtx; mongoc_cond_t srv_polling_cond; /** * @brief Signal for background monitoring threads to signal stop/shutdown. * * The values stored are mongoc_topology_scanner_state_t values */ int scanner_state; /** * @brief This lock is held in order to serialize operations that modify the * topology description. It *should not* be held while performing read-only * operations on the topology. * * This mutex is also used by server selection to synchronize with threads * that may update the topology following a failed server selection. It is * used in conjunction with `cond_client`. This protects _shared_descr_, as * well as the server_monitors and rtt_monitors. */ bson_mutex_t tpld_modification_mtx; /** * @brief Condition variable used to signal client threads that the topology * has been updated by another thread. This CV should be used with * tpld_modification_mtx, as it signals modifications to the topology. * * Note that mc_tpld_modify_begin/commit/drop will acquire/release * tpld_modification_mtx as well. */ mongoc_cond_t cond_client; bool single_threaded; bool stale; mongoc_server_session_pool session_pool; /* Is client side encryption enabled? */ mongoc_topology_cse_state_t cse_state; bool is_srv_polling; #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION _mongoc_crypt_t *crypt; struct _mongoc_client_t *mongocryptd_client; /* single threaded */ struct _mongoc_client_t *keyvault_client; /* single threaded */ struct _mongoc_client_pool_t *mongocryptd_client_pool; /* multi threaded */ struct _mongoc_client_pool_t *keyvault_client_pool; /* multi threaded */ char *keyvault_db; char *keyvault_coll; bool bypass_auto_encryption; bool mongocryptd_bypass_spawn; char *mongocryptd_spawn_path; bson_t *mongocryptd_spawn_args; bool bypass_query_analysis; #endif struct { struct { struct { char *cryptSharedLibPath; bool cryptSharedLibRequired; } extraOptions; } autoOptions; } clientSideEncryption; // Corresponds to AutoEncryptionOpts.encryptedFieldsMap. bson_t *encrypted_fields_map; /* For background monitoring. */ mongoc_set_t *server_monitors; mongoc_set_t *rtt_monitors; // APM callbacks, structured logging handlers and callbacks. // Documented as per-client and per-pool, implemented as owned by topology_t. mongoc_log_and_monitor_instance_t log_and_monitor; /* This is overridable for SRV polling tests to mock DNS records. */ _mongoc_rr_resolver_fn rr_resolver; /* valid is false when mongoc_topology_new failed to construct a valid * topology. This could occur if the URI is invalid. * An invalid topology does not monitor servers. */ bool valid; // `usleep_fn` and `usleep_data` may be overridden by // `mongoc_client_set_usleep_impl`. mongoc_usleep_func_t usleep_fn; void *usleep_data; // `srv_prefer_tcp` determines if DNS lookup for SRV tries TCP first instead of UDP. // DNS implementations are expected to try UDP first, then retry with TCP if the UDP response indicates truncation. // Some DNS servers truncate UDP responses without setting the truncated (TC) flag. This may result in no TCP retry. bool srv_prefer_tcp; } mongoc_topology_t; mongoc_topology_t * mongoc_topology_new (const mongoc_uri_t *uri, bool single_threaded); void mongoc_topology_set_structured_log_opts (mongoc_topology_t *topology, const mongoc_structured_log_opts_t *opts); void mongoc_topology_destroy (mongoc_topology_t *topology); void mongoc_topology_reconcile (const mongoc_topology_t *topology, mongoc_topology_description_t *td); bool mongoc_topology_compatible (const mongoc_topology_description_t *td, const mongoc_read_prefs_t *read_prefs, bson_error_t *error); /** * @brief Select a server description for an operation. May scan and update the * topology. * * A server description might be returned that matches the given `optype` and * `read_prefs`. If the topology is out-of-date or due for a scan, then this * function will perform a scan and update the topology accordingly. If no * matching server is found, returns a NULL pointer. * * @param topology The topology to inspect and/or update. * @param optype The operation that is intended to be performed. * @param log_context Additional contextual information used only to support standardized logging. * @param read_prefs The read preferences for the command. * @param must_use_primary An optional output parameter. Server selection might * need to override the caller's read preferences' read mode to 'primary'. * Whether or not that takes place will be set through this pointer. * @param error An output parameter for any error information. * @return mongoc_server_description_t* A copy of the topology's server * description that matches the request, or NULL if there is no such server. * * @note The returned object is a COPY, and should be released with * `mongoc_server_description_destroy()` * * @note This function may update the topology description. */ mongoc_server_description_t * mongoc_topology_select (mongoc_topology_t *topology, mongoc_ss_optype_t optype, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, bool *must_use_primary, bson_error_t *error); /** * @brief Obtain the integral ID of a server description matching the requested * ops. * * Refer to @see mongoc_topology_select() for more information * * @param topology The topology to inspect and/or update. * @param optype The operation that is intended to be performed. * @param log_context Additional contextual information used only to support standardized logging. * @param read_prefs The read preferences for the command. * @param must_use_primary An optional output parameter. Server selection might * need to override the caller's read preferences' read mode to 'primary'. * Whether or not that takes place will be set through this pointer. * @param ds A list of servers that should be selected only if there are no * other suitable servers. * @param error An output parameter for any error information. * @return uint32_t A non-zero integer ID of the server description. In case of * error, sets `error` and returns zero. * * @note This function may update the topology description. */ uint32_t mongoc_topology_select_server_id (mongoc_topology_t *topology, mongoc_ss_optype_t optype, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, bool *must_use_primary, const mongoc_deprioritized_servers_t *ds, bson_error_t *error); /** * @brief Return a new mongoc_host_list_t for the given server matching the * given ID. * * @param topology The topology description to inspect * @param id The ID of a server in the topology * @param error Output error information * @return mongoc_host_list_t* A new host list, or NULL on error * * @note The returned list should be freed with * `_mongoc_host_list_destroy_all()` */ mongoc_host_list_t * _mongoc_topology_host_by_id (const mongoc_topology_description_t *topology, uint32_t id, bson_error_t *error); /** * @brief Update the topology from the response to a handshake on a new * application connection. * * @note Only applicable to a client pool (single-threaded clients reuse * monitoring connections). * * @param topology The topology that will be updated. * @param sd The server description that contains the hello response. * @return true If the server is valid in the topology. * @return false If the server was already removed from the topology. */ bool _mongoc_topology_update_from_handshake (mongoc_topology_t *topology, const mongoc_server_description_t *sd); void _mongoc_topology_update_last_used (mongoc_topology_t *topology, uint32_t server_id); int64_t mongoc_topology_server_timestamp (mongoc_topology_t *topology, uint32_t id); /** * @brief Get the current type of the topology */ mongoc_topology_description_type_t _mongoc_topology_get_type (const mongoc_topology_t *topology); bool _mongoc_topology_set_appname (mongoc_topology_t *topology, const char *appname); void _mongoc_topology_update_cluster_time (mongoc_topology_t *topology, const bson_t *reply); mongoc_server_session_t * _mongoc_topology_pop_server_session (mongoc_topology_t *topology, const mongoc_ss_log_context_t *log_context, bson_error_t *error); void _mongoc_topology_push_server_session (mongoc_topology_t *topology, mongoc_server_session_t *server_session); bool _mongoc_topology_end_sessions_cmd (mongoc_topology_t *topology, bson_t *cmd); void _mongoc_topology_do_blocking_scan (mongoc_topology_t *topology, bson_error_t *error); /** * @brief Duplicate the handshake command of the topology scanner. * * @param topology The topology to inspect. * @param copy_into The destination of the copy. Should be uninitialized storage * for a bson_t. * * @note This API will lazily construct the handshake command for the scanner. * * @note This is called at the start of the scan in * _mongoc_topology_run_background, when a node is added in * _mongoc_topology_reconcile_add_nodes, or when running a hello directly on a * node in _mongoc_stream_run_hello. */ void _mongoc_topology_dup_handshake_cmd (const mongoc_topology_t *topology, bson_t *copy_into); void _mongoc_topology_request_scan (mongoc_topology_t *topology); void _mongoc_topology_bypass_cooldown (mongoc_topology_t *topology); typedef enum { MONGOC_SDAM_APP_ERROR_COMMAND, MONGOC_SDAM_APP_ERROR_NETWORK, MONGOC_SDAM_APP_ERROR_TIMEOUT } _mongoc_sdam_app_error_type_t; /** * @brief Handle an error from an app connection * * Processes network errors, timeouts, and command replies. * * @param topology The topology that will be updated * @param server_id The ID of the server on which the error occurred. * @param handshake_complete Whether the handshake was complete for this server * @param type The type of error to process * @param reply If checking for a command error, the server reply. Otherwise * NULL * @param why An error that will be attached to the server description * @param max_wire_version * @param generation The generation of the server description the caller was * using. * @param service_id A service ID for a load-balanced deployment. If not * applicable, pass kZeroObjectId. * @return true If the topology was updated and the pool was cleared. * @return false If no modifications were made and the error was ignored. * * @note May update the topology description. */ bool _mongoc_topology_handle_app_error (mongoc_topology_t *topology, uint32_t server_id, bool handshake_complete, _mongoc_sdam_app_error_type_t type, const bson_t *reply, const bson_error_t *why, uint32_t max_wire_version, uint32_t generation, const bson_oid_t *service_id); void mongoc_topology_rescan_srv (mongoc_topology_t *topology); bool mongoc_topology_should_rescan_srv (mongoc_topology_t *topology); /* _mongoc_topology_set_rr_resolver is called by tests to mock DNS responses for * SRV polling. * This is necessarily called after initial seedlist discovery completes in * mongoc_topology_new. * Callers should call this before monitoring starts. */ void _mongoc_topology_set_rr_resolver (mongoc_topology_t *topology, _mongoc_rr_resolver_fn rr_resolver); /** * @brief Thread-safe update the SRV polling rescan interval on the given topology */ static BSON_INLINE void _mongoc_topology_set_srv_polling_rescan_interval_ms (mongoc_topology_t *topology, int64_t val) { mcommon_atomic_int64_exchange (&topology->_atomic_srv_polling_rescan_interval_ms, val, mcommon_memory_order_seq_cst); } /** * @brief Thread-safe get the SRV polling interval */ static BSON_INLINE int64_t _mongoc_topology_get_srv_polling_rescan_interval_ms (mongoc_topology_t const *topology) { return mcommon_atomic_int64_fetch (&topology->_atomic_srv_polling_rescan_interval_ms, mcommon_memory_order_seq_cst); } /** * @brief Return the latest connection generation for the server_id and/or * service_id. * * Use this generation for newly established connections. * * @param td The topology that contains the server * @param server_id The ID of the server to inspect * @param service_id The service ID of the connection if applicable, or * kZeroObjectId. * @returns uint32_t A generation counter for the given server, or zero if the * server does not exist in the topology. */ uint32_t _mongoc_topology_get_connection_pool_generation (const mongoc_topology_description_t *td, uint32_t server_id, const bson_oid_t *service_id); /** * @brief Obtain a reference to the current topology description for the given * topology. * * Returns a ref-counted reference to the topology description. The returned * reference must later be released with mc_tpld_drop_ref(). The contents of the * topology description are immutable. */ static BSON_INLINE mc_shared_tpld mc_tpld_take_ref (const mongoc_topology_t *tpl) { return (mc_shared_tpld){._sptr_ = mongoc_atomic_shared_ptr_load (&tpl->_shared_descr_._sptr_)}; } /** * @brief Release a reference to a topology description obtained via * mc_tpld_take_ref(). * * The pointed-to shared reference will be reset to NULL. */ static BSON_INLINE void mc_tpld_drop_ref (mc_shared_tpld *p) { mongoc_shared_ptr_reset_null (&p->_sptr_); } /** * @brief Refresh a reference to a topology description for the given topology. * * @param td Pointer-to-shared-pointer of the topology description * @param tpl The topology to query. * * The pointed-to shared pointer will be modified to refer to the topology * description of the topology. * * Equivalent to a call to `mc_tpld_drop_ref()` followed by a call to * `mc_tpld_take_ref()`. */ static BSON_INLINE void mc_tpld_renew_ref (mc_shared_tpld *td, mongoc_topology_t *tpl) { mc_tpld_drop_ref (td); *td = mc_tpld_take_ref (tpl); } /** * @brief A pending topology description modification. * * Create an instance using `mc_tpld_modify_begin()`. */ typedef struct mc_tpld_modification { /** The new topology. Modifications should be applied to this topology * description. Those modifications will be published by * `mc_tpld_modify_commit()`. */ mongoc_topology_description_t *new_td; /** The topology that owns the topology description */ mongoc_topology_t *topology; } mc_tpld_modification; /** * @brief Begin a new modification transaction of the topology description owned * by `tpl` * * @return mc_tpld_modification A pending modification. * * @note MUST be followed by a call to `mc_tpld_modify_commit` OR * `mc_tpld_modify_drop` * * @note THIS FUNCTION MAY BLOCK: This call takes a lock, which will only be * released by mc_tpld_modify_commit() or mc_tpld_modify_drop(). Do not call * this API while the current thread is already performing a modification! */ mc_tpld_modification mc_tpld_modify_begin (mongoc_topology_t *tpl); /** * @brief Commit a topology description modification to the owning topology. * * All later calls to mc_tpld_take_ref() will see the new topology. */ void mc_tpld_modify_commit (mc_tpld_modification); /** * @brief Drop a pending modification to a topology description. No changes will * be made to the topology. */ void mc_tpld_modify_drop (mc_tpld_modification); /** * @brief Obtain a pointer-to-mutable mongoc_topology_description_t for the * given topology. * * This call is "unsafe" as the returned pointer may be invalidated by * concurrent modifications done using mc_tpld_modify_begin() and * mc_tpld_modify_commit(). * * To obtain a safe pointer to the topology description, use mc_tpld_take_ref(). */ static BSON_INLINE mongoc_topology_description_t * mc_tpld_unsafe_get_mutable (mongoc_topology_t *tpl) { return tpl->_shared_descr_._sptr_.ptr; } /** * @brief Obtain a pointer-to-const mongoc_topology_description_t for the * given topology. * * This call is "unsafe" as the returned pointer may be invalidated by * concurrent modifications done using mc_tpld_modify_begin() and * mc_tpld_modify_commit(). * * To obtain a safe pointer to the topology description, use mc_tpld_take_ref(). * * @return const mongoc_topology_description_t* Pointer to the topology * description for the given topology. */ static BSON_INLINE const mongoc_topology_description_t * mc_tpld_unsafe_get_const (const mongoc_topology_t *tpl) { return tpl->_shared_descr_._sptr_.ptr; } /** * @brief Directly invalidate a server in the topology by its ID. * * This is intended for testing purposes, as it provides thread-safe * direct topology modification. * * @param topology The topology to modify. * @param server_id The ID of a server in the topology. */ static BSON_INLINE void _mongoc_topology_invalidate_server (mongoc_topology_t *topology, uint32_t server_id) { bson_error_t error; mc_tpld_modification tdmod = mc_tpld_modify_begin (topology); bson_set_error (&error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "invalidated"); mongoc_topology_description_invalidate_server (tdmod.new_td, &topology->log_and_monitor, server_id, &error); mc_tpld_modify_commit (tdmod); } /* Return an array view to `max_hosts` or fewer elements of `hl`, or NULL if * `hl` is empty. The size of the returned array is written to `hl_array_size` * even if `hl` is empty. * * The returned array must be freed with `bson_free()`. The elements of the * array must not be freed, as they are still owned by `hl`. */ const mongoc_host_list_t ** _mongoc_apply_srv_max_hosts (const mongoc_host_list_t *hl, size_t max_hosts, size_t *hl_array_size); /* Returns true if a versioned server API has been selected, otherwise returns * false. */ bool mongoc_topology_uses_server_api (const mongoc_topology_t *topology); /* Returns true if load balancing mode has been seelected, otherwise returns * false. */ bool mongoc_topology_uses_loadbalanced (const mongoc_topology_t *topology); #endif mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-scanner-private.h0000644000175100001660000002160014760300420026111 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TOPOLOGY_SCANNER_PRIVATE_H #define MONGOC_TOPOLOGY_SCANNER_PRIVATE_H /* TODO: rename to TOPOLOGY scanner */ #include #ifdef MONGOC_ENABLE_SSL_OPENSSL #include #endif #include #include #include #include #include #include #include #include #include #include BSON_BEGIN_DECLS typedef void (*mongoc_topology_scanner_setup_err_cb_t) (uint32_t id, void *data, const bson_error_t *error /* IN */); typedef void (*mongoc_topology_scanner_cb_t) ( uint32_t id, const bson_t *bson, int64_t rtt, void *data, const bson_error_t *error /* IN */); struct mongoc_topology_scanner; struct mongoc_topology_scanner_node; typedef struct mongoc_topology_scanner_node { uint32_t id; /* after scanning, this is set to the successful stream if one exists. */ mongoc_stream_t *stream; int64_t last_used; /* last_failed is set upon a network error trying to check a server. * last_failed is used to enforce cooldownMS. * last_failed is not set upon a network error during an application * operation on @stream. */ int64_t last_failed; bool has_auth; bool hello_ok; mongoc_host_list_t host; struct mongoc_topology_scanner *ts; struct mongoc_topology_scanner_node *next; struct mongoc_topology_scanner_node *prev; bool retired; bson_error_t last_error; /* the hostname for a node may resolve to multiple DNS results. * dns_results has the full list of DNS results, ordered by host preference. * successful_dns_result is the most recent successful DNS result. */ struct addrinfo *dns_results; struct addrinfo *successful_dns_result; int64_t last_dns_cache; /* used by single-threaded clients to store negotiated sasl mechanisms on a * node. */ mongoc_handshake_sasl_supported_mechs_t sasl_supported_mechs; bool negotiated_sasl_supported_mechs; bson_t speculative_auth_response; mongoc_scram_t scram; /* handshake_sd is a server description constructed from the response of the * initial handshake. It is bound to the lifetime of stream. */ mongoc_server_description_t *handshake_sd; } mongoc_topology_scanner_node_t; typedef enum handshake_state_t { /** * The handshake command has no value. The handshake_cmd pointer will be * NULL. */ HANDSHAKE_CMD_UNINITIALIZED, /** * The handshake command could not be constructed because it would be too * large. The handshake_cmd pointer will be NULL. */ HANDSHAKE_CMD_TOO_BIG, /** * The handshake command is valid and ready to be copied-from. */ HANDSHAKE_CMD_OKAY, } handshake_state_t; typedef struct mongoc_topology_scanner { mongoc_async_t *async; int64_t connect_timeout_msec; mongoc_topology_scanner_node_t *nodes; bson_t hello_cmd; bson_t legacy_hello_cmd; bson_mutex_t handshake_cmd_mtx; bson_t *handshake_cmd; handshake_state_t handshake_state; bson_t cluster_time; bson_oid_t topology_id; const char *appname; mongoc_topology_scanner_setup_err_cb_t setup_err_cb; mongoc_topology_scanner_cb_t cb; void *cb_data; const mongoc_uri_t *uri; mongoc_async_cmd_setup_t setup; mongoc_stream_initiator_t initiator; void *initiator_context; bson_error_t error; #ifdef MONGOC_ENABLE_SSL mongoc_ssl_opt_t *ssl_opts; #endif #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L SSL_CTX *openssl_ctx; #endif int64_t dns_cache_timeout_ms; /* only used by single-threaded clients to negotiate auth mechanisms. */ bool negotiate_sasl_supported_mechs; bool bypass_cooldown; bool speculative_authentication; mongoc_server_api_t *api; mongoc_log_and_monitor_instance_t *log_and_monitor; // Not null. bool loadbalanced; } mongoc_topology_scanner_t; mongoc_topology_scanner_t * mongoc_topology_scanner_new (const mongoc_uri_t *uri, const bson_oid_t *topology_id, mongoc_log_and_monitor_instance_t *log_and_monitor, mongoc_topology_scanner_setup_err_cb_t setup_err_cb, mongoc_topology_scanner_cb_t cb, void *data, int64_t connect_timeout_msec); void mongoc_topology_scanner_destroy (mongoc_topology_scanner_t *ts); bool mongoc_topology_scanner_valid (mongoc_topology_scanner_t *ts); void mongoc_topology_scanner_add (mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, uint32_t id, bool hello_ok); void mongoc_topology_scanner_scan (mongoc_topology_scanner_t *ts, uint32_t id); void mongoc_topology_scanner_disconnect (mongoc_topology_scanner_t *scanner); void mongoc_topology_scanner_node_retire (mongoc_topology_scanner_node_t *node); void mongoc_topology_scanner_node_disconnect (mongoc_topology_scanner_node_t *node, bool failed); void mongoc_topology_scanner_node_destroy (mongoc_topology_scanner_node_t *node, bool failed); bool mongoc_topology_scanner_in_cooldown (mongoc_topology_scanner_t *ts, int64_t when); void mongoc_topology_scanner_start (mongoc_topology_scanner_t *ts, bool obey_cooldown); void mongoc_topology_scanner_work (mongoc_topology_scanner_t *ts); void _mongoc_topology_scanner_finish (mongoc_topology_scanner_t *ts); void mongoc_topology_scanner_get_error (mongoc_topology_scanner_t *ts, bson_error_t *error); void mongoc_topology_scanner_reset (mongoc_topology_scanner_t *ts); void mongoc_topology_scanner_node_setup (mongoc_topology_scanner_node_t *node, bson_error_t *error); mongoc_topology_scanner_node_t * mongoc_topology_scanner_get_node (mongoc_topology_scanner_t *ts, uint32_t id); void _mongoc_topology_scanner_add_speculative_authentication (bson_t *cmd, const mongoc_uri_t *uri, const mongoc_ssl_opt_t *ssl_opts, mongoc_scram_t *scram /* OUT */); void _mongoc_topology_scanner_parse_speculative_authentication (const bson_t *hello, bson_t *speculative_authenticate); const char * _mongoc_topology_scanner_get_speculative_auth_mechanism (const mongoc_uri_t *uri); const bson_t * _mongoc_topology_scanner_get_monitoring_cmd (mongoc_topology_scanner_t *ts, bool hello_ok); /** * @brief Get the scanner's associated handshake command BSON document. * * @param ts The scanner to inspect * @param copy_into A pointer to an initialized bson_t. The handshake command * will be copied into the pointee. */ void _mongoc_topology_scanner_dup_handshake_cmd (mongoc_topology_scanner_t *ts, bson_t *copy_into); bool mongoc_topology_scanner_has_node_for_host (mongoc_topology_scanner_t *ts, mongoc_host_list_t *host); void mongoc_topology_scanner_set_stream_initiator (mongoc_topology_scanner_t *ts, mongoc_stream_initiator_t si, void *ctx); bool _mongoc_topology_scanner_set_appname (mongoc_topology_scanner_t *ts, const char *name); void _mongoc_topology_scanner_set_cluster_time (mongoc_topology_scanner_t *ts, const bson_t *cluster_time); void _mongoc_topology_scanner_set_dns_cache_timeout (mongoc_topology_scanner_t *ts, int64_t timeout_ms); #ifdef MONGOC_ENABLE_SSL void mongoc_topology_scanner_set_ssl_opts (mongoc_topology_scanner_t *ts, mongoc_ssl_opt_t *opts); #endif bool mongoc_topology_scanner_node_in_cooldown (mongoc_topology_scanner_node_t *node, int64_t when); void _mongoc_topology_scanner_set_server_api (mongoc_topology_scanner_t *ts, const mongoc_server_api_t *api); void _mongoc_topology_scanner_set_loadbalanced (mongoc_topology_scanner_t *ts, bool val); /* for testing. */ mongoc_stream_t * _mongoc_topology_scanner_tcp_initiate (mongoc_async_cmd_t *acmd); /* Returns true if versioned server API has been selected, otherwise * false. */ bool mongoc_topology_scanner_uses_server_api (const mongoc_topology_scanner_t *ts); /* Returns true if load balancing mode has been selected, otherwise false. */ bool mongoc_topology_scanner_uses_loadbalanced (const mongoc_topology_scanner_t *ts); BSON_END_DECLS #endif /* MONGOC_TOPOLOGY_SCANNER_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology-scanner.c0000644000175100001660000013266414760300420024451 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #endif #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "topology_scanner" #define DNS_CACHE_TIMEOUT_MS 10 * 60 * 1000 #define HAPPY_EYEBALLS_DELAY_MS 250 /* forward declarations */ static void _async_connected (mongoc_async_cmd_t *acmd); static void _async_success (mongoc_async_cmd_t *acmd, const bson_t *hello_response, int64_t duration_usec); static void _async_error_or_timeout (mongoc_async_cmd_t *acmd, int64_t duration_usec, const char *default_err_msg); static void _async_handler (mongoc_async_cmd_t *acmd, mongoc_async_cmd_result_t async_status, const bson_t *hello_response, int64_t duration_usec); static void _mongoc_topology_scanner_monitor_heartbeat_started (const mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host); static void _mongoc_topology_scanner_monitor_heartbeat_succeeded (const mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, const bson_t *reply, int64_t duration_usec); static void _mongoc_topology_scanner_monitor_heartbeat_failed (const mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, const bson_error_t *error, int64_t duration_usec); /* reset "retired" nodes that failed or were removed in the previous scan */ static void _delete_retired_nodes (mongoc_topology_scanner_t *ts); /* cancel any pending async commands for a specific node excluding acmd. * If acmd is NULL, cancel all async commands on the node. */ static void _cancel_commands_excluding (mongoc_topology_scanner_node_t *node, mongoc_async_cmd_t *acmd); /* return the number of pending async commands for a node. */ static int _count_acmds (mongoc_topology_scanner_node_t *node); /* if acmd fails, schedule the sibling commands sooner. */ static void _jumpstart_other_acmds (mongoc_topology_scanner_node_t *node, mongoc_async_cmd_t *acmd); static void _add_hello (mongoc_topology_scanner_t *ts) { BSON_APPEND_INT32 (&ts->hello_cmd, "hello", 1); BSON_APPEND_BOOL (&ts->hello_cmd, "helloOk", true); BSON_APPEND_INT32 (&ts->legacy_hello_cmd, HANDSHAKE_CMD_LEGACY_HELLO, 1); BSON_APPEND_BOOL (&ts->legacy_hello_cmd, "helloOk", true); /* Append appropriate server API metadata (such as "serverApi") if selected: */ if (mongoc_topology_scanner_uses_server_api (ts)) { _mongoc_cmd_append_server_api (&ts->hello_cmd, ts->api); } } static void _init_hello (mongoc_topology_scanner_t *ts) { bson_init (&ts->hello_cmd); bson_init (&ts->legacy_hello_cmd); bson_init (&ts->cluster_time); ts->handshake_cmd = NULL; _add_hello (ts); } static void _reset_hello (mongoc_topology_scanner_t *ts) { bson_t *prev_cmd; bson_reinit (&ts->hello_cmd); bson_reinit (&ts->legacy_hello_cmd); bson_mutex_lock (&ts->handshake_cmd_mtx); prev_cmd = ts->handshake_cmd; ts->handshake_cmd = NULL; ts->handshake_state = HANDSHAKE_CMD_UNINITIALIZED; bson_mutex_unlock (&ts->handshake_cmd_mtx); bson_destroy (prev_cmd); _add_hello (ts); } const char * _mongoc_topology_scanner_get_speculative_auth_mechanism (const mongoc_uri_t *uri) { const char *mechanism = mongoc_uri_get_auth_mechanism (uri); bool requires_auth = mechanism || mongoc_uri_get_username (uri); if (!requires_auth) { return NULL; } if (!mechanism) { return "SCRAM-SHA-256"; } return mechanism; } void _mongoc_topology_scanner_add_speculative_authentication (bson_t *cmd, const mongoc_uri_t *uri, const mongoc_ssl_opt_t *ssl_opts, mongoc_scram_t *scram /* OUT */) { bson_t auth_cmd; bson_error_t error; bool has_auth = false; const char *mechanism = _mongoc_topology_scanner_get_speculative_auth_mechanism (uri); if (!mechanism) { return; } if (strcasecmp (mechanism, "MONGODB-X509") == 0) { /* Ignore errors while building authentication document: we proceed with * the handshake as usual and let the subsequent authenticate command * fail. */ if (_mongoc_cluster_get_auth_cmd_x509 (uri, ssl_opts, &auth_cmd, &error)) { has_auth = true; BSON_APPEND_UTF8 (&auth_cmd, "db", "$external"); } } #ifdef MONGOC_ENABLE_CRYPTO if (strcasecmp (mechanism, "SCRAM-SHA-1") == 0 || strcasecmp (mechanism, "SCRAM-SHA-256") == 0) { mongoc_crypto_hash_algorithm_t algo = strcasecmp (mechanism, "SCRAM-SHA-1") == 0 ? MONGOC_CRYPTO_ALGORITHM_SHA_1 : MONGOC_CRYPTO_ALGORITHM_SHA_256; _mongoc_uri_init_scram (uri, scram, algo); if (_mongoc_cluster_get_auth_cmd_scram (algo, scram, &auth_cmd, &error)) { const char *auth_source; if (!(auth_source = mongoc_uri_get_auth_source (uri)) || (*auth_source == '\0')) { auth_source = "admin"; } has_auth = true; BSON_APPEND_UTF8 (&auth_cmd, "db", auth_source); } } #endif if (has_auth) { BSON_APPEND_DOCUMENT (cmd, "speculativeAuthenticate", &auth_cmd); bson_destroy (&auth_cmd); } } void _mongoc_topology_scanner_parse_speculative_authentication (const bson_t *hello, bson_t *speculative_authenticate) { bson_iter_t iter; uint32_t data_len; const uint8_t *data; bson_t auth_response; BSON_ASSERT (hello); BSON_ASSERT (speculative_authenticate); if (!bson_iter_init_find (&iter, hello, "speculativeAuthenticate")) { return; } bson_iter_document (&iter, &data_len, &data); BSON_ASSERT (bson_init_static (&auth_response, data, data_len)); bson_destroy (speculative_authenticate); bson_copy_to (&auth_response, speculative_authenticate); } static bson_t * _build_handshake_cmd (const bson_t *basis_cmd, const char *appname, const mongoc_uri_t *uri, bool is_loadbalanced) { bson_t *doc = bson_copy (basis_cmd); bson_iter_t iter; const bson_t *compressors; bson_array_builder_t *subarray; BSON_ASSERT (doc); bson_t *handshake_doc = _mongoc_handshake_build_doc_with_application (appname); if (!handshake_doc) { bson_destroy (doc); return NULL; } bson_append_document (doc, HANDSHAKE_FIELD, -1, handshake_doc); bson_destroy (handshake_doc); BSON_APPEND_ARRAY_BUILDER_BEGIN (doc, "compression", &subarray); if (uri) { compressors = mongoc_uri_get_compressors (uri); if (bson_iter_init (&iter, compressors)) { while (bson_iter_next (&iter)) { bson_array_builder_append_utf8 (subarray, bson_iter_key (&iter), -1); } } } bson_append_array_builder_end (doc, subarray); if (is_loadbalanced) { BSON_APPEND_BOOL (doc, "loadBalanced", true); } /* Return whether the handshake doc fit the size limit */ return doc; } static bool _should_use_op_msg (const mongoc_topology_scanner_t *ts) { return mongoc_topology_scanner_uses_server_api (ts) || mongoc_topology_scanner_uses_loadbalanced (ts); } const bson_t * _mongoc_topology_scanner_get_monitoring_cmd (mongoc_topology_scanner_t *ts, bool hello_ok) { return hello_ok || _should_use_op_msg (ts) ? &ts->hello_cmd : &ts->legacy_hello_cmd; } void _mongoc_topology_scanner_dup_handshake_cmd (mongoc_topology_scanner_t *ts, bson_t *copy_into) { bson_t *new_cmd; const char *appname; BSON_ASSERT_PARAM (ts); BSON_ASSERT_PARAM (copy_into); /* appname will only be changed from NULL, so a non-null pointer will never * be invalidated after this fetch. */ appname = mcommon_atomic_ptr_fetch ((void *) &ts->appname, mcommon_memory_order_relaxed); bson_mutex_lock (&ts->handshake_cmd_mtx); /* If this is the first time using the node or if it's the first time * using it after a failure, build handshake doc */ if (ts->handshake_state != HANDSHAKE_CMD_UNINITIALIZED) { /* We're good to just return the handshake now */ goto after_init; } /* There is not yet a handshake command associated with this scanner. * Initialize one and set it now. */ /* Note: Don't hold the mutex while we build our command */ /* Construct a new handshake command to be sent */ BSON_ASSERT (ts->handshake_cmd == NULL); bson_mutex_unlock (&ts->handshake_cmd_mtx); new_cmd = _build_handshake_cmd ( _should_use_op_msg (ts) ? &ts->hello_cmd : &ts->legacy_hello_cmd, appname, ts->uri, ts->loadbalanced); bson_mutex_lock (&ts->handshake_cmd_mtx); if (ts->handshake_state != HANDSHAKE_CMD_UNINITIALIZED) { /* Someone else updated the handshake_cmd while we were building ours. * Defer to their copy and just destroy the one we created. */ bson_destroy (new_cmd); goto after_init; } BSON_ASSERT (ts->handshake_cmd == NULL); /* We're still the one updating the command */ ts->handshake_cmd = new_cmd; /* The "_build" may have failed. */ /* Even if new_cmd is NULL, this is still what we want */ ts->handshake_state = new_cmd == NULL ? HANDSHAKE_CMD_TOO_BIG : HANDSHAKE_CMD_OKAY; if (ts->handshake_state == HANDSHAKE_CMD_TOO_BIG) { MONGOC_WARNING ("Handshake doc too big, not including in hello"); } after_init: /* If the doc turned out to be too big */ if (ts->handshake_state == HANDSHAKE_CMD_TOO_BIG) { bson_t *ret = _should_use_op_msg (ts) ? &ts->hello_cmd : &ts->legacy_hello_cmd; bson_copy_to (ret, copy_into); } else { BSON_ASSERT (ts->handshake_cmd != NULL); bson_copy_to (ts->handshake_cmd, copy_into); } bson_mutex_unlock (&ts->handshake_cmd_mtx); } static void _begin_hello_cmd (mongoc_topology_scanner_node_t *node, mongoc_stream_t *stream, bool is_setup_done, struct addrinfo *dns_result, int64_t initiate_delay_ms, bool use_handshake) { mongoc_topology_scanner_t *ts = node->ts; bson_t cmd; /* If we're asked to use a specific API version, we should send our hello handshake via op_msg rather than the legacy op_query: */ const int32_t cmd_opcode = _should_use_op_msg (ts) ? MONGOC_OP_CODE_MSG : MONGOC_OP_CODE_QUERY; if (node->last_used != -1 && node->last_failed == -1 && !use_handshake) { /* The node's been used before and not failed recently */ bson_copy_to (_mongoc_topology_scanner_get_monitoring_cmd (ts, node->hello_ok), &cmd); } else { _mongoc_topology_scanner_dup_handshake_cmd (ts, &cmd); } if (node->ts->negotiate_sasl_supported_mechs && !node->negotiated_sasl_supported_mechs) { _mongoc_handshake_append_sasl_supported_mechs (ts->uri, &cmd); } if (node->ts->speculative_authentication && !node->has_auth && bson_empty (&node->speculative_auth_response) && node->scram.step == 0) { mongoc_ssl_opt_t *ssl_opts = NULL; #ifdef MONGOC_ENABLE_SSL ssl_opts = ts->ssl_opts; #endif _mongoc_topology_scanner_add_speculative_authentication (&cmd, ts->uri, ssl_opts, &node->scram); } if (!bson_empty (&ts->cluster_time)) { bson_append_document (&cmd, "$clusterTime", 12, &ts->cluster_time); } /* if the node should connect with a TCP socket, stream will be null, and * dns_result will be set. The async loop is responsible for calling the * _tcp_initiator to construct TCP sockets. */ mongoc_async_cmd_new (ts->async, stream, is_setup_done, dns_result, _mongoc_topology_scanner_tcp_initiate, initiate_delay_ms, ts->setup, node->host.host, "admin", &cmd, cmd_opcode, &_async_handler, node, ts->connect_timeout_msec); bson_destroy (&cmd); } mongoc_topology_scanner_t * mongoc_topology_scanner_new (const mongoc_uri_t *uri, const bson_oid_t *topology_id, mongoc_log_and_monitor_instance_t *log_and_monitor, mongoc_topology_scanner_setup_err_cb_t setup_err_cb, mongoc_topology_scanner_cb_t cb, void *data, int64_t connect_timeout_msec) { mongoc_topology_scanner_t *ts = BSON_ALIGNED_ALLOC0 (mongoc_topology_scanner_t); ts->async = mongoc_async_new (); bson_oid_copy (topology_id, &ts->topology_id); ts->setup_err_cb = setup_err_cb; ts->cb = cb; ts->cb_data = data; ts->uri = uri; ts->appname = NULL; ts->log_and_monitor = log_and_monitor; ts->api = NULL; ts->handshake_state = HANDSHAKE_CMD_UNINITIALIZED; ts->connect_timeout_msec = connect_timeout_msec; /* may be overridden for testing. */ ts->dns_cache_timeout_ms = DNS_CACHE_TIMEOUT_MS; bson_mutex_init (&ts->handshake_cmd_mtx); _init_hello (ts); return ts; } #ifdef MONGOC_ENABLE_SSL void mongoc_topology_scanner_set_ssl_opts (mongoc_topology_scanner_t *ts, mongoc_ssl_opt_t *opts) { ts->ssl_opts = opts; ts->setup = mongoc_async_cmd_tls_setup; } #endif void mongoc_topology_scanner_set_stream_initiator (mongoc_topology_scanner_t *ts, mongoc_stream_initiator_t si, void *ctx) { ts->initiator = si; ts->initiator_context = ctx; ts->setup = NULL; } void mongoc_topology_scanner_destroy (mongoc_topology_scanner_t *ts) { mongoc_topology_scanner_node_t *ele, *tmp; DL_FOREACH_SAFE (ts->nodes, ele, tmp) { mongoc_topology_scanner_node_destroy (ele, false); } mongoc_async_destroy (ts->async); bson_destroy (&ts->hello_cmd); bson_destroy (&ts->legacy_hello_cmd); bson_destroy (ts->handshake_cmd); bson_destroy (&ts->cluster_time); mongoc_server_api_destroy (ts->api); bson_mutex_destroy (&ts->handshake_cmd_mtx); #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L SSL_CTX_free (ts->openssl_ctx); ts->openssl_ctx = NULL; #endif /* This field can be set by a mongoc_client */ bson_free ((char *) ts->appname); bson_free (ts); } /* whether the scanner was successfully initialized - false if a mongodb+srv * URI failed to resolve to any hosts */ bool mongoc_topology_scanner_valid (mongoc_topology_scanner_t *ts) { return ts->nodes != NULL; } void mongoc_topology_scanner_add (mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, uint32_t id, bool hello_ok) { mongoc_topology_scanner_node_t *node; node = BSON_ALIGNED_ALLOC0 (mongoc_topology_scanner_node_t); memcpy (&node->host, host, sizeof (*host)); node->id = id; node->ts = ts; node->last_failed = -1; node->last_used = -1; node->hello_ok = hello_ok; bson_init (&node->speculative_auth_response); DL_APPEND (ts->nodes, node); } void mongoc_topology_scanner_scan (mongoc_topology_scanner_t *ts, uint32_t id) { mongoc_topology_scanner_node_t *node; node = mongoc_topology_scanner_get_node (ts, id); /* begin non-blocking connection, don't wait for success */ if (node) { mongoc_topology_scanner_node_setup (node, &node->last_error); } /* if setup fails the node stays in the scanner. destroyed after the scan. */ } void mongoc_topology_scanner_disconnect (mongoc_topology_scanner_t *scanner) { mongoc_topology_scanner_node_t *node; BSON_ASSERT (scanner); node = scanner->nodes; while (node) { mongoc_topology_scanner_node_disconnect (node, false); node = node->next; } } void mongoc_topology_scanner_node_retire (mongoc_topology_scanner_node_t *node) { /* cancel any pending commands. */ _cancel_commands_excluding (node, NULL); node->retired = true; } void mongoc_topology_scanner_node_disconnect (mongoc_topology_scanner_node_t *node, bool failed) { /* the node may or may not have succeeded in finding a working stream. */ if (node->stream) { if (failed) { mongoc_stream_failed (node->stream); } else { mongoc_stream_destroy (node->stream); } node->stream = NULL; } mongoc_server_description_destroy (node->handshake_sd); node->handshake_sd = NULL; } void mongoc_topology_scanner_node_destroy (mongoc_topology_scanner_node_t *node, bool failed) { DL_DELETE (node->ts->nodes, node); mongoc_topology_scanner_node_disconnect (node, failed); if (node->dns_results) { freeaddrinfo (node->dns_results); } bson_destroy (&node->speculative_auth_response); #ifdef MONGOC_ENABLE_CRYPTO _mongoc_scram_destroy (&node->scram); #endif bson_free (node); } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_get_node -- * * Return the scanner node with the given id. * *-------------------------------------------------------------------------- */ mongoc_topology_scanner_node_t * mongoc_topology_scanner_get_node (mongoc_topology_scanner_t *ts, uint32_t id) { mongoc_topology_scanner_node_t *ele, *tmp; DL_FOREACH_SAFE (ts->nodes, ele, tmp) { if (ele->id == id) { return ele; } if (ele->id > id) { break; } } return NULL; } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_has_node_for_host -- * * Whether the scanner has a node for the given host and port. * *-------------------------------------------------------------------------- */ bool mongoc_topology_scanner_has_node_for_host (mongoc_topology_scanner_t *ts, mongoc_host_list_t *host) { mongoc_topology_scanner_node_t *ele, *tmp; DL_FOREACH_SAFE (ts->nodes, ele, tmp) { if (_mongoc_host_list_compare_one (&ele->host, host)) { return true; } } return false; } static void _async_connected (mongoc_async_cmd_t *acmd) { mongoc_topology_scanner_node_t *node = (mongoc_topology_scanner_node_t *) acmd->data; /* this cmd connected successfully, cancel other cmds on this node. */ _cancel_commands_excluding (node, acmd); node->successful_dns_result = acmd->dns_result; } static void _async_success (mongoc_async_cmd_t *acmd, const bson_t *hello_response, int64_t duration_usec) { void *data = acmd->data; mongoc_topology_scanner_node_t *node = (mongoc_topology_scanner_node_t *) data; mongoc_stream_t *stream = acmd->stream; mongoc_topology_scanner_t *ts = node->ts; if (node->retired) { if (stream) { mongoc_stream_failed (stream); } return; } node->last_used = bson_get_monotonic_time (); node->last_failed = -1; _mongoc_topology_scanner_monitor_heartbeat_succeeded (ts, &node->host, hello_response, duration_usec); /* set our successful stream. */ BSON_ASSERT (!node->stream); node->stream = stream; if (!node->handshake_sd) { mongoc_server_description_t sd; /* Store a server description associated with the handshake. */ mongoc_server_description_init (&sd, node->host.host_and_port, node->id); mongoc_server_description_handle_hello (&sd, hello_response, duration_usec / 1000, &acmd->error); node->handshake_sd = mongoc_server_description_new_copy (&sd); mongoc_server_description_cleanup (&sd); } if (ts->negotiate_sasl_supported_mechs && !node->negotiated_sasl_supported_mechs) { _mongoc_handshake_parse_sasl_supported_mechs (hello_response, &node->sasl_supported_mechs); } if (ts->speculative_authentication) { _mongoc_topology_scanner_parse_speculative_authentication (hello_response, &node->speculative_auth_response); } /* mongoc_topology_scanner_cb_t takes rtt_msec, not usec */ ts->cb (node->id, hello_response, duration_usec / 1000, ts->cb_data, &acmd->error); } static void _async_error_or_timeout (mongoc_async_cmd_t *acmd, int64_t duration_usec, const char *default_err_msg) { void *data = acmd->data; mongoc_topology_scanner_node_t *node = (mongoc_topology_scanner_node_t *) data; mongoc_stream_t *stream = acmd->stream; mongoc_topology_scanner_t *ts = node->ts; bson_error_t *error = &acmd->error; int64_t now = bson_get_monotonic_time (); const char *message; /* the stream may have failed on initiation. */ if (stream) { mongoc_stream_failed (stream); } if (node->retired) { return; } node->last_used = now; if (!node->stream && _count_acmds (node) == 1) { /* there are no remaining streams, connecting has failed. */ node->last_failed = now; if (error->code) { message = error->message; } else { message = default_err_msg; } /* invalidate any cached DNS results. */ if (node->dns_results) { freeaddrinfo (node->dns_results); node->dns_results = NULL; node->successful_dns_result = NULL; } bson_set_error (&node->last_error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_STREAM_CONNECT, "%s calling hello on \'%s\'", message, node->host.host_and_port); _mongoc_topology_scanner_monitor_heartbeat_failed (ts, &node->host, &node->last_error, duration_usec); /* call the topology scanner callback. cannot connect to this node. * callback takes rtt_msec, not usec. */ ts->cb (node->id, NULL, duration_usec / 1000, ts->cb_data, error); mongoc_server_description_destroy (node->handshake_sd); node->handshake_sd = NULL; } else { /* there are still more commands left for this node or it succeeded * with another stream. skip the topology scanner callback. */ _jumpstart_other_acmds (node, acmd); } } /* *----------------------------------------------------------------------- * * This is the callback passed to async_cmd when we're running * hellos from within the topology monitor. * *----------------------------------------------------------------------- */ static void _async_handler (mongoc_async_cmd_t *acmd, mongoc_async_cmd_result_t async_status, const bson_t *hello_response, int64_t duration_usec) { BSON_ASSERT (acmd->data); switch (async_status) { case MONGOC_ASYNC_CMD_CONNECTED: _async_connected (acmd); return; case MONGOC_ASYNC_CMD_SUCCESS: _async_success (acmd, hello_response, duration_usec); return; case MONGOC_ASYNC_CMD_TIMEOUT: _async_error_or_timeout (acmd, duration_usec, "connection timeout"); return; case MONGOC_ASYNC_CMD_ERROR: _async_error_or_timeout (acmd, duration_usec, "connection error"); return; case MONGOC_ASYNC_CMD_IN_PROGRESS: default: fprintf (stderr, "unexpected async status: %d\n", (int) async_status); BSON_ASSERT (false); return; } } mongoc_stream_t * _mongoc_topology_scanner_node_setup_stream_for_tls (mongoc_topology_scanner_node_t *node, mongoc_stream_t *stream) { #ifdef MONGOC_ENABLE_SSL mongoc_stream_t *tls_stream; #endif if (!stream) { return NULL; } #ifdef MONGOC_ENABLE_SSL if (node->ts->ssl_opts) { #if defined(MONGOC_ENABLE_SSL_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10100000L tls_stream = mongoc_stream_tls_new_with_hostname_and_openssl_context ( stream, node->host.host, node->ts->ssl_opts, 1, node->ts->openssl_ctx); #else tls_stream = mongoc_stream_tls_new_with_hostname (stream, node->host.host, node->ts->ssl_opts, 1); #endif if (!tls_stream) { mongoc_stream_destroy (stream); return NULL; } else { return tls_stream; } } #endif return stream; } /* attempt to create a new socket stream using this dns result. */ mongoc_stream_t * _mongoc_topology_scanner_tcp_initiate (mongoc_async_cmd_t *acmd) { mongoc_topology_scanner_node_t *node = (mongoc_topology_scanner_node_t *) acmd->data; struct addrinfo *res = acmd->dns_result; mongoc_socket_t *sock = NULL; BSON_ASSERT (acmd->dns_result); /* create a new non-blocking socket. */ if (!(sock = mongoc_socket_new (res->ai_family, res->ai_socktype, res->ai_protocol))) { return NULL; } (void) mongoc_socket_connect (sock, res->ai_addr, (mongoc_socklen_t) res->ai_addrlen, 0); return _mongoc_topology_scanner_node_setup_stream_for_tls (node, mongoc_stream_socket_new (sock)); } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_node_setup_tcp -- * * Create an async command for each DNS record found for this node. * * Returns: * A bool. On failure error is set. * *-------------------------------------------------------------------------- */ bool mongoc_topology_scanner_node_setup_tcp (mongoc_topology_scanner_node_t *node, bson_error_t *error) { struct addrinfo hints; struct addrinfo *iter; char portstr[8]; mongoc_host_list_t *host; int s; int64_t delay = 0; int64_t now = bson_get_monotonic_time (); ENTRY; host = &node->host; /* if cached dns results are expired, flush. */ if (node->dns_results && (now - node->last_dns_cache) > node->ts->dns_cache_timeout_ms * 1000) { freeaddrinfo (node->dns_results); node->dns_results = NULL; node->successful_dns_result = NULL; } if (!node->dns_results) { // Expect no truncation. int req = bson_snprintf (portstr, sizeof portstr, "%hu", host->port); BSON_ASSERT (mcommon_cmp_less_su (req, sizeof portstr)); memset (&hints, 0, sizeof hints); hints.ai_family = host->family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = 0; s = getaddrinfo (host->host, portstr, &hints, &node->dns_results); if (s != 0) { mongoc_counter_dns_failure_inc (); bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "Failed to resolve '%s'", host->host); RETURN (false); } mongoc_counter_dns_success_inc (); node->last_dns_cache = now; } if (node->successful_dns_result) { _begin_hello_cmd (node, NULL /* stream */, false /* is_setup_done */, node->successful_dns_result, 0 /* initiate_delay_ms */, true /* use_handshake */); } else { LL_FOREACH2 (node->dns_results, iter, ai_next) { _begin_hello_cmd (node, NULL /* stream */, false /* is_setup_done */, iter, delay, true /* use_handshake */); /* each subsequent DNS result will have an additional 250ms delay. */ delay += HAPPY_EYEBALLS_DELAY_MS; } } RETURN (true); } bool mongoc_topology_scanner_node_connect_unix (mongoc_topology_scanner_node_t *node, bson_error_t *error) { #ifdef _WIN32 ENTRY; bson_set_error ( error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "UNIX domain sockets not supported on win32."); RETURN (false); #else struct sockaddr_un saddr; mongoc_socket_t *sock; mongoc_stream_t *stream; mongoc_host_list_t *host; ENTRY; host = &node->host; memset (&saddr, 0, sizeof saddr); saddr.sun_family = AF_UNIX; // Expect no truncation. int req = bson_snprintf (saddr.sun_path, sizeof saddr.sun_path - 1, "%s", host->host); if (mcommon_cmp_greater_equal_su (req, sizeof saddr.sun_path - 1)) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to define socket address path."); RETURN (false); } sock = mongoc_socket_new (AF_UNIX, SOCK_STREAM, 0); if (sock == NULL) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_SOCKET, "Failed to create socket."); RETURN (false); } if (-1 == mongoc_socket_connect (sock, (struct sockaddr *) &saddr, sizeof saddr, -1)) { char buf[128]; char *errstr; errstr = bson_strerror_r (mongoc_socket_errno (sock), buf, sizeof (buf)); bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to connect to UNIX domain socket: %s", errstr); mongoc_socket_destroy (sock); RETURN (false); } stream = _mongoc_topology_scanner_node_setup_stream_for_tls (node, mongoc_stream_socket_new (sock)); if (stream) { _begin_hello_cmd ( node, stream, false /* is_setup_done */, NULL /* dns result */, 0 /* delay */, true /* use_handshake */); RETURN (true); } bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_CONNECT, "Failed to create TLS stream"); RETURN (false); #endif } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_node_setup -- * * Create a stream and begin a non-blocking connect. * * Returns: * true on success, or false and error is set. * *-------------------------------------------------------------------------- */ void mongoc_topology_scanner_node_setup (mongoc_topology_scanner_node_t *node, bson_error_t *error) { bool success = false; mongoc_stream_t *stream; int64_t start; _mongoc_topology_scanner_monitor_heartbeat_started (node->ts, &node->host); start = bson_get_monotonic_time (); /* if there is already a working stream, push it back to be re-scanned. */ if (node->stream) { _begin_hello_cmd (node, node->stream, true /* is_setup_done */, NULL /* dns_result */, 0 /* initiate_delay_ms */, false /* use_handshake */); node->stream = NULL; return; } BSON_ASSERT (!node->retired); // If a new stream is needed, reset state authentication state. // Authentication state is tied to a stream. { node->has_auth = false; bson_reinit (&node->speculative_auth_response); #ifdef MONGOC_ENABLE_CRYPTO // Destroy and zero `node->scram`. _mongoc_scram_destroy (&node->scram); #endif memset (&node->sasl_supported_mechs, 0, sizeof (node->sasl_supported_mechs)); node->negotiated_sasl_supported_mechs = false; } if (node->ts->initiator) { stream = node->ts->initiator (node->ts->uri, &node->host, node->ts->initiator_context, error); if (stream) { success = true; _begin_hello_cmd (node, stream, false /* is_setup_done */, NULL /* dns_result */, 0 /* initiate_delay_ms */, true /* use_handshake */); } } else { if (node->host.family == AF_UNIX) { success = mongoc_topology_scanner_node_connect_unix (node, error); } else { success = mongoc_topology_scanner_node_setup_tcp (node, error); } } if (!success) { _mongoc_topology_scanner_monitor_heartbeat_failed ( node->ts, &node->host, error, (bson_get_monotonic_time () - start) / 1000); node->ts->setup_err_cb (node->id, node->ts->cb_data, error); return; } } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_node_in_cooldown -- * * Return true if @node has experienced a network error attempting * to call "hello" less than 5 seconds before @when, a timestamp in * microseconds. * * Server Discovery and Monitoring Spec: "After a single-threaded client * gets a network error trying to check a server, the client skips * re-checking the server until cooldownMS has passed. This avoids * spending connectTimeoutMS on each unavailable server during each scan. * This value MUST be 5000 ms, and it MUST NOT be configurable." * *-------------------------------------------------------------------------- */ bool mongoc_topology_scanner_node_in_cooldown (mongoc_topology_scanner_node_t *node, int64_t when) { if (node->last_failed == -1 || node->ts->bypass_cooldown) { return false; /* node is new, or connected */ } return node->last_failed + 1000 * MONGOC_TOPOLOGY_COOLDOWN_MS >= when; } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_in_cooldown -- * * Return true if all nodes will be in cooldown at time @when, a * timestamp in microseconds. * *-------------------------------------------------------------------------- */ bool mongoc_topology_scanner_in_cooldown (mongoc_topology_scanner_t *ts, int64_t when) { mongoc_topology_scanner_node_t *node; if (ts->bypass_cooldown) { return false; } DL_FOREACH (ts->nodes, node) { if (!mongoc_topology_scanner_node_in_cooldown (node, when)) { return false; } } return true; } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_start -- * * Initializes the scanner and begins a full topology check. This * should be called once before calling mongoc_topology_scanner_work() * to complete the scan. * * If "obey_cooldown" is true, this is a single-threaded blocking scan * that must obey the Server Discovery And Monitoring Spec's cooldownMS: * * "After a single-threaded client gets a network error trying to check * a server, the client skips re-checking the server until cooldownMS has * passed. * * "This avoids spending connectTimeoutMS on each unavailable server * during each scan. * * "This value MUST be 5000 ms, and it MUST NOT be configurable." * *-------------------------------------------------------------------------- */ void mongoc_topology_scanner_start (mongoc_topology_scanner_t *ts, bool obey_cooldown) { mongoc_topology_scanner_node_t *node, *tmp; bool skip; int64_t now; BSON_ASSERT (ts); _delete_retired_nodes (ts); now = bson_get_monotonic_time (); DL_FOREACH_SAFE (ts->nodes, node, tmp) { skip = obey_cooldown && mongoc_topology_scanner_node_in_cooldown (node, now); if (!skip) { mongoc_topology_scanner_node_setup (node, &node->last_error); } } } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_finish_scan -- * * Summarizes all scanner node errors into one error message, * deletes retired nodes. * *-------------------------------------------------------------------------- */ void _mongoc_topology_scanner_finish (mongoc_topology_scanner_t *ts) { mongoc_topology_scanner_node_t *node, *tmp; bson_error_t *error = &ts->error; memset (&ts->error, 0, sizeof (bson_error_t)); mcommon_string_append_t msg; mcommon_string_new_as_fixed_capacity_append (&msg, sizeof error->message - 1u); DL_FOREACH_SAFE (ts->nodes, node, tmp) { if (node->last_error.code) { if (!mcommon_string_from_append_is_empty (&msg)) { mcommon_string_append (&msg, " "); } mcommon_string_append_printf (&msg, "[%s]", node->last_error.message); /* last error domain and code win */ error->domain = node->last_error.domain; error->code = node->last_error.code; } } bson_strncpy ((char *) &error->message, mcommon_str_from_append (&msg), sizeof error->message); mcommon_string_from_append_destroy (&msg); _delete_retired_nodes (ts); } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_work -- * * Crank the knob on the topology scanner state machine. This should * be called only after mongoc_topology_scanner_start() has been used * to begin the scan. * *-------------------------------------------------------------------------- */ void mongoc_topology_scanner_work (mongoc_topology_scanner_t *ts) { mongoc_async_run (ts->async); BSON_ASSERT (ts->async->ncmds == 0); } /* *-------------------------------------------------------------------------- * * mongoc_topology_scanner_get_error -- * * Copy the scanner's current error; which may no-error (code 0). * *-------------------------------------------------------------------------- */ void mongoc_topology_scanner_get_error (mongoc_topology_scanner_t *ts, bson_error_t *error) { BSON_ASSERT (ts); BSON_ASSERT (error); memcpy (error, &ts->error, sizeof (bson_error_t)); } /* * Set a field in the topology scanner. */ bool _mongoc_topology_scanner_set_appname (mongoc_topology_scanner_t *ts, const char *appname) { char *s; const char *prev; if (!_mongoc_handshake_appname_is_valid (appname)) { MONGOC_ERROR ("Cannot set appname: %s is invalid", appname); return false; } s = bson_strdup (appname); prev = mcommon_atomic_ptr_compare_exchange_strong ((void *) &ts->appname, NULL, s, mcommon_memory_order_relaxed); if (prev == NULL) { return true; } MONGOC_ERROR ("Cannot set appname more than once"); bson_free (s); return false; } /* * Set the scanner's clusterTime unconditionally: don't compare with prior * @cluster_time is like {clusterTime: } */ void _mongoc_topology_scanner_set_cluster_time (mongoc_topology_scanner_t *ts, const bson_t *cluster_time) { bson_destroy (&ts->cluster_time); bson_copy_to (cluster_time, &ts->cluster_time); } /* SDAM Monitoring Spec: send HeartbeatStartedEvent */ static void _mongoc_topology_scanner_monitor_heartbeat_started (const mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host) { mongoc_structured_log (ts->log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Server heartbeat started", oid ("topologyId", &ts->topology_id), utf8 ("serverHost", host->host), int32 ("serverPort", host->port), boolean ("awaited", false)); if (ts->log_and_monitor->apm_callbacks.server_heartbeat_started) { mongoc_apm_server_heartbeat_started_t event; event.host = host; event.context = ts->log_and_monitor->apm_context; event.awaited = false; ts->log_and_monitor->apm_callbacks.server_heartbeat_started (&event); } } /* SDAM Monitoring Spec: send HeartbeatSucceededEvent */ static void _mongoc_topology_scanner_monitor_heartbeat_succeeded (const mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, const bson_t *reply, int64_t duration_usec) { /* This redaction is more lenient than the general command redaction in the Command Logging and Monitoring spec and * the cmd*() structured log items. In those general command logs, sensitive replies are omitted entirely. In this * APM message, the reply is passed through with only the speculativeAuthenticate field stripped. The Server * Discovery and Monitoring Logging spec does not mention reply redaction, so we choose to be consistent with the APM * event. */ bson_t hello_redacted; bson_init (&hello_redacted); bson_copy_to_excluding_noinit (reply, &hello_redacted, "speculativeAuthenticate", NULL); mongoc_structured_log (ts->log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Server heartbeat succeeded", oid ("topologyId", &ts->topology_id), utf8 ("serverHost", host->host), int32 ("serverPort", host->port), boolean ("awaited", false), monotonic_time_duration (duration_usec), bson_as_json ("reply", &hello_redacted)); if (ts->log_and_monitor->apm_callbacks.server_heartbeat_succeeded) { mongoc_apm_server_heartbeat_succeeded_t event; event.host = host; event.context = ts->log_and_monitor->apm_context; event.reply = reply; event.duration_usec = duration_usec; event.awaited = false; ts->log_and_monitor->apm_callbacks.server_heartbeat_succeeded (&event); } bson_destroy (&hello_redacted); } /* SDAM Monitoring Spec: send HeartbeatFailedEvent */ static void _mongoc_topology_scanner_monitor_heartbeat_failed (const mongoc_topology_scanner_t *ts, const mongoc_host_list_t *host, const bson_error_t *error, int64_t duration_usec) { mongoc_structured_log (ts->log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_TOPOLOGY, "Server heartbeat failed", oid ("topologyId", &ts->topology_id), utf8 ("serverHost", host->host), int32 ("serverPort", host->port), boolean ("awaited", false), monotonic_time_duration (duration_usec), error ("failure", error)); if (ts->log_and_monitor->apm_callbacks.server_heartbeat_failed) { mongoc_apm_server_heartbeat_failed_t event; event.host = host; event.context = ts->log_and_monitor->apm_context; event.error = error; event.duration_usec = duration_usec; event.awaited = false; ts->log_and_monitor->apm_callbacks.server_heartbeat_failed (&event); } } /* this is for testing the dns cache timeout. */ void _mongoc_topology_scanner_set_dns_cache_timeout (mongoc_topology_scanner_t *ts, int64_t timeout_ms) { ts->dns_cache_timeout_ms = timeout_ms; } /* reset "retired" nodes that failed or were removed in the previous scan */ static void _delete_retired_nodes (mongoc_topology_scanner_t *ts) { mongoc_topology_scanner_node_t *node, *tmp; DL_FOREACH_SAFE (ts->nodes, node, tmp) { if (node->retired) { mongoc_topology_scanner_node_destroy (node, true); } } } static void _cancel_commands_excluding (mongoc_topology_scanner_node_t *node, mongoc_async_cmd_t *acmd) { mongoc_async_cmd_t *iter; DL_FOREACH (node->ts->async->cmds, iter) { if ((mongoc_topology_scanner_node_t *) iter->data == node && iter != acmd) { iter->state = MONGOC_ASYNC_CMD_CANCELED_STATE; } } } static int _count_acmds (mongoc_topology_scanner_node_t *node) { mongoc_async_cmd_t *iter; int count = 0; DL_FOREACH (node->ts->async->cmds, iter) { if ((mongoc_topology_scanner_node_t *) iter->data == node) { ++count; } } return count; } static void _jumpstart_other_acmds (mongoc_topology_scanner_node_t *node, mongoc_async_cmd_t *acmd) { mongoc_async_cmd_t *iter; DL_FOREACH (node->ts->async->cmds, iter) { if ((mongoc_topology_scanner_node_t *) iter->data == node && iter != acmd && acmd->initiate_delay_ms < iter->initiate_delay_ms) { iter->initiate_delay_ms = BSON_MAX (iter->initiate_delay_ms - HAPPY_EYEBALLS_DELAY_MS, 0); } } } void _mongoc_topology_scanner_set_server_api (mongoc_topology_scanner_t *ts, const mongoc_server_api_t *api) { BSON_ASSERT (ts); BSON_ASSERT (api); mongoc_server_api_destroy (ts->api); ts->api = mongoc_server_api_copy (api); _reset_hello (ts); } /* This must be called before the handshake command is constructed. */ void _mongoc_topology_scanner_set_loadbalanced (mongoc_topology_scanner_t *ts, bool val) { BSON_UNUSED (val); BSON_ASSERT (ts->handshake_cmd == NULL); ts->loadbalanced = true; } bool mongoc_topology_scanner_uses_server_api (const mongoc_topology_scanner_t *ts) { BSON_ASSERT_PARAM (ts); return NULL != ts->api; } bool mongoc_topology_scanner_uses_loadbalanced (const mongoc_topology_scanner_t *ts) { BSON_ASSERT_PARAM (ts); return ts->loadbalanced; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-topology.c0000644000175100001660000022223014760300420023007 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void _topology_collect_errors (const mongoc_topology_description_t *topology, bson_error_t *error_out); static bool _mongoc_topology_reconcile_add_nodes (mongoc_server_description_t *sd, mongoc_topology_scanner_t *scanner) { mongoc_topology_scanner_node_t *node; /* Search by ID and update hello_ok */ node = mongoc_topology_scanner_get_node (scanner, sd->id); if (node) { node->hello_ok = sd->hello_ok; } else if (!mongoc_topology_scanner_has_node_for_host (scanner, &sd->host)) { /* A node for this host was retired in this scan. */ mongoc_topology_scanner_add (scanner, &sd->host, sd->id, sd->hello_ok); mongoc_topology_scanner_scan (scanner, sd->id); } return true; } /* Called from: * - the topology scanner callback (when a hello was just received) * - at the start of a single-threaded scan (mongoc_topology_scan_once) * Not called for multi threaded monitoring. */ void mongoc_topology_reconcile (const mongoc_topology_t *topology, mongoc_topology_description_t *td) { mongoc_set_t *servers; mongoc_server_description_t *sd; mongoc_topology_scanner_node_t *ele, *tmp; BSON_ASSERT (topology->single_threaded); servers = mc_tpld_servers (td); /* Add newly discovered nodes */ for (size_t i = 0u; i < servers->items_len; i++) { sd = mongoc_set_get_item (servers, i); _mongoc_topology_reconcile_add_nodes (sd, topology->scanner); } /* Remove removed nodes */ DL_FOREACH_SAFE (topology->scanner->nodes, ele, tmp) { if (!mongoc_topology_description_server_by_id (td, ele->id, NULL)) { mongoc_topology_scanner_node_retire (ele); } } } /* call this while already holding the lock */ static bool _mongoc_topology_update_no_lock (uint32_t id, const bson_t *hello_response, int64_t rtt_msec, mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, const bson_error_t *error /* IN */) { mongoc_topology_description_handle_hello (td, log_and_monitor, id, hello_response, rtt_msec, error); /* return false if server removed from topology */ return mongoc_topology_description_server_by_id (td, id, NULL) != NULL; } /* *------------------------------------------------------------------------- * * _mongoc_topology_scanner_setup_err_cb -- * * Callback method to handle errors during topology scanner node * setup, typically DNS or SSL errors. * *------------------------------------------------------------------------- */ void _mongoc_topology_scanner_setup_err_cb (uint32_t id, void *data, const bson_error_t *error /* IN */) { mongoc_topology_t *topology = BSON_ASSERT_PTR_INLINE (data); BSON_ASSERT (topology->single_threaded); if (_mongoc_topology_get_type (topology) == MONGOC_TOPOLOGY_LOAD_BALANCED) { /* In load balanced mode, scanning is only for connection establishment. * It must not modify the topology description. */ } else { // Use `mc_tpld_unsafe_get_mutable` to get a mutable topology description // without locking. This function only applies to single-threaded clients. mongoc_topology_description_t *td = mc_tpld_unsafe_get_mutable (topology); mongoc_topology_description_handle_hello ( td, &topology->log_and_monitor, id, NULL /* hello reply */, -1 /* rtt_msec */, error); } } /* *------------------------------------------------------------------------- * * _mongoc_topology_scanner_cb -- * * Callback method to handle hello responses received by async * command objects. * * Only called for single-threaded monitoring. * *------------------------------------------------------------------------- */ void _mongoc_topology_scanner_cb ( uint32_t id, const bson_t *hello_response, int64_t rtt_msec, void *data, const bson_error_t *error /* IN */) { mongoc_topology_t *const topology = BSON_ASSERT_PTR_INLINE (data); mongoc_server_description_t *sd; mongoc_topology_description_t *td; BSON_ASSERT (topology->single_threaded); if (_mongoc_topology_get_type (topology) == MONGOC_TOPOLOGY_LOAD_BALANCED) { /* In load balanced mode, scanning is only for connection establishment. * It must not modify the topology description. */ return; } // Use `mc_tpld_unsafe_get_mutable` to get a mutable topology description // without locking. This function only applies to single-threaded clients. td = mc_tpld_unsafe_get_mutable (topology); sd = mongoc_topology_description_server_by_id (td, id, NULL); if (!hello_response) { /* Server monitoring: When a server check fails due to a network error * (including a network timeout), the client MUST clear its connection * pool for the server */ _mongoc_topology_description_clear_connection_pool (td, id, &kZeroObjectId); } /* Server Discovery and Monitoring Spec: "Once a server is connected, the * client MUST change its type to Unknown only after it has retried the * server once." */ if (!hello_response && sd && sd->type != MONGOC_SERVER_UNKNOWN) { _mongoc_topology_update_no_lock (id, hello_response, rtt_msec, td, &topology->log_and_monitor, error); /* add another hello call to the current scan - the scan continues * until all commands are done */ mongoc_topology_scanner_scan (topology->scanner, sd->id); } else { _mongoc_topology_update_no_lock (id, hello_response, rtt_msec, td, &topology->log_and_monitor, error); /* The processing of the hello results above may have added, changed, or * removed server descriptions. We need to reconcile that with our * monitoring agents */ mongoc_topology_reconcile (topology, td); } } static void _server_session_init (void *session, void *unused, bson_error_t *error) { BSON_UNUSED (unused); _mongoc_server_session_init (session, error); } static void _server_session_destroy (void *session, void *unused) { BSON_UNUSED (unused); _mongoc_server_session_destroy (session); } static int _server_session_should_prune (const void *session_vp, void *topo_vp) { BSON_ASSERT_PARAM (session_vp); BSON_ASSERT_PARAM (topo_vp); const mongoc_server_session_t *const session = session_vp; mongoc_topology_t *const topo = topo_vp; /** If "dirty" (i.e. contains a network error), it should be dropped */ if (session->dirty) { return true; } /** If the session has never been used, it should be dropped */ if (session->last_used_usec == SESSION_NEVER_USED) { return true; } /* Check for a timeout */ mc_shared_tpld td = mc_tpld_take_ref (topo); const int64_t timeout = td.ptr->session_timeout_minutes; const bool is_loadbalanced = td.ptr->type == MONGOC_TOPOLOGY_LOAD_BALANCED; mc_tpld_drop_ref (&td); /** Load balanced topology sessions never expire */ if (is_loadbalanced) { return false; } /* Prune the session if it has hit a timeout */ return _mongoc_server_session_timed_out (session, timeout); } static void _tpld_destroy_and_free (void *tpl_descr) { mongoc_topology_description_t *td = tpl_descr; mongoc_topology_description_destroy (td); } const mongoc_host_list_t ** _mongoc_apply_srv_max_hosts (const mongoc_host_list_t *hl, size_t max_hosts, size_t *hl_array_size) { const mongoc_host_list_t **hl_array; BSON_ASSERT_PARAM (hl_array_size); const size_t hl_size = _mongoc_host_list_length (hl); if (hl_size == 0u) { *hl_array_size = 0u; return NULL; } hl_array = bson_malloc (hl_size * sizeof (mongoc_host_list_t *)); for (size_t idx = 0u; hl; hl = hl->next) { hl_array[idx++] = hl; } if (max_hosts == 0u || // Unlimited. hl_size == 1u || // Trivial case. hl_size <= max_hosts // Already satisfies limit. ) { /* No random shuffle or selection required. */ *hl_array_size = hl_size; return hl_array; } /* Initial DNS Seedlist Discovery Spec: If `srvMaxHosts` is greater than zero * and less than the number of hosts in the DNS result, the driver MUST * randomly select that many hosts and use them to populate the seedlist. * Drivers SHOULD use the `Fisher-Yates shuffle` for randomization. */ for (size_t idx = hl_size - 1u; idx > 0u; --idx) { /* 0 <= swap_pos <= idx */ const size_t swap_pos = _mongoc_rand_size_t (0u, idx); const mongoc_host_list_t *tmp = hl_array[swap_pos]; hl_array[swap_pos] = hl_array[idx]; hl_array[idx] = tmp; } *hl_array_size = max_hosts; return hl_array; } // `_detect_nongenuine_host` logs if the host string suggests use of CosmosDB or // DocumentDB. See DRIVERS-2583 for behavior requirements. Returns true if a // CosmosDB or DocumentDB host is detected. static bool _detect_nongenuine_host (const char *host) { char *const host_lowercase = bson_strdup (host); mongoc_lowercase (host, host_lowercase); if (mongoc_ends_with (host_lowercase, ".cosmos.azure.com")) { MONGOC_INFO ("You appear to be connected to a CosmosDB cluster. For more " "information regarding feature compatibility and support please " "visit https://www.mongodb.com/supportability/cosmosdb"); bson_free (host_lowercase); return true; } if (mongoc_ends_with (host_lowercase, ".docdb.amazonaws.com") || mongoc_ends_with (host_lowercase, ".docdb-elastic.amazonaws.com")) { MONGOC_INFO ("You appear to be connected to a DocumentDB cluster. For more " "information regarding feature compatibility and support please " "visit https://www.mongodb.com/supportability/documentdb"); bson_free (host_lowercase); return true; } bson_free (host_lowercase); return false; } static void _detect_nongenuine_hosts (const mongoc_uri_t *uri) { const char *srv_hostname = mongoc_uri_get_srv_hostname (uri); if (srv_hostname) { _detect_nongenuine_host (srv_hostname); return; } const mongoc_host_list_t *iter; LL_FOREACH (mongoc_uri_get_hosts (uri), iter) { if (_detect_nongenuine_host (iter->host)) { return; } } } /* *------------------------------------------------------------------------- * * mongoc_topology_new -- * * Creates and returns a new topology object. * * Returns: * A new topology object. * * Side effects: * None. * *------------------------------------------------------------------------- */ mongoc_topology_t * mongoc_topology_new (const mongoc_uri_t *uri, bool single_threaded) { mongoc_topology_t *topology; mongoc_topology_description_type_t init_type; mongoc_topology_description_t *td; const char *srv_hostname; const mongoc_host_list_t *hl; mongoc_rr_data_t rr_data; bool has_directconnection; bool directconnection; BSON_ASSERT (uri); _detect_nongenuine_hosts (uri); #ifndef MONGOC_ENABLE_CRYPTO if (mongoc_uri_get_option_as_bool (uri, MONGOC_URI_RETRYWRITES, MONGOC_DEFAULT_RETRYWRITES)) { /* retryWrites requires sessions, which require crypto - just warn */ MONGOC_WARNING ("retryWrites not supported without an SSL crypto library"); } #endif topology = (mongoc_topology_t *) bson_malloc0 (sizeof *topology); // Check if requested to use TCP for SRV lookup. { char *srv_prefer_tcp = _mongoc_getenv ("MONGOC_EXPERIMENTAL_SRV_PREFER_TCP"); if (srv_prefer_tcp) { topology->srv_prefer_tcp = true; } bson_free (srv_prefer_tcp); } topology->usleep_fn = mongoc_usleep_default_impl; topology->session_pool = mongoc_server_session_pool_new_with_params ( _server_session_init, _server_session_destroy, _server_session_should_prune, topology); // Capture default structured log options from the environment mongoc_log_and_monitor_instance_init (&topology->log_and_monitor); topology->valid = false; const int32_t heartbeat_default = single_threaded ? MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_SINGLE_THREADED : MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_MULTI_THREADED; const int32_t heartbeat = mongoc_uri_get_option_as_int32 (uri, MONGOC_URI_HEARTBEATFREQUENCYMS, heartbeat_default); topology->_shared_descr_._sptr_ = mongoc_shared_ptr_create (BSON_ALIGNED_ALLOC0 (mongoc_topology_description_t), _tpld_destroy_and_free); td = mc_tpld_unsafe_get_mutable (topology); mongoc_topology_description_init (td, heartbeat); td->set_name = bson_strdup (mongoc_uri_get_replica_set (uri)); topology->uri = mongoc_uri_copy (uri); topology->cse_state = MONGOC_CSE_DISABLED; topology->single_threaded = single_threaded; if (single_threaded) { /* Server Selection Spec: * * "Single-threaded drivers MUST provide a "serverSelectionTryOnce" * mode, in which the driver scans the topology exactly once after * server selection fails, then either selects a server or raises an * error. * * "The serverSelectionTryOnce option MUST be true by default." */ topology->server_selection_try_once = mongoc_uri_get_option_as_bool (uri, MONGOC_URI_SERVERSELECTIONTRYONCE, true); } else { topology->server_selection_try_once = false; } topology->server_selection_timeout_msec = mongoc_uri_get_option_as_int32 ( topology->uri, MONGOC_URI_SERVERSELECTIONTIMEOUTMS, MONGOC_TOPOLOGY_SERVER_SELECTION_TIMEOUT_MS); /* tests can override this */ topology->min_heartbeat_frequency_msec = MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS; topology->local_threshold_msec = mongoc_uri_get_local_threshold_option (topology->uri); /* Total time allowed to check a server is connectTimeoutMS. * Server Discovery And Monitoring Spec: * * "The socket used to check a server MUST use the same connectTimeoutMS as * regular sockets. Multi-threaded clients SHOULD set monitoring sockets' * socketTimeoutMS to the connectTimeoutMS." */ topology->connect_timeout_msec = mongoc_uri_get_option_as_int32 (topology->uri, MONGOC_URI_CONNECTTIMEOUTMS, MONGOC_DEFAULT_CONNECTTIMEOUTMS); topology->scanner_state = MONGOC_TOPOLOGY_SCANNER_OFF; topology->scanner = mongoc_topology_scanner_new (topology->uri, &td->topology_id, &topology->log_and_monitor, _mongoc_topology_scanner_setup_err_cb, _mongoc_topology_scanner_cb, topology, topology->connect_timeout_msec); bson_mutex_init (&topology->tpld_modification_mtx); mongoc_cond_init (&topology->cond_client); if (single_threaded) { /* single threaded drivers attempt speculative authentication during a * topology scan */ topology->scanner->speculative_authentication = true; /* single threaded clients negotiate sasl supported mechanisms during * a topology scan. */ if (_mongoc_uri_requires_auth_negotiation (uri)) { topology->scanner->negotiate_sasl_supported_mechs = true; } } srv_hostname = mongoc_uri_get_srv_hostname (uri); if (srv_hostname) { char *prefixed_hostname; memset (&rr_data, 0, sizeof (mongoc_rr_data_t)); /* Set the default resource record resolver */ topology->rr_resolver = _mongoc_client_get_rr; /* Initialize the last scan time and interval. Even if the initial DNS * lookup fails, SRV polling will still start when background monitoring * starts. */ topology->srv_polling_last_scan_ms = bson_get_monotonic_time () / 1000; _mongoc_topology_set_srv_polling_rescan_interval_ms (topology, MONGOC_TOPOLOGY_MIN_RESCAN_SRV_INTERVAL_MS); /* a mongodb+srv URI. try SRV lookup, if no error then also try TXT */ prefixed_hostname = bson_strdup_printf ("_%s._tcp.%s", mongoc_uri_get_srv_service_name (uri), srv_hostname); if (!topology->rr_resolver (prefixed_hostname, MONGOC_RR_SRV, &rr_data, MONGOC_RR_DEFAULT_BUFFER_SIZE, topology->srv_prefer_tcp, &topology->scanner->error)) { GOTO (srv_fail); } /* Failure to find TXT records will not return an error (since it is only * for options). But _mongoc_client_get_rr may return an error if * there is more than one TXT record returned. */ if (!topology->rr_resolver (srv_hostname, MONGOC_RR_TXT, &rr_data, MONGOC_RR_DEFAULT_BUFFER_SIZE, topology->srv_prefer_tcp, &topology->scanner->error)) { GOTO (srv_fail); } /* Use rr_data to update the topology's URI. */ if (rr_data.txt_record_opts && !mongoc_uri_parse_options ( topology->uri, rr_data.txt_record_opts, true /* from_dns */, &topology->scanner->error)) { GOTO (srv_fail); } if (!mongoc_uri_init_with_srv_host_list (topology->uri, rr_data.hosts, &topology->scanner->error)) { GOTO (srv_fail); } topology->srv_polling_last_scan_ms = bson_get_monotonic_time () / 1000; /* TODO (CDRIVER-4047) use BSON_MIN */ int64_t new_iv = BSON_MAX (rr_data.min_ttl * 1000, MONGOC_TOPOLOGY_MIN_RESCAN_SRV_INTERVAL_MS); _mongoc_topology_set_srv_polling_rescan_interval_ms (topology, new_iv); topology->valid = true; srv_fail: bson_free (rr_data.txt_record_opts); bson_free (prefixed_hostname); _mongoc_host_list_destroy_all (rr_data.hosts); } else { topology->valid = true; } if (!mongoc_uri_finalize (topology->uri, &topology->scanner->error)) { topology->valid = false; } td->max_hosts = mongoc_uri_get_option_as_int32 (uri, MONGOC_URI_SRVMAXHOSTS, 0); if (td->max_hosts < 0) { topology->valid = false; } /* * Set topology type from URI: * + if directConnection=true * - whether or not we have a replicaSet name, initialize to SINGLE * (directConnect with SRV or multiple hosts triggers a URI parse error) * + if directConnection=false * - if we've got a replicaSet name, initialize to RS_NO_PRIMARY * - otherwise, initialize to UNKNOWN * + if directConnection was not specified in the URI (old behavior) * - if we've got a replicaSet name, initialize to RS_NO_PRIMARY * - otherwise, if the seed list has a single host, initialize to SINGLE * - everything else gets initialized to UNKNOWN */ has_directconnection = mongoc_uri_has_option (uri, MONGOC_URI_DIRECTCONNECTION); directconnection = has_directconnection && mongoc_uri_get_option_as_bool (uri, MONGOC_URI_DIRECTCONNECTION, false); hl = mongoc_uri_get_hosts (topology->uri); /* If loadBalanced is enabled, directConnection is disabled. This was * validated in mongoc_uri_finalize_loadbalanced, which is called by * mongoc_uri_finalize. */ if (mongoc_uri_get_option_as_bool (topology->uri, MONGOC_URI_LOADBALANCED, false)) { init_type = MONGOC_TOPOLOGY_LOAD_BALANCED; if (topology->single_threaded) { /* Cooldown only applies to server monitoring for single-threaded * clients. In load balanced mode, the topology scanner is used to * create connections. The cooldown period does not apply. A network * error to a load balanced connection does not imply subsequent * connection attempts will be to the same server and that a delay * should occur. */ _mongoc_topology_bypass_cooldown (topology); } _mongoc_topology_scanner_set_loadbalanced (topology->scanner, true); } else if (srv_hostname && !has_directconnection) { init_type = MONGOC_TOPOLOGY_UNKNOWN; } else if (has_directconnection) { if (directconnection) { init_type = MONGOC_TOPOLOGY_SINGLE; } else { if (mongoc_uri_get_replica_set (topology->uri)) { init_type = MONGOC_TOPOLOGY_RS_NO_PRIMARY; } else { init_type = MONGOC_TOPOLOGY_UNKNOWN; } } } else if (mongoc_uri_get_replica_set (topology->uri)) { init_type = MONGOC_TOPOLOGY_RS_NO_PRIMARY; } else { if (hl && hl->next) { init_type = MONGOC_TOPOLOGY_UNKNOWN; } else { init_type = MONGOC_TOPOLOGY_SINGLE; } } td->type = init_type; if (!topology->single_threaded) { topology->server_monitors = mongoc_set_new (1, NULL, NULL); topology->rtt_monitors = mongoc_set_new (1, NULL, NULL); bson_mutex_init (&topology->srv_polling_mtx); mongoc_cond_init (&topology->srv_polling_cond); } if (!topology->valid) { TRACE ("%s", "topology invalid"); /* add no nodes */ return topology; } size_t hl_array_size = 0u; BSON_ASSERT (mcommon_in_range_signed (size_t, td->max_hosts)); const mongoc_host_list_t *const *hl_array = _mongoc_apply_srv_max_hosts (hl, (size_t) td->max_hosts, &hl_array_size); for (size_t idx = 0u; idx < hl_array_size; ++idx) { const mongoc_host_list_t *const elem = hl_array[idx]; uint32_t id = 0u; mongoc_topology_description_add_server (td, &topology->log_and_monitor, elem->host_and_port, &id); mongoc_topology_scanner_add (topology->scanner, elem, id, false); } bson_free ((void *) hl_array); return topology; } /* *------------------------------------------------------------------------- * * mongoc_topology_destroy -- * * Free the memory associated with this topology object. * * Returns: * None. * * Side effects: * @topology will be cleaned up. * *------------------------------------------------------------------------- */ void mongoc_topology_destroy (mongoc_topology_t *topology) { if (!topology) { return; } #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION bson_free (topology->keyvault_db); bson_free (topology->keyvault_coll); mongoc_client_destroy (topology->mongocryptd_client); mongoc_client_pool_destroy (topology->mongocryptd_client_pool); _mongoc_crypt_destroy (topology->crypt); bson_destroy (topology->mongocryptd_spawn_args); bson_free (topology->mongocryptd_spawn_path); #endif if (!topology->single_threaded) { _mongoc_topology_background_monitoring_stop (topology); BSON_ASSERT (topology->scanner_state == MONGOC_TOPOLOGY_SCANNER_OFF); mongoc_set_destroy (topology->server_monitors); mongoc_set_destroy (topology->rtt_monitors); bson_mutex_destroy (&topology->srv_polling_mtx); mongoc_cond_destroy (&topology->srv_polling_cond); } /* Before reporting this topology as closed, life cycle rules expect us to close * all servers and transition to an unknown topology. */ { /* Prefer mc_tpld_unsafe_get_const to mc_tpld_take_ref/drop_ref here: no other references remain, and bypassing * the shared pointer lock has the side-effect of revealing problems in TSAN. */ const mongoc_topology_description_t *td = mc_tpld_unsafe_get_const (topology); for (size_t i = 0u; i < mc_tpld_servers_const (td)->items_len; i++) { const mongoc_server_description_t *sd = mongoc_set_get_item_const (mc_tpld_servers_const (td), i); _mongoc_topology_description_monitor_server_closed (td, &topology->log_and_monitor, sd); } // Transition to an "Unknown" td that will exist only for monitoring purposes just before closing mongoc_topology_description_t next_td; mongoc_topology_description_init (&next_td, td->heartbeat_msec); bson_oid_copy (&td->topology_id, &next_td.topology_id); next_td.opened = td->opened; _mongoc_topology_description_monitor_changed (td, &next_td, &topology->log_and_monitor); _mongoc_topology_description_monitor_closed (&next_td, &topology->log_and_monitor); mongoc_topology_description_cleanup (&next_td); } mongoc_uri_destroy (topology->uri); mongoc_shared_ptr_reset_null (&topology->_shared_descr_._sptr_); mongoc_topology_scanner_destroy (topology->scanner); mongoc_server_session_pool_free (topology->session_pool); bson_free (topology->clientSideEncryption.autoOptions.extraOptions.cryptSharedLibPath); mongoc_log_and_monitor_instance_destroy_contents (&topology->log_and_monitor); mongoc_cond_destroy (&topology->cond_client); bson_mutex_destroy (&topology->tpld_modification_mtx); bson_destroy (topology->encrypted_fields_map); bson_free (topology); } /* Returns false if none of the hosts were valid. */ bool mongoc_topology_apply_scanned_srv_hosts (mongoc_uri_t *uri, mongoc_topology_description_t *td, const mongoc_log_and_monitor_instance_t *log_and_monitor, mongoc_host_list_t *hosts, bson_error_t *error) { mongoc_host_list_t *host; mongoc_host_list_t *valid_hosts = NULL; bool had_valid_hosts = false; /* Validate that the hosts have a matching domain. * If validation fails, log it. * If no valid hosts remain, do not update the topology description. */ LL_FOREACH (hosts, host) { if (mongoc_uri_validate_srv_result (uri, host->host, error)) { _mongoc_host_list_upsert (&valid_hosts, host); } else { MONGOC_ERROR ("Invalid host returned by SRV: %s", host->host_and_port); /* Continue on, there may still be valid hosts returned. */ } } if (valid_hosts) { /* Reconcile with the topology description. Newly found servers will start * getting monitored and are eligible to be used by clients. */ mongoc_topology_description_reconcile (td, log_and_monitor, valid_hosts); had_valid_hosts = true; } else { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NAME_RESOLUTION, "SRV response did not contain any valid hosts"); } _mongoc_host_list_destroy_all (valid_hosts); return had_valid_hosts; } /* *-------------------------------------------------------------------------- * * mongoc_topology_should_rescan_srv -- * * Checks whether it is valid to rescan SRV records on the topology. * Namely, that the topology type is Sharded or Unknown, and that * the topology URI was configured with SRV. * * If this returns false, caller can stop scanning SRV records * and does not need to try again in the future. * * -------------------------------------------------------------------------- */ bool mongoc_topology_should_rescan_srv (mongoc_topology_t *topology) { const char *srv_hostname = mongoc_uri_get_srv_hostname (topology->uri); mongoc_topology_description_type_t type; if (!srv_hostname) { /* Only rescan if we have a mongodb+srv:// URI. */ return false; } type = _mongoc_topology_get_type (topology); /* Only perform rescan for sharded topology. */ return type == MONGOC_TOPOLOGY_SHARDED || type == MONGOC_TOPOLOGY_UNKNOWN; } /* *-------------------------------------------------------------------------- * * mongoc_topology_rescan_srv -- * * Queries SRV records for new hosts in a mongos cluster. * Caller must call mongoc_topology_should_rescan_srv before calling * to ensure preconditions are met. * * NOTE: This method may update the topology description. * * -------------------------------------------------------------------------- */ void mongoc_topology_rescan_srv (mongoc_topology_t *topology) { mongoc_rr_data_t rr_data = {0}; const char *srv_hostname; char *prefixed_hostname = NULL; int64_t scan_time_ms; bool ret; mc_shared_tpld td; mc_tpld_modification tdmod; BSON_ASSERT (mongoc_topology_should_rescan_srv (topology)); srv_hostname = mongoc_uri_get_srv_hostname (topology->uri); scan_time_ms = topology->srv_polling_last_scan_ms + _mongoc_topology_get_srv_polling_rescan_interval_ms (topology); if (bson_get_monotonic_time () / 1000 < scan_time_ms) { /* Query SRV no more frequently than srv_polling_rescan_interval_ms. */ return; } TRACE ("%s", "Polling for SRV records"); /* Go forth and query... */ prefixed_hostname = bson_strdup_printf ("_%s._tcp.%s", mongoc_uri_get_srv_service_name (topology->uri), srv_hostname); ret = topology->rr_resolver (prefixed_hostname, MONGOC_RR_SRV, &rr_data, MONGOC_RR_DEFAULT_BUFFER_SIZE, topology->srv_prefer_tcp, &topology->scanner->error); td = mc_tpld_take_ref (topology); topology->srv_polling_last_scan_ms = bson_get_monotonic_time () / 1000; if (!ret) { /* Failed querying, soldier on and try again next time. */ _mongoc_topology_set_srv_polling_rescan_interval_ms (topology, td.ptr->heartbeat_msec); MONGOC_ERROR ("SRV polling error: %s", topology->scanner->error.message); GOTO (done); } /* TODO (CDRIVER-4047) use BSON_MIN */ const int64_t new_iv = BSON_MAX (rr_data.min_ttl * 1000, MONGOC_TOPOLOGY_MIN_RESCAN_SRV_INTERVAL_MS); _mongoc_topology_set_srv_polling_rescan_interval_ms (topology, new_iv); tdmod = mc_tpld_modify_begin (topology); if (!mongoc_topology_apply_scanned_srv_hosts ( topology->uri, tdmod.new_td, &topology->log_and_monitor, rr_data.hosts, &topology->scanner->error)) { MONGOC_ERROR ("%s", topology->scanner->error.message); /* Special case when DNS returns zero records successfully or no valid * hosts exist. * Leave the toplogy alone and perform another scan at the next interval * rather than removing all records and having nothing to connect to. * For no verified hosts drivers "MUST temporarily set * srv_polling_rescan_interval_ms * to heartbeatFrequencyMS until at least one verified SRV record is * obtained." */ _mongoc_topology_set_srv_polling_rescan_interval_ms (topology, td.ptr->heartbeat_msec); } mc_tpld_modify_commit (tdmod); done: mc_tpld_drop_ref (&td); bson_free (prefixed_hostname); _mongoc_host_list_destroy_all (rr_data.hosts); } /* *-------------------------------------------------------------------------- * * mongoc_topology_scan_once -- * * Runs a single complete scan. * * NOTE: This method updates the topology description. * * Only runs for single threaded monitoring. (obey_cooldown is always * true). * *-------------------------------------------------------------------------- */ static void mongoc_topology_scan_once (mongoc_topology_t *topology, bool obey_cooldown) { mongoc_topology_description_t *td; BSON_ASSERT (topology->single_threaded); if (mongoc_topology_should_rescan_srv (topology)) { /* Prior to scanning hosts, update the list of SRV hosts, if applicable. */ mongoc_topology_rescan_srv (topology); } /* since the last scan, members may be added or removed from the topology * description based on hello responses in connection handshakes, see * _mongoc_topology_update_from_handshake. retire scanner nodes for removed * members and create scanner nodes for new ones. */ // Use `mc_tpld_unsafe_get_mutable` to get a mutable topology description // without locking. This function only applies to single-threaded clients. td = mc_tpld_unsafe_get_mutable (topology); mongoc_topology_reconcile (topology, td); mongoc_topology_scanner_start (topology->scanner, obey_cooldown); mongoc_topology_scanner_work (topology->scanner); _mongoc_topology_scanner_finish (topology->scanner); topology->last_scan = bson_get_monotonic_time (); topology->stale = false; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_do_blocking_scan -- * * Monitoring entry for single-threaded use case. Assumes the caller * has checked that it's the right time to scan. * *-------------------------------------------------------------------------- */ void _mongoc_topology_do_blocking_scan (mongoc_topology_t *topology, bson_error_t *error) { BSON_ASSERT (topology->single_threaded); _mongoc_handshake_freeze (); mongoc_topology_scan_once (topology, true /* obey cooldown */); mongoc_topology_scanner_get_error (topology->scanner, error); } bool mongoc_topology_compatible (const mongoc_topology_description_t *td, const mongoc_read_prefs_t *read_prefs, bson_error_t *error) { if (td->compatibility_error.code) { if (error) { memcpy (error, &td->compatibility_error, sizeof (bson_error_t)); } return false; } if (!read_prefs) { /* NULL means read preference Primary */ return true; } const int64_t max_staleness_seconds = mongoc_read_prefs_get_max_staleness_seconds (read_prefs); if (max_staleness_seconds != MONGOC_NO_MAX_STALENESS) { /* shouldn't happen if we've properly enforced wire version */ if (!mongoc_topology_description_all_sds_have_write_date (td)) { bson_set_error ( error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "Not all servers have lastWriteDate"); return false; } if (!_mongoc_topology_description_validate_max_staleness (td, max_staleness_seconds, error)) { return false; } } return true; } static void _mongoc_server_selection_error (const char *msg, const bson_error_t *scanner_error, bson_error_t *error) { if (scanner_error && scanner_error->code) { bson_set_error (error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "%s: %s", msg, scanner_error->message); } else { bson_set_error (error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "%s", msg); } } mongoc_server_description_t * mongoc_topology_select (mongoc_topology_t *topology, mongoc_ss_optype_t optype, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, bool *must_use_primary, bson_error_t *error) { uint32_t server_id = mongoc_topology_select_server_id (topology, optype, log_context, read_prefs, must_use_primary, NULL, error); if (server_id) { /* new copy of the server description */ mongoc_server_description_t *ret; mc_shared_tpld td = mc_tpld_take_ref (topology); mongoc_server_description_t const *sd = mongoc_topology_description_server_by_id_const (td.ptr, server_id, error); ret = mongoc_server_description_new_copy (sd); mc_tpld_drop_ref (&td); return ret; } else { return NULL; } } /* Bypasses normal server selection behavior for a load balanced topology. * Returns the id of the one load balancer server. Returns 0 on failure. * Successful post-condition: On a single threaded client, a connection will * have been established. */ static uint32_t _mongoc_topology_select_server_id_loadbalanced (mongoc_topology_t *topology, bson_error_t *error) { mongoc_server_description_t const *selected_server; int32_t selected_server_id; mongoc_topology_scanner_node_t *node; bson_error_t scanner_error = {0}; mc_shared_tpld td = mc_tpld_take_ref (topology); BSON_ASSERT (td.ptr->type == MONGOC_TOPOLOGY_LOAD_BALANCED); /* Emit the opening SDAM events if they have not emitted already. */ { mc_tpld_modification tdmod = mc_tpld_modify_begin (topology); _mongoc_topology_description_monitor_opening (tdmod.new_td, &topology->log_and_monitor); mc_tpld_modify_commit (tdmod); mc_tpld_renew_ref (&td, topology); } selected_server = mongoc_topology_description_select (td.ptr, MONGOC_SS_WRITE, NULL /* read prefs */, NULL /* chosen read mode */, NULL /* deprioritized servers */, 0 /* local threshold */); if (!selected_server) { _mongoc_server_selection_error ("No suitable server found in load balanced deployment", NULL, error); selected_server_id = 0; goto done; } selected_server_id = selected_server->id; if (!topology->single_threaded) { goto done; } /* If this is a single threaded topology, we must ensure that a connection is * available to this server. Wrapping drivers make the assumption that * successful server selection implies a connection is available. */ node = mongoc_topology_scanner_get_node (topology->scanner, selected_server_id); if (!node) { _mongoc_server_selection_error ("Topology scanner in invalid state; cannot find load balancer", NULL, error); selected_server_id = 0; goto done; } if (!node->stream) { TRACE ("%s", "Server selection performing scan since no connection has " "been established"); _mongoc_topology_do_blocking_scan (topology, &scanner_error); } if (!node->stream) { /* Use the same error domain / code that is returned in mongoc-cluster.c * when fetching a stream fails. */ if (scanner_error.code) { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "Could not establish stream for node %s: %s", node->host.host_and_port, scanner_error.message); } else { bson_set_error (error, MONGOC_ERROR_STREAM, MONGOC_ERROR_STREAM_NOT_ESTABLISHED, "Could not establish stream for node %s", node->host.host_and_port); } selected_server_id = 0; goto done; } done: mc_tpld_drop_ref (&td); return selected_server_id; } uint32_t mongoc_topology_select_server_id (mongoc_topology_t *topology, mongoc_ss_optype_t optype, const mongoc_ss_log_context_t *log_context, const mongoc_read_prefs_t *read_prefs, bool *must_use_primary, const mongoc_deprioritized_servers_t *ds, bson_error_t *error) { static const char *timeout_msg = "No suitable servers found: `serverSelectionTimeoutMS` expired"; mongoc_topology_scanner_t *ts; int r; int64_t local_threshold_ms; const mongoc_server_description_t *selected_server = NULL; bool try_once; int64_t sleep_usec; bool tried_once; bool logged_waiting_for_suitable_server = false; bson_error_t scanner_error = {0}; int64_t heartbeat_msec; uint32_t server_id; mc_shared_tpld td = mc_tpld_take_ref (topology); const mongoc_log_and_monitor_instance_t *log_and_monitor = &topology->log_and_monitor; mcommon_string_append_t topology_type; mcommon_string_new_as_append (&topology_type); mcommon_string_append (&topology_type, ". Topology type: "); mcommon_string_append (&topology_type, mongoc_topology_description_type (td.ptr)); /* These names come from the Server Selection Spec pseudocode */ int64_t loop_start; /* when we entered this function */ int64_t loop_end; /* when we last completed a loop (single-threaded) */ int64_t scan_ready; /* the soonest we can do a blocking scan */ int64_t next_update; /* the latest we must do a blocking scan */ int64_t expire_at; /* when server selection timeout expires */ BSON_ASSERT (topology); ts = topology->scanner; mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION, "Server selection started", read_prefs ("selector", read_prefs), utf8 ("operation", log_context->operation), int64 (log_context->has_operation_id ? "operationId" : NULL, log_context->operation_id), topology_as_description_json ("topologyDescription", topology)); if (!mongoc_topology_scanner_valid (ts)) { if (error) { mongoc_topology_scanner_get_error (ts, error); error->domain = MONGOC_ERROR_SERVER_SELECTION; error->code = MONGOC_ERROR_SERVER_SELECTION_FAILURE; } server_id = 0; goto done; } if (td.ptr->type == MONGOC_TOPOLOGY_LOAD_BALANCED) { server_id = _mongoc_topology_select_server_id_loadbalanced (topology, error); goto done; } heartbeat_msec = td.ptr->heartbeat_msec; local_threshold_ms = topology->local_threshold_msec; try_once = topology->server_selection_try_once; loop_start = loop_end = bson_get_monotonic_time (); expire_at = loop_start + ((int64_t) topology->server_selection_timeout_msec * 1000); if (topology->single_threaded) { // Use `mc_tpld_unsafe_get_mutable` to get a mutable topology // description without locking. This block only applies to // single-threaded clients. _mongoc_topology_description_monitor_opening (mc_tpld_unsafe_get_mutable (topology), log_and_monitor); mc_tpld_renew_ref (&td, topology); tried_once = false; next_update = topology->last_scan + heartbeat_msec * 1000; if (next_update < loop_start) { /* we must scan now */ topology->stale = true; } /* until we find a server or time out */ for (;;) { if (topology->stale) { /* how soon are we allowed to scan? */ scan_ready = topology->last_scan + topology->min_heartbeat_frequency_msec * 1000; if (scan_ready > expire_at && !try_once) { /* selection timeout will expire before min heartbeat passes */ _mongoc_server_selection_error (timeout_msg, &scanner_error, error); server_id = 0; goto done; } sleep_usec = scan_ready - loop_end; if (sleep_usec > 0) { if (try_once && mongoc_topology_scanner_in_cooldown (ts, scan_ready)) { _mongoc_server_selection_error ("No servers yet eligible for rescan", &scanner_error, error); server_id = 0; goto done; } if (!logged_waiting_for_suitable_server) { logged_waiting_for_suitable_server = true; mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_INFO, MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION, "Waiting for suitable server to become available", read_prefs ("selector", read_prefs), utf8 ("operation", log_context->operation), int64 (log_context->has_operation_id ? "operationId" : NULL, log_context->operation_id), topology_as_description_json ("topologyDescription", topology), int64 ("remainingTimeMS", (expire_at - loop_end) / 1000)); } topology->usleep_fn (sleep_usec, topology->usleep_data); } /* takes up to connectTimeoutMS. sets "last_scan", clears "stale" */ _mongoc_topology_do_blocking_scan (topology, &scanner_error); loop_end = topology->last_scan; tried_once = true; } /* Topology may have just been updated by a scan. */ mc_tpld_renew_ref (&td, topology); if (!mongoc_topology_compatible (td.ptr, read_prefs, error)) { server_id = 0; goto done; } selected_server = mongoc_topology_description_select (td.ptr, optype, read_prefs, must_use_primary, ds, local_threshold_ms); if (selected_server) { server_id = selected_server->id; goto done; } topology->stale = true; if (try_once) { if (tried_once) { _mongoc_server_selection_error ( "No suitable servers found (`serverSelectionTryOnce` set)", &scanner_error, error); server_id = 0; goto done; } } else { loop_end = bson_get_monotonic_time (); if (loop_end > expire_at) { /* no time left in server_selection_timeout_msec */ _mongoc_server_selection_error (timeout_msg, &scanner_error, error); server_id = 0; goto done; } } } } /* With background thread */ /* we break out when we've found a server or timed out */ for (;;) { /* Topology may have been updated on a previous loop iteration */ mc_tpld_renew_ref (&td, topology); if (!mongoc_topology_compatible (td.ptr, read_prefs, error)) { server_id = 0; goto done; } selected_server = mongoc_topology_description_select (td.ptr, optype, read_prefs, must_use_primary, ds, local_threshold_ms); if (selected_server) { server_id = selected_server->id; goto done; } /* tlpd_modification_mtx is used to synchronize updates to the topology. * Take that lock to do a wait on the topology to become up-to-date and * synchronize with a condition variable that will be signalled upon * topology changes. */ bson_mutex_lock (&topology->tpld_modification_mtx); /* Now that we have the lock, check again, since a scan may have * occurred while we were waiting on the lock. */ mc_tpld_renew_ref (&td, topology); selected_server = mongoc_topology_description_select (td.ptr, optype, read_prefs, must_use_primary, ds, local_threshold_ms); if (selected_server) { server_id = selected_server->id; bson_mutex_unlock (&topology->tpld_modification_mtx); goto done; } /* Still nothing. Request that the scanner do a scan now. */ TRACE ("server selection requesting an immediate scan, want %s", _mongoc_read_mode_as_str (mongoc_read_prefs_get_mode (read_prefs))); _mongoc_topology_request_scan (topology); if (!logged_waiting_for_suitable_server) { logged_waiting_for_suitable_server = true; mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_INFO, MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION, "Waiting for suitable server to become available", read_prefs ("selector", read_prefs), utf8 ("operation", log_context->operation), int64 (log_context->has_operation_id ? "operationId" : NULL, log_context->operation_id), topology_as_description_json ("topologyDescription", topology), int64 ("remainingTimeMS", (expire_at - loop_start) / 1000)); } TRACE ("server selection about to wait for %" PRId64 "ms", (expire_at - loop_start) / 1000); r = mongoc_cond_timedwait ( &topology->cond_client, &topology->tpld_modification_mtx, (expire_at - loop_start) / 1000); TRACE ("%s", "server selection awake"); /* Refresh our topology handle */ mc_tpld_renew_ref (&td, topology); _topology_collect_errors (td.ptr, &scanner_error); bson_mutex_unlock (&topology->tpld_modification_mtx); #ifdef _WIN32 if (r == WSAETIMEDOUT) { #else if (r == ETIMEDOUT) { #endif /* handle timeouts */ _mongoc_server_selection_error (timeout_msg, &scanner_error, error); server_id = 0; goto done; } else if (r) { bson_set_error (error, MONGOC_ERROR_SERVER_SELECTION, MONGOC_ERROR_SERVER_SELECTION_FAILURE, "Unknown error '%d' received while waiting on " "thread condition", r); server_id = 0; goto done; } loop_start = bson_get_monotonic_time (); if (loop_start > expire_at) { _mongoc_server_selection_error (timeout_msg, &scanner_error, error); server_id = 0; goto done; } } done: /* server_id set to zero indicates an error has occured and that `error` should be initialized */ if (server_id == 0) { if (error && error->domain == MONGOC_ERROR_SERVER_SELECTION) { _mongoc_error_append (error, mcommon_str_from_append (&topology_type)); } mongoc_structured_log (log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION, "Server selection failed", read_prefs ("selector", read_prefs), utf8 ("operation", log_context->operation), int64 (log_context->has_operation_id ? "operationId" : NULL, log_context->operation_id), topology_as_description_json ("topologyDescription", topology), error ("failure", error)); } else { mongoc_structured_log ( log_and_monitor->structured_log, MONGOC_STRUCTURED_LOG_LEVEL_DEBUG, MONGOC_STRUCTURED_LOG_COMPONENT_SERVER_SELECTION, "Server selection succeeded", read_prefs ("selector", read_prefs), utf8 ("operation", log_context->operation), int64 (log_context->has_operation_id ? "operationId" : NULL, log_context->operation_id), topology_as_description_json ("topologyDescription", topology), server_description ( mongoc_topology_description_server_by_id_const (td.ptr, server_id, NULL), SERVER_HOST, SERVER_PORT)); } mcommon_string_from_append_destroy (&topology_type); mc_tpld_drop_ref (&td); return server_id; } mongoc_host_list_t * _mongoc_topology_host_by_id (const mongoc_topology_description_t *td, uint32_t id, bson_error_t *error) { mongoc_server_description_t const *sd; mongoc_host_list_t *host = NULL; /* not a copy - direct pointer into topology description data */ sd = mongoc_topology_description_server_by_id_const (td, id, error); if (sd) { host = bson_malloc0 (sizeof (mongoc_host_list_t)); memcpy (host, &sd->host, sizeof (mongoc_host_list_t)); } return host; } void _mongoc_topology_request_scan (mongoc_topology_t *topology) { _mongoc_topology_background_monitoring_request_scan (topology); } bool _mongoc_topology_update_from_handshake (mongoc_topology_t *topology, const mongoc_server_description_t *sd) { bool has_server; mc_tpld_modification tdmod; BSON_ASSERT (topology); BSON_ASSERT (sd); BSON_ASSERT (!topology->single_threaded); if (_mongoc_topology_get_type (topology) == MONGOC_TOPOLOGY_LOAD_BALANCED) { /* In load balanced mode, scanning is only for connection establishment. * It must not modify the topology description. */ return true; } tdmod = mc_tpld_modify_begin (topology); /* return false if server was removed from topology */ has_server = _mongoc_topology_update_no_lock ( sd->id, &sd->last_hello_response, sd->round_trip_time_msec, tdmod.new_td, &topology->log_and_monitor, NULL); /* if pooled, wake threads waiting in mongoc_topology_server_by_id */ mongoc_cond_broadcast (&topology->cond_client); /* Update background monitoring. */ _mongoc_topology_background_monitoring_reconcile (topology, tdmod.new_td); mc_tpld_modify_commit (tdmod); return has_server; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_update_last_used -- * * Internal function. In single-threaded mode only, track when the socket * to a particular server was last used. This is required for * mongoc_cluster_check_interval to know when a socket has been idle. * *-------------------------------------------------------------------------- */ void _mongoc_topology_update_last_used (mongoc_topology_t *topology, uint32_t server_id) { mongoc_topology_scanner_node_t *node; if (!topology->single_threaded) { return; } node = mongoc_topology_scanner_get_node (topology->scanner, server_id); if (node) { node->last_used = bson_get_monotonic_time (); } } mongoc_topology_description_type_t _mongoc_topology_get_type (const mongoc_topology_t *topology) { mc_shared_tpld td = mc_tpld_take_ref (topology); mongoc_topology_description_type_t td_type = td.ptr->type; mc_tpld_drop_ref (&td); return td_type; } bool _mongoc_topology_set_appname (mongoc_topology_t *topology, const char *appname) { bool ret = false; if (topology->scanner_state == MONGOC_TOPOLOGY_SCANNER_OFF) { ret = _mongoc_topology_scanner_set_appname (topology->scanner, appname); } else { MONGOC_ERROR ("Cannot set appname after handshake initiated"); } return ret; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_update_cluster_time -- * * Internal function. If the server reply has a later $clusterTime than * any seen before, update the topology's clusterTime. See the Driver * Sessions Spec. * *-------------------------------------------------------------------------- */ void _mongoc_topology_update_cluster_time (mongoc_topology_t *topology, const bson_t *reply) { bson_iter_t iter; bson_iter_t child; const uint8_t *data; uint32_t size; bson_t cluster_time; mc_shared_tpld td; if (!reply || !bson_iter_init_find (&iter, reply, "$clusterTime")) { return; } if (!BSON_ITER_HOLDS_DOCUMENT (&iter) || !bson_iter_recurse (&iter, &child)) { MONGOC_ERROR ("Can't parse $clusterTime"); return; } bson_iter_document (&iter, &size, &data); BSON_ASSERT (bson_init_static (&cluster_time, data, (size_t) size)); td = mc_tpld_take_ref (topology); /* This func is called frequently and repeatedly, but the cluster time itself * is infrequently updated. mc_tpld_modify_begin() is very expensive, so we * only want to actually call it if we anticipate performing an update to the * cluster time. * * Check that the cluster time has actually changed from what we have on * record before opening a topology modification to update it. */ if (bson_empty (&td.ptr->cluster_time) || _mongoc_cluster_time_greater (&cluster_time, &td.ptr->cluster_time)) { mc_tpld_modification tdmod = mc_tpld_modify_begin (topology); /* Check again if we need to update the cluster time, since it may have * been updated behind our back. */ if (bson_empty (&tdmod.new_td->cluster_time) || _mongoc_cluster_time_greater (&cluster_time, &tdmod.new_td->cluster_time)) { bson_destroy (&tdmod.new_td->cluster_time); bson_copy_to (&cluster_time, &tdmod.new_td->cluster_time); _mongoc_topology_scanner_set_cluster_time (topology->scanner, &tdmod.new_td->cluster_time); mc_tpld_modify_commit (tdmod); } else { mc_tpld_modify_drop (tdmod); } } mc_tpld_drop_ref (&td); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_pop_server_session -- * * Internal function. Get a server session from the pool or create * one. On error, return NULL and fill out @error. * *-------------------------------------------------------------------------- */ mongoc_server_session_t * _mongoc_topology_pop_server_session (mongoc_topology_t *topology, const mongoc_ss_log_context_t *log_context, bson_error_t *error) { int64_t timeout; mongoc_server_session_t *ss = NULL; bool loadbalanced; mc_shared_tpld td = mc_tpld_take_ref (topology); ENTRY; timeout = td.ptr->session_timeout_minutes; loadbalanced = td.ptr->type == MONGOC_TOPOLOGY_LOAD_BALANCED; /* When the topology type is LoadBalanced, sessions are always supported. */ if (!loadbalanced && timeout == MONGOC_NO_SESSIONS) { /* if needed, connect and check for session timeout again */ if (!mongoc_topology_description_has_data_node (td.ptr)) { if (!mongoc_topology_select_server_id (topology, MONGOC_SS_READ, log_context, NULL /* read prefs */, NULL /* chosen read mode */, NULL /* deprioritized servers */, error)) { ss = NULL; goto done; } /* Topology may have been updated by a scan */ mc_tpld_renew_ref (&td, topology); timeout = td.ptr->session_timeout_minutes; } if (timeout == MONGOC_NO_SESSIONS) { bson_set_error ( error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_SESSION_FAILURE, "Server does not support sessions"); ss = NULL; goto done; } } ss = mongoc_server_session_pool_get (topology->session_pool, error); done: mc_tpld_drop_ref (&td); RETURN (ss); } /* *-------------------------------------------------------------------------- * * _mongoc_topology_push_server_session -- * * Internal function. Return a server session to the pool. * *-------------------------------------------------------------------------- */ void _mongoc_topology_push_server_session (mongoc_topology_t *topology, mongoc_server_session_t *server_session) { ENTRY; /** * ! note: * At time of writing, this diverges from the spec: * https://github.com/mongodb/specifications/blob/master/source/sessions/driver-sessions.md#algorithm-to-return-a-serversession-instance-to-the-server-session-pool * * The spec notes that before returning a session, we should first inspect * the back of the pool for expired items and delete them. In this case, we * simply return the item to the top of the pool and leave the remainder * unchanged. * * The next pop operation that encounters an expired session will clear the * entire session pool, thus preventing unbounded growth of the pool. */ mongoc_server_session_pool_return (topology->session_pool, server_session); EXIT; } /* *-------------------------------------------------------------------------- * * _mongoc_topology_end_sessions_cmd -- * * Internal function. End up to 10,000 server sessions. @cmd is an * uninitialized document. Sessions are destroyed as their ids are * appended to @cmd. * * Driver Sessions Spec: "If the number of sessions is very large the * endSessions command SHOULD be run multiple times to end 10,000 * sessions at a time (in order to avoid creating excessively large * commands)." * * Returns: * true if any session ids were appended to @cmd. * *-------------------------------------------------------------------------- */ bool _mongoc_topology_end_sessions_cmd (mongoc_topology_t *topology, bson_t *cmd) { bson_array_builder_t *ar; /* Only end up to 10'000 sessions */ const int ENDED_SESSION_PRUNING_LIMIT = 10000; int i = 0; mongoc_server_session_t *ss = mongoc_server_session_pool_get_existing (topology->session_pool); bson_init (cmd); BSON_APPEND_ARRAY_BUILDER_BEGIN (cmd, "endSessions", &ar); for (; i < ENDED_SESSION_PRUNING_LIMIT && ss != NULL; ++i, ss = mongoc_server_session_pool_get_existing (topology->session_pool)) { bson_array_builder_append_document (ar, &ss->lsid); mongoc_server_session_pool_drop (topology->session_pool, ss); } if (ss) { /* We deleted at least 10'000 sessions, so we will need to return the * final session that we didn't drop */ mongoc_server_session_pool_return (topology->session_pool, ss); } bson_append_array_builder_end (cmd, ar); return i > 0; } void _mongoc_topology_dup_handshake_cmd (const mongoc_topology_t *topology, bson_t *copy_into) { _mongoc_topology_scanner_dup_handshake_cmd (topology->scanner, copy_into); } void _mongoc_topology_bypass_cooldown (mongoc_topology_t *topology) { BSON_ASSERT (topology->single_threaded); topology->scanner->bypass_cooldown = true; } static void _find_topology_version (const bson_t *reply, bson_t *topology_version) { bson_iter_t iter; const uint8_t *bytes; uint32_t len; if (!bson_iter_init_find (&iter, reply, "topologyVersion") || !BSON_ITER_HOLDS_DOCUMENT (&iter)) { bson_init (topology_version); return; } bson_iter_document (&iter, &len, &bytes); BSON_ASSERT (bson_init_static (topology_version, bytes, len)); } static bool _handle_sdam_app_error_command (mongoc_topology_t *topology, const mongoc_topology_description_t *td, uint32_t server_id, uint32_t generation, const bson_oid_t *service_id, const mongoc_server_description_t *sd, uint32_t max_wire_version, const bson_t *reply) { bson_error_t cmd_error; bson_t incoming_topology_version; bool pool_cleared = false; bool should_clear_pool = false; mc_tpld_modification tdmod; mongoc_server_description_t *mut_sd; BSON_UNUSED (td); if (_mongoc_cmd_check_ok_no_wce (reply, MONGOC_ERROR_API_VERSION_2, &cmd_error)) { /* No error. */ return false; } if (!_mongoc_error_is_state_change (&cmd_error)) { /* Not a "not primary" or "node is recovering" error. */ return false; } /* Check if the error is "stale", i.e. the topologyVersion refers to an * older * version of the server than we have stored in the topology description. */ _find_topology_version (reply, &incoming_topology_version); if (mongoc_server_description_topology_version_cmp (&sd->topology_version, &incoming_topology_version) >= 0) { /* The server description is greater or equal, ignore the error. */ bson_destroy (&incoming_topology_version); return false; } should_clear_pool = (max_wire_version <= WIRE_VERSION_4_0 || _mongoc_error_is_shutdown (&cmd_error)); tdmod = mc_tpld_modify_begin (topology); /* Get the server handle again, which might have been removed. */ mut_sd = mongoc_topology_description_server_by_id (tdmod.new_td, server_id, NULL); if (!mut_sd) { /* Server was already removed/invalidated */ mc_tpld_modify_drop (tdmod); bson_destroy (&incoming_topology_version); return false; } /* Check the topology version a second time, now that we have an exclusive * lock on the latest topology description. */ if (mongoc_server_description_topology_version_cmp (&mut_sd->topology_version, &incoming_topology_version) >= 0) { /* The server description is greater or equal, ignore the error. */ mc_tpld_modify_drop (tdmod); bson_destroy (&incoming_topology_version); return false; } if (generation < mc_tpl_sd_get_generation (mut_sd, service_id)) { /* Our view of the server description is stale. Ignore it. */ mc_tpld_modify_drop (tdmod); bson_destroy (&incoming_topology_version); return false; } /* Overwrite the topology version. */ mongoc_server_description_set_topology_version (mut_sd, &incoming_topology_version); /* SDAM: When handling a "not primary" or "node is recovering" error, the * client MUST clear the server's connection pool if and only if the error * is "node is shutting down" or the error originated from server version * < 4.2. */ if (should_clear_pool) { _mongoc_topology_description_clear_connection_pool (tdmod.new_td, server_id, service_id); pool_cleared = true; } /* * SDAM: When the client sees a "not primary" or "node is recovering" * error and the error's topologyVersion is strictly greater than the * current ServerDescription's topologyVersion it MUST replace the * server's description with a ServerDescription of type Unknown. */ mongoc_topology_description_invalidate_server (tdmod.new_td, &topology->log_and_monitor, server_id, &cmd_error); if (topology->single_threaded) { /* SDAM: For single-threaded clients, in the case of a "not primary" or * "node is shutting down" error, the client MUST mark the topology as * "stale" */ if (_mongoc_error_is_not_primary (&cmd_error)) { topology->stale = true; } } else { /* SDAM Spec: "Multi-threaded and asynchronous clients MUST request an * immediate check of the server." * Instead of requesting a check of the one server, request a scan * to all servers (to find the new primary). */ _mongoc_topology_request_scan (topology); } mc_tpld_modify_commit (tdmod); bson_destroy (&incoming_topology_version); return pool_cleared; } bool _mongoc_topology_handle_app_error (mongoc_topology_t *topology, uint32_t server_id, bool handshake_complete, _mongoc_sdam_app_error_type_t type, const bson_t *reply, const bson_error_t *why, uint32_t max_wire_version, uint32_t generation, const bson_oid_t *service_id) { bson_error_t server_selection_error; const mongoc_server_description_t *sd; bool cleared_pool = false; mc_shared_tpld td = mc_tpld_take_ref (topology); /* Start by checking every condition in which we should ignore the error */ sd = mongoc_topology_description_server_by_id_const (td.ptr, server_id, &server_selection_error); if (!sd) { /* The server was already removed from the topology. Ignore error. */ goto ignore_error; } /* When establishing a new connection in load balanced mode, drivers MUST NOT * perform SDAM error handling for any errors that occur before the MongoDB * Handshake. */ if (td.ptr->type == MONGOC_TOPOLOGY_LOAD_BALANCED && !handshake_complete) { goto ignore_error; } if (generation < mc_tpl_sd_get_generation (sd, service_id)) { /* This is a stale connection. Ignore. */ goto ignore_error; } if (type == MONGOC_SDAM_APP_ERROR_TIMEOUT && handshake_complete) { /* Timeout errors after handshake are ok, do nothing. */ goto ignore_error; } /* Do something with the error */ if (type == MONGOC_SDAM_APP_ERROR_COMMAND) { cleared_pool = _handle_sdam_app_error_command ( topology, td.ptr, server_id, generation, service_id, sd, max_wire_version, reply); } else { /* Invalidate the server that saw the error. */ mc_tpld_modification tdmod = mc_tpld_modify_begin (topology); sd = mongoc_topology_description_server_by_id_const (tdmod.new_td, server_id, NULL); /* Check if the server has already been invalidated */ if (!sd || generation < mc_tpl_sd_get_generation (sd, service_id)) { mc_tpld_modify_drop (tdmod); goto ignore_error; } /* Mark server as unknown. */ mongoc_topology_description_invalidate_server (tdmod.new_td, &topology->log_and_monitor, server_id, why); /* Clear the connection pool */ _mongoc_topology_description_clear_connection_pool (tdmod.new_td, server_id, service_id); cleared_pool = true; if (!topology->single_threaded) { _mongoc_topology_background_monitoring_cancel_check (topology, server_id); } mc_tpld_modify_commit (tdmod); } ignore_error: /* <- Jump taken if we should ignore the error */ mc_tpld_drop_ref (&td); return cleared_pool; } /* Called from application threads * Caller must hold topology lock. * For single-threaded monitoring, the topology scanner may include errors for * servers that were removed from the topology. */ static void _topology_collect_errors (const mongoc_topology_description_t *td, bson_error_t *error_out) { const mongoc_server_description_t *server_description; memset (error_out, 0, sizeof (bson_error_t)); mcommon_string_append_t error_message; mcommon_string_new_as_fixed_capacity_append (&error_message, sizeof error_out->message - 1u); for (size_t i = 0u; i < mc_tpld_servers_const (td)->items_len; i++) { const bson_error_t *error; server_description = mc_tpld_servers_const (td)->items[i].item; error = &server_description->error; if (error->code) { if (!mcommon_string_from_append_is_empty (&error_message)) { mcommon_string_append (&error_message, " "); } mcommon_string_append_printf (&error_message, "[%s]", server_description->error.message); /* The last error's code and domain wins. */ error_out->code = error->code; error_out->domain = error->domain; } } bson_strncpy ((char *) &error_out->message, mcommon_str_from_append (&error_message), sizeof (error_out->message)); mcommon_string_from_append_destroy (&error_message); } void _mongoc_topology_set_rr_resolver (mongoc_topology_t *topology, _mongoc_rr_resolver_fn rr_resolver) { topology->rr_resolver = rr_resolver; } uint32_t _mongoc_topology_get_connection_pool_generation (const mongoc_topology_description_t *td, uint32_t server_id, const bson_oid_t *service_id) { const mongoc_server_description_t *sd; bson_error_t error; BSON_ASSERT (service_id); sd = mongoc_topology_description_server_by_id_const (td, server_id, &error); if (!sd) { /* Server removed, ignore and ignore error. */ return 0; } return mc_tpl_sd_get_generation (sd, service_id); } mc_tpld_modification mc_tpld_modify_begin (mongoc_topology_t *tpl) { mc_shared_tpld prev_td; mongoc_topology_description_t *new_td; bson_mutex_lock (&tpl->tpld_modification_mtx); prev_td = mc_tpld_take_ref (tpl); new_td = mongoc_topology_description_new_copy (prev_td.ptr); mc_tpld_drop_ref (&prev_td); return (mc_tpld_modification){ .new_td = new_td, .topology = tpl, }; } void mc_tpld_modify_commit (mc_tpld_modification mod) { mongoc_shared_ptr old_sptr = mongoc_shared_ptr_copy (mod.topology->_shared_descr_._sptr_); mongoc_shared_ptr new_sptr = mongoc_shared_ptr_create (mod.new_td, _tpld_destroy_and_free); mongoc_atomic_shared_ptr_store (&mod.topology->_shared_descr_._sptr_, new_sptr); bson_mutex_unlock (&mod.topology->tpld_modification_mtx); mongoc_shared_ptr_reset_null (&new_sptr); mongoc_shared_ptr_reset_null (&old_sptr); } void mc_tpld_modify_drop (mc_tpld_modification mod) { bson_mutex_unlock (&mod.topology->tpld_modification_mtx); mongoc_topology_description_destroy (mod.new_td); } bool mongoc_topology_uses_server_api (const mongoc_topology_t *topology) { BSON_ASSERT_PARAM (topology); return mongoc_topology_scanner_uses_server_api (topology->scanner); } bool mongoc_topology_uses_loadbalanced (const mongoc_topology_t *topology) { BSON_ASSERT_PARAM (topology); return mongoc_topology_scanner_uses_loadbalanced (topology->scanner); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-trace-private.h0000644000175100001660000001466414760300420023720 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TRACE_PRIVATE_H #define MONGOC_TRACE_PRIVATE_H #include #include #include #include #include BSON_BEGIN_DECLS // `gLogTrace` determines if tracing is enabled at runtime. extern bool gLogTrace; #define TRACE(msg, ...) \ do { \ if (MONGOC_TRACE_ENABLED && gLogTrace) { \ mongoc_log (MONGOC_LOG_LEVEL_TRACE, \ MONGOC_LOG_DOMAIN, \ "TRACE: %s():%d " msg, \ BSON_FUNC, \ (int) (__LINE__), \ __VA_ARGS__); \ } \ } while (0) #define ENTRY \ do { \ if (MONGOC_TRACE_ENABLED && gLogTrace) { \ mongoc_log (MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, "ENTRY: %s():%d", BSON_FUNC, (int) (__LINE__)); \ } \ } while (0) #define EXIT \ do { \ if (MONGOC_TRACE_ENABLED && gLogTrace) { \ mongoc_log (MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, " EXIT: %s():%d", BSON_FUNC, (int) (__LINE__)); \ } \ return; \ } while (0) #define RETURN(ret) \ do { \ if (MONGOC_TRACE_ENABLED && gLogTrace) { \ mongoc_log (MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, " EXIT: %s():%d", BSON_FUNC, (int) (__LINE__)); \ } \ return ret; \ } while (0) #define GOTO(label) \ do { \ if (MONGOC_TRACE_ENABLED && gLogTrace) { \ mongoc_log ( \ MONGOC_LOG_LEVEL_TRACE, MONGOC_LOG_DOMAIN, " GOTO: %s():%d %s", BSON_FUNC, (int) (__LINE__), #label); \ } \ goto label; \ } while (0) #define DUMP_BSON(_bson) \ do { \ if (MONGOC_TRACE_ENABLED && gLogTrace) { \ char *_bson_str; \ if (_bson) { \ _bson_str = bson_as_canonical_extended_json (_bson, NULL); \ } else { \ _bson_str = bson_strdup (""); \ } \ mongoc_log (MONGOC_LOG_LEVEL_TRACE, \ MONGOC_LOG_DOMAIN, \ "TRACE: %s():%d %s = %s", \ BSON_FUNC, \ (int) (__LINE__), \ #_bson, \ _bson_str); \ bson_free (_bson_str); \ } \ } while (0) #define DUMP_IOVEC(_n, _iov, _iovcnt) \ do { \ if (MONGOC_TRACE_ENABLED && gLogTrace) { \ mongoc_log (MONGOC_LOG_LEVEL_TRACE, \ MONGOC_LOG_DOMAIN, \ "TRACE: %s():%d %s = %p [%d]", \ BSON_FUNC, \ (int) (__LINE__), \ #_n, \ (void *) _iov, \ (int) _iovcnt); \ mongoc_log_trace_iovec (MONGOC_LOG_DOMAIN, _iov, _iovcnt); \ } \ } while (0) BSON_END_DECLS #endif /* MONGOC_TRACE_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-ts-pool-private.h0000644000175100001660000004247214760300420024215 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_TS_POOL_PRIVATE_H #define MONGOC_TS_POOL_PRIVATE_H #include #include struct _bson_error_t; /** Type of an object constructor function */ typedef void (*_erased_constructor_fn) (void *self, void *userdata, struct _bson_error_t *error_out); /** Type of an object destructor function */ typedef void (*_erased_destructor_fn) (void *self, void *userdata); /** Type of an object pruning predicate */ typedef int (*_erased_prune_predicate) (const void *self, void *userdata); /** Type of a pool visit function */ typedef int (*_erased_visit_fn) (void *elem, void *pool_userdata, void *visit_userdata); /** * @brief Construction parameters for creating a new object pool. */ typedef struct mongoc_ts_pool_params { /** * @brief The alignment of the objects that are managed by the pool */ size_t element_alignment; /** * @brief The size of the objects that are managed by the pool */ size_t element_size; /** * @brief Arbitrary data pointer that is passed to the * constructor/destructor/prune_predicate functions */ void *userdata; /** * @brief A function that is called on a newly-allocated object in the pool. * * If `NULL`, newly created objects are just zero-initialized. * * Called as `constructor(item_ptr, userdata_ptr, bson_error_ptr)`. * * The `bson_error_ptr` is never `NULL`. If the bson_error_ptr->code is * non-zero, the pool will consider the constructor to have failed, and will * deallocate the item without destroying it, and then report that failure to * the caller of `mongoc_ts_pool_get()` that caused the creation of the new * item. */ _erased_constructor_fn constructor; /** * @brief A function that will destroy an item before it is deallocated. * * If `NULL`, destructing an object is a no-op. * * Called as `destructor(item_ptr, userdata_ptr)`. */ _erased_destructor_fn destructor; /** * @brief A predicate function that is used to automatically drop items from * the pool. * * If `NULL`, item are never automatically dropped from the pool, and * can only be discarded by use of `mongoc_ts_pool_drop()`. Items will still * be dropped when the pool is freed, though. * * Called as `prune_predicate(item_ptr, userdata_ptr)`. * * If this function returns non-zero, this informs the pool that the item * should not be returned to the pool nor yielded to a pool user. Instead, * the item will be given to `mongoc_ts_pool_drop`. */ _erased_prune_predicate prune_predicate; } mongoc_ts_pool_params; /** * @brief A thread-safe object pool. * * Object pools act as a thread-safe stack of reusable objects. The pool can be * given a prune-predicate function that will be used to discard elements * automatically if they meet some user-specified condition. * * When an item is taken from a pool, the pool will either create a new item or * return the *most-recently-returned* *non-pruned* item. i.e. The pool acts as * a LIFO stack. * * Objects are created *automatically* by the pool: Only objects obtained from a * pool instance can be returned to that pool, and all objects obtained from * a given pool must either be returned to that same pool, or dropped using * `mongoc_ts_pool_drop`. * * Refer to `mongoc_ts_pool_params` for more information on the construction, * destruction, and pruning of pool items. */ typedef struct mongoc_ts_pool mongoc_ts_pool; /** * @brief Create a new thread-safe pool * * @param params The operating parameters for the pool. @see * mongoc_ts_pool_params * * @returns A new thread-safe pool constructed with the given parameters. * * @note The pool must be destroyed using `mongoc_ts_pool_free` */ mongoc_ts_pool * mongoc_ts_pool_new (mongoc_ts_pool_params params); /** * @brief Destroy a pool of objects previously created with `mongo_ts_pool_new` * * Any objects remaining in the pool will also be destroyed. * * @note All objects that have been obtained from the pool must be returned to * the pool before it is freed. */ void mongoc_ts_pool_free (mongoc_ts_pool *pool); /** * @brief Obtain an object from the pool. * * If the pool is empty, the pool will try to create a new item and return it. * If the constructor of that item fails, this function will return `NULL` and * set an error in `error`. * * @param pool The pool of objects. * @param error An error out-parameter. If the constructor of an object is * called and fails, it will set an error through this parameter. * @returns A pointer to an object associated with the pool, or `NULL` if the * object's constructor fails. * * @note Returns the most-recently-returned non-pruned item from the pool (i.e. * the pool is a LIFO stack). * * @note If the return value is `NULL`, then an error will be set in `*error`. * If the return value is non-`NULL`, then the value of `*error` is unspecified. * * @note A non-NULL returned item MUST be passed to either * `mongo_ts_pool_return` or `mongo_ts_pool_drop` BEFORE the pool is destroyed * with `mongo_ts_pool_free`. */ void * mongoc_ts_pool_get (mongoc_ts_pool *pool, struct _bson_error_t *error); /** * @brief Attempt to pop an object from the pool. * * Unlike `mongoc_ts_pool_get`, if the pool is empty, this function returns * `NULL` unconditionally. * * @param pool The pool of objects. * @returns A pointer to an object previously passed to `mongo_ts_pool_push`, * or `NULL` if the pool is empty. * * @note Returns the most-recently-returned non-pruned item from the pool * (i.e. the pool is a LIFO stack). */ void * mongoc_ts_pool_get_existing (mongoc_ts_pool *pool); /** * @brief Return an object obtained from a pool back to the pool that manages it * * @param item A pointer that was previously returned from a call to * `mongoc_ts_pool_get` or `mongoc_ts_pool_get_existing` */ void mongoc_ts_pool_return (mongoc_ts_pool *pool, void *item); /** * @brief Obtain the number of elements in the pool. * * @note If the pool could be modified by another thread simultaneously, then * the return value may become immediately stale. */ size_t mongoc_ts_pool_size (const mongoc_ts_pool *pool); /** * @brief Determine whether the pool is empty. * * @note If the pool could be modified by another thread simultaneously, then * the result may become immediately stale. */ int mongoc_ts_pool_is_empty (const mongoc_ts_pool *pool); /** * @brief Destroy all items currently in the given pool. * * Objects that are "checked-out" of the pool are unaffected. * * @note This does not free the pool. For that purpose, us `mongoc_ts_pool_free` */ void mongoc_ts_pool_clear (mongoc_ts_pool *pool); /** * @brief Destroy an item that was created by a pool * * Instead of returning to the pool, the item will be destroyed and deallocated. * * @param item A pointer returned by `mongoc_ts_pool_get` or * `mongo_ts_pool_get_existing`. */ void mongoc_ts_pool_drop (mongoc_ts_pool *pool, void *item); /** * @brief Visit each element of the pool, optionally pruning items. * * @note While this visit function is executing, all pool operations are * blocked on all threads. Attempting to return/get/drop items in the pool from * within the visit callback will deadlock. * * The visit function will be called as: * * visit(pool_item, pool_userdata, visit_userdata) * * If the visitor function returns non-zero for an item, then that item will be * removed from the pool. * * @param pool The pool of items to visit * @param visit_userdata Optional additional context for the visitor * @param visitor The visit function * */ void mongoc_ts_pool_visit_each (mongoc_ts_pool *pool, void *visit_userdata, _erased_visit_fn visitor); /** * @brief Declare a thread-safe pool type that contains elements of a specific * type. Wraps a `mongoc_ts_pool`. * * @param ElementType The type of object contained in the pool * @param PoolName The name of the pool type. All methods of the pool will be * prefixed by this name. * @param UserDataType The type of the userdata associated with the constructor, * destructor, and prune predicate. May be `void`. * @param Constructor A function that constructs new elements for the pool, or * `NULL` * @param Destructor An element destructor function, or `NULL` * @param PrunePredicate A function that checks whether elements should be * dropped from the pool, or `NULL` */ #define MONGOC_DECL_SPECIAL_TS_POOL(ElementType, PoolName, UserDataType, Constructor, Destructor, PrunePredicate) \ typedef struct PoolName { \ mongoc_ts_pool *pool; \ } PoolName; \ \ BSON_MAYBE_UNUSED static BSON_INLINE PoolName PoolName##_new_with_params (_erased_constructor_fn constructor, \ _erased_destructor_fn destructor, \ _erased_prune_predicate prune_predicate, \ UserDataType *userdata) \ { \ PoolName ret; \ mongoc_ts_pool_params params = {0}; \ params.userdata = userdata; \ params.constructor = constructor; \ params.destructor = destructor; \ params.prune_predicate = prune_predicate; \ params.element_alignment = BSON_ALIGNOF (ElementType); \ params.element_size = sizeof (ElementType); \ ret.pool = mongoc_ts_pool_new (params); \ return ret; \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE PoolName PoolName##_new (UserDataType *userdata) \ { \ return PoolName##_new_with_params (Constructor, Destructor, PrunePredicate, userdata); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE void PoolName##_free (PoolName p) \ { \ mongoc_ts_pool_free (p.pool); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE void PoolName##_clear (PoolName p) \ { \ mongoc_ts_pool_clear (p.pool); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE ElementType *PoolName##_get_existing (PoolName p) \ { \ return (ElementType *) mongoc_ts_pool_get_existing (p.pool); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE ElementType *PoolName##_get (PoolName p, struct _bson_error_t *error) \ { \ return (ElementType *) mongoc_ts_pool_get (p.pool, error); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE void PoolName##_return (PoolName p, ElementType *elem) \ { \ mongoc_ts_pool_return (p.pool, elem); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE void PoolName##_drop (PoolName p, ElementType *elem) \ { \ mongoc_ts_pool_drop (p.pool, elem); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE size_t PoolName##_size (PoolName p) \ { \ return mongoc_ts_pool_size (p.pool); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE int PoolName##_is_empty (PoolName p) \ { \ return mongoc_ts_pool_is_empty (p.pool); \ } \ \ BSON_MAYBE_UNUSED static BSON_INLINE void PoolName##_visit_each ( \ PoolName p, void *visit_userdata, _erased_visit_fn visitor) \ { \ mongoc_ts_pool_visit_each (p.pool, visit_userdata, visitor); \ } #endif /* MONGOC_TS_POOL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-ts-pool.c0000644000175100001660000002406114760300420022532 0ustar #include #include #include #include /** * Toggle this to enable/disable checks that all items are returned to the pool * before the pool is destroyed */ static const bool audit_pool_enabled = false; /** * To support correct alignment of the item allocated within pool_node::data, * pool_node has the following data layout: * * [ next | owner_pool | (padding) | item ] * ^ ^ ^ * | | | * pool_node * | first byte of aligned item * pool_node::data * * If alignment of the item is not greater than the alignment of pool_node, * then pool_node::data already satisfies the alignment requirements and no * padding is necessary. The position of the allocated item should be obtained * via _pool_node_data_offset. */ typedef struct pool_node { struct pool_node *next; mongoc_ts_pool *owner_pool; unsigned char data[]; } pool_node; // Flexible member array member should not contribute to sizeof result. BSON_STATIC_ASSERT2 (pool_node_size, sizeof (pool_node) == sizeof (void *) * 2u); struct mongoc_ts_pool { mongoc_ts_pool_params params; pool_node *head; /* Number of elements in the pool */ int32_t size; bson_mutex_t mtx; /* Number of elements that the pool has given to users. * If audit_pool_enabled is zero, this member is unused */ int32_t outstanding_items; }; /** * @brief Return the offset of the item allocated within pool_node::data. */ static size_t _pool_node_data_offset (const mongoc_ts_pool *pool) { BSON_ASSERT_PARAM (pool); const size_t alignment = pool->params.element_alignment; // If element type has alignment greater than that of pool_node, position of // item within storage region must be offset accordingly. if (alignment > BSON_ALIGNOF (pool_node)) { return alignment - sizeof (pool_node); } return 0u; } /** * @brief Allocate a pool_node object with the appropriate flexible array member * length to accomodate the alignment and size of the element type. */ static pool_node * _pool_node_new (const mongoc_ts_pool *pool) { BSON_ASSERT_PARAM (pool); const size_t alignment = pool->params.element_alignment; const size_t size = pool->params.element_size; const size_t minimum_size = sizeof (pool_node) + _pool_node_data_offset (pool) + size; if (alignment == 0) { return bson_malloc0 (minimum_size); } // aligned_alloc requires allocation size to be a multiple of the alignment. const size_t required_size = minimum_size + (alignment - (minimum_size % alignment)); return bson_aligned_alloc0 (alignment, required_size); } /** * @brief Return a pointer to the item owned by the given node. */ static const void * _pool_node_get_data_const (const pool_node *node) { BSON_ASSERT_PARAM (node); return node->data + _pool_node_data_offset (node->owner_pool); } /** * @brief Return a pointer to the item owned by the given node. */ static void * _pool_node_get_data (pool_node *node) { BSON_ASSERT_PARAM (node); return node->data + _pool_node_data_offset (node->owner_pool); } /** * @brief Obtain a pointer to the pool_node that owns the given item. */ static pool_node * _pool_node_from_item (void *item, const mongoc_ts_pool *pool) { return (void *) (((unsigned char *) item) - _pool_node_data_offset (pool) - offsetof (pool_node, data)); } /** * @brief Check whether we should drop the given node from the pool */ static bool _should_prune (const pool_node *node) { mongoc_ts_pool *pool = node->owner_pool; return pool->params.prune_predicate && pool->params.prune_predicate (_pool_node_get_data_const (node), pool->params.userdata); } /** * @brief Create a new pool node and contained element. * * @return pool_node* A pointer to a constructed element, or NULL if the * constructor sets `error` */ static pool_node * _new_item (mongoc_ts_pool *pool, bson_error_t *error) { pool_node *node = _pool_node_new (pool); node->owner_pool = pool; if (pool->params.constructor) { /* To construct, we need to know if that constructor fails */ bson_error_t my_error; if (!error) { /* Caller doesn't care about the error, but we care in case the * constructor might fail */ error = &my_error; } /* Clear the error */ error->code = 0; error->domain = 0; error->message[0] = 0; /* Construct the object */ pool->params.constructor (_pool_node_get_data (node), pool->params.userdata, error); if (error->code != 0) { /* Constructor reported an error. Deallocate and drop the node. */ bson_free (node); node = NULL; } } if (node && audit_pool_enabled) { mcommon_atomic_int32_fetch_add (&pool->outstanding_items, 1, mcommon_memory_order_relaxed); } return node; } /** * @brief Destroy the given node and the element that it contains */ static void _delete_item (pool_node *node) { mongoc_ts_pool *pool = node->owner_pool; if (pool->params.destructor) { pool->params.destructor (_pool_node_get_data (node), pool->params.userdata); } bson_free (node); } /** * @brief Try to take a node from the pool. Returns `NULL` if the pool is empty. */ static pool_node * _try_get (mongoc_ts_pool *pool) { pool_node *node; bson_mutex_lock (&pool->mtx); node = pool->head; if (node) { pool->head = node->next; } bson_mutex_unlock (&pool->mtx); if (node) { mcommon_atomic_int32_fetch_sub (&pool->size, 1, mcommon_memory_order_relaxed); if (audit_pool_enabled) { mcommon_atomic_int32_fetch_add (&pool->outstanding_items, 1, mcommon_memory_order_relaxed); } } return node; } mongoc_ts_pool * mongoc_ts_pool_new (mongoc_ts_pool_params params) { mongoc_ts_pool *r = bson_malloc0 (sizeof (mongoc_ts_pool)); r->params = params; r->head = NULL; r->size = 0; if (audit_pool_enabled) { r->outstanding_items = 0; } bson_mutex_init (&r->mtx); // Promote alignment if it is too small to satisfy bson_aligned_alloc // requirements. { const size_t alignment = r->params.element_alignment; if (alignment != 0 && alignment < BSON_ALIGN_OF_PTR) { r->params.element_alignment = BSON_ALIGN_OF_PTR; } } return r; } void mongoc_ts_pool_free (mongoc_ts_pool *pool) { if (audit_pool_enabled) { BSON_ASSERT (pool->outstanding_items == 0 && "Pool was destroyed while there are still items checked out"); } mongoc_ts_pool_clear (pool); bson_mutex_destroy (&pool->mtx); bson_free (pool); } void mongoc_ts_pool_clear (mongoc_ts_pool *pool) { pool_node *node; { bson_mutex_lock (&pool->mtx); node = pool->head; pool->head = NULL; pool->size = 0; bson_mutex_unlock (&pool->mtx); } while (node) { pool_node *n = node; node = n->next; _delete_item (n); } } void * mongoc_ts_pool_get_existing (mongoc_ts_pool *pool) { pool_node *node; retry: node = _try_get (pool); if (node && _should_prune (node)) { /* This node should be pruned now. Drop it and try again. */ mongoc_ts_pool_drop (pool, _pool_node_get_data (node)); goto retry; } return node ? _pool_node_get_data (node) : NULL; } void * mongoc_ts_pool_get (mongoc_ts_pool *pool, bson_error_t *error) { pool_node *node; retry: node = _try_get (pool); if (node && _should_prune (node)) { /* This node should be pruned now. Drop it and try again. */ mongoc_ts_pool_drop (pool, _pool_node_get_data (node)); goto retry; } if (node == NULL) { /* We need a new item */ node = _new_item (pool, error); } if (node == NULL) { /* No item in pool, and we couldn't create one either */ return NULL; } return _pool_node_get_data (node); } void mongoc_ts_pool_return (mongoc_ts_pool *pool, void *item) { pool_node *node = _pool_node_from_item (item, pool); BSON_ASSERT (pool == node->owner_pool); if (_should_prune (node)) { mongoc_ts_pool_drop (pool, item); } else { bson_mutex_lock (&pool->mtx); node->next = pool->head; pool->head = node; bson_mutex_unlock (&pool->mtx); mcommon_atomic_int32_fetch_add (&node->owner_pool->size, 1, mcommon_memory_order_relaxed); if (audit_pool_enabled) { mcommon_atomic_int32_fetch_sub (&node->owner_pool->outstanding_items, 1, mcommon_memory_order_relaxed); } } } void mongoc_ts_pool_drop (mongoc_ts_pool *pool, void *item) { pool_node *node = _pool_node_from_item (item, pool); BSON_ASSERT (pool == node->owner_pool); if (audit_pool_enabled) { mcommon_atomic_int32_fetch_sub (&node->owner_pool->outstanding_items, 1, mcommon_memory_order_relaxed); } _delete_item (node); } int mongoc_ts_pool_is_empty (const mongoc_ts_pool *pool) { return mongoc_ts_pool_size (pool) == 0; } size_t mongoc_ts_pool_size (const mongoc_ts_pool *pool) { return mcommon_atomic_int32_fetch (&pool->size, mcommon_memory_order_relaxed); } void mongoc_ts_pool_visit_each (mongoc_ts_pool *pool, void *visit_userdata, int (*visit) (void *item, void *pool_userdata, void *visit_userdata)) { /* Pointer to the pointer that must be updated in case of an item pruning */ pool_node **node_ptrptr; /* The node we are looking at */ pool_node *node; bson_mutex_lock (&pool->mtx); node_ptrptr = &pool->head; node = pool->head; while (node) { const bool should_remove = visit (_pool_node_get_data (node), pool->params.userdata, visit_userdata); pool_node *const next_node = node->next; if (!should_remove) { node_ptrptr = &node->next; node = next_node; continue; } /* Retarget the previous pointer to the next node in line */ *node_ptrptr = node->next; _delete_item (node); pool->size--; /* Leave node_ptrptr pointing to the previous pointer, because we may * need to erase another item */ node = next_node; } bson_mutex_unlock (&pool->mtx); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-uri-private.h0000644000175100001660000000405414760300420023411 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_URI_PRIVATE_H #define MONGOC_URI_PRIVATE_H #include #include #include BSON_BEGIN_DECLS bool mongoc_uri_upsert_host_and_port (mongoc_uri_t *uri, const char *host_and_port, bson_error_t *error); bool mongoc_uri_upsert_host (mongoc_uri_t *uri, const char *host, uint16_t port, bson_error_t *error); void mongoc_uri_remove_host (mongoc_uri_t *uri, const char *host, uint16_t port); bool mongoc_uri_parse_host (mongoc_uri_t *uri, const char *str); bool mongoc_uri_parse_options (mongoc_uri_t *uri, const char *str, bool from_dns, bson_error_t *error); int32_t mongoc_uri_get_local_threshold_option (const mongoc_uri_t *uri); bool _mongoc_uri_requires_auth_negotiation (const mongoc_uri_t *uri); const char * mongoc_uri_canonicalize_option (const char *key); mongoc_uri_t * _mongoc_uri_copy_and_replace_host_list (const mongoc_uri_t *original, const char *host); bool mongoc_uri_init_with_srv_host_list (mongoc_uri_t *uri, mongoc_host_list_t *hosts, bson_error_t *error); bool mongoc_uri_validate_srv_result (const mongoc_uri_t *uri, const char *host, bson_error_t *error); #ifdef MONGOC_ENABLE_CRYPTO void _mongoc_uri_init_scram (const mongoc_uri_t *uri, mongoc_scram_t *scram, mongoc_crypto_hash_algorithm_t algo); #endif bool mongoc_uri_finalize (mongoc_uri_t *uri, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_URI_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-uri.c0000644000175100001660000027174414760300420021750 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include /* strcasecmp on windows */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct _mongoc_uri_t { char *str; bool is_srv; char srv[BSON_HOST_NAME_MAX + 1]; mongoc_host_list_t *hosts; char *username; char *password; char *database; bson_t raw; /* Unparsed options, see mongoc_uri_parse_options */ bson_t options; /* Type-coerced and canonicalized options */ bson_t credentials; bson_t compressors; mongoc_read_prefs_t *read_prefs; mongoc_read_concern_t *read_concern; mongoc_write_concern_t *write_concern; }; #define MONGOC_URI_ERROR(error, format, ...) \ bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, format, __VA_ARGS__) static const char *escape_instructions = "Percent-encode username and password" " according to RFC 3986"; static bool _mongoc_uri_set_option_as_int32 (mongoc_uri_t *uri, const char *option, int32_t value); static bool _mongoc_uri_set_option_as_int32_with_error (mongoc_uri_t *uri, const char *option, int32_t value, bson_error_t *error); static bool _mongoc_uri_set_option_as_int64_with_error (mongoc_uri_t *uri, const char *option, int64_t value, bson_error_t *error); static void mongoc_uri_do_unescape (char **str) { char *tmp; if ((tmp = *str)) { *str = mongoc_uri_unescape (tmp); bson_free (tmp); } } #define VALIDATE_SRV_ERR() \ do { \ bson_set_error (error, \ MONGOC_ERROR_STREAM, \ MONGOC_ERROR_STREAM_NAME_RESOLUTION, \ "Invalid host \"%s\" returned for service \"%s\": " \ "host must be subdomain of service name", \ host, \ srv_hostname); \ return false; \ } while (0) static int count_dots (const char *s) { int n = 0; const char *dot = s; while ((dot = strchr (dot + 1, '.'))) { n++; } return n; } static char * lowercase_str_new (const char *key) { char *ret = bson_strdup (key); mongoc_lowercase (key, ret); return ret; } /* at least one character, and does not start with dot */ static bool valid_hostname (const char *s) { size_t len = strlen (s); return len > 1 && s[0] != '.'; } bool mongoc_uri_validate_srv_result (const mongoc_uri_t *uri, const char *host, bson_error_t *error) { const char *srv_hostname; const char *srv_host; srv_hostname = mongoc_uri_get_srv_hostname (uri); BSON_ASSERT (srv_hostname); if (!valid_hostname (host)) { VALIDATE_SRV_ERR (); } srv_host = strchr (srv_hostname, '.'); BSON_ASSERT (srv_host); /* host must be descendent of service root: if service is * "a.foo.co" host can be like "a.foo.co", "b.foo.co", "a.b.foo.co", etc. */ if (strlen (host) < strlen (srv_host)) { VALIDATE_SRV_ERR (); } if (!mongoc_ends_with (host, srv_host)) { VALIDATE_SRV_ERR (); } return true; } /* copy and upsert @host into @uri's host list. */ static bool _upsert_into_host_list (mongoc_uri_t *uri, mongoc_host_list_t *host, bson_error_t *error) { if (uri->is_srv && !mongoc_uri_validate_srv_result (uri, host->host, error)) { return false; } _mongoc_host_list_upsert (&uri->hosts, host); return true; } bool mongoc_uri_upsert_host_and_port (mongoc_uri_t *uri, const char *host_and_port, bson_error_t *error) { mongoc_host_list_t temp; memset (&temp, 0, sizeof (mongoc_host_list_t)); if (!_mongoc_host_list_from_string_with_err (&temp, host_and_port, error)) { return false; } return _upsert_into_host_list (uri, &temp, error); } bool mongoc_uri_upsert_host (mongoc_uri_t *uri, const char *host, uint16_t port, bson_error_t *error) { mongoc_host_list_t temp; memset (&temp, 0, sizeof (mongoc_host_list_t)); if (!_mongoc_host_list_from_hostport_with_err (&temp, host, port, error)) { return false; } return _upsert_into_host_list (uri, &temp, error); } void mongoc_uri_remove_host (mongoc_uri_t *uri, const char *host, uint16_t port) { _mongoc_host_list_remove_host (&(uri->hosts), host, port); } /* *-------------------------------------------------------------------------- * * scan_to_unichar -- * * Scans 'str' until either a character matching 'match' is found, * until one of the characters in 'terminators' is encountered, or * until we reach the end of 'str'. * * NOTE: 'terminators' may not include multibyte UTF-8 characters. * * Returns: * If 'match' is found, returns a copy of the section of 'str' before * that character. Otherwise, returns NULL. * * Side Effects: * If 'match' is found, sets 'end' to begin at the matching character * in 'str'. * *-------------------------------------------------------------------------- */ static char * scan_to_unichar (const char *str, bson_unichar_t match, const char *terminators, const char **end) { bson_unichar_t c; const char *iter; for (iter = str; iter && *iter && (c = bson_utf8_get_char (iter)); iter = bson_utf8_next_char (iter)) { if (c == match) { *end = iter; return bson_strndup (str, iter - str); } else if (c == '\\') { iter = bson_utf8_next_char (iter); if (!bson_utf8_get_char (iter)) { break; } } else { const char *term_iter; for (term_iter = terminators; *term_iter; term_iter++) { if (c == *term_iter) { return NULL; } } } } return NULL; } static bool mongoc_uri_parse_scheme (mongoc_uri_t *uri, const char *str, const char **end) { if (!strncmp (str, "mongodb+srv://", 14)) { uri->is_srv = true; *end = str + 14; return true; } if (!strncmp (str, "mongodb://", 10)) { uri->is_srv = false; *end = str + 10; return true; } return false; } static bool mongoc_uri_has_unescaped_chars (const char *str, const char *chars) { const char *c; const char *tmp; char *s; for (c = chars; *c; c++) { s = scan_to_unichar (str, (bson_unichar_t) *c, "", &tmp); if (s) { bson_free (s); return true; } } return false; } /* "str" is non-NULL, the part of URI between "mongodb://" and first "@" */ static bool mongoc_uri_parse_userpass (mongoc_uri_t *uri, const char *str, bson_error_t *error) { const char *prohibited = "@:/"; const char *end_user; BSON_ASSERT (str); BSON_ASSERT (uri); if ((uri->username = scan_to_unichar (str, ':', "", &end_user))) { uri->password = bson_strdup (end_user + 1); } else { uri->username = bson_strdup (str); uri->password = NULL; } if (mongoc_uri_has_unescaped_chars (uri->username, prohibited)) { MONGOC_URI_ERROR (error, "Username \"%s\" must not have unescaped chars. %s", uri->username, escape_instructions); return false; } mongoc_uri_do_unescape (&uri->username); if (!uri->username) { MONGOC_URI_ERROR (error, "Incorrect URI escapes in username. %s", escape_instructions); return false; } /* Providing password at all is optional */ if (uri->password) { if (mongoc_uri_has_unescaped_chars (uri->password, prohibited)) { MONGOC_URI_ERROR ( error, "Password \"%s\" must not have unescaped chars. %s", uri->password, escape_instructions); return false; } mongoc_uri_do_unescape (&uri->password); if (!uri->password) { MONGOC_URI_ERROR (error, "%s", "Incorrect URI escapes in password"); return false; } } return true; } bool mongoc_uri_parse_host (mongoc_uri_t *uri, const char *host_and_port_in) { char *host_and_port = bson_strdup (host_and_port_in); bson_error_t err = {0}; bool r; /* unescape host. It doesn't hurt including port. */ if (mongoc_uri_has_unescaped_chars (host_and_port, "/")) { MONGOC_WARNING ("Unix Domain Sockets must be escaped (e.g. / = %%2F)"); bson_free (host_and_port); return false; } mongoc_uri_do_unescape (&host_and_port); if (!host_and_port) { /* invalid */ bson_free (host_and_port); return false; } r = mongoc_uri_upsert_host_and_port (uri, host_and_port, &err); if (!r) { MONGOC_ERROR ("%s", err.message); bson_free (host_and_port); return false; } bson_free (host_and_port); return true; } static bool mongoc_uri_parse_srv (mongoc_uri_t *uri, const char *str, bson_error_t *error) { if (*str == '\0') { MONGOC_URI_ERROR (error, "%s", "Missing service name in SRV URI"); return false; } { char *service = bson_strdup (str); mongoc_uri_do_unescape (&service); if (!service || !valid_hostname (service) || count_dots (service) < 2) { MONGOC_URI_ERROR (error, "%s", "Invalid service name in URI"); bson_free (service); return false; } bson_strncpy (uri->srv, service, sizeof uri->srv); bson_free (service); } if (strchr (uri->srv, ',')) { MONGOC_URI_ERROR (error, "%s", "Multiple service names are prohibited in an SRV URI"); return false; } if (strchr (uri->srv, ':')) { MONGOC_URI_ERROR (error, "%s", "Port numbers are prohibited in an SRV URI"); return false; } return true; } /* "hosts" is non-NULL, the part between "mongodb://" or "@" and last "/" */ static bool mongoc_uri_parse_hosts (mongoc_uri_t *uri, const char *hosts) { const char *next; const char *end_hostport; char *s; BSON_ASSERT (hosts); /* * Parsing the series of hosts is a lot more complicated than you might * imagine. This is due to some characters being both separators as well as * valid characters within the "hostname". In particularly, we can have file * paths to specify paths to UNIX domain sockets. We impose the restriction * that they must be suffixed with ".sock" to simplify the parsing. * * You can separate hosts and file system paths to UNIX domain sockets with * ",". */ s = scan_to_unichar (hosts, '?', "", &end_hostport); if (s) { MONGOC_WARNING ("%s", "A '/' is required between the host list and any options."); goto error; } next = hosts; do { /* makes a copy of the section of the string */ s = scan_to_unichar (next, ',', "", &end_hostport); if (s) { next = (char *) end_hostport + 1; } else { s = bson_strdup (next); next = NULL; } if (!mongoc_uri_parse_host (uri, s)) { goto error; } bson_free (s); } while (next); return true; error: bson_free (s); return false; } /* ----------------------------------------------------------------------------- * * mongoc_uri_parse_database -- * * Parse the database after @str. @str is expected to point after the * host list to the character immediately after the / in the uri string. * If no database is specified in the uri, e.g. the uri has a form like: * mongodb://localhost/?option=X then uri->database remains NULL after * parsing. * * Return: * True if the parsed database is valid. An empty database is considered * valid. * ----------------------------------------------------------------------------- */ static bool mongoc_uri_parse_database (mongoc_uri_t *uri, const char *str, const char **end) { const char *end_database; const char *c; char *invalid_c; const char *tmp; if ((uri->database = scan_to_unichar (str, '?', "", &end_database))) { if (strcmp (uri->database, "") == 0) { /* no database is found, don't store the empty string. */ bson_free (uri->database); uri->database = NULL; /* but it is valid to have an empty database. */ return true; } *end = end_database; } else if (*str) { uri->database = bson_strdup (str); *end = str + strlen (str); } mongoc_uri_do_unescape (&uri->database); if (!uri->database) { /* invalid */ return false; } /* invalid characters in database name */ for (c = "/\\. \"$"; *c; c++) { invalid_c = scan_to_unichar (uri->database, (bson_unichar_t) *c, "", &tmp); if (invalid_c) { bson_free (invalid_c); return false; } } return true; } static bool mongoc_uri_parse_auth_mechanism_properties (mongoc_uri_t *uri, const char *str) { char *field; char *value; const char *end_scan; bson_t properties; bson_init (&properties); /* build up the properties document */ while ((field = scan_to_unichar (str, ':', "&", &end_scan))) { str = end_scan + 1; if (!(value = scan_to_unichar (str, ',', ":&", &end_scan))) { value = bson_strdup (str); str = ""; } else { str = end_scan + 1; } bson_append_utf8 (&properties, field, -1, value, -1); bson_free (field); bson_free (value); } /* append our auth properties to our credentials */ if (!mongoc_uri_set_mechanism_properties (uri, &properties)) { bson_destroy (&properties); return false; } bson_destroy (&properties); return true; } static bool mongoc_uri_check_srv_service_name (mongoc_uri_t *uri, const char *str) { /* 63 character DNS query limit, excluding prepended underscore. */ const size_t mongoc_srv_service_name_max = 62u; size_t length = 0u; size_t num_alpha = 0u; size_t i = 0u; char prev = '\0'; BSON_ASSERT_PARAM (uri); BSON_ASSERT_PARAM (str); length = strlen (str); /* Initial DNS Seedlist Discovery Spec: This option specifies a valid SRV * service name according to RFC 6335, with the exception that it may exceed * 15 characters as long as the 63rd (62nd with prepended underscore) * character DNS query limit is not surpassed. */ if (length > mongoc_srv_service_name_max) { return false; } /* RFC 6335: MUST be at least 1 character. */ if (length == 0u) { return false; } for (i = 0u; i < length; ++i) { const char c = str[i]; /* RFC 6335: MUST contain only US-ASCII letters 'A' - 'Z' and 'a' - 'z', * digits '0' - '9', and hyphens ('-', ASCII 0x2D or decimal 45). */ if (!isalpha (c) && !isdigit (c) && c != '-') { return false; } /* RFC 6335: hyphens MUST NOT be adjacent to other hyphens. */ if (c == '-' && prev == '-') { return false; } num_alpha += isalpha (c) ? 1u : 0u; prev = c; } /* RFC 6335: MUST contain at least one letter ('A' - 'Z' or 'a' - 'z') */ if (num_alpha == 0u) { return false; } /* RFC 6335: MUST NOT begin or end with a hyphen. */ if (str[0] == '-' || str[length - 1u] == '-') { return false; } return true; } static bool mongoc_uri_parse_tags (mongoc_uri_t *uri, /* IN */ const char *str) /* IN */ { const char *end_keyval; const char *end_key; bson_t b; char *keyval; char *key; bson_init (&b); again: if ((keyval = scan_to_unichar (str, ',', "", &end_keyval))) { if (!(key = scan_to_unichar (keyval, ':', "", &end_key))) { bson_free (keyval); goto fail; } bson_append_utf8 (&b, key, -1, end_key + 1, -1); bson_free (key); bson_free (keyval); str = end_keyval + 1; goto again; } else if ((key = scan_to_unichar (str, ':', "", &end_key))) { bson_append_utf8 (&b, key, -1, end_key + 1, -1); bson_free (key); } else if (strlen (str)) { /* we're not finished but we couldn't parse the string */ goto fail; } mongoc_read_prefs_add_tag (uri->read_prefs, &b); bson_destroy (&b); return true; fail: MONGOC_WARNING ("Unsupported value for \"" MONGOC_URI_READPREFERENCETAGS "\": \"%s\"", str); bson_destroy (&b); return false; } /* *-------------------------------------------------------------------------- * * mongoc_uri_bson_append_or_replace_key -- * * * Appends 'option' to the end of 'options' if not already set. * * Since we cannot grow utf8 strings inline, we have to allocate a * temporary bson variable and splice in the new value if the key * is already set. * * NOTE: This function keeps the order of the BSON keys. * * NOTE: 'option' is case*in*sensitive. * * *-------------------------------------------------------------------------- */ static void mongoc_uri_bson_append_or_replace_key (bson_t *options, const char *option, const char *value) { bson_iter_t iter; bool found = false; if (bson_iter_init (&iter, options)) { bson_t tmp = BSON_INITIALIZER; while (bson_iter_next (&iter)) { const bson_value_t *bvalue; if (!strcasecmp (bson_iter_key (&iter), option)) { bson_append_utf8 (&tmp, option, -1, value, -1); found = true; continue; } bvalue = bson_iter_value (&iter); BSON_APPEND_VALUE (&tmp, bson_iter_key (&iter), bvalue); } if (!found) { bson_append_utf8 (&tmp, option, -1, value, -1); } bson_destroy (options); bson_copy_to (&tmp, options); bson_destroy (&tmp); } } bool mongoc_uri_has_option (const mongoc_uri_t *uri, const char *key) { bson_iter_t iter; return bson_iter_init_find_case (&iter, &uri->options, key); } bool mongoc_uri_option_is_int32 (const char *key) { return mongoc_uri_option_is_int64 (key) || !strcasecmp (key, MONGOC_URI_CONNECTTIMEOUTMS) || !strcasecmp (key, MONGOC_URI_HEARTBEATFREQUENCYMS) || !strcasecmp (key, MONGOC_URI_SERVERSELECTIONTIMEOUTMS) || !strcasecmp (key, MONGOC_URI_SOCKETCHECKINTERVALMS) || !strcasecmp (key, MONGOC_URI_SOCKETTIMEOUTMS) || !strcasecmp (key, MONGOC_URI_LOCALTHRESHOLDMS) || !strcasecmp (key, MONGOC_URI_MAXPOOLSIZE) || !strcasecmp (key, MONGOC_URI_MAXSTALENESSSECONDS) || !strcasecmp (key, MONGOC_URI_MINPOOLSIZE) || !strcasecmp (key, MONGOC_URI_WAITQUEUETIMEOUTMS) || !strcasecmp (key, MONGOC_URI_ZLIBCOMPRESSIONLEVEL) || !strcasecmp (key, MONGOC_URI_SRVMAXHOSTS); /* Not including deprecated unimplemented options: * - MONGOC_URI_MAXIDLETIMEMS * - MONGOC_URI_WAITQUEUEMULTIPLE */ } bool mongoc_uri_option_is_int64 (const char *key) { return !strcasecmp (key, MONGOC_URI_WTIMEOUTMS); } bool mongoc_uri_option_is_bool (const char *key) { return !strcasecmp (key, MONGOC_URI_CANONICALIZEHOSTNAME) || !strcasecmp (key, MONGOC_URI_DIRECTCONNECTION) || !strcasecmp (key, MONGOC_URI_JOURNAL) || !strcasecmp (key, MONGOC_URI_RETRYREADS) || !strcasecmp (key, MONGOC_URI_RETRYWRITES) || !strcasecmp (key, MONGOC_URI_SAFE) || !strcasecmp (key, MONGOC_URI_SERVERSELECTIONTRYONCE) || !strcasecmp (key, MONGOC_URI_TLS) || !strcasecmp (key, MONGOC_URI_TLSINSECURE) || !strcasecmp (key, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES) || !strcasecmp (key, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES) || !strcasecmp (key, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK) || !strcasecmp (key, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK) || !strcasecmp (key, MONGOC_URI_LOADBALANCED) || /* deprecated options with canonical equivalents */ !strcasecmp (key, MONGOC_URI_SSL) || !strcasecmp (key, MONGOC_URI_SSLALLOWINVALIDCERTIFICATES) || !strcasecmp (key, MONGOC_URI_SSLALLOWINVALIDHOSTNAMES); } bool mongoc_uri_option_is_utf8 (const char *key) { return !strcasecmp (key, MONGOC_URI_APPNAME) || !strcasecmp (key, MONGOC_URI_REPLICASET) || !strcasecmp (key, MONGOC_URI_READPREFERENCE) || !strcasecmp (key, MONGOC_URI_SERVERMONITORINGMODE) || !strcasecmp (key, MONGOC_URI_SRVSERVICENAME) || !strcasecmp (key, MONGOC_URI_TLSCERTIFICATEKEYFILE) || !strcasecmp (key, MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD) || !strcasecmp (key, MONGOC_URI_TLSCAFILE) || /* deprecated options with canonical equivalents */ !strcasecmp (key, MONGOC_URI_SSLCLIENTCERTIFICATEKEYFILE) || !strcasecmp (key, MONGOC_URI_SSLCLIENTCERTIFICATEKEYPASSWORD) || !strcasecmp (key, MONGOC_URI_SSLCERTIFICATEAUTHORITYFILE); } const char * mongoc_uri_canonicalize_option (const char *key) { if (!strcasecmp (key, MONGOC_URI_SSL)) { return MONGOC_URI_TLS; } else if (!strcasecmp (key, MONGOC_URI_SSLCLIENTCERTIFICATEKEYFILE)) { return MONGOC_URI_TLSCERTIFICATEKEYFILE; } else if (!strcasecmp (key, MONGOC_URI_SSLCLIENTCERTIFICATEKEYPASSWORD)) { return MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD; } else if (!strcasecmp (key, MONGOC_URI_SSLCERTIFICATEAUTHORITYFILE)) { return MONGOC_URI_TLSCAFILE; } else if (!strcasecmp (key, MONGOC_URI_SSLALLOWINVALIDCERTIFICATES)) { return MONGOC_URI_TLSALLOWINVALIDCERTIFICATES; } else if (!strcasecmp (key, MONGOC_URI_SSLALLOWINVALIDHOSTNAMES)) { return MONGOC_URI_TLSALLOWINVALIDHOSTNAMES; } else { return key; } } static bool _mongoc_uri_parse_int64 (const char *key, const char *value, int64_t *result) { char *endptr; int64_t i; errno = 0; i = bson_ascii_strtoll (value, &endptr, 10); if (errno || endptr < value + strlen (value)) { MONGOC_WARNING ("Invalid %s: cannot parse integer\n", key); return false; } *result = i; return true; } static bool mongoc_uri_parse_int32 (const char *key, const char *value, int32_t *result) { int64_t i; if (!_mongoc_uri_parse_int64 (key, value, &i)) { /* _mongoc_uri_parse_int64 emits a warning if it could not parse the * given value, so we don't have to add one here. */ return false; } if (i > INT32_MAX || i < INT32_MIN) { MONGOC_WARNING ("Invalid %s: cannot fit in int32\n", key); return false; } *result = (int32_t) i; return true; } static bool dns_option_allowed (const char *lkey) { /* Initial DNS Seedlist Discovery Spec: "A Client MUST only support the * authSource, replicaSet, and loadBalanced options through a TXT record, and * MUST raise an error if any other option is encountered." */ return !strcmp (lkey, MONGOC_URI_AUTHSOURCE) || !strcmp (lkey, MONGOC_URI_REPLICASET) || !strcmp (lkey, MONGOC_URI_LOADBALANCED); } /* Decompose a key=val pair and place them into a document. * Includes case-folding for key portion. */ static bool mongoc_uri_split_option (mongoc_uri_t *uri, bson_t *options, const char *str, bool from_dns, bson_error_t *error) { bson_iter_t iter; const char *end_key; char *key = NULL; char *lkey = NULL; char *value = NULL; const char *opt; char *opt_end; size_t opt_len; bool ret = false; if (!(key = scan_to_unichar (str, '=', "", &end_key))) { MONGOC_URI_ERROR (error, "URI option \"%s\" contains no \"=\" sign", str); goto CLEANUP; } value = bson_strdup (end_key + 1); mongoc_uri_do_unescape (&value); if (!value) { /* do_unescape detected invalid UTF-8 and freed value */ MONGOC_URI_ERROR (error, "Value for URI option \"%s\" contains invalid UTF-8", key); goto CLEANUP; } lkey = bson_strdup (key); mongoc_lowercase (key, lkey); /* Initial DNS Seedlist Discovery Spec: "A Client MUST only support the * authSource, replicaSet, and loadBalanced options through a TXT record, and * MUST raise an error if any other option is encountered."*/ if (from_dns && !dns_option_allowed (lkey)) { MONGOC_URI_ERROR (error, "URI option \"%s\" prohibited in TXT record", key); goto CLEANUP; } /* Special case: READPREFERENCETAGS is a composing option. * Multiple instances should append, not overwrite. * Encode them directly to the options field, * bypassing canonicalization and duplicate checks. */ if (!strcmp (lkey, MONGOC_URI_READPREFERENCETAGS)) { if (!mongoc_uri_parse_tags (uri, value)) { MONGOC_URI_ERROR (error, "Unsupported value for \"%s\": \"%s\"", key, value); goto CLEANUP; } } else if (bson_iter_init_find (&iter, &uri->raw, lkey) || bson_iter_init_find (&iter, options, lkey)) { /* Special case, MONGOC_URI_W == "any non-int" is not overridden * by later values. */ if (!strcmp (lkey, MONGOC_URI_W) && (opt = bson_iter_utf8_unsafe (&iter, &opt_len))) { strtol (opt, &opt_end, 10); if (*opt_end != '\0') { ret = true; goto CLEANUP; } } /* Initial DNS Seedlist Discovery Spec: "Client MUST use options * specified in the Connection String to override options provided * through TXT records." So, do NOT override existing options with TXT * options. */ if (from_dns) { if (0 == strcmp (lkey, MONGOC_URI_AUTHSOURCE)) { // Treat `authSource` as a special case. A server may support authentication with multiple mechanisms. // MONGODB-X509 requires authSource=$external. SCRAM-SHA-256 requires authSource=admin. // Only log a trace message since this may be expected. TRACE ("Ignoring URI option \"%s\" from TXT record \"%s\". Option is already present in URI", key, str); } else { MONGOC_WARNING ( "Ignoring URI option \"%s\" from TXT record \"%s\". Option is already present in URI", key, str); } ret = true; goto CLEANUP; } MONGOC_WARNING ("Overwriting previously provided value for '%s'", key); } if (!(strcmp (lkey, MONGOC_URI_REPLICASET)) && *value == '\0') { MONGOC_URI_ERROR (error, "Value for URI option \"%s\" cannot be empty string", lkey); goto CLEANUP; } mongoc_uri_bson_append_or_replace_key (options, lkey, value); ret = true; CLEANUP: bson_free (key); bson_free (lkey); bson_free (value); return ret; } /* Check for canonical/deprecated conflicts * between the option list a, and b. * If both names exist either way with differing values, error. */ static bool mongoc_uri_options_validate_names (const bson_t *a, const bson_t *b, bson_error_t *error) { bson_iter_t key_iter, canon_iter; const char *key = NULL; const char *canon = NULL; const char *value = NULL; const char *cval = NULL; size_t value_len = 0; size_t cval_len = 0; /* Scan `a` looking for deprecated names * where the canonical name was also used in `a`, * or was used in `b`. */ bson_iter_init (&key_iter, a); while (bson_iter_next (&key_iter)) { key = bson_iter_key (&key_iter); value = bson_iter_utf8_unsafe (&key_iter, &value_len); canon = mongoc_uri_canonicalize_option (key); if (key == canon) { /* Canonical form, no point checking `b`. */ continue; } /* Check for a conflict in `a`. */ if (bson_iter_init_find (&canon_iter, a, canon)) { cval = bson_iter_utf8_unsafe (&canon_iter, &cval_len); if ((value_len != cval_len) || strcmp (value, cval)) { goto HANDLE_CONFLICT; } } /* Check for a conflict in `b`. */ if (bson_iter_init_find (&canon_iter, b, canon)) { cval = bson_iter_utf8_unsafe (&canon_iter, &cval_len); if ((value_len != cval_len) || strcmp (value, cval)) { goto HANDLE_CONFLICT; } } } return true; HANDLE_CONFLICT: MONGOC_URI_ERROR (error, "Deprecated option '%s=%s' conflicts with " "canonical name '%s=%s'", key, value, canon, cval); return false; } #define HANDLE_DUPE() \ if (from_dns) { \ MONGOC_WARNING ("Cannot override URI option \"%s\" from TXT record", key); \ continue; \ } else if (1) { \ MONGOC_WARNING ("Overwriting previously provided value for '%s'", key); \ } else \ (void) 0 static bool mongoc_uri_apply_options (mongoc_uri_t *uri, const bson_t *options, bool from_dns, bson_error_t *error) { bson_iter_t iter; int32_t v_int; int64_t v_int64; const char *key = NULL; const char *canon = NULL; const char *value = NULL; size_t value_len; bool bval; bson_iter_init (&iter, options); while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); canon = mongoc_uri_canonicalize_option (key); value = bson_iter_utf8_unsafe (&iter, &value_len); /* Keep a record of how the option was originally presented. */ mongoc_uri_bson_append_or_replace_key (&uri->raw, key, value); /* This check precedes mongoc_uri_option_is_int32 as all 64-bit values are * also recognised as 32-bit ints. */ if (mongoc_uri_option_is_int64 (key)) { if (0 < strlen (value)) { if (!_mongoc_uri_parse_int64 (key, value, &v_int64)) { goto UNSUPPORTED_VALUE; } if (!_mongoc_uri_set_option_as_int64_with_error (uri, canon, v_int64, error)) { return false; } } else { MONGOC_WARNING ("Empty value provided for \"%s\"", key); } } else if (mongoc_uri_option_is_int32 (key)) { if (0 < strlen (value)) { if (!mongoc_uri_parse_int32 (key, value, &v_int)) { goto UNSUPPORTED_VALUE; } if (!_mongoc_uri_set_option_as_int32_with_error (uri, canon, v_int, error)) { return false; } } else { MONGOC_WARNING ("Empty value provided for \"%s\"", key); } } else if (!strcmp (key, MONGOC_URI_W)) { if (*value == '-' || isdigit (*value)) { v_int = (int) strtol (value, NULL, 10); _mongoc_uri_set_option_as_int32 (uri, MONGOC_URI_W, v_int); } else if (0 == strcasecmp (value, "majority")) { mongoc_uri_bson_append_or_replace_key (&uri->options, MONGOC_URI_W, "majority"); } else if (*value) { mongoc_uri_bson_append_or_replace_key (&uri->options, MONGOC_URI_W, value); } } else if (mongoc_uri_option_is_bool (key)) { if (0 < strlen (value)) { if (0 == strcasecmp (value, "true")) { bval = true; } else if (0 == strcasecmp (value, "false")) { bval = false; } else if ((0 == strcmp (value, "1")) || (0 == strcasecmp (value, "yes")) || (0 == strcasecmp (value, "y")) || (0 == strcasecmp (value, "t"))) { MONGOC_WARNING ("Deprecated boolean value for \"%s\": \"%s\", " "please update to \"%s=true\"", key, value, key); bval = true; } else if ((0 == strcasecmp (value, "0")) || (0 == strcasecmp (value, "-1")) || (0 == strcmp (value, "no")) || (0 == strcmp (value, "n")) || (0 == strcmp (value, "f"))) { MONGOC_WARNING ("Deprecated boolean value for \"%s\": \"%s\", " "please update to \"%s=false\"", key, value, key); bval = false; } else { goto UNSUPPORTED_VALUE; } if (!mongoc_uri_set_option_as_bool (uri, canon, bval)) { bson_set_error ( error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Failed to set %s to %d", canon, bval); return false; } } else { MONGOC_WARNING ("Empty value provided for \"%s\"", key); } } else if (!strcmp (key, MONGOC_URI_READPREFERENCETAGS)) { /* Skip this option here. * It was marshalled during mongoc_uri_split_option() * as a special case composing option. */ } else if (!strcmp (key, MONGOC_URI_AUTHMECHANISM) || !strcmp (key, MONGOC_URI_AUTHSOURCE)) { if (bson_has_field (&uri->credentials, key)) { HANDLE_DUPE (); } mongoc_uri_bson_append_or_replace_key (&uri->credentials, canon, value); } else if (!strcmp (key, MONGOC_URI_READCONCERNLEVEL)) { if (!mongoc_read_concern_is_default (uri->read_concern)) { HANDLE_DUPE (); } mongoc_read_concern_set_level (uri->read_concern, value); } else if (!strcmp (key, MONGOC_URI_GSSAPISERVICENAME)) { char *tmp = bson_strdup_printf ("SERVICE_NAME:%s", value); if (bson_has_field (&uri->credentials, MONGOC_URI_AUTHMECHANISMPROPERTIES)) { MONGOC_WARNING ("authMechanismProperties SERVICE_NAME already set, " "ignoring '%s'", key); } else if (!mongoc_uri_parse_auth_mechanism_properties (uri, tmp)) { bson_free (tmp); goto UNSUPPORTED_VALUE; } bson_free (tmp); } else if (!strcmp (key, MONGOC_URI_SRVSERVICENAME)) { if (!mongoc_uri_check_srv_service_name (uri, value)) { goto UNSUPPORTED_VALUE; } mongoc_uri_bson_append_or_replace_key (&uri->options, canon, value); } else if (!strcmp (key, MONGOC_URI_AUTHMECHANISMPROPERTIES)) { if (bson_has_field (&uri->credentials, key)) { HANDLE_DUPE (); } if (!mongoc_uri_parse_auth_mechanism_properties (uri, value)) { goto UNSUPPORTED_VALUE; } } else if (!strcmp (key, MONGOC_URI_APPNAME)) { /* Part of uri->options */ if (!mongoc_uri_set_appname (uri, value)) { goto UNSUPPORTED_VALUE; } } else if (!strcmp (key, MONGOC_URI_COMPRESSORS)) { if (!bson_empty (mongoc_uri_get_compressors (uri))) { HANDLE_DUPE (); } if (!mongoc_uri_set_compressors (uri, value)) { goto UNSUPPORTED_VALUE; } } else if (!strcmp (key, MONGOC_URI_SERVERMONITORINGMODE)) { if (!mongoc_uri_set_server_monitoring_mode (uri, value)) { goto UNSUPPORTED_VALUE; } } else if (mongoc_uri_option_is_utf8 (key)) { mongoc_uri_bson_append_or_replace_key (&uri->options, canon, value); } else { /* * Keys that aren't supported by a driver MUST be ignored. * * A WARN level logging message MUST be issued * https://github.com/mongodb/specifications/blob/master/source/connection-string/connection-string-spec.md#keys */ MONGOC_WARNING ("Unsupported URI option \"%s\"", key); } } return true; UNSUPPORTED_VALUE: MONGOC_URI_ERROR (error, "Unsupported value for \"%s\": \"%s\"", key, value); return false; } /* Processes a query string formatted set of driver options * (i.e. tls=true&connectTimeoutMS=250 ) into a BSON dict of values. * uri->raw is initially populated with the raw split of key/value pairs, * then the keys are canonicalized and the values coerced * to their appropriate type and stored in uri->options. */ bool mongoc_uri_parse_options (mongoc_uri_t *uri, const char *str, bool from_dns, bson_error_t *error) { bson_t options; const char *end_option; char *option; bson_init (&options); while ((option = scan_to_unichar (str, '&', "", &end_option))) { if (!mongoc_uri_split_option (uri, &options, option, from_dns, error)) { bson_free (option); bson_destroy (&options); return false; } bson_free (option); str = end_option + 1; } if (*str && !mongoc_uri_split_option (uri, &options, str, from_dns, error)) { bson_destroy (&options); return false; } /* Walk both sides of this map to handle each ordering: * deprecated first canonical later, and vice-versa. * Then finalize parse by writing final values to uri->options. */ if (!mongoc_uri_options_validate_names (&uri->options, &options, error) || !mongoc_uri_options_validate_names (&options, &uri->options, error) || !mongoc_uri_apply_options (uri, &options, from_dns, error)) { bson_destroy (&options); return false; } bson_destroy (&options); return true; } static bool mongoc_uri_finalize_tls (mongoc_uri_t *uri, bson_error_t *error) { /* Initial DNS Seedlist Discovery Spec: "If mongodb+srv is used, a driver * MUST implicitly also enable TLS." */ if (uri->is_srv && !bson_has_field (&uri->options, MONGOC_URI_TLS)) { mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true); } /* tlsInsecure implies tlsAllowInvalidCertificates, tlsAllowInvalidHostnames, * tlsDisableOCSPEndpointCheck, and tlsDisableCertificateRevocationCheck, so * consider it an error to have both. The user might have the wrong idea. */ if (bson_has_field (&uri->options, MONGOC_URI_TLSINSECURE) && (bson_has_field (&uri->options, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES) || bson_has_field (&uri->options, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES) || bson_has_field (&uri->options, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK) || bson_has_field (&uri->options, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK))) { MONGOC_URI_ERROR (error, "%s may not be specified with %s, %s, %s, or %s", MONGOC_URI_TLSINSECURE, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK); return false; } /* tlsAllowInvalidCertificates implies tlsDisableOCSPEndpointCheck and * tlsDisableCertificateRevocationCheck, so consider it an error to have * both. The user might have the wrong idea. */ if (bson_has_field (&uri->options, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES) && (bson_has_field (&uri->options, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK) || bson_has_field (&uri->options, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK))) { MONGOC_URI_ERROR (error, "%s may not be specified with %s or %s", MONGOC_URI_TLSALLOWINVALIDCERTIFICATES, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK); return false; } /* tlsDisableCertificateRevocationCheck implies tlsDisableOCSPEndpointCheck, * so consider it an error to have both. The user might have the wrong idea. */ if (bson_has_field (&uri->options, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK) && bson_has_field (&uri->options, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK)) { MONGOC_URI_ERROR (error, "%s may not be specified with %s", MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK); return false; } return true; } static bool mongoc_uri_finalize_auth (mongoc_uri_t *uri, bson_error_t *error) { bson_iter_t iter; const char *source = NULL; const bool require_auth = uri->username != NULL; if (bson_iter_init_find_case (&iter, &uri->credentials, MONGOC_URI_AUTHSOURCE)) { source = bson_iter_utf8 (&iter, NULL); } if (mongoc_uri_get_auth_mechanism (uri)) { /* authSource with GSSAPI or X509 should always be external */ if (!strcasecmp (mongoc_uri_get_auth_mechanism (uri), "GSSAPI") || !strcasecmp (mongoc_uri_get_auth_mechanism (uri), "MONGODB-X509")) { if (source) { if (strcasecmp (source, "$external")) { MONGOC_URI_ERROR (error, "%s", "GSSAPI and X509 require \"$external\" authSource"); return false; } } else { bson_append_utf8 (&uri->credentials, MONGOC_URI_AUTHSOURCE, -1, "$external", -1); } } /* MONGODB-X509 and MONGODB-AWS are the only mechanisms that don't require * username */ if (!(strcasecmp (mongoc_uri_get_auth_mechanism (uri), "MONGODB-X509") == 0 || strcasecmp (mongoc_uri_get_auth_mechanism (uri), "MONGODB-AWS") == 0)) { if (!mongoc_uri_get_username (uri) || strcmp (mongoc_uri_get_username (uri), "") == 0) { MONGOC_URI_ERROR ( error, "'%s' authentication mechanism requires username", mongoc_uri_get_auth_mechanism (uri)); return false; } } /* MONGODB-X509 errors if a password is supplied. */ if (strcasecmp (mongoc_uri_get_auth_mechanism (uri), "MONGODB-X509") == 0) { if (mongoc_uri_get_password (uri)) { MONGOC_URI_ERROR ( error, "'%s' authentication mechanism does not accept a password", mongoc_uri_get_auth_mechanism (uri)); return false; } } /* GSSAPI uses 'mongodb' as the default service name */ if (strcasecmp (mongoc_uri_get_auth_mechanism (uri), "GSSAPI") == 0 && !(bson_iter_init_find (&iter, &uri->credentials, MONGOC_URI_AUTHMECHANISMPROPERTIES) && BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &iter) && bson_iter_find_case (&iter, "SERVICE_NAME"))) { bson_t tmp; bson_t *props = NULL; props = mongoc_uri_get_mechanism_properties (uri, &tmp) ? bson_copy (&tmp) : bson_new (); BSON_APPEND_UTF8 (props, "SERVICE_NAME", "mongodb"); mongoc_uri_set_mechanism_properties (uri, props); bson_destroy (props); } } else if (require_auth) /* Default auth mechanism is used */ { if (!mongoc_uri_get_username (uri) || strcmp (mongoc_uri_get_username (uri), "") == 0) { MONGOC_URI_ERROR (error, "%s", "Default authentication mechanism requires username"); return false; } } return true; } static bool mongoc_uri_finalize_directconnection (mongoc_uri_t *uri, bson_error_t *error) { bool directconnection = false; directconnection = mongoc_uri_get_option_as_bool (uri, MONGOC_URI_DIRECTCONNECTION, false); if (!directconnection) { return true; } /* URI options spec: "The driver MUST report an error if the * directConnection=true URI option is specified with an SRV URI, because * the URI may resolve to multiple hosts. The driver MUST allow specifying * directConnection=false URI option with an SRV URI." */ if (uri->is_srv) { MONGOC_URI_ERROR (error, "%s", "SRV URI not allowed with directConnection option"); return false; } /* URI options spec: "The driver MUST report an error if the * directConnection=true URI option is specified with multiple seeds." */ if (uri->hosts && uri->hosts->next) { MONGOC_URI_ERROR (error, "%s", "Multiple seeds not allowed with directConnection option"); return false; } return true; } static bool mongoc_uri_parse_before_slash (mongoc_uri_t *uri, const char *before_slash, bson_error_t *error) { char *userpass; const char *hosts; userpass = scan_to_unichar (before_slash, '@', "", &hosts); if (userpass) { if (!mongoc_uri_parse_userpass (uri, userpass, error)) { goto error; } hosts++; /* advance past "@" */ if (*hosts == '@') { /* special case: "mongodb://alice@@localhost" */ MONGOC_URI_ERROR (error, "Invalid username or password. %s", escape_instructions); goto error; } } else { hosts = before_slash; } if (uri->is_srv) { if (!mongoc_uri_parse_srv (uri, hosts, error)) { goto error; } } else { if (!mongoc_uri_parse_hosts (uri, hosts)) { MONGOC_URI_ERROR (error, "%s", "Invalid host string in URI"); goto error; } } bson_free (userpass); return true; error: bson_free (userpass); return false; } static bool mongoc_uri_parse (mongoc_uri_t *uri, const char *str, bson_error_t *error) { BSON_ASSERT_PARAM (str); char *before_slash = NULL; const char *tmp; if (!bson_utf8_validate (str, strlen (str), false /* allow_null */)) { MONGOC_URI_ERROR (error, "%s", "Invalid UTF-8 in URI"); goto error; } if (!mongoc_uri_parse_scheme (uri, str, &str)) { MONGOC_URI_ERROR (error, "%s", "Invalid URI Schema, expecting 'mongodb://' or 'mongodb+srv://'"); goto error; } before_slash = scan_to_unichar (str, '/', "", &tmp); if (!before_slash) { // Handle cases of optional delimiting slash char *userpass = NULL; char *hosts = NULL; // Skip any "?"s that exist in the userpass userpass = scan_to_unichar (str, '@', "", &tmp); if (!userpass) { // If none found, safely check for "?" indicating beginning of options before_slash = scan_to_unichar (str, '?', "", &tmp); } else { const size_t userpass_len = (size_t) (tmp - str); // Otherwise, see if options exist after userpass and concatenate result hosts = scan_to_unichar (tmp, '?', "", &tmp); if (hosts) { const size_t hosts_len = (size_t) (tmp - str) - userpass_len; before_slash = bson_strndup (str, userpass_len + hosts_len); } } bson_free (userpass); bson_free (hosts); } if (!before_slash) { before_slash = bson_strdup (str); str += strlen (before_slash); } else { str = tmp; } if (!mongoc_uri_parse_before_slash (uri, before_slash, error)) { goto error; } BSON_ASSERT (str); if (*str) { // Check for valid end of hostname delimeter (skip slash if necessary) if (*str != '/' && *str != '?') { MONGOC_URI_ERROR (error, "%s", "Expected end of hostname delimiter"); goto error; } if (*str == '/') { // Try to parse database. str++; if (*str) { if (!mongoc_uri_parse_database (uri, str, &str)) { MONGOC_URI_ERROR (error, "%s", "Invalid database name in URI"); goto error; } } } if (*str == '?') { // Try to parse options. str++; if (*str) { if (!mongoc_uri_parse_options (uri, str, false /* from DNS */, error)) { goto error; } } } } if (!mongoc_uri_finalize (uri, error)) { goto error; } bson_free (before_slash); return true; error: bson_free (before_slash); return false; } const mongoc_host_list_t * mongoc_uri_get_hosts (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->hosts; } const char * mongoc_uri_get_replica_set (const mongoc_uri_t *uri) { bson_iter_t iter; BSON_ASSERT (uri); if (bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_REPLICASET) && BSON_ITER_HOLDS_UTF8 (&iter)) { return bson_iter_utf8 (&iter, NULL); } return NULL; } const bson_t * mongoc_uri_get_credentials (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return &uri->credentials; } const char * mongoc_uri_get_auth_mechanism (const mongoc_uri_t *uri) { bson_iter_t iter; BSON_ASSERT (uri); if (bson_iter_init_find_case (&iter, &uri->credentials, MONGOC_URI_AUTHMECHANISM) && BSON_ITER_HOLDS_UTF8 (&iter)) { return bson_iter_utf8 (&iter, NULL); } return NULL; } bool mongoc_uri_set_auth_mechanism (mongoc_uri_t *uri, const char *value) { size_t len; BSON_ASSERT (value); len = strlen (value); if (!bson_utf8_validate (value, len, false)) { return false; } mongoc_uri_bson_append_or_replace_key (&uri->credentials, MONGOC_URI_AUTHMECHANISM, value); return true; } bool mongoc_uri_get_mechanism_properties (const mongoc_uri_t *uri, bson_t *properties /* OUT */) { bson_iter_t iter; BSON_ASSERT (uri); BSON_ASSERT (properties); if (bson_iter_init_find_case (&iter, &uri->credentials, MONGOC_URI_AUTHMECHANISMPROPERTIES) && BSON_ITER_HOLDS_DOCUMENT (&iter)) { uint32_t len = 0; const uint8_t *data = NULL; bson_iter_document (&iter, &len, &data); BSON_ASSERT (bson_init_static (properties, data, len)); return true; } return false; } bool mongoc_uri_set_mechanism_properties (mongoc_uri_t *uri, const bson_t *properties) { BSON_ASSERT (uri); BSON_ASSERT (properties); bson_t tmp = BSON_INITIALIZER; bsonBuildAppend (tmp, // Copy the existing credentials, dropping the existing properties if // present insert (uri->credentials, not(key (MONGOC_URI_AUTHMECHANISMPROPERTIES))), // Append the new properties kv (MONGOC_URI_AUTHMECHANISMPROPERTIES, bson (*properties))); bson_reinit (&uri->credentials); bsonBuildAppend (uri->credentials, insert (tmp, true)); bson_destroy (&tmp); return bsonBuildError == NULL; } static bool _mongoc_uri_assign_read_prefs_mode (mongoc_uri_t *uri, bson_error_t *error) { BSON_ASSERT (uri); mongoc_read_mode_t mode = 0; const char *pref = NULL; bsonParse (uri->options, find ( // Find the 'readPreference' string iKeyWithType (MONGOC_URI_READPREFERENCE, utf8), case ( // Switch on the string content: when (iStrEqual ("primary"), do (mode = MONGOC_READ_PRIMARY)), when (iStrEqual ("primaryPreferred"), do (mode = MONGOC_READ_PRIMARY_PREFERRED)), when (iStrEqual ("secondary"), do (mode = MONGOC_READ_SECONDARY)), when (iStrEqual ("secondaryPreferred"), do (mode = MONGOC_READ_SECONDARY_PREFERRED)), when (iStrEqual ("nearest"), do (mode = MONGOC_READ_NEAREST)), else (do ({ pref = bsonAs (cstr); bsonParseError = "Unsupported readPreference value"; }))))); if (bsonParseError) { const char *prefix = "Error while assigning URI read preference"; if (pref) { MONGOC_URI_ERROR (error, "%s: %s [readPreference=%s]", prefix, bsonParseError, pref); } else { MONGOC_URI_ERROR (error, "%s: %s", prefix, bsonParseError); } return false; } if (mode != 0) { mongoc_read_prefs_set_mode (uri->read_prefs, mode); } return true; } static bool _mongoc_uri_build_write_concern (mongoc_uri_t *uri, bson_error_t *error) { mongoc_write_concern_t *write_concern; int64_t wtimeoutms; BSON_ASSERT (uri); write_concern = mongoc_write_concern_new (); uri->write_concern = write_concern; bsonParse (uri->options, find (iKeyWithType (MONGOC_URI_SAFE, boolean), do (mongoc_write_concern_set_w (write_concern, bsonAs (boolean) ? 1 : MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED)))); if (bsonParseError) { MONGOC_URI_ERROR (error, "Error while parsing 'safe' URI option: %s", bsonParseError); return false; } wtimeoutms = mongoc_uri_get_option_as_int64 (uri, MONGOC_URI_WTIMEOUTMS, 0); if (wtimeoutms < 0) { MONGOC_URI_ERROR (error, "Unsupported wtimeoutMS value [w=%" PRId64 "]", wtimeoutms); return false; } else if (wtimeoutms > 0) { mongoc_write_concern_set_wtimeout_int64 (write_concern, wtimeoutms); } bsonParse (uri->options, find (iKeyWithType (MONGOC_URI_JOURNAL, boolean), do (mongoc_write_concern_set_journal (write_concern, bsonAs (boolean))))); if (bsonParseError) { MONGOC_URI_ERROR (error, "Error while parsing 'journal' URI option: %s", bsonParseError); return false; } int w_int = INT_MAX; const char *w_str = NULL; bsonParse (uri->options, find (iKey ("w"), // storeInt32 (w_int), storeStrRef (w_str), case ( // Special W options: when (anyOf (eq (int32, MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED), eq (int32, MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED)), // These conflict with journalling: if (eval (mongoc_write_concern_get_journal (write_concern)), then (error ("Journal conflicts with w value"))), do (mongoc_write_concern_set_w (write_concern, bsonAs (int32)))), // Other positive 'w' value: when (allOf (type (int32), eval (bsonAs (int32) > 0)), do (mongoc_write_concern_set_w (write_concern, bsonAs (int32)))), // Special "majority" string: when (iStrEqual ("majority"), do (mongoc_write_concern_set_w (write_concern, MONGOC_WRITE_CONCERN_W_MAJORITY))), // Other string: when (type (utf8), do (mongoc_write_concern_set_wtag (write_concern, bsonAs (cstr)))), // Invalid value: else (error ("Unsupported w value"))))); if (bsonParseError) { const char *const prefix = "Error while parsing the 'w' URI option"; if (w_str) { MONGOC_URI_ERROR (error, "%s: %s [w=%s]", prefix, bsonParseError, w_str); } else if (w_int != INT_MAX) { MONGOC_URI_ERROR (error, "%s: %s [w=%d]", prefix, bsonParseError, w_int); } else { MONGOC_URI_ERROR (error, "%s: %s", prefix, bsonParseError); } return false; } return true; } /* can't use mongoc_uri_get_option_as_int32, it treats 0 specially */ static int32_t _mongoc_uri_get_max_staleness_option (const mongoc_uri_t *uri) { const bson_t *options; bson_iter_t iter; int32_t retval = MONGOC_NO_MAX_STALENESS; if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, MONGOC_URI_MAXSTALENESSSECONDS) && BSON_ITER_HOLDS_INT32 (&iter)) { retval = bson_iter_int32 (&iter); if (retval == 0) { MONGOC_WARNING ("Unsupported value for \"" MONGOC_URI_MAXSTALENESSSECONDS "\": \"%d\"", retval); retval = -1; } else if (retval < 0 && retval != -1) { MONGOC_WARNING ("Unsupported value for \"" MONGOC_URI_MAXSTALENESSSECONDS "\": \"%d\"", retval); retval = MONGOC_NO_MAX_STALENESS; } } return retval; } mongoc_uri_t * mongoc_uri_new_with_error (const char *uri_string, bson_error_t *error) { mongoc_uri_t *uri; int32_t max_staleness_seconds; uri = BSON_ALIGNED_ALLOC0 (mongoc_uri_t); bson_init (&uri->raw); bson_init (&uri->options); bson_init (&uri->credentials); bson_init (&uri->compressors); /* Initialize read_prefs, since parsing may add to it */ uri->read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY); /* Initialize empty read_concern */ uri->read_concern = mongoc_read_concern_new (); if (!uri_string) { uri_string = "mongodb://127.0.0.1/"; } if (!mongoc_uri_parse (uri, uri_string, error)) { mongoc_uri_destroy (uri); return NULL; } uri->str = bson_strdup (uri_string); if (!_mongoc_uri_assign_read_prefs_mode (uri, error)) { mongoc_uri_destroy (uri); return NULL; } max_staleness_seconds = _mongoc_uri_get_max_staleness_option (uri); mongoc_read_prefs_set_max_staleness_seconds (uri->read_prefs, max_staleness_seconds); if (!mongoc_read_prefs_is_valid (uri->read_prefs)) { mongoc_uri_destroy (uri); MONGOC_URI_ERROR (error, "%s", "Invalid readPreferences"); return NULL; } if (!_mongoc_uri_build_write_concern (uri, error)) { mongoc_uri_destroy (uri); return NULL; } if (!mongoc_write_concern_is_valid (uri->write_concern)) { mongoc_uri_destroy (uri); MONGOC_URI_ERROR (error, "%s", "Invalid writeConcern"); return NULL; } return uri; } mongoc_uri_t * mongoc_uri_new (const char *uri_string) { bson_error_t error = {0}; mongoc_uri_t *uri; uri = mongoc_uri_new_with_error (uri_string, &error); if (error.domain) { MONGOC_WARNING ("Error parsing URI: '%s'", error.message); } return uri; } mongoc_uri_t * mongoc_uri_new_for_host_port (const char *hostname, uint16_t port) { mongoc_uri_t *uri; char *str; BSON_ASSERT (hostname); BSON_ASSERT (port); str = bson_strdup_printf ("mongodb://%s:%hu/", hostname, port); uri = mongoc_uri_new (str); bson_free (str); return uri; } const char * mongoc_uri_get_username (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->username; } bool mongoc_uri_set_username (mongoc_uri_t *uri, const char *username) { size_t len; BSON_ASSERT (username); len = strlen (username); if (!bson_utf8_validate (username, len, false)) { return false; } if (uri->username) { bson_free (uri->username); } uri->username = bson_strdup (username); return true; } const char * mongoc_uri_get_password (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->password; } bool mongoc_uri_set_password (mongoc_uri_t *uri, const char *password) { size_t len; BSON_ASSERT (password); len = strlen (password); if (!bson_utf8_validate (password, len, false)) { return false; } if (uri->password) { bson_free (uri->password); } uri->password = bson_strdup (password); return true; } const char * mongoc_uri_get_database (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->database; } bool mongoc_uri_set_database (mongoc_uri_t *uri, const char *database) { size_t len; BSON_ASSERT (database); len = strlen (database); if (!bson_utf8_validate (database, len, false)) { return false; } if (uri->database) { bson_free (uri->database); } uri->database = bson_strdup (database); return true; } const char * mongoc_uri_get_auth_source (const mongoc_uri_t *uri) { bson_iter_t iter; const char *mechanism; BSON_ASSERT (uri); if (bson_iter_init_find_case (&iter, &uri->credentials, MONGOC_URI_AUTHSOURCE)) { return bson_iter_utf8 (&iter, NULL); } /* Auth spec: * "For GSSAPI and MONGODB-X509 authMechanisms the authSource defaults to * $external. For PLAIN the authSource defaults to the database name if * supplied on the connection string or $external. For * SCRAM-SHA-1 and SCRAM-SHA-256 authMechanisms, the authSource defaults to * the database name if supplied on the connection string or admin." */ mechanism = mongoc_uri_get_auth_mechanism (uri); if (mechanism) { if (!strcasecmp (mechanism, "GSSAPI") || !strcasecmp (mechanism, "MONGODB-X509")) { return "$external"; } if (!strcasecmp (mechanism, "PLAIN")) { return uri->database ? uri->database : "$external"; } } return uri->database ? uri->database : "admin"; } bool mongoc_uri_set_auth_source (mongoc_uri_t *uri, const char *value) { size_t len; BSON_ASSERT (value); len = strlen (value); if (!bson_utf8_validate (value, len, false)) { return false; } mongoc_uri_bson_append_or_replace_key (&uri->credentials, MONGOC_URI_AUTHSOURCE, value); return true; } const char * mongoc_uri_get_appname (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return mongoc_uri_get_option_as_utf8 (uri, MONGOC_URI_APPNAME, NULL); } bool mongoc_uri_set_appname (mongoc_uri_t *uri, const char *value) { BSON_ASSERT (value); if (!bson_utf8_validate (value, strlen (value), false)) { return false; } if (!_mongoc_handshake_appname_is_valid (value)) { return false; } mongoc_uri_bson_append_or_replace_key (&uri->options, MONGOC_URI_APPNAME, value); return true; } bool mongoc_uri_set_compressors (mongoc_uri_t *uri, const char *value) { const char *end_compressor; char *entry; bson_destroy (&uri->compressors); bson_init (&uri->compressors); if (value && !bson_utf8_validate (value, strlen (value), false)) { return false; } while ((entry = scan_to_unichar (value, ',', "", &end_compressor))) { if (mongoc_compressor_supported (entry)) { mongoc_uri_bson_append_or_replace_key (&uri->compressors, entry, "yes"); } else { MONGOC_WARNING ("Unsupported compressor: '%s'", entry); } value = end_compressor + 1; bson_free (entry); } if (value) { if (mongoc_compressor_supported (value)) { mongoc_uri_bson_append_or_replace_key (&uri->compressors, value, "yes"); } else { MONGOC_WARNING ("Unsupported compressor: '%s'", value); } } return true; } const bson_t * mongoc_uri_get_compressors (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return &uri->compressors; } /* can't use mongoc_uri_get_option_as_int32, it treats 0 specially */ int32_t mongoc_uri_get_local_threshold_option (const mongoc_uri_t *uri) { const bson_t *options; bson_iter_t iter; int32_t retval = MONGOC_TOPOLOGY_LOCAL_THRESHOLD_MS; if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, "localthresholdms") && BSON_ITER_HOLDS_INT32 (&iter)) { retval = bson_iter_int32 (&iter); if (retval < 0) { MONGOC_WARNING ("Invalid localThresholdMS: %d", retval); retval = MONGOC_TOPOLOGY_LOCAL_THRESHOLD_MS; } } return retval; } const char * mongoc_uri_get_srv_hostname (const mongoc_uri_t *uri) { if (uri->is_srv) { return uri->srv; } return NULL; } const char * mongoc_uri_get_service (const mongoc_uri_t *uri) { return mongoc_uri_get_srv_hostname (uri); } /* Initial DNS Seedlist Discovery Spec: `srvServiceName` requires a string value * and defaults to "mongodb". */ static const char *const mongoc_default_srv_service_name = "mongodb"; const char * mongoc_uri_get_srv_service_name (const mongoc_uri_t *uri) { bson_iter_t iter; BSON_ASSERT_PARAM (uri); if (bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_SRVSERVICENAME)) { BSON_ASSERT (BSON_ITER_HOLDS_UTF8 (&iter)); return bson_iter_utf8 (&iter, NULL); } return mongoc_default_srv_service_name; } const bson_t * mongoc_uri_get_options (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return &uri->options; } void mongoc_uri_destroy (mongoc_uri_t *uri) { if (uri) { _mongoc_host_list_destroy_all (uri->hosts); bson_free (uri->str); bson_free (uri->database); bson_free (uri->username); bson_destroy (&uri->raw); bson_destroy (&uri->options); bson_destroy (&uri->credentials); bson_destroy (&uri->compressors); mongoc_read_prefs_destroy (uri->read_prefs); mongoc_read_concern_destroy (uri->read_concern); mongoc_write_concern_destroy (uri->write_concern); if (uri->password) { bson_zero_free (uri->password, strlen (uri->password)); } bson_free (uri); } } mongoc_uri_t * mongoc_uri_copy (const mongoc_uri_t *uri) { mongoc_uri_t *copy; mongoc_host_list_t *iter; bson_error_t error; BSON_ASSERT (uri); copy = BSON_ALIGNED_ALLOC0 (mongoc_uri_t); copy->str = bson_strdup (uri->str); copy->is_srv = uri->is_srv; bson_strncpy (copy->srv, uri->srv, sizeof uri->srv); copy->username = bson_strdup (uri->username); copy->password = bson_strdup (uri->password); copy->database = bson_strdup (uri->database); copy->read_prefs = mongoc_read_prefs_copy (uri->read_prefs); copy->read_concern = mongoc_read_concern_copy (uri->read_concern); copy->write_concern = mongoc_write_concern_copy (uri->write_concern); LL_FOREACH (uri->hosts, iter) { if (!mongoc_uri_upsert_host (copy, iter->host, iter->port, &error)) { MONGOC_ERROR ("%s", error.message); mongoc_uri_destroy (copy); return NULL; } } bson_copy_to (&uri->raw, ©->raw); bson_copy_to (&uri->options, ©->options); bson_copy_to (&uri->credentials, ©->credentials); bson_copy_to (&uri->compressors, ©->compressors); return copy; } const char * mongoc_uri_get_string (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return uri->str; } const bson_t * mongoc_uri_get_read_prefs (const mongoc_uri_t *uri) { BSON_ASSERT (uri); return mongoc_read_prefs_get_tags (uri->read_prefs); } char * mongoc_uri_unescape (const char *escaped_string) { bson_unichar_t c; unsigned int hex = 0; const char *ptr; const char *end; size_t len; bool unescape_occurred = false; BSON_ASSERT (escaped_string); len = strlen (escaped_string); /* * Double check that this is a UTF-8 valid string. Bail out if necessary. */ if (!bson_utf8_validate (escaped_string, len, false)) { MONGOC_WARNING ("%s(): escaped_string contains invalid UTF-8", BSON_FUNC); return NULL; } ptr = escaped_string; end = ptr + len; mcommon_string_append_t append; mcommon_string_new_with_capacity_as_append (&append, len); for (; *ptr; ptr = bson_utf8_next_char (ptr)) { c = bson_utf8_get_char (ptr); switch (c) { case '%': if (((end - ptr) < 2) || !isxdigit (ptr[1]) || !isxdigit (ptr[2]) || #ifdef _MSC_VER (1 != sscanf_s (&ptr[1], "%02x", &hex)) #else (1 != sscanf (&ptr[1], "%02x", &hex)) #endif || 0 == hex) { mcommon_string_from_append_destroy (&append); MONGOC_WARNING ("Invalid %% escape sequence"); return NULL; } // This isn't guaranteed to be valid UTF-8, we check again below char byte = (char) hex; mcommon_string_append_bytes (&append, &byte, 1); ptr += 2; unescape_occurred = true; break; default: mcommon_string_append_unichar (&append, c); break; } } /* Check that after unescaping, it is still valid UTF-8 */ if (unescape_occurred && !bson_utf8_validate (mcommon_str_from_append (&append), mcommon_strlen_from_append (&append), false)) { MONGOC_WARNING ("Invalid %% escape sequence: unescaped string contains invalid UTF-8"); mcommon_string_from_append_destroy (&append); return NULL; } return mcommon_string_from_append_destroy_with_steal (&append); } const mongoc_read_prefs_t * mongoc_uri_get_read_prefs_t (const mongoc_uri_t *uri) /* IN */ { BSON_ASSERT (uri); return uri->read_prefs; } void mongoc_uri_set_read_prefs_t (mongoc_uri_t *uri, const mongoc_read_prefs_t *prefs) { BSON_ASSERT (uri); BSON_ASSERT (prefs); mongoc_read_prefs_destroy (uri->read_prefs); uri->read_prefs = mongoc_read_prefs_copy (prefs); } const mongoc_read_concern_t * mongoc_uri_get_read_concern (const mongoc_uri_t *uri) /* IN */ { BSON_ASSERT (uri); return uri->read_concern; } void mongoc_uri_set_read_concern (mongoc_uri_t *uri, const mongoc_read_concern_t *rc) { BSON_ASSERT (uri); BSON_ASSERT (rc); mongoc_read_concern_destroy (uri->read_concern); uri->read_concern = mongoc_read_concern_copy (rc); } const mongoc_write_concern_t * mongoc_uri_get_write_concern (const mongoc_uri_t *uri) /* IN */ { BSON_ASSERT (uri); return uri->write_concern; } void mongoc_uri_set_write_concern (mongoc_uri_t *uri, const mongoc_write_concern_t *wc) { BSON_ASSERT (uri); BSON_ASSERT (wc); mongoc_write_concern_destroy (uri->write_concern); uri->write_concern = mongoc_write_concern_copy (wc); } bool mongoc_uri_get_tls (const mongoc_uri_t *uri) /* IN */ { bson_iter_t iter; BSON_ASSERT (uri); if (bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLS) && BSON_ITER_HOLDS_BOOL (&iter)) { return bson_iter_bool (&iter); } if (bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLSCERTIFICATEKEYFILE) || bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLSCAFILE) || bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES) || bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES) || bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLSINSECURE) || bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD) || bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK) || bson_iter_init_find_case (&iter, &uri->options, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK)) { return true; } return false; } bool mongoc_uri_get_ssl (const mongoc_uri_t *uri) /* IN */ { return mongoc_uri_get_tls (uri); } const char * mongoc_uri_get_server_monitoring_mode (const mongoc_uri_t *uri) { BSON_ASSERT_PARAM (uri); return mongoc_uri_get_option_as_utf8 (uri, MONGOC_URI_SERVERMONITORINGMODE, "auto"); } bool mongoc_uri_set_server_monitoring_mode (mongoc_uri_t *uri, const char *value) { BSON_ASSERT_PARAM (uri); BSON_ASSERT_PARAM (value); // Check for valid value if (strcmp (value, "stream") && strcmp (value, "poll") && strcmp (value, "auto")) { return false; } mongoc_uri_bson_append_or_replace_key (&uri->options, MONGOC_URI_SERVERMONITORINGMODE, value); return true; } /* *-------------------------------------------------------------------------- * * mongoc_uri_get_option_as_int32 -- * * Checks if the URI 'option' is set and of correct type (int32). * The special value '0' is considered as "unset". * This is so users can provide * sprintf("mongodb://localhost/?option=%d", myvalue) style connection * strings, and still apply default values. * * If not set, or set to invalid type, 'fallback' is returned. * * NOTE: 'option' is case*in*sensitive. * * Returns: * The value of 'option' if available as int32 (and not 0), or * 'fallback'. * *-------------------------------------------------------------------------- */ int32_t mongoc_uri_get_option_as_int32 (const mongoc_uri_t *uri, const char *option_orig, int32_t fallback) { const char *option; const bson_t *options; bson_iter_t iter; int64_t retval = 0; option = mongoc_uri_canonicalize_option (option_orig); /* BC layer to allow retrieving 32-bit values stored in 64-bit options */ if (mongoc_uri_option_is_int64 (option_orig)) { retval = mongoc_uri_get_option_as_int64 (uri, option_orig, 0); if (retval > INT32_MAX || retval < INT32_MIN) { MONGOC_WARNING ("Cannot read 64-bit value for \"%s\": %" PRId64, option_orig, retval); retval = 0; } } else if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option) && BSON_ITER_HOLDS_INT32 (&iter)) { retval = bson_iter_int32 (&iter); } if (!retval) { retval = fallback; } return (int32_t) retval; } /* *-------------------------------------------------------------------------- * * mongoc_uri_set_option_as_int32 -- * * Sets a URI option 'after the fact'. Allows users to set individual * URI options without passing them as a connection string. * * Only allows a set of known options to be set. * @see mongoc_uri_option_is_int32 (). * * Does in-place-update of the option BSON if 'option' is already set. * Appends the option to the end otherwise. * * NOTE: If 'option' is already set, and is of invalid type, this * function will return false. * * NOTE: 'option' is case*in*sensitive. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ bool mongoc_uri_set_option_as_int32 (mongoc_uri_t *uri, const char *option_orig, int32_t value) { const char *option; bson_error_t error; bool r; if (mongoc_uri_option_is_int64 (option_orig)) { return mongoc_uri_set_option_as_int64 (uri, option_orig, value); } option = mongoc_uri_canonicalize_option (option_orig); if (!mongoc_uri_option_is_int32 (option)) { MONGOC_WARNING ("Unsupported value for \"%s\": %d, \"%s\" is not an int32 option", option_orig, value, option); return false; } r = _mongoc_uri_set_option_as_int32_with_error (uri, option, value, &error); if (!r) { MONGOC_WARNING ("%s", error.message); } return r; } /* *-------------------------------------------------------------------------- * * _mongoc_uri_set_option_as_int32_with_error -- * * Same as mongoc_uri_set_option_as_int32, with error reporting. * * Precondition: * mongoc_uri_option_is_int32(option) must be true. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_uri_set_option_as_int32_with_error (mongoc_uri_t *uri, const char *option_orig, int32_t value, bson_error_t *error) { const char *option; const bson_t *options; bson_iter_t iter; char *option_lowercase = NULL; option = mongoc_uri_canonicalize_option (option_orig); /* Server Discovery and Monitoring Spec: "the driver MUST NOT permit users * to configure it less than minHeartbeatFrequencyMS (500ms)." */ if (!bson_strcasecmp (option, MONGOC_URI_HEARTBEATFREQUENCYMS) && value < MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS) { MONGOC_URI_ERROR (error, "Invalid \"%s\" of %d: must be at least %d", option_orig, value, MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS); return false; } /* zlib levels are from -1 (default) through 9 (best compression) */ if (!bson_strcasecmp (option, MONGOC_URI_ZLIBCOMPRESSIONLEVEL) && (value < -1 || value > 9)) { MONGOC_URI_ERROR (error, "Invalid \"%s\" of %d: must be between -1 and 9", option_orig, value); return false; } if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option)) { if (BSON_ITER_HOLDS_INT32 (&iter)) { bson_iter_overwrite_int32 (&iter, value); return true; } else { MONGOC_URI_ERROR (error, "Cannot set URI option \"%s\" to %d, it already has " "a non-32-bit integer value", option, value); return false; } } option_lowercase = lowercase_str_new (option); if (!bson_append_int32 (&uri->options, option_lowercase, -1, value)) { bson_free (option_lowercase); MONGOC_URI_ERROR (error, "Failed to set URI option \"%s\" to %d", option_orig, value); return false; } bson_free (option_lowercase); return true; } /* *-------------------------------------------------------------------------- * * _mongoc_uri_set_option_as_int32 -- * * Same as mongoc_uri_set_option_as_int32, except the option is not * validated against valid int32 options * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_uri_set_option_as_int32 (mongoc_uri_t *uri, const char *option_orig, int32_t value) { const char *option; const bson_t *options; bson_iter_t iter; char *option_lowercase = NULL; option = mongoc_uri_canonicalize_option (option_orig); if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option)) { if (BSON_ITER_HOLDS_INT32 (&iter)) { bson_iter_overwrite_int32 (&iter, value); return true; } else { return false; } } option_lowercase = lowercase_str_new (option); bson_append_int32 (&uri->options, option_lowercase, -1, value); bson_free (option_lowercase); return true; } /* *-------------------------------------------------------------------------- * * mongoc_uri_get_option_as_int64 -- * * Checks if the URI 'option' is set and of correct type (int32 or * int64). * The special value '0' is considered as "unset". * This is so users can provide * sprintf("mongodb://localhost/?option=%" PRId64, myvalue) style * connection strings, and still apply default values. * * If not set, or set to invalid type, 'fallback' is returned. * * NOTE: 'option' is case*in*sensitive. * * Returns: * The value of 'option' if available as int64 or int32 (and not 0), or * 'fallback'. * *-------------------------------------------------------------------------- */ int64_t mongoc_uri_get_option_as_int64 (const mongoc_uri_t *uri, const char *option_orig, int64_t fallback) { const char *option; const bson_t *options; bson_iter_t iter; int64_t retval = fallback; option = mongoc_uri_canonicalize_option (option_orig); if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option)) { if (BSON_ITER_HOLDS_INT (&iter)) { if (!(retval = bson_iter_as_int64 (&iter))) { retval = fallback; } } } return retval; } /* *-------------------------------------------------------------------------- * * mongoc_uri_set_option_as_int64 -- * * Sets a URI option 'after the fact'. Allows users to set individual * URI options without passing them as a connection string. * * Only allows a set of known options to be set. * @see mongoc_uri_option_is_int64 (). * * Does in-place-update of the option BSON if 'option' is already set. * Appends the option to the end otherwise. * * NOTE: If 'option' is already set, and is of invalid type, this * function will return false. * * NOTE: 'option' is case*in*sensitive. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ bool mongoc_uri_set_option_as_int64 (mongoc_uri_t *uri, const char *option_orig, int64_t value) { const char *option; bson_error_t error; bool r; option = mongoc_uri_canonicalize_option (option_orig); if (!mongoc_uri_option_is_int64 (option)) { if (mongoc_uri_option_is_int32 (option_orig)) { if (value >= INT32_MIN && value <= INT32_MAX) { MONGOC_WARNING ("Setting value for 32-bit option \"%s\" through 64-bit method", option_orig); return mongoc_uri_set_option_as_int32 (uri, option_orig, (int32_t) value); } MONGOC_WARNING ( "Unsupported value for \"%s\": %" PRId64 ", \"%s\" is not an int64 option", option_orig, value, option); return false; } } r = _mongoc_uri_set_option_as_int64_with_error (uri, option, value, &error); if (!r) { MONGOC_WARNING ("%s", error.message); } return r; } /* *-------------------------------------------------------------------------- * * _mongoc_uri_set_option_as_int64_with_error -- * * Same as mongoc_uri_set_option_as_int64, with error reporting. * * Precondition: * mongoc_uri_option_is_int64(option) must be true. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ static bool _mongoc_uri_set_option_as_int64_with_error (mongoc_uri_t *uri, const char *option_orig, int64_t value, bson_error_t *error) { const char *option; const bson_t *options; bson_iter_t iter; char *option_lowercase = NULL; option = mongoc_uri_canonicalize_option (option_orig); if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option)) { if (BSON_ITER_HOLDS_INT64 (&iter)) { bson_iter_overwrite_int64 (&iter, value); return true; } else { MONGOC_URI_ERROR (error, "Cannot set URI option \"%s\" to %" PRId64 ", it already has " "a non-64-bit integer value", option, value); return false; } } option_lowercase = lowercase_str_new (option); if (!bson_append_int64 (&uri->options, option_lowercase, -1, value)) { bson_free (option_lowercase); MONGOC_URI_ERROR (error, "Failed to set URI option \"%s\" to %" PRId64, option_orig, value); return false; } bson_free (option_lowercase); return true; } /* *-------------------------------------------------------------------------- * * mongoc_uri_get_option_as_bool -- * * Checks if the URI 'option' is set and of correct type (bool). * * If not set, or set to invalid type, 'fallback' is returned. * * NOTE: 'option' is case*in*sensitive. * * Returns: * The value of 'option' if available as bool, or 'fallback'. * *-------------------------------------------------------------------------- */ bool mongoc_uri_get_option_as_bool (const mongoc_uri_t *uri, const char *option_orig, bool fallback) { const char *option; const bson_t *options; bson_iter_t iter; option = mongoc_uri_canonicalize_option (option_orig); if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option) && BSON_ITER_HOLDS_BOOL (&iter)) { return bson_iter_bool (&iter); } return fallback; } /* *-------------------------------------------------------------------------- * * mongoc_uri_set_option_as_bool -- * * Sets a URI option 'after the fact'. Allows users to set individual * URI options without passing them as a connection string. * * Only allows a set of known options to be set. * @see mongoc_uri_option_is_bool (). * * Does in-place-update of the option BSON if 'option' is already set. * Appends the option to the end otherwise. * * NOTE: If 'option' is already set, and is of invalid type, this * function will return false. * * NOTE: 'option' is case*in*sensitive. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ bool mongoc_uri_set_option_as_bool (mongoc_uri_t *uri, const char *option_orig, bool value) { const char *option; char *option_lowercase; const bson_t *options; bson_iter_t iter; option = mongoc_uri_canonicalize_option (option_orig); BSON_ASSERT (option); if (!mongoc_uri_option_is_bool (option)) { return false; } if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option)) { if (BSON_ITER_HOLDS_BOOL (&iter)) { bson_iter_overwrite_bool (&iter, value); return true; } else { return false; } } option_lowercase = lowercase_str_new (option); bson_append_bool (&uri->options, option_lowercase, -1, value); bson_free (option_lowercase); return true; } /* *-------------------------------------------------------------------------- * * mongoc_uri_get_option_as_utf8 -- * * Checks if the URI 'option' is set and of correct type (utf8). * * If not set, or set to invalid type, 'fallback' is returned. * * NOTE: 'option' is case*in*sensitive. * * Returns: * The value of 'option' if available as utf8, or 'fallback'. * *-------------------------------------------------------------------------- */ const char * mongoc_uri_get_option_as_utf8 (const mongoc_uri_t *uri, const char *option_orig, const char *fallback) { const char *option; const bson_t *options; bson_iter_t iter; option = mongoc_uri_canonicalize_option (option_orig); if ((options = mongoc_uri_get_options (uri)) && bson_iter_init_find_case (&iter, options, option) && BSON_ITER_HOLDS_UTF8 (&iter)) { return bson_iter_utf8 (&iter, NULL); } return fallback; } /* *-------------------------------------------------------------------------- * * mongoc_uri_set_option_as_utf8 -- * * Sets a URI option 'after the fact'. Allows users to set individual * URI options without passing them as a connection string. * * Only allows a set of known options to be set. * @see mongoc_uri_option_is_utf8 (). * * If the option is not already set, this function will append it to *the end of the options bson. NOTE: If the option is already set the entire *options bson will be overwritten, containing the new option=value *(at the same position). * * NOTE: If 'option' is already set, and is of invalid type, this * function will return false. * * NOTE: 'option' must be valid utf8. * * NOTE: 'option' is case*in*sensitive. * * Returns: * true on successfully setting the option, false on failure. * *-------------------------------------------------------------------------- */ bool mongoc_uri_set_option_as_utf8 (mongoc_uri_t *uri, const char *option_orig, const char *value) { const char *option; size_t len; char *option_lowercase = NULL; option = mongoc_uri_canonicalize_option (option_orig); BSON_ASSERT (option); len = strlen (value); if (!bson_utf8_validate (value, len, false)) { return false; } if (!mongoc_uri_option_is_utf8 (option)) { return false; } if (!bson_strcasecmp (option, MONGOC_URI_APPNAME)) { return mongoc_uri_set_appname (uri, value); } else if (!bson_strcasecmp (option, MONGOC_URI_SERVERMONITORINGMODE)) { return mongoc_uri_set_server_monitoring_mode (uri, value); } else { option_lowercase = lowercase_str_new (option); mongoc_uri_bson_append_or_replace_key (&uri->options, option_lowercase, value); bson_free (option_lowercase); } return true; } /* *-------------------------------------------------------------------------- * * _mongoc_uri_requires_auth_negotiation -- * * Returns true if auth mechanism is necessary for this uri. According * to the auth spec: "If an application provides a username but does * not provide an authentication mechanism, drivers MUST negotiate a * mechanism". * * Returns: * true if the driver should negotiate the auth mechanism for the uri * *-------------------------------------------------------------------------- */ bool _mongoc_uri_requires_auth_negotiation (const mongoc_uri_t *uri) { return mongoc_uri_get_username (uri) && !mongoc_uri_get_auth_mechanism (uri); } /* A bit of a hack. Needed for multi mongos tests to create a URI with the same * auth, SSL, and compressors settings but with only one specific host. */ mongoc_uri_t * _mongoc_uri_copy_and_replace_host_list (const mongoc_uri_t *original, const char *host) { mongoc_uri_t *uri = mongoc_uri_copy (original); _mongoc_host_list_destroy_all (uri->hosts); uri->hosts = bson_malloc0 (sizeof (mongoc_host_list_t)); _mongoc_host_list_from_string (uri->hosts, host); return uri; } bool mongoc_uri_init_with_srv_host_list (mongoc_uri_t *uri, mongoc_host_list_t *host_list, bson_error_t *error) { mongoc_host_list_t *host; BSON_ASSERT (uri->is_srv); BSON_ASSERT (!uri->hosts); LL_FOREACH (host_list, host) { if (!mongoc_uri_upsert_host_and_port (uri, host->host_and_port, error)) { return false; } } return true; } #ifdef MONGOC_ENABLE_CRYPTO void _mongoc_uri_init_scram (const mongoc_uri_t *uri, mongoc_scram_t *scram, mongoc_crypto_hash_algorithm_t algo) { BSON_ASSERT (uri); BSON_ASSERT (scram); _mongoc_scram_init (scram, algo); _mongoc_scram_set_pass (scram, mongoc_uri_get_password (uri)); _mongoc_scram_set_user (scram, mongoc_uri_get_username (uri)); } #endif static bool mongoc_uri_finalize_loadbalanced (const mongoc_uri_t *uri, bson_error_t *error) { if (!mongoc_uri_get_option_as_bool (uri, MONGOC_URI_LOADBALANCED, false)) { return true; } /* Load Balancer Spec: When `loadBalanced=true` is provided in the connection * string, the driver MUST throw an exception if the connection string * contains more than one host/port. */ if (uri->hosts && uri->hosts->next) { MONGOC_URI_ERROR (error, "URI with \"%s\" enabled must not contain more than one host", MONGOC_URI_LOADBALANCED); return false; } if (mongoc_uri_has_option (uri, MONGOC_URI_REPLICASET)) { MONGOC_URI_ERROR (error, "URI with \"%s\" enabled must not contain option \"%s\"", MONGOC_URI_LOADBALANCED, MONGOC_URI_REPLICASET); return false; } if (mongoc_uri_has_option (uri, MONGOC_URI_DIRECTCONNECTION) && mongoc_uri_get_option_as_bool (uri, MONGOC_URI_DIRECTCONNECTION, false)) { MONGOC_URI_ERROR (error, "URI with \"%s\" enabled must not contain option \"%s\" enabled", MONGOC_URI_LOADBALANCED, MONGOC_URI_DIRECTCONNECTION); return false; } return true; } static bool mongoc_uri_finalize_srv (const mongoc_uri_t *uri, bson_error_t *error) { /* Initial DNS Seedlist Discovery Spec: The driver MUST report an error if * either the `srvServiceName` or `srvMaxHosts` URI options are specified * with a non-SRV URI. */ if (!uri->is_srv) { const char *option = NULL; if (mongoc_uri_has_option (uri, MONGOC_URI_SRVSERVICENAME)) { option = MONGOC_URI_SRVSERVICENAME; } else if (mongoc_uri_has_option (uri, MONGOC_URI_SRVMAXHOSTS)) { option = MONGOC_URI_SRVMAXHOSTS; } if (option) { MONGOC_URI_ERROR (error, "%s must not be specified with a non-SRV URI", option); return false; } } if (uri->is_srv) { const int32_t max_hosts = mongoc_uri_get_option_as_int32 (uri, MONGOC_URI_SRVMAXHOSTS, 0); /* Initial DNS Seedless Discovery Spec: This option requires a * non-negative integer and defaults to zero (i.e. no limit). */ if (max_hosts < 0) { MONGOC_URI_ERROR (error, "%s is required to be a non-negative integer, but " "has value %" PRId32, MONGOC_URI_SRVMAXHOSTS, max_hosts); return false; } if (max_hosts > 0) { /* Initial DNS Seedless Discovery spec: If srvMaxHosts is a positive * integer, the driver MUST throw an error if the connection string * contains a `replicaSet` option. */ if (mongoc_uri_has_option (uri, MONGOC_URI_REPLICASET)) { MONGOC_URI_ERROR (error, "%s must not be specified with %s", MONGOC_URI_SRVMAXHOSTS, MONGOC_URI_REPLICASET); return false; } /* Initial DNS Seedless Discovery Spec: If srvMaxHosts is a positive * integer, the driver MUST throw an error if the connection string * contains a `loadBalanced` option with a value of `true`. */ if (mongoc_uri_get_option_as_bool (uri, MONGOC_URI_LOADBALANCED, false)) { MONGOC_URI_ERROR ( error, "%s must not be specified with %s=true", MONGOC_URI_SRVMAXHOSTS, MONGOC_URI_LOADBALANCED); return false; } } } return true; } /* This should be called whenever URI options change (e.g. parsing a new URI * string, after setting one or more options explicitly, applying TXT records). * While the primary purpose of this function is to validate the URI, it may * also alter the URI (e.g. implicitly enable TLS when SRV is used). Returns * true on success; otherwise, returns false and sets @error. */ bool mongoc_uri_finalize (mongoc_uri_t *uri, bson_error_t *error) { BSON_ASSERT_PARAM (uri); if (!mongoc_uri_finalize_tls (uri, error)) { return false; } if (!mongoc_uri_finalize_auth (uri, error)) { return false; } if (!mongoc_uri_finalize_directconnection (uri, error)) { return false; } if (!mongoc_uri_finalize_loadbalanced (uri, error)) { return false; } if (!mongoc_uri_finalize_srv (uri, error)) { return false; } return true; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-uri.h0000644000175100001660000002177414760300420021751 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_URI_H #define MONGOC_URI_H #include #include #include #include #include #include #include #ifndef MONGOC_DEFAULT_PORT #define MONGOC_DEFAULT_PORT 27017 #endif #define MONGOC_URI_APPNAME "appname" #define MONGOC_URI_AUTHMECHANISM "authmechanism" #define MONGOC_URI_AUTHMECHANISMPROPERTIES "authmechanismproperties" #define MONGOC_URI_AUTHSOURCE "authsource" #define MONGOC_URI_CANONICALIZEHOSTNAME "canonicalizehostname" #define MONGOC_URI_CONNECTTIMEOUTMS "connecttimeoutms" #define MONGOC_URI_COMPRESSORS "compressors" #define MONGOC_URI_DIRECTCONNECTION "directconnection" #define MONGOC_URI_GSSAPISERVICENAME "gssapiservicename" #define MONGOC_URI_HEARTBEATFREQUENCYMS "heartbeatfrequencyms" #define MONGOC_URI_JOURNAL "journal" #define MONGOC_URI_LOADBALANCED "loadbalanced" #define MONGOC_URI_LOCALTHRESHOLDMS "localthresholdms" #define MONGOC_URI_MAXIDLETIMEMS "maxidletimems" #define MONGOC_URI_MAXPOOLSIZE "maxpoolsize" #define MONGOC_URI_MAXSTALENESSSECONDS "maxstalenessseconds" #define MONGOC_URI_MINPOOLSIZE "minpoolsize" #define MONGOC_URI_READCONCERNLEVEL "readconcernlevel" #define MONGOC_URI_READPREFERENCE "readpreference" #define MONGOC_URI_READPREFERENCETAGS "readpreferencetags" #define MONGOC_URI_REPLICASET "replicaset" #define MONGOC_URI_RETRYREADS "retryreads" #define MONGOC_URI_RETRYWRITES "retrywrites" #define MONGOC_URI_SAFE "safe" #define MONGOC_URI_SERVERMONITORINGMODE "servermonitoringmode" #define MONGOC_URI_SERVERSELECTIONTIMEOUTMS "serverselectiontimeoutms" #define MONGOC_URI_SERVERSELECTIONTRYONCE "serverselectiontryonce" #define MONGOC_URI_SLAVEOK "slaveok" #define MONGOC_URI_SOCKETCHECKINTERVALMS "socketcheckintervalms" #define MONGOC_URI_SOCKETTIMEOUTMS "sockettimeoutms" #define MONGOC_URI_SRVSERVICENAME "srvservicename" #define MONGOC_URI_SRVMAXHOSTS "srvmaxhosts" #define MONGOC_URI_TLS "tls" #define MONGOC_URI_TLSCERTIFICATEKEYFILE "tlscertificatekeyfile" #define MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD "tlscertificatekeyfilepassword" #define MONGOC_URI_TLSCAFILE "tlscafile" #define MONGOC_URI_TLSALLOWINVALIDCERTIFICATES "tlsallowinvalidcertificates" #define MONGOC_URI_TLSALLOWINVALIDHOSTNAMES "tlsallowinvalidhostnames" #define MONGOC_URI_TLSINSECURE "tlsinsecure" #define MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK "tlsdisablecertificaterevocationcheck" #define MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK "tlsdisableocspendpointcheck" #define MONGOC_URI_W "w" #define MONGOC_URI_WAITQUEUEMULTIPLE "waitqueuemultiple" #define MONGOC_URI_WAITQUEUETIMEOUTMS "waitqueuetimeoutms" #define MONGOC_URI_WTIMEOUTMS "wtimeoutms" #define MONGOC_URI_ZLIBCOMPRESSIONLEVEL "zlibcompressionlevel" /* Deprecated in MongoDB 4.2, use "tls" variants instead. */ #define MONGOC_URI_SSL "ssl" #define MONGOC_URI_SSLCLIENTCERTIFICATEKEYFILE "sslclientcertificatekeyfile" #define MONGOC_URI_SSLCLIENTCERTIFICATEKEYPASSWORD "sslclientcertificatekeypassword" #define MONGOC_URI_SSLCERTIFICATEAUTHORITYFILE "sslcertificateauthorityfile" #define MONGOC_URI_SSLALLOWINVALIDCERTIFICATES "sslallowinvalidcertificates" #define MONGOC_URI_SSLALLOWINVALIDHOSTNAMES "sslallowinvalidhostnames" BSON_BEGIN_DECLS typedef struct _mongoc_uri_t mongoc_uri_t; MONGOC_EXPORT (mongoc_uri_t *) mongoc_uri_copy (const mongoc_uri_t *uri) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_uri_destroy (mongoc_uri_t *uri); MONGOC_EXPORT (mongoc_uri_t *) mongoc_uri_new (const char *uri_string) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_uri_t *) mongoc_uri_new_with_error (const char *uri_string, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_uri_t *) mongoc_uri_new_for_host_port (const char *hostname, uint16_t port) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (const mongoc_host_list_t *) mongoc_uri_get_hosts (const mongoc_uri_t *uri); MONGOC_EXPORT (const char *) mongoc_uri_get_service (const mongoc_uri_t *uri) BSON_GNUC_DEPRECATED_FOR (mongoc_uri_get_srv_hostname); MONGOC_EXPORT (const char *) mongoc_uri_get_srv_hostname (const mongoc_uri_t *uri); MONGOC_EXPORT (const char *) mongoc_uri_get_srv_service_name (const mongoc_uri_t *uri); MONGOC_EXPORT (const char *) mongoc_uri_get_database (const mongoc_uri_t *uri); MONGOC_EXPORT (bool) mongoc_uri_set_database (mongoc_uri_t *uri, const char *database); MONGOC_EXPORT (const bson_t *) mongoc_uri_get_compressors (const mongoc_uri_t *uri); MONGOC_EXPORT (const bson_t *) mongoc_uri_get_options (const mongoc_uri_t *uri); MONGOC_EXPORT (const char *) mongoc_uri_get_password (const mongoc_uri_t *uri); MONGOC_EXPORT (bool) mongoc_uri_set_password (mongoc_uri_t *uri, const char *password); MONGOC_EXPORT (bool) mongoc_uri_has_option (const mongoc_uri_t *uri, const char *key); MONGOC_EXPORT (bool) mongoc_uri_option_is_int32 (const char *key); MONGOC_EXPORT (bool) mongoc_uri_option_is_int64 (const char *key); MONGOC_EXPORT (bool) mongoc_uri_option_is_bool (const char *key); MONGOC_EXPORT (bool) mongoc_uri_option_is_utf8 (const char *key); MONGOC_EXPORT (int32_t) mongoc_uri_get_option_as_int32 (const mongoc_uri_t *uri, const char *option, int32_t fallback); MONGOC_EXPORT (int64_t) mongoc_uri_get_option_as_int64 (const mongoc_uri_t *uri, const char *option, int64_t fallback); MONGOC_EXPORT (bool) mongoc_uri_get_option_as_bool (const mongoc_uri_t *uri, const char *option, bool fallback); MONGOC_EXPORT (const char *) mongoc_uri_get_option_as_utf8 (const mongoc_uri_t *uri, const char *option, const char *fallback); MONGOC_EXPORT (bool) mongoc_uri_set_option_as_int32 (mongoc_uri_t *uri, const char *option, int32_t value); MONGOC_EXPORT (bool) mongoc_uri_set_option_as_int64 (mongoc_uri_t *uri, const char *option, int64_t value); MONGOC_EXPORT (bool) mongoc_uri_set_option_as_bool (mongoc_uri_t *uri, const char *option, bool value); MONGOC_EXPORT (bool) mongoc_uri_set_option_as_utf8 (mongoc_uri_t *uri, const char *option, const char *value); MONGOC_EXPORT (const bson_t *) mongoc_uri_get_read_prefs (const mongoc_uri_t *uri) BSON_GNUC_DEPRECATED_FOR (mongoc_uri_get_read_prefs_t); MONGOC_EXPORT (const char *) mongoc_uri_get_replica_set (const mongoc_uri_t *uri); MONGOC_EXPORT (const char *) mongoc_uri_get_string (const mongoc_uri_t *uri); MONGOC_EXPORT (const char *) mongoc_uri_get_username (const mongoc_uri_t *uri); MONGOC_EXPORT (bool) mongoc_uri_set_username (mongoc_uri_t *uri, const char *username); MONGOC_EXPORT (const bson_t *) mongoc_uri_get_credentials (const mongoc_uri_t *uri); MONGOC_EXPORT (const char *) mongoc_uri_get_auth_source (const mongoc_uri_t *uri); MONGOC_EXPORT (bool) mongoc_uri_set_auth_source (mongoc_uri_t *uri, const char *value); MONGOC_EXPORT (const char *) mongoc_uri_get_appname (const mongoc_uri_t *uri); MONGOC_EXPORT (bool) mongoc_uri_set_appname (mongoc_uri_t *uri, const char *value); MONGOC_EXPORT (bool) mongoc_uri_set_compressors (mongoc_uri_t *uri, const char *value); MONGOC_EXPORT (const char *) mongoc_uri_get_auth_mechanism (const mongoc_uri_t *uri); MONGOC_EXPORT (bool) mongoc_uri_set_auth_mechanism (mongoc_uri_t *uri, const char *value); MONGOC_EXPORT (bool) mongoc_uri_get_mechanism_properties (const mongoc_uri_t *uri, bson_t *properties); MONGOC_EXPORT (bool) mongoc_uri_set_mechanism_properties (mongoc_uri_t *uri, const bson_t *properties); MONGOC_EXPORT (bool) mongoc_uri_get_ssl (const mongoc_uri_t *uri) BSON_GNUC_DEPRECATED_FOR (mongoc_uri_get_tls); MONGOC_EXPORT (bool) mongoc_uri_get_tls (const mongoc_uri_t *uri); MONGOC_EXPORT (char *) mongoc_uri_unescape (const char *escaped_string) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (const mongoc_read_prefs_t *) mongoc_uri_get_read_prefs_t (const mongoc_uri_t *uri); MONGOC_EXPORT (void) mongoc_uri_set_read_prefs_t (mongoc_uri_t *uri, const mongoc_read_prefs_t *prefs); MONGOC_EXPORT (const mongoc_write_concern_t *) mongoc_uri_get_write_concern (const mongoc_uri_t *uri); MONGOC_EXPORT (void) mongoc_uri_set_write_concern (mongoc_uri_t *uri, const mongoc_write_concern_t *wc); MONGOC_EXPORT (const mongoc_read_concern_t *) mongoc_uri_get_read_concern (const mongoc_uri_t *uri); MONGOC_EXPORT (void) mongoc_uri_set_read_concern (mongoc_uri_t *uri, const mongoc_read_concern_t *rc); MONGOC_EXPORT (const char *) mongoc_uri_get_server_monitoring_mode (const mongoc_uri_t *uri); MONGOC_EXPORT (bool) mongoc_uri_set_server_monitoring_mode (mongoc_uri_t *uri, const char *value); BSON_END_DECLS #endif /* MONGOC_URI_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-util-private.h0000644000175100001660000001666614760300420023603 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_UTIL_PRIVATE_H #define MONGOC_UTIL_PRIVATE_H #include #include #ifdef BSON_HAVE_STRINGS_H #include #endif #include /* string comparison functions for Windows */ #ifdef _WIN32 #define strcasecmp _stricmp #define strncasecmp _strnicmp #endif #ifndef _WIN32 #define MONGOC_PRINTF_FORMAT(a, b) __attribute__ ((format (__printf__, a, b))) #else #define MONGOC_PRINTF_FORMAT(a, b) /* no-op */ #endif #define COALESCE(x, y) ((x == 0) ? (y) : (x)) /* Helper macros for stringifying things */ #define MONGOC_STR(s) #s #define MONGOC_EVALUATE_STR(s) MONGOC_STR (s) BSON_BEGIN_DECLS extern const bson_validate_flags_t _mongoc_default_insert_vflags; extern const bson_validate_flags_t _mongoc_default_replace_vflags; extern const bson_validate_flags_t _mongoc_default_update_vflags; int _mongoc_rand_simple (unsigned int *seed); char * _mongoc_hex_md5 (const char *input); void _mongoc_usleep (int64_t usec); /* Get the current time as a number of milliseconds since the Unix Epoch. */ int64_t _mongoc_get_real_time_ms (void); const char * _mongoc_get_command_name (const bson_t *command); bool _mongoc_lookup_bool (const bson_t *bson, const char *key, bool default_value); /* Returns a database name that the caller must free. */ char * _mongoc_get_db_name (const char *ns); void _mongoc_bson_init_if_set (bson_t *bson); const char * _mongoc_bson_type_to_str (bson_type_t t); const char * _mongoc_wire_version_to_server_version (int32_t version); bool _mongoc_get_server_id_from_opts (const bson_t *opts, mongoc_error_domain_t domain, mongoc_error_code_t code, uint32_t *server_id, bson_error_t *error); bool _mongoc_validate_new_document (const bson_t *insert, bson_validate_flags_t vflags, bson_error_t *error); bool _mongoc_validate_replace (const bson_t *insert, bson_validate_flags_t vflags, bson_error_t *error); bool _mongoc_validate_update (const bson_t *update, bson_validate_flags_t vflags, bson_error_t *error); bool mongoc_ends_with (const char *str, const char *suffix); void mongoc_lowercase (const char *src, char *buf /* OUT */); bool mongoc_parse_port (uint16_t *port, const char *str); void _mongoc_bson_array_add_label (bson_t *bson, const char *label); void _mongoc_bson_array_copy_labels_to (const bson_t *reply, bson_t *dst); void _mongoc_add_transient_txn_error (const mongoc_client_session_t *cs, bson_t *reply); bool _mongoc_document_is_pipeline (const bson_t *document); /* *-------------------------------------------------------------------------- * * _mongoc_getenv -- * * Get the value of an environment variable. * * Returns: * A string you must bson_free, or NULL if the variable is not set. * * Side effects: * None. * *-------------------------------------------------------------------------- */ char * _mongoc_getenv (const char *name); /* *-------------------------------------------------------------------------- * * _mongoc_setenv -- * * Set or overwrite the value of an environment variable. * * Returns: * False if setting the variable was unsuccessful. * *-------------------------------------------------------------------------- */ bool _mongoc_setenv (const char *name, const char *value); void bson_copy_to_including_noinit (const bson_t *src, bson_t *dst, const char *first_include, ...) BSON_GNUC_NULL_TERMINATED; void bson_copy_to_including_noinit_va (const bson_t *src, bson_t *dst, const char *first_include, va_list args); /* Returns a uniformly-distributed uint32_t generated using * `_mongoc_rand_bytes()` if a source of cryptographic randomness is available * (defined only if `MONGOC_ENABLE_CRYPTO` is defined). */ uint32_t _mongoc_crypto_rand_uint32_t (void); /* Returns a uniformly-distributed uint64_t generated using * `_mongoc_rand_bytes()` if a source of cryptographic randomness is available * (defined only if `MONGOC_ENABLE_CRYPTO` is defined). */ uint64_t _mongoc_crypto_rand_uint64_t (void); /* Returns a uniformly-distributed size_t generated using * `_mongoc_rand_bytes()` if a source of cryptographic randomness is available * (defined only if `MONGOC_ENABLE_CRYPTO` is defined). */ size_t _mongoc_crypto_rand_size_t (void); /* Returns a uniformly-distributed random uint32_t generated using `rand()`. * Note: may invoke `srand()`, which may not be thread-safe. Concurrent calls to * `_mongoc_simple_rand_*()` functions, however, is thread-safe. */ uint32_t _mongoc_simple_rand_uint32_t (void); /* Returns a uniformly-distributed random uint64_t generated using `rand()`. * Note: may invoke `srand()`, which may not be thread-safe. Concurrent calls to * `_mongoc_simple_rand_*()` functions, however, is thread-safe. */ uint64_t _mongoc_simple_rand_uint64_t (void); /* Returns a uniformly-distributed random size_t generated using `rand()`. * Note: may invoke `srand()`, which may not be thread-safe. Concurrent calls to * `_mongoc_simple_rand_*()` functions, however, is thread-safe. */ size_t _mongoc_simple_rand_size_t (void); /* Returns a uniformly-distributed random integer in the range [min, max] * using the provided `rand` generator. * * The size of the range [min, max] must not equal the size of the representable * range of uint32_t (`min == 0 && max == UINT32_MAX` must not be true). * * The generator `rand` must return a random integer uniformly distributed in * the full range of representable values of uint32_t. */ uint32_t _mongoc_rand_uint32_t (uint32_t min, uint32_t max, uint32_t (*rand) (void)); /* Returns a uniformly-distributed random integer in the range [min, max] * using the provided `rand` generator. * * The size of the range [min, max] must not equal the size of the representable * range of uint64_t (`min == 0 && max == UINT64_MAX` must not be true). * * The generator `rand` must return a random integer uniformly distributed in * the full range of representable values of uint64_t. */ uint64_t _mongoc_rand_uint64_t (uint64_t min, uint64_t max, uint64_t (*rand) (void)); /* Returns a uniformly-distributed random integer in the range [min, max] * using the `_mongoc_simple_rand_size_t()` generator. * * The size of the range [min, max] must not equal the size of the representable * range of size_t (`min == 0 && max == SIZE_MAX` must not be true). */ size_t _mongoc_rand_size_t (size_t min, size_t max); /* _mongoc_iter_document_as_bson attempts to read the document from @iter into * @bson. */ bool _mongoc_iter_document_as_bson (const bson_iter_t *iter, bson_t *bson, bson_error_t *error); uint8_t * hex_to_bin (const char *hex, uint32_t *len); char * bin_to_hex (const uint8_t *bin, uint32_t len); typedef struct { bool set; uint64_t value; } mcd_optional_u64_t; BSON_END_DECLS #endif /* MONGOC_UTIL_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-util.c0000644000175100001660000005712414760300420022120 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifdef _WIN32 #define _CRT_RAND_S #endif #include #include #include #include #include #include #include #include // WIRE_VERSION_* macros. #include #include #include #include const bson_validate_flags_t _mongoc_default_insert_vflags = BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_EMPTY_KEYS; const bson_validate_flags_t _mongoc_default_replace_vflags = BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_EMPTY_KEYS; const bson_validate_flags_t _mongoc_default_update_vflags = BSON_VALIDATE_UTF8 | BSON_VALIDATE_UTF8_ALLOW_NULL | BSON_VALIDATE_EMPTY_KEYS; int _mongoc_rand_simple (unsigned int *seed) { #ifdef _WIN32 /* ignore the seed */ unsigned int ret = 0; errno_t err; err = rand_s (&ret); if (0 != err) { MONGOC_ERROR ("rand_s failed: %s", strerror (err)); } return (int) ret; #else return rand_r (seed); #endif } char * _mongoc_hex_md5 (const char *input) { uint8_t digest[16]; bson_md5_t md5; char digest_str[33]; int i; mcommon_md5_init (&md5); mcommon_md5_append (&md5, (const uint8_t *) input, (uint32_t) strlen (input)); mcommon_md5_finish (&md5, digest); for (i = 0; i < sizeof digest; i++) { // Expect no truncation. int req = bson_snprintf (&digest_str[i * 2], 3, "%02x", digest[i]); BSON_ASSERT (req < 3); } digest_str[sizeof digest_str - 1] = '\0'; return bson_strdup (digest_str); } void mongoc_client_set_usleep_impl (mongoc_client_t *client, mongoc_usleep_func_t usleep_func, void *user_data) { client->topology->usleep_fn = usleep_func; client->topology->usleep_data = user_data; } void mongoc_usleep_default_impl (int64_t usec, void *user_data) { BSON_UNUSED (user_data); #ifdef _WIN32 LARGE_INTEGER ft; HANDLE timer; BSON_ASSERT (usec >= 0); ft.QuadPart = -(10 * usec); timer = CreateWaitableTimer (NULL, true, NULL); SetWaitableTimer (timer, &ft, 0, NULL, NULL, 0); WaitForSingleObject (timer, INFINITE); CloseHandle (timer); #else BSON_ASSERT (usec >= 0); usleep ((useconds_t) usec); #endif } void _mongoc_usleep (int64_t usec) { mongoc_usleep_default_impl (usec, NULL); } int64_t _mongoc_get_real_time_ms (void) { struct timeval tv; const bool rc = bson_gettimeofday (&tv); if (rc != 0) { return -1; } return tv.tv_sec * (int64_t) 1000 + tv.tv_usec / (int64_t) 1000; } const char * _mongoc_get_command_name (const bson_t *command) { bson_iter_t iter; const char *name; bson_iter_t child; const char *wrapper_name = NULL; BSON_ASSERT (command); if (!bson_iter_init (&iter, command) || !bson_iter_next (&iter)) { return NULL; } name = bson_iter_key (&iter); /* wrapped in "$query" or "query"? * * {$query: {count: "collection"}, $readPreference: {...}} */ if (name[0] == '$') { wrapper_name = "$query"; } else if (!strcmp (name, "query")) { wrapper_name = "query"; } if (wrapper_name && bson_iter_init_find (&iter, command, wrapper_name) && BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child) && bson_iter_next (&child)) { name = bson_iter_key (&child); } return name; } bool _mongoc_lookup_bool (const bson_t *bson, const char *key, bool default_value) { bson_iter_t iter; bson_iter_t child; if (!bson) { return default_value; } BSON_ASSERT (bson_iter_init (&iter, bson)); if (!bson_iter_find_descendant (&iter, key, &child)) { return default_value; } return bson_iter_as_bool (&child); } char * _mongoc_get_db_name (const char *ns) { size_t dblen; const char *dot; BSON_ASSERT (ns); dot = strstr (ns, "."); if (dot) { dblen = dot - ns; return bson_strndup (ns, dblen); } else { return bson_strdup (ns); } } void _mongoc_bson_init_if_set (bson_t *bson) { if (bson) { bson_init (bson); } } const char * _mongoc_bson_type_to_str (bson_type_t t) { switch (t) { case BSON_TYPE_EOD: return "EOD"; case BSON_TYPE_DOUBLE: return "DOUBLE"; case BSON_TYPE_UTF8: return "UTF8"; case BSON_TYPE_DOCUMENT: return "DOCUMENT"; case BSON_TYPE_ARRAY: return "ARRAY"; case BSON_TYPE_BINARY: return "BINARY"; case BSON_TYPE_UNDEFINED: return "UNDEFINED"; case BSON_TYPE_OID: return "OID"; case BSON_TYPE_BOOL: return "BOOL"; case BSON_TYPE_DATE_TIME: return "DATE_TIME"; case BSON_TYPE_NULL: return "NULL"; case BSON_TYPE_REGEX: return "REGEX"; case BSON_TYPE_DBPOINTER: return "DBPOINTER"; case BSON_TYPE_CODE: return "CODE"; case BSON_TYPE_SYMBOL: return "SYMBOL"; case BSON_TYPE_CODEWSCOPE: return "CODEWSCOPE"; case BSON_TYPE_INT32: return "INT32"; case BSON_TYPE_TIMESTAMP: return "TIMESTAMP"; case BSON_TYPE_INT64: return "INT64"; case BSON_TYPE_MAXKEY: return "MAXKEY"; case BSON_TYPE_MINKEY: return "MINKEY"; case BSON_TYPE_DECIMAL128: return "DECIMAL128"; default: return "Unknown"; } } /* Refer to: * https://github.com/mongodb/specifications/blob/master/source/wireversion-featurelist/wireversion-featurelist.md * and: * https://github.com/mongodb/mongo/blob/master/src/mongo/db/wire_version.h#L57 */ const char * _mongoc_wire_version_to_server_version (int32_t version) { switch (version) { case 1: case 2: return "2.6"; case 3: return "3.0"; case 4: return "3.2"; case 5: return "3.4"; case 6: return "3.6"; case WIRE_VERSION_4_0: return "4.0"; case WIRE_VERSION_4_2: return "4.2"; case WIRE_VERSION_4_4: return "4.4"; case 10: return "4.7"; case 11: return "4.8"; case WIRE_VERSION_4_9: return "4.9"; case WIRE_VERSION_5_0: return "5.0"; case WIRE_VERSION_5_1: return "5.1"; case 15: return "5.2"; case 16: return "5.3"; case WIRE_VERSION_6_0: return "6.0"; case WIRE_VERSION_7_0: return "7.0"; case WIRE_VERSION_8_0: return "8.0"; default: return "Unknown"; } } /* Get "serverId" from opts. Sets *server_id to the serverId from "opts" or 0 * if absent. On error, fills out *error with domain and code and return false. */ bool _mongoc_get_server_id_from_opts ( const bson_t *opts, mongoc_error_domain_t domain, mongoc_error_code_t code, uint32_t *server_id, bson_error_t *error) { bson_iter_t iter; ENTRY; BSON_ASSERT (server_id); *server_id = 0; if (!opts || !bson_iter_init_find (&iter, opts, "serverId")) { RETURN (true); } if (!BSON_ITER_HOLDS_INT (&iter)) { bson_set_error (error, domain, code, "The serverId option must be an integer"); RETURN (false); } if (bson_iter_as_int64 (&iter) <= 0) { bson_set_error (error, domain, code, "The serverId option must be >= 1"); RETURN (false); } *server_id = (uint32_t) bson_iter_as_int64 (&iter); RETURN (true); } bool _mongoc_validate_new_document (const bson_t *doc, bson_validate_flags_t vflags, bson_error_t *error) { bson_error_t validate_err; if (vflags == BSON_VALIDATE_NONE) { return true; } if (!bson_validate_with_error (doc, vflags, &validate_err)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "invalid document for insert: %s", validate_err.message); return false; } return true; } bool _mongoc_validate_replace (const bson_t *doc, bson_validate_flags_t vflags, bson_error_t *error) { bson_error_t validate_err; bson_iter_t iter; const char *key; if (vflags == BSON_VALIDATE_NONE) { return true; } if (!bson_validate_with_error (doc, vflags, &validate_err)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "invalid argument for replace: %s", validate_err.message); return false; } if (!bson_iter_init (&iter, doc)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "replace document is corrupt"); return false; } while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (key[0] == '$') { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid key '%s': replace prohibits $ operators", key); return false; } } return true; } bool _mongoc_validate_update (const bson_t *update, bson_validate_flags_t vflags, bson_error_t *error) { bson_error_t validate_err; bson_iter_t iter; const char *key; if (vflags == BSON_VALIDATE_NONE) { return true; } if (!bson_validate_with_error (update, vflags, &validate_err)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "invalid argument for update: %s", validate_err.message); return false; } if (_mongoc_document_is_pipeline (update)) { return true; } if (!bson_iter_init (&iter, update)) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "update document is corrupt"); return false; } while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); if (key[0] != '$') { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid key '%s': update only works with $ operators" " and pipelines", key); return false; } } return true; } static bool should_include (const char *first_include, va_list args, const char *name) { bool ret = false; const char *include = first_include; va_list args_copy; va_copy (args_copy, args); do { if (!strcmp (name, include)) { ret = true; break; } } while ((include = va_arg (args_copy, const char *))); va_end (args_copy); return ret; } void bson_copy_to_including_noinit_va (const bson_t *src, bson_t *dst, const char *first_include, va_list args) { BSON_ASSERT_PARAM (src); BSON_ASSERT_PARAM (dst); BSON_ASSERT_PARAM (first_include); bson_iter_t iter; if (bson_iter_init (&iter, src)) { while (bson_iter_next (&iter)) { if (should_include (first_include, args, bson_iter_key (&iter))) { if (!bson_append_iter (dst, NULL, 0, &iter)) { /* * This should not be able to happen since we are copying * from within a valid bson_t. */ BSON_ASSERT (false); return; } } } } } void bson_copy_to_including_noinit (const bson_t *src, bson_t *dst, const char *first_include, ...) { BSON_ASSERT_PARAM (src); BSON_ASSERT_PARAM (dst); BSON_ASSERT_PARAM (first_include); va_list args; va_start (args, first_include); bson_copy_to_including_noinit_va (src, dst, first_include, args); va_end (args); } /* *-------------------------------------------------------------------------- * * mongoc_ends_with -- * * Return true if str ends with suffix. * *-------------------------------------------------------------------------- */ bool mongoc_ends_with (const char *str, const char *suffix) { BSON_ASSERT_PARAM (str); BSON_ASSERT_PARAM (suffix); const size_t str_len = strlen (str); const size_t suffix_len = strlen (suffix); if (str_len < suffix_len) { return false; } return strcmp (str + (str_len - suffix_len), suffix) == 0; } void mongoc_lowercase (const char *src, char *buf /* OUT */) { for (; *src; ++src, ++buf) { /* UTF8 non-ascii characters have a 1 at the leftmost bit. If this is the * case, just copy */ if ((*src & (0x1 << 7)) == 0) { *buf = (char) tolower (*src); } else { *buf = *src; } } } bool mongoc_parse_port (uint16_t *port, const char *str) { unsigned long ul_port; ul_port = strtoul (str, NULL, 10); if (ul_port == 0 || ul_port > UINT16_MAX) { /* Parse error or port number out of range. mongod prohibits port 0. */ return false; } *port = (uint16_t) ul_port; return true; } /*-------------------------------------------------------------------------- * * _mongoc_bson_array_add_label -- * * Append an error label like "TransientTransactionError" to a BSON * array iff the array does not already contain it. * * Side effects: * Aborts if the array is invalid or contains non-string elements. * *-------------------------------------------------------------------------- */ void _mongoc_bson_array_add_label (bson_t *bson, const char *label) { bson_iter_t iter; char buf[16]; uint32_t i = 0; const char *key; BSON_ASSERT (bson_iter_init (&iter, bson)); while (bson_iter_next (&iter)) { if (!strcmp (bson_iter_utf8 (&iter, NULL), label)) { /* already included once */ return; } i++; } bson_uint32_to_string (i, &key, buf, sizeof buf); BSON_APPEND_UTF8 (bson, key, label); } /*-------------------------------------------------------------------------- * * _mongoc_bson_array_copy_labels_to -- * * Copy error labels like "TransientTransactionError" from a server * reply to a BSON array iff the array does not already contain it. * * Side effects: * Aborts if @dst is invalid or contains non-string elements. * *-------------------------------------------------------------------------- */ void _mongoc_bson_array_copy_labels_to (const bson_t *reply, bson_t *dst) { bson_iter_t iter; bson_iter_t label; if (bson_iter_init_find (&iter, reply, "errorLabels")) { BSON_ASSERT (bson_iter_recurse (&iter, &label)); while (bson_iter_next (&label)) { if (BSON_ITER_HOLDS_UTF8 (&label)) { _mongoc_bson_array_add_label (dst, bson_iter_utf8 (&label, NULL)); } } } } /*-------------------------------------------------------------------------- * * _mongoc_add_transient_txn_error -- * * If @cs is not NULL and in a transaction, add errorLabels: * ["TransientTransactionError"] to @reply. * * Transactions Spec: TransientTransactionError includes "server * selection error encountered running any command besides * commitTransaction in a transaction. ...in the case of network errors * or server selection errors where the client receives no server reply, * the client adds the label." * * Side effects: * None. * *-------------------------------------------------------------------------- */ void _mongoc_add_transient_txn_error (const mongoc_client_session_t *cs, bson_t *reply) { if (!reply) { return; } if (_mongoc_client_session_in_txn (cs)) { bson_t labels = BSON_INITIALIZER; _mongoc_bson_array_copy_labels_to (reply, &labels); _mongoc_bson_array_add_label (&labels, TRANSIENT_TXN_ERR); bson_t new_reply = BSON_INITIALIZER; bson_copy_to_excluding_noinit (reply, &new_reply, "errorLabels", NULL); BSON_APPEND_ARRAY (&new_reply, "errorLabels", &labels); bson_reinit (reply); bson_concat (reply, &new_reply); bson_destroy (&labels); bson_destroy (&new_reply); } } bool _mongoc_document_is_pipeline (const bson_t *document) { bson_iter_t iter; bson_iter_t child; const char *key; int i = 0; char *i_str; if (!bson_iter_init (&iter, document)) { return false; } while (bson_iter_next (&iter)) { key = bson_iter_key (&iter); i_str = bson_strdup_printf ("%d", i++); if (strcmp (key, i_str)) { bson_free (i_str); return false; } bson_free (i_str); if (BSON_ITER_HOLDS_DOCUMENT (&iter)) { if (!bson_iter_recurse (&iter, &child)) { return false; } if (!bson_iter_next (&child)) { return false; } key = bson_iter_key (&child); if (key[0] != '$') { return false; } } else { return false; } } /* should return false when the document is empty */ return i != 0; } char * _mongoc_getenv (const char *name) { #ifdef _MSC_VER char buf[2048]; size_t buflen; if ((0 == getenv_s (&buflen, buf, sizeof buf, name)) && buflen) { return bson_strdup (buf); } else { return NULL; } #else char *const var = getenv (name); if (var && strlen (var)) { return bson_strdup (var); } else { return NULL; } #endif } bool _mongoc_setenv (const char *name, const char *value) { #ifdef _WIN32 return SetEnvironmentVariableA (name, value) != 0; #else if (0 != setenv (name, value, 1)) { return false; } return true; #endif } /* Nearly Divisionless (Algorithm 5): https://arxiv.org/abs/1805.10941 */ static uint32_t _mongoc_rand_nduid32 (uint32_t s, uint32_t (*rand32) (void)) { const uint64_t limit = UINT32_MAX; /* 2^L */ uint64_t x, m, l; x = rand32 (); m = x * s; l = m % limit; if (l < s) { const uint64_t t = (limit - s) % s; while (l < t) { x = rand32 (); m = x * s; l = m % limit; } } return (uint32_t) (m / limit); } /* Java Algorithm (Algorithm 4): https://arxiv.org/abs/1805.10941 * The 64-bit version of the nearly divisionless algorithm requires 128-bit * integer arithmetic. Instead of trying to deal with cross-platform support for * `__int128`, fallback to using the Java algorithm for 64-bit instead. */ static uint64_t _mongoc_rand_java64 (uint64_t s, uint64_t (*rand64) (void)) { const uint64_t limit = UINT64_MAX; /* 2^L */ uint64_t x, r; x = rand64 (); r = x % s; while ((x - r) > (limit - s)) { x = rand64 (); r = x % s; } return r; } #if defined(MONGOC_ENABLE_CRYPTO) uint32_t _mongoc_crypto_rand_uint32_t (void) { uint32_t res; (void) _mongoc_rand_bytes ((uint8_t *) &res, sizeof (res)); return res; } uint64_t _mongoc_crypto_rand_uint64_t (void) { uint64_t res; (void) _mongoc_rand_bytes ((uint8_t *) &res, sizeof (res)); return res; } size_t _mongoc_crypto_rand_size_t (void) { size_t res; (void) _mongoc_rand_bytes ((uint8_t *) &res, sizeof (res)); return res; } #endif /* defined(MONGOC_ENABLE_CRYPTO) */ static BSON_ONCE_FUN (_mongoc_simple_rand_init) { struct timeval tv; unsigned int seed = 0; bson_gettimeofday (&tv); seed ^= (unsigned int) tv.tv_sec; seed ^= (unsigned int) tv.tv_usec; srand (seed); BSON_ONCE_RETURN; } static bson_once_t _mongoc_simple_rand_init_once = BSON_ONCE_INIT; uint32_t _mongoc_simple_rand_uint32_t (void) { bson_once (&_mongoc_simple_rand_init_once, _mongoc_simple_rand_init); /* Ensure *all* bits are random, as RAND_MAX is only required to be at least * 32767 (2^15). */ return (((uint32_t) rand () & 0x7FFFu) << 0u) | (((uint32_t) rand () & 0x7FFFu) << 15u) | (((uint32_t) rand () & 0x0003u) << 30u); } uint64_t _mongoc_simple_rand_uint64_t (void) { bson_once (&_mongoc_simple_rand_init_once, _mongoc_simple_rand_init); /* Ensure *all* bits are random, as RAND_MAX is only required to be at least * 32767 (2^15). */ return (((uint64_t) rand () & 0x7FFFu) << 0u) | (((uint64_t) rand () & 0x7FFFu) << 15u) | (((uint64_t) rand () & 0x7FFFu) << 30u) | (((uint64_t) rand () & 0x7FFFu) << 45u) | (((uint64_t) rand () & 0x0003u) << 60u); } uint32_t _mongoc_rand_uint32_t (uint32_t min, uint32_t max, uint32_t (*rand) (void)) { BSON_ASSERT (min <= max); BSON_ASSERT (min != 0u || max != UINT32_MAX); return _mongoc_rand_nduid32 (max - min + 1u, rand) + min; } uint64_t _mongoc_rand_uint64_t (uint64_t min, uint64_t max, uint64_t (*rand) (void)) { BSON_ASSERT (min <= max); BSON_ASSERT (min != 0u || max != UINT64_MAX); return _mongoc_rand_java64 (max - min + 1u, rand) + min; } #if SIZE_MAX == UINT64_MAX BSON_STATIC_ASSERT2 (_mongoc_simple_rand_size_t, sizeof (size_t) == sizeof (uint64_t)); size_t _mongoc_simple_rand_size_t (void) { return (size_t) _mongoc_simple_rand_uint64_t (); } size_t _mongoc_rand_size_t (size_t min, size_t max) { BSON_ASSERT (min <= max); BSON_ASSERT (min != 0u || max != UINT64_MAX); return _mongoc_rand_java64 (max - min + 1u, &_mongoc_simple_rand_uint64_t) + min; } #elif SIZE_MAX == UINT32_MAX BSON_STATIC_ASSERT2 (_mongoc_simple_rand_size_t, sizeof (size_t) == sizeof (uint32_t)); size_t _mongoc_simple_rand_size_t (void) { return (size_t) _mongoc_simple_rand_uint32_t (); } size_t _mongoc_rand_size_t (size_t min, size_t max) { BSON_ASSERT (min <= max); BSON_ASSERT (min != 0u || max != UINT32_MAX); return _mongoc_rand_nduid32 (max - min + 1u, &_mongoc_simple_rand_uint32_t) + min; } #else #error "Implementation of _mongoc_simple_rand_size_t() requires size_t be exactly 32-bit or 64-bit" #endif bool _mongoc_iter_document_as_bson (const bson_iter_t *iter, bson_t *bson, bson_error_t *error) { uint32_t len; const uint8_t *data; if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "expected BSON document for field: %s", bson_iter_key (iter)); return false; } bson_iter_document (iter, &len, &data); if (!bson_init_static (bson, data, len)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "unable to initialize BSON document from field: %s", bson_iter_key (iter)); return false; } return true; } uint8_t * hex_to_bin (const char *hex, uint32_t *len) { uint8_t *out; const size_t hex_len = strlen (hex); if (hex_len % 2u != 0u) { return NULL; } BSON_ASSERT (mcommon_in_range_unsigned (uint32_t, hex_len / 2u)); *len = (uint32_t) (hex_len / 2u); out = bson_malloc0 (*len); for (uint32_t i = 0; i < hex_len; i += 2u) { uint32_t hex_char; if (1 != sscanf (hex + i, "%2x", &hex_char)) { bson_free (out); return NULL; } BSON_ASSERT (mcommon_in_range_unsigned (uint8_t, hex_char)); out[i / 2u] = (uint8_t) hex_char; } return out; } char * bin_to_hex (const uint8_t *bin, uint32_t len) { char *out = bson_malloc0 (2u * len + 1u); for (uint32_t i = 0u; i < len; i++) { // Expect no truncation. int req = bson_snprintf (out + (2u * i), 3, "%02x", bin[i]); BSON_ASSERT (req < 3); } return out; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version-functions.c0000644000175100001660000000325514760300420024632 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include /** * mongoc_get_major_version: * * Helper function to return the runtime major version of the library. */ int mongoc_get_major_version (void) { return MONGOC_MAJOR_VERSION; } /** * mongoc_get_minor_version: * * Helper function to return the runtime minor version of the library. */ int mongoc_get_minor_version (void) { return MONGOC_MINOR_VERSION; } /** * mongoc_get_micro_version: * * Helper function to return the runtime micro version of the library. */ int mongoc_get_micro_version (void) { return MONGOC_MICRO_VERSION; } /** * mongoc_get_version: * * Helper function to return the runtime string version of the library. */ const char * mongoc_get_version (void) { return MONGOC_VERSION_S; } /** * mongoc_check_version: * * True if libmongoc's version is greater than or equal to the required * version. */ bool mongoc_check_version (int required_major, int required_minor, int required_micro) { return MONGOC_CHECK_VERSION (required_major, required_minor, required_micro); } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version-functions.h0000644000175100001660000000223614760300420024635 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_VERSION_FUNCTIONS_H #define MONGOC_VERSION_FUNCTIONS_H #include /* for "bool" */ #include BSON_BEGIN_DECLS MONGOC_EXPORT (int) mongoc_get_major_version (void); MONGOC_EXPORT (int) mongoc_get_minor_version (void); MONGOC_EXPORT (int) mongoc_get_micro_version (void); MONGOC_EXPORT (const char *) mongoc_get_version (void); MONGOC_EXPORT (bool) mongoc_check_version (int required_major, int required_minor, int required_micro); BSON_END_DECLS #endif /* MONGOC_VERSION_FUNCTIONS_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version.h0000644000175100001660000000473014760300420022630 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(MONGOC_INSIDE) && !defined(MONGOC_COMPILATION) #error "Only can be included directly." #endif // clang-format off #ifndef MONGOC_VERSION_H #define MONGOC_VERSION_H /** * MONGOC_MAJOR_VERSION: * * MONGOC major version component (e.g. 1 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MAJOR_VERSION (1) /** * MONGOC_MINOR_VERSION: * * MONGOC minor version component (e.g. 2 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MINOR_VERSION (30) /** * MONGOC_MICRO_VERSION: * * MONGOC micro version component (e.g. 3 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MICRO_VERSION (1) /** * MONGOC_PRERELEASE_VERSION: * * MONGOC prerelease version component (e.g. pre if %MONGOC_VERSION is 1.2.3-pre) */ #define MONGOC_PRERELEASE_VERSION () /** * MONGOC_VERSION: * * MONGOC version. */ #define MONGOC_VERSION (1.30.1) /** * MONGOC_VERSION_S: * * MONGOC version, encoded as a string, useful for printing and * concatenation. */ #define MONGOC_VERSION_S "1.30.1" /** * MONGOC_VERSION_HEX: * * MONGOC version, encoded as an hexadecimal number, useful for * integer comparisons. */ #define MONGOC_VERSION_HEX (MONGOC_MAJOR_VERSION << 24 | \ MONGOC_MINOR_VERSION << 16 | \ MONGOC_MICRO_VERSION << 8) /** * MONGOC_CHECK_VERSION: * @major: required major version * @minor: required minor version * @micro: required micro version * * Compile-time version checking. Evaluates to %TRUE if the version * of MONGOC is greater than or equal to the required one. */ #define MONGOC_CHECK_VERSION(major,minor,micro) \ (MONGOC_MAJOR_VERSION > (major) || \ (MONGOC_MAJOR_VERSION == (major) && MONGOC_MINOR_VERSION > (minor)) || \ (MONGOC_MAJOR_VERSION == (major) && MONGOC_MINOR_VERSION == (minor) && \ MONGOC_MICRO_VERSION >= (micro))) #endif /* MONGOC_VERSION_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version.h.in0000644000175100001660000000514114760300420023232 0ustar /* * Copyright 2009-present MongoDB, 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. */ #if !defined(MONGOC_INSIDE) && !defined(MONGOC_COMPILATION) #error "Only can be included directly." #endif // clang-format off #ifndef MONGOC_VERSION_H #define MONGOC_VERSION_H /** * MONGOC_MAJOR_VERSION: * * MONGOC major version component (e.g. 1 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MAJOR_VERSION (@libmongoc_VERSION_MAJOR@) /** * MONGOC_MINOR_VERSION: * * MONGOC minor version component (e.g. 2 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MINOR_VERSION (@libmongoc_VERSION_MINOR@) /** * MONGOC_MICRO_VERSION: * * MONGOC micro version component (e.g. 3 if %MONGOC_VERSION is 1.2.3) */ #define MONGOC_MICRO_VERSION (@libmongoc_VERSION_PATCH@) /** * MONGOC_PRERELEASE_VERSION: * * MONGOC prerelease version component (e.g. pre if %MONGOC_VERSION is 1.2.3-pre) */ #define MONGOC_PRERELEASE_VERSION (@libmongoc_VERSION_PRERELEASE@) /** * MONGOC_VERSION: * * MONGOC version. */ #define MONGOC_VERSION (@libmongoc_VERSION_FULL@) /** * MONGOC_VERSION_S: * * MONGOC version, encoded as a string, useful for printing and * concatenation. */ #define MONGOC_VERSION_S "@libmongoc_VERSION_FULL@" /** * MONGOC_VERSION_HEX: * * MONGOC version, encoded as an hexadecimal number, useful for * integer comparisons. */ #define MONGOC_VERSION_HEX (MONGOC_MAJOR_VERSION << 24 | \ MONGOC_MINOR_VERSION << 16 | \ MONGOC_MICRO_VERSION << 8) /** * MONGOC_CHECK_VERSION: * @major: required major version * @minor: required minor version * @micro: required micro version * * Compile-time version checking. Evaluates to %TRUE if the version * of MONGOC is greater than or equal to the required one. */ #define MONGOC_CHECK_VERSION(major,minor,micro) \ (MONGOC_MAJOR_VERSION > (major) || \ (MONGOC_MAJOR_VERSION == (major) && MONGOC_MINOR_VERSION > (minor)) || \ (MONGOC_MAJOR_VERSION == (major) && MONGOC_MINOR_VERSION == (minor) && \ MONGOC_MICRO_VERSION >= (micro))) #endif /* MONGOC_VERSION_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-write-command-private.h0000644000175100001660000001770114760300420025363 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_WRITE_COMMAND_PRIVATE_H #define MONGOC_WRITE_COMMAND_PRIVATE_H #include #include #include #include #include #include BSON_BEGIN_DECLS /* forward decl */ struct _mongoc_crud_opts_t; #define MONGOC_WRITE_COMMAND_DELETE 0 #define MONGOC_WRITE_COMMAND_INSERT 1 #define MONGOC_WRITE_COMMAND_UPDATE 2 /* MongoDB has a extra allowance to allow updating 16mb document, as the update * operators would otherwise overflow the 16mb object limit. See SERVER-10643 * for context. */ #define BSON_OBJECT_ALLOWANCE (16 * 1024) #define RETRYABLE_WRITE_ERROR "RetryableWriteError" struct _mongoc_bulk_write_flags_t { bool ordered; bool bypass_document_validation; bool has_collation; bool has_multi_write; bool has_array_filters; bool has_update_hint; bool has_delete_hint; }; typedef struct { int type; mongoc_buffer_t payload; uint32_t n_documents; mongoc_bulk_write_flags_t flags; int64_t operation_id; bson_t cmd_opts; } mongoc_write_command_t; typedef struct { uint32_t nInserted; uint32_t nMatched; uint32_t nModified; uint32_t nRemoved; uint32_t nUpserted; /* like [{"index": int, "code": int, "errmsg": str}, ...] */ bson_t writeErrors; /* like [{"index": int, "_id": value}, ...] */ bson_t upserted; uint32_t n_writeConcernErrors; /* like [{"code": 64, "errmsg": "duplicate"}, ...] */ bson_t writeConcernErrors; /* like ["TransientTransactionError", ...] */ bson_t errorLabels; bool failed; /* The command failed */ bool must_stop; /* The stream may have been disconnected */ bson_error_t error; uint32_t upsert_append_count; /* If the command initially failed with a retryable write, and selected a new * primary, this contains the server id of the newly selected primary. Only * applies to OP_MSG. Is left at 0 if no retry occurs. */ uint32_t retry_server_id; /* store the raw server response if an error occured */ uint32_t n_errorReplies; bson_t rawErrorReplies; } mongoc_write_result_t; typedef enum { MONGOC_WRITE_ERR_NONE, MONGOC_WRITE_ERR_OTHER, MONGOC_WRITE_ERR_RETRY, MONGOC_WRITE_ERR_WRITE_CONCERN, } mongoc_write_err_type_t; void _mongoc_write_command_destroy (mongoc_write_command_t *command); void _mongoc_write_command_init (bson_t *doc, mongoc_write_command_t *command, const char *collection); void _mongoc_write_command_init_insert (mongoc_write_command_t *command, const bson_t *document, const bson_t *cmd_opts, mongoc_bulk_write_flags_t flags, int64_t operation_id); void _mongoc_write_command_init_insert_one_idl (mongoc_write_command_t *command, const bson_t *document, const bson_t *cmd_opts, bson_t *insert_id, int64_t operation_id); void _mongoc_write_command_init_insert_idl (mongoc_write_command_t *command, const bson_t *document, const bson_t *cmd_opts, int64_t operation_id); void _mongoc_write_command_init_delete (mongoc_write_command_t *command, const bson_t *selectors, const bson_t *cmd_opts, const bson_t *opts, mongoc_bulk_write_flags_t flags, int64_t operation_id); void _mongoc_write_command_init_delete_idl (mongoc_write_command_t *command, const bson_t *selector, const bson_t *cmd_opts, const bson_t *opts, int64_t operation_id); void _mongoc_write_command_init_update (mongoc_write_command_t *command, const bson_t *selector, const bson_t *update, const bson_t *cmd_opts, const bson_t *opts, mongoc_bulk_write_flags_t flags, int64_t operation_id); void _mongoc_write_command_init_update_idl (mongoc_write_command_t *command, const bson_t *selector, const bson_t *update, const bson_t *cmd_opts, const bson_t *opts, int64_t operation_id); void _mongoc_write_command_insert_append (mongoc_write_command_t *command, const bson_t *document); void _mongoc_write_command_update_append (mongoc_write_command_t *command, const bson_t *selector, const bson_t *update, const bson_t *opts); void _mongoc_write_command_delete_append (mongoc_write_command_t *command, const bson_t *selector, const bson_t *opts); void _mongoc_write_command_execute (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t offset, mongoc_client_session_t *cs, mongoc_write_result_t *result); void _mongoc_write_command_execute_idl (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, uint32_t offset, const struct _mongoc_crud_opts_t *crud, mongoc_write_result_t *result); const char * _mongoc_write_command_get_name (const mongoc_write_command_t *command); void _mongoc_write_result_init (mongoc_write_result_t *result); #define MONGOC_WRITE_RESULT_COMPLETE(_result, ...) _mongoc_write_result_complete (_result, __VA_ARGS__, NULL) bool _mongoc_write_result_complete (mongoc_write_result_t *result, int32_t error_api_version, const mongoc_write_concern_t *wc, mongoc_error_domain_t err_domain_override, bson_t *reply, bson_error_t *error, ...); void _mongoc_write_result_destroy (mongoc_write_result_t *result); mongoc_write_err_type_t _mongoc_write_error_get_type (bson_t *reply); bool _mongoc_write_error_update_if_unsupported_storage_engine (bool cmd_ret, bson_error_t *cmd_err, bson_t *reply); BSON_END_DECLS #endif /* MONGOC_WRITE_COMMAND_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-write-command.c0000644000175100001660000012254214760300420023706 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* indexed by MONGOC_WRITE_COMMAND_DELETE, INSERT, UPDATE */ static const char *gCommandNames[] = {"delete", "insert", "update"}; static const char *gCommandFields[] = {"deletes", "documents", "updates"}; static const uint32_t gCommandFieldLens[] = {7, 9, 7}; void _mongoc_write_command_insert_append (mongoc_write_command_t *command, const bson_t *document) { bson_iter_t iter; bson_oid_t oid; bson_t tmp; ENTRY; BSON_ASSERT (command); BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_INSERT); BSON_ASSERT (document); BSON_ASSERT (document->len >= 5); /* * If the document does not contain an "_id" field, we need to generate * a new oid for "_id". */ if (!bson_iter_init_find (&iter, document, "_id")) { bson_init (&tmp); bson_oid_init (&oid, NULL); BSON_APPEND_OID (&tmp, "_id", &oid); bson_concat (&tmp, document); _mongoc_buffer_append (&command->payload, bson_get_data (&tmp), tmp.len); bson_destroy (&tmp); } else { _mongoc_buffer_append (&command->payload, bson_get_data (document), document->len); } command->n_documents++; EXIT; } void _mongoc_write_command_update_append (mongoc_write_command_t *command, const bson_t *selector, const bson_t *update, const bson_t *opts) { bson_t document; ENTRY; BSON_ASSERT (command); BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_UPDATE); BSON_ASSERT (selector && update); bson_init (&document); BSON_APPEND_DOCUMENT (&document, "q", selector); if (_mongoc_document_is_pipeline (update)) { BSON_APPEND_ARRAY (&document, "u", update); } else { BSON_APPEND_DOCUMENT (&document, "u", update); } if (opts) { bson_concat (&document, opts); } _mongoc_buffer_append (&command->payload, bson_get_data (&document), document.len); command->n_documents++; bson_destroy (&document); EXIT; } void _mongoc_write_command_delete_append (mongoc_write_command_t *command, const bson_t *selector, const bson_t *opts) { bson_t document; ENTRY; BSON_ASSERT (command); BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_DELETE); BSON_ASSERT (selector); BSON_ASSERT (selector->len >= 5); bson_init (&document); BSON_APPEND_DOCUMENT (&document, "q", selector); if (opts) { bson_concat (&document, opts); } _mongoc_buffer_append (&command->payload, bson_get_data (&document), document.len); command->n_documents++; bson_destroy (&document); EXIT; } static void _mongoc_write_command_init_bulk ( mongoc_write_command_t *command, int type, mongoc_bulk_write_flags_t flags, int64_t operation_id, const bson_t *opts) { ENTRY; BSON_ASSERT (command); command->type = type; command->flags = flags; command->operation_id = operation_id; if (!bson_empty0 (opts)) { bson_copy_to (opts, &command->cmd_opts); } else { bson_init (&command->cmd_opts); } _mongoc_buffer_init (&command->payload, NULL, 0, NULL, NULL); command->n_documents = 0; EXIT; } void _mongoc_write_command_init_insert (mongoc_write_command_t *command, /* IN */ const bson_t *document, /* IN */ const bson_t *cmd_opts, /* IN */ mongoc_bulk_write_flags_t flags, /* IN */ int64_t operation_id) /* IN */ { ENTRY; BSON_ASSERT (command); _mongoc_write_command_init_bulk (command, MONGOC_WRITE_COMMAND_INSERT, flags, operation_id, cmd_opts); /* must handle NULL document from mongoc_collection_insert_bulk */ if (document) { _mongoc_write_command_insert_append (command, document); } EXIT; } // `_mongoc_write_command_init_insert_one_idl` returns the inserted ID in `inserted_id`. // Only called by mongoc_collection_insert_one. void _mongoc_write_command_init_insert_one_idl (mongoc_write_command_t *command, const bson_t *document, const bson_t *cmd_opts, bson_t *insert_id, int64_t operation_id) { mongoc_bulk_write_flags_t flags = MONGOC_BULK_WRITE_FLAGS_INIT; ENTRY; BSON_ASSERT_PARAM (command); BSON_ASSERT_PARAM (document); BSON_ASSERT_PARAM (cmd_opts); BSON_ASSERT_PARAM (insert_id); _mongoc_write_command_init_bulk (command, MONGOC_WRITE_COMMAND_INSERT, flags, operation_id, cmd_opts); /* near identical to _mongoc_write_command_insert_append but additionally records the inserted id */ /* no need to handle NULL document from mongoc_collection_insert_bulk since only called by insert_one */ BSON_ASSERT (command->type == MONGOC_WRITE_COMMAND_INSERT); BSON_ASSERT (document->len >= 5); bson_iter_t iter; bson_oid_t oid; bson_t tmp; /* * If the document does not contain an "_id" field, we need to generate * a new oid for "_id". */ if (!bson_iter_init_find (&iter, document, "_id")) { bson_init (&tmp); bson_oid_init (&oid, NULL); BSON_APPEND_OID (&tmp, "_id", &oid); bson_concat (&tmp, document); _mongoc_buffer_append (&command->payload, bson_get_data (&tmp), tmp.len); BSON_APPEND_OID (insert_id, "insertedId", &oid); bson_destroy (&tmp); } else { _mongoc_buffer_append (&command->payload, bson_get_data (document), document->len); BSON_APPEND_VALUE (insert_id, "insertedId", bson_iter_value (&iter)); } command->n_documents++; EXIT; } void _mongoc_write_command_init_insert_idl (mongoc_write_command_t *command, const bson_t *document, const bson_t *cmd_opts, int64_t operation_id) { mongoc_bulk_write_flags_t flags = MONGOC_BULK_WRITE_FLAGS_INIT; ENTRY; BSON_ASSERT (command); _mongoc_write_command_init_bulk (command, MONGOC_WRITE_COMMAND_INSERT, flags, operation_id, cmd_opts); /* must handle NULL document from mongoc_collection_insert_bulk */ if (document) { _mongoc_write_command_insert_append (command, document); } EXIT; } void _mongoc_write_command_init_delete (mongoc_write_command_t *command, /* IN */ const bson_t *selector, /* IN */ const bson_t *cmd_opts, /* IN */ const bson_t *opts, /* IN */ mongoc_bulk_write_flags_t flags, /* IN */ int64_t operation_id) /* IN */ { ENTRY; BSON_ASSERT (command); BSON_ASSERT (selector); _mongoc_write_command_init_bulk (command, MONGOC_WRITE_COMMAND_DELETE, flags, operation_id, cmd_opts); _mongoc_write_command_delete_append (command, selector, opts); EXIT; } void _mongoc_write_command_init_delete_idl (mongoc_write_command_t *command, const bson_t *selector, const bson_t *cmd_opts, const bson_t *opts, int64_t operation_id) { mongoc_bulk_write_flags_t flags = MONGOC_BULK_WRITE_FLAGS_INIT; ENTRY; BSON_ASSERT (command); BSON_ASSERT (selector); _mongoc_write_command_init_bulk (command, MONGOC_WRITE_COMMAND_DELETE, flags, operation_id, cmd_opts); _mongoc_write_command_delete_append (command, selector, opts); EXIT; } void _mongoc_write_command_init_update (mongoc_write_command_t *command, /* IN */ const bson_t *selector, /* IN */ const bson_t *update, /* IN */ const bson_t *cmd_opts, /* IN */ const bson_t *opts, /* IN */ mongoc_bulk_write_flags_t flags, /* IN */ int64_t operation_id) /* IN */ { ENTRY; BSON_ASSERT (command); BSON_ASSERT (selector); BSON_ASSERT (update); _mongoc_write_command_init_bulk (command, MONGOC_WRITE_COMMAND_UPDATE, flags, operation_id, cmd_opts); _mongoc_write_command_update_append (command, selector, update, opts); EXIT; } void _mongoc_write_command_init_update_idl (mongoc_write_command_t *command, const bson_t *selector, const bson_t *update, const bson_t *cmd_opts, const bson_t *opts, int64_t operation_id) { mongoc_bulk_write_flags_t flags = MONGOC_BULK_WRITE_FLAGS_INIT; ENTRY; BSON_ASSERT (command); _mongoc_write_command_init_bulk (command, MONGOC_WRITE_COMMAND_UPDATE, flags, operation_id, cmd_opts); _mongoc_write_command_update_append (command, selector, update, opts); EXIT; } const char * _mongoc_write_command_get_name (const mongoc_write_command_t *command) { BSON_ASSERT_PARAM (command); BSON_ASSERT (command->type >= 0 && command->type < (int) (sizeof gCommandNames / sizeof gCommandNames[0])); return gCommandNames[command->type]; } /* takes initialized bson_t *doc and begins formatting a write command */ void _mongoc_write_command_init (bson_t *doc, mongoc_write_command_t *command, const char *collection) { ENTRY; if (!command->n_documents) { EXIT; } BSON_APPEND_UTF8 (doc, _mongoc_write_command_get_name (command), collection); BSON_APPEND_BOOL (doc, "ordered", command->flags.ordered); if (command->flags.bypass_document_validation) { BSON_APPEND_BOOL (doc, "bypassDocumentValidation", command->flags.bypass_document_validation); } EXIT; } /* *------------------------------------------------------------------------- * * _mongoc_write_command_too_large_error -- * * Fill a bson_error_t and optional bson_t with error info after * receiving a document for bulk insert, update, or remove that is * larger than max_bson_size. * * "err_doc" should be NULL or an empty initialized bson_t. * * Returns: * None. * * Side effects: * "error" and optionally "err_doc" are filled out. * *------------------------------------------------------------------------- */ static void _mongoc_write_command_too_large_error (bson_error_t *error, int32_t idx, int32_t len, int32_t max_bson_size) { bson_set_error (error, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "Document %" PRId32 " is too large for the cluster. " "Document is %" PRId32 " bytes, max is %" PRId32 ".", idx, len, max_bson_size); } static void _empty_error (mongoc_write_command_t *command, bson_error_t *error) { static const uint32_t codes[] = {MONGOC_ERROR_COLLECTION_DELETE_FAILED, MONGOC_ERROR_COLLECTION_INSERT_FAILED, MONGOC_ERROR_COLLECTION_UPDATE_FAILED}; bson_set_error (error, MONGOC_ERROR_COLLECTION, codes[command->type], "Cannot do an empty %s", _mongoc_write_command_get_name (command)); } static int32_t _mongoc_write_result_merge_arrays (uint32_t offset, mongoc_write_result_t *result, /* IN */ bson_t *dest, /* IN */ bson_iter_t *iter) /* IN */ { const bson_value_t *value; bson_iter_t ar; bson_iter_t citer; int32_t idx; int32_t count = 0; int32_t aridx; bson_t child; const char *keyptr = NULL; char key[12]; int len; ENTRY; BSON_ASSERT (result); BSON_ASSERT (dest); BSON_ASSERT (iter); BSON_ASSERT (BSON_ITER_HOLDS_ARRAY (iter)); aridx = bson_count_keys (dest); if (bson_iter_recurse (iter, &ar)) { while (bson_iter_next (&ar)) { if (BSON_ITER_HOLDS_DOCUMENT (&ar) && bson_iter_recurse (&ar, &citer)) { len = (int) bson_uint32_to_string (aridx++, &keyptr, key, sizeof key); bson_append_document_begin (dest, keyptr, len, &child); while (bson_iter_next (&citer)) { if (BSON_ITER_IS_KEY (&citer, "index")) { idx = bson_iter_int32 (&citer) + offset; BSON_APPEND_INT32 (&child, "index", idx); } else { value = bson_iter_value (&citer); BSON_APPEND_VALUE (&child, bson_iter_key (&citer), value); } } bson_append_document_end (dest, &child); count++; } } } RETURN (count); } static void _mongoc_write_result_append_upsert (mongoc_write_result_t *result, int32_t idx, const bson_value_t *value) { bson_t child; const char *keyptr = NULL; char key[12]; int len; BSON_ASSERT (result); BSON_ASSERT (value); len = (int) bson_uint32_to_string (result->upsert_append_count, &keyptr, key, sizeof key); bson_append_document_begin (&result->upserted, keyptr, len, &child); BSON_APPEND_INT32 (&child, "index", idx); BSON_APPEND_VALUE (&child, "_id", value); bson_append_document_end (&result->upserted, &child); result->upsert_append_count++; } static void _mongoc_write_result_merge (mongoc_write_result_t *result, /* IN */ mongoc_write_command_t *command, /* IN */ const bson_t *reply, /* IN */ uint32_t offset) { int32_t server_index = 0; const bson_value_t *value; bson_iter_t iter; bson_iter_t citer; bson_iter_t ar; int32_t n_upserted = 0; int32_t affected = 0; ENTRY; BSON_ASSERT (result); BSON_ASSERT (reply); if (bson_iter_init_find (&iter, reply, "n") && BSON_ITER_HOLDS_INT32 (&iter)) { affected = bson_iter_int32 (&iter); } if (bson_iter_init_find (&iter, reply, "writeErrors") && BSON_ITER_HOLDS_ARRAY (&iter) && bson_iter_recurse (&iter, &citer) && bson_iter_next (&citer)) { result->failed = true; } switch (command->type) { case MONGOC_WRITE_COMMAND_INSERT: result->nInserted += affected; break; case MONGOC_WRITE_COMMAND_DELETE: result->nRemoved += affected; break; case MONGOC_WRITE_COMMAND_UPDATE: /* server returns each upserted _id with its index into this batch * look for "upserted": [{"index": 4, "_id": ObjectId()}, ...] */ if (bson_iter_init_find (&iter, reply, "upserted")) { if (BSON_ITER_HOLDS_ARRAY (&iter) && (bson_iter_recurse (&iter, &ar))) { while (bson_iter_next (&ar)) { if (BSON_ITER_HOLDS_DOCUMENT (&ar) && bson_iter_recurse (&ar, &citer) && bson_iter_find (&citer, "index") && BSON_ITER_HOLDS_INT32 (&citer)) { server_index = bson_iter_int32 (&citer); if (bson_iter_recurse (&ar, &citer) && bson_iter_find (&citer, "_id")) { value = bson_iter_value (&citer); _mongoc_write_result_append_upsert (result, offset + server_index, value); n_upserted++; } } } } result->nUpserted += n_upserted; /* * XXX: The following addition to nMatched needs some checking. * I'm highly skeptical of it. */ result->nMatched += BSON_MAX (0, (affected - n_upserted)); } else { result->nMatched += affected; } if (bson_iter_init_find (&iter, reply, "nModified") && BSON_ITER_HOLDS_INT32 (&iter)) { result->nModified += bson_iter_int32 (&iter); } break; default: BSON_ASSERT (false); break; } if (bson_iter_init_find (&iter, reply, "writeErrors") && BSON_ITER_HOLDS_ARRAY (&iter)) { _mongoc_write_result_merge_arrays (offset, result, &result->writeErrors, &iter); } if (bson_iter_init_find (&iter, reply, "writeConcernError") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { uint32_t len; const uint8_t *data; bson_t write_concern_error; char str[16]; const char *key; /* writeConcernError is a subdocument in the server response * append it to the result->writeConcernErrors array */ bson_iter_document (&iter, &len, &data); BSON_ASSERT (bson_init_static (&write_concern_error, data, len)); bson_uint32_to_string (result->n_writeConcernErrors, &key, str, sizeof str); if (!bson_append_document (&result->writeConcernErrors, key, -1, &write_concern_error)) { MONGOC_ERROR ("Error adding \"%s\" to writeConcernErrors.\n", key); } result->n_writeConcernErrors++; } /* If a server error ocurred, then append the raw response to the * error_replies array. */ if (!_mongoc_cmd_check_ok (reply, MONGOC_ERROR_API_VERSION_2, NULL /* error */)) { char str[16]; const char *key; bson_uint32_to_string (result->n_errorReplies, &key, str, sizeof str); if (!bson_append_document (&result->rawErrorReplies, key, -1, reply)) { MONGOC_ERROR ("Error adding \"%s\" to errorReplies.\n", key); } result->n_errorReplies++; } /* inefficient if there are ever large numbers: for each label in each err, * we linear-search result->errorLabels to see if it's included yet */ _mongoc_bson_array_copy_labels_to (reply, &result->errorLabels); EXIT; } static void _mongoc_write_opmsg (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, const mongoc_write_concern_t *write_concern, uint32_t index_offset, mongoc_client_session_t *cs, mongoc_write_result_t *result, bson_error_t *error) { mongoc_cmd_parts_t parts; bson_iter_t iter; bson_t cmd; bson_t reply; bool ret = false; int32_t max_msg_size; int32_t max_bson_obj_size; int32_t max_document_count; uint32_t payload_batch_size = 0; uint32_t payload_total_offset = 0; bool ship_it = false; int document_count = 0; mongoc_server_stream_t *retry_server_stream = NULL; ENTRY; BSON_ASSERT (command); BSON_ASSERT_PARAM (client); BSON_ASSERT (database); BSON_ASSERT (server_stream); BSON_ASSERT (collection); max_bson_obj_size = mongoc_server_stream_max_bson_obj_size (server_stream); max_msg_size = mongoc_server_stream_max_msg_size (server_stream); if (_mongoc_cse_is_enabled (client)) { max_msg_size = MONGOC_REDUCED_MAX_MSG_SIZE_FOR_FLE; } max_document_count = mongoc_server_stream_max_write_batch_size (server_stream); bson_init (&cmd); _mongoc_write_command_init (&cmd, command, collection); mongoc_cmd_parts_init (&parts, client, database, MONGOC_QUERY_NONE, &cmd); parts.assembled.operation_id = command->operation_id; parts.is_write_command = true; if (!mongoc_cmd_parts_set_write_concern (&parts, write_concern, error)) { bson_destroy (&cmd); mongoc_cmd_parts_cleanup (&parts); EXIT; } if (parts.assembled.is_acknowledged) { mongoc_cmd_parts_set_session (&parts, cs); } /* Write commands that include multi-document operations are not retryable. * Set this explicitly so that mongoc_cmd_parts_assemble does not need to * inspect the command body later. */ parts.allow_txn_number = (command->flags.has_multi_write || !parts.assembled.is_acknowledged) ? MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_NO : MONGOC_CMD_PARTS_ALLOW_TXN_NUMBER_YES; BSON_ASSERT (bson_iter_init (&iter, &command->cmd_opts)); if (!mongoc_cmd_parts_append_opts (&parts, &iter, error)) { bson_destroy (&cmd); mongoc_cmd_parts_cleanup (&parts); EXIT; } if (!mongoc_cmd_parts_assemble (&parts, server_stream, error)) { bson_destroy (&cmd); mongoc_cmd_parts_cleanup (&parts); EXIT; } // Calculate overhead of OP_MSG data. See OP_MSG spec for description of fields. uint32_t opmsg_overhead = 0; { opmsg_overhead += 16; // OP_MSG.MsgHeader opmsg_overhead += 4; // OP_MSG.flagBits opmsg_overhead += 1; // OP_MSG.Section[0].payloadType (0) opmsg_overhead += parts.assembled.command->len; // OP_MSG.Section[0].payload.document opmsg_overhead += 1; // OP_MSG.Section[1].payloadType (1) opmsg_overhead += 4; // OP_MSG.Section[1].payload.size opmsg_overhead += gCommandFieldLens[command->type] + 1; // OP_MSG.Section[1].payload.identifier // OP_MSG.Section[1].payload.documents is omitted. Calculated below with remaining size. } do { uint32_t ulen; memcpy (&ulen, command->payload.data + payload_batch_size + payload_total_offset, 4); ulen = BSON_UINT32_FROM_LE (ulen); // Although messageLength is an int32, it should never be negative. BSON_ASSERT (mcommon_in_range_unsigned (int32_t, ulen)); const int32_t slen = (int32_t) ulen; if (slen > max_bson_obj_size + BSON_OBJECT_ALLOWANCE) { /* Quit if the document is too large */ _mongoc_write_command_too_large_error (error, index_offset, slen, max_bson_obj_size); result->failed = true; break; } else if (mcommon_cmp_less_equal_us (payload_batch_size + opmsg_overhead + ulen, max_msg_size) || document_count == 0) { /* The current batch is still under max batch size in bytes */ payload_batch_size += ulen; /* If this document filled the maximum document count */ if (++document_count == max_document_count) { ship_it = true; /* If this document is the last document we have */ } else if (payload_batch_size + payload_total_offset == command->payload.len) { ship_it = true; } else { ship_it = false; } } else { ship_it = true; } if (ship_it) { parts.assembled.payloads_count = 1; mongoc_cmd_payload_t *const payload = &parts.assembled.payloads[0]; /* Seek past the document offset we have already sent */ payload->documents = command->payload.data + payload_total_offset; /* Only send the documents up to this size */ payload->size = payload_batch_size; payload->identifier = gCommandFields[command->type]; mongoc_server_stream_t *new_retry_server_stream = NULL; ret = mongoc_cluster_run_retryable_write ( &client->cluster, &parts.assembled, parts.is_retryable_write, &new_retry_server_stream, &reply, error); if (new_retry_server_stream) { mongoc_server_stream_cleanup (retry_server_stream); retry_server_stream = new_retry_server_stream; } /* Add this batch size so we skip these documents next time */ payload_total_offset += payload_batch_size; payload_batch_size = 0; if (!ret) { result->failed = true; /* Stop for ordered bulk writes or when the server stream has been * properly invalidated (e.g., due to a network error). */ if (command->flags.ordered || !mongoc_cluster_stream_valid (&client->cluster, server_stream)) { result->must_stop = true; } } /* Result merge needs to know the absolute index for a document * so it can rewrite the error message which contains the relative * document index per batch */ _mongoc_write_result_merge (result, command, &reply, index_offset); index_offset += document_count; document_count = 0; bson_destroy (&reply); } /* While we have more documents to write */ } while (payload_total_offset < command->payload.len && !result->must_stop); bson_destroy (&cmd); mongoc_cmd_parts_cleanup (&parts); if (retry_server_stream) { if (ret) { /* if a retry succeeded, report that in the result so bulk write can * use the newly selected server. */ result->retry_server_id = mongoc_server_description_id (retry_server_stream->sd); } mongoc_server_stream_cleanup (retry_server_stream); } if (ret) { /* if a retry succeeded, clear the initial error */ memset (&result->error, 0, sizeof (bson_error_t)); } EXIT; } void _mongoc_write_command_execute (mongoc_write_command_t *command, /* IN */ mongoc_client_t *client, /* IN */ mongoc_server_stream_t *server_stream, /* IN */ const char *database, /* IN */ const char *collection, /* IN */ const mongoc_write_concern_t *write_concern, /* IN */ uint32_t offset, /* IN */ mongoc_client_session_t *cs, /* IN */ mongoc_write_result_t *result) /* OUT */ { mongoc_crud_opts_t crud = {0}; ENTRY; BSON_ASSERT (command); BSON_ASSERT_PARAM (client); BSON_ASSERT (server_stream); BSON_ASSERT (database); BSON_ASSERT (collection); BSON_ASSERT (result); if (!write_concern) { write_concern = client->write_concern; } if (!mongoc_write_concern_is_valid (write_concern)) { bson_set_error ( &result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "The write concern is invalid."); result->failed = true; EXIT; } crud.client_session = cs; crud.writeConcern = (mongoc_write_concern_t *) write_concern; _mongoc_write_command_execute_idl (command, client, server_stream, database, collection, offset, &crud, result); EXIT; } void _mongoc_write_command_execute_idl (mongoc_write_command_t *command, mongoc_client_t *client, mongoc_server_stream_t *server_stream, const char *database, const char *collection, uint32_t offset, const mongoc_crud_opts_t *crud, mongoc_write_result_t *result) { ENTRY; BSON_ASSERT (command); BSON_ASSERT_PARAM (client); BSON_ASSERT (server_stream); BSON_ASSERT (database); BSON_ASSERT (collection); BSON_ASSERT (result); if (command->flags.has_collation) { if (!mongoc_write_concern_is_acknowledged (crud->writeConcern)) { result->failed = true; bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set collation for unacknowledged writes"); EXIT; } } if (command->flags.has_array_filters) { if (!mongoc_write_concern_is_acknowledged (crud->writeConcern)) { result->failed = true; bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot use array filters with unacknowledged writes"); EXIT; } } if (command->flags.has_update_hint) { if (server_stream->sd->max_wire_version < WIRE_VERSION_UPDATE_HINT && !mongoc_write_concern_is_acknowledged (crud->writeConcern)) { bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support hint for update"); result->failed = true; EXIT; } } if (command->flags.has_delete_hint) { if (server_stream->sd->max_wire_version < WIRE_VERSION_DELETE_HINT && !mongoc_write_concern_is_acknowledged (crud->writeConcern)) { bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION, "The selected server does not support hint for delete"); result->failed = true; EXIT; } } if (command->flags.bypass_document_validation) { if (!mongoc_write_concern_is_acknowledged (crud->writeConcern)) { result->failed = true; bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot set bypassDocumentValidation for unacknowledged writes"); EXIT; } } if (crud->client_session && !mongoc_write_concern_is_acknowledged (crud->writeConcern)) { result->failed = true; bson_set_error (&result->error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Cannot use client session with unacknowledged writes"); EXIT; } if (command->payload.len == 0) { _empty_error (command, &result->error); EXIT; } _mongoc_write_opmsg (command, client, server_stream, database, collection, crud->writeConcern, offset, crud->client_session, result, &result->error); EXIT; } void _mongoc_write_command_destroy (mongoc_write_command_t *command) { ENTRY; if (command) { bson_destroy (&command->cmd_opts); _mongoc_buffer_destroy (&command->payload); } EXIT; } void _mongoc_write_result_init (mongoc_write_result_t *result) /* IN */ { ENTRY; BSON_ASSERT (result); memset (result, 0, sizeof *result); bson_init (&result->upserted); bson_init (&result->writeConcernErrors); bson_init (&result->writeErrors); bson_init (&result->errorLabels); bson_init (&result->rawErrorReplies); EXIT; } void _mongoc_write_result_destroy (mongoc_write_result_t *result) { ENTRY; BSON_ASSERT (result); bson_destroy (&result->upserted); bson_destroy (&result->writeConcernErrors); bson_destroy (&result->writeErrors); bson_destroy (&result->errorLabels); bson_destroy (&result->rawErrorReplies); EXIT; } /* * If error is not set, set code from first document in array like * [{"code": 64, "errmsg": "duplicate"}, ...]. Format the error message * from all errors in array. */ static void _set_error_from_response (bson_t *bson_array, mongoc_error_domain_t domain, const char *error_type, bson_error_t *error /* OUT */) { bson_iter_t array_iter; bson_iter_t doc_iter; const char *errmsg = NULL; int32_t code = 0; uint32_t n_keys, i; mcommon_string_append_t compound_err; mcommon_string_new_as_fixed_capacity_append (&compound_err, sizeof error->message - 1u); n_keys = bson_count_keys (bson_array); if (n_keys > 1) { mcommon_string_append_printf (&compound_err, "Multiple %s errors: ", error_type); } if (!bson_empty0 (bson_array) && bson_iter_init (&array_iter, bson_array)) { /* get first code and all error messages */ i = 0; while (bson_iter_next (&array_iter)) { if (BSON_ITER_HOLDS_DOCUMENT (&array_iter) && bson_iter_recurse (&array_iter, &doc_iter)) { /* parse doc, which is like {"code": 64, "errmsg": "duplicate"} */ while (bson_iter_next (&doc_iter)) { /* use the first error code we find */ if (BSON_ITER_IS_KEY (&doc_iter, "code") && code == 0) { code = (uint32_t) bson_iter_as_int64 (&doc_iter); } else if (BSON_ITER_IS_KEY (&doc_iter, "errmsg")) { errmsg = bson_iter_utf8 (&doc_iter, NULL); /* build message like 'Multiple write errors: "foo", "bar"' */ if (n_keys > 1) { mcommon_string_append_printf (&compound_err, "\"%s\"", errmsg); if (i < n_keys - 1) { mcommon_string_append (&compound_err, ", "); } } else { /* single error message */ mcommon_string_append (&compound_err, errmsg); } } } i++; } } if (code && !mcommon_string_from_append_is_empty (&compound_err)) { bson_set_error (error, domain, (uint32_t) code, "%s", mcommon_str_from_append (&compound_err)); } } mcommon_string_from_append_destroy (&compound_err); } /* complete a write result, including only certain fields */ bool _mongoc_write_result_complete (mongoc_write_result_t *result, /* IN */ int32_t error_api_version, /* IN */ const mongoc_write_concern_t *wc, /* IN */ mongoc_error_domain_t err_domain_override, /* IN */ bson_t *bson, /* OUT */ bson_error_t *error, /* OUT */ ...) { mongoc_error_domain_t domain; va_list args; const char *field; int n_args; bson_iter_t iter; bson_iter_t child; ENTRY; BSON_ASSERT (result); if (error_api_version >= MONGOC_ERROR_API_VERSION_2) { domain = MONGOC_ERROR_SERVER; } else if (err_domain_override) { domain = err_domain_override; } else if (result->error.domain) { domain = (mongoc_error_domain_t) result->error.domain; } else { domain = MONGOC_ERROR_COLLECTION; } /* produce either old fields like nModified from the deprecated Bulk API Spec * or new fields like modifiedCount from the CRUD Spec, which we partly obey */ if (bson && mongoc_write_concern_is_acknowledged (wc)) { n_args = 0; va_start (args, error); while ((field = va_arg (args, const char *))) { n_args++; if (!strcmp (field, "nInserted")) { BSON_APPEND_INT32 (bson, field, result->nInserted); } else if (!strcmp (field, "insertedCount")) { BSON_APPEND_INT32 (bson, field, result->nInserted); } else if (!strcmp (field, "nMatched")) { BSON_APPEND_INT32 (bson, field, result->nMatched); } else if (!strcmp (field, "matchedCount")) { BSON_APPEND_INT32 (bson, field, result->nMatched); } else if (!strcmp (field, "nModified")) { BSON_APPEND_INT32 (bson, field, result->nModified); } else if (!strcmp (field, "modifiedCount")) { BSON_APPEND_INT32 (bson, field, result->nModified); } else if (!strcmp (field, "nRemoved")) { BSON_APPEND_INT32 (bson, field, result->nRemoved); } else if (!strcmp (field, "deletedCount")) { BSON_APPEND_INT32 (bson, field, result->nRemoved); } else if (!strcmp (field, "nUpserted")) { BSON_APPEND_INT32 (bson, field, result->nUpserted); } else if (!strcmp (field, "upsertedCount")) { BSON_APPEND_INT32 (bson, field, result->nUpserted); } else if (!strcmp (field, "upserted") && !bson_empty0 (&result->upserted)) { BSON_APPEND_ARRAY (bson, field, &result->upserted); } else if (!strcmp (field, "upsertedId") && !bson_empty0 (&result->upserted) && bson_iter_init_find (&iter, &result->upserted, "0") && bson_iter_recurse (&iter, &child) && bson_iter_find (&child, "_id")) { /* "upsertedId", singular, for update_one() */ BSON_APPEND_VALUE (bson, "upsertedId", bson_iter_value (&child)); } } va_end (args); /* default: a standard result includes all Bulk API fields */ if (!n_args) { BSON_APPEND_INT32 (bson, "nInserted", result->nInserted); BSON_APPEND_INT32 (bson, "nMatched", result->nMatched); BSON_APPEND_INT32 (bson, "nModified", result->nModified); BSON_APPEND_INT32 (bson, "nRemoved", result->nRemoved); BSON_APPEND_INT32 (bson, "nUpserted", result->nUpserted); if (!bson_empty0 (&result->upserted)) { BSON_APPEND_ARRAY (bson, "upserted", &result->upserted); } } /* always append errors if there are any */ if (!n_args || !bson_empty (&result->writeErrors)) { BSON_APPEND_ARRAY (bson, "writeErrors", &result->writeErrors); } if (result->n_writeConcernErrors) { BSON_APPEND_ARRAY (bson, "writeConcernErrors", &result->writeConcernErrors); } } /* If there is a raw error response then we know a server error has occurred. * We should add the raw result to the reply. */ if (bson && !bson_empty (&result->rawErrorReplies)) { BSON_APPEND_ARRAY (bson, "errorReplies", &result->rawErrorReplies); } /* set bson_error_t from first write error or write concern error */ _set_error_from_response (&result->writeErrors, domain, "write", &result->error); if (!result->error.code) { _set_error_from_response ( &result->writeConcernErrors, MONGOC_ERROR_WRITE_CONCERN, "write concern", &result->error); } if (bson && !bson_empty (&result->errorLabels)) { BSON_APPEND_ARRAY (bson, "errorLabels", &result->errorLabels); } if (error) { memcpy (error, &result->error, sizeof *error); } RETURN (!result->failed && result->error.code == 0); } /*-------------------------------------------------------------------------- * * _mongoc_write_error_get_type -- * * Checks if the error or reply from a write command is considered * retryable according to the retryable writes spec. Checks both * for a client error (a network exception) and a server error in * the reply. @cmd_ret and @cmd_err come from the result of a * write_command function. This function should be called after * error labels are appended in _mongoc_write_error_handle_labels, * which should be called after mongoc_cluster_run_command_monitored. * * * Return: * A mongoc_write_error_type_t indicating the type of error (if any). * *-------------------------------------------------------------------------- */ mongoc_write_err_type_t _mongoc_write_error_get_type (bson_t *reply) { bson_error_t error; if (mongoc_error_has_label (reply, RETRYABLE_WRITE_ERROR)) { return MONGOC_WRITE_ERR_RETRY; } /* check for a server error. */ if (_mongoc_cmd_check_ok_no_wce (reply, MONGOC_ERROR_API_VERSION_2, &error)) { return MONGOC_WRITE_ERR_NONE; } switch (error.code) { case 64: /* WriteConcernFailed */ return MONGOC_WRITE_ERR_WRITE_CONCERN; default: return MONGOC_WRITE_ERR_OTHER; } } /* Returns true and modifies reply and cmd_err. */ bool _mongoc_write_error_update_if_unsupported_storage_engine (bool cmd_ret, bson_error_t *cmd_err, bson_t *reply) { bson_error_t server_error; if (cmd_ret) { return false; } if (_mongoc_cmd_check_ok_no_wce (reply, MONGOC_ERROR_API_VERSION_2, &server_error)) { return false; } if (server_error.code == 20 && strstr (server_error.message, "Transaction numbers") == server_error.message) { const char *replacement = "This MongoDB deployment does not support " "retryable writes. Please add " "retryWrites=false to your connection string."; strcpy (cmd_err->message, replacement); if (reply) { bson_t *new_reply = bson_new (); bson_copy_to_excluding_noinit (reply, new_reply, "errmsg", NULL); BSON_APPEND_UTF8 (new_reply, "errmsg", replacement); bson_destroy (reply); bson_steal (reply, new_reply); } return true; } return false; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-write-concern-private.h0000644000175100001660000000254714760300420025376 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_WRITE_CONCERN_PRIVATE_H #define MONGOC_WRITE_CONCERN_PRIVATE_H #include BSON_BEGIN_DECLS #define MONGOC_WRITE_CONCERN_FSYNC_DEFAULT -1 #define MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT -1 struct _mongoc_write_concern_t { int8_t fsync_; /* deprecated */ int8_t journal; int32_t w; int64_t wtimeout; char *wtag; bool frozen; bson_t compiled; bool is_default; }; mongoc_write_concern_t * _mongoc_write_concern_new_from_iter (const bson_iter_t *iter, bson_error_t *error); const bson_t * _mongoc_write_concern_get_bson (mongoc_write_concern_t *write_concern); bool _mongoc_parse_wc_err (const bson_t *doc, bson_error_t *error); BSON_END_DECLS #endif /* MONGOC_WRITE_CONCERN_PRIVATE_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-write-concern.c0000644000175100001660000003646614760300420023730 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #include #include #include #include #include // BEGIN_IGNORE_DEPRECATIONS static void _mongoc_write_concern_freeze (mongoc_write_concern_t *write_concern); /** * mongoc_write_concern_new: * * Create a new mongoc_write_concern_t. * * Returns: A newly allocated mongoc_write_concern_t. This should be freed * with mongoc_write_concern_destroy(). */ mongoc_write_concern_t * mongoc_write_concern_new (void) { mongoc_write_concern_t *write_concern; write_concern = BSON_ALIGNED_ALLOC0 (mongoc_write_concern_t); write_concern->w = MONGOC_WRITE_CONCERN_W_DEFAULT; write_concern->fsync_ = MONGOC_WRITE_CONCERN_FSYNC_DEFAULT; write_concern->journal = MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT; write_concern->is_default = true; bson_init (&write_concern->compiled); return write_concern; } mongoc_write_concern_t * mongoc_write_concern_copy (const mongoc_write_concern_t *write_concern) { mongoc_write_concern_t *ret = NULL; if (write_concern) { ret = mongoc_write_concern_new (); ret->fsync_ = write_concern->fsync_; ret->journal = write_concern->journal; ret->w = write_concern->w; ret->wtimeout = write_concern->wtimeout; ret->frozen = false; ret->wtag = bson_strdup (write_concern->wtag); ret->is_default = write_concern->is_default; } return ret; } /** * mongoc_write_concern_destroy: * @write_concern: A mongoc_write_concern_t. * * Releases a mongoc_write_concern_t and all associated memory. */ void mongoc_write_concern_destroy (mongoc_write_concern_t *write_concern) { if (write_concern) { bson_destroy (&write_concern->compiled); bson_free (write_concern->wtag); bson_free (write_concern); } } bool mongoc_write_concern_get_fsync (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return (write_concern->fsync_ == true); } /** * mongoc_write_concern_set_fsync: * @write_concern: A mongoc_write_concern_t. * @fsync_: If the write concern requires fsync() by the server. * * Set if fsync() should be called on the server before acknowledging a * write request. */ void mongoc_write_concern_set_fsync (mongoc_write_concern_t *write_concern, bool fsync_) { BSON_ASSERT (write_concern); write_concern->fsync_ = !!fsync_; write_concern->is_default = false; write_concern->frozen = false; } bool mongoc_write_concern_get_journal (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return (write_concern->journal == true); } bool mongoc_write_concern_journal_is_set (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return (write_concern->journal != MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT); } /** * mongoc_write_concern_set_journal: * @write_concern: A mongoc_write_concern_t. * @journal: If the write should be journaled. * * Set if the write request should be journaled before acknowledging the * write request. */ void mongoc_write_concern_set_journal (mongoc_write_concern_t *write_concern, bool journal) { BSON_ASSERT (write_concern); write_concern->journal = !!journal; write_concern->is_default = false; write_concern->frozen = false; } int32_t mongoc_write_concern_get_w (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return write_concern->w; } /** * mongoc_write_concern_set_w: * @w: The number of nodes for write or MONGOC_WRITE_CONCERN_W_MAJORITY * for "majority". * * Sets the number of nodes that must acknowledge the write request before * acknowledging the write request to the client. * * You may specify @w as MONGOC_WRITE_CONCERN_W_MAJORITY to request that * a "majority" of nodes acknowledge the request. */ void mongoc_write_concern_set_w (mongoc_write_concern_t *write_concern, int32_t w) { BSON_ASSERT (write_concern); BSON_ASSERT (w >= -3); write_concern->w = w; if (w != MONGOC_WRITE_CONCERN_W_DEFAULT) { write_concern->is_default = false; } write_concern->frozen = false; } int32_t mongoc_write_concern_get_wtimeout (const mongoc_write_concern_t *write_concern) { return (int32_t) mongoc_write_concern_get_wtimeout_int64 (write_concern); } int64_t mongoc_write_concern_get_wtimeout_int64 (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return write_concern->wtimeout; } void mongoc_write_concern_set_wtimeout (mongoc_write_concern_t *write_concern, int32_t wtimeout_msec) { mongoc_write_concern_set_wtimeout_int64 (write_concern, (int64_t) wtimeout_msec); } void mongoc_write_concern_set_wtimeout_int64 (mongoc_write_concern_t *write_concern, int64_t wtimeout_msec) { BSON_ASSERT (write_concern); if (wtimeout_msec < 0) { return; } write_concern->wtimeout = wtimeout_msec; write_concern->is_default = false; write_concern->frozen = false; } bool mongoc_write_concern_get_wmajority (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); return (write_concern->w == MONGOC_WRITE_CONCERN_W_MAJORITY); } /** * mongoc_write_concern_set_wmajority: * @write_concern: A mongoc_write_concern_t. * @wtimeout_msec: Number of milliseconds before timeout. * * Sets the "w" of a write concern to "majority". It is suggested that * you provide a reasonable @wtimeout_msec to wait before considering the * write request failed. A @wtimeout_msec value of 0 indicates no write timeout. * * The @wtimeout_msec parameter must be positive or zero. Negative values will * be ignored. */ void mongoc_write_concern_set_wmajority (mongoc_write_concern_t *write_concern, int32_t wtimeout_msec) { BSON_ASSERT (write_concern); write_concern->w = MONGOC_WRITE_CONCERN_W_MAJORITY; write_concern->is_default = false; write_concern->frozen = false; if (wtimeout_msec >= 0) { write_concern->wtimeout = wtimeout_msec; } } const char * mongoc_write_concern_get_wtag (const mongoc_write_concern_t *write_concern) { BSON_ASSERT (write_concern); if (write_concern->w == MONGOC_WRITE_CONCERN_W_TAG) { return write_concern->wtag; } return NULL; } void mongoc_write_concern_set_wtag (mongoc_write_concern_t *write_concern, const char *wtag) { BSON_ASSERT (write_concern); bson_free (write_concern->wtag); write_concern->wtag = bson_strdup (wtag); write_concern->w = MONGOC_WRITE_CONCERN_W_TAG; write_concern->is_default = false; write_concern->frozen = false; } /** * mongoc_write_concern_get_bson: * @write_concern: A mongoc_write_concern_t. * * This is an internal function. * * Returns: A bson_t representing the write concern, which is owned by the * mongoc_write_concern_t instance and should not be modified or freed. */ const bson_t * _mongoc_write_concern_get_bson (mongoc_write_concern_t *write_concern) { if (!write_concern->frozen) { _mongoc_write_concern_freeze (write_concern); } return &write_concern->compiled; } /** * mongoc_write_concern_is_default: * @write_concern: A mongoc_write_concern_t. * * Returns is_default, which is true when write_concern has not been modified. * */ bool mongoc_write_concern_is_default (const mongoc_write_concern_t *write_concern) { return !write_concern || write_concern->is_default; } /** * mongoc_write_concern_freeze: * @write_concern: A mongoc_write_concern_t. * * This is an internal function. * * Encodes the write concern into a bson_t, which may then be returned by * _mongoc_write_concern_get_bson(). */ static void _mongoc_write_concern_freeze (mongoc_write_concern_t *write_concern) { bson_t *compiled; BSON_ASSERT (write_concern); compiled = &write_concern->compiled; write_concern->frozen = true; bson_reinit (compiled); if (write_concern->w == MONGOC_WRITE_CONCERN_W_TAG) { BSON_ASSERT (write_concern->wtag); BSON_APPEND_UTF8 (compiled, "w", write_concern->wtag); } else if (write_concern->w == MONGOC_WRITE_CONCERN_W_MAJORITY) { BSON_APPEND_UTF8 (compiled, "w", "majority"); } else if (write_concern->w == MONGOC_WRITE_CONCERN_W_DEFAULT) { /* Do Nothing */ } else { BSON_APPEND_INT32 (compiled, "w", write_concern->w); } if (write_concern->fsync_ != MONGOC_WRITE_CONCERN_FSYNC_DEFAULT) { bson_append_bool (compiled, "fsync", 5, !!write_concern->fsync_); } if (write_concern->journal != MONGOC_WRITE_CONCERN_JOURNAL_DEFAULT) { bson_append_bool (compiled, "j", 1, !!write_concern->journal); } if (write_concern->wtimeout) { bson_append_int64 (compiled, "wtimeout", 8, write_concern->wtimeout); } } /** * mongoc_write_concern_is_acknowledged: * @concern: (in): A mongoc_write_concern_t. * * Checks to see if @write_concern requests that a getlasterror command is to * be delivered to the MongoDB server. * * Returns: true if a getlasterror command should be sent. */ bool mongoc_write_concern_is_acknowledged (const mongoc_write_concern_t *write_concern) { if (write_concern) { return (((write_concern->w != MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED) && (write_concern->w != MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED)) || write_concern->fsync_ == true || mongoc_write_concern_get_journal (write_concern)); } return true; } /** * mongoc_write_concern_is_valid: * @write_concern: (in): A mongoc_write_concern_t. * * Checks to see if @write_concern is valid and does not contain conflicting * options. * * Returns: true if the write concern is valid; otherwise false. */ bool mongoc_write_concern_is_valid (const mongoc_write_concern_t *write_concern) { if (!write_concern) { return false; } /* Journal or fsync should require acknowledgement. */ if ((write_concern->fsync_ == true || mongoc_write_concern_get_journal (write_concern)) && (write_concern->w == MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED || write_concern->w == MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED)) { return false; } if (write_concern->wtimeout < 0) { return false; } return true; } static bool _mongoc_write_concern_validate (const mongoc_write_concern_t *write_concern, bson_error_t *error) { if (write_concern && !mongoc_write_concern_is_valid (write_concern)) { bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid writeConcern"); return false; } return true; } /** * _mongoc_parse_wc_err: * @doc: (in): A bson document. * @error: (out): A bson_error_t. * * Parses a document, usually a server reply, * looking for a writeConcernError. Returns true if * there is a writeConcernError, false otherwise. */ bool _mongoc_parse_wc_err (const bson_t *doc, bson_error_t *error) { bson_iter_t iter; bson_iter_t inner; if (bson_iter_init_find (&iter, doc, "writeConcernError") && BSON_ITER_HOLDS_DOCUMENT (&iter)) { const char *errmsg = NULL; int32_t code = 0; BSON_ASSERT (bson_iter_recurse (&iter, &inner)); while (bson_iter_next (&inner)) { if (BSON_ITER_IS_KEY (&inner, "code")) { code = (uint32_t) bson_iter_as_int64 (&inner); } else if (BSON_ITER_IS_KEY (&inner, "errmsg")) { errmsg = bson_iter_utf8 (&inner, NULL); } } bson_set_error (error, MONGOC_ERROR_WRITE_CONCERN, code, "Write Concern error: %s", errmsg); return true; } return false; } /** * mongoc_write_concern_append: * @write_concern: (in): A mongoc_write_concern_t. * @command: (out): A pointer to a bson document. * * Appends a write_concern document to a command, to send to * a server. * * Returns true on success, false on failure. * */ bool mongoc_write_concern_append (mongoc_write_concern_t *write_concern, bson_t *command) { if (!mongoc_write_concern_is_valid (write_concern)) { MONGOC_ERROR ("Invalid writeConcern passed into " "mongoc_write_concern_append."); return false; } if (!bson_append_document (command, "writeConcern", 12, _mongoc_write_concern_get_bson (write_concern))) { MONGOC_ERROR ("Could not append writeConcern to command."); return false; } return true; } /** * _mongoc_write_concern_new_from_iter: * * Create a new mongoc_write_concern_t from an iterator positioned on * a "writeConcern" document. * * Returns: A newly allocated mongoc_write_concern_t. This should be freed * with mongoc_write_concern_destroy(). */ mongoc_write_concern_t * _mongoc_write_concern_new_from_iter (const bson_iter_t *iter, bson_error_t *error) { bson_iter_t inner; mongoc_write_concern_t *write_concern; int32_t w; BSON_ASSERT (iter); write_concern = mongoc_write_concern_new (); if (!BSON_ITER_HOLDS_DOCUMENT (iter)) { goto fail; } BSON_ASSERT (bson_iter_recurse (iter, &inner)); while (bson_iter_next (&inner)) { if (BSON_ITER_IS_KEY (&inner, "w")) { if (BSON_ITER_HOLDS_INT32 (&inner)) { w = bson_iter_int32 (&inner); if (w < MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED) { goto fail; } mongoc_write_concern_set_w (write_concern, w); } else if (BSON_ITER_HOLDS_UTF8 (&inner)) { if (!strcmp (bson_iter_utf8 (&inner, NULL), "majority")) { /* mongoc_write_concern_set_wmajority() only assigns wtimeout if * it is >= 0. Since we set wtimeout below, pass -1 here. */ mongoc_write_concern_set_wmajority (write_concern, -1); } else { mongoc_write_concern_set_wtag (write_concern, bson_iter_utf8 (&inner, NULL)); } } else { /* wrong type for "w" */ goto fail; } } else if (BSON_ITER_IS_KEY (&inner, "fsync")) { if (!BSON_ITER_HOLDS_BOOL (&inner)) { goto fail; } BEGIN_IGNORE_DEPRECATIONS mongoc_write_concern_set_fsync (write_concern, bson_iter_bool (&inner)); END_IGNORE_DEPRECATIONS } else if (BSON_ITER_IS_KEY (&inner, "j")) { if (!BSON_ITER_HOLDS_BOOL (&inner)) { goto fail; } mongoc_write_concern_set_journal (write_concern, bson_iter_bool (&inner)); } else if (BSON_ITER_IS_KEY (&inner, "wtimeout")) { if (!BSON_ITER_HOLDS_INT (&inner) || bson_iter_as_int64 (&inner) < 0) { goto fail; } mongoc_write_concern_set_wtimeout_int64 (write_concern, bson_iter_as_int64 (&inner)); } } if (!_mongoc_write_concern_validate (write_concern, error)) { mongoc_write_concern_destroy (write_concern); return NULL; } return write_concern; fail: bson_set_error (error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "Invalid writeConcern"); mongoc_write_concern_destroy (write_concern); return NULL; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc-write-concern.h0000644000175100001660000000672314760300420023726 0ustar /* * Copyright 2009-present MongoDB, 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. */ #include #ifndef MONGOC_WRITE_CONCERN_H #define MONGOC_WRITE_CONCERN_H #include #include BSON_BEGIN_DECLS #define MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED 0 #define MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED -1 /* deprecated */ #define MONGOC_WRITE_CONCERN_W_DEFAULT -2 #define MONGOC_WRITE_CONCERN_W_MAJORITY -3 #define MONGOC_WRITE_CONCERN_W_TAG -4 typedef struct _mongoc_write_concern_t mongoc_write_concern_t; MONGOC_EXPORT (mongoc_write_concern_t *) mongoc_write_concern_new (void) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (mongoc_write_concern_t *) mongoc_write_concern_copy (const mongoc_write_concern_t *write_concern) BSON_GNUC_WARN_UNUSED_RESULT; MONGOC_EXPORT (void) mongoc_write_concern_destroy (mongoc_write_concern_t *write_concern); MONGOC_EXPORT (bool) mongoc_write_concern_get_fsync (const mongoc_write_concern_t *write_concern) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (void) mongoc_write_concern_set_fsync (mongoc_write_concern_t *write_concern, bool fsync_) BSON_GNUC_DEPRECATED; MONGOC_EXPORT (bool) mongoc_write_concern_get_journal (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (bool) mongoc_write_concern_journal_is_set (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (void) mongoc_write_concern_set_journal (mongoc_write_concern_t *write_concern, bool journal); MONGOC_EXPORT (int32_t) mongoc_write_concern_get_w (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (void) mongoc_write_concern_set_w (mongoc_write_concern_t *write_concern, int32_t w); MONGOC_EXPORT (const char *) mongoc_write_concern_get_wtag (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (void) mongoc_write_concern_set_wtag (mongoc_write_concern_t *write_concern, const char *tag); MONGOC_EXPORT (int32_t) mongoc_write_concern_get_wtimeout (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (int64_t) mongoc_write_concern_get_wtimeout_int64 (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (void) mongoc_write_concern_set_wtimeout (mongoc_write_concern_t *write_concern, int32_t wtimeout_msec); MONGOC_EXPORT (void) mongoc_write_concern_set_wtimeout_int64 (mongoc_write_concern_t *write_concern, int64_t wtimeout_msec); MONGOC_EXPORT (bool) mongoc_write_concern_get_wmajority (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (void) mongoc_write_concern_set_wmajority (mongoc_write_concern_t *write_concern, int32_t wtimeout_msec); MONGOC_EXPORT (bool) mongoc_write_concern_is_acknowledged (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (bool) mongoc_write_concern_is_valid (const mongoc_write_concern_t *write_concern); MONGOC_EXPORT (bool) mongoc_write_concern_append (mongoc_write_concern_t *write_concern, bson_t *doc); MONGOC_EXPORT (bool) mongoc_write_concern_is_default (const mongoc_write_concern_t *write_concern); BSON_END_DECLS #endif /* MONGOC_WRITE_CONCERN_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/mongoc.h0000644000175100001660000000442314760300420021144 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifndef MONGOC_H #define MONGOC_H #include #define MONGOC_INSIDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MONGOC_ENABLE_SSL #include #include #include #endif #undef MONGOC_INSIDE #endif /* MONGOC_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/service-gcp.c0000644000175100001660000001131214760300420022057 0ustar /** * Copyright 2009-present MongoDB, 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. */ #include #include #define HOST "metadata.google.internal" static const char *const DEFAULT_METADATA_PATH = "/computeMetadata/v1/instance/service-accounts/default/token"; void gcp_request_init (gcp_request *req, const char *const opt_host, int opt_port, const char *const opt_extra_headers) { BSON_ASSERT_PARAM (req); _mongoc_http_request_init (&req->req); // The HTTP host of the Google metadata server req->req.host = req->_owned_host = bson_strdup (opt_host ? opt_host : HOST); if (opt_port) { req->req.port = opt_port; } else { req->req.port = 80; } // Empty body req->req.body = ""; // We GET req->req.method = "GET"; req->req.extra_headers = req->_owned_headers = bson_strdup_printf ("Metadata-Flavor: Google\r\n%s", opt_extra_headers ? opt_extra_headers : ""); req->req.path = req->_owned_path = bson_strdup (DEFAULT_METADATA_PATH); } void gcp_request_destroy (gcp_request *req) { BSON_ASSERT_PARAM (req); bson_free (req->_owned_headers); bson_free (req->_owned_host); bson_free (req->_owned_path); *req = (gcp_request){ .req = {0}, ._owned_path = NULL, ._owned_host = NULL, ._owned_headers = NULL, }; } void gcp_access_token_destroy (gcp_service_account_token *token) { bson_free (token->access_token); bson_free (token->token_type); token->access_token = NULL; token->token_type = NULL; } bool gcp_access_token_try_parse_from_json (gcp_service_account_token *out, const char *json, int len, bson_error_t *error) { BSON_ASSERT_PARAM (out); BSON_ASSERT_PARAM (json); bool okay = false; // Zero the output *out = (gcp_service_account_token){0}; // Parse the JSON data bson_t bson; if (!bson_init_from_json (&bson, json, len, error)) { return false; } bson_iter_t iter; // access_token bool found = bson_iter_init_find (&iter, &bson, "access_token"); const char *const access_token = !found ? NULL : bson_iter_utf8 (&iter, NULL); // token_type found = bson_iter_init_find (&iter, &bson, "token_type"); const char *const token_type = !found ? NULL : bson_iter_utf8 (&iter, NULL); if (!(access_token && token_type)) { bson_set_error (error, MONGOC_ERROR_GCP, MONGOC_ERROR_KMS_SERVER_BAD_JSON, "One or more required JSON properties are " "missing/invalid: data: %.*s", len, json); goto done; } *out = (gcp_service_account_token){ .access_token = bson_strdup (access_token), .token_type = bson_strdup (token_type), }; okay = true; done: bson_destroy (&bson); return okay; } bool gcp_access_token_from_gcp_server (gcp_service_account_token *out, const char *opt_host, int opt_port, const char *opt_extra_headers, bson_error_t *error) { BSON_ASSERT_PARAM (out); bool okay = false; // Clear the output *out = (gcp_service_account_token){0}; mongoc_http_response_t resp; _mongoc_http_response_init (&resp); gcp_request req = { .req = {0}, ._owned_path = NULL, ._owned_host = NULL, ._owned_headers = NULL, }; gcp_request_init (&req, opt_host, opt_port, opt_extra_headers); if (!_mongoc_http_send (&req.req, 3 * 1000, false, NULL, &resp, error)) { goto fail; } // Only accept an HTTP 200 as success if (resp.status != 200) { bson_set_error (error, MONGOC_ERROR_GCP, MONGOC_ERROR_KMS_SERVER_HTTP, "Error from the GCP metadata server while looking for " "access token: %.*s", resp.body_len, resp.body); goto fail; } if (!gcp_access_token_try_parse_from_json (out, resp.body, resp.body_len, error)) { goto fail; } okay = true; fail: gcp_request_destroy (&req); _mongoc_http_response_cleanup (&resp); return okay; } mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/service-gcp.h0000644000175100001660000000722514760300420022074 0ustar /** * Copyright 2009-present MongoDB, 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. */ #ifndef SERVICE_GCP_H_INCLUDED #define SERVICE_GCP_H_INCLUDED #include #include #include /** * @brief A GCP access token obtained from the GCP metadata server */ typedef struct gcp_service_account_token { /// The access token string char *access_token; // The HTTP type of the token char *token_type; } gcp_service_account_token; /** * @brief A GCP request */ typedef struct gcp_request { /// The underlying HTTP request object to be sent mongoc_http_request_t req; // optional parameters (used in testing) to override defaults char *_owned_path; char *_owned_host; char *_owned_headers; } gcp_request; /** * @brief Initialize a new GCP HTTP request * * @param out The object to initialize * @param opt_host (Optional) the IP host of the metadata server (default is * metadata.google.internal) * @param opt_port (Optional) The port of the HTTP server (default is 80) * @param opt_extra_headers (Optional) Set extra HTTP headers for the request * * @note the request must later be destroyed with gcp_request_destroy */ void gcp_request_init (gcp_request *req, const char *const opt_host, int opt_port, const char *const opt_extra_headers); /** * @brief Destroy an GCP request created with gcp_request_init() * * @param req */ void gcp_request_destroy (gcp_request *req); /** * @brief Destroy and zero-fill GCP service account token * * @param token The service account token to destory */ void gcp_access_token_destroy (gcp_service_account_token *token); /** * @brief Try to parse a GCP access token from the metadata server JSON response * * @param out The token to initialize. Should be uninitialized. Must later be * destroyed by the caller. * @param json The JSON string body * @param len The length of 'body' * @param error An output parameter for errors * @retval true If 'out' was successfully initialized to a token. * @retval false Otherwise * * @note The 'out' token must later be given to gcp_access_token_destroy */ bool gcp_access_token_try_parse_from_json (gcp_service_account_token *out, const char *json, int len, bson_error_t *error); /** * @brief Attempt to obtain a new GCP service account token from a GCP metadata * server. * * @param out The output parameter for the obtained token. Must later be * destroyed * @param opt_host (Optional) Override the IP host of the GCP server (used * in testing) * @param opt_port (Optional) The port of the HTTP server (default is 80) * (used in testing) * @param opt_extra_headers (Optional) Set extra HTTP headers for the request * (used in testing) * @param error Output parameter for errors * @retval true Upon success * @retval false Otherwise. Sets an error via `error` * */ bool gcp_access_token_from_gcp_server (gcp_service_account_token *out, const char *opt_host, int opt_port, const char *opt_extra_headers, bson_error_t *error); #endif /* SERVICE_GCP_H */ mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/uthash.h0000644000175100001660000000153514760300420021157 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifndef MONGOC_UTHASH_H #define MONGOC_UTHASH_H #include #include #define uthash_malloc(sz) bson_malloc (sz) #define uthash_free(ptr, sz) bson_free (ptr) #include #endif // MONGOC_UTHASH_H mongodb-1.21.0/src/libmongoc/src/libmongoc/src/mongoc/utlist.h0000644000175100001660000000135514760300420021207 0ustar /* * Copyright 2009-present MongoDB, 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. */ #ifndef MONGOC_UTLIST_H #define MONGOC_UTLIST_H #include #include #endif // MONGOC_UTLIST_H mongodb-1.21.0/src/libmongoc/src/utf8proc-2.8.0/utf8proc.c0000644000175100001660000007453614760300420017636 0ustar /* -*- mode: c; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*- */ /* * Copyright (c) 2014-2021 Steven G. Johnson, Jiahao Chen, Peter Colberg, Tony Kelman, Scott P. Jones, and other contributors. * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany * * 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. */ /* * This library contains derived data from a modified version of the * Unicode data files. * * The original data files are available at * https://www.unicode.org/Public/UNIDATA/ * * Please notice the copyright statement in the file "utf8proc_data.c". */ /* * File name: utf8proc.c * * Description: * Implementation of libutf8proc. */ #include "utf8proc.h" #ifndef SSIZE_MAX #define SSIZE_MAX ((size_t)SIZE_MAX/2) #endif #ifndef UINT16_MAX # define UINT16_MAX 65535U #endif #include "utf8proc_data.c" UTF8PROC_DLLEXPORT const utf8proc_int8_t utf8proc_utf8class[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0 }; #define UTF8PROC_HANGUL_SBASE 0xAC00 #define UTF8PROC_HANGUL_LBASE 0x1100 #define UTF8PROC_HANGUL_VBASE 0x1161 #define UTF8PROC_HANGUL_TBASE 0x11A7 #define UTF8PROC_HANGUL_LCOUNT 19 #define UTF8PROC_HANGUL_VCOUNT 21 #define UTF8PROC_HANGUL_TCOUNT 28 #define UTF8PROC_HANGUL_NCOUNT 588 #define UTF8PROC_HANGUL_SCOUNT 11172 /* END is exclusive */ #define UTF8PROC_HANGUL_L_START 0x1100 #define UTF8PROC_HANGUL_L_END 0x115A #define UTF8PROC_HANGUL_L_FILLER 0x115F #define UTF8PROC_HANGUL_V_START 0x1160 #define UTF8PROC_HANGUL_V_END 0x11A3 #define UTF8PROC_HANGUL_T_START 0x11A8 #define UTF8PROC_HANGUL_T_END 0x11FA #define UTF8PROC_HANGUL_S_START 0xAC00 #define UTF8PROC_HANGUL_S_END 0xD7A4 /* Should follow semantic-versioning rules (semver.org) based on API compatibility. (Note that the shared-library version number will be different, being based on ABI compatibility.): */ #define STRINGIZEx(x) #x #define STRINGIZE(x) STRINGIZEx(x) UTF8PROC_DLLEXPORT const char *utf8proc_version(void) { return STRINGIZE(UTF8PROC_VERSION_MAJOR) "." STRINGIZE(UTF8PROC_VERSION_MINOR) "." STRINGIZE(UTF8PROC_VERSION_PATCH) ""; } UTF8PROC_DLLEXPORT const char *utf8proc_unicode_version(void) { return "15.0.0"; } UTF8PROC_DLLEXPORT const char *utf8proc_errmsg(utf8proc_ssize_t errcode) { switch (errcode) { case UTF8PROC_ERROR_NOMEM: return "Memory for processing UTF-8 data could not be allocated."; case UTF8PROC_ERROR_OVERFLOW: return "UTF-8 string is too long to be processed."; case UTF8PROC_ERROR_INVALIDUTF8: return "Invalid UTF-8 string"; case UTF8PROC_ERROR_NOTASSIGNED: return "Unassigned Unicode code point found in UTF-8 string."; case UTF8PROC_ERROR_INVALIDOPTS: return "Invalid options for UTF-8 processing chosen."; default: return "An unknown error occurred while processing UTF-8 data."; } } #define utf_cont(ch) (((ch) & 0xc0) == 0x80) UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_iterate( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *dst ) { utf8proc_int32_t uc; const utf8proc_uint8_t *end; *dst = -1; if (!strlen) return 0; end = str + ((strlen < 0) ? 4 : strlen); uc = *str++; if (uc < 0x80) { *dst = uc; return 1; } // Must be between 0xc2 and 0xf4 inclusive to be valid if ((utf8proc_uint32_t)(uc - 0xc2) > (0xf4-0xc2)) return UTF8PROC_ERROR_INVALIDUTF8; if (uc < 0xe0) { // 2-byte sequence // Must have valid continuation character if (str >= end || !utf_cont(*str)) return UTF8PROC_ERROR_INVALIDUTF8; *dst = ((uc & 0x1f)<<6) | (*str & 0x3f); return 2; } if (uc < 0xf0) { // 3-byte sequence if ((str + 1 >= end) || !utf_cont(*str) || !utf_cont(str[1])) return UTF8PROC_ERROR_INVALIDUTF8; // Check for surrogate chars if (uc == 0xed && *str > 0x9f) return UTF8PROC_ERROR_INVALIDUTF8; uc = ((uc & 0xf)<<12) | ((*str & 0x3f)<<6) | (str[1] & 0x3f); if (uc < 0x800) return UTF8PROC_ERROR_INVALIDUTF8; *dst = uc; return 3; } // 4-byte sequence // Must have 3 valid continuation characters if ((str + 2 >= end) || !utf_cont(*str) || !utf_cont(str[1]) || !utf_cont(str[2])) return UTF8PROC_ERROR_INVALIDUTF8; // Make sure in correct range (0x10000 - 0x10ffff) if (uc == 0xf0) { if (*str < 0x90) return UTF8PROC_ERROR_INVALIDUTF8; } else if (uc == 0xf4) { if (*str > 0x8f) return UTF8PROC_ERROR_INVALIDUTF8; } *dst = ((uc & 7)<<18) | ((*str & 0x3f)<<12) | ((str[1] & 0x3f)<<6) | (str[2] & 0x3f); return 4; } UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_codepoint_valid(utf8proc_int32_t uc) { return (((utf8proc_uint32_t)uc)-0xd800 > 0x07ff) && ((utf8proc_uint32_t)uc < 0x110000); } UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t *dst) { if (uc < 0x00) { return 0; } else if (uc < 0x80) { dst[0] = (utf8proc_uint8_t) uc; return 1; } else if (uc < 0x800) { dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6)); dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); return 2; // Note: we allow encoding 0xd800-0xdfff here, so as not to change // the API, however, these are actually invalid in UTF-8 } else if (uc < 0x10000) { dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12)); dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F)); dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); return 3; } else if (uc < 0x110000) { dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18)); dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F)); dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F)); dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); return 4; } else return 0; } /* internal version used for inserting 0xff bytes between graphemes */ static utf8proc_ssize_t charbound_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t *dst) { if (uc < 0x00) { if (uc == -1) { /* internal value used for grapheme breaks */ dst[0] = (utf8proc_uint8_t)0xFF; return 1; } return 0; } else if (uc < 0x80) { dst[0] = (utf8proc_uint8_t)uc; return 1; } else if (uc < 0x800) { dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6)); dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); return 2; } else if (uc < 0x10000) { dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12)); dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F)); dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); return 3; } else if (uc < 0x110000) { dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18)); dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F)); dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F)); dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F)); return 4; } else return 0; } /* internal "unsafe" version that does not check whether uc is in range */ static const utf8proc_property_t *unsafe_get_property(utf8proc_int32_t uc) { /* ASSERT: uc >= 0 && uc < 0x110000 */ return utf8proc_properties + ( utf8proc_stage2table[ utf8proc_stage1table[uc >> 8] + (uc & 0xFF) ] ); } UTF8PROC_DLLEXPORT const utf8proc_property_t *utf8proc_get_property(utf8proc_int32_t uc) { return uc < 0 || uc >= 0x110000 ? utf8proc_properties : unsafe_get_property(uc); } /* return whether there is a grapheme break between boundclasses lbc and tbc (according to the definition of extended grapheme clusters) Rule numbering refers to TR29 Version 29 (Unicode 9.0.0): http://www.unicode.org/reports/tr29/tr29-29.html CAVEATS: Please note that evaluation of GB10 (grapheme breaks between emoji zwj sequences) and GB 12/13 (regional indicator code points) require knowledge of previous characters and are thus not handled by this function. This may result in an incorrect break before an E_Modifier class codepoint and an incorrectly missing break between two REGIONAL_INDICATOR class code points if such support does not exist in the caller. See the special support in grapheme_break_extended, for required bookkeeping by the caller. */ static utf8proc_bool grapheme_break_simple(int lbc, int tbc) { return (lbc == UTF8PROC_BOUNDCLASS_START) ? true : // GB1 (lbc == UTF8PROC_BOUNDCLASS_CR && // GB3 tbc == UTF8PROC_BOUNDCLASS_LF) ? false : // --- (lbc >= UTF8PROC_BOUNDCLASS_CR && lbc <= UTF8PROC_BOUNDCLASS_CONTROL) ? true : // GB4 (tbc >= UTF8PROC_BOUNDCLASS_CR && tbc <= UTF8PROC_BOUNDCLASS_CONTROL) ? true : // GB5 (lbc == UTF8PROC_BOUNDCLASS_L && // GB6 (tbc == UTF8PROC_BOUNDCLASS_L || // --- tbc == UTF8PROC_BOUNDCLASS_V || // --- tbc == UTF8PROC_BOUNDCLASS_LV || // --- tbc == UTF8PROC_BOUNDCLASS_LVT)) ? false : // --- ((lbc == UTF8PROC_BOUNDCLASS_LV || // GB7 lbc == UTF8PROC_BOUNDCLASS_V) && // --- (tbc == UTF8PROC_BOUNDCLASS_V || // --- tbc == UTF8PROC_BOUNDCLASS_T)) ? false : // --- ((lbc == UTF8PROC_BOUNDCLASS_LVT || // GB8 lbc == UTF8PROC_BOUNDCLASS_T) && // --- tbc == UTF8PROC_BOUNDCLASS_T) ? false : // --- (tbc == UTF8PROC_BOUNDCLASS_EXTEND || // GB9 tbc == UTF8PROC_BOUNDCLASS_ZWJ || // --- tbc == UTF8PROC_BOUNDCLASS_SPACINGMARK || // GB9a lbc == UTF8PROC_BOUNDCLASS_PREPEND) ? false : // GB9b (lbc == UTF8PROC_BOUNDCLASS_E_ZWG && // GB11 (requires additional handling below) tbc == UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC) ? false : // ---- (lbc == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR && // GB12/13 (requires additional handling below) tbc == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR) ? false : // ---- true; // GB999 } static utf8proc_bool grapheme_break_extended(int lbc, int tbc, utf8proc_int32_t *state) { if (state) { int lbc_override; if (*state == UTF8PROC_BOUNDCLASS_START) *state = lbc_override = lbc; else lbc_override = *state; utf8proc_bool break_permitted = grapheme_break_simple(lbc_override, tbc); // Special support for GB 12/13 made possible by GB999. After two RI // class codepoints we want to force a break. Do this by resetting the // second RI's bound class to UTF8PROC_BOUNDCLASS_OTHER, to force a break // after that character according to GB999 (unless of course such a break is // forbidden by a different rule such as GB9). if (*state == tbc && tbc == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR) *state = UTF8PROC_BOUNDCLASS_OTHER; // Special support for GB11 (emoji extend* zwj / emoji) else if (*state == UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC) { if (tbc == UTF8PROC_BOUNDCLASS_EXTEND) // fold EXTEND codepoints into emoji *state = UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC; else if (tbc == UTF8PROC_BOUNDCLASS_ZWJ) *state = UTF8PROC_BOUNDCLASS_E_ZWG; // state to record emoji+zwg combo else *state = tbc; } else *state = tbc; return break_permitted; } else return grapheme_break_simple(lbc, tbc); } UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break_stateful( utf8proc_int32_t c1, utf8proc_int32_t c2, utf8proc_int32_t *state) { return grapheme_break_extended(utf8proc_get_property(c1)->boundclass, utf8proc_get_property(c2)->boundclass, state); } UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break( utf8proc_int32_t c1, utf8proc_int32_t c2) { return utf8proc_grapheme_break_stateful(c1, c2, NULL); } static utf8proc_int32_t seqindex_decode_entry(const utf8proc_uint16_t **entry) { utf8proc_int32_t entry_cp = **entry; if ((entry_cp & 0xF800) == 0xD800) { *entry = *entry + 1; entry_cp = ((entry_cp & 0x03FF) << 10) | (**entry & 0x03FF); entry_cp += 0x10000; } return entry_cp; } static utf8proc_int32_t seqindex_decode_index(const utf8proc_uint32_t seqindex) { const utf8proc_uint16_t *entry = &utf8proc_sequences[seqindex]; return seqindex_decode_entry(&entry); } static utf8proc_ssize_t seqindex_write_char_decomposed(utf8proc_uint16_t seqindex, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) { utf8proc_ssize_t written = 0; const utf8proc_uint16_t *entry = &utf8proc_sequences[seqindex & 0x3FFF]; int len = seqindex >> 14; if (len >= 3) { len = *entry; entry++; } for (; len >= 0; entry++, len--) { utf8proc_int32_t entry_cp = seqindex_decode_entry(&entry); written += utf8proc_decompose_char(entry_cp, dst+written, (bufsize > written) ? (bufsize - written) : 0, options, last_boundclass); if (written < 0) return UTF8PROC_ERROR_OVERFLOW; } return written; } UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_tolower(utf8proc_int32_t c) { utf8proc_int32_t cl = utf8proc_get_property(c)->lowercase_seqindex; return cl != UINT16_MAX ? seqindex_decode_index((utf8proc_uint32_t)cl) : c; } UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_toupper(utf8proc_int32_t c) { utf8proc_int32_t cu = utf8proc_get_property(c)->uppercase_seqindex; return cu != UINT16_MAX ? seqindex_decode_index((utf8proc_uint32_t)cu) : c; } UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_totitle(utf8proc_int32_t c) { utf8proc_int32_t cu = utf8proc_get_property(c)->titlecase_seqindex; return cu != UINT16_MAX ? seqindex_decode_index((utf8proc_uint32_t)cu) : c; } UTF8PROC_DLLEXPORT int utf8proc_islower(utf8proc_int32_t c) { const utf8proc_property_t *p = utf8proc_get_property(c); return p->lowercase_seqindex != p->uppercase_seqindex && p->lowercase_seqindex == UINT16_MAX; } UTF8PROC_DLLEXPORT int utf8proc_isupper(utf8proc_int32_t c) { const utf8proc_property_t *p = utf8proc_get_property(c); return p->lowercase_seqindex != p->uppercase_seqindex && p->uppercase_seqindex == UINT16_MAX && p->category != UTF8PROC_CATEGORY_LT; } /* return a character width analogous to wcwidth (except portable and hopefully less buggy than most system wcwidth functions). */ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) { return utf8proc_get_property(c)->charwidth; } UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) { return (utf8proc_category_t) utf8proc_get_property(c)->category; } UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) { static const char s[][3] = {"Cn","Lu","Ll","Lt","Lm","Lo","Mn","Mc","Me","Nd","Nl","No","Pc","Pd","Ps","Pe","Pi","Pf","Po","Sm","Sc","Sk","So","Zs","Zl","Zp","Cc","Cf","Cs","Co"}; return s[utf8proc_category(c)]; } #define utf8proc_decompose_lump(replacement_uc) \ return utf8proc_decompose_char((replacement_uc), dst, bufsize, \ options & ~(unsigned int)UTF8PROC_LUMP, last_boundclass) UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) { const utf8proc_property_t *property; utf8proc_propval_t category; utf8proc_int32_t hangul_sindex; if (uc < 0 || uc >= 0x110000) return UTF8PROC_ERROR_NOTASSIGNED; property = unsafe_get_property(uc); category = property->category; hangul_sindex = uc - UTF8PROC_HANGUL_SBASE; if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) { utf8proc_int32_t hangul_tindex; if (bufsize >= 1) { dst[0] = UTF8PROC_HANGUL_LBASE + hangul_sindex / UTF8PROC_HANGUL_NCOUNT; if (bufsize >= 2) dst[1] = UTF8PROC_HANGUL_VBASE + (hangul_sindex % UTF8PROC_HANGUL_NCOUNT) / UTF8PROC_HANGUL_TCOUNT; } hangul_tindex = hangul_sindex % UTF8PROC_HANGUL_TCOUNT; if (!hangul_tindex) return 2; if (bufsize >= 3) dst[2] = UTF8PROC_HANGUL_TBASE + hangul_tindex; return 3; } } if (options & UTF8PROC_REJECTNA) { if (!category) return UTF8PROC_ERROR_NOTASSIGNED; } if (options & UTF8PROC_IGNORE) { if (property->ignorable) return 0; } if (options & UTF8PROC_STRIPNA) { if (!category) return 0; } if (options & UTF8PROC_LUMP) { if (category == UTF8PROC_CATEGORY_ZS) utf8proc_decompose_lump(0x0020); if (uc == 0x2018 || uc == 0x2019 || uc == 0x02BC || uc == 0x02C8) utf8proc_decompose_lump(0x0027); if (category == UTF8PROC_CATEGORY_PD || uc == 0x2212) utf8proc_decompose_lump(0x002D); if (uc == 0x2044 || uc == 0x2215) utf8proc_decompose_lump(0x002F); if (uc == 0x2236) utf8proc_decompose_lump(0x003A); if (uc == 0x2039 || uc == 0x2329 || uc == 0x3008) utf8proc_decompose_lump(0x003C); if (uc == 0x203A || uc == 0x232A || uc == 0x3009) utf8proc_decompose_lump(0x003E); if (uc == 0x2216) utf8proc_decompose_lump(0x005C); if (uc == 0x02C4 || uc == 0x02C6 || uc == 0x2038 || uc == 0x2303) utf8proc_decompose_lump(0x005E); if (category == UTF8PROC_CATEGORY_PC || uc == 0x02CD) utf8proc_decompose_lump(0x005F); if (uc == 0x02CB) utf8proc_decompose_lump(0x0060); if (uc == 0x2223) utf8proc_decompose_lump(0x007C); if (uc == 0x223C) utf8proc_decompose_lump(0x007E); if ((options & UTF8PROC_NLF2LS) && (options & UTF8PROC_NLF2PS)) { if (category == UTF8PROC_CATEGORY_ZL || category == UTF8PROC_CATEGORY_ZP) utf8proc_decompose_lump(0x000A); } } if (options & UTF8PROC_STRIPMARK) { if (category == UTF8PROC_CATEGORY_MN || category == UTF8PROC_CATEGORY_MC || category == UTF8PROC_CATEGORY_ME) return 0; } if (options & UTF8PROC_CASEFOLD) { if (property->casefold_seqindex != UINT16_MAX) { return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass); } } if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { if (property->decomp_seqindex != UINT16_MAX && (!property->decomp_type || (options & UTF8PROC_COMPAT))) { return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass); } } if (options & UTF8PROC_CHARBOUND) { utf8proc_bool boundary; int tbc = property->boundclass; boundary = grapheme_break_extended(*last_boundclass, tbc, last_boundclass); if (boundary) { if (bufsize >= 1) dst[0] = -1; /* sentinel value for grapheme break */ if (bufsize >= 2) dst[1] = uc; return 2; } } if (bufsize >= 1) *dst = uc; return 1; } UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options ) { return utf8proc_decompose_custom(str, strlen, buffer, bufsize, options, NULL, NULL); } UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options, utf8proc_custom_func custom_func, void *custom_data ) { /* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */ utf8proc_ssize_t wpos = 0; if ((options & UTF8PROC_COMPOSE) && (options & UTF8PROC_DECOMPOSE)) return UTF8PROC_ERROR_INVALIDOPTS; if ((options & UTF8PROC_STRIPMARK) && !(options & UTF8PROC_COMPOSE) && !(options & UTF8PROC_DECOMPOSE)) return UTF8PROC_ERROR_INVALIDOPTS; { utf8proc_int32_t uc; utf8proc_ssize_t rpos = 0; utf8proc_ssize_t decomp_result; int boundclass = UTF8PROC_BOUNDCLASS_START; while (1) { if (options & UTF8PROC_NULLTERM) { rpos += utf8proc_iterate(str + rpos, -1, &uc); /* checking of return value is not necessary, as 'uc' is < 0 in case of error */ if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; if (rpos < 0) return UTF8PROC_ERROR_OVERFLOW; if (uc == 0) break; } else { if (rpos >= strlen) break; rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc); if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; } if (custom_func != NULL) { uc = custom_func(uc, custom_data); /* user-specified custom mapping */ } decomp_result = utf8proc_decompose_char( uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options, &boundclass ); if (decomp_result < 0) return decomp_result; wpos += decomp_result; /* prohibiting integer overflows due to too long strings: */ if (wpos < 0 || wpos > (utf8proc_ssize_t)(SSIZE_MAX/sizeof(utf8proc_int32_t)/2)) return UTF8PROC_ERROR_OVERFLOW; } } if ((options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) && bufsize >= wpos) { utf8proc_ssize_t pos = 0; while (pos < wpos-1) { utf8proc_int32_t uc1, uc2; const utf8proc_property_t *property1, *property2; uc1 = buffer[pos]; uc2 = buffer[pos+1]; property1 = unsafe_get_property(uc1); property2 = unsafe_get_property(uc2); if (property1->combining_class > property2->combining_class && property2->combining_class > 0) { buffer[pos] = uc2; buffer[pos+1] = uc1; if (pos > 0) pos--; else pos++; } else { pos++; } } } return wpos; } UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) { /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored */ if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) { utf8proc_ssize_t rpos; utf8proc_ssize_t wpos = 0; utf8proc_int32_t uc; for (rpos = 0; rpos < length; rpos++) { uc = buffer[rpos]; if (uc == 0x000D && rpos < length-1 && buffer[rpos+1] == 0x000A) rpos++; if (uc == 0x000A || uc == 0x000D || uc == 0x0085 || ((options & UTF8PROC_STRIPCC) && (uc == 0x000B || uc == 0x000C))) { if (options & UTF8PROC_NLF2LS) { if (options & UTF8PROC_NLF2PS) { buffer[wpos++] = 0x000A; } else { buffer[wpos++] = 0x2028; } } else { if (options & UTF8PROC_NLF2PS) { buffer[wpos++] = 0x2029; } else { buffer[wpos++] = 0x0020; } } } else if ((options & UTF8PROC_STRIPCC) && (uc < 0x0020 || (uc >= 0x007F && uc < 0x00A0))) { if (uc == 0x0009) buffer[wpos++] = 0x0020; } else { buffer[wpos++] = uc; } } length = wpos; } if (options & UTF8PROC_COMPOSE) { utf8proc_int32_t *starter = NULL; utf8proc_int32_t current_char; const utf8proc_property_t *starter_property = NULL, *current_property; utf8proc_propval_t max_combining_class = -1; utf8proc_ssize_t rpos; utf8proc_ssize_t wpos = 0; utf8proc_int32_t composition; for (rpos = 0; rpos < length; rpos++) { current_char = buffer[rpos]; current_property = unsafe_get_property(current_char); if (starter && current_property->combining_class > max_combining_class) { /* combination perhaps possible */ utf8proc_int32_t hangul_lindex; utf8proc_int32_t hangul_sindex; hangul_lindex = *starter - UTF8PROC_HANGUL_LBASE; if (hangul_lindex >= 0 && hangul_lindex < UTF8PROC_HANGUL_LCOUNT) { utf8proc_int32_t hangul_vindex; hangul_vindex = current_char - UTF8PROC_HANGUL_VBASE; if (hangul_vindex >= 0 && hangul_vindex < UTF8PROC_HANGUL_VCOUNT) { *starter = UTF8PROC_HANGUL_SBASE + (hangul_lindex * UTF8PROC_HANGUL_VCOUNT + hangul_vindex) * UTF8PROC_HANGUL_TCOUNT; starter_property = NULL; continue; } } hangul_sindex = *starter - UTF8PROC_HANGUL_SBASE; if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT && (hangul_sindex % UTF8PROC_HANGUL_TCOUNT) == 0) { utf8proc_int32_t hangul_tindex; hangul_tindex = current_char - UTF8PROC_HANGUL_TBASE; if (hangul_tindex >= 0 && hangul_tindex < UTF8PROC_HANGUL_TCOUNT) { *starter += hangul_tindex; starter_property = NULL; continue; } } if (!starter_property) { starter_property = unsafe_get_property(*starter); } if (starter_property->comb_index < 0x8000 && current_property->comb_index != UINT16_MAX && current_property->comb_index >= 0x8000) { int sidx = starter_property->comb_index; int idx = current_property->comb_index & 0x3FFF; if (idx >= utf8proc_combinations[sidx] && idx <= utf8proc_combinations[sidx + 1] ) { idx += sidx + 2 - utf8proc_combinations[sidx]; if (current_property->comb_index & 0x4000) { composition = (utf8proc_combinations[idx] << 16) | utf8proc_combinations[idx+1]; } else composition = utf8proc_combinations[idx]; if (composition > 0 && (!(options & UTF8PROC_STABLE) || !(unsafe_get_property(composition)->comp_exclusion))) { *starter = composition; starter_property = NULL; continue; } } } } buffer[wpos] = current_char; if (current_property->combining_class) { if (current_property->combining_class > max_combining_class) { max_combining_class = current_property->combining_class; } } else { starter = buffer + wpos; starter_property = NULL; max_combining_class = -1; } wpos++; } length = wpos; } return length; } UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) { /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored ASSERT: 'buffer' has one spare byte of free space at the end! */ length = utf8proc_normalize_utf32(buffer, length, options); if (length < 0) return length; { utf8proc_ssize_t rpos, wpos = 0; utf8proc_int32_t uc; if (options & UTF8PROC_CHARBOUND) { for (rpos = 0; rpos < length; rpos++) { uc = buffer[rpos]; wpos += charbound_encode_char(uc, ((utf8proc_uint8_t *)buffer) + wpos); } } else { for (rpos = 0; rpos < length; rpos++) { uc = buffer[rpos]; wpos += utf8proc_encode_char(uc, ((utf8proc_uint8_t *)buffer) + wpos); } } ((utf8proc_uint8_t *)buffer)[wpos] = 0; return wpos; } } UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options ) { return utf8proc_map_custom(str, strlen, dstptr, options, NULL, NULL); } UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options, utf8proc_custom_func custom_func, void *custom_data ) { utf8proc_int32_t *buffer; utf8proc_ssize_t result; *dstptr = NULL; result = utf8proc_decompose_custom(str, strlen, NULL, 0, options, custom_func, custom_data); if (result < 0) return result; buffer = (utf8proc_int32_t *) malloc(((utf8proc_size_t)result) * sizeof(utf8proc_int32_t) + 1); if (!buffer) return UTF8PROC_ERROR_NOMEM; result = utf8proc_decompose_custom(str, strlen, buffer, result, options, custom_func, custom_data); if (result < 0) { free(buffer); return result; } result = utf8proc_reencode(buffer, result, options); if (result < 0) { free(buffer); return result; } { utf8proc_int32_t *newptr; newptr = (utf8proc_int32_t *) realloc(buffer, (size_t)result+1); if (newptr) buffer = newptr; } *dstptr = (utf8proc_uint8_t *)buffer; return result; } UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) { utf8proc_uint8_t *retval; utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_DECOMPOSE); return retval; } UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) { utf8proc_uint8_t *retval; utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE); return retval; } UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) { utf8proc_uint8_t *retval; utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT); return retval; } UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) { utf8proc_uint8_t *retval; utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE | UTF8PROC_COMPAT); return retval; } UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC_Casefold(const utf8proc_uint8_t *str) { utf8proc_uint8_t *retval; utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE | UTF8PROC_COMPAT | UTF8PROC_CASEFOLD | UTF8PROC_IGNORE); return retval; } mongodb-1.21.0/src/libmongoc/src/utf8proc-2.8.0/utf8proc.h0000644000175100001660000007443114760300420017635 0ustar /* * Copyright (c) 2014-2021 Steven G. Johnson, Jiahao Chen, Peter Colberg, Tony Kelman, Scott P. Jones, and other contributors. * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany * * 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. */ /** * @mainpage * * utf8proc is a free/open-source (MIT/expat licensed) C library * providing Unicode normalization, case-folding, and other operations * for strings in the UTF-8 encoding, supporting up-to-date Unicode versions. * See the utf8proc home page (http://julialang.org/utf8proc/) * for downloads and other information, or the source code on github * (https://github.com/JuliaLang/utf8proc). * * For the utf8proc API documentation, see: @ref utf8proc.h * * The features of utf8proc include: * * - Transformation of strings (@ref utf8proc_map) to: * - decompose (@ref UTF8PROC_DECOMPOSE) or compose (@ref UTF8PROC_COMPOSE) Unicode combining characters (http://en.wikipedia.org/wiki/Combining_character) * - canonicalize Unicode compatibility characters (@ref UTF8PROC_COMPAT) * - strip "ignorable" (@ref UTF8PROC_IGNORE) characters, control characters (@ref UTF8PROC_STRIPCC), or combining characters such as accents (@ref UTF8PROC_STRIPMARK) * - case-folding (@ref UTF8PROC_CASEFOLD) * - Unicode normalization: @ref utf8proc_NFD, @ref utf8proc_NFC, @ref utf8proc_NFKD, @ref utf8proc_NFKC * - Detecting grapheme boundaries (@ref utf8proc_grapheme_break and @ref UTF8PROC_CHARBOUND) * - Character-width computation: @ref utf8proc_charwidth * - Classification of characters by Unicode category: @ref utf8proc_category and @ref utf8proc_category_string * - Encode (@ref utf8proc_encode_char) and decode (@ref utf8proc_iterate) Unicode codepoints to/from UTF-8. */ /** @file */ #ifndef UTF8PROC_H #define UTF8PROC_H /** @name API version * * The utf8proc API version MAJOR.MINOR.PATCH, following * semantic-versioning rules (http://semver.org) based on API * compatibility. * * This is also returned at runtime by @ref utf8proc_version; however, the * runtime version may append a string like "-dev" to the version number * for prerelease versions. * * @note The shared-library version number in the Makefile * (and CMakeLists.txt, and MANIFEST) may be different, * being based on ABI compatibility rather than API compatibility. */ /** @{ */ /** The MAJOR version number (increased when backwards API compatibility is broken). */ #define UTF8PROC_VERSION_MAJOR 2 /** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */ #define UTF8PROC_VERSION_MINOR 8 /** The PATCH version (increased for fixes that do not change the API). */ #define UTF8PROC_VERSION_PATCH 0 /** @} */ #include #if defined(_MSC_VER) && _MSC_VER < 1800 // MSVC prior to 2013 lacked stdbool.h and inttypes.h typedef signed char utf8proc_int8_t; typedef unsigned char utf8proc_uint8_t; typedef short utf8proc_int16_t; typedef unsigned short utf8proc_uint16_t; typedef int utf8proc_int32_t; typedef unsigned int utf8proc_uint32_t; # ifdef _WIN64 typedef __int64 utf8proc_ssize_t; typedef unsigned __int64 utf8proc_size_t; # else typedef int utf8proc_ssize_t; typedef unsigned int utf8proc_size_t; # endif # ifndef __cplusplus // emulate C99 bool typedef unsigned char utf8proc_bool; # ifndef __bool_true_false_are_defined # define false 0 # define true 1 # define __bool_true_false_are_defined 1 # endif # else typedef bool utf8proc_bool; # endif #else # include # include # include typedef int8_t utf8proc_int8_t; typedef uint8_t utf8proc_uint8_t; typedef int16_t utf8proc_int16_t; typedef uint16_t utf8proc_uint16_t; typedef int32_t utf8proc_int32_t; typedef uint32_t utf8proc_uint32_t; typedef size_t utf8proc_size_t; typedef ptrdiff_t utf8proc_ssize_t; typedef bool utf8proc_bool; #endif #include #ifdef UTF8PROC_STATIC # define UTF8PROC_DLLEXPORT #else # ifdef _WIN32 # ifdef UTF8PROC_EXPORTS # define UTF8PROC_DLLEXPORT __declspec(dllexport) # else # define UTF8PROC_DLLEXPORT __declspec(dllimport) # endif # elif __GNUC__ >= 4 # define UTF8PROC_DLLEXPORT __attribute__ ((visibility("default"))) # else # define UTF8PROC_DLLEXPORT # endif #endif #ifdef __cplusplus extern "C" { #endif /** * Option flags used by several functions in the library. */ typedef enum { /** The given UTF-8 input is NULL terminated. */ UTF8PROC_NULLTERM = (1<<0), /** Unicode Versioning Stability has to be respected. */ UTF8PROC_STABLE = (1<<1), /** Compatibility decomposition (i.e. formatting information is lost). */ UTF8PROC_COMPAT = (1<<2), /** Return a result with decomposed characters. */ UTF8PROC_COMPOSE = (1<<3), /** Return a result with decomposed characters. */ UTF8PROC_DECOMPOSE = (1<<4), /** Strip "default ignorable characters" such as SOFT-HYPHEN or ZERO-WIDTH-SPACE. */ UTF8PROC_IGNORE = (1<<5), /** Return an error, if the input contains unassigned codepoints. */ UTF8PROC_REJECTNA = (1<<6), /** * Indicating that NLF-sequences (LF, CRLF, CR, NEL) are representing a * line break, and should be converted to the codepoint for line * separation (LS). */ UTF8PROC_NLF2LS = (1<<7), /** * Indicating that NLF-sequences are representing a paragraph break, and * should be converted to the codepoint for paragraph separation * (PS). */ UTF8PROC_NLF2PS = (1<<8), /** Indicating that the meaning of NLF-sequences is unknown. */ UTF8PROC_NLF2LF = (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS), /** Strips and/or convers control characters. * * NLF-sequences are transformed into space, except if one of the * NLF2LS/PS/LF options is given. HorizontalTab (HT) and FormFeed (FF) * are treated as a NLF-sequence in this case. All other control * characters are simply removed. */ UTF8PROC_STRIPCC = (1<<9), /** * Performs unicode case folding, to be able to do a case-insensitive * string comparison. */ UTF8PROC_CASEFOLD = (1<<10), /** * Inserts 0xFF bytes at the beginning of each sequence which is * representing a single grapheme cluster (see UAX#29). */ UTF8PROC_CHARBOUND = (1<<11), /** Lumps certain characters together. * * E.g. HYPHEN U+2010 and MINUS U+2212 to ASCII "-". See lump.md for details. * * If NLF2LF is set, this includes a transformation of paragraph and * line separators to ASCII line-feed (LF). */ UTF8PROC_LUMP = (1<<12), /** Strips all character markings. * * This includes non-spacing, spacing and enclosing (i.e. accents). * @note This option works only with @ref UTF8PROC_COMPOSE or * @ref UTF8PROC_DECOMPOSE */ UTF8PROC_STRIPMARK = (1<<13), /** * Strip unassigned codepoints. */ UTF8PROC_STRIPNA = (1<<14), } utf8proc_option_t; /** @name Error codes * Error codes being returned by almost all functions. */ /** @{ */ /** Memory could not be allocated. */ #define UTF8PROC_ERROR_NOMEM -1 /** The given string is too long to be processed. */ #define UTF8PROC_ERROR_OVERFLOW -2 /** The given string is not a legal UTF-8 string. */ #define UTF8PROC_ERROR_INVALIDUTF8 -3 /** The @ref UTF8PROC_REJECTNA flag was set and an unassigned codepoint was found. */ #define UTF8PROC_ERROR_NOTASSIGNED -4 /** Invalid options have been used. */ #define UTF8PROC_ERROR_INVALIDOPTS -5 /** @} */ /* @name Types */ /** Holds the value of a property. */ typedef utf8proc_int16_t utf8proc_propval_t; /** Struct containing information about a codepoint. */ typedef struct utf8proc_property_struct { /** * Unicode category. * @see utf8proc_category_t. */ utf8proc_propval_t category; utf8proc_propval_t combining_class; /** * Bidirectional class. * @see utf8proc_bidi_class_t. */ utf8proc_propval_t bidi_class; /** * @anchor Decomposition type. * @see utf8proc_decomp_type_t. */ utf8proc_propval_t decomp_type; utf8proc_uint16_t decomp_seqindex; utf8proc_uint16_t casefold_seqindex; utf8proc_uint16_t uppercase_seqindex; utf8proc_uint16_t lowercase_seqindex; utf8proc_uint16_t titlecase_seqindex; utf8proc_uint16_t comb_index; unsigned bidi_mirrored:1; unsigned comp_exclusion:1; /** * Can this codepoint be ignored? * * Used by @ref utf8proc_decompose_char when @ref UTF8PROC_IGNORE is * passed as an option. */ unsigned ignorable:1; unsigned control_boundary:1; /** The width of the codepoint. */ unsigned charwidth:2; unsigned pad:2; /** * Boundclass. * @see utf8proc_boundclass_t. */ unsigned boundclass:8; } utf8proc_property_t; /** Unicode categories. */ typedef enum { UTF8PROC_CATEGORY_CN = 0, /**< Other, not assigned */ UTF8PROC_CATEGORY_LU = 1, /**< Letter, uppercase */ UTF8PROC_CATEGORY_LL = 2, /**< Letter, lowercase */ UTF8PROC_CATEGORY_LT = 3, /**< Letter, titlecase */ UTF8PROC_CATEGORY_LM = 4, /**< Letter, modifier */ UTF8PROC_CATEGORY_LO = 5, /**< Letter, other */ UTF8PROC_CATEGORY_MN = 6, /**< Mark, nonspacing */ UTF8PROC_CATEGORY_MC = 7, /**< Mark, spacing combining */ UTF8PROC_CATEGORY_ME = 8, /**< Mark, enclosing */ UTF8PROC_CATEGORY_ND = 9, /**< Number, decimal digit */ UTF8PROC_CATEGORY_NL = 10, /**< Number, letter */ UTF8PROC_CATEGORY_NO = 11, /**< Number, other */ UTF8PROC_CATEGORY_PC = 12, /**< Punctuation, connector */ UTF8PROC_CATEGORY_PD = 13, /**< Punctuation, dash */ UTF8PROC_CATEGORY_PS = 14, /**< Punctuation, open */ UTF8PROC_CATEGORY_PE = 15, /**< Punctuation, close */ UTF8PROC_CATEGORY_PI = 16, /**< Punctuation, initial quote */ UTF8PROC_CATEGORY_PF = 17, /**< Punctuation, final quote */ UTF8PROC_CATEGORY_PO = 18, /**< Punctuation, other */ UTF8PROC_CATEGORY_SM = 19, /**< Symbol, math */ UTF8PROC_CATEGORY_SC = 20, /**< Symbol, currency */ UTF8PROC_CATEGORY_SK = 21, /**< Symbol, modifier */ UTF8PROC_CATEGORY_SO = 22, /**< Symbol, other */ UTF8PROC_CATEGORY_ZS = 23, /**< Separator, space */ UTF8PROC_CATEGORY_ZL = 24, /**< Separator, line */ UTF8PROC_CATEGORY_ZP = 25, /**< Separator, paragraph */ UTF8PROC_CATEGORY_CC = 26, /**< Other, control */ UTF8PROC_CATEGORY_CF = 27, /**< Other, format */ UTF8PROC_CATEGORY_CS = 28, /**< Other, surrogate */ UTF8PROC_CATEGORY_CO = 29, /**< Other, private use */ } utf8proc_category_t; /** Bidirectional character classes. */ typedef enum { UTF8PROC_BIDI_CLASS_L = 1, /**< Left-to-Right */ UTF8PROC_BIDI_CLASS_LRE = 2, /**< Left-to-Right Embedding */ UTF8PROC_BIDI_CLASS_LRO = 3, /**< Left-to-Right Override */ UTF8PROC_BIDI_CLASS_R = 4, /**< Right-to-Left */ UTF8PROC_BIDI_CLASS_AL = 5, /**< Right-to-Left Arabic */ UTF8PROC_BIDI_CLASS_RLE = 6, /**< Right-to-Left Embedding */ UTF8PROC_BIDI_CLASS_RLO = 7, /**< Right-to-Left Override */ UTF8PROC_BIDI_CLASS_PDF = 8, /**< Pop Directional Format */ UTF8PROC_BIDI_CLASS_EN = 9, /**< European Number */ UTF8PROC_BIDI_CLASS_ES = 10, /**< European Separator */ UTF8PROC_BIDI_CLASS_ET = 11, /**< European Number Terminator */ UTF8PROC_BIDI_CLASS_AN = 12, /**< Arabic Number */ UTF8PROC_BIDI_CLASS_CS = 13, /**< Common Number Separator */ UTF8PROC_BIDI_CLASS_NSM = 14, /**< Nonspacing Mark */ UTF8PROC_BIDI_CLASS_BN = 15, /**< Boundary Neutral */ UTF8PROC_BIDI_CLASS_B = 16, /**< Paragraph Separator */ UTF8PROC_BIDI_CLASS_S = 17, /**< Segment Separator */ UTF8PROC_BIDI_CLASS_WS = 18, /**< Whitespace */ UTF8PROC_BIDI_CLASS_ON = 19, /**< Other Neutrals */ UTF8PROC_BIDI_CLASS_LRI = 20, /**< Left-to-Right Isolate */ UTF8PROC_BIDI_CLASS_RLI = 21, /**< Right-to-Left Isolate */ UTF8PROC_BIDI_CLASS_FSI = 22, /**< First Strong Isolate */ UTF8PROC_BIDI_CLASS_PDI = 23, /**< Pop Directional Isolate */ } utf8proc_bidi_class_t; /** Decomposition type. */ typedef enum { UTF8PROC_DECOMP_TYPE_FONT = 1, /**< Font */ UTF8PROC_DECOMP_TYPE_NOBREAK = 2, /**< Nobreak */ UTF8PROC_DECOMP_TYPE_INITIAL = 3, /**< Initial */ UTF8PROC_DECOMP_TYPE_MEDIAL = 4, /**< Medial */ UTF8PROC_DECOMP_TYPE_FINAL = 5, /**< Final */ UTF8PROC_DECOMP_TYPE_ISOLATED = 6, /**< Isolated */ UTF8PROC_DECOMP_TYPE_CIRCLE = 7, /**< Circle */ UTF8PROC_DECOMP_TYPE_SUPER = 8, /**< Super */ UTF8PROC_DECOMP_TYPE_SUB = 9, /**< Sub */ UTF8PROC_DECOMP_TYPE_VERTICAL = 10, /**< Vertical */ UTF8PROC_DECOMP_TYPE_WIDE = 11, /**< Wide */ UTF8PROC_DECOMP_TYPE_NARROW = 12, /**< Narrow */ UTF8PROC_DECOMP_TYPE_SMALL = 13, /**< Small */ UTF8PROC_DECOMP_TYPE_SQUARE = 14, /**< Square */ UTF8PROC_DECOMP_TYPE_FRACTION = 15, /**< Fraction */ UTF8PROC_DECOMP_TYPE_COMPAT = 16, /**< Compat */ } utf8proc_decomp_type_t; /** Boundclass property. (TR29) */ typedef enum { UTF8PROC_BOUNDCLASS_START = 0, /**< Start */ UTF8PROC_BOUNDCLASS_OTHER = 1, /**< Other */ UTF8PROC_BOUNDCLASS_CR = 2, /**< Cr */ UTF8PROC_BOUNDCLASS_LF = 3, /**< Lf */ UTF8PROC_BOUNDCLASS_CONTROL = 4, /**< Control */ UTF8PROC_BOUNDCLASS_EXTEND = 5, /**< Extend */ UTF8PROC_BOUNDCLASS_L = 6, /**< L */ UTF8PROC_BOUNDCLASS_V = 7, /**< V */ UTF8PROC_BOUNDCLASS_T = 8, /**< T */ UTF8PROC_BOUNDCLASS_LV = 9, /**< Lv */ UTF8PROC_BOUNDCLASS_LVT = 10, /**< Lvt */ UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR = 11, /**< Regional indicator */ UTF8PROC_BOUNDCLASS_SPACINGMARK = 12, /**< Spacingmark */ UTF8PROC_BOUNDCLASS_PREPEND = 13, /**< Prepend */ UTF8PROC_BOUNDCLASS_ZWJ = 14, /**< Zero Width Joiner */ /* the following are no longer used in Unicode 11, but we keep the constants here for backward compatibility */ UTF8PROC_BOUNDCLASS_E_BASE = 15, /**< Emoji Base */ UTF8PROC_BOUNDCLASS_E_MODIFIER = 16, /**< Emoji Modifier */ UTF8PROC_BOUNDCLASS_GLUE_AFTER_ZWJ = 17, /**< Glue_After_ZWJ */ UTF8PROC_BOUNDCLASS_E_BASE_GAZ = 18, /**< E_BASE + GLUE_AFTER_ZJW */ /* the Extended_Pictographic property is used in the Unicode 11 grapheme-boundary rules, so we store it in the boundclass field */ UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC = 19, UTF8PROC_BOUNDCLASS_E_ZWG = 20, /* UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC + ZWJ */ } utf8proc_boundclass_t; /** * Function pointer type passed to @ref utf8proc_map_custom and * @ref utf8proc_decompose_custom, which is used to specify a user-defined * mapping of codepoints to be applied in conjunction with other mappings. */ typedef utf8proc_int32_t (*utf8proc_custom_func)(utf8proc_int32_t codepoint, void *data); /** * Array containing the byte lengths of a UTF-8 encoded codepoint based * on the first byte. */ UTF8PROC_DLLEXPORT extern const utf8proc_int8_t utf8proc_utf8class[256]; /** * Returns the utf8proc API version as a string MAJOR.MINOR.PATCH * (http://semver.org format), possibly with a "-dev" suffix for * development versions. */ UTF8PROC_DLLEXPORT const char *utf8proc_version(void); /** * Returns the utf8proc supported Unicode version as a string MAJOR.MINOR.PATCH. */ UTF8PROC_DLLEXPORT const char *utf8proc_unicode_version(void); /** * Returns an informative error string for the given utf8proc error code * (e.g. the error codes returned by @ref utf8proc_map). */ UTF8PROC_DLLEXPORT const char *utf8proc_errmsg(utf8proc_ssize_t errcode); /** * Reads a single codepoint from the UTF-8 sequence being pointed to by `str`. * The maximum number of bytes read is `strlen`, unless `strlen` is * negative (in which case up to 4 bytes are read). * * If a valid codepoint could be read, it is stored in the variable * pointed to by `codepoint_ref`, otherwise that variable will be set to -1. * In case of success, the number of bytes read is returned; otherwise, a * negative error code is returned. */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_iterate(const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *codepoint_ref); /** * Check if a codepoint is valid (regardless of whether it has been * assigned a value by the current Unicode standard). * * @return 1 if the given `codepoint` is valid and otherwise return 0. */ UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_codepoint_valid(utf8proc_int32_t codepoint); /** * Encodes the codepoint as an UTF-8 string in the byte array pointed * to by `dst`. This array must be at least 4 bytes long. * * In case of success the number of bytes written is returned, and * otherwise 0 is returned. * * This function does not check whether `codepoint` is valid Unicode. */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t codepoint, utf8proc_uint8_t *dst); /** * Look up the properties for a given codepoint. * * @param codepoint The Unicode codepoint. * * @returns * A pointer to a (constant) struct containing information about * the codepoint. * @par * If the codepoint is unassigned or invalid, a pointer to a special struct is * returned in which `category` is 0 (@ref UTF8PROC_CATEGORY_CN). */ UTF8PROC_DLLEXPORT const utf8proc_property_t *utf8proc_get_property(utf8proc_int32_t codepoint); /** Decompose a codepoint into an array of codepoints. * * @param codepoint the codepoint. * @param dst the destination buffer. * @param bufsize the size of the destination buffer. * @param options one or more of the following flags: * - @ref UTF8PROC_REJECTNA - return an error `codepoint` is unassigned * - @ref UTF8PROC_IGNORE - strip "default ignorable" codepoints * - @ref UTF8PROC_CASEFOLD - apply Unicode casefolding * - @ref UTF8PROC_COMPAT - replace certain codepoints with their * compatibility decomposition * - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster * - @ref UTF8PROC_LUMP - lump certain different codepoints together * - @ref UTF8PROC_STRIPMARK - remove all character marks * - @ref UTF8PROC_STRIPNA - remove unassigned codepoints * @param last_boundclass * Pointer to an integer variable containing * the previous codepoint's boundary class if the @ref UTF8PROC_CHARBOUND * option is used. Otherwise, this parameter is ignored. * * @return * In case of success, the number of codepoints written is returned; in case * of an error, a negative error code is returned (@ref utf8proc_errmsg). * @par * If the number of written codepoints would be bigger than `bufsize`, the * required buffer size is returned, while the buffer will be overwritten with * undefined data. */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char( utf8proc_int32_t codepoint, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass ); /** * The same as @ref utf8proc_decompose_char, but acts on a whole UTF-8 * string and orders the decomposed sequences correctly. * * If the @ref UTF8PROC_NULLTERM flag in `options` is set, processing * will be stopped, when a NULL byte is encountered, otherwise `strlen` * bytes are processed. The result (in the form of 32-bit unicode * codepoints) is written into the buffer being pointed to by * `buffer` (which must contain at least `bufsize` entries). In case of * success, the number of codepoints written is returned; in case of an * error, a negative error code is returned (@ref utf8proc_errmsg). * See @ref utf8proc_decompose_custom to supply additional transformations. * * If the number of written codepoints would be bigger than `bufsize`, the * required buffer size is returned, while the buffer will be overwritten with * undefined data. */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options ); /** * The same as @ref utf8proc_decompose, but also takes a `custom_func` mapping function * that is called on each codepoint in `str` before any other transformations * (along with a `custom_data` pointer that is passed through to `custom_func`). * The `custom_func` argument is ignored if it is `NULL`. See also @ref utf8proc_map_custom. */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options, utf8proc_custom_func custom_func, void *custom_data ); /** * Normalizes the sequence of `length` codepoints pointed to by `buffer` * in-place (i.e., the result is also stored in `buffer`). * * @param buffer the (native-endian UTF-32) unicode codepoints to re-encode. * @param length the length (in codepoints) of the buffer. * @param options a bitwise or (`|`) of one or more of the following flags: * - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS * - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS * - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF * - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters * - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite * codepoints * - @ref UTF8PROC_STABLE - prohibit combining characters that would violate * the unicode versioning stability * * @return * In case of success, the length (in codepoints) of the normalized UTF-32 string is * returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg). * * @warning The entries of the array pointed to by `str` have to be in the * range `0x0000` to `0x10FFFF`. Otherwise, the program might crash! */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options); /** * Reencodes the sequence of `length` codepoints pointed to by `buffer` * UTF-8 data in-place (i.e., the result is also stored in `buffer`). * Can optionally normalize the UTF-32 sequence prior to UTF-8 conversion. * * @param buffer the (native-endian UTF-32) unicode codepoints to re-encode. * @param length the length (in codepoints) of the buffer. * @param options a bitwise or (`|`) of one or more of the following flags: * - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS * - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS * - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF * - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters * - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite * codepoints * - @ref UTF8PROC_STABLE - prohibit combining characters that would violate * the unicode versioning stability * - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster * * @return * In case of success, the length (in bytes) of the resulting nul-terminated * UTF-8 string is returned; otherwise, a negative error code is returned * (@ref utf8proc_errmsg). * * @warning The amount of free space pointed to by `buffer` must * exceed the amount of the input data by one byte, and the * entries of the array pointed to by `str` have to be in the * range `0x0000` to `0x10FFFF`. Otherwise, the program might crash! */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options); /** * Given a pair of consecutive codepoints, return whether a grapheme break is * permitted between them (as defined by the extended grapheme clusters in UAX#29). * * @param codepoint1 The first codepoint. * @param codepoint2 The second codepoint, occurring consecutively after `codepoint1`. * @param state Beginning with Version 29 (Unicode 9.0.0), this algorithm requires * state to break graphemes. This state can be passed in as a pointer * in the `state` argument and should initially be set to 0. If the * state is not passed in (i.e. a null pointer is passed), UAX#29 rules * GB10/12/13 which require this state will not be applied, essentially * matching the rules in Unicode 8.0.0. * * @warning If the state parameter is used, `utf8proc_grapheme_break_stateful` must * be called IN ORDER on ALL potential breaks in a string. However, it * is safe to reset the state to zero after a grapheme break. */ UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break_stateful( utf8proc_int32_t codepoint1, utf8proc_int32_t codepoint2, utf8proc_int32_t *state); /** * Same as @ref utf8proc_grapheme_break_stateful, except without support for the * Unicode 9 additions to the algorithm. Supported for legacy reasons. */ UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break( utf8proc_int32_t codepoint1, utf8proc_int32_t codepoint2); /** * Given a codepoint `c`, return the codepoint of the corresponding * lower-case character, if any; otherwise (if there is no lower-case * variant, or if `c` is not a valid codepoint) return `c`. */ UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_tolower(utf8proc_int32_t c); /** * Given a codepoint `c`, return the codepoint of the corresponding * upper-case character, if any; otherwise (if there is no upper-case * variant, or if `c` is not a valid codepoint) return `c`. */ UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_toupper(utf8proc_int32_t c); /** * Given a codepoint `c`, return the codepoint of the corresponding * title-case character, if any; otherwise (if there is no title-case * variant, or if `c` is not a valid codepoint) return `c`. */ UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_totitle(utf8proc_int32_t c); /** * Given a codepoint `c`, return `1` if the codepoint corresponds to a lower-case character * and `0` otherwise. */ UTF8PROC_DLLEXPORT int utf8proc_islower(utf8proc_int32_t c); /** * Given a codepoint `c`, return `1` if the codepoint corresponds to an upper-case character * and `0` otherwise. */ UTF8PROC_DLLEXPORT int utf8proc_isupper(utf8proc_int32_t c); /** * Given a codepoint, return a character width analogous to `wcwidth(codepoint)`, * except that a width of 0 is returned for non-printable codepoints * instead of -1 as in `wcwidth`. * * @note * If you want to check for particular types of non-printable characters, * (analogous to `isprint` or `iscntrl`), use @ref utf8proc_category. */ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t codepoint); /** * Return the Unicode category for the codepoint (one of the * @ref utf8proc_category_t constants.) */ UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t codepoint); /** * Return the two-letter (nul-terminated) Unicode category string for * the codepoint (e.g. `"Lu"` or `"Co"`). */ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t codepoint); /** * Maps the given UTF-8 string pointed to by `str` to a new UTF-8 * string, allocated dynamically by `malloc` and returned via `dstptr`. * * If the @ref UTF8PROC_NULLTERM flag in the `options` field is set, * the length is determined by a NULL terminator, otherwise the * parameter `strlen` is evaluated to determine the string length, but * in any case the result will be NULL terminated (though it might * contain NULL characters with the string if `str` contained NULL * characters). Other flags in the `options` field are passed to the * functions defined above, and regarded as described. See also * @ref utf8proc_map_custom to supply a custom codepoint transformation. * * In case of success the length of the new string is returned, * otherwise a negative error code is returned. * * @note The memory of the new UTF-8 string will have been allocated * with `malloc`, and should therefore be deallocated with `free`. */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options ); /** * Like @ref utf8proc_map, but also takes a `custom_func` mapping function * that is called on each codepoint in `str` before any other transformations * (along with a `custom_data` pointer that is passed through to `custom_func`). * The `custom_func` argument is ignored if it is `NULL`. */ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom( const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options, utf8proc_custom_func custom_func, void *custom_data ); /** @name Unicode normalization * * Returns a pointer to newly allocated memory of a NFD, NFC, NFKD, NFKC or * NFKC_Casefold normalized version of the null-terminated string `str`. These * are shortcuts to calling @ref utf8proc_map with @ref UTF8PROC_NULLTERM * combined with @ref UTF8PROC_STABLE and flags indicating the normalization. */ /** @{ */ /** NFD normalization (@ref UTF8PROC_DECOMPOSE). */ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str); /** NFC normalization (@ref UTF8PROC_COMPOSE). */ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str); /** NFKD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str); /** NFKC normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str); /** * NFKC_Casefold normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT * and @ref UTF8PROC_CASEFOLD and @ref UTF8PROC_IGNORE). **/ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC_Casefold(const utf8proc_uint8_t *str); /** @} */ #ifdef __cplusplus } #endif #endif mongodb-1.21.0/src/libmongoc/src/utf8proc-2.8.0/utf8proc_data.c0000644000175100001660000730776414760300420020640 0ustar static const utf8proc_uint16_t utf8proc_sequences[] = { 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 32, 32, 776, 32, 772, 50, 51, 32, 769, 956, 32, 807, 49, 49, 8260, 52, 49, 8260, 50, 51, 8260, 52, 65, 768, 224, 65, 769, 225, 65, 770, 226, 65, 771, 227, 65, 776, 228, 65, 778, 229, 230, 67, 807, 231, 69, 768, 232, 69, 769, 233, 69, 770, 234, 69, 776, 235, 73, 768, 236, 73, 769, 237, 73, 770, 238, 73, 776, 239, 240, 78, 771, 241, 79, 768, 242, 79, 769, 243, 79, 770, 244, 79, 771, 245, 79, 776, 246, 248, 85, 768, 249, 85, 769, 250, 85, 770, 251, 85, 776, 252, 89, 769, 253, 254, 115, 115, 97, 768, 97, 769, 97, 770, 97, 771, 97, 776, 97, 778, 99, 807, 101, 768, 101, 769, 101, 770, 101, 776, 105, 768, 105, 769, 105, 770, 105, 776, 110, 771, 111, 768, 111, 769, 111, 770, 111, 771, 111, 776, 117, 768, 117, 769, 117, 770, 117, 776, 121, 769, 121, 776, 65, 772, 257, 97, 772, 65, 774, 259, 97, 774, 65, 808, 261, 97, 808, 67, 769, 263, 99, 769, 67, 770, 265, 99, 770, 67, 775, 267, 99, 775, 67, 780, 269, 99, 780, 68, 780, 271, 100, 780, 273, 69, 772, 275, 101, 772, 69, 774, 277, 101, 774, 69, 775, 279, 101, 775, 69, 808, 281, 101, 808, 69, 780, 283, 101, 780, 71, 770, 285, 103, 770, 71, 774, 287, 103, 774, 71, 775, 289, 103, 775, 71, 807, 291, 103, 807, 72, 770, 293, 104, 770, 295, 73, 771, 297, 105, 771, 73, 772, 299, 105, 772, 73, 774, 301, 105, 774, 73, 808, 303, 105, 808, 73, 775, 105, 775, 73, 74, 307, 105, 106, 74, 770, 309, 106, 770, 75, 807, 311, 107, 807, 76, 769, 314, 108, 769, 76, 807, 316, 108, 807, 76, 780, 318, 108, 780, 76, 183, 320, 108, 183, 322, 78, 769, 324, 110, 769, 78, 807, 326, 110, 807, 78, 780, 328, 110, 780, 700, 110, 331, 79, 772, 333, 111, 772, 79, 774, 335, 111, 774, 79, 779, 337, 111, 779, 339, 82, 769, 341, 114, 769, 82, 807, 343, 114, 807, 82, 780, 345, 114, 780, 83, 769, 347, 115, 769, 83, 770, 349, 115, 770, 83, 807, 351, 115, 807, 83, 780, 353, 115, 780, 84, 807, 355, 116, 807, 84, 780, 357, 116, 780, 359, 85, 771, 361, 117, 771, 85, 772, 363, 117, 772, 85, 774, 365, 117, 774, 85, 778, 367, 117, 778, 85, 779, 369, 117, 779, 85, 808, 371, 117, 808, 87, 770, 373, 119, 770, 89, 770, 375, 121, 770, 89, 776, 255, 90, 769, 378, 122, 769, 90, 775, 380, 122, 775, 90, 780, 382, 122, 780, 595, 387, 389, 596, 392, 598, 599, 396, 477, 601, 603, 402, 608, 611, 617, 616, 409, 623, 626, 629, 79, 795, 417, 111, 795, 419, 421, 640, 424, 643, 429, 648, 85, 795, 432, 117, 795, 650, 651, 436, 438, 658, 441, 445, 68, 381, 454, 68, 382, 100, 382, 76, 74, 457, 76, 106, 108, 106, 78, 74, 460, 78, 106, 110, 106, 65, 780, 462, 97, 780, 73, 780, 464, 105, 780, 79, 780, 466, 111, 780, 85, 780, 468, 117, 780, 220, 772, 470, 252, 772, 220, 769, 472, 252, 769, 220, 780, 474, 252, 780, 220, 768, 476, 252, 768, 196, 772, 479, 228, 772, 550, 772, 481, 551, 772, 198, 772, 483, 230, 772, 485, 71, 780, 487, 103, 780, 75, 780, 489, 107, 780, 79, 808, 491, 111, 808, 490, 772, 493, 491, 772, 439, 780, 495, 658, 780, 106, 780, 68, 90, 499, 68, 122, 100, 122, 71, 769, 501, 103, 769, 405, 447, 78, 768, 505, 110, 768, 197, 769, 507, 229, 769, 198, 769, 509, 230, 769, 216, 769, 511, 248, 769, 65, 783, 513, 97, 783, 65, 785, 515, 97, 785, 69, 783, 517, 101, 783, 69, 785, 519, 101, 785, 73, 783, 521, 105, 783, 73, 785, 523, 105, 785, 79, 783, 525, 111, 783, 79, 785, 527, 111, 785, 82, 783, 529, 114, 783, 82, 785, 531, 114, 785, 85, 783, 533, 117, 783, 85, 785, 535, 117, 785, 83, 806, 537, 115, 806, 84, 806, 539, 116, 806, 541, 72, 780, 543, 104, 780, 414, 547, 549, 65, 775, 551, 97, 775, 69, 807, 553, 101, 807, 214, 772, 555, 246, 772, 213, 772, 557, 245, 772, 79, 775, 559, 111, 775, 558, 772, 561, 559, 772, 89, 772, 563, 121, 772, 11365, 572, 410, 11366, 578, 384, 649, 652, 583, 585, 587, 589, 591, 614, 633, 635, 641, 32, 774, 32, 775, 32, 778, 32, 808, 32, 771, 32, 779, 661, 768, 769, 787, 776, 769, 953, 881, 883, 697, 887, 32, 837, 59, 1011, 168, 769, 913, 769, 940, 183, 917, 769, 941, 919, 769, 942, 921, 769, 943, 927, 769, 972, 933, 769, 973, 937, 769, 974, 970, 769, 953, 776, 769, 945, 946, 947, 948, 949, 950, 951, 952, 954, 955, 957, 958, 959, 960, 961, 963, 964, 965, 966, 967, 968, 969, 921, 776, 970, 933, 776, 971, 945, 769, 949, 769, 951, 769, 953, 769, 971, 769, 965, 776, 769, 953, 776, 965, 776, 959, 769, 965, 769, 969, 769, 983, 933, 978, 769, 978, 776, 985, 987, 989, 991, 993, 995, 997, 999, 1001, 1003, 1005, 1007, 962, 920, 1016, 931, 1010, 1019, 891, 892, 893, 1045, 768, 1104, 1045, 776, 1105, 1106, 1043, 769, 1107, 1108, 1109, 1110, 1030, 776, 1111, 1112, 1113, 1114, 1115, 1050, 769, 1116, 1048, 768, 1117, 1059, 774, 1118, 1119, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1048, 774, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1080, 774, 1077, 768, 1077, 776, 1075, 769, 1110, 776, 1082, 769, 1080, 768, 1091, 774, 1121, 1123, 1125, 1127, 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1140, 783, 1143, 1141, 783, 1145, 1147, 1149, 1151, 1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215, 1231, 1046, 774, 1218, 1078, 774, 1220, 1222, 1224, 1226, 1228, 1230, 1040, 774, 1233, 1072, 774, 1040, 776, 1235, 1072, 776, 1237, 1045, 774, 1239, 1077, 774, 1241, 1240, 776, 1243, 1241, 776, 1046, 776, 1245, 1078, 776, 1047, 776, 1247, 1079, 776, 1249, 1048, 772, 1251, 1080, 772, 1048, 776, 1253, 1080, 776, 1054, 776, 1255, 1086, 776, 1257, 1256, 776, 1259, 1257, 776, 1069, 776, 1261, 1101, 776, 1059, 772, 1263, 1091, 772, 1059, 776, 1265, 1091, 776, 1059, 779, 1267, 1091, 779, 1063, 776, 1269, 1095, 776, 1271, 1067, 776, 1273, 1099, 776, 1275, 1277, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299, 1301, 1303, 1305, 1307, 1309, 1311, 1313, 1315, 1317, 1319, 1321, 1323, 1325, 1327, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1381, 1410, 1575, 1619, 1575, 1620, 1608, 1620, 1575, 1621, 1610, 1620, 1575, 1652, 1608, 1652, 1735, 1652, 1610, 1652, 1749, 1620, 1729, 1620, 1746, 1620, 2344, 2364, 2352, 2364, 2355, 2364, 2325, 2364, 2326, 2364, 2327, 2364, 2332, 2364, 2337, 2364, 2338, 2364, 2347, 2364, 2351, 2364, 2503, 2494, 2503, 2519, 2465, 2492, 2466, 2492, 2479, 2492, 2610, 2620, 2616, 2620, 2582, 2620, 2583, 2620, 2588, 2620, 2603, 2620, 2887, 2902, 2887, 2878, 2887, 2903, 2849, 2876, 2850, 2876, 2962, 3031, 3014, 3006, 3015, 3006, 3014, 3031, 3142, 3158, 3263, 3285, 3270, 3285, 3270, 3286, 3270, 3266, 3274, 3285, 3398, 3390, 3399, 3390, 3398, 3415, 3545, 3530, 3545, 3535, 3548, 3530, 3545, 3551, 3661, 3634, 3789, 3762, 3755, 3737, 3755, 3745, 3851, 3906, 4023, 3916, 4023, 3921, 4023, 3926, 4023, 3931, 4023, 3904, 4021, 3953, 3954, 3953, 3956, 4018, 3968, 4018, 3969, 4019, 3968, 4019, 3969, 3953, 3968, 3986, 4023, 3996, 4023, 4001, 4023, 4006, 4023, 4011, 4023, 3984, 4021, 4133, 4142, 11520, 11521, 11522, 11523, 11524, 11525, 11526, 11527, 11528, 11529, 11530, 11531, 11532, 11533, 11534, 11535, 11536, 11537, 11538, 11539, 11540, 11541, 11542, 11543, 11544, 11545, 11546, 11547, 11548, 11549, 11550, 11551, 11552, 11553, 11554, 11555, 11556, 11557, 11559, 11565, 4316, 5104, 5105, 5106, 5107, 5108, 5109, 6917, 6965, 6919, 6965, 6921, 6965, 6923, 6965, 6925, 6965, 6929, 6965, 6970, 6965, 6972, 6965, 6974, 6965, 6975, 6965, 6978, 6965, 42571, 4304, 4305, 4306, 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314, 4315, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 4349, 4350, 4351, 65, 198, 66, 68, 69, 398, 71, 72, 73, 74, 75, 76, 77, 78, 79, 546, 80, 82, 84, 85, 87, 592, 593, 7426, 604, 7446, 7447, 7453, 7461, 594, 597, 607, 609, 613, 618, 7547, 669, 621, 7557, 671, 625, 624, 627, 628, 632, 642, 427, 7452, 656, 657, 65, 805, 7681, 97, 805, 66, 775, 7683, 98, 775, 66, 803, 7685, 98, 803, 66, 817, 7687, 98, 817, 199, 769, 7689, 231, 769, 68, 775, 7691, 100, 775, 68, 803, 7693, 100, 803, 68, 817, 7695, 100, 817, 68, 807, 7697, 100, 807, 68, 813, 7699, 100, 813, 274, 768, 7701, 275, 768, 274, 769, 7703, 275, 769, 69, 813, 7705, 101, 813, 69, 816, 7707, 101, 816, 552, 774, 7709, 553, 774, 70, 775, 7711, 102, 775, 71, 772, 7713, 103, 772, 72, 775, 7715, 104, 775, 72, 803, 7717, 104, 803, 72, 776, 7719, 104, 776, 72, 807, 7721, 104, 807, 72, 814, 7723, 104, 814, 73, 816, 7725, 105, 816, 207, 769, 7727, 239, 769, 75, 769, 7729, 107, 769, 75, 803, 7731, 107, 803, 75, 817, 7733, 107, 817, 76, 803, 7735, 108, 803, 7734, 772, 7737, 7735, 772, 76, 817, 7739, 108, 817, 76, 813, 7741, 108, 813, 77, 769, 7743, 109, 769, 77, 775, 7745, 109, 775, 77, 803, 7747, 109, 803, 78, 775, 7749, 110, 775, 78, 803, 7751, 110, 803, 78, 817, 7753, 110, 817, 78, 813, 7755, 110, 813, 213, 769, 7757, 245, 769, 213, 776, 7759, 245, 776, 332, 768, 7761, 333, 768, 332, 769, 7763, 333, 769, 80, 769, 7765, 112, 769, 80, 775, 7767, 112, 775, 82, 775, 7769, 114, 775, 82, 803, 7771, 114, 803, 7770, 772, 7773, 7771, 772, 82, 817, 7775, 114, 817, 83, 775, 7777, 115, 775, 83, 803, 7779, 115, 803, 346, 775, 7781, 347, 775, 352, 775, 7783, 353, 775, 7778, 775, 7785, 7779, 775, 84, 775, 7787, 116, 775, 84, 803, 7789, 116, 803, 84, 817, 7791, 116, 817, 84, 813, 7793, 116, 813, 85, 804, 7795, 117, 804, 85, 816, 7797, 117, 816, 85, 813, 7799, 117, 813, 360, 769, 7801, 361, 769, 362, 776, 7803, 363, 776, 86, 771, 7805, 118, 771, 86, 803, 7807, 118, 803, 87, 768, 7809, 119, 768, 87, 769, 7811, 119, 769, 87, 776, 7813, 119, 776, 87, 775, 7815, 119, 775, 87, 803, 7817, 119, 803, 88, 775, 7819, 120, 775, 88, 776, 7821, 120, 776, 89, 775, 7823, 121, 775, 90, 770, 7825, 122, 770, 90, 803, 7827, 122, 803, 90, 817, 7829, 122, 817, 104, 817, 116, 776, 119, 778, 121, 778, 97, 702, 383, 775, 65, 803, 7841, 97, 803, 65, 777, 7843, 97, 777, 194, 769, 7845, 226, 769, 194, 768, 7847, 226, 768, 194, 777, 7849, 226, 777, 194, 771, 7851, 226, 771, 7840, 770, 7853, 7841, 770, 258, 769, 7855, 259, 769, 258, 768, 7857, 259, 768, 258, 777, 7859, 259, 777, 258, 771, 7861, 259, 771, 7840, 774, 7863, 7841, 774, 69, 803, 7865, 101, 803, 69, 777, 7867, 101, 777, 69, 771, 7869, 101, 771, 202, 769, 7871, 234, 769, 202, 768, 7873, 234, 768, 202, 777, 7875, 234, 777, 202, 771, 7877, 234, 771, 7864, 770, 7879, 7865, 770, 73, 777, 7881, 105, 777, 73, 803, 7883, 105, 803, 79, 803, 7885, 111, 803, 79, 777, 7887, 111, 777, 212, 769, 7889, 244, 769, 212, 768, 7891, 244, 768, 212, 777, 7893, 244, 777, 212, 771, 7895, 244, 771, 7884, 770, 7897, 7885, 770, 416, 769, 7899, 417, 769, 416, 768, 7901, 417, 768, 416, 777, 7903, 417, 777, 416, 771, 7905, 417, 771, 416, 803, 7907, 417, 803, 85, 803, 7909, 117, 803, 85, 777, 7911, 117, 777, 431, 769, 7913, 432, 769, 431, 768, 7915, 432, 768, 431, 777, 7917, 432, 777, 431, 771, 7919, 432, 771, 431, 803, 7921, 432, 803, 89, 768, 7923, 121, 768, 89, 803, 7925, 121, 803, 89, 777, 7927, 121, 777, 89, 771, 7929, 121, 771, 7931, 7933, 7935, 945, 787, 945, 788, 7936, 768, 7937, 768, 7936, 769, 7937, 769, 7936, 834, 7937, 834, 913, 787, 7936, 913, 788, 7937, 7944, 768, 7938, 7945, 768, 7939, 7944, 769, 7940, 7945, 769, 7941, 7944, 834, 7942, 7945, 834, 7943, 949, 787, 949, 788, 7952, 768, 7953, 768, 7952, 769, 7953, 769, 917, 787, 7952, 917, 788, 7953, 7960, 768, 7954, 7961, 768, 7955, 7960, 769, 7956, 7961, 769, 7957, 951, 787, 951, 788, 7968, 768, 7969, 768, 7968, 769, 7969, 769, 7968, 834, 7969, 834, 919, 787, 7968, 919, 788, 7969, 7976, 768, 7970, 7977, 768, 7971, 7976, 769, 7972, 7977, 769, 7973, 7976, 834, 7974, 7977, 834, 7975, 953, 787, 953, 788, 7984, 768, 7985, 768, 7984, 769, 7985, 769, 7984, 834, 7985, 834, 921, 787, 7984, 921, 788, 7985, 7992, 768, 7986, 7993, 768, 7987, 7992, 769, 7988, 7993, 769, 7989, 7992, 834, 7990, 7993, 834, 7991, 959, 787, 959, 788, 8000, 768, 8001, 768, 8000, 769, 8001, 769, 927, 787, 8000, 927, 788, 8001, 8008, 768, 8002, 8009, 768, 8003, 8008, 769, 8004, 8009, 769, 8005, 965, 787, 965, 788, 8016, 768, 965, 787, 768, 8017, 768, 8016, 769, 965, 787, 769, 8017, 769, 8016, 834, 965, 787, 834, 8017, 834, 933, 788, 8017, 8025, 768, 8019, 8025, 769, 8021, 8025, 834, 8023, 969, 787, 969, 788, 8032, 768, 8033, 768, 8032, 769, 8033, 769, 8032, 834, 8033, 834, 937, 787, 8032, 937, 788, 8033, 8040, 768, 8034, 8041, 768, 8035, 8040, 769, 8036, 8041, 769, 8037, 8040, 834, 8038, 8041, 834, 8039, 945, 768, 949, 768, 951, 768, 953, 768, 959, 768, 965, 768, 969, 768, 7936, 837, 7936, 953, 7937, 837, 7937, 953, 7938, 837, 7938, 953, 7939, 837, 7939, 953, 7940, 837, 7940, 953, 7941, 837, 7941, 953, 7942, 837, 7942, 953, 7943, 837, 7943, 953, 7944, 837, 7945, 837, 7946, 837, 7947, 837, 7948, 837, 7949, 837, 7950, 837, 7951, 837, 7968, 837, 7968, 953, 7969, 837, 7969, 953, 7970, 837, 7970, 953, 7971, 837, 7971, 953, 7972, 837, 7972, 953, 7973, 837, 7973, 953, 7974, 837, 7974, 953, 7975, 837, 7975, 953, 7976, 837, 7977, 837, 7978, 837, 7979, 837, 7980, 837, 7981, 837, 7982, 837, 7983, 837, 8032, 837, 8032, 953, 8033, 837, 8033, 953, 8034, 837, 8034, 953, 8035, 837, 8035, 953, 8036, 837, 8036, 953, 8037, 837, 8037, 953, 8038, 837, 8038, 953, 8039, 837, 8039, 953, 8040, 837, 8041, 837, 8042, 837, 8043, 837, 8044, 837, 8045, 837, 8046, 837, 8047, 837, 945, 774, 945, 772, 8048, 837, 8048, 953, 945, 837, 945, 953, 940, 837, 940, 953, 945, 834, 8118, 837, 945, 834, 953, 913, 774, 8112, 913, 772, 8113, 913, 768, 8048, 902, 8049, 913, 837, 32, 787, 32, 834, 168, 834, 8052, 837, 8052, 953, 951, 837, 951, 953, 942, 837, 942, 953, 951, 834, 8134, 837, 951, 834, 953, 917, 768, 8050, 904, 8051, 919, 768, 8052, 905, 8053, 919, 837, 8127, 768, 8127, 769, 8127, 834, 953, 774, 953, 772, 970, 768, 953, 776, 768, 912, 953, 834, 970, 834, 953, 776, 834, 921, 774, 8144, 921, 772, 8145, 921, 768, 8054, 906, 8055, 8190, 768, 8190, 769, 8190, 834, 965, 774, 965, 772, 971, 768, 965, 776, 768, 944, 961, 787, 961, 788, 965, 834, 971, 834, 965, 776, 834, 933, 774, 8160, 933, 772, 8161, 933, 768, 8058, 910, 8059, 929, 788, 8165, 168, 768, 901, 96, 8060, 837, 8060, 953, 969, 837, 969, 953, 974, 837, 974, 953, 969, 834, 8182, 837, 969, 834, 953, 927, 768, 8056, 908, 8057, 937, 768, 8060, 911, 8061, 937, 837, 180, 32, 788, 8194, 8195, 8208, 32, 819, 46, 46, 46, 46, 46, 46, 8242, 8242, 8242, 8242, 8242, 8245, 8245, 8245, 8245, 8245, 33, 33, 32, 773, 63, 63, 63, 33, 33, 63, 3, 8242, 8242, 8242, 8242, 48, 52, 53, 54, 55, 56, 57, 43, 8722, 61, 40, 41, 82, 115, 97, 47, 99, 97, 47, 115, 67, 176, 67, 99, 47, 111, 99, 47, 117, 400, 176, 70, 78, 111, 81, 83, 77, 84, 69, 76, 84, 77, 90, 937, 197, 70, 8526, 1488, 1489, 1490, 1491, 70, 65, 88, 915, 928, 8721, 49, 8260, 55, 49, 8260, 57, 3, 49, 8260, 49, 48, 49, 8260, 51, 50, 8260, 51, 49, 8260, 53, 50, 8260, 53, 51, 8260, 53, 52, 8260, 53, 49, 8260, 54, 53, 8260, 54, 49, 8260, 56, 51, 8260, 56, 53, 8260, 56, 55, 8260, 56, 49, 8260, 8560, 73, 73, 8561, 73, 73, 73, 8562, 73, 86, 8563, 86, 8564, 86, 73, 8565, 86, 73, 73, 8566, 3, 86, 73, 73, 73, 8567, 73, 88, 8568, 88, 8569, 88, 73, 8570, 88, 73, 73, 8571, 8572, 8573, 8574, 8575, 105, 105, 105, 105, 105, 105, 118, 118, 105, 118, 105, 105, 3, 118, 105, 105, 105, 105, 120, 120, 105, 120, 105, 105, 8580, 48, 8260, 51, 8592, 824, 8594, 824, 8596, 824, 8656, 824, 8660, 824, 8658, 824, 8707, 824, 8712, 824, 8715, 824, 8739, 824, 8741, 824, 8747, 8747, 8747, 8747, 8747, 8750, 8750, 8750, 8750, 8750, 8764, 824, 8771, 824, 8773, 824, 8776, 824, 61, 824, 8801, 824, 8781, 824, 60, 824, 62, 824, 8804, 824, 8805, 824, 8818, 824, 8819, 824, 8822, 824, 8823, 824, 8826, 824, 8827, 824, 8834, 824, 8835, 824, 8838, 824, 8839, 824, 8866, 824, 8872, 824, 8873, 824, 8875, 824, 8828, 824, 8829, 824, 8849, 824, 8850, 824, 8882, 824, 8883, 824, 8884, 824, 8885, 824, 12296, 12297, 49, 48, 49, 49, 49, 50, 49, 51, 49, 52, 49, 53, 49, 54, 49, 55, 49, 56, 49, 57, 50, 48, 40, 49, 41, 40, 50, 41, 40, 51, 41, 40, 52, 41, 40, 53, 41, 40, 54, 41, 40, 55, 41, 40, 56, 41, 40, 57, 41, 3, 40, 49, 48, 41, 3, 40, 49, 49, 41, 3, 40, 49, 50, 41, 3, 40, 49, 51, 41, 3, 40, 49, 52, 41, 3, 40, 49, 53, 41, 3, 40, 49, 54, 41, 3, 40, 49, 55, 41, 3, 40, 49, 56, 41, 3, 40, 49, 57, 41, 3, 40, 50, 48, 41, 49, 46, 50, 46, 51, 46, 52, 46, 53, 46, 54, 46, 55, 46, 56, 46, 57, 46, 49, 48, 46, 49, 49, 46, 49, 50, 46, 49, 51, 46, 49, 52, 46, 49, 53, 46, 49, 54, 46, 49, 55, 46, 49, 56, 46, 49, 57, 46, 50, 48, 46, 40, 97, 41, 40, 98, 41, 40, 99, 41, 40, 100, 41, 40, 101, 41, 40, 102, 41, 40, 103, 41, 40, 104, 41, 40, 105, 41, 40, 106, 41, 40, 107, 41, 40, 108, 41, 40, 109, 41, 40, 110, 41, 40, 111, 41, 40, 112, 41, 40, 113, 41, 40, 114, 41, 40, 115, 41, 40, 116, 41, 40, 117, 41, 40, 118, 41, 40, 119, 41, 40, 120, 41, 40, 121, 41, 40, 122, 41, 9424, 9425, 9426, 9427, 9428, 9429, 9430, 9431, 9432, 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, 9441, 83, 9442, 9443, 9444, 9445, 9446, 9447, 89, 9448, 9449, 3, 8747, 8747, 8747, 8747, 58, 58, 61, 61, 61, 61, 61, 61, 10973, 824, 11312, 11313, 11314, 11315, 11316, 11317, 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325, 11326, 11327, 11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, 11342, 11343, 11344, 11345, 11346, 11347, 11348, 11349, 11350, 11351, 11352, 11353, 11354, 11355, 11356, 11357, 11358, 11359, 11361, 619, 7549, 637, 11368, 11370, 11372, 11379, 11382, 575, 576, 11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423, 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, 11483, 11485, 11487, 11489, 11491, 11500, 11502, 11507, 11617, 27597, 40863, 19968, 20008, 20022, 20031, 20057, 20101, 20108, 20128, 20154, 20799, 20837, 20843, 20866, 20886, 20907, 20960, 20981, 20992, 21147, 21241, 21269, 21274, 21304, 21313, 21340, 21353, 21378, 21430, 21448, 21475, 22231, 22303, 22763, 22786, 22794, 22805, 22823, 22899, 23376, 23424, 23544, 23567, 23586, 23608, 23662, 23665, 24027, 24037, 24049, 24062, 24178, 24186, 24191, 24308, 24318, 24331, 24339, 24400, 24417, 24435, 24515, 25096, 25142, 25163, 25903, 25908, 25991, 26007, 26020, 26041, 26080, 26085, 26352, 26376, 26408, 27424, 27490, 27513, 27571, 27595, 27604, 27611, 27663, 27668, 27700, 28779, 29226, 29238, 29243, 29247, 29255, 29273, 29275, 29356, 29572, 29577, 29916, 29926, 29976, 29983, 29992, 30000, 30091, 30098, 30326, 30333, 30382, 30399, 30446, 30683, 30690, 30707, 31034, 31160, 31166, 31348, 31435, 31481, 31859, 31992, 32566, 32593, 32650, 32701, 32769, 32780, 32786, 32819, 32895, 32905, 33251, 33258, 33267, 33276, 33292, 33307, 33311, 33390, 33394, 33400, 34381, 34411, 34880, 34892, 34915, 35198, 35211, 35282, 35328, 35895, 35910, 35925, 35960, 35997, 36196, 36208, 36275, 36523, 36554, 36763, 36784, 36789, 37009, 37193, 37318, 37324, 37329, 38263, 38272, 38428, 38582, 38585, 38632, 38737, 38750, 38754, 38761, 38859, 38893, 38899, 38913, 39080, 39131, 39135, 39318, 39321, 39340, 39592, 39640, 39647, 39717, 39727, 39730, 39740, 39770, 40165, 40565, 40575, 40613, 40635, 40643, 40653, 40657, 40697, 40701, 40718, 40723, 40736, 40763, 40778, 40786, 40845, 40860, 40864, 12306, 21316, 21317, 12363, 12441, 12365, 12441, 12367, 12441, 12369, 12441, 12371, 12441, 12373, 12441, 12375, 12441, 12377, 12441, 12379, 12441, 12381, 12441, 12383, 12441, 12385, 12441, 12388, 12441, 12390, 12441, 12392, 12441, 12399, 12441, 12399, 12442, 12402, 12441, 12402, 12442, 12405, 12441, 12405, 12442, 12408, 12441, 12408, 12442, 12411, 12441, 12411, 12442, 12358, 12441, 32, 12441, 32, 12442, 12445, 12441, 12424, 12426, 12459, 12441, 12461, 12441, 12463, 12441, 12465, 12441, 12467, 12441, 12469, 12441, 12471, 12441, 12473, 12441, 12475, 12441, 12477, 12441, 12479, 12441, 12481, 12441, 12484, 12441, 12486, 12441, 12488, 12441, 12495, 12441, 12495, 12442, 12498, 12441, 12498, 12442, 12501, 12441, 12501, 12442, 12504, 12441, 12504, 12442, 12507, 12441, 12507, 12442, 12454, 12441, 12527, 12441, 12528, 12441, 12529, 12441, 12530, 12441, 12541, 12441, 12467, 12488, 4352, 4353, 4522, 4354, 4524, 4525, 4355, 4356, 4357, 4528, 4529, 4530, 4531, 4532, 4533, 4378, 4358, 4359, 4360, 4385, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, 4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469, 4448, 4372, 4373, 4551, 4552, 4556, 4558, 4563, 4567, 4569, 4380, 4573, 4575, 4381, 4382, 4384, 4386, 4387, 4391, 4393, 4395, 4396, 4397, 4398, 4399, 4402, 4406, 4416, 4423, 4428, 4593, 4594, 4439, 4440, 4441, 4484, 4485, 4488, 4497, 4498, 4500, 4510, 4513, 19977, 22235, 19978, 20013, 19979, 30002, 19993, 19969, 22825, 22320, 40, 4352, 41, 40, 4354, 41, 40, 4355, 41, 40, 4357, 41, 40, 4358, 41, 40, 4359, 41, 40, 4361, 41, 40, 4363, 41, 40, 4364, 41, 40, 4366, 41, 40, 4367, 41, 40, 4368, 41, 40, 4369, 41, 40, 4370, 41, 3, 40, 4352, 4449, 41, 3, 40, 4354, 4449, 41, 3, 40, 4355, 4449, 41, 3, 40, 4357, 4449, 41, 3, 40, 4358, 4449, 41, 3, 40, 4359, 4449, 41, 3, 40, 4361, 4449, 41, 3, 40, 4363, 4449, 41, 3, 40, 4364, 4449, 41, 3, 40, 4366, 4449, 41, 3, 40, 4367, 4449, 41, 3, 40, 4368, 4449, 41, 3, 40, 4369, 4449, 41, 3, 40, 4370, 4449, 41, 3, 40, 4364, 4462, 41, 6, 40, 4363, 4457, 4364, 4453, 4523, 41, 5, 40, 4363, 4457, 4370, 4462, 41, 40, 19968, 41, 40, 20108, 41, 40, 19977, 41, 40, 22235, 41, 40, 20116, 41, 40, 20845, 41, 40, 19971, 41, 40, 20843, 41, 40, 20061, 41, 40, 21313, 41, 40, 26376, 41, 40, 28779, 41, 40, 27700, 41, 40, 26408, 41, 40, 37329, 41, 40, 22303, 41, 40, 26085, 41, 40, 26666, 41, 40, 26377, 41, 40, 31038, 41, 40, 21517, 41, 40, 29305, 41, 40, 36001, 41, 40, 31069, 41, 40, 21172, 41, 40, 20195, 41, 40, 21628, 41, 40, 23398, 41, 40, 30435, 41, 40, 20225, 41, 40, 36039, 41, 40, 21332, 41, 40, 31085, 41, 40, 20241, 41, 40, 33258, 41, 40, 33267, 41, 21839, 24188, 31631, 80, 84, 69, 50, 49, 50, 50, 50, 51, 50, 52, 50, 53, 50, 54, 50, 55, 50, 56, 50, 57, 51, 48, 51, 49, 51, 50, 51, 51, 51, 52, 51, 53, 4352, 4449, 4354, 4449, 4355, 4449, 4357, 4449, 4358, 4449, 4359, 4449, 4361, 4449, 4363, 4449, 4364, 4449, 4366, 4449, 4367, 4449, 4368, 4449, 4369, 4449, 4370, 4449, 4, 4366, 4449, 4535, 4352, 4457, 3, 4364, 4462, 4363, 4468, 4363, 4462, 20116, 20845, 19971, 20061, 26666, 26377, 31038, 21517, 29305, 36001, 31069, 21172, 31192, 30007, 36969, 20778, 21360, 27880, 38917, 20241, 20889, 27491, 24038, 21491, 21307, 23447, 23398, 30435, 20225, 36039, 21332, 22812, 51, 54, 51, 55, 51, 56, 51, 57, 52, 48, 52, 49, 52, 50, 52, 51, 52, 52, 52, 53, 52, 54, 52, 55, 52, 56, 52, 57, 53, 48, 49, 26376, 50, 26376, 51, 26376, 52, 26376, 53, 26376, 54, 26376, 55, 26376, 56, 26376, 57, 26376, 49, 48, 26376, 49, 49, 26376, 49, 50, 26376, 72, 103, 101, 114, 103, 101, 86, 76, 84, 68, 12450, 12452, 12454, 12456, 12458, 12459, 12461, 12463, 12465, 12467, 12469, 12471, 12473, 12475, 12477, 12479, 12481, 12484, 12486, 12488, 12490, 12491, 12492, 12493, 12494, 12495, 12498, 12501, 12504, 12507, 12510, 12511, 12512, 12513, 12514, 12516, 12518, 12520, 12521, 12522, 12523, 12524, 12525, 12527, 12528, 12529, 12530, 20196, 21644, 3, 12450, 12497, 12540, 12488, 3, 12450, 12523, 12501, 12449, 3, 12450, 12531, 12506, 12450, 12450, 12540, 12523, 3, 12452, 12491, 12531, 12464, 12452, 12531, 12481, 12454, 12457, 12531, 4, 12456, 12473, 12463, 12540, 12489, 3, 12456, 12540, 12459, 12540, 12458, 12531, 12473, 12458, 12540, 12512, 12459, 12452, 12522, 3, 12459, 12521, 12483, 12488, 3, 12459, 12525, 12522, 12540, 12460, 12525, 12531, 12460, 12531, 12510, 12462, 12460, 12462, 12491, 12540, 3, 12461, 12517, 12522, 12540, 3, 12462, 12523, 12480, 12540, 12461, 12525, 4, 12461, 12525, 12464, 12521, 12512, 5, 12461, 12525, 12513, 12540, 12488, 12523, 4, 12461, 12525, 12527, 12483, 12488, 12464, 12521, 12512, 4, 12464, 12521, 12512, 12488, 12531, 4, 12463, 12523, 12476, 12452, 12525, 3, 12463, 12525, 12540, 12493, 12465, 12540, 12473, 12467, 12523, 12490, 12467, 12540, 12509, 3, 12469, 12452, 12463, 12523, 4, 12469, 12531, 12481, 12540, 12512, 3, 12471, 12522, 12531, 12464, 12475, 12531, 12481, 12475, 12531, 12488, 12480, 12540, 12473, 12487, 12471, 12489, 12523, 12488, 12531, 12490, 12494, 12494, 12483, 12488, 12495, 12452, 12484, 4, 12497, 12540, 12475, 12531, 12488, 12497, 12540, 12484, 3, 12496, 12540, 12524, 12523, 4, 12500, 12450, 12473, 12488, 12523, 12500, 12463, 12523, 12500, 12467, 12499, 12523, 4, 12501, 12449, 12521, 12483, 12489, 3, 12501, 12451, 12540, 12488, 4, 12502, 12483, 12471, 12455, 12523, 12501, 12521, 12531, 4, 12504, 12463, 12479, 12540, 12523, 12506, 12477, 12506, 12491, 12498, 12504, 12523, 12484, 12506, 12531, 12473, 12506, 12540, 12472, 12505, 12540, 12479, 3, 12509, 12452, 12531, 12488, 12508, 12523, 12488, 12507, 12531, 12509, 12531, 12489, 12507, 12540, 12523, 12507, 12540, 12531, 3, 12510, 12452, 12463, 12525, 12510, 12452, 12523, 12510, 12483, 12495, 12510, 12523, 12463, 4, 12510, 12531, 12471, 12519, 12531, 3, 12511, 12463, 12525, 12531, 12511, 12522, 4, 12511, 12522, 12496, 12540, 12523, 12513, 12460, 3, 12513, 12460, 12488, 12531, 3, 12513, 12540, 12488, 12523, 12516, 12540, 12489, 12516, 12540, 12523, 12518, 12450, 12531, 3, 12522, 12483, 12488, 12523, 12522, 12521, 12523, 12500, 12540, 3, 12523, 12540, 12502, 12523, 12524, 12512, 4, 12524, 12531, 12488, 12466, 12531, 12527, 12483, 12488, 48, 28857, 49, 28857, 50, 28857, 51, 28857, 52, 28857, 53, 28857, 54, 28857, 55, 28857, 56, 28857, 57, 28857, 49, 48, 28857, 49, 49, 28857, 49, 50, 28857, 49, 51, 28857, 49, 52, 28857, 49, 53, 28857, 49, 54, 28857, 49, 55, 28857, 49, 56, 28857, 49, 57, 28857, 50, 48, 28857, 50, 49, 28857, 50, 50, 28857, 50, 51, 28857, 50, 52, 28857, 104, 80, 97, 100, 97, 65, 85, 98, 97, 114, 111, 86, 112, 99, 100, 109, 100, 109, 178, 100, 109, 179, 73, 85, 24179, 25104, 26157, 21644, 22823, 27491, 26126, 27835, 3, 26666, 24335, 20250, 31038, 112, 65, 110, 65, 956, 65, 109, 65, 107, 65, 75, 66, 77, 66, 71, 66, 99, 97, 108, 3, 107, 99, 97, 108, 112, 70, 110, 70, 956, 70, 956, 103, 109, 103, 107, 103, 72, 122, 107, 72, 122, 77, 72, 122, 71, 72, 122, 84, 72, 122, 956, 8467, 109, 8467, 100, 8467, 107, 8467, 102, 109, 110, 109, 956, 109, 109, 109, 99, 109, 107, 109, 109, 109, 178, 99, 109, 178, 109, 178, 107, 109, 178, 109, 109, 179, 99, 109, 179, 109, 179, 107, 109, 179, 109, 8725, 115, 3, 109, 8725, 115, 178, 80, 97, 107, 80, 97, 77, 80, 97, 71, 80, 97, 114, 97, 100, 4, 114, 97, 100, 8725, 115, 5, 114, 97, 100, 8725, 115, 178, 112, 115, 110, 115, 956, 115, 109, 115, 112, 86, 110, 86, 956, 86, 109, 86, 107, 86, 77, 86, 112, 87, 110, 87, 956, 87, 109, 87, 107, 87, 77, 87, 107, 937, 77, 937, 3, 97, 46, 109, 46, 66, 113, 99, 99, 99, 100, 3, 67, 8725, 107, 103, 67, 111, 46, 100, 66, 71, 121, 104, 97, 72, 80, 105, 110, 75, 75, 75, 77, 107, 116, 108, 109, 108, 110, 108, 111, 103, 108, 120, 109, 98, 109, 105, 108, 109, 111, 108, 80, 72, 3, 112, 46, 109, 46, 80, 80, 77, 80, 82, 115, 114, 83, 118, 87, 98, 86, 8725, 109, 65, 8725, 109, 49, 26085, 50, 26085, 51, 26085, 52, 26085, 53, 26085, 54, 26085, 55, 26085, 56, 26085, 57, 26085, 49, 48, 26085, 49, 49, 26085, 49, 50, 26085, 49, 51, 26085, 49, 52, 26085, 49, 53, 26085, 49, 54, 26085, 49, 55, 26085, 49, 56, 26085, 49, 57, 26085, 50, 48, 26085, 50, 49, 26085, 50, 50, 26085, 50, 51, 26085, 50, 52, 26085, 50, 53, 26085, 50, 54, 26085, 50, 55, 26085, 50, 56, 26085, 50, 57, 26085, 51, 48, 26085, 51, 49, 26085, 103, 97, 108, 42561, 42563, 42565, 42567, 42569, 42573, 42575, 42577, 42579, 42581, 42583, 42585, 42587, 42589, 42591, 42593, 42595, 42597, 42599, 42601, 42603, 42605, 42625, 42627, 42629, 42631, 42633, 42635, 42637, 42639, 42641, 42643, 42645, 42647, 42649, 42651, 42787, 42789, 42791, 42793, 42795, 42797, 42799, 42803, 42805, 42807, 42809, 42811, 42813, 42815, 42817, 42819, 42821, 42823, 42825, 42827, 42829, 42831, 42833, 42835, 42837, 42839, 42841, 42843, 42845, 42847, 42849, 42851, 42853, 42855, 42857, 42859, 42861, 42863, 42874, 42876, 7545, 42879, 42881, 42883, 42885, 42887, 42892, 42897, 42899, 42903, 42905, 42907, 42909, 42911, 42913, 42915, 42917, 42919, 42921, 620, 670, 647, 43859, 42933, 42935, 42937, 42939, 42941, 42943, 42945, 42947, 42900, 7566, 42952, 42954, 42961, 42967, 42969, 42998, 294, 43831, 43858, 653, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072, 5073, 5074, 5075, 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 35912, 26356, 36040, 28369, 20018, 21477, 22865, 21895, 22856, 25078, 30313, 32645, 34367, 34746, 35064, 37007, 27138, 27931, 28889, 29662, 33853, 37226, 39409, 20098, 21365, 27396, 29211, 34349, 40478, 23888, 28651, 34253, 35172, 25289, 33240, 34847, 24266, 26391, 28010, 29436, 37070, 20358, 20919, 21214, 25796, 27347, 29200, 30439, 34310, 34396, 36335, 38706, 39791, 40442, 30860, 31103, 32160, 33737, 37636, 35542, 22751, 24324, 31840, 32894, 29282, 30922, 36034, 38647, 22744, 23650, 27155, 28122, 28431, 32047, 32311, 38475, 21202, 32907, 20956, 20940, 31260, 32190, 33777, 38517, 35712, 25295, 35582, 20025, 23527, 24594, 29575, 30064, 21271, 30971, 20415, 24489, 19981, 27852, 25976, 32034, 21443, 22622, 30465, 33865, 35498, 27578, 27784, 25342, 33509, 25504, 30053, 20142, 20841, 20937, 26753, 31975, 33391, 35538, 37327, 21237, 21570, 24300, 26053, 28670, 31018, 38317, 39530, 40599, 40654, 26310, 27511, 36706, 24180, 24976, 25088, 25754, 28451, 29001, 29833, 31178, 32244, 32879, 36646, 34030, 36899, 37706, 21015, 21155, 21693, 28872, 35010, 24265, 24565, 25467, 27566, 31806, 29557, 20196, 22265, 23994, 24604, 29618, 29801, 32666, 32838, 37428, 38646, 38728, 38936, 20363, 31150, 37300, 38584, 24801, 20102, 20698, 23534, 23615, 26009, 29134, 30274, 34044, 36988, 26248, 38446, 21129, 26491, 26611, 27969, 28316, 29705, 30041, 30827, 32016, 39006, 25134, 38520, 20523, 23833, 28138, 36650, 24459, 24900, 26647, 38534, 21033, 21519, 23653, 26131, 26446, 26792, 27877, 29702, 30178, 32633, 35023, 35041, 38626, 21311, 28346, 21533, 29136, 29848, 34298, 38563, 40023, 40607, 26519, 28107, 33256, 31520, 31890, 29376, 28825, 35672, 20160, 33590, 21050, 20999, 24230, 25299, 31958, 23429, 27934, 26292, 36667, 38477, 24275, 20800, 21952, 22618, 26228, 20958, 29482, 30410, 31036, 31070, 31077, 31119, 38742, 31934, 34322, 35576, 36920, 37117, 39151, 39164, 39208, 40372, 37086, 38583, 20398, 20711, 20813, 21193, 21220, 21329, 21917, 22022, 22120, 22592, 22696, 23652, 24724, 24936, 24974, 25074, 25935, 26082, 26257, 26757, 28023, 28186, 28450, 29038, 29227, 29730, 30865, 31049, 31048, 31056, 31062, 31117, 31118, 31296, 31361, 31680, 32265, 32321, 32626, 32773, 33261, 33401, 33879, 35088, 35222, 35585, 35641, 36051, 36104, 36790, 38627, 38911, 38971, 24693, 55376, 57070, 33304, 20006, 20917, 20840, 20352, 20805, 20864, 21191, 21242, 21845, 21913, 21986, 22707, 22852, 22868, 23138, 23336, 24274, 24281, 24425, 24493, 24792, 24910, 24840, 24928, 25140, 25540, 25628, 25682, 25942, 26395, 26454, 28379, 28363, 28702, 30631, 29237, 29359, 29809, 29958, 30011, 30237, 30239, 30427, 30452, 30538, 30528, 30924, 31409, 31867, 32091, 32574, 33618, 33775, 34681, 35137, 35206, 35519, 35531, 35565, 35722, 36664, 36978, 37273, 37494, 38524, 38875, 38923, 39698, 55370, 56394, 55370, 56388, 55372, 57301, 15261, 16408, 16441, 55380, 56905, 55383, 56528, 55391, 57043, 40771, 40846, 102, 102, 102, 105, 102, 108, 102, 102, 105, 102, 102, 108, 383, 116, 115, 116, 1396, 1398, 1396, 1381, 1396, 1387, 1406, 1398, 1396, 1389, 1497, 1460, 1522, 1463, 1506, 1492, 1499, 1500, 1501, 1512, 1514, 1513, 1473, 1513, 1474, 64329, 1473, 64329, 1474, 1488, 1463, 1488, 1464, 1488, 1468, 1489, 1468, 1490, 1468, 1491, 1468, 1492, 1468, 1493, 1468, 1494, 1468, 1496, 1468, 1497, 1468, 1498, 1468, 1499, 1468, 1500, 1468, 1502, 1468, 1504, 1468, 1505, 1468, 1507, 1468, 1508, 1468, 1510, 1468, 1511, 1468, 1512, 1468, 1513, 1468, 1514, 1468, 1493, 1465, 1489, 1471, 1499, 1471, 1508, 1471, 1488, 1500, 1649, 1659, 1662, 1664, 1658, 1663, 1657, 1700, 1702, 1668, 1667, 1670, 1671, 1677, 1676, 1678, 1672, 1688, 1681, 1705, 1711, 1715, 1713, 1722, 1723, 1728, 1729, 1726, 1746, 1747, 1709, 1735, 1734, 1736, 1655, 1739, 1733, 1737, 1744, 1609, 1574, 1575, 1574, 1749, 1574, 1608, 1574, 1735, 1574, 1734, 1574, 1736, 1574, 1744, 1574, 1609, 1740, 1574, 1580, 1574, 1581, 1574, 1605, 1574, 1610, 1576, 1580, 1576, 1581, 1576, 1582, 1576, 1605, 1576, 1609, 1576, 1610, 1578, 1580, 1578, 1581, 1578, 1582, 1578, 1605, 1578, 1609, 1578, 1610, 1579, 1580, 1579, 1605, 1579, 1609, 1579, 1610, 1580, 1581, 1580, 1605, 1581, 1580, 1581, 1605, 1582, 1580, 1582, 1581, 1582, 1605, 1587, 1580, 1587, 1581, 1587, 1582, 1587, 1605, 1589, 1581, 1589, 1605, 1590, 1580, 1590, 1581, 1590, 1582, 1590, 1605, 1591, 1581, 1591, 1605, 1592, 1605, 1593, 1580, 1593, 1605, 1594, 1580, 1594, 1605, 1601, 1580, 1601, 1581, 1601, 1582, 1601, 1605, 1601, 1609, 1601, 1610, 1602, 1581, 1602, 1605, 1602, 1609, 1602, 1610, 1603, 1575, 1603, 1580, 1603, 1581, 1603, 1582, 1603, 1604, 1603, 1605, 1603, 1609, 1603, 1610, 1604, 1580, 1604, 1581, 1604, 1582, 1604, 1605, 1604, 1609, 1604, 1610, 1605, 1580, 1605, 1581, 1605, 1582, 1605, 1605, 1605, 1609, 1605, 1610, 1606, 1580, 1606, 1581, 1606, 1582, 1606, 1605, 1606, 1609, 1606, 1610, 1607, 1580, 1607, 1605, 1607, 1609, 1607, 1610, 1610, 1580, 1610, 1581, 1610, 1582, 1610, 1605, 1610, 1609, 1610, 1610, 1584, 1648, 1585, 1648, 1609, 1648, 32, 1612, 1617, 32, 1613, 1617, 32, 1614, 1617, 32, 1615, 1617, 32, 1616, 1617, 32, 1617, 1648, 1574, 1585, 1574, 1586, 1574, 1606, 1576, 1585, 1576, 1586, 1576, 1606, 1578, 1585, 1578, 1586, 1578, 1606, 1579, 1585, 1579, 1586, 1579, 1606, 1605, 1575, 1606, 1585, 1606, 1586, 1606, 1606, 1610, 1585, 1610, 1586, 1610, 1606, 1574, 1582, 1574, 1607, 1576, 1607, 1578, 1607, 1589, 1582, 1604, 1607, 1606, 1607, 1607, 1648, 1610, 1607, 1579, 1607, 1587, 1607, 1588, 1605, 1588, 1607, 1600, 1614, 1617, 1600, 1615, 1617, 1600, 1616, 1617, 1591, 1609, 1591, 1610, 1593, 1609, 1593, 1610, 1594, 1609, 1594, 1610, 1587, 1609, 1587, 1610, 1588, 1609, 1588, 1610, 1581, 1609, 1581, 1610, 1580, 1609, 1580, 1610, 1582, 1609, 1582, 1610, 1589, 1609, 1589, 1610, 1590, 1609, 1590, 1610, 1588, 1580, 1588, 1581, 1588, 1582, 1588, 1585, 1587, 1585, 1589, 1585, 1590, 1585, 1575, 1611, 1578, 1580, 1605, 1578, 1581, 1580, 1578, 1581, 1605, 1578, 1582, 1605, 1578, 1605, 1580, 1578, 1605, 1581, 1578, 1605, 1582, 1580, 1605, 1581, 1581, 1605, 1610, 1581, 1605, 1609, 1587, 1581, 1580, 1587, 1580, 1581, 1587, 1580, 1609, 1587, 1605, 1581, 1587, 1605, 1580, 1587, 1605, 1605, 1589, 1581, 1581, 1589, 1605, 1605, 1588, 1581, 1605, 1588, 1580, 1610, 1588, 1605, 1582, 1588, 1605, 1605, 1590, 1581, 1609, 1590, 1582, 1605, 1591, 1605, 1581, 1591, 1605, 1605, 1591, 1605, 1610, 1593, 1580, 1605, 1593, 1605, 1605, 1593, 1605, 1609, 1594, 1605, 1605, 1594, 1605, 1610, 1594, 1605, 1609, 1601, 1582, 1605, 1602, 1605, 1581, 1602, 1605, 1605, 1604, 1581, 1605, 1604, 1581, 1610, 1604, 1581, 1609, 1604, 1580, 1580, 1604, 1582, 1605, 1604, 1605, 1581, 1605, 1581, 1580, 1605, 1581, 1605, 1605, 1581, 1610, 1605, 1580, 1581, 1605, 1580, 1605, 1605, 1582, 1580, 1605, 1582, 1605, 1605, 1580, 1582, 1607, 1605, 1580, 1607, 1605, 1605, 1606, 1581, 1605, 1606, 1581, 1609, 1606, 1580, 1605, 1606, 1580, 1609, 1606, 1605, 1610, 1606, 1605, 1609, 1610, 1605, 1605, 1576, 1582, 1610, 1578, 1580, 1610, 1578, 1580, 1609, 1578, 1582, 1610, 1578, 1582, 1609, 1578, 1605, 1610, 1578, 1605, 1609, 1580, 1605, 1610, 1580, 1581, 1609, 1580, 1605, 1609, 1587, 1582, 1609, 1589, 1581, 1610, 1588, 1581, 1610, 1590, 1581, 1610, 1604, 1580, 1610, 1604, 1605, 1610, 1610, 1581, 1610, 1610, 1580, 1610, 1610, 1605, 1610, 1605, 1605, 1610, 1602, 1605, 1610, 1606, 1581, 1610, 1593, 1605, 1610, 1603, 1605, 1610, 1606, 1580, 1581, 1605, 1582, 1610, 1604, 1580, 1605, 1603, 1605, 1605, 1580, 1581, 1610, 1581, 1580, 1610, 1605, 1580, 1610, 1601, 1605, 1610, 1576, 1581, 1610, 1587, 1582, 1610, 1606, 1580, 1610, 1589, 1604, 1746, 1602, 1604, 1746, 3, 1575, 1604, 1604, 1607, 3, 1575, 1603, 1576, 1585, 3, 1605, 1581, 1605, 1583, 3, 1589, 1604, 1593, 1605, 3, 1585, 1587, 1608, 1604, 3, 1593, 1604, 1610, 1607, 3, 1608, 1587, 1604, 1605, 1589, 1604, 1609, 17, 1589, 1604, 1609, 32, 1575, 1604, 1604, 1607, 32, 1593, 1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, 7, 1580, 1604, 32, 1580, 1604, 1575, 1604, 1607, 3, 1585, 1740, 1575, 1604, 44, 12289, 12290, 58, 33, 63, 12310, 12311, 8230, 8229, 8212, 8211, 95, 123, 125, 12308, 12309, 12304, 12305, 12298, 12299, 12300, 12301, 12302, 12303, 91, 93, 8254, 35, 38, 42, 45, 60, 62, 92, 36, 37, 64, 32, 1611, 1600, 1611, 32, 1612, 32, 1613, 32, 1614, 1600, 1614, 32, 1615, 1600, 1615, 32, 1616, 1600, 1616, 32, 1617, 1600, 1617, 32, 1618, 1600, 1618, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1610, 1604, 1570, 1604, 1571, 1604, 1573, 1604, 1575, 34, 39, 47, 65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359, 65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370, 94, 124, 126, 10629, 10630, 12539, 12449, 12451, 12453, 12455, 12457, 12515, 12517, 12519, 12483, 12540, 12531, 12441, 12442, 12644, 12593, 12594, 12595, 12596, 12597, 12598, 12599, 12600, 12601, 12602, 12603, 12604, 12605, 12606, 12607, 12608, 12609, 12610, 12611, 12612, 12613, 12614, 12615, 12616, 12617, 12618, 12619, 12620, 12621, 12622, 12623, 12624, 12625, 12626, 12627, 12628, 12629, 12630, 12631, 12632, 12633, 12634, 12635, 12636, 12637, 12638, 12639, 12640, 12641, 12642, 12643, 162, 163, 172, 175, 166, 165, 8361, 9474, 8592, 8593, 8594, 8595, 9632, 9675, 55297, 56360, 55297, 56361, 55297, 56362, 55297, 56363, 55297, 56364, 55297, 56365, 55297, 56366, 55297, 56367, 55297, 56368, 55297, 56369, 55297, 56370, 55297, 56371, 55297, 56372, 55297, 56373, 55297, 56374, 55297, 56375, 55297, 56376, 55297, 56377, 55297, 56378, 55297, 56379, 55297, 56380, 55297, 56381, 55297, 56382, 55297, 56383, 55297, 56384, 55297, 56385, 55297, 56386, 55297, 56387, 55297, 56388, 55297, 56389, 55297, 56390, 55297, 56391, 55297, 56392, 55297, 56393, 55297, 56394, 55297, 56395, 55297, 56396, 55297, 56397, 55297, 56398, 55297, 56399, 55297, 56536, 55297, 56537, 55297, 56538, 55297, 56539, 55297, 56540, 55297, 56541, 55297, 56542, 55297, 56543, 55297, 56544, 55297, 56545, 55297, 56546, 55297, 56547, 55297, 56548, 55297, 56549, 55297, 56550, 55297, 56551, 55297, 56552, 55297, 56553, 55297, 56554, 55297, 56555, 55297, 56556, 55297, 56557, 55297, 56558, 55297, 56559, 55297, 56560, 55297, 56561, 55297, 56562, 55297, 56563, 55297, 56564, 55297, 56565, 55297, 56566, 55297, 56567, 55297, 56568, 55297, 56569, 55297, 56570, 55297, 56571, 55297, 56727, 55297, 56728, 55297, 56729, 55297, 56730, 55297, 56731, 55297, 56732, 55297, 56733, 55297, 56734, 55297, 56735, 55297, 56736, 55297, 56737, 55297, 56739, 55297, 56740, 55297, 56741, 55297, 56742, 55297, 56743, 55297, 56744, 55297, 56745, 55297, 56746, 55297, 56747, 55297, 56748, 55297, 56749, 55297, 56750, 55297, 56751, 55297, 56752, 55297, 56753, 55297, 56755, 55297, 56756, 55297, 56757, 55297, 56758, 55297, 56759, 55297, 56760, 55297, 56761, 55297, 56763, 55297, 56764, 720, 721, 665, 675, 43878, 677, 676, 7569, 600, 606, 681, 612, 610, 667, 668, 615, 644, 682, 683, 55351, 57092, 42894, 622, 55351, 57093, 654, 55351, 57094, 630, 631, 634, 55351, 57096, 638, 680, 678, 43879, 679, 11377, 655, 673, 674, 664, 448, 449, 450, 55351, 57098, 55351, 57118, 55299, 56512, 55299, 56513, 55299, 56514, 55299, 56515, 55299, 56516, 55299, 56517, 55299, 56518, 55299, 56519, 55299, 56520, 55299, 56521, 55299, 56522, 55299, 56523, 55299, 56524, 55299, 56525, 55299, 56526, 55299, 56527, 55299, 56528, 55299, 56529, 55299, 56530, 55299, 56531, 55299, 56532, 55299, 56533, 55299, 56534, 55299, 56535, 55299, 56536, 55299, 56537, 55299, 56538, 55299, 56539, 55299, 56540, 55299, 56541, 55299, 56542, 55299, 56543, 55299, 56544, 55299, 56545, 55299, 56546, 55299, 56547, 55299, 56548, 55299, 56549, 55299, 56550, 55299, 56551, 55299, 56552, 55299, 56553, 55299, 56554, 55299, 56555, 55299, 56556, 55299, 56557, 55299, 56558, 55299, 56559, 55299, 56560, 55299, 56561, 55299, 56562, 55300, 56473, 55300, 56506, 55300, 56475, 55300, 56506, 55300, 56485, 55300, 56506, 55300, 56625, 55300, 56615, 55300, 56626, 55300, 56615, 55300, 57159, 55300, 57150, 55300, 57159, 55300, 57175, 55301, 56505, 55301, 56506, 55301, 56505, 55301, 56496, 55301, 56505, 55301, 56509, 55301, 56760, 55301, 56751, 55301, 56761, 55301, 56751, 55302, 56512, 55302, 56513, 55302, 56514, 55302, 56515, 55302, 56516, 55302, 56517, 55302, 56518, 55302, 56519, 55302, 56520, 55302, 56521, 55302, 56522, 55302, 56523, 55302, 56524, 55302, 56525, 55302, 56526, 55302, 56527, 55302, 56528, 55302, 56529, 55302, 56530, 55302, 56531, 55302, 56532, 55302, 56533, 55302, 56534, 55302, 56535, 55302, 56536, 55302, 56537, 55302, 56538, 55302, 56539, 55302, 56540, 55302, 56541, 55302, 56542, 55302, 56543, 55302, 56629, 55302, 56624, 55323, 56928, 55323, 56929, 55323, 56930, 55323, 56931, 55323, 56932, 55323, 56933, 55323, 56934, 55323, 56935, 55323, 56936, 55323, 56937, 55323, 56938, 55323, 56939, 55323, 56940, 55323, 56941, 55323, 56942, 55323, 56943, 55323, 56944, 55323, 56945, 55323, 56946, 55323, 56947, 55323, 56948, 55323, 56949, 55323, 56950, 55323, 56951, 55323, 56952, 55323, 56953, 55323, 56954, 55323, 56955, 55323, 56956, 55323, 56957, 55323, 56958, 55323, 56959, 55348, 56663, 55348, 56677, 55348, 56664, 55348, 56677, 55348, 56671, 55348, 56686, 55348, 56671, 55348, 56687, 55348, 56671, 55348, 56688, 55348, 56671, 55348, 56689, 55348, 56671, 55348, 56690, 55348, 56761, 55348, 56677, 55348, 56762, 55348, 56677, 55348, 56763, 55348, 56686, 55348, 56764, 55348, 56686, 55348, 56763, 55348, 56687, 55348, 56764, 55348, 56687, 305, 567, 913, 914, 916, 917, 918, 919, 921, 922, 923, 924, 925, 926, 927, 929, 1012, 932, 934, 935, 936, 8711, 8706, 1013, 977, 1008, 981, 1009, 982, 988, 55354, 56610, 55354, 56611, 55354, 56612, 55354, 56613, 55354, 56614, 55354, 56615, 55354, 56616, 55354, 56617, 55354, 56618, 55354, 56619, 55354, 56620, 55354, 56621, 55354, 56622, 55354, 56623, 55354, 56624, 55354, 56625, 55354, 56626, 55354, 56627, 55354, 56628, 55354, 56629, 55354, 56630, 55354, 56631, 55354, 56632, 55354, 56633, 55354, 56634, 55354, 56635, 55354, 56636, 55354, 56637, 55354, 56638, 55354, 56639, 55354, 56640, 55354, 56641, 55354, 56642, 55354, 56643, 1646, 1697, 1647, 48, 46, 48, 44, 49, 44, 50, 44, 51, 44, 52, 44, 53, 44, 54, 44, 55, 44, 56, 44, 57, 44, 40, 65, 41, 40, 66, 41, 40, 67, 41, 40, 68, 41, 40, 69, 41, 40, 70, 41, 40, 71, 41, 40, 72, 41, 40, 73, 41, 40, 74, 41, 40, 75, 41, 40, 76, 41, 40, 77, 41, 40, 78, 41, 40, 79, 41, 40, 80, 41, 40, 81, 41, 40, 82, 41, 40, 83, 41, 40, 84, 41, 40, 85, 41, 40, 86, 41, 40, 87, 41, 40, 88, 41, 40, 89, 41, 40, 90, 41, 12308, 83, 12309, 67, 68, 87, 90, 72, 86, 83, 68, 83, 83, 80, 80, 86, 87, 67, 77, 67, 77, 68, 77, 82, 68, 74, 12411, 12363, 12467, 12467, 23383, 21452, 12487, 22810, 35299, 20132, 26144, 28961, 21069, 24460, 20877, 26032, 21021, 32066, 36009, 22768, 21561, 28436, 25237, 25429, 36938, 25351, 25171, 31105, 31354, 21512, 28288, 30003, 21106, 21942, 37197, 12308, 26412, 12309, 12308, 19977, 12309, 12308, 20108, 12309, 12308, 23433, 12309, 12308, 28857, 12309, 12308, 25171, 12309, 12308, 30423, 12309, 12308, 21213, 12309, 12308, 25943, 12309, 24471, 21487, 20029, 20024, 20033, 55360, 56610, 20320, 20411, 20482, 20602, 20633, 20687, 13470, 55361, 56890, 20820, 20836, 20855, 55361, 56604, 13497, 20839, 55361, 56651, 20887, 20900, 20172, 20908, 55396, 56799, 20995, 13535, 21051, 21062, 21111, 13589, 21253, 21254, 21321, 21338, 21363, 21373, 21375, 55362, 56876, 28784, 21450, 21471, 55362, 57187, 21483, 21489, 21510, 21662, 21560, 21576, 21608, 21666, 21750, 21776, 21843, 21859, 21892, 21931, 21939, 21954, 22294, 22295, 22097, 22132, 22766, 22478, 22516, 22541, 22411, 22578, 22577, 22700, 55365, 56548, 22770, 22775, 22790, 22818, 22882, 55365, 57000, 55365, 57066, 23020, 23067, 23079, 23000, 23142, 14062, 14076, 23304, 23358, 55366, 56776, 23491, 23512, 23539, 55366, 57112, 23551, 23558, 24403, 14209, 23648, 23744, 23693, 55367, 56804, 23875, 55367, 56806, 23918, 23915, 23932, 24033, 24034, 14383, 24061, 24104, 24125, 24169, 14434, 55368, 56707, 14460, 24240, 24243, 24246, 55400, 57234, 55368, 57137, 33281, 24354, 14535, 55372, 57016, 55384, 56794, 24418, 24427, 14563, 24474, 24525, 24535, 24569, 24705, 14650, 14620, 55369, 57044, 24775, 24904, 24908, 24954, 25010, 24996, 25007, 25054, 25104, 25115, 25181, 25265, 25300, 25424, 55370, 57100, 25405, 25340, 25448, 25475, 25572, 55370, 57329, 25634, 25541, 25513, 14894, 25705, 25726, 25757, 25719, 14956, 25964, 55372, 56330, 26083, 26360, 26185, 15129, 15112, 15076, 20882, 20885, 26368, 26268, 32941, 17369, 26401, 26462, 26451, 55372, 57283, 15177, 26618, 26501, 26706, 55373, 56429, 26766, 26655, 26900, 26946, 27043, 27114, 27304, 55373, 56995, 27355, 15384, 27425, 55374, 56487, 27476, 15438, 27506, 27551, 27579, 55374, 56973, 55367, 56587, 55374, 57082, 27726, 55375, 56508, 27839, 27853, 27751, 27926, 27966, 28009, 28024, 28037, 55375, 56606, 27956, 28207, 28270, 15667, 28359, 55375, 57041, 28153, 28526, 55375, 57182, 55375, 57230, 28614, 28729, 28699, 15766, 28746, 28797, 28791, 28845, 55361, 56613, 28997, 55376, 56931, 29084, 55376, 57259, 29224, 29264, 55377, 56840, 29312, 29333, 55377, 57141, 55378, 56340, 29562, 29579, 16044, 29605, 16056, 29767, 29788, 29829, 29898, 16155, 29988, 55379, 56374, 30014, 55379, 56466, 55368, 56735, 30224, 55379, 57249, 55379, 57272, 55380, 56388, 16380, 16392, 55380, 56563, 55380, 56562, 55380, 56601, 55380, 56627, 30494, 30495, 30603, 16454, 16534, 55381, 56349, 30798, 16611, 55381, 56870, 55381, 56986, 55381, 57029, 31211, 16687, 31306, 31311, 55382, 56700, 55382, 56999, 31470, 16898, 55382, 57259, 31686, 31689, 16935, 55383, 56448, 31954, 17056, 31976, 31971, 32000, 55383, 57222, 32099, 17153, 32199, 32258, 32325, 17204, 55384, 56872, 55384, 56903, 17241, 55384, 57049, 32634, 55384, 57150, 32661, 32762, 55385, 56538, 55385, 56611, 32864, 55385, 56744, 32880, 55372, 57183, 17365, 32946, 33027, 17419, 33086, 23221, 55385, 57255, 55385, 57269, 55372, 57235, 55372, 57244, 33284, 36766, 17515, 33425, 33419, 33437, 21171, 33457, 33459, 33469, 33510, 55386, 57148, 33565, 33635, 33709, 33571, 33725, 33767, 33619, 33738, 33740, 33756, 55387, 56374, 55387, 56683, 55387, 56533, 17707, 34033, 34035, 34070, 55388, 57290, 34148, 55387, 57132, 17757, 17761, 55387, 57265, 55388, 56530, 17771, 34384, 34407, 34409, 34473, 34440, 34574, 34530, 34600, 34667, 34694, 17879, 34785, 34817, 17913, 34912, 55389, 56935, 35031, 35038, 17973, 35066, 13499, 55390, 56494, 55390, 56678, 18110, 18119, 35488, 55391, 56488, 36011, 36033, 36123, 36215, 55391, 57135, 55362, 56324, 36299, 36284, 36336, 55362, 56542, 36564, 55393, 56786, 55393, 56813, 37012, 37105, 37137, 55393, 57134, 37147, 37432, 37591, 37592, 37500, 37881, 37909, 55394, 57338, 38283, 18837, 38327, 55395, 56695, 18918, 38595, 23986, 38691, 55396, 56645, 55396, 56858, 19054, 19062, 38880, 55397, 56330, 19122, 55397, 56470, 38953, 55397, 56758, 39138, 19251, 39209, 39335, 39362, 39422, 19406, 55398, 57136, 40000, 40189, 19662, 19693, 40295, 55400, 56526, 19704, 55400, 56581, 55400, 56846, 55400, 56977, 19798, 40702, 40709, 40719, 40726, 55401, 56832, 170, 186, 7838, 192, 193, 194, 195, 196, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, 220, 221, 222, 376, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 296, 298, 300, 302, 306, 308, 310, 312, 313, 315, 317, 319, 321, 323, 325, 327, 329, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 377, 379, 381, 579, 386, 388, 391, 395, 397, 401, 502, 408, 573, 411, 544, 416, 418, 420, 423, 426, 428, 431, 435, 437, 440, 442, 444, 446, 503, 453, 452, 456, 455, 459, 458, 461, 463, 465, 467, 469, 471, 473, 475, 478, 480, 482, 484, 486, 488, 490, 492, 494, 496, 498, 497, 500, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 545, 548, 550, 552, 554, 556, 558, 560, 562, 564, 565, 566, 568, 569, 571, 11390, 11391, 577, 582, 584, 586, 588, 590, 11375, 11373, 11376, 385, 390, 393, 394, 399, 602, 42923, 605, 403, 42924, 404, 42893, 42922, 407, 406, 42926, 11362, 42925, 412, 11374, 413, 415, 636, 11364, 639, 422, 42949, 425, 645, 646, 42929, 430, 580, 433, 434, 581, 439, 659, 662, 663, 666, 42930, 42928, 672, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 704, 705, 736, 737, 738, 739, 740, 880, 882, 886, 890, 1021, 1022, 1023, 938, 939, 978, 979, 980, 975, 984, 986, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1017, 895, 1015, 1018, 1020, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1120, 1122, 1124, 1126, 1128, 1130, 1132, 1134, 1136, 1138, 1140, 1142, 1144, 1146, 1148, 1150, 1152, 1162, 1164, 1166, 1168, 1170, 1172, 1174, 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196, 1198, 1200, 1202, 1204, 1206, 1208, 1210, 1212, 1214, 1217, 1219, 1221, 1223, 1225, 1227, 1229, 1216, 1232, 1234, 1236, 1238, 1240, 1242, 1244, 1246, 1248, 1250, 1252, 1254, 1256, 1258, 1260, 1262, 1264, 1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298, 1300, 1302, 1304, 1306, 1308, 1310, 1312, 1314, 1316, 1318, 1320, 1322, 1324, 1326, 1376, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1415, 1416, 7312, 7313, 7314, 7315, 7316, 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327, 7328, 7329, 7330, 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, 4348, 7357, 7358, 7359, 43888, 43889, 43890, 43891, 43892, 43893, 43894, 43895, 43896, 43897, 43898, 43899, 43900, 43901, 43902, 43903, 43904, 43905, 43906, 43907, 43908, 43909, 43910, 43911, 43912, 43913, 43914, 43915, 43916, 43917, 43918, 43919, 43920, 43921, 43922, 43923, 43924, 43925, 43926, 43927, 43928, 43929, 43930, 43931, 43932, 43933, 43934, 43935, 43936, 43937, 43938, 43939, 43940, 43941, 43942, 43943, 43944, 43945, 43946, 43947, 43948, 43949, 43950, 43951, 43952, 43953, 43954, 43955, 43956, 43957, 43958, 43959, 43960, 43961, 43962, 43963, 43964, 43965, 43966, 43967, 5112, 5113, 5114, 5115, 5116, 5117, 42570, 7424, 7425, 7427, 7428, 7429, 7430, 7431, 7432, 7433, 7434, 7435, 7436, 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7448, 7449, 7450, 7451, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7462, 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, 7471, 7472, 7473, 7474, 7475, 7476, 7477, 7478, 7479, 7480, 7481, 7482, 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494, 7495, 7496, 7497, 7498, 7499, 7500, 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509, 7510, 7511, 7512, 7513, 7514, 7515, 7516, 7517, 7518, 7519, 7520, 7521, 7522, 7523, 7524, 7525, 7526, 7527, 7528, 7529, 7530, 7531, 7532, 7533, 7534, 7535, 7536, 7537, 7538, 7539, 7540, 7541, 7542, 7543, 7544, 42877, 7546, 7548, 11363, 7550, 7551, 7552, 7553, 7554, 7555, 7556, 7558, 7559, 7560, 7561, 7562, 7563, 7564, 7565, 42950, 7567, 7568, 7570, 7571, 7572, 7573, 7574, 7575, 7576, 7577, 7578, 7579, 7580, 7581, 7582, 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, 7593, 7594, 7595, 7596, 7597, 7598, 7599, 7600, 7601, 7602, 7603, 7604, 7605, 7606, 7607, 7608, 7609, 7610, 7611, 7612, 7613, 7614, 7615, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 7824, 7826, 7828, 7830, 7831, 7832, 7833, 7834, 7836, 7837, 223, 7839, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934, 7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951, 7960, 7961, 7962, 7963, 7964, 7965, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999, 8008, 8009, 8010, 8011, 8012, 8013, 8016, 8025, 8018, 8027, 8020, 8029, 8022, 8031, 8040, 8041, 8042, 8043, 8044, 8045, 8046, 8047, 8122, 8123, 8136, 8137, 8138, 8139, 8154, 8155, 8184, 8185, 8170, 8171, 8186, 8187, 8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079, 8064, 8065, 8066, 8067, 8068, 8069, 8070, 8071, 8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095, 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, 8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111, 8096, 8097, 8098, 8099, 8100, 8101, 8102, 8103, 8120, 8121, 8114, 8124, 8116, 8118, 8119, 8115, 8130, 8140, 8132, 8134, 8135, 8131, 8152, 8153, 8146, 8147, 8150, 8151, 8168, 8169, 8162, 8163, 8164, 8172, 8166, 8167, 8178, 8188, 8180, 8182, 8183, 8179, 8305, 8319, 8336, 8337, 8338, 8339, 8340, 8341, 8342, 8343, 8344, 8345, 8346, 8347, 8348, 8450, 8455, 8458, 8459, 8460, 8461, 8462, 8463, 8464, 8465, 8466, 8467, 8469, 8473, 8474, 8475, 8476, 8477, 8484, 8488, 8492, 8493, 8495, 8496, 8497, 8499, 8500, 8505, 8508, 8509, 8510, 8511, 8517, 8518, 8519, 8520, 8521, 8498, 8544, 8545, 8546, 8547, 8548, 8549, 8550, 8551, 8552, 8553, 8554, 8555, 8556, 8557, 8558, 8559, 8579, 9398, 9399, 9400, 9401, 9402, 9403, 9404, 9405, 9406, 9407, 9408, 9409, 9410, 9411, 9412, 9413, 9414, 9415, 9416, 9417, 9418, 9419, 9420, 9421, 9422, 9423, 11264, 11265, 11266, 11267, 11268, 11269, 11270, 11271, 11272, 11273, 11274, 11275, 11276, 11277, 11278, 11279, 11280, 11281, 11282, 11283, 11284, 11285, 11286, 11287, 11288, 11289, 11290, 11291, 11292, 11293, 11294, 11295, 11296, 11297, 11298, 11299, 11300, 11301, 11302, 11303, 11304, 11305, 11306, 11307, 11308, 11309, 11310, 11311, 11360, 570, 574, 11367, 11369, 11371, 11378, 11380, 11381, 11383, 11384, 11385, 11386, 11387, 11388, 11389, 11392, 11394, 11396, 11398, 11400, 11402, 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, 11486, 11488, 11490, 11492, 11499, 11501, 11506, 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4295, 4301, 42560, 42562, 42564, 42566, 42568, 42572, 42574, 42576, 42578, 42580, 42582, 42584, 42586, 42588, 42590, 42592, 42594, 42596, 42598, 42600, 42602, 42604, 42624, 42626, 42628, 42630, 42632, 42634, 42636, 42638, 42640, 42642, 42644, 42646, 42648, 42650, 42652, 42653, 42786, 42788, 42790, 42792, 42794, 42796, 42798, 42800, 42801, 42802, 42804, 42806, 42808, 42810, 42812, 42814, 42816, 42818, 42820, 42822, 42824, 42826, 42828, 42830, 42832, 42834, 42836, 42838, 42840, 42842, 42844, 42846, 42848, 42850, 42852, 42854, 42856, 42858, 42860, 42862, 42864, 42865, 42866, 42867, 42868, 42869, 42870, 42871, 42872, 42873, 42875, 42878, 42880, 42882, 42884, 42886, 42891, 42896, 42898, 42948, 42901, 42902, 42904, 42906, 42908, 42910, 42912, 42914, 42916, 42918, 42920, 42927, 42932, 42934, 42936, 42938, 42940, 42942, 42944, 42946, 42951, 42953, 42960, 42963, 42965, 42966, 42968, 42994, 42995, 42996, 42997, 43000, 43001, 43002, 43824, 43825, 43826, 43827, 43828, 43829, 43830, 43832, 43833, 43834, 43835, 43836, 43837, 43838, 43839, 43840, 43841, 43842, 43843, 43844, 43845, 43846, 43847, 43848, 43849, 43850, 43851, 43852, 43853, 43854, 43855, 43856, 43857, 42931, 43860, 43861, 43862, 43863, 43864, 43865, 43866, 43868, 43869, 43870, 43871, 43872, 43873, 43874, 43875, 43876, 43877, 43880, 43881, 64256, 64257, 64258, 64259, 64260, 64261, 64262, 64275, 64276, 64277, 64278, 64279, 65313, 65314, 65315, 65316, 65317, 65318, 65319, 65320, 65321, 65322, 65323, 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, 65332, 65333, 65334, 65335, 65336, 65337, 65338, 55297, 56320, 55297, 56321, 55297, 56322, 55297, 56323, 55297, 56324, 55297, 56325, 55297, 56326, 55297, 56327, 55297, 56328, 55297, 56329, 55297, 56330, 55297, 56331, 55297, 56332, 55297, 56333, 55297, 56334, 55297, 56335, 55297, 56336, 55297, 56337, 55297, 56338, 55297, 56339, 55297, 56340, 55297, 56341, 55297, 56342, 55297, 56343, 55297, 56344, 55297, 56345, 55297, 56346, 55297, 56347, 55297, 56348, 55297, 56349, 55297, 56350, 55297, 56351, 55297, 56352, 55297, 56353, 55297, 56354, 55297, 56355, 55297, 56356, 55297, 56357, 55297, 56358, 55297, 56359, 55297, 56496, 55297, 56497, 55297, 56498, 55297, 56499, 55297, 56500, 55297, 56501, 55297, 56502, 55297, 56503, 55297, 56504, 55297, 56505, 55297, 56506, 55297, 56507, 55297, 56508, 55297, 56509, 55297, 56510, 55297, 56511, 55297, 56512, 55297, 56513, 55297, 56514, 55297, 56515, 55297, 56516, 55297, 56517, 55297, 56518, 55297, 56519, 55297, 56520, 55297, 56521, 55297, 56522, 55297, 56523, 55297, 56524, 55297, 56525, 55297, 56526, 55297, 56527, 55297, 56528, 55297, 56529, 55297, 56530, 55297, 56531, 55297, 56688, 55297, 56689, 55297, 56690, 55297, 56691, 55297, 56692, 55297, 56693, 55297, 56694, 55297, 56695, 55297, 56696, 55297, 56697, 55297, 56698, 55297, 56700, 55297, 56701, 55297, 56702, 55297, 56703, 55297, 56704, 55297, 56705, 55297, 56706, 55297, 56707, 55297, 56708, 55297, 56709, 55297, 56710, 55297, 56711, 55297, 56712, 55297, 56713, 55297, 56714, 55297, 56716, 55297, 56717, 55297, 56718, 55297, 56719, 55297, 56720, 55297, 56721, 55297, 56722, 55297, 56724, 55297, 56725, 55297, 57216, 55297, 57219, 55297, 57220, 55297, 57221, 55297, 57223, 55297, 57224, 55297, 57225, 55297, 57226, 55297, 57227, 55297, 57228, 55297, 57229, 55297, 57230, 55297, 57231, 55297, 57232, 55297, 57233, 55297, 57234, 55297, 57235, 55297, 57236, 55297, 57237, 55297, 57238, 55297, 57239, 55297, 57240, 55297, 57241, 55297, 57242, 55297, 57243, 55297, 57244, 55297, 57245, 55297, 57246, 55297, 57247, 55297, 57248, 55297, 57249, 55297, 57250, 55297, 57251, 55297, 57252, 55297, 57253, 55297, 57254, 55297, 57255, 55297, 57256, 55297, 57257, 55297, 57258, 55297, 57259, 55297, 57260, 55297, 57261, 55297, 57262, 55297, 57263, 55297, 57264, 55297, 57266, 55297, 57267, 55297, 57268, 55297, 57269, 55297, 57270, 55297, 57271, 55297, 57272, 55297, 57273, 55297, 57274, 55299, 56448, 55299, 56449, 55299, 56450, 55299, 56451, 55299, 56452, 55299, 56453, 55299, 56454, 55299, 56455, 55299, 56456, 55299, 56457, 55299, 56458, 55299, 56459, 55299, 56460, 55299, 56461, 55299, 56462, 55299, 56463, 55299, 56464, 55299, 56465, 55299, 56466, 55299, 56467, 55299, 56468, 55299, 56469, 55299, 56470, 55299, 56471, 55299, 56472, 55299, 56473, 55299, 56474, 55299, 56475, 55299, 56476, 55299, 56477, 55299, 56478, 55299, 56479, 55299, 56480, 55299, 56481, 55299, 56482, 55299, 56483, 55299, 56484, 55299, 56485, 55299, 56486, 55299, 56487, 55299, 56488, 55299, 56489, 55299, 56490, 55299, 56491, 55299, 56492, 55299, 56493, 55299, 56494, 55299, 56495, 55299, 56496, 55299, 56497, 55299, 56498, 55302, 56480, 55302, 56481, 55302, 56482, 55302, 56483, 55302, 56484, 55302, 56485, 55302, 56486, 55302, 56487, 55302, 56488, 55302, 56489, 55302, 56490, 55302, 56491, 55302, 56492, 55302, 56493, 55302, 56494, 55302, 56495, 55302, 56496, 55302, 56497, 55302, 56498, 55302, 56499, 55302, 56500, 55302, 56501, 55302, 56502, 55302, 56503, 55302, 56504, 55302, 56505, 55302, 56506, 55302, 56507, 55302, 56508, 55302, 56509, 55302, 56510, 55302, 56511, 55323, 56896, 55323, 56897, 55323, 56898, 55323, 56899, 55323, 56900, 55323, 56901, 55323, 56902, 55323, 56903, 55323, 56904, 55323, 56905, 55323, 56906, 55323, 56907, 55323, 56908, 55323, 56909, 55323, 56910, 55323, 56911, 55323, 56912, 55323, 56913, 55323, 56914, 55323, 56915, 55323, 56916, 55323, 56917, 55323, 56918, 55323, 56919, 55323, 56920, 55323, 56921, 55323, 56922, 55323, 56923, 55323, 56924, 55323, 56925, 55323, 56926, 55323, 56927, 55349, 56320, 55349, 56321, 55349, 56322, 55349, 56323, 55349, 56324, 55349, 56325, 55349, 56326, 55349, 56327, 55349, 56328, 55349, 56329, 55349, 56330, 55349, 56331, 55349, 56332, 55349, 56333, 55349, 56334, 55349, 56335, 55349, 56336, 55349, 56337, 55349, 56338, 55349, 56339, 55349, 56340, 55349, 56341, 55349, 56342, 55349, 56343, 55349, 56344, 55349, 56345, 55349, 56346, 55349, 56347, 55349, 56348, 55349, 56349, 55349, 56350, 55349, 56351, 55349, 56352, 55349, 56353, 55349, 56354, 55349, 56355, 55349, 56356, 55349, 56357, 55349, 56358, 55349, 56359, 55349, 56360, 55349, 56361, 55349, 56362, 55349, 56363, 55349, 56364, 55349, 56365, 55349, 56366, 55349, 56367, 55349, 56368, 55349, 56369, 55349, 56370, 55349, 56371, 55349, 56372, 55349, 56373, 55349, 56374, 55349, 56375, 55349, 56376, 55349, 56377, 55349, 56378, 55349, 56379, 55349, 56380, 55349, 56381, 55349, 56382, 55349, 56383, 55349, 56384, 55349, 56385, 55349, 56386, 55349, 56387, 55349, 56388, 55349, 56389, 55349, 56390, 55349, 56391, 55349, 56392, 55349, 56393, 55349, 56394, 55349, 56395, 55349, 56396, 55349, 56397, 55349, 56398, 55349, 56399, 55349, 56400, 55349, 56401, 55349, 56402, 55349, 56403, 55349, 56404, 55349, 56406, 55349, 56407, 55349, 56408, 55349, 56409, 55349, 56410, 55349, 56411, 55349, 56412, 55349, 56413, 55349, 56414, 55349, 56415, 55349, 56416, 55349, 56417, 55349, 56418, 55349, 56419, 55349, 56420, 55349, 56421, 55349, 56422, 55349, 56423, 55349, 56424, 55349, 56425, 55349, 56426, 55349, 56427, 55349, 56428, 55349, 56429, 55349, 56430, 55349, 56431, 55349, 56432, 55349, 56433, 55349, 56434, 55349, 56435, 55349, 56436, 55349, 56437, 55349, 56438, 55349, 56439, 55349, 56440, 55349, 56441, 55349, 56442, 55349, 56443, 55349, 56444, 55349, 56445, 55349, 56446, 55349, 56447, 55349, 56448, 55349, 56449, 55349, 56450, 55349, 56451, 55349, 56452, 55349, 56453, 55349, 56454, 55349, 56455, 55349, 56456, 55349, 56457, 55349, 56458, 55349, 56459, 55349, 56460, 55349, 56461, 55349, 56462, 55349, 56463, 55349, 56464, 55349, 56465, 55349, 56466, 55349, 56467, 55349, 56468, 55349, 56469, 55349, 56470, 55349, 56471, 55349, 56472, 55349, 56473, 55349, 56474, 55349, 56475, 55349, 56476, 55349, 56478, 55349, 56479, 55349, 56482, 55349, 56485, 55349, 56486, 55349, 56489, 55349, 56490, 55349, 56491, 55349, 56492, 55349, 56494, 55349, 56495, 55349, 56496, 55349, 56497, 55349, 56498, 55349, 56499, 55349, 56500, 55349, 56501, 55349, 56502, 55349, 56503, 55349, 56504, 55349, 56505, 55349, 56507, 55349, 56509, 55349, 56510, 55349, 56511, 55349, 56512, 55349, 56513, 55349, 56514, 55349, 56515, 55349, 56517, 55349, 56518, 55349, 56519, 55349, 56520, 55349, 56521, 55349, 56522, 55349, 56523, 55349, 56524, 55349, 56525, 55349, 56526, 55349, 56527, 55349, 56528, 55349, 56529, 55349, 56530, 55349, 56531, 55349, 56532, 55349, 56533, 55349, 56534, 55349, 56535, 55349, 56536, 55349, 56537, 55349, 56538, 55349, 56539, 55349, 56540, 55349, 56541, 55349, 56542, 55349, 56543, 55349, 56544, 55349, 56545, 55349, 56546, 55349, 56547, 55349, 56548, 55349, 56549, 55349, 56550, 55349, 56551, 55349, 56552, 55349, 56553, 55349, 56554, 55349, 56555, 55349, 56556, 55349, 56557, 55349, 56558, 55349, 56559, 55349, 56560, 55349, 56561, 55349, 56562, 55349, 56563, 55349, 56564, 55349, 56565, 55349, 56566, 55349, 56567, 55349, 56568, 55349, 56569, 55349, 56570, 55349, 56571, 55349, 56572, 55349, 56573, 55349, 56574, 55349, 56575, 55349, 56576, 55349, 56577, 55349, 56578, 55349, 56579, 55349, 56580, 55349, 56581, 55349, 56583, 55349, 56584, 55349, 56585, 55349, 56586, 55349, 56589, 55349, 56590, 55349, 56591, 55349, 56592, 55349, 56593, 55349, 56594, 55349, 56595, 55349, 56596, 55349, 56598, 55349, 56599, 55349, 56600, 55349, 56601, 55349, 56602, 55349, 56603, 55349, 56604, 55349, 56606, 55349, 56607, 55349, 56608, 55349, 56609, 55349, 56610, 55349, 56611, 55349, 56612, 55349, 56613, 55349, 56614, 55349, 56615, 55349, 56616, 55349, 56617, 55349, 56618, 55349, 56619, 55349, 56620, 55349, 56621, 55349, 56622, 55349, 56623, 55349, 56624, 55349, 56625, 55349, 56626, 55349, 56627, 55349, 56628, 55349, 56629, 55349, 56630, 55349, 56631, 55349, 56632, 55349, 56633, 55349, 56635, 55349, 56636, 55349, 56637, 55349, 56638, 55349, 56640, 55349, 56641, 55349, 56642, 55349, 56643, 55349, 56644, 55349, 56646, 55349, 56650, 55349, 56651, 55349, 56652, 55349, 56653, 55349, 56654, 55349, 56655, 55349, 56656, 55349, 56658, 55349, 56659, 55349, 56660, 55349, 56661, 55349, 56662, 55349, 56663, 55349, 56664, 55349, 56665, 55349, 56666, 55349, 56667, 55349, 56668, 55349, 56669, 55349, 56670, 55349, 56671, 55349, 56672, 55349, 56673, 55349, 56674, 55349, 56675, 55349, 56676, 55349, 56677, 55349, 56678, 55349, 56679, 55349, 56680, 55349, 56681, 55349, 56682, 55349, 56683, 55349, 56684, 55349, 56685, 55349, 56686, 55349, 56687, 55349, 56688, 55349, 56689, 55349, 56690, 55349, 56691, 55349, 56692, 55349, 56693, 55349, 56694, 55349, 56695, 55349, 56696, 55349, 56697, 55349, 56698, 55349, 56699, 55349, 56700, 55349, 56701, 55349, 56702, 55349, 56703, 55349, 56704, 55349, 56705, 55349, 56706, 55349, 56707, 55349, 56708, 55349, 56709, 55349, 56710, 55349, 56711, 55349, 56712, 55349, 56713, 55349, 56714, 55349, 56715, 55349, 56716, 55349, 56717, 55349, 56718, 55349, 56719, 55349, 56720, 55349, 56721, 55349, 56722, 55349, 56723, 55349, 56724, 55349, 56725, 55349, 56726, 55349, 56727, 55349, 56728, 55349, 56729, 55349, 56730, 55349, 56731, 55349, 56732, 55349, 56733, 55349, 56734, 55349, 56735, 55349, 56736, 55349, 56737, 55349, 56738, 55349, 56739, 55349, 56740, 55349, 56741, 55349, 56742, 55349, 56743, 55349, 56744, 55349, 56745, 55349, 56746, 55349, 56747, 55349, 56748, 55349, 56749, 55349, 56750, 55349, 56751, 55349, 56752, 55349, 56753, 55349, 56754, 55349, 56755, 55349, 56756, 55349, 56757, 55349, 56758, 55349, 56759, 55349, 56760, 55349, 56761, 55349, 56762, 55349, 56763, 55349, 56764, 55349, 56765, 55349, 56766, 55349, 56767, 55349, 56768, 55349, 56769, 55349, 56770, 55349, 56771, 55349, 56772, 55349, 56773, 55349, 56774, 55349, 56775, 55349, 56776, 55349, 56777, 55349, 56778, 55349, 56779, 55349, 56780, 55349, 56781, 55349, 56782, 55349, 56783, 55349, 56784, 55349, 56785, 55349, 56786, 55349, 56787, 55349, 56788, 55349, 56789, 55349, 56790, 55349, 56791, 55349, 56792, 55349, 56793, 55349, 56794, 55349, 56795, 55349, 56796, 55349, 56797, 55349, 56798, 55349, 56799, 55349, 56800, 55349, 56801, 55349, 56802, 55349, 56803, 55349, 56804, 55349, 56805, 55349, 56806, 55349, 56807, 55349, 56808, 55349, 56809, 55349, 56810, 55349, 56811, 55349, 56812, 55349, 56813, 55349, 56814, 55349, 56815, 55349, 56816, 55349, 56817, 55349, 56818, 55349, 56819, 55349, 56820, 55349, 56821, 55349, 56822, 55349, 56823, 55349, 56824, 55349, 56825, 55349, 56826, 55349, 56827, 55349, 56828, 55349, 56829, 55349, 56830, 55349, 56831, 55349, 56832, 55349, 56833, 55349, 56834, 55349, 56835, 55349, 56836, 55349, 56837, 55349, 56838, 55349, 56839, 55349, 56840, 55349, 56841, 55349, 56842, 55349, 56843, 55349, 56844, 55349, 56845, 55349, 56846, 55349, 56847, 55349, 56848, 55349, 56849, 55349, 56850, 55349, 56851, 55349, 56852, 55349, 56853, 55349, 56854, 55349, 56855, 55349, 56856, 55349, 56857, 55349, 56858, 55349, 56859, 55349, 56860, 55349, 56861, 55349, 56862, 55349, 56863, 55349, 56864, 55349, 56865, 55349, 56866, 55349, 56867, 55349, 56868, 55349, 56869, 55349, 56870, 55349, 56871, 55349, 56872, 55349, 56873, 55349, 56874, 55349, 56875, 55349, 56876, 55349, 56877, 55349, 56878, 55349, 56879, 55349, 56880, 55349, 56881, 55349, 56882, 55349, 56883, 55349, 56884, 55349, 56885, 55349, 56886, 55349, 56887, 55349, 56888, 55349, 56889, 55349, 56890, 55349, 56891, 55349, 56892, 55349, 56893, 55349, 56894, 55349, 56895, 55349, 56896, 55349, 56897, 55349, 56898, 55349, 56899, 55349, 56900, 55349, 56901, 55349, 56902, 55349, 56903, 55349, 56904, 55349, 56905, 55349, 56906, 55349, 56907, 55349, 56908, 55349, 56909, 55349, 56910, 55349, 56911, 55349, 56912, 55349, 56913, 55349, 56914, 55349, 56915, 55349, 56916, 55349, 56917, 55349, 56918, 55349, 56919, 55349, 56920, 55349, 56921, 55349, 56922, 55349, 56923, 55349, 56924, 55349, 56925, 55349, 56926, 55349, 56927, 55349, 56928, 55349, 56929, 55349, 56930, 55349, 56931, 55349, 56932, 55349, 56933, 55349, 56934, 55349, 56935, 55349, 56936, 55349, 56937, 55349, 56938, 55349, 56939, 55349, 56940, 55349, 56941, 55349, 56942, 55349, 56943, 55349, 56944, 55349, 56945, 55349, 56946, 55349, 56947, 55349, 56948, 55349, 56949, 55349, 56950, 55349, 56951, 55349, 56952, 55349, 56953, 55349, 56954, 55349, 56955, 55349, 56956, 55349, 56957, 55349, 56958, 55349, 56959, 55349, 56960, 55349, 56961, 55349, 56962, 55349, 56963, 55349, 56964, 55349, 56965, 55349, 56966, 55349, 56967, 55349, 56968, 55349, 56969, 55349, 56970, 55349, 56971, 55349, 56972, 55349, 56973, 55349, 56974, 55349, 56975, 55349, 56976, 55349, 56977, 55349, 56978, 55349, 56979, 55349, 56980, 55349, 56981, 55349, 56982, 55349, 56983, 55349, 56984, 55349, 56985, 55349, 56986, 55349, 56987, 55349, 56988, 55349, 56989, 55349, 56990, 55349, 56991, 55349, 56992, 55349, 56993, 55349, 56994, 55349, 56995, 55349, 56996, 55349, 56997, 55349, 57000, 55349, 57001, 55349, 57002, 55349, 57003, 55349, 57004, 55349, 57005, 55349, 57006, 55349, 57007, 55349, 57008, 55349, 57009, 55349, 57010, 55349, 57011, 55349, 57012, 55349, 57013, 55349, 57014, 55349, 57015, 55349, 57016, 55349, 57017, 55349, 57018, 55349, 57019, 55349, 57020, 55349, 57021, 55349, 57022, 55349, 57023, 55349, 57024, 55349, 57026, 55349, 57027, 55349, 57028, 55349, 57029, 55349, 57030, 55349, 57031, 55349, 57032, 55349, 57033, 55349, 57034, 55349, 57035, 55349, 57036, 55349, 57037, 55349, 57038, 55349, 57039, 55349, 57040, 55349, 57041, 55349, 57042, 55349, 57043, 55349, 57044, 55349, 57045, 55349, 57046, 55349, 57047, 55349, 57048, 55349, 57049, 55349, 57050, 55349, 57052, 55349, 57053, 55349, 57054, 55349, 57055, 55349, 57056, 55349, 57057, 55349, 57058, 55349, 57059, 55349, 57060, 55349, 57061, 55349, 57062, 55349, 57063, 55349, 57064, 55349, 57065, 55349, 57066, 55349, 57067, 55349, 57068, 55349, 57069, 55349, 57070, 55349, 57071, 55349, 57072, 55349, 57073, 55349, 57074, 55349, 57075, 55349, 57076, 55349, 57077, 55349, 57078, 55349, 57079, 55349, 57080, 55349, 57081, 55349, 57082, 55349, 57084, 55349, 57085, 55349, 57086, 55349, 57087, 55349, 57088, 55349, 57089, 55349, 57090, 55349, 57091, 55349, 57092, 55349, 57093, 55349, 57094, 55349, 57095, 55349, 57096, 55349, 57097, 55349, 57098, 55349, 57099, 55349, 57100, 55349, 57101, 55349, 57102, 55349, 57103, 55349, 57104, 55349, 57105, 55349, 57106, 55349, 57107, 55349, 57108, 55349, 57110, 55349, 57111, 55349, 57112, 55349, 57113, 55349, 57114, 55349, 57115, 55349, 57116, 55349, 57117, 55349, 57118, 55349, 57119, 55349, 57120, 55349, 57121, 55349, 57122, 55349, 57123, 55349, 57124, 55349, 57125, 55349, 57126, 55349, 57127, 55349, 57128, 55349, 57129, 55349, 57130, 55349, 57131, 55349, 57132, 55349, 57133, 55349, 57134, 55349, 57135, 55349, 57136, 55349, 57137, 55349, 57138, 55349, 57139, 55349, 57140, 55349, 57142, 55349, 57143, 55349, 57144, 55349, 57145, 55349, 57146, 55349, 57147, 55349, 57148, 55349, 57149, 55349, 57150, 55349, 57151, 55349, 57152, 55349, 57153, 55349, 57154, 55349, 57155, 55349, 57156, 55349, 57157, 55349, 57158, 55349, 57159, 55349, 57160, 55349, 57161, 55349, 57162, 55349, 57163, 55349, 57164, 55349, 57165, 55349, 57166, 55349, 57168, 55349, 57169, 55349, 57170, 55349, 57171, 55349, 57172, 55349, 57173, 55349, 57174, 55349, 57175, 55349, 57176, 55349, 57177, 55349, 57178, 55349, 57179, 55349, 57180, 55349, 57181, 55349, 57182, 55349, 57183, 55349, 57184, 55349, 57185, 55349, 57186, 55349, 57187, 55349, 57188, 55349, 57189, 55349, 57190, 55349, 57191, 55349, 57192, 55349, 57193, 55349, 57194, 55349, 57195, 55349, 57196, 55349, 57197, 55349, 57198, 55349, 57200, 55349, 57201, 55349, 57202, 55349, 57203, 55349, 57204, 55349, 57205, 55349, 57206, 55349, 57207, 55349, 57208, 55349, 57209, 55349, 57210, 55349, 57211, 55349, 57212, 55349, 57213, 55349, 57214, 55349, 57215, 55349, 57216, 55349, 57217, 55349, 57218, 55349, 57219, 55349, 57220, 55349, 57221, 55349, 57222, 55349, 57223, 55349, 57224, 55349, 57226, 55349, 57227, 55349, 57228, 55349, 57229, 55349, 57230, 55349, 57231, 55349, 57232, 55349, 57233, 55349, 57234, 55349, 57235, 55349, 57236, 55349, 57237, 55349, 57238, 55349, 57239, 55349, 57240, 55349, 57241, 55349, 57242, 55349, 57243, 55349, 57244, 55349, 57245, 55349, 57246, 55349, 57247, 55349, 57248, 55349, 57249, 55349, 57250, 55349, 57251, 55349, 57252, 55349, 57253, 55349, 57254, 55349, 57255, 55349, 57256, 55349, 57258, 55349, 57259, 55349, 57260, 55349, 57261, 55349, 57262, 55349, 57263, 55349, 57264, 55349, 57265, 55349, 57266, 55349, 57267, 55349, 57268, 55349, 57269, 55349, 57270, 55349, 57271, 55349, 57272, 55349, 57273, 55349, 57274, 55349, 57275, 55349, 57276, 55349, 57277, 55349, 57278, 55349, 57279, 55349, 57280, 55349, 57281, 55349, 57282, 55349, 57284, 55349, 57285, 55349, 57286, 55349, 57287, 55349, 57288, 55349, 57289, 55349, 57290, 55349, 57291, 55351, 57088, 55351, 57089, 55351, 57090, 55351, 57091, 55351, 57095, 55351, 57097, 55351, 57099, 55351, 57100, 55351, 57101, 55351, 57102, 55351, 57103, 55351, 57104, 55351, 57105, 55351, 57106, 55351, 57107, 55351, 57108, 55351, 57109, 55351, 57110, 55351, 57111, 55351, 57112, 55351, 57113, 55351, 57114, 55351, 57115, 55351, 57116, 55351, 57117, 55351, 57125, 55351, 57126, 55351, 57127, 55351, 57128, 55351, 57129, 55351, 57130, 55352, 56368, 55352, 56369, 55352, 56370, 55352, 56371, 55352, 56372, 55352, 56373, 55352, 56374, 55352, 56375, 55352, 56376, 55352, 56377, 55352, 56378, 55352, 56379, 55352, 56380, 55352, 56381, 55352, 56382, 55352, 56383, 55352, 56384, 55352, 56385, 55352, 56386, 55352, 56387, 55352, 56388, 55352, 56389, 55352, 56390, 55352, 56391, 55352, 56392, 55352, 56393, 55352, 56394, 55352, 56395, 55352, 56396, 55352, 56397, 55352, 56398, 55352, 56399, 55352, 56400, 55352, 56401, 55352, 56402, 55352, 56403, 55352, 56404, 55352, 56405, 55352, 56406, 55352, 56407, 55352, 56408, 55352, 56409, 55352, 56410, 55352, 56411, 55352, 56412, 55352, 56413, 55352, 56414, 55352, 56415, 55352, 56416, 55352, 56417, 55352, 56418, 55352, 56419, 55352, 56420, 55352, 56421, 55352, 56422, 55352, 56423, 55352, 56424, 55352, 56425, 55352, 56426, 55352, 56427, 55352, 56428, 55352, 56429, 55354, 56576, 55354, 56577, 55354, 56578, 55354, 56579, 55354, 56580, 55354, 56581, 55354, 56582, 55354, 56583, 55354, 56584, 55354, 56585, 55354, 56586, 55354, 56587, 55354, 56588, 55354, 56589, 55354, 56590, 55354, 56591, 55354, 56592, 55354, 56593, 55354, 56594, 55354, 56595, 55354, 56596, 55354, 56597, 55354, 56598, 55354, 56599, 55354, 56600, 55354, 56601, 55354, 56602, 55354, 56603, 55354, 56604, 55354, 56605, 55354, 56606, 55354, 56607, 55354, 56608, 55354, 56609, 55356, 56624, 55356, 56625, 55356, 56626, 55356, 56627, 55356, 56628, 55356, 56629, 55356, 56630, 55356, 56631, 55356, 56632, 55356, 56633, 55356, 56634, 55356, 56635, 55356, 56636, 55356, 56637, 55356, 56638, 55356, 56639, 55356, 56640, 55356, 56641, 55356, 56642, 55356, 56643, 55356, 56644, 55356, 56645, 55356, 56646, 55356, 56647, 55356, 56648, 55356, 56649, 55356, 56656, 55356, 56657, 55356, 56658, 55356, 56659, 55356, 56660, 55356, 56661, 55356, 56662, 55356, 56663, 55356, 56664, 55356, 56665, 55356, 56666, 55356, 56667, 55356, 56668, 55356, 56669, 55356, 56670, 55356, 56671, 55356, 56672, 55356, 56673, 55356, 56674, 55356, 56675, 55356, 56676, 55356, 56677, 55356, 56678, 55356, 56679, 55356, 56680, 55356, 56681, 55356, 56688, 55356, 56689, 55356, 56690, 55356, 56691, 55356, 56692, 55356, 56693, 55356, 56694, 55356, 56695, 55356, 56696, 55356, 56697, 55356, 56698, 55356, 56699, 55356, 56700, 55356, 56701, 55356, 56702, 55356, 56703, 55356, 56704, 55356, 56705, 55356, 56706, 55356, 56707, 55356, 56708, 55356, 56709, 55356, 56710, 55356, 56711, 55356, 56712, 55356, 56713, }; static const utf8proc_uint16_t utf8proc_stage1table[] = { 0, 256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680, 7936, 8192, 8448, 8704, 8960, 9216, 9472, 9728, 9984, 10240, 10496, 10752, 11008, 11264, 11520, 11776, 12032, 12288, 12544, 12800, 13056, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13568, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13824, 13312, 13312, 13312, 14080, 5376, 14336, 14592, 14848, 15104, 15360, 15616, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 15872, 17664, 17920, 17920, 17920, 17920, 17920, 17920, 17920, 17920, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18432, 18688, 18944, 19200, 19456, 19712, 19968, 20224, 20480, 20736, 20992, 21248, 21504, 5376, 21760, 22016, 22272, 22528, 22784, 23040, 23296, 23552, 23808, 24064, 24320, 24576, 24832, 25088, 25344, 25600, 25856, 26112, 26368, 26624, 26880, 27136, 27392, 27648, 27904, 5376, 5376, 5376, 28160, 28416, 28672, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 29184, 5376, 5376, 5376, 5376, 29440, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 5376, 5376, 29696, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 5376, 5376, 29952, 30208, 28928, 28928, 30464, 30720, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 30976, 13312, 13312, 13312, 13312, 31232, 31488, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 31744, 13312, 32000, 32256, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 32512, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 32768, 33024, 33280, 33536, 33792, 34048, 34304, 34560, 34816, 10240, 10240, 35072, 28928, 28928, 28928, 28928, 35328, 35584, 35840, 36096, 28928, 36352, 28928, 28928, 36608, 36864, 37120, 28928, 28928, 37376, 37632, 37888, 28928, 38144, 38400, 38656, 38912, 39168, 39424, 39680, 39936, 40192, 40448, 40704, 40960, 28928, 28928, 28928, 28928, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 41216, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 41472, 41728, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 41984, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 42240, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 42496, 42752, 43008, 28928, 28928, 28928, 28928, 28928, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 43264, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 13312, 43520, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 43776, 44032, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 28928, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 44288, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 18176, 44288, }; static const utf8proc_uint16_t utf8proc_stage2table[] = { 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 3, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 3, 8, 9, 9, 10, 11, 10, 9, 9, 12, 13, 9, 14, 15, 16, 15, 15, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 15, 9, 18, 19, 20, 9, 9, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 12, 9, 13, 47, 48, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 12, 75, 13, 75, 2, 2, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 76, 9, 11, 11, 11, 11, 77, 9, 78, 79, 80, 81, 75, 82, 79, 83, 84, 85, 86, 87, 88, 89, 9, 9, 90, 91, 92, 93, 94, 95, 96, 9, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 75, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 75, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 346, 346, 346, 346, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 346, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 595, 596, 596, 596, 596, 596, 597, 598, 47, 47, 47, 47, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 596, 596, 47, 47, 47, 47, 47, 47, 599, 600, 601, 602, 603, 604, 47, 47, 605, 606, 607, 608, 609, 47, 47, 47, 47, 47, 47, 47, 595, 47, 596, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 615, 615, 623, 615, 624, 615, 625, 626, 627, 628, 628, 628, 628, 627, 629, 628, 628, 628, 628, 628, 630, 630, 631, 632, 633, 634, 635, 636, 628, 628, 628, 628, 637, 638, 628, 639, 640, 628, 628, 641, 641, 641, 641, 642, 628, 628, 628, 628, 615, 615, 615, 643, 644, 645, 646, 647, 648, 615, 628, 628, 628, 615, 615, 615, 628, 628, 649, 615, 615, 615, 628, 628, 628, 628, 615, 627, 628, 628, 615, 650, 651, 651, 650, 651, 651, 650, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 652, 653, 654, 655, 656, 47, 657, 658, 0, 0, 659, 660, 661, 662, 663, 664, 0, 0, 0, 0, 88, 665, 666, 667, 668, 669, 670, 0, 671, 0, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 0, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 75, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 615, 615, 615, 615, 615, 915, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 0, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 0, 0, 596, 1120, 1120, 1120, 1120, 1120, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1120, 1162, 0, 0, 77, 77, 11, 0, 628, 615, 615, 615, 615, 628, 615, 615, 615, 1163, 628, 615, 615, 615, 615, 615, 615, 628, 628, 628, 628, 628, 628, 615, 615, 628, 615, 615, 1163, 1164, 615, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1180, 615, 628, 1180, 1173, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1180, 1180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1184, 1184, 1184, 1184, 1184, 1184, 75, 75, 1185, 10, 10, 1186, 15, 1187, 77, 77, 615, 615, 615, 615, 615, 615, 615, 615, 1188, 1189, 1190, 1187, 1191, 1187, 1187, 1187, 1192, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1199, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1200, 1192, 1201, 1202, 1203, 1204, 1188, 1189, 1190, 1205, 1206, 1207, 1208, 1209, 628, 615, 615, 615, 615, 615, 628, 615, 615, 628, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 10, 1211, 1211, 1187, 1192, 1192, 1212, 1192, 1192, 1192, 1192, 1213, 1214, 1215, 1216, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1217, 1218, 1219, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1220, 1221, 1187, 1222, 615, 615, 615, 615, 615, 615, 615, 1184, 77, 615, 615, 615, 615, 628, 615, 1199, 1199, 615, 615, 77, 628, 615, 615, 628, 1192, 1192, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 1192, 1192, 1192, 1223, 1223, 1192, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187, 0, 1224, 1192, 1225, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 615, 628, 615, 615, 628, 615, 615, 628, 628, 628, 615, 628, 628, 615, 628, 615, 615, 615, 628, 615, 628, 615, 628, 615, 628, 615, 615, 0, 0, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 615, 615, 615, 615, 615, 615, 615, 628, 615, 1228, 1228, 77, 9, 9, 9, 1228, 0, 0, 628, 1229, 1229, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 615, 615, 615, 615, 1228, 615, 615, 615, 615, 615, 615, 615, 615, 615, 1228, 615, 615, 615, 1228, 615, 615, 615, 615, 615, 0, 0, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 628, 628, 628, 0, 0, 1180, 0, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 0, 0, 0, 0, 0, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1230, 1192, 1192, 1192, 1192, 1192, 1192, 0, 1184, 1184, 0, 0, 0, 0, 0, 0, 615, 628, 628, 628, 615, 615, 615, 615, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1199, 615, 615, 615, 615, 615, 628, 628, 628, 628, 628, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 1184, 628, 615, 615, 628, 615, 615, 628, 615, 615, 615, 628, 628, 628, 1202, 1203, 1204, 615, 615, 615, 628, 615, 615, 628, 628, 615, 615, 615, 615, 615, 1226, 1226, 1226, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1232, 1233, 346, 346, 346, 346, 346, 346, 1234, 1235, 346, 1236, 1237, 346, 346, 346, 346, 346, 1226, 1231, 1238, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1231, 1231, 1239, 1231, 1231, 346, 615, 628, 615, 615, 1226, 1226, 1226, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 346, 346, 1226, 1226, 1120, 1120, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1120, 596, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1231, 1231, 0, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 0, 0, 0, 346, 346, 346, 346, 0, 0, 1249, 346, 1250, 1231, 1231, 1226, 1226, 1226, 1226, 0, 0, 1251, 1231, 0, 0, 1252, 1253, 1239, 346, 0, 0, 0, 0, 0, 0, 0, 0, 1254, 0, 0, 0, 0, 1255, 1256, 0, 1257, 346, 346, 1226, 1226, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 346, 346, 11, 11, 1258, 1258, 1258, 1258, 1258, 1258, 914, 11, 346, 1120, 615, 0, 0, 1226, 1226, 1231, 0, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 1259, 0, 346, 1260, 0, 346, 346, 0, 0, 1249, 0, 1231, 1231, 1231, 1226, 1226, 0, 0, 0, 0, 1226, 1226, 0, 0, 1226, 1226, 1239, 0, 0, 0, 1226, 0, 0, 0, 0, 0, 0, 0, 1261, 1262, 1263, 346, 0, 1264, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1226, 1226, 346, 346, 346, 1226, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 1226, 1231, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 0, 346, 346, 346, 346, 346, 0, 0, 1249, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 0, 1226, 1226, 1231, 0, 1231, 1231, 1239, 0, 0, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 1226, 1226, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1120, 11, 0, 0, 0, 0, 0, 0, 0, 346, 1226, 1226, 1226, 1226, 1226, 1226, 0, 1226, 1231, 1231, 0, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 0, 346, 346, 346, 346, 346, 0, 0, 1249, 346, 1265, 1226, 1231, 1226, 1226, 1226, 1226, 0, 0, 1266, 1267, 0, 0, 1268, 1269, 1239, 0, 0, 0, 0, 0, 0, 0, 1226, 1270, 1271, 0, 0, 0, 0, 1272, 1273, 0, 346, 346, 346, 1226, 1226, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 914, 346, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 346, 0, 346, 346, 346, 346, 346, 346, 0, 0, 0, 346, 346, 346, 0, 1274, 346, 1275, 346, 0, 0, 0, 346, 346, 0, 346, 0, 346, 346, 0, 0, 0, 346, 346, 0, 0, 0, 346, 346, 346, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 1276, 1231, 1226, 1231, 1231, 0, 0, 0, 1277, 1278, 1231, 0, 1279, 1280, 1281, 1239, 0, 0, 346, 0, 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1258, 1258, 1258, 77, 77, 77, 77, 77, 77, 11, 77, 0, 0, 0, 0, 0, 1226, 1231, 1231, 1231, 1226, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 1249, 346, 1226, 1226, 1226, 1231, 1231, 1231, 1231, 0, 1283, 1226, 1284, 0, 1226, 1226, 1226, 1239, 0, 0, 0, 0, 0, 0, 0, 1285, 1286, 0, 346, 346, 346, 0, 0, 346, 0, 0, 346, 346, 1226, 1226, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 0, 1120, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 914, 346, 1226, 1231, 1231, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 0, 0, 1249, 346, 1231, 1288, 1289, 1231, 1290, 1231, 1231, 0, 1291, 1292, 1293, 0, 1294, 1295, 1226, 1239, 0, 0, 0, 0, 0, 0, 0, 1296, 1297, 0, 0, 0, 0, 0, 0, 346, 346, 0, 346, 346, 1226, 1226, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 346, 346, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 1226, 1231, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1239, 1239, 346, 1298, 1231, 1231, 1226, 1226, 1226, 1226, 0, 1299, 1300, 1231, 0, 1301, 1302, 1303, 1239, 1304, 914, 0, 0, 0, 0, 346, 346, 346, 1305, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 346, 346, 346, 1226, 1226, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 914, 346, 346, 346, 346, 346, 346, 0, 1226, 1231, 1231, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 1306, 0, 0, 0, 0, 1307, 1231, 1231, 1226, 1226, 1226, 0, 1226, 0, 1231, 1308, 1309, 1231, 1310, 1311, 1312, 1313, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 1231, 1231, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 346, 1314, 1226, 1226, 1226, 1226, 1315, 1315, 1239, 0, 0, 0, 0, 11, 346, 346, 346, 346, 346, 346, 596, 1226, 1316, 1316, 1316, 1316, 1226, 1226, 1226, 1120, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 0, 346, 0, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 346, 1317, 1226, 1226, 1226, 1226, 1318, 1318, 1239, 1226, 1226, 346, 0, 0, 346, 346, 346, 346, 346, 0, 596, 0, 1319, 1319, 1319, 1319, 1226, 1226, 1226, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 1320, 1321, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 914, 914, 914, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1322, 1120, 1120, 1120, 1120, 1120, 1120, 914, 1120, 914, 914, 914, 628, 628, 914, 914, 914, 914, 914, 914, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 914, 628, 914, 628, 914, 1323, 12, 13, 12, 13, 1231, 1231, 346, 346, 346, 1324, 346, 346, 346, 346, 0, 346, 346, 346, 346, 1325, 346, 346, 346, 346, 1326, 346, 346, 346, 346, 1327, 346, 346, 346, 346, 1328, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1329, 346, 346, 346, 0, 0, 0, 0, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1331, 1331, 1331, 1331, 1226, 1231, 1331, 1339, 615, 615, 1239, 1120, 615, 615, 346, 346, 346, 346, 346, 1226, 1226, 1226, 1226, 1226, 1226, 1340, 1226, 1226, 1226, 1226, 0, 1226, 1226, 1226, 1226, 1341, 1226, 1226, 1226, 1226, 1342, 1226, 1226, 1226, 1226, 1343, 1226, 1226, 1226, 1226, 1344, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1345, 1226, 1226, 1226, 0, 914, 914, 914, 914, 914, 914, 914, 914, 628, 914, 914, 914, 914, 914, 914, 0, 914, 914, 1120, 1120, 1120, 1120, 1120, 914, 914, 914, 914, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1346, 1347, 346, 346, 346, 346, 1348, 1348, 1226, 1349, 1226, 1226, 1231, 1226, 1226, 1226, 1226, 1226, 1249, 1348, 1239, 1239, 1231, 1231, 1226, 1226, 346, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1120, 1120, 1120, 1120, 1120, 1120, 346, 346, 346, 346, 346, 346, 1231, 1231, 1226, 1226, 346, 346, 346, 346, 1226, 1226, 1226, 346, 1348, 1348, 1348, 346, 346, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 346, 346, 346, 1226, 1226, 1226, 1226, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1348, 1231, 1226, 1226, 1348, 1348, 1348, 1348, 1348, 1348, 628, 346, 1348, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1348, 1348, 1348, 1226, 914, 914, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 0, 1388, 0, 0, 0, 0, 0, 1389, 0, 0, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1120, 1433, 1434, 1435, 1436, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1438, 1439, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 0, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 0, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 615, 615, 615, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 0, 0, 1528, 1529, 1530, 1531, 1532, 1533, 0, 0, 1162, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 914, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 8, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 12, 13, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1120, 1120, 1120, 1534, 1534, 1534, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 1239, 1535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 1535, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 0, 1226, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 649, 649, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1226, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1239, 1226, 1120, 1120, 1120, 596, 1120, 1120, 1120, 11, 346, 615, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 1162, 9, 9, 9, 9, 649, 649, 649, 1536, 649, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 596, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 1226, 1226, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1164, 346, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 1226, 1226, 1226, 1231, 1231, 1231, 1231, 1226, 1226, 1231, 1231, 1231, 0, 0, 0, 0, 1231, 1231, 1226, 1231, 1231, 1231, 1231, 1231, 1231, 1163, 615, 628, 0, 0, 0, 0, 77, 0, 0, 0, 9, 9, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1258, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 615, 628, 1231, 1231, 1226, 0, 0, 1120, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1226, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, 1239, 1348, 1226, 1348, 1348, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1231, 1231, 1231, 1231, 1226, 1226, 615, 615, 615, 615, 615, 615, 615, 615, 0, 0, 628, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 596, 1120, 1120, 1120, 1120, 1120, 1120, 0, 0, 615, 615, 615, 615, 615, 628, 628, 628, 628, 628, 628, 615, 615, 628, 915, 628, 628, 615, 615, 628, 628, 615, 615, 615, 615, 615, 628, 615, 615, 615, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 1226, 1226, 1226, 1231, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 346, 346, 1547, 1548, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1249, 1549, 1226, 1226, 1226, 1226, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1535, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 615, 628, 615, 615, 615, 615, 615, 615, 615, 914, 914, 914, 914, 914, 914, 914, 914, 914, 1120, 1120, 0, 1226, 1226, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1226, 1226, 1226, 1226, 1231, 1231, 1226, 1226, 1535, 1239, 1226, 1226, 346, 346, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1249, 1231, 1226, 1226, 1231, 1231, 1231, 1226, 1231, 1226, 1226, 1226, 1535, 1535, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 1120, 1120, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1226, 1249, 0, 0, 0, 1120, 1120, 1120, 1120, 1120, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 346, 346, 346, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 596, 596, 596, 596, 596, 596, 1120, 1120, 1560, 1561, 1562, 1563, 1564, 1564, 1565, 1566, 1567, 0, 0, 0, 0, 0, 0, 0, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 0, 0, 1611, 1612, 1613, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 615, 615, 615, 1120, 641, 628, 628, 628, 628, 628, 615, 615, 628, 628, 628, 628, 615, 1231, 641, 641, 641, 641, 641, 641, 641, 346, 346, 346, 346, 628, 346, 346, 346, 346, 346, 346, 615, 346, 346, 1231, 615, 615, 346, 0, 0, 0, 0, 0, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 1720, 1721, 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1804, 1805, 615, 615, 628, 615, 615, 615, 615, 615, 615, 615, 628, 615, 615, 651, 1806, 628, 630, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 627, 1164, 1164, 628, 1807, 615, 650, 628, 615, 628, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 0, 0, 2086, 2087, 2088, 2089, 2090, 2091, 0, 0, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 0, 0, 2130, 2131, 2132, 2133, 2134, 2135, 0, 0, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 0, 2144, 0, 2145, 0, 2146, 0, 2147, 2148, 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 0, 0, 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196, 2197, 2198, 2199, 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2225, 2226, 2227, 2228, 2229, 2230, 0, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2244, 2245, 0, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, 2259, 0, 0, 2260, 2261, 2262, 2263, 2264, 2265, 0, 2266, 2267, 2268, 2269, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2284, 0, 0, 2285, 2286, 2287, 0, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2296, 0, 2297, 2298, 2299, 2299, 2299, 2299, 2299, 2300, 2299, 2299, 2299, 1536, 2301, 2302, 2303, 2304, 1162, 2305, 1162, 1162, 1162, 1162, 9, 2306, 2307, 2308, 2309, 2307, 2307, 2308, 2309, 2307, 9, 9, 9, 9, 2310, 2311, 2312, 9, 2313, 2314, 2315, 2316, 2317, 2318, 2319, 76, 10, 10, 10, 2320, 2321, 9, 2322, 2323, 9, 81, 93, 9, 2324, 9, 2325, 48, 48, 9, 9, 9, 2326, 12, 13, 2327, 2328, 2329, 9, 9, 9, 9, 9, 9, 9, 9, 75, 9, 48, 9, 9, 2330, 9, 9, 9, 9, 9, 9, 9, 2299, 1536, 1536, 1536, 1536, 1536, 0, 2331, 2332, 2333, 2334, 1536, 1536, 1536, 1536, 1536, 1536, 2335, 2336, 0, 0, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, 2359, 2360, 2361, 2362, 2363, 0, 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 2377, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 615, 615, 641, 641, 615, 615, 615, 615, 641, 641, 641, 615, 615, 915, 915, 915, 915, 615, 915, 915, 915, 641, 641, 615, 628, 615, 641, 641, 628, 628, 628, 628, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2378, 2379, 2380, 2381, 77, 2382, 2383, 2384, 77, 2385, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2393, 2394, 2395, 77, 2396, 2397, 77, 75, 2398, 2399, 2400, 2401, 2402, 77, 77, 2403, 2404, 2405, 77, 2406, 77, 2407, 77, 2408, 77, 2409, 2410, 2411, 2412, 84, 2413, 2414, 2415, 2416, 2417, 2418, 2419, 2420, 2421, 2422, 2423, 77, 2424, 2425, 2426, 2427, 2428, 2429, 75, 75, 75, 75, 2430, 2431, 2432, 2433, 2434, 77, 75, 77, 77, 2435, 914, 2436, 2437, 2438, 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2454, 2455, 2456, 2457, 2458, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2480, 2481, 2482, 2483, 1534, 1534, 1534, 2484, 2485, 1534, 1534, 1534, 1534, 2486, 77, 77, 0, 0, 0, 0, 2487, 75, 2488, 75, 2489, 79, 79, 79, 79, 79, 2490, 2491, 77, 77, 77, 77, 75, 77, 77, 75, 77, 77, 75, 77, 77, 79, 79, 77, 77, 77, 2492, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2493, 2494, 2495, 2496, 77, 2497, 77, 2498, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2499, 2499, 2500, 2501, 75, 75, 75, 2502, 2503, 2499, 2504, 2505, 2499, 75, 75, 75, 2499, 14, 85, 75, 2499, 2499, 75, 75, 75, 2499, 2499, 2499, 2499, 75, 2499, 2499, 2499, 2499, 2506, 2507, 2508, 2509, 75, 75, 75, 75, 2499, 2510, 2511, 2499, 2512, 2513, 2499, 2499, 2499, 75, 75, 75, 75, 75, 2499, 75, 2499, 2514, 2499, 2499, 2499, 2499, 2515, 2499, 2516, 2517, 2518, 2499, 2519, 2520, 2521, 2499, 2499, 2499, 2522, 75, 75, 75, 75, 2499, 2499, 2499, 2499, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2499, 2523, 2524, 2525, 75, 2526, 2527, 2499, 2499, 2499, 2499, 2499, 2499, 75, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541, 2542, 2543, 2544, 2499, 2499, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2499, 2499, 2499, 75, 75, 2499, 2499, 2555, 2556, 75, 75, 75, 75, 75, 2499, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2557, 2499, 75, 75, 2499, 2499, 2558, 2559, 2499, 2560, 2561, 2562, 2563, 2564, 2499, 2499, 2565, 2566, 2567, 2568, 2499, 2499, 2499, 75, 75, 75, 75, 75, 2499, 2499, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2499, 2499, 2499, 2499, 2499, 75, 75, 2499, 2499, 75, 75, 75, 75, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2569, 2570, 2571, 2572, 2499, 2499, 2499, 2499, 2499, 2499, 2573, 2574, 2575, 2576, 75, 75, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 77, 77, 77, 77, 77, 77, 77, 77, 12, 13, 12, 13, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2577, 2577, 77, 77, 77, 77, 2499, 2499, 77, 77, 77, 77, 77, 77, 79, 2578, 2579, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 77, 75, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 914, 77, 77, 77, 77, 77, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 75, 75, 75, 75, 75, 75, 77, 77, 77, 77, 77, 77, 77, 2577, 2577, 2577, 2577, 79, 79, 79, 2577, 79, 79, 2577, 77, 77, 77, 77, 79, 79, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2580, 2581, 2582, 2583, 2584, 2585, 2586, 2587, 2588, 2589, 2590, 2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2600, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, 2650, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, 2677, 2678, 2679, 2680, 2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2710, 2711, 2712, 2713, 2714, 2715, 2716, 2717, 2718, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 75, 77, 77, 77, 77, 77, 77, 77, 77, 79, 75, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 75, 75, 75, 2719, 2719, 2720, 2720, 75, 79, 79, 79, 79, 79, 79, 77, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 77, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2719, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 2721, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 79, 79, 79, 79, 79, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 79, 2577, 79, 79, 79, 79, 2577, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 79, 2577, 77, 77, 79, 79, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 77, 79, 77, 79, 77, 77, 77, 77, 77, 77, 79, 77, 77, 77, 79, 77, 77, 77, 77, 77, 77, 2577, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 77, 77, 79, 77, 77, 77, 77, 2577, 77, 2577, 77, 77, 77, 77, 2577, 2577, 2577, 77, 2577, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 79, 79, 79, 79, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 77, 2577, 2577, 2577, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2577, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2577, 2499, 75, 75, 2499, 2499, 12, 13, 75, 2499, 2499, 75, 2499, 2499, 2499, 75, 75, 75, 75, 75, 2499, 2499, 2499, 2499, 75, 75, 75, 75, 75, 2499, 2499, 2499, 75, 75, 75, 2499, 2499, 2499, 2499, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2719, 2719, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 12, 13, 75, 75, 2499, 2499, 2499, 2499, 2499, 2499, 75, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 75, 75, 75, 75, 75, 75, 75, 75, 2499, 75, 75, 75, 75, 75, 75, 75, 2499, 2499, 2499, 2499, 2499, 2499, 75, 75, 75, 2499, 75, 75, 75, 75, 2499, 2499, 2499, 2499, 2499, 75, 2499, 2499, 75, 75, 12, 13, 12, 13, 2499, 75, 75, 75, 75, 2499, 75, 2499, 2499, 2499, 75, 75, 2499, 2499, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2499, 2499, 2499, 2499, 2499, 2499, 75, 75, 12, 13, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2499, 2499, 2722, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 75, 2499, 2499, 2499, 2499, 75, 75, 2499, 75, 2499, 75, 75, 2499, 75, 2499, 2499, 2499, 2499, 75, 75, 75, 75, 75, 2499, 2499, 75, 75, 75, 75, 75, 75, 2499, 2499, 2499, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2499, 2499, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2499, 2499, 75, 75, 75, 75, 2499, 2499, 2499, 2499, 75, 2499, 2499, 75, 75, 2499, 2723, 2724, 2725, 75, 75, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 75, 75, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 75, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 2499, 75, 75, 75, 75, 75, 2726, 2727, 2499, 75, 75, 75, 2499, 2499, 2499, 2499, 2499, 75, 75, 75, 75, 75, 2499, 2499, 2499, 75, 75, 75, 75, 2499, 75, 75, 75, 2499, 2499, 2499, 2499, 2499, 75, 2499, 75, 75, 77, 77, 77, 77, 77, 79, 79, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2577, 2577, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 77, 77, 75, 75, 75, 75, 75, 75, 77, 77, 77, 2577, 77, 77, 77, 77, 2577, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2728, 77, 2729, 2730, 2731, 2732, 2733, 2734, 2735, 2736, 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2746, 2747, 2748, 2749, 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2774, 2775, 2776, 2777, 2778, 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826, 2827, 2828, 2829, 2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850, 2851, 2852, 2853, 2854, 2855, 2856, 2857, 2858, 2859, 2860, 2861, 2862, 2863, 2864, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885, 2886, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899, 2900, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 2933, 2934, 2935, 2936, 2937, 2938, 2939, 2940, 2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949, 2950, 2951, 2952, 2953, 2954, 2955, 2956, 2957, 77, 77, 77, 77, 77, 77, 2958, 2959, 2960, 2961, 615, 615, 615, 2962, 2963, 0, 0, 0, 0, 0, 9, 9, 9, 9, 1287, 9, 9, 2964, 2965, 2966, 2967, 2968, 2969, 2970, 2971, 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, 2991, 2992, 2993, 2994, 2995, 2996, 2997, 2998, 2999, 3000, 3001, 0, 3002, 0, 0, 0, 0, 0, 3003, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 3004, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1239, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 9, 9, 81, 93, 81, 93, 9, 9, 9, 81, 93, 9, 81, 93, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1162, 9, 9, 1162, 9, 81, 93, 9, 9, 81, 93, 12, 13, 12, 13, 12, 13, 12, 13, 9, 9, 9, 9, 9, 595, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1162, 1162, 9, 9, 9, 9, 1162, 9, 2309, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 77, 77, 9, 9, 9, 12, 13, 12, 13, 12, 13, 12, 13, 1162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 0, 3005, 3005, 3005, 3005, 3006, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3007, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3008, 3009, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, 3079, 3080, 3081, 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, 3095, 3096, 3097, 3098, 3099, 3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, 3127, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176, 3177, 3178, 3179, 3180, 3181, 3182, 3183, 3184, 3185, 3186, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3199, 3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3213, 3214, 3215, 3216, 3217, 3218, 3219, 3220, 3221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 0, 0, 0, 0, 3222, 3223, 3223, 3223, 3005, 3224, 3225, 3226, 3227, 3228, 3227, 3228, 3227, 3228, 3227, 3228, 3227, 3228, 3005, 3005, 3227, 3228, 3227, 3228, 3227, 3228, 3227, 3228, 3229, 3230, 3231, 3231, 3005, 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226, 1807, 1164, 627, 1163, 3232, 3232, 3233, 3224, 3224, 3224, 3224, 3224, 3234, 3005, 3235, 3236, 3237, 3224, 3225, 3238, 3005, 77, 0, 3225, 3225, 3225, 3225, 3225, 3239, 3225, 3225, 3225, 3225, 3240, 3241, 3242, 3243, 3244, 3245, 3246, 3247, 3248, 3249, 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3260, 3261, 3262, 3263, 3225, 3264, 3265, 3266, 3267, 3268, 3269, 3225, 3225, 3225, 3225, 3225, 3270, 3271, 3272, 3273, 3274, 3275, 3276, 3277, 3278, 3279, 3280, 3281, 3282, 3283, 3284, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3285, 3225, 3225, 0, 0, 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3229, 3225, 3225, 3225, 3225, 3225, 3293, 3225, 3225, 3225, 3225, 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3317, 3225, 3318, 3319, 3320, 3321, 3322, 3323, 3225, 3225, 3225, 3225, 3225, 3324, 3325, 3326, 3327, 3328, 3329, 3330, 3331, 3332, 3333, 3334, 3335, 3336, 3337, 3338, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3339, 3340, 3341, 3342, 3225, 3343, 3225, 3225, 3344, 3345, 3346, 3347, 3223, 3224, 3348, 3349, 3350, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, 3370, 3371, 3372, 3373, 3374, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, 3400, 3401, 3402, 3403, 3404, 3405, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, 3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3444, 0, 3445, 3445, 3446, 3447, 3448, 3449, 3450, 3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3460, 3461, 3462, 3463, 3464, 3465, 3466, 3467, 3468, 3469, 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3489, 3490, 0, 3491, 3492, 3493, 3494, 3495, 3496, 3497, 3498, 3499, 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, 3514, 3515, 3516, 3517, 3518, 3519, 3520, 3521, 3522, 3523, 3524, 3525, 3526, 3527, 3528, 3529, 3530, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3549, 3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557, 3558, 3559, 3560, 3561, 3562, 3563, 3564, 3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, 3574, 3575, 3576, 3577, 3445, 3578, 3579, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, 3604, 3605, 3606, 3607, 3608, 3609, 3610, 3611, 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, 3620, 3621, 3622, 3623, 3624, 3625, 3626, 3627, 3628, 3629, 3630, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 3640, 3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, 3650, 3651, 3652, 3653, 3654, 3655, 3656, 3657, 3658, 3659, 3660, 3661, 3662, 3663, 3664, 3665, 3666, 3667, 3668, 3669, 3670, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3678, 3679, 3680, 3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3695, 3696, 3697, 3698, 3699, 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, 3712, 3713, 3714, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 3770, 3771, 3772, 3773, 3774, 3775, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3786, 3787, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3813, 3814, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3826, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3841, 3842, 3843, 3844, 3845, 3846, 3847, 3848, 3849, 3850, 3851, 3852, 3853, 3854, 3855, 3856, 3857, 3858, 3859, 3860, 3861, 3862, 3863, 3864, 3865, 3866, 3867, 3868, 3869, 3870, 3871, 3872, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, 3884, 3885, 3886, 3887, 3888, 3889, 3890, 3891, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3907, 3908, 3909, 3910, 3911, 3912, 3913, 3914, 3915, 3916, 3917, 3918, 3919, 3920, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939, 3940, 3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948, 3949, 3950, 3951, 3952, 3953, 3954, 3955, 3956, 3957, 3958, 3959, 3960, 3961, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3224, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 596, 596, 596, 596, 596, 596, 1120, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 596, 9, 9, 9, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 3986, 3987, 3988, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 346, 615, 915, 915, 915, 9, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 9, 595, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4035, 4036, 4037, 615, 615, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 615, 615, 1120, 1120, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 595, 595, 595, 595, 595, 595, 595, 595, 595, 47, 47, 4038, 4039, 4040, 4041, 4042, 4043, 4044, 4045, 4046, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059, 4060, 4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, 4079, 4080, 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099, 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 595, 4140, 4140, 4141, 4142, 4143, 4144, 346, 4145, 4146, 4147, 4148, 4149, 4150, 4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4175, 4176, 4177, 4178, 4179, 4180, 4181, 4182, 4183, 4184, 4185, 4186, 4187, 4188, 4189, 4190, 4191, 4192, 4193, 4194, 4195, 4196, 4197, 4198, 4199, 4200, 4201, 4202, 4203, 0, 0, 0, 0, 0, 4204, 4205, 0, 4206, 0, 4207, 4208, 4209, 4210, 4211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4212, 4213, 4214, 4215, 4216, 346, 4217, 4218, 4219, 346, 346, 346, 346, 346, 346, 346, 1226, 346, 346, 346, 1239, 346, 346, 346, 346, 1226, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1226, 1226, 1231, 77, 77, 77, 77, 1239, 0, 0, 0, 1258, 1258, 1258, 1258, 1258, 1258, 914, 914, 11, 84, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1231, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1239, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 1120, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 346, 346, 346, 346, 346, 346, 1120, 1120, 1120, 346, 1120, 346, 346, 1226, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 1226, 1226, 1226, 628, 628, 628, 1120, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 0, 0, 0, 1226, 1226, 1226, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1249, 1231, 1231, 1226, 1226, 1226, 1226, 1231, 1231, 1226, 1226, 1231, 1231, 1535, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 0, 596, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 1120, 1120, 346, 346, 346, 346, 346, 1226, 596, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1226, 1226, 1231, 1231, 1226, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 1226, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1231, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 1120, 1120, 1120, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 596, 346, 346, 346, 346, 346, 346, 914, 914, 914, 346, 1348, 1226, 1348, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 615, 346, 615, 615, 628, 346, 346, 615, 615, 346, 346, 346, 346, 346, 615, 615, 346, 615, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 596, 1120, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1226, 1226, 1231, 1231, 1120, 1120, 346, 596, 596, 1231, 1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 4220, 4221, 4222, 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 4234, 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4245, 4246, 4247, 4248, 4249, 4250, 4251, 4252, 4253, 4254, 4255, 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4140, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 47, 47, 0, 0, 0, 0, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, 4295, 4296, 4297, 4298, 4299, 4300, 4301, 4302, 4303, 4304, 4305, 4306, 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 4347, 4348, 4349, 4350, 4351, 4352, 4353, 4354, 4355, 4356, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1226, 1231, 1231, 1226, 1231, 1231, 1120, 1231, 1239, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4357, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 4358, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 0, 0, 0, 0, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 1441, 0, 0, 0, 0, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4359, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4368, 4369, 4370, 4371, 4372, 4373, 4374, 4375, 4376, 4377, 4378, 4379, 4380, 4381, 4382, 4383, 4384, 4385, 4386, 4387, 4388, 4389, 4390, 4391, 4392, 4393, 4394, 4395, 4396, 4397, 4398, 4399, 4400, 4401, 4402, 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, 4411, 4412, 4413, 4414, 4415, 4416, 4417, 4418, 4419, 4420, 4421, 4422, 4423, 4424, 4425, 4426, 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434, 4435, 4436, 4437, 4438, 4439, 4440, 4441, 4442, 4443, 4444, 4445, 4446, 4447, 4448, 4449, 4450, 4451, 4380, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469, 4470, 4471, 4472, 4473, 4474, 4475, 4476, 4477, 4478, 4479, 4480, 4481, 4482, 4483, 4484, 4485, 4486, 4487, 4488, 4489, 4490, 4491, 4492, 4493, 4494, 4495, 4496, 4497, 4498, 4499, 4500, 4501, 4502, 4503, 4504, 4505, 4506, 4507, 4508, 4509, 4510, 4511, 4512, 4513, 4514, 4515, 4516, 4517, 4518, 4519, 4470, 4520, 4521, 4522, 4523, 4524, 4525, 4526, 4527, 4454, 4528, 4529, 4530, 4531, 4532, 4533, 4534, 4535, 4536, 4537, 4538, 4539, 4540, 4541, 4542, 4543, 4544, 4545, 4546, 4547, 4380, 4548, 4549, 4550, 4551, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4559, 4560, 4561, 4562, 4563, 4564, 4565, 4566, 4567, 4568, 4569, 4570, 4571, 4572, 4573, 4574, 4456, 4575, 4576, 4577, 4578, 4579, 4580, 4581, 4582, 4583, 4584, 4585, 4586, 4587, 4588, 4589, 4590, 4591, 4592, 4593, 4594, 4595, 4596, 4597, 4598, 4599, 4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, 4608, 4609, 4610, 4611, 4612, 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, 3225, 3225, 4625, 3225, 4626, 3225, 3225, 4627, 4628, 4629, 4630, 4631, 4632, 4633, 4634, 4635, 4636, 3225, 4637, 3225, 4638, 3225, 3225, 4639, 4640, 3225, 3225, 3225, 4641, 4642, 4643, 4644, 4645, 4646, 4647, 4648, 4649, 4650, 4651, 4652, 4653, 4654, 4655, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4664, 4665, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4673, 4674, 4675, 4676, 4677, 4678, 4679, 4680, 4681, 4682, 4683, 4684, 4685, 4509, 4686, 4687, 4688, 4689, 4690, 4691, 4691, 4692, 4693, 4694, 4695, 4696, 4697, 4698, 4699, 4639, 4700, 4701, 4702, 4703, 4704, 4705, 0, 0, 4706, 4707, 4708, 4709, 4710, 4711, 4712, 4713, 4653, 4714, 4715, 4716, 4625, 4717, 4718, 4719, 4720, 4721, 4722, 4723, 4724, 4725, 4726, 4727, 4728, 4662, 4729, 4663, 4730, 4731, 4732, 4733, 4734, 4626, 4401, 4735, 4736, 4737, 4471, 4558, 4738, 4739, 4670, 4740, 4671, 4741, 4742, 4743, 4628, 4744, 4745, 4746, 4747, 4748, 4629, 4749, 4750, 4751, 4752, 4753, 4754, 4685, 4755, 4756, 4509, 4757, 4689, 4758, 4759, 4760, 4761, 4762, 4694, 4763, 4638, 4764, 4695, 4452, 4765, 4696, 4766, 4698, 4767, 4768, 4769, 4770, 4771, 4700, 4634, 4772, 4701, 4773, 4702, 4774, 4368, 4775, 4776, 4777, 4778, 4779, 4780, 4781, 4782, 4783, 4784, 4785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4786, 4787, 4788, 4789, 4790, 4791, 4792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4793, 4794, 4795, 4796, 4797, 0, 0, 0, 0, 0, 4798, 4799, 4800, 4801, 4802, 4803, 4804, 4805, 4806, 4807, 4808, 4809, 4810, 4811, 4812, 4813, 4814, 4815, 4816, 4817, 4818, 4819, 4820, 4821, 4822, 4823, 0, 4824, 4825, 4826, 4827, 4828, 0, 4829, 0, 4830, 4831, 0, 4832, 4833, 0, 4834, 4835, 4836, 4837, 4838, 4839, 4840, 4841, 4842, 4843, 4844, 4845, 4846, 4847, 4848, 4849, 4850, 4851, 4852, 4853, 4854, 4855, 4856, 4857, 4858, 4859, 4860, 4861, 4862, 4863, 4864, 4865, 4866, 4867, 4868, 4869, 4870, 4871, 4872, 4873, 4874, 4875, 4876, 4877, 4878, 4879, 4880, 4881, 4882, 4883, 4884, 4885, 4886, 4887, 4888, 4889, 4890, 4891, 4892, 4893, 4894, 4895, 4896, 4897, 4898, 4899, 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, 4920, 4921, 4922, 4923, 4924, 4925, 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, 4940, 4941, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949, 4950, 4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959, 4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, 4984, 4985, 4986, 4987, 4988, 4989, 4980, 4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, 5000, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072, 5073, 5074, 5075, 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, 4981, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108, 5109, 5110, 5111, 5112, 5113, 5114, 5115, 5116, 5117, 5118, 5119, 5120, 5121, 5122, 5123, 5124, 5125, 5126, 5127, 5128, 5129, 5130, 5131, 5132, 5133, 5134, 5135, 5136, 5137, 5138, 5139, 5140, 5141, 5142, 5143, 5144, 5145, 5146, 5147, 5148, 5149, 5150, 5151, 5152, 5153, 5154, 5155, 5156, 5157, 5158, 5159, 5160, 5161, 5162, 5163, 5164, 5165, 5166, 5167, 5168, 5169, 5170, 5171, 5172, 5173, 5174, 5175, 5176, 5177, 5178, 5179, 5180, 5181, 5182, 5183, 5184, 5185, 5186, 5187, 5188, 5189, 5190, 5191, 5192, 5193, 5194, 5195, 5196, 5197, 5198, 5199, 5200, 5201, 5202, 5203, 5204, 5205, 5206, 5207, 5208, 5209, 5210, 5211, 5212, 5213, 5214, 5215, 5216, 5217, 5218, 5219, 5220, 5221, 5222, 5223, 5224, 5225, 5226, 5227, 5228, 5229, 5230, 5231, 5232, 5233, 5234, 5235, 5236, 5237, 5238, 5239, 5240, 5241, 5242, 5243, 5244, 5245, 5246, 5247, 5248, 5249, 5250, 5251, 5252, 5253, 5254, 5255, 5256, 5257, 5258, 5259, 5260, 5261, 5262, 5263, 5264, 5265, 5266, 5267, 5268, 5269, 5270, 5271, 5272, 5273, 5274, 5275, 5276, 5277, 5278, 5279, 5280, 5281, 5282, 5283, 5284, 5285, 5286, 5287, 5288, 5289, 5290, 5291, 5292, 5293, 5294, 5295, 5296, 5297, 5298, 5299, 5300, 5301, 5302, 5303, 2309, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 5304, 5305, 5306, 5307, 5308, 5309, 5310, 5311, 5312, 5313, 5314, 5315, 5316, 5317, 5318, 5319, 5320, 5321, 5322, 5323, 5324, 5325, 5326, 5327, 5328, 5329, 5330, 5331, 5332, 5333, 5334, 5335, 5336, 5337, 5338, 5339, 5340, 5341, 5342, 5343, 5344, 5345, 5346, 5347, 5348, 5349, 5350, 5351, 5352, 5353, 5354, 5355, 5356, 5357, 5358, 5359, 5360, 5361, 5362, 5363, 5364, 5365, 5366, 5367, 0, 0, 5368, 5369, 5370, 5371, 5372, 5373, 5374, 5375, 5376, 5377, 5378, 5379, 5380, 5381, 5382, 5383, 5384, 5385, 5386, 5387, 5388, 5389, 5390, 5391, 5392, 5393, 5394, 5395, 5396, 5397, 5398, 5399, 5400, 5401, 5402, 5403, 5404, 5405, 5406, 5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5421, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5422, 5423, 5424, 5425, 5426, 5427, 5428, 5429, 5430, 5431, 5432, 5433, 5434, 77, 77, 77, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5442, 5443, 5444, 0, 0, 0, 0, 0, 0, 615, 615, 615, 615, 615, 615, 615, 628, 628, 628, 628, 628, 628, 628, 615, 615, 5445, 5446, 5447, 5448, 5448, 5449, 5450, 5451, 5452, 5453, 5454, 5455, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, 3223, 3223, 5465, 5466, 5467, 5467, 5467, 5467, 5468, 5468, 5468, 5469, 5470, 5471, 0, 5472, 5473, 5474, 5475, 5476, 5477, 5478, 5479, 5480, 5481, 5482, 5483, 5484, 5485, 5486, 5487, 5488, 5489, 5490, 0, 5491, 5492, 5493, 5494, 0, 0, 0, 0, 5495, 5496, 5497, 1192, 5498, 0, 5499, 5500, 5501, 5502, 5503, 5504, 5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516, 5517, 5518, 5519, 5520, 5521, 5522, 5523, 5524, 5525, 5526, 5527, 5528, 5529, 5530, 5531, 5532, 5533, 5534, 5535, 5536, 5537, 5538, 5539, 5540, 5541, 5542, 5543, 5544, 5545, 5546, 5547, 5548, 5549, 5550, 5551, 5552, 5553, 5554, 5555, 5556, 5557, 5558, 5559, 5560, 5561, 5562, 5563, 5564, 5565, 5566, 5567, 5568, 5569, 5570, 5571, 5572, 5573, 5574, 5575, 5576, 5577, 5578, 5579, 5580, 5581, 5582, 5583, 5584, 5585, 5586, 5587, 5588, 5589, 5590, 5591, 5592, 5593, 5594, 5595, 5596, 5597, 5598, 5599, 5600, 5601, 5602, 5603, 5604, 5605, 5606, 5607, 5608, 5609, 5610, 5611, 5612, 5613, 5614, 5615, 5616, 5617, 5618, 5619, 5620, 5621, 5622, 5623, 5624, 5625, 5626, 5627, 5628, 5629, 5630, 5631, 5632, 5633, 0, 0, 1536, 0, 5634, 5635, 5636, 5637, 5638, 5639, 5640, 5641, 5642, 5643, 5644, 5645, 5646, 5647, 5648, 5649, 5650, 5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, 5659, 5660, 5661, 5662, 5663, 5664, 5665, 5666, 5667, 5668, 5669, 5670, 5671, 5672, 5673, 5674, 5675, 5676, 5677, 5678, 5679, 5680, 5681, 5682, 5683, 5684, 5685, 5686, 5687, 5688, 5689, 5690, 5691, 5692, 5693, 5694, 5695, 5696, 5697, 5698, 5699, 5700, 5701, 5702, 5703, 5704, 5705, 5706, 5707, 5708, 5709, 5710, 5711, 5712, 5713, 5714, 5715, 5716, 5717, 5718, 5719, 5720, 5721, 5722, 5723, 5724, 5725, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734, 5735, 5736, 5737, 5738, 5739, 5740, 5741, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749, 5750, 5751, 5752, 5753, 5754, 5755, 5756, 5757, 5758, 5759, 5760, 5761, 5762, 5763, 5764, 5765, 5766, 5767, 5768, 5769, 5770, 5771, 5772, 5773, 5774, 5775, 5776, 5777, 5778, 5779, 5780, 5781, 5782, 5783, 5784, 5785, 5786, 5787, 5788, 5789, 5790, 5791, 5792, 5793, 5794, 5795, 5796, 5797, 5798, 5799, 5800, 5801, 5802, 5803, 5804, 5805, 5806, 5807, 5808, 5809, 5810, 5811, 5812, 5813, 5814, 5815, 5816, 5817, 5818, 5819, 5820, 5821, 5822, 5823, 0, 0, 0, 5824, 5825, 5826, 5827, 5828, 5829, 0, 0, 5830, 5831, 5832, 5833, 5834, 5835, 0, 0, 5836, 5837, 5838, 5839, 5840, 5841, 0, 0, 5842, 5843, 5844, 0, 0, 0, 5845, 5846, 5847, 5848, 5849, 5850, 5851, 0, 5852, 5853, 5854, 5855, 5856, 5857, 5858, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5859, 5859, 5859, 77, 77, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 1120, 9, 1120, 0, 0, 0, 0, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 914, 914, 914, 914, 914, 914, 914, 914, 914, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 5860, 1287, 1287, 1287, 1287, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 1287, 1287, 77, 914, 914, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 628, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 628, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 5861, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1258, 1258, 1258, 1258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1534, 346, 346, 346, 346, 346, 346, 346, 346, 1534, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 615, 615, 615, 615, 615, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 1120, 1534, 1534, 1534, 1534, 1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5862, 5863, 5864, 5865, 5866, 5867, 5868, 5869, 5870, 5871, 5872, 5873, 5874, 5875, 5876, 5877, 5878, 5879, 5880, 5881, 5882, 5883, 5884, 5885, 5886, 5887, 5888, 5889, 5890, 5891, 5892, 5893, 5894, 5895, 5896, 5897, 5898, 5899, 5900, 5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909, 5910, 5911, 5912, 5913, 5914, 5915, 5916, 5917, 5918, 5919, 5920, 5921, 5922, 5923, 5924, 5925, 5926, 5927, 5928, 5929, 5930, 5931, 5932, 5933, 5934, 5935, 5936, 5937, 5938, 5939, 5940, 5941, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 5942, 5943, 5944, 5945, 5946, 5947, 5948, 5949, 5950, 5951, 5952, 5953, 5954, 5955, 5956, 5957, 5958, 5959, 5960, 5961, 5962, 5963, 5964, 5965, 5966, 5967, 5968, 5969, 5970, 5971, 5972, 5973, 5974, 5975, 5976, 5977, 0, 0, 0, 0, 5978, 5979, 5980, 5981, 5982, 5983, 5984, 5985, 5986, 5987, 5988, 5989, 5990, 5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999, 6000, 6001, 6002, 6003, 6004, 6005, 6006, 6007, 6008, 6009, 6010, 6011, 6012, 6013, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 6014, 6015, 6016, 6017, 6018, 6019, 6020, 6021, 6022, 6023, 6024, 0, 6025, 6026, 6027, 6028, 6029, 6030, 6031, 6032, 6033, 6034, 6035, 6036, 6037, 6038, 6039, 0, 6040, 6041, 6042, 6043, 6044, 6045, 6046, 0, 6047, 6048, 0, 6049, 6050, 6051, 6052, 6053, 6054, 6055, 6056, 6057, 6058, 6059, 0, 6060, 6061, 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069, 6070, 6071, 6072, 6073, 6074, 0, 6075, 6076, 6077, 6078, 6079, 6080, 6081, 0, 6082, 6083, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6084, 6085, 6086, 6087, 6088, 6089, 0, 6090, 6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, 6099, 6100, 6101, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 6109, 6110, 6111, 6112, 6113, 6114, 6115, 6116, 6117, 6118, 6119, 6120, 6121, 6122, 6123, 6124, 6125, 6126, 6127, 6128, 6129, 6130, 6131, 0, 6132, 6133, 6134, 6135, 6136, 6137, 6138, 6139, 6140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 1183, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 1183, 1183, 0, 0, 0, 1183, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 1180, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 6142, 6142, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 0, 0, 0, 0, 0, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 1183, 1183, 0, 0, 0, 0, 0, 6141, 6141, 6141, 6141, 6141, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 6141, 6141, 6141, 6141, 6141, 6141, 0, 0, 0, 9, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 0, 0, 1180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 0, 6141, 6141, 1183, 1183, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 0, 0, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 1183, 1226, 1226, 1226, 0, 1226, 1226, 0, 0, 0, 0, 0, 1226, 628, 1226, 615, 1183, 1183, 1183, 1183, 0, 1183, 1183, 1183, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 615, 641, 628, 0, 0, 0, 0, 1239, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 0, 0, 0, 0, 0, 0, 0, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 6141, 6141, 1180, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 6141, 6141, 6141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 6142, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 615, 628, 0, 0, 0, 0, 6141, 6141, 6141, 6141, 6141, 1180, 1180, 1180, 1180, 1180, 1180, 1180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 0, 0, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 0, 0, 0, 0, 1180, 1180, 1180, 1180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6143, 6144, 6145, 6146, 6147, 6148, 6149, 6150, 6151, 6152, 6153, 6154, 6155, 6156, 6157, 6158, 6159, 6160, 6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, 6169, 6170, 6171, 6172, 6173, 6174, 6175, 6176, 6177, 6178, 6179, 6180, 6181, 6182, 6183, 6184, 6185, 6186, 6187, 6188, 6189, 6190, 6191, 6192, 6193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6194, 6195, 6196, 6197, 6198, 6199, 6200, 6201, 6202, 6203, 6204, 6205, 6206, 6207, 6208, 6209, 6210, 6211, 6212, 6213, 6214, 6215, 6216, 6217, 6218, 6219, 6220, 6221, 6222, 6223, 6224, 6225, 6226, 6227, 6228, 6229, 6230, 6231, 6232, 6233, 6234, 6235, 6236, 6237, 6238, 6239, 6240, 6241, 6242, 6243, 6244, 0, 0, 0, 0, 0, 0, 0, 6141, 6141, 6141, 6141, 6141, 6141, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 615, 615, 615, 615, 0, 0, 0, 0, 0, 0, 0, 0, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 1210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 6245, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 615, 615, 1178, 0, 0, 1183, 1183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 628, 628, 628, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 1183, 0, 0, 0, 0, 0, 0, 0, 0, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 628, 628, 615, 615, 615, 628, 615, 628, 628, 628, 628, 6246, 6246, 6246, 6246, 1187, 1187, 1187, 1187, 1187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 615, 628, 615, 628, 1180, 1180, 1180, 1180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1231, 1226, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1239, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1239, 346, 346, 1226, 1226, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1239, 1226, 1226, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 6247, 6248, 6249, 6250, 346, 346, 346, 346, 346, 346, 346, 346, 6251, 346, 346, 346, 346, 346, 6252, 346, 346, 346, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1231, 1231, 1239, 6253, 1120, 1120, 6254, 1120, 1120, 1120, 1120, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6254, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 615, 615, 615, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 6255, 1226, 1226, 1226, 1226, 1231, 1226, 6256, 6257, 1226, 6258, 6259, 1239, 1239, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1120, 1120, 1120, 1120, 346, 1231, 1231, 346, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1249, 1120, 1120, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 1226, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1535, 346, 1304, 1304, 346, 1120, 1120, 1120, 1120, 1226, 1249, 1226, 1226, 1120, 1231, 1226, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 346, 1120, 346, 1120, 1120, 1120, 0, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1231, 1231, 1226, 1535, 1249, 1226, 1120, 1120, 1120, 1120, 1120, 1120, 1226, 346, 346, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 0, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1120, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1249, 1239, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 1226, 1226, 1231, 1231, 0, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 0, 346, 346, 346, 346, 346, 0, 1249, 1249, 346, 6260, 1231, 1226, 1231, 1231, 1231, 1231, 0, 0, 6261, 1231, 0, 0, 6262, 6263, 1535, 0, 0, 346, 0, 0, 0, 0, 0, 0, 6264, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 1231, 1231, 0, 0, 615, 615, 615, 615, 615, 615, 615, 0, 0, 0, 615, 615, 615, 615, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1239, 1226, 1226, 1231, 1249, 346, 346, 346, 346, 1120, 1120, 1120, 1120, 1120, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1120, 1120, 0, 1120, 615, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 6265, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 6266, 6267, 6268, 6269, 6270, 6271, 1226, 1226, 1231, 1239, 1249, 346, 346, 1120, 346, 0, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 6272, 1231, 1231, 1226, 1226, 1226, 1226, 0, 0, 6273, 6274, 6275, 6276, 1226, 1226, 1231, 1239, 1249, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 346, 346, 346, 346, 1226, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1226, 1231, 1239, 1226, 1120, 1120, 1120, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1231, 1226, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1535, 1249, 346, 1120, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 1226, 1226, 1226, 1348, 1348, 1226, 1226, 1226, 1226, 1231, 1226, 1226, 1226, 1226, 1239, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1258, 1258, 1120, 1120, 1120, 914, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1239, 1249, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6277, 6278, 6279, 6280, 6281, 6282, 6283, 6284, 6285, 6286, 6287, 6288, 6289, 6290, 6291, 6292, 6293, 6294, 6295, 6296, 6297, 6298, 6299, 6300, 6301, 6302, 6303, 6304, 6305, 6306, 6307, 6308, 6309, 6310, 6311, 6312, 6313, 6314, 6315, 6316, 6317, 6318, 6319, 6320, 6321, 6322, 6323, 6324, 6325, 6326, 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, 6335, 6336, 6337, 6338, 6339, 6340, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 6341, 1231, 1231, 1231, 1231, 6342, 0, 1231, 6343, 0, 0, 1226, 1226, 1535, 1239, 1304, 1231, 1304, 1231, 1249, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1226, 1226, 1226, 1226, 0, 0, 1226, 1226, 1231, 1231, 1231, 1231, 1239, 346, 1120, 346, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 1226, 1226, 1226, 1226, 1226, 1226, 6344, 6344, 1226, 1226, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1239, 1226, 1226, 1226, 1226, 1231, 1304, 1226, 1226, 1226, 1226, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1239, 0, 0, 0, 0, 0, 0, 0, 0, 346, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1231, 1226, 1226, 1226, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1304, 1304, 1304, 1304, 1304, 1304, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1226, 1239, 1120, 1120, 1120, 346, 1120, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 6345, 346, 1120, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 1120, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, 1231, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1231, 1226, 1226, 1231, 1226, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 1226, 1226, 1226, 1226, 0, 0, 0, 1226, 0, 1226, 1226, 0, 1226, 1226, 1226, 1249, 1226, 1239, 1239, 1304, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 0, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1231, 1231, 1231, 0, 1226, 1226, 0, 1231, 1231, 1226, 1231, 1239, 346, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1226, 1226, 1231, 1231, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 1226, 1226, 1304, 1231, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1231, 1231, 1226, 1226, 1226, 1226, 1226, 0, 0, 0, 1231, 1231, 1226, 1535, 1239, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 77, 77, 77, 77, 77, 77, 77, 77, 11, 11, 11, 11, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 0, 1120, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 6346, 1226, 346, 346, 346, 346, 346, 346, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 1120, 1120, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 641, 641, 641, 641, 641, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 615, 615, 615, 615, 615, 615, 615, 1120, 1120, 1120, 1120, 1120, 914, 914, 914, 914, 596, 596, 596, 596, 1120, 914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6347, 6348, 6349, 6350, 6351, 6352, 6353, 6354, 6355, 6356, 6357, 6358, 6359, 6360, 6361, 6362, 6363, 6364, 6365, 6366, 6367, 6368, 6369, 6370, 6371, 6372, 6373, 6374, 6375, 6376, 6377, 6378, 6379, 6380, 6381, 6382, 6383, 6384, 6385, 6386, 6387, 6388, 6389, 6390, 6391, 6392, 6393, 6394, 6395, 6396, 6397, 6398, 6399, 6400, 6401, 6402, 6403, 6404, 6405, 6406, 6407, 6408, 6409, 6410, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 1226, 346, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 0, 0, 0, 0, 0, 0, 0, 1226, 1226, 1226, 1226, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3224, 3224, 3223, 3224, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6411, 6411, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3224, 3224, 3224, 3224, 0, 3224, 3224, 3224, 3224, 3224, 3224, 3224, 0, 3224, 3224, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 0, 0, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 914, 1226, 641, 1120, 1536, 1536, 1536, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, 0, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 0, 0, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 6412, 6413, 914, 914, 914, 914, 914, 6414, 6415, 6416, 6417, 6418, 6419, 6420, 6421, 6422, 641, 641, 641, 914, 914, 914, 6423, 6424, 6425, 6426, 6427, 6428, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 628, 628, 628, 628, 628, 628, 628, 628, 914, 914, 615, 615, 615, 615, 615, 628, 628, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 615, 615, 615, 615, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 6429, 6430, 6431, 6432, 6433, 6434, 6435, 6436, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 615, 615, 615, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 1258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6437, 6438, 6439, 6440, 6441, 6442, 6443, 6444, 6445, 6446, 6447, 6448, 6449, 6450, 6451, 6452, 6453, 6454, 6455, 6456, 6457, 6458, 6459, 6460, 6461, 6462, 6463, 6464, 6465, 6466, 6467, 6468, 6469, 6470, 6471, 6472, 6473, 6474, 6475, 6476, 6477, 6478, 6479, 6480, 6481, 6482, 6483, 6484, 6485, 6486, 6487, 6488, 6489, 6490, 6491, 6492, 6493, 6494, 6495, 6496, 6497, 6498, 6499, 6500, 6501, 6502, 6503, 6504, 6505, 6506, 6507, 6508, 6509, 6510, 6511, 6512, 6513, 6514, 6515, 6516, 6517, 6518, 6519, 6520, 6521, 0, 6522, 6523, 6524, 6525, 6526, 6527, 6528, 6529, 6530, 6531, 6532, 6533, 6534, 6535, 6536, 6537, 6538, 6539, 6540, 6541, 6542, 6543, 6544, 6545, 6546, 6547, 6548, 6549, 6550, 6551, 6552, 6553, 6554, 6555, 6556, 6557, 6558, 6559, 6560, 6561, 6562, 6563, 6564, 6565, 6566, 6567, 6568, 6569, 6570, 6571, 6572, 6573, 6574, 6575, 6576, 6577, 6578, 6579, 6580, 6581, 6582, 6583, 6584, 6585, 6586, 6587, 6588, 6589, 6590, 6591, 6592, 0, 6593, 6594, 0, 0, 6595, 0, 0, 6596, 6597, 0, 0, 6598, 6599, 6600, 6601, 0, 6602, 6603, 6604, 6605, 6606, 6607, 6608, 6609, 6610, 6611, 6612, 6613, 0, 6614, 0, 6615, 6616, 6617, 6618, 6619, 6620, 6621, 0, 6622, 6623, 6624, 6625, 6626, 6627, 6628, 6629, 6630, 6631, 6632, 6633, 6634, 6635, 6636, 6637, 6638, 6639, 6640, 6641, 6642, 6643, 6644, 6645, 6646, 6647, 6648, 6649, 6650, 6651, 6652, 6653, 6654, 6655, 6656, 6657, 6658, 6659, 6660, 6661, 6662, 6663, 6664, 6665, 6666, 6667, 6668, 6669, 6670, 6671, 6672, 6673, 6674, 6675, 6676, 6677, 6678, 6679, 6680, 6681, 6682, 6683, 6684, 6685, 6686, 0, 6687, 6688, 6689, 6690, 0, 0, 6691, 6692, 6693, 6694, 6695, 6696, 6697, 6698, 0, 6699, 6700, 6701, 6702, 6703, 6704, 6705, 0, 6706, 6707, 6708, 6709, 6710, 6711, 6712, 6713, 6714, 6715, 6716, 6717, 6718, 6719, 6720, 6721, 6722, 6723, 6724, 6725, 6726, 6727, 6728, 6729, 6730, 6731, 6732, 6733, 0, 6734, 6735, 6736, 6737, 0, 6738, 6739, 6740, 6741, 6742, 0, 6743, 0, 0, 0, 6744, 6745, 6746, 6747, 6748, 6749, 6750, 0, 6751, 6752, 6753, 6754, 6755, 6756, 6757, 6758, 6759, 6760, 6761, 6762, 6763, 6764, 6765, 6766, 6767, 6768, 6769, 6770, 6771, 6772, 6773, 6774, 6775, 6776, 6777, 6778, 6779, 6780, 6781, 6782, 6783, 6784, 6785, 6786, 6787, 6788, 6789, 6790, 6791, 6792, 6793, 6794, 6795, 6796, 6797, 6798, 6799, 6800, 6801, 6802, 6803, 6804, 6805, 6806, 6807, 6808, 6809, 6810, 6811, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819, 6820, 6821, 6822, 6823, 6824, 6825, 6826, 6827, 6828, 6829, 6830, 6831, 6832, 6833, 6834, 6835, 6836, 6837, 6838, 6839, 6840, 6841, 6842, 6843, 6844, 6845, 6846, 6847, 6848, 6849, 6850, 6851, 6852, 6853, 6854, 6855, 6856, 6857, 6858, 6859, 6860, 6861, 6862, 6863, 6864, 6865, 6866, 6867, 6868, 6869, 6870, 6871, 6872, 6873, 6874, 6875, 6876, 6877, 6878, 6879, 6880, 6881, 6882, 6883, 6884, 6885, 6886, 6887, 6888, 6889, 6890, 6891, 6892, 6893, 6894, 6895, 6896, 6897, 6898, 6899, 6900, 6901, 6902, 6903, 6904, 6905, 6906, 6907, 6908, 6909, 6910, 6911, 6912, 6913, 6914, 6915, 6916, 6917, 6918, 6919, 6920, 6921, 6922, 6923, 6924, 6925, 6926, 6927, 6928, 6929, 6930, 6931, 6932, 6933, 6934, 6935, 6936, 6937, 6938, 6939, 6940, 6941, 6942, 6943, 6944, 6945, 6946, 6947, 6948, 6949, 6950, 6951, 6952, 6953, 6954, 6955, 6956, 6957, 6958, 6959, 6960, 6961, 6962, 6963, 6964, 6965, 6966, 6967, 6968, 6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978, 6979, 6980, 6981, 6982, 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, 6993, 6994, 6995, 6996, 6997, 6998, 6999, 7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, 7041, 7042, 7043, 7044, 7045, 7046, 7047, 7048, 7049, 7050, 7051, 7052, 7053, 7054, 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063, 7064, 7065, 7066, 7067, 7068, 7069, 7070, 7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, 7079, 7080, 7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, 7089, 7090, 0, 0, 7091, 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099, 7100, 7101, 7102, 7103, 7104, 7105, 7106, 7107, 7108, 7109, 7110, 7111, 7112, 7113, 7114, 7115, 7116, 7117, 7118, 7119, 7120, 7121, 7122, 7123, 7124, 7125, 7126, 7127, 7128, 7129, 7130, 7131, 7132, 7133, 7134, 7135, 7136, 7137, 7138, 7139, 7140, 7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, 7149, 7150, 7151, 7152, 7153, 7154, 7155, 7156, 7157, 7158, 7159, 7160, 7161, 7162, 7163, 7164, 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, 7173, 7116, 7174, 7175, 7176, 7177, 7178, 7179, 7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, 7188, 7189, 7190, 7191, 7192, 7193, 7194, 7195, 7196, 7197, 7198, 7142, 7199, 7200, 7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, 7209, 7210, 7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, 7220, 7221, 7222, 7223, 7224, 7225, 7226, 7227, 7228, 7229, 7116, 7230, 7231, 7232, 7233, 7234, 7235, 7236, 7237, 7238, 7239, 7240, 7241, 7242, 7243, 7244, 7245, 7246, 7247, 7248, 7249, 7250, 7251, 7252, 7253, 7254, 7142, 7255, 7256, 7257, 7258, 7259, 7260, 7261, 7262, 7263, 7264, 7265, 7266, 7267, 7268, 7269, 7270, 7271, 7272, 7273, 7274, 7275, 7276, 7277, 7278, 7279, 7280, 7281, 7282, 7283, 7284, 7285, 7116, 7286, 7287, 7288, 7289, 7290, 7291, 7292, 7293, 7294, 7295, 7296, 7297, 7298, 7299, 7300, 7301, 7302, 7303, 7304, 7305, 7306, 7307, 7308, 7309, 7310, 7142, 7311, 7312, 7313, 7314, 7315, 7316, 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327, 7328, 7329, 7330, 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7116, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, 7355, 7356, 7357, 7358, 7359, 7360, 7361, 7362, 7363, 7364, 7365, 7366, 7142, 7367, 7368, 7369, 7370, 7371, 7372, 7373, 7374, 0, 0, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 914, 914, 914, 914, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 914, 914, 914, 914, 914, 914, 914, 914, 1226, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 1226, 914, 914, 1120, 1120, 1120, 1120, 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 1226, 1226, 1226, 1226, 0, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7385, 7386, 7387, 7388, 7389, 7390, 7391, 7392, 7393, 7394, 346, 7395, 7396, 7397, 7398, 7399, 7400, 7401, 7402, 7403, 7404, 7405, 7406, 7407, 7408, 7409, 7410, 7411, 7412, 7413, 7414, 0, 0, 0, 0, 0, 0, 7415, 7416, 7417, 7418, 7419, 7420, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 615, 615, 615, 615, 615, 615, 615, 0, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 0, 0, 615, 615, 615, 615, 615, 615, 615, 0, 615, 615, 0, 615, 615, 615, 615, 615, 0, 0, 0, 0, 0, 7421, 7422, 7423, 7424, 7425, 7426, 7427, 7428, 7429, 7430, 7431, 7432, 7433, 7434, 7435, 7436, 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7446, 7447, 7448, 7449, 7450, 7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7461, 7462, 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, 7471, 7472, 7473, 7474, 7475, 7476, 7477, 7478, 7479, 7480, 7481, 7482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 0, 0, 615, 615, 615, 615, 615, 615, 615, 596, 596, 596, 596, 596, 596, 596, 0, 0, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 346, 914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 615, 615, 615, 615, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 596, 627, 627, 628, 615, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 346, 346, 346, 346, 346, 346, 0, 346, 346, 346, 346, 0, 346, 346, 0, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 346, 0, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 1183, 0, 0, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 6141, 628, 628, 628, 628, 628, 628, 628, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494, 7495, 7496, 7497, 7498, 7499, 7500, 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509, 7510, 7511, 7512, 7513, 7514, 7515, 7516, 7517, 7518, 7519, 7520, 7521, 7522, 7523, 7524, 7525, 7526, 7527, 7528, 7529, 7530, 7531, 7532, 7533, 7534, 7535, 7536, 7537, 7538, 7539, 7540, 7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, 7549, 7550, 615, 615, 615, 615, 615, 615, 1249, 1228, 0, 0, 0, 0, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 1227, 0, 0, 0, 0, 1180, 1180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 1223, 6246, 6246, 6246, 1186, 6246, 6246, 6246, 6246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 1223, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 6246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7551, 7552, 7553, 7554, 0, 7555, 7556, 7557, 7558, 7559, 7560, 7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 7569, 7570, 7571, 7572, 7573, 7574, 7575, 7576, 7577, 7578, 7579, 7580, 7581, 0, 7552, 7553, 0, 7582, 0, 0, 7557, 0, 7559, 7560, 7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 0, 7570, 7571, 7572, 7573, 0, 7575, 0, 7577, 0, 0, 0, 0, 0, 0, 7553, 0, 0, 0, 0, 7557, 0, 7559, 0, 7561, 0, 7563, 7564, 7565, 0, 7567, 7568, 0, 7570, 0, 0, 7573, 0, 7575, 0, 7577, 0, 7579, 0, 7581, 0, 7552, 7553, 0, 7582, 0, 0, 7557, 7558, 7559, 7560, 0, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 0, 7570, 7571, 7572, 7573, 0, 7575, 7576, 7577, 7578, 0, 7580, 0, 7551, 7552, 7553, 7554, 7582, 7555, 7556, 7557, 7558, 7559, 0, 7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 7569, 7570, 7571, 7572, 7573, 7574, 7575, 7576, 7577, 0, 0, 0, 0, 0, 7552, 7553, 7554, 0, 7555, 7556, 7557, 7558, 7559, 0, 7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 7569, 7570, 7571, 7572, 7573, 7574, 7575, 7576, 7577, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 0, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 0, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, 7593, 1287, 1287, 79, 79, 79, 7594, 7595, 7596, 7597, 7598, 7599, 7600, 7601, 7602, 7603, 7604, 7605, 7606, 7607, 7608, 7609, 7610, 7611, 7612, 7613, 7614, 7615, 7616, 7617, 7618, 7619, 7620, 7621, 7622, 7623, 7624, 79, 7625, 7626, 7627, 7628, 7629, 7630, 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, 7641, 7642, 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, 7651, 7652, 7653, 7654, 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7665, 7666, 7667, 7668, 7669, 7670, 7671, 7672, 7673, 7674, 7675, 7676, 7677, 7678, 7679, 7680, 7681, 7682, 7683, 7684, 7685, 79, 79, 79, 7686, 7687, 7688, 7689, 7690, 7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699, 7700, 7701, 7702, 7703, 7704, 7705, 7706, 7707, 7708, 7709, 7710, 7711, 914, 914, 914, 914, 7712, 914, 7713, 7712, 7712, 7712, 7712, 7712, 7712, 7712, 7712, 7712, 7712, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 914, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7714, 7715, 7716, 7717, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7718, 7719, 7720, 7721, 7722, 7723, 7724, 7725, 7726, 7727, 7728, 7729, 7730, 7731, 7732, 7733, 7734, 7735, 7736, 7737, 7738, 7739, 7740, 7741, 7742, 7743, 7744, 7745, 7746, 7747, 7748, 7749, 7750, 7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, 7760, 7761, 0, 0, 0, 0, 7762, 7763, 7764, 7765, 7766, 7767, 7768, 7769, 7770, 0, 0, 0, 0, 0, 0, 0, 7771, 7772, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 2577, 79, 79, 79, 2577, 2577, 2577, 7773, 7773, 7773, 7773, 7773, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 2577, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 77, 77, 77, 77, 77, 77, 77, 77, 79, 79, 79, 79, 79, 2577, 2577, 2577, 2577, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 79, 79, 2577, 79, 79, 79, 2577, 2577, 2577, 79, 79, 2577, 2577, 2577, 0, 0, 0, 0, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2577, 2577, 0, 0, 0, 79, 79, 79, 79, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 79, 79, 0, 0, 0, 0, 79, 79, 79, 79, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 0, 2577, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 79, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 77, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 77, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 0, 0, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 0, 0, 0, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 0, 0, 0, 0, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7774, 7775, 7776, 7777, 7778, 4647, 7779, 7780, 7781, 7782, 4648, 7783, 7784, 7785, 4649, 7786, 7787, 7788, 7789, 7790, 7791, 7792, 7793, 7794, 7795, 7796, 7797, 4707, 7798, 7799, 7800, 7801, 7802, 7803, 7804, 7805, 7806, 4712, 4650, 4651, 4713, 7807, 7808, 4458, 7809, 4652, 7810, 7811, 7812, 7813, 7813, 7813, 7814, 7815, 7816, 7817, 7818, 7819, 7820, 7821, 7822, 7823, 7824, 7825, 7826, 7827, 7828, 7829, 7830, 7831, 7831, 4715, 7832, 7833, 7834, 7835, 4654, 7836, 7837, 7838, 4611, 7839, 7840, 7841, 7842, 7843, 7844, 7845, 7846, 7847, 7848, 7849, 7850, 7851, 7852, 7853, 7854, 7855, 7856, 7857, 7858, 7859, 7860, 7861, 7862, 7863, 7864, 7864, 7865, 7866, 7867, 4454, 7868, 7869, 7870, 7871, 7872, 7873, 7874, 7875, 4659, 7876, 7877, 7878, 7879, 7880, 7881, 7882, 7883, 7884, 7885, 7886, 7887, 7888, 7889, 7890, 7891, 7892, 7893, 7894, 7895, 7896, 4400, 7897, 7898, 7899, 7899, 7900, 7901, 7901, 7902, 7903, 7904, 7905, 7906, 7907, 7908, 7909, 7910, 7911, 7912, 7913, 7914, 4660, 7915, 7916, 7917, 7918, 4727, 7918, 7919, 4662, 7920, 7921, 7922, 7923, 4663, 4373, 7924, 7925, 7926, 7927, 7928, 7929, 7930, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 7944, 7945, 4664, 7946, 7947, 7948, 7949, 7950, 7951, 4666, 7952, 7953, 7954, 7955, 7956, 7957, 7958, 7959, 4401, 4735, 7960, 7961, 7962, 7963, 7964, 7965, 7966, 7967, 4667, 7968, 7969, 7970, 7971, 4778, 7972, 7973, 7974, 7975, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 7984, 4471, 7985, 7986, 7987, 7988, 7989, 7990, 7991, 7992, 7993, 7994, 7995, 4668, 4558, 7996, 7997, 7998, 7999, 8000, 8001, 8002, 8003, 4739, 8004, 8005, 8006, 8007, 8008, 8009, 8010, 8011, 4740, 8012, 8013, 8014, 8015, 8016, 8017, 8018, 8019, 8020, 8021, 8022, 8023, 4742, 8024, 8025, 8026, 8027, 8028, 8029, 8030, 8031, 8032, 8033, 8034, 8034, 8035, 8036, 4744, 8037, 8038, 8039, 8040, 8041, 8042, 8043, 4457, 8044, 8045, 8046, 8047, 8048, 8049, 8050, 4750, 8051, 8052, 8053, 8054, 8055, 8056, 8056, 4751, 4780, 8057, 8058, 8059, 8060, 8061, 4419, 4753, 8062, 8063, 4679, 8064, 8065, 4633, 8066, 8067, 4683, 8068, 8069, 8070, 8071, 8071, 8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079, 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095, 8096, 8097, 8098, 4689, 8099, 8100, 8101, 8102, 8103, 8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111, 8112, 8113, 8114, 7900, 8115, 8116, 8117, 8118, 8119, 8120, 8121, 8122, 8123, 8124, 8125, 8126, 4475, 8127, 8128, 8129, 8130, 8131, 8132, 4692, 8133, 8134, 8135, 8136, 8137, 8138, 8139, 8140, 8141, 8142, 8143, 8144, 8145, 8146, 8147, 8148, 8149, 8150, 8151, 8152, 4414, 8153, 8154, 8155, 8156, 8157, 8158, 4760, 8159, 8160, 8161, 8162, 8163, 8164, 8165, 8166, 8167, 8168, 8169, 8170, 8171, 8172, 8173, 8174, 8175, 8176, 8177, 8178, 4765, 4766, 8179, 8180, 8181, 8182, 8183, 8184, 8185, 8186, 8187, 8188, 8189, 8190, 8191, 4767, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8203, 8204, 8205, 8206, 8207, 8208, 8209, 8210, 8211, 8212, 8213, 8214, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 4773, 4773, 8222, 8223, 8224, 8225, 8226, 8227, 8228, 8229, 8230, 8231, 4774, 8232, 8233, 8234, 8235, 8236, 8237, 8238, 8239, 8240, 8241, 8242, 8243, 8244, 8245, 8246, 8247, 8248, 8249, 8250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 2301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 4360, 0, 0, }; static const utf8proc_property_t utf8proc_properties[] = { {0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_S, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_B, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_LF}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_WS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_B, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CR}, {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_B, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5093, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5084, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5096, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 0, UINT16_MAX, 0, UINT16_MAX, 0, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1, UINT16_MAX, 1, UINT16_MAX, 2784, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2, UINT16_MAX, 2, UINT16_MAX, 49, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3, UINT16_MAX, 3, UINT16_MAX, 704, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 4, UINT16_MAX, 4, UINT16_MAX, 62, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5, UINT16_MAX, 5, UINT16_MAX, 2872, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6, UINT16_MAX, 6, UINT16_MAX, 782, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7, UINT16_MAX, 7, UINT16_MAX, 808, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 8, UINT16_MAX, 8, UINT16_MAX, 111, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 9, UINT16_MAX, 9, UINT16_MAX, 898, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 10, UINT16_MAX, 10, UINT16_MAX, 913, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 11, UINT16_MAX, 11, UINT16_MAX, 999, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 12, UINT16_MAX, 12, UINT16_MAX, 2890, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 13, UINT16_MAX, 13, UINT16_MAX, 160, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 14, UINT16_MAX, 14, UINT16_MAX, 205, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 15, UINT16_MAX, 15, UINT16_MAX, 2982, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 16, UINT16_MAX, 16, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 17, UINT16_MAX, 17, UINT16_MAX, 1087, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 18, UINT16_MAX, 18, UINT16_MAX, 1173, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 19, UINT16_MAX, 19, UINT16_MAX, 1257, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 20, UINT16_MAX, 20, UINT16_MAX, 254, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 21, UINT16_MAX, 21, UINT16_MAX, 3042, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 22, UINT16_MAX, 22, UINT16_MAX, 1337, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 23, UINT16_MAX, 23, UINT16_MAX, 3122, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 24, UINT16_MAX, 24, UINT16_MAX, 303, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 25, UINT16_MAX, 25, UINT16_MAX, 1423, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1491, UINT16_MAX, 1491, 352, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1493, UINT16_MAX, 1493, 2818, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2813, UINT16_MAX, 2813, 401, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1494, UINT16_MAX, 1494, 743, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1495, UINT16_MAX, 1495, 414, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2838, UINT16_MAX, 2838, 2875, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1497, UINT16_MAX, 1497, 795, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1498, UINT16_MAX, 1498, 853, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1499, UINT16_MAX, 1499, 463, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1500, UINT16_MAX, 1500, 901, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1501, UINT16_MAX, 1501, 956, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1502, UINT16_MAX, 1502, 1043, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1503, UINT16_MAX, 1503, 2932, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1504, UINT16_MAX, 1504, 512, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1505, UINT16_MAX, 1505, 557, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1507, UINT16_MAX, 1507, 2994, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2827, UINT16_MAX, 2827, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1508, UINT16_MAX, 1508, 1130, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 3320, UINT16_MAX, 3320, 1215, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1509, UINT16_MAX, 1509, 1296, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1510, UINT16_MAX, 1510, 606, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2910, UINT16_MAX, 2910, 3082, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1511, UINT16_MAX, 1511, 1380, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2928, UINT16_MAX, 2928, 3131, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 3327, UINT16_MAX, 3327, 655, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2835, UINT16_MAX, 2835, 1466, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_NOBREAK, 26, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 16411, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 1621, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 0, UINT16_MAX, 8289, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PI, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 1, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 16413, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ET, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ET, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 16417, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35, 35, 7440, UINT16_MAX, 7440, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 16420, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 14, UINT16_MAX, 8290, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PF, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 32807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 32810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 32813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16432, 50, UINT16_MAX, 50, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16435, 53, UINT16_MAX, 53, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16438, 56, UINT16_MAX, 56, UINT16_MAX, 3143, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16441, 59, UINT16_MAX, 59, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16444, 62, UINT16_MAX, 62, UINT16_MAX, 1537, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16447, 65, UINT16_MAX, 65, UINT16_MAX, 1579, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 66, UINT16_MAX, 66, UINT16_MAX, 1549, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16451, 69, UINT16_MAX, 69, UINT16_MAX, 2852, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16454, 72, UINT16_MAX, 72, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16457, 75, UINT16_MAX, 75, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16460, 78, UINT16_MAX, 78, UINT16_MAX, 3357, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16463, 81, UINT16_MAX, 81, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16466, 84, UINT16_MAX, 84, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16469, 87, UINT16_MAX, 87, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16472, 90, UINT16_MAX, 90, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16475, 93, UINT16_MAX, 93, UINT16_MAX, 2878, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 94, UINT16_MAX, 94, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16479, 97, UINT16_MAX, 97, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16482, 100, UINT16_MAX, 100, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16485, 103, UINT16_MAX, 103, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16488, 106, UINT16_MAX, 106, UINT16_MAX, 3461, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16491, 109, UINT16_MAX, 109, UINT16_MAX, 1597, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16494, 112, UINT16_MAX, 112, UINT16_MAX, 1591, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 113, UINT16_MAX, 113, UINT16_MAX, 1585, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16498, 116, UINT16_MAX, 116, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16501, 119, UINT16_MAX, 119, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16504, 122, UINT16_MAX, 122, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16507, 125, UINT16_MAX, 125, UINT16_MAX, 1509, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16510, 128, UINT16_MAX, 128, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 129, UINT16_MAX, 129, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 16514, 8291, UINT16_MAX, 8291, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16516, UINT16_MAX, 8292, UINT16_MAX, 8292, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16518, UINT16_MAX, 8293, UINT16_MAX, 8293, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16520, UINT16_MAX, 8294, UINT16_MAX, 8294, 3192, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16522, UINT16_MAX, 8295, UINT16_MAX, 8295, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16524, UINT16_MAX, 8296, UINT16_MAX, 8296, 1540, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16526, UINT16_MAX, 2837, UINT16_MAX, 2837, 1582, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1492, UINT16_MAX, 1492, 1558, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16528, UINT16_MAX, 8297, UINT16_MAX, 8297, 2855, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16530, UINT16_MAX, 8298, UINT16_MAX, 8298, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16532, UINT16_MAX, 8299, UINT16_MAX, 8299, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16534, UINT16_MAX, 8300, UINT16_MAX, 8300, 3406, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16536, UINT16_MAX, 8301, UINT16_MAX, 8301, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16538, UINT16_MAX, 8302, UINT16_MAX, 8302, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16540, UINT16_MAX, 8303, UINT16_MAX, 8303, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16542, UINT16_MAX, 8304, UINT16_MAX, 8304, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16544, UINT16_MAX, 8305, UINT16_MAX, 8305, 2881, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8306, UINT16_MAX, 8306, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16546, UINT16_MAX, 8307, UINT16_MAX, 8307, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16548, UINT16_MAX, 8308, UINT16_MAX, 8308, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16550, UINT16_MAX, 8309, UINT16_MAX, 8309, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16552, UINT16_MAX, 8310, UINT16_MAX, 8310, 3510, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16554, UINT16_MAX, 8311, UINT16_MAX, 8311, 1606, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16556, UINT16_MAX, 8312, UINT16_MAX, 8312, 1594, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8313, UINT16_MAX, 8313, 1588, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16558, UINT16_MAX, 8314, UINT16_MAX, 8314, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16560, UINT16_MAX, 8315, UINT16_MAX, 8315, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16562, UINT16_MAX, 8316, UINT16_MAX, 8316, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16564, UINT16_MAX, 8317, UINT16_MAX, 8317, 1523, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16566, UINT16_MAX, 8318, UINT16_MAX, 8318, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8319, UINT16_MAX, 8319, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16568, UINT16_MAX, 8320, UINT16_MAX, 8320, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16570, 188, UINT16_MAX, 188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16573, UINT16_MAX, 8321, UINT16_MAX, 8321, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16575, 193, UINT16_MAX, 193, UINT16_MAX, 3259, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16578, UINT16_MAX, 8322, UINT16_MAX, 8322, 3308, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16580, 198, UINT16_MAX, 198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16583, UINT16_MAX, 8323, UINT16_MAX, 8323, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16585, 203, UINT16_MAX, 203, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16588, UINT16_MAX, 8324, UINT16_MAX, 8324, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16590, 208, UINT16_MAX, 208, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16593, UINT16_MAX, 8325, UINT16_MAX, 8325, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16595, 213, UINT16_MAX, 213, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16598, UINT16_MAX, 8326, UINT16_MAX, 8326, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16600, 218, UINT16_MAX, 218, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16603, UINT16_MAX, 8327, UINT16_MAX, 8327, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16605, 223, UINT16_MAX, 223, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16608, UINT16_MAX, 8328, UINT16_MAX, 8328, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 226, UINT16_MAX, 226, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8329, UINT16_MAX, 8329, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16611, 229, UINT16_MAX, 229, UINT16_MAX, 2858, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16614, UINT16_MAX, 8330, UINT16_MAX, 8330, 2862, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16616, 234, UINT16_MAX, 234, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16619, UINT16_MAX, 8331, UINT16_MAX, 8331, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16621, 239, UINT16_MAX, 239, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16624, UINT16_MAX, 8332, UINT16_MAX, 8332, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16626, 244, UINT16_MAX, 244, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16629, UINT16_MAX, 8333, UINT16_MAX, 8333, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16631, 249, UINT16_MAX, 249, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16634, UINT16_MAX, 8334, UINT16_MAX, 8334, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16636, 254, UINT16_MAX, 254, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16639, UINT16_MAX, 8335, UINT16_MAX, 8335, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16641, 259, UINT16_MAX, 259, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16644, UINT16_MAX, 8336, UINT16_MAX, 8336, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16646, 264, UINT16_MAX, 264, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16649, UINT16_MAX, 8337, UINT16_MAX, 8337, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16651, 269, UINT16_MAX, 269, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16654, UINT16_MAX, 8338, UINT16_MAX, 8338, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16656, 274, UINT16_MAX, 274, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16659, UINT16_MAX, 8339, UINT16_MAX, 8339, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 277, UINT16_MAX, 277, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 5251, UINT16_MAX, 5251, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16662, 280, UINT16_MAX, 280, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16665, UINT16_MAX, 8340, UINT16_MAX, 8340, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16667, 285, UINT16_MAX, 285, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16670, UINT16_MAX, 8341, UINT16_MAX, 8341, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16672, 290, UINT16_MAX, 290, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16675, UINT16_MAX, 8342, UINT16_MAX, 8342, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16677, 295, UINT16_MAX, 295, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16680, UINT16_MAX, 8343, UINT16_MAX, 8343, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16682, 16684, UINT16_MAX, 8, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1499, UINT16_MAX, 1499, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16686, 304, UINT16_MAX, 304, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16689, UINT16_MAX, 8344, UINT16_MAX, 8344, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16691, 309, UINT16_MAX, 309, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16694, UINT16_MAX, 8345, UINT16_MAX, 8345, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16696, 314, UINT16_MAX, 314, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16699, UINT16_MAX, 8346, UINT16_MAX, 8346, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8347, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16701, 319, UINT16_MAX, 319, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16704, UINT16_MAX, 8348, UINT16_MAX, 8348, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16706, 324, UINT16_MAX, 324, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16709, UINT16_MAX, 8349, UINT16_MAX, 8349, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16711, 329, UINT16_MAX, 329, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16714, UINT16_MAX, 8350, UINT16_MAX, 8350, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16716, 334, UINT16_MAX, 334, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16719, UINT16_MAX, 8351, UINT16_MAX, 8351, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 337, UINT16_MAX, 337, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8352, UINT16_MAX, 8352, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16722, 340, UINT16_MAX, 340, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16725, UINT16_MAX, 8353, UINT16_MAX, 8353, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16727, 345, UINT16_MAX, 345, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16730, UINT16_MAX, 8354, UINT16_MAX, 8354, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16732, 350, UINT16_MAX, 350, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16735, UINT16_MAX, 8355, UINT16_MAX, 8355, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16737, 16737, 8356, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 355, UINT16_MAX, 355, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8357, UINT16_MAX, 8357, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16740, 358, UINT16_MAX, 358, UINT16_MAX, 2974, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16743, UINT16_MAX, 8358, UINT16_MAX, 8358, 2978, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16745, 363, UINT16_MAX, 363, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16748, UINT16_MAX, 8359, UINT16_MAX, 8359, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16750, 368, UINT16_MAX, 368, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16753, UINT16_MAX, 8360, UINT16_MAX, 8360, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 371, UINT16_MAX, 371, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8361, UINT16_MAX, 8361, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16756, 374, UINT16_MAX, 374, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16759, UINT16_MAX, 8362, UINT16_MAX, 8362, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16761, 379, UINT16_MAX, 379, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16764, UINT16_MAX, 8363, UINT16_MAX, 8363, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16766, 384, UINT16_MAX, 384, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16769, UINT16_MAX, 8364, UINT16_MAX, 8364, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16771, 389, UINT16_MAX, 389, UINT16_MAX, 3012, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16774, UINT16_MAX, 8365, UINT16_MAX, 8365, 3015, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16776, 394, UINT16_MAX, 394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16779, UINT16_MAX, 8366, UINT16_MAX, 8366, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16781, 399, UINT16_MAX, 399, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16784, UINT16_MAX, 8367, UINT16_MAX, 8367, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16786, 404, UINT16_MAX, 404, UINT16_MAX, 3018, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16789, UINT16_MAX, 8368, UINT16_MAX, 8368, 3021, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16791, 409, UINT16_MAX, 409, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16794, UINT16_MAX, 8369, UINT16_MAX, 8369, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16796, 414, UINT16_MAX, 414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16799, UINT16_MAX, 8370, UINT16_MAX, 8370, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 417, UINT16_MAX, 417, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8371, UINT16_MAX, 8371, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16802, 420, UINT16_MAX, 420, UINT16_MAX, 3030, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16805, UINT16_MAX, 8372, UINT16_MAX, 8372, 3033, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16807, 425, UINT16_MAX, 425, UINT16_MAX, 3036, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16810, UINT16_MAX, 8373, UINT16_MAX, 8373, 3039, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16812, 430, UINT16_MAX, 430, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16815, UINT16_MAX, 8374, UINT16_MAX, 8374, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16817, 435, UINT16_MAX, 435, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16820, UINT16_MAX, 8375, UINT16_MAX, 8375, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16822, 440, UINT16_MAX, 440, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16825, UINT16_MAX, 8376, UINT16_MAX, 8376, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16827, 445, UINT16_MAX, 445, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16830, UINT16_MAX, 8377, UINT16_MAX, 8377, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16832, 450, UINT16_MAX, 450, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16835, UINT16_MAX, 8378, UINT16_MAX, 8378, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16837, 455, UINT16_MAX, 455, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16840, UINT16_MAX, 8379, UINT16_MAX, 8379, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16842, 460, UINT16_MAX, 460, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16845, 463, UINT16_MAX, 463, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16848, UINT16_MAX, 8380, UINT16_MAX, 8380, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16850, 468, UINT16_MAX, 468, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16853, UINT16_MAX, 8381, UINT16_MAX, 8381, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16855, 473, UINT16_MAX, 473, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16858, UINT16_MAX, 8382, UINT16_MAX, 8382, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 18, 18, 3320, UINT16_MAX, 3320, 3140, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8383, UINT16_MAX, 8383, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 476, UINT16_MAX, 476, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 477, UINT16_MAX, 477, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8384, UINT16_MAX, 8384, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 478, UINT16_MAX, 478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8385, UINT16_MAX, 8385, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 479, UINT16_MAX, 479, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 480, UINT16_MAX, 480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8386, UINT16_MAX, 8386, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 481, UINT16_MAX, 481, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 482, UINT16_MAX, 482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 483, UINT16_MAX, 483, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8387, UINT16_MAX, 8387, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8388, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 484, UINT16_MAX, 484, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 485, UINT16_MAX, 485, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 486, UINT16_MAX, 486, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 487, UINT16_MAX, 487, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8389, UINT16_MAX, 8389, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 488, UINT16_MAX, 488, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 489, UINT16_MAX, 489, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8390, UINT16_MAX, 8390, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 490, UINT16_MAX, 490, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 491, UINT16_MAX, 491, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 492, UINT16_MAX, 492, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8391, UINT16_MAX, 8391, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8392, UINT16_MAX, 8392, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8393, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 493, UINT16_MAX, 493, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 494, UINT16_MAX, 494, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8394, UINT16_MAX, 8394, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 495, UINT16_MAX, 495, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16880, 498, UINT16_MAX, 498, UINT16_MAX, 3565, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16883, UINT16_MAX, 8395, UINT16_MAX, 8395, 3614, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 501, UINT16_MAX, 501, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8396, UINT16_MAX, 8396, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 502, UINT16_MAX, 502, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8397, UINT16_MAX, 8397, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 503, UINT16_MAX, 503, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 504, UINT16_MAX, 504, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8398, UINT16_MAX, 8398, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 505, UINT16_MAX, 505, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8399, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1537, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 506, UINT16_MAX, 506, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8400, UINT16_MAX, 8400, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 507, UINT16_MAX, 507, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16892, 510, UINT16_MAX, 510, UINT16_MAX, 3663, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16895, UINT16_MAX, 8401, UINT16_MAX, 8401, 3712, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 513, UINT16_MAX, 513, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 514, UINT16_MAX, 514, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 515, UINT16_MAX, 515, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8402, UINT16_MAX, 8402, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 516, UINT16_MAX, 516, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8403, UINT16_MAX, 8403, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 517, UINT16_MAX, 517, UINT16_MAX, 1573, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 518, UINT16_MAX, 518, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8404, UINT16_MAX, 8404, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8405, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 519, UINT16_MAX, 519, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8406, UINT16_MAX, 8406, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8407, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8408, UINT16_MAX, 8408, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16904, 522, UINT16_MAX, 522, 8409, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16907, 522, 8410, 522, 8409, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16909, UINT16_MAX, 8410, UINT16_MAX, 8409, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16911, 529, UINT16_MAX, 529, 8411, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16914, 529, 8412, 529, 8411, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16916, UINT16_MAX, 8412, UINT16_MAX, 8411, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16918, 536, UINT16_MAX, 536, 8413, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16921, 536, 8414, 536, 8413, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 16923, UINT16_MAX, 8414, UINT16_MAX, 8413, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16925, 543, UINT16_MAX, 543, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16928, UINT16_MAX, 8415, UINT16_MAX, 8415, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16930, 548, UINT16_MAX, 548, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16933, UINT16_MAX, 8416, UINT16_MAX, 8416, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16935, 553, UINT16_MAX, 553, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16938, UINT16_MAX, 8417, UINT16_MAX, 8417, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16940, 558, UINT16_MAX, 558, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16943, UINT16_MAX, 8418, UINT16_MAX, 8418, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16945, 563, UINT16_MAX, 563, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16948, UINT16_MAX, 8419, UINT16_MAX, 8419, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16950, 568, UINT16_MAX, 568, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16953, UINT16_MAX, 8420, UINT16_MAX, 8420, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16955, 573, UINT16_MAX, 573, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16958, UINT16_MAX, 8421, UINT16_MAX, 8421, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16960, 578, UINT16_MAX, 578, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16963, UINT16_MAX, 8422, UINT16_MAX, 8422, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1496, UINT16_MAX, 1496, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16965, 583, UINT16_MAX, 583, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16968, UINT16_MAX, 8423, UINT16_MAX, 8423, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16970, 588, UINT16_MAX, 588, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16973, UINT16_MAX, 8424, UINT16_MAX, 8424, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16975, 593, UINT16_MAX, 593, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16978, UINT16_MAX, 8425, UINT16_MAX, 8425, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 596, UINT16_MAX, 596, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8426, UINT16_MAX, 8426, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16981, 599, UINT16_MAX, 599, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16984, UINT16_MAX, 8427, UINT16_MAX, 8427, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16986, 604, UINT16_MAX, 604, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16989, UINT16_MAX, 8428, UINT16_MAX, 8428, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16991, 609, UINT16_MAX, 609, UINT16_MAX, 1567, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16994, UINT16_MAX, 8429, UINT16_MAX, 8429, 1570, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 16996, 614, UINT16_MAX, 614, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 16999, UINT16_MAX, 8430, UINT16_MAX, 8430, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17001, 619, UINT16_MAX, 619, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17004, UINT16_MAX, 8431, UINT16_MAX, 8431, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17006, 17006, 8432, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17008, 626, UINT16_MAX, 626, 8433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17011, 626, 8434, 626, 8433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17013, UINT16_MAX, 8434, UINT16_MAX, 8433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17015, 633, UINT16_MAX, 633, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17018, UINT16_MAX, 8435, UINT16_MAX, 8435, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 636, UINT16_MAX, 636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 637, UINT16_MAX, 637, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17022, 640, UINT16_MAX, 640, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17025, UINT16_MAX, 8436, UINT16_MAX, 8436, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17027, 645, UINT16_MAX, 645, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17030, UINT16_MAX, 8437, UINT16_MAX, 8437, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17032, 650, UINT16_MAX, 650, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17035, UINT16_MAX, 8438, UINT16_MAX, 8438, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17037, 655, UINT16_MAX, 655, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17040, UINT16_MAX, 8439, UINT16_MAX, 8439, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17042, 660, UINT16_MAX, 660, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17045, UINT16_MAX, 8440, UINT16_MAX, 8440, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17047, 665, UINT16_MAX, 665, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17050, UINT16_MAX, 8441, UINT16_MAX, 8441, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17052, 670, UINT16_MAX, 670, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17055, UINT16_MAX, 8442, UINT16_MAX, 8442, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17057, 675, UINT16_MAX, 675, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17060, UINT16_MAX, 8443, UINT16_MAX, 8443, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17062, 680, UINT16_MAX, 680, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17065, UINT16_MAX, 8444, UINT16_MAX, 8444, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17067, 685, UINT16_MAX, 685, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17070, UINT16_MAX, 8445, UINT16_MAX, 8445, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17072, 690, UINT16_MAX, 690, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17075, UINT16_MAX, 8446, UINT16_MAX, 8446, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17077, 695, UINT16_MAX, 695, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17080, UINT16_MAX, 8447, UINT16_MAX, 8447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17082, 700, UINT16_MAX, 700, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17085, UINT16_MAX, 8448, UINT16_MAX, 8448, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17087, 705, UINT16_MAX, 705, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17090, UINT16_MAX, 8449, UINT16_MAX, 8449, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17092, 710, UINT16_MAX, 710, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17095, UINT16_MAX, 8450, UINT16_MAX, 8450, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17097, 715, UINT16_MAX, 715, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17100, UINT16_MAX, 8451, UINT16_MAX, 8451, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17102, 720, UINT16_MAX, 720, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17105, UINT16_MAX, 8452, UINT16_MAX, 8452, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17107, 725, UINT16_MAX, 725, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17110, UINT16_MAX, 8453, UINT16_MAX, 8453, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 728, UINT16_MAX, 728, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8454, UINT16_MAX, 8454, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17113, 731, UINT16_MAX, 731, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17116, UINT16_MAX, 8455, UINT16_MAX, 8455, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 734, UINT16_MAX, 734, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8456, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 735, UINT16_MAX, 735, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1506, UINT16_MAX, 1506, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 736, UINT16_MAX, 736, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8457, UINT16_MAX, 8457, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17121, 739, UINT16_MAX, 739, UINT16_MAX, 1543, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17124, UINT16_MAX, 8458, UINT16_MAX, 8458, 1546, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17126, 744, UINT16_MAX, 744, UINT16_MAX, 2866, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17129, UINT16_MAX, 8459, UINT16_MAX, 8459, 2869, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17131, 749, UINT16_MAX, 749, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17134, UINT16_MAX, 8460, UINT16_MAX, 8460, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17136, 754, UINT16_MAX, 754, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17139, UINT16_MAX, 8461, UINT16_MAX, 8461, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17141, 759, UINT16_MAX, 759, UINT16_MAX, 1615, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17144, UINT16_MAX, 8462, UINT16_MAX, 8462, 1618, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17146, 764, UINT16_MAX, 764, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17149, UINT16_MAX, 8463, UINT16_MAX, 8463, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17151, 769, UINT16_MAX, 769, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17154, UINT16_MAX, 8464, UINT16_MAX, 8464, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8465, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8466, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8467, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7430, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8468, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8469, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 772, UINT16_MAX, 772, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 773, UINT16_MAX, 773, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8470, UINT16_MAX, 8470, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 774, UINT16_MAX, 774, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 775, UINT16_MAX, 775, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8471, UINT16_MAX, 8471, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8472, UINT16_MAX, 8472, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 776, UINT16_MAX, 776, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8473, UINT16_MAX, 8473, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 777, UINT16_MAX, 777, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 778, UINT16_MAX, 778, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 779, UINT16_MAX, 779, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 780, UINT16_MAX, 780, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8474, UINT16_MAX, 8474, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 781, UINT16_MAX, 781, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8475, UINT16_MAX, 8475, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 782, UINT16_MAX, 782, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8476, UINT16_MAX, 8476, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 783, UINT16_MAX, 783, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8477, UINT16_MAX, 8477, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 784, UINT16_MAX, 784, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8478, UINT16_MAX, 8478, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8479, UINT16_MAX, 8479, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8480, UINT16_MAX, 8480, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8481, UINT16_MAX, 8481, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8482, UINT16_MAX, 8482, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8483, UINT16_MAX, 8483, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1521, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8484, UINT16_MAX, 8484, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8485, UINT16_MAX, 8485, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7053, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8486, UINT16_MAX, 8486, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8487, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2822, UINT16_MAX, 2822, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8488, UINT16_MAX, 8488, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8489, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7054, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1522, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8490, UINT16_MAX, 8490, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8491, UINT16_MAX, 8491, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7057, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8492, UINT16_MAX, 8492, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7056, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8493, UINT16_MAX, 8493, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8494, UINT16_MAX, 8494, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7060, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8495, UINT16_MAX, 8495, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8496, UINT16_MAX, 8496, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8497, UINT16_MAX, 8497, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8498, UINT16_MAX, 8498, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8499, UINT16_MAX, 8499, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1528, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7067, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8500, UINT16_MAX, 8500, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1532, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8501, UINT16_MAX, 8501, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8502, UINT16_MAX, 8502, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1533, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1534, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8503, UINT16_MAX, 8503, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7073, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7074, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1535, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 786, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7075, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 787, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8504, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8505, UINT16_MAX, 8505, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7078, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8506, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8507, UINT16_MAX, 8507, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 788, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8508, UINT16_MAX, 8508, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8509, UINT16_MAX, 8509, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7061, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8510, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8511, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8512, UINT16_MAX, 8512, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8513, UINT16_MAX, 8513, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8514, UINT16_MAX, 8514, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8515, UINT16_MAX, 8515, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8516, UINT16_MAX, 8516, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8517, UINT16_MAX, 8517, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 5254, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7070, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7084, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1539, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1540, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8518, UINT16_MAX, 8518, 1576, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8519, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 801, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8520, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8521, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7087, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7047, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8522, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7058, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7059, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8523, UINT16_MAX, 8523, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8524, UINT16_MAX, 8524, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1530, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8525, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7085, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7086, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7048, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7051, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7050, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7080, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7082, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7079, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7055, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7062, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7063, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8526, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8527, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8528, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8529, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7, UINT16_MAX, 8530, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 785, UINT16_MAX, 8531, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 9, UINT16_MAX, 8532, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 17, UINT16_MAX, 8533, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 786, UINT16_MAX, 8534, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 787, UINT16_MAX, 8535, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 788, UINT16_MAX, 8536, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 22, UINT16_MAX, 8537, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 24, UINT16_MAX, 8538, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8539, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8540, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17173, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17175, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 17183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 489, UINT16_MAX, 8541, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 11, UINT16_MAX, 8542, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 18, UINT16_MAX, 8543, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 23, UINT16_MAX, 8544, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 801, UINT16_MAX, 8545, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32768, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32769, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32770, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32771, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32775, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32776, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32778, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32772, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32814, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32773, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32780, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32779, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32782, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32783, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32815, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32816, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 232, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32781, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32808, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32813, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32807, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32784, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32774, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32777, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32810, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32812, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32811, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32809, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 1, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 1, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32819, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, 802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, 803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32817, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, 804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, 17189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 240, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, 807, 7437, UINT16_MAX, 7437, 32818, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 233, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 234, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 808, UINT16_MAX, 808, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8546, UINT16_MAX, 8546, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 809, UINT16_MAX, 809, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8547, UINT16_MAX, 8547, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 811, UINT16_MAX, 811, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8548, UINT16_MAX, 8548, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17196, UINT16_MAX, 8549, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8550, UINT16_MAX, 8550, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8551, UINT16_MAX, 8551, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8552, UINT16_MAX, 8552, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, 814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 815, UINT16_MAX, 815, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 17200, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17202, 820, UINT16_MAX, 820, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, 821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17206, 824, UINT16_MAX, 824, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17209, 827, UINT16_MAX, 827, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17212, 830, UINT16_MAX, 830, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17215, 833, UINT16_MAX, 833, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17218, 836, UINT16_MAX, 836, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17221, 839, UINT16_MAX, 839, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17224, 33610, 2659, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 845, UINT16_MAX, 845, UINT16_MAX, 1673, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 846, UINT16_MAX, 846, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 847, UINT16_MAX, 847, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 848, UINT16_MAX, 848, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 849, UINT16_MAX, 849, UINT16_MAX, 1726, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 850, UINT16_MAX, 850, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 851, UINT16_MAX, 851, UINT16_MAX, 1777, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 852, UINT16_MAX, 852, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 807, UINT16_MAX, 807, UINT16_MAX, 1830, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 853, UINT16_MAX, 853, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 854, UINT16_MAX, 854, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 35, UINT16_MAX, 35, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 855, UINT16_MAX, 855, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 856, UINT16_MAX, 856, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 857, UINT16_MAX, 857, UINT16_MAX, 1881, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 858, UINT16_MAX, 858, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 859, UINT16_MAX, 859, UINT16_MAX, 5027, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 860, UINT16_MAX, 860, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 861, UINT16_MAX, 861, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 862, UINT16_MAX, 862, UINT16_MAX, 1932, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 863, UINT16_MAX, 863, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 864, UINT16_MAX, 864, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 865, UINT16_MAX, 865, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 866, UINT16_MAX, 866, UINT16_MAX, 1983, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17251, 869, UINT16_MAX, 869, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17254, 872, UINT16_MAX, 872, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17257, UINT16_MAX, 2603, UINT16_MAX, 2603, 4904, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17259, UINT16_MAX, 2635, UINT16_MAX, 2635, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17261, UINT16_MAX, 2640, UINT16_MAX, 2640, 4913, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17263, UINT16_MAX, 2676, UINT16_MAX, 2676, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17265, 33651, 2693, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7431, UINT16_MAX, 7431, 2088, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7432, UINT16_MAX, 7432, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2847, UINT16_MAX, 2847, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7433, UINT16_MAX, 7433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7434, UINT16_MAX, 7434, 2141, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7435, UINT16_MAX, 7435, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7436, UINT16_MAX, 7436, 2192, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 915, UINT16_MAX, 915, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7437, UINT16_MAX, 7437, 2245, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7438, UINT16_MAX, 7438, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7439, UINT16_MAX, 7439, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7440, UINT16_MAX, 7440, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7441, UINT16_MAX, 7441, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7442, UINT16_MAX, 7442, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7443, UINT16_MAX, 7443, 2401, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2848, UINT16_MAX, 2848, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7444, UINT16_MAX, 7444, 5023, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 860, 917, UINT16_MAX, 917, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 917, UINT16_MAX, 917, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7446, UINT16_MAX, 7446, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 897, UINT16_MAX, 897, 2349, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7447, UINT16_MAX, 7447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7448, UINT16_MAX, 7448, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7449, UINT16_MAX, 7449, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 2836, UINT16_MAX, 2836, 2452, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17270, UINT16_MAX, 8553, UINT16_MAX, 8553, 2036, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17272, UINT16_MAX, 8554, UINT16_MAX, 8554, 2297, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17274, UINT16_MAX, 2745, UINT16_MAX, 2745, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17276, UINT16_MAX, 2714, UINT16_MAX, 2714, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17278, UINT16_MAX, 2750, UINT16_MAX, 2750, 5033, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 896, UINT16_MAX, 896, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 846, 846, 7432, UINT16_MAX, 7432, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 852, 852, 915, UINT16_MAX, 915, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 897, UINT16_MAX, UINT16_MAX, 8555, UINT16_MAX, 2505, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17282, UINT16_MAX, UINT16_MAX, 8556, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17284, UINT16_MAX, UINT16_MAX, 8557, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 863, 863, 7447, UINT16_MAX, 7447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 858, 858, 2848, UINT16_MAX, 2848, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8558, UINT16_MAX, 8558, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 902, UINT16_MAX, 902, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8559, UINT16_MAX, 8559, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 903, UINT16_MAX, 903, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8560, UINT16_MAX, 8560, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 904, UINT16_MAX, 904, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7458, UINT16_MAX, 7458, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 905, UINT16_MAX, 905, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8561, UINT16_MAX, 8561, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 906, UINT16_MAX, 906, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8562, UINT16_MAX, 8562, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 907, UINT16_MAX, 907, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8563, UINT16_MAX, 8563, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 908, UINT16_MAX, 908, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8564, UINT16_MAX, 8564, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 909, UINT16_MAX, 909, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8565, UINT16_MAX, 8565, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 910, UINT16_MAX, 910, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8566, UINT16_MAX, 8566, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 911, UINT16_MAX, 911, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8567, UINT16_MAX, 8567, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 912, UINT16_MAX, 912, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8568, UINT16_MAX, 8568, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 913, UINT16_MAX, 913, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8569, UINT16_MAX, 8569, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 853, 853, 7438, UINT16_MAX, 7438, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 859, 859, 7444, UINT16_MAX, 7444, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 914, UINT16_MAX, 8570, UINT16_MAX, 8570, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8571, UINT16_MAX, 8571, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 915, 852, UINT16_MAX, 852, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 849, 849, 7434, UINT16_MAX, 7434, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 916, UINT16_MAX, 916, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8572, UINT16_MAX, 8572, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 917, 918, UINT16_MAX, 918, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 919, UINT16_MAX, 919, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8573, UINT16_MAX, 8573, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8574, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 920, UINT16_MAX, 920, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 921, UINT16_MAX, 921, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 922, UINT16_MAX, 922, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17307, 925, UINT16_MAX, 925, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17310, 928, UINT16_MAX, 928, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 929, UINT16_MAX, 929, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17314, 932, UINT16_MAX, 932, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 933, UINT16_MAX, 933, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 934, UINT16_MAX, 934, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 935, UINT16_MAX, 935, UINT16_MAX, 2525, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17320, 938, UINT16_MAX, 938, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 939, UINT16_MAX, 939, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 940, UINT16_MAX, 940, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 941, UINT16_MAX, 941, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 942, UINT16_MAX, 942, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17327, 945, UINT16_MAX, 945, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17330, 948, UINT16_MAX, 948, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17333, 951, UINT16_MAX, 951, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 952, UINT16_MAX, 952, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 953, UINT16_MAX, 953, UINT16_MAX, 2615, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 954, UINT16_MAX, 954, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 955, UINT16_MAX, 955, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 956, UINT16_MAX, 956, UINT16_MAX, 2522, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 957, UINT16_MAX, 957, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 958, UINT16_MAX, 958, UINT16_MAX, 2511, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 959, UINT16_MAX, 959, UINT16_MAX, 2601, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 960, UINT16_MAX, 960, UINT16_MAX, 2635, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 961, UINT16_MAX, 961, UINT16_MAX, 2531, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17346, 964, UINT16_MAX, 964, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 965, UINT16_MAX, 965, UINT16_MAX, 2528, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 966, UINT16_MAX, 966, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 967, UINT16_MAX, 967, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 968, UINT16_MAX, 968, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 969, UINT16_MAX, 969, UINT16_MAX, 2641, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 970, UINT16_MAX, 970, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 971, UINT16_MAX, 971, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 972, UINT16_MAX, 972, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 973, UINT16_MAX, 973, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 974, UINT16_MAX, 974, UINT16_MAX, 2542, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 975, UINT16_MAX, 975, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 976, UINT16_MAX, 976, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 977, UINT16_MAX, 977, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 978, UINT16_MAX, 978, UINT16_MAX, 2659, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 979, UINT16_MAX, 979, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 980, UINT16_MAX, 980, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 981, UINT16_MAX, 981, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 982, UINT16_MAX, 982, UINT16_MAX, 2665, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 983, UINT16_MAX, 983, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 984, UINT16_MAX, 984, UINT16_MAX, 2653, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 985, UINT16_MAX, 985, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 986, UINT16_MAX, 986, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8575, UINT16_MAX, 8575, 2622, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8576, UINT16_MAX, 8576, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8577, UINT16_MAX, 8577, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8578, UINT16_MAX, 8578, 2575, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8579, UINT16_MAX, 8579, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8580, UINT16_MAX, 8580, 2564, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8581, UINT16_MAX, 8581, 2608, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8582, UINT16_MAX, 8582, 2638, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8583, UINT16_MAX, 8583, 2553, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17371, UINT16_MAX, 8584, UINT16_MAX, 8584, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8585, UINT16_MAX, 8585, 2581, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8586, UINT16_MAX, 8586, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8587, UINT16_MAX, 8587, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8588, UINT16_MAX, 8588, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8589, UINT16_MAX, 8589, 2644, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8590, UINT16_MAX, 8590, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8591, UINT16_MAX, 8591, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8592, UINT16_MAX, 8592, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8593, UINT16_MAX, 8593, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8594, UINT16_MAX, 8594, 2584, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8595, UINT16_MAX, 8595, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8596, UINT16_MAX, 8596, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8597, UINT16_MAX, 8597, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8598, UINT16_MAX, 8598, 2662, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8599, UINT16_MAX, 8599, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8600, UINT16_MAX, 8600, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8601, UINT16_MAX, 8601, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8602, UINT16_MAX, 8602, 2668, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8603, UINT16_MAX, 8603, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8604, UINT16_MAX, 8604, 2656, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8605, UINT16_MAX, 8605, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8606, UINT16_MAX, 8606, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17373, UINT16_MAX, 8607, UINT16_MAX, 8607, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17375, UINT16_MAX, 8608, UINT16_MAX, 8608, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8609, UINT16_MAX, 8609, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17377, UINT16_MAX, 8610, UINT16_MAX, 8610, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8611, UINT16_MAX, 8611, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8612, UINT16_MAX, 8612, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8613, UINT16_MAX, 8613, 2578, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17379, UINT16_MAX, 8614, UINT16_MAX, 8614, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8615, UINT16_MAX, 8615, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8616, UINT16_MAX, 8616, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8617, UINT16_MAX, 8617, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8618, UINT16_MAX, 8618, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17381, UINT16_MAX, 8619, UINT16_MAX, 8619, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17383, UINT16_MAX, 8620, UINT16_MAX, 8620, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17385, UINT16_MAX, 8621, UINT16_MAX, 8621, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8622, UINT16_MAX, 8622, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1003, UINT16_MAX, 1003, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8623, UINT16_MAX, 8623, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1004, UINT16_MAX, 1004, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8624, UINT16_MAX, 8624, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1005, UINT16_MAX, 1005, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8625, UINT16_MAX, 8625, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1006, UINT16_MAX, 1006, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8626, UINT16_MAX, 8626, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1007, UINT16_MAX, 1007, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8627, UINT16_MAX, 8627, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1008, UINT16_MAX, 1008, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8628, UINT16_MAX, 8628, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1009, UINT16_MAX, 1009, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8629, UINT16_MAX, 8629, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1010, UINT16_MAX, 1010, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8630, UINT16_MAX, 8630, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1011, UINT16_MAX, 1011, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8631, UINT16_MAX, 8631, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1012, UINT16_MAX, 1012, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8632, UINT16_MAX, 8632, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1013, UINT16_MAX, 1013, UINT16_MAX, 2595, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8633, UINT16_MAX, 8633, 2598, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17398, 1016, UINT16_MAX, 1016, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17401, UINT16_MAX, 8634, UINT16_MAX, 8634, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1019, UINT16_MAX, 1019, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8635, UINT16_MAX, 8635, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1020, UINT16_MAX, 1020, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8636, UINT16_MAX, 8636, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1021, UINT16_MAX, 1021, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8637, UINT16_MAX, 8637, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1022, UINT16_MAX, 1022, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8638, UINT16_MAX, 8638, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1023, UINT16_MAX, 1023, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8639, UINT16_MAX, 8639, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ME, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1024, UINT16_MAX, 1024, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8640, UINT16_MAX, 8640, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1025, UINT16_MAX, 1025, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8641, UINT16_MAX, 8641, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1026, UINT16_MAX, 1026, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8642, UINT16_MAX, 8642, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1027, UINT16_MAX, 1027, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8643, UINT16_MAX, 8643, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1028, UINT16_MAX, 1028, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8644, UINT16_MAX, 8644, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1029, UINT16_MAX, 1029, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8645, UINT16_MAX, 8645, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1030, UINT16_MAX, 1030, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8646, UINT16_MAX, 8646, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1031, UINT16_MAX, 1031, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8647, UINT16_MAX, 8647, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1032, UINT16_MAX, 1032, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8648, UINT16_MAX, 8648, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1033, UINT16_MAX, 1033, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8649, UINT16_MAX, 8649, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1034, UINT16_MAX, 1034, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8650, UINT16_MAX, 8650, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1035, UINT16_MAX, 1035, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8651, UINT16_MAX, 8651, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1036, UINT16_MAX, 1036, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8652, UINT16_MAX, 8652, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1037, UINT16_MAX, 1037, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8653, UINT16_MAX, 8653, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1038, UINT16_MAX, 1038, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8654, UINT16_MAX, 8654, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1039, UINT16_MAX, 1039, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8655, UINT16_MAX, 8655, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1040, UINT16_MAX, 1040, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8656, UINT16_MAX, 8656, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1041, UINT16_MAX, 1041, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8657, UINT16_MAX, 8657, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1042, UINT16_MAX, 1042, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8658, UINT16_MAX, 8658, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1043, UINT16_MAX, 1043, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8659, UINT16_MAX, 8659, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1044, UINT16_MAX, 1044, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8660, UINT16_MAX, 8660, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1045, UINT16_MAX, 1045, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8661, UINT16_MAX, 8661, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1046, UINT16_MAX, 1046, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8662, UINT16_MAX, 8662, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1047, UINT16_MAX, 1047, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8663, UINT16_MAX, 8663, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1048, UINT16_MAX, 1048, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8664, UINT16_MAX, 8664, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1049, UINT16_MAX, 1049, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8665, UINT16_MAX, 8665, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1050, UINT16_MAX, 1050, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8666, UINT16_MAX, 8666, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1051, UINT16_MAX, 1051, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17436, 1054, UINT16_MAX, 1054, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17439, UINT16_MAX, 8667, UINT16_MAX, 8667, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1057, UINT16_MAX, 1057, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8668, UINT16_MAX, 8668, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1058, UINT16_MAX, 1058, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8669, UINT16_MAX, 8669, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1059, UINT16_MAX, 1059, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8670, UINT16_MAX, 8670, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1060, UINT16_MAX, 1060, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8671, UINT16_MAX, 8671, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1061, UINT16_MAX, 1061, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8672, UINT16_MAX, 8672, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1062, UINT16_MAX, 1062, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8673, UINT16_MAX, 8673, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8674, UINT16_MAX, 8674, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17447, 1065, UINT16_MAX, 1065, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17450, UINT16_MAX, 8675, UINT16_MAX, 8675, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17452, 1070, UINT16_MAX, 1070, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17455, UINT16_MAX, 8676, UINT16_MAX, 8676, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1073, UINT16_MAX, 1073, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8677, UINT16_MAX, 8677, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17458, 1076, UINT16_MAX, 1076, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17461, UINT16_MAX, 8678, UINT16_MAX, 8678, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1079, UINT16_MAX, 1079, UINT16_MAX, 2629, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8679, UINT16_MAX, 8679, 2632, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17464, 1082, UINT16_MAX, 1082, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17467, UINT16_MAX, 8680, UINT16_MAX, 8680, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17469, 1087, UINT16_MAX, 1087, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17472, UINT16_MAX, 8681, UINT16_MAX, 8681, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17474, 1092, UINT16_MAX, 1092, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17477, UINT16_MAX, 8682, UINT16_MAX, 8682, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1095, UINT16_MAX, 1095, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8683, UINT16_MAX, 8683, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17480, 1098, UINT16_MAX, 1098, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17483, UINT16_MAX, 8684, UINT16_MAX, 8684, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17485, 1103, UINT16_MAX, 1103, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17488, UINT16_MAX, 8685, UINT16_MAX, 8685, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17490, 1108, UINT16_MAX, 1108, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17493, UINT16_MAX, 8686, UINT16_MAX, 8686, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1111, UINT16_MAX, 1111, UINT16_MAX, 2647, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8687, UINT16_MAX, 8687, 2650, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17496, 1114, UINT16_MAX, 1114, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17499, UINT16_MAX, 8688, UINT16_MAX, 8688, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17501, 1119, UINT16_MAX, 1119, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17504, UINT16_MAX, 8689, UINT16_MAX, 8689, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17506, 1124, UINT16_MAX, 1124, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17509, UINT16_MAX, 8690, UINT16_MAX, 8690, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17511, 1129, UINT16_MAX, 1129, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17514, UINT16_MAX, 8691, UINT16_MAX, 8691, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17516, 1134, UINT16_MAX, 1134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17519, UINT16_MAX, 8692, UINT16_MAX, 8692, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17521, 1139, UINT16_MAX, 1139, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17524, UINT16_MAX, 8693, UINT16_MAX, 8693, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1142, UINT16_MAX, 1142, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8694, UINT16_MAX, 8694, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17527, 1145, UINT16_MAX, 1145, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17530, UINT16_MAX, 8695, UINT16_MAX, 8695, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1148, UINT16_MAX, 1148, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8696, UINT16_MAX, 8696, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1149, UINT16_MAX, 1149, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8697, UINT16_MAX, 8697, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1150, UINT16_MAX, 1150, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8698, UINT16_MAX, 8698, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1151, UINT16_MAX, 1151, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8699, UINT16_MAX, 8699, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1152, UINT16_MAX, 1152, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8700, UINT16_MAX, 8700, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1153, UINT16_MAX, 1153, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8701, UINT16_MAX, 8701, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1154, UINT16_MAX, 1154, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8702, UINT16_MAX, 8702, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1155, UINT16_MAX, 1155, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8703, UINT16_MAX, 8703, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1156, UINT16_MAX, 1156, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8704, UINT16_MAX, 8704, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1157, UINT16_MAX, 1157, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8705, UINT16_MAX, 8705, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1158, UINT16_MAX, 1158, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8706, UINT16_MAX, 8706, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1159, UINT16_MAX, 1159, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8707, UINT16_MAX, 8707, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1160, UINT16_MAX, 1160, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8708, UINT16_MAX, 8708, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1161, UINT16_MAX, 1161, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8709, UINT16_MAX, 8709, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1162, UINT16_MAX, 1162, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8710, UINT16_MAX, 8710, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1163, UINT16_MAX, 1163, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8711, UINT16_MAX, 8711, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1164, UINT16_MAX, 1164, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8712, UINT16_MAX, 8712, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1165, UINT16_MAX, 1165, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8713, UINT16_MAX, 8713, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1166, UINT16_MAX, 1166, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8714, UINT16_MAX, 8714, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1167, UINT16_MAX, 1167, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8715, UINT16_MAX, 8715, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1168, UINT16_MAX, 1168, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8716, UINT16_MAX, 8716, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1169, UINT16_MAX, 1169, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8717, UINT16_MAX, 8717, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1170, UINT16_MAX, 1170, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8718, UINT16_MAX, 8718, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1171, UINT16_MAX, 1171, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8719, UINT16_MAX, 8719, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1172, UINT16_MAX, 1172, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8720, UINT16_MAX, 8720, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1173, UINT16_MAX, 1173, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8721, UINT16_MAX, 8721, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1174, UINT16_MAX, 1174, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8722, UINT16_MAX, 8722, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1175, UINT16_MAX, 1175, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1176, UINT16_MAX, 1176, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1177, UINT16_MAX, 1177, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1178, UINT16_MAX, 1178, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1179, UINT16_MAX, 1179, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1180, UINT16_MAX, 1180, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1181, UINT16_MAX, 1181, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1182, UINT16_MAX, 1182, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1183, UINT16_MAX, 1183, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1184, UINT16_MAX, 1184, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1185, UINT16_MAX, 1185, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1186, UINT16_MAX, 1186, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1187, UINT16_MAX, 1187, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1188, UINT16_MAX, 1188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1189, UINT16_MAX, 1189, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1190, UINT16_MAX, 1190, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1191, UINT16_MAX, 1191, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1192, UINT16_MAX, 1192, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1193, UINT16_MAX, 1193, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1194, UINT16_MAX, 1194, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1195, UINT16_MAX, 1195, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1196, UINT16_MAX, 1196, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1197, UINT16_MAX, 1197, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1198, UINT16_MAX, 1198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1199, UINT16_MAX, 1199, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1200, UINT16_MAX, 1200, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1201, UINT16_MAX, 1201, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1202, UINT16_MAX, 1202, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1203, UINT16_MAX, 1203, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1204, UINT16_MAX, 1204, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1205, UINT16_MAX, 1205, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1206, UINT16_MAX, 1206, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1207, UINT16_MAX, 1207, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1208, UINT16_MAX, 1208, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1209, UINT16_MAX, 1209, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1210, UINT16_MAX, 1210, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1211, UINT16_MAX, 1211, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1212, UINT16_MAX, 1212, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8723, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8724, UINT16_MAX, 8724, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8725, UINT16_MAX, 8725, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8726, UINT16_MAX, 8726, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8727, UINT16_MAX, 8727, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8728, UINT16_MAX, 8728, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8729, UINT16_MAX, 8729, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8730, UINT16_MAX, 8730, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8731, UINT16_MAX, 8731, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8732, UINT16_MAX, 8732, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8733, UINT16_MAX, 8733, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8734, UINT16_MAX, 8734, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8735, UINT16_MAX, 8735, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8736, UINT16_MAX, 8736, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8737, UINT16_MAX, 8737, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8738, UINT16_MAX, 8738, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8739, UINT16_MAX, 8739, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8740, UINT16_MAX, 8740, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8741, UINT16_MAX, 8741, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8742, UINT16_MAX, 8742, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8743, UINT16_MAX, 8743, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8744, UINT16_MAX, 8744, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8745, UINT16_MAX, 8745, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8746, UINT16_MAX, 8746, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8747, UINT16_MAX, 8747, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8748, UINT16_MAX, 8748, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8749, UINT16_MAX, 8749, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8750, UINT16_MAX, 8750, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8751, UINT16_MAX, 8751, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8752, UINT16_MAX, 8752, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8753, UINT16_MAX, 8753, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8754, UINT16_MAX, 8754, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8755, UINT16_MAX, 8755, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8756, UINT16_MAX, 8756, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8757, UINT16_MAX, 8757, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8758, UINT16_MAX, 8758, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8759, UINT16_MAX, 8759, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8760, UINT16_MAX, 8760, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8761, UINT16_MAX, 8761, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17597, 17597, 8762, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8763, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 222, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 228, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 10, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 11, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 12, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 13, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 14, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 15, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 16, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 17, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 18, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 19, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 20, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 21, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 22, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 23, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 24, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 25, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_AN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_PREPEND}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 30, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 31, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 32, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2671, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2676, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2679, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 27, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 28, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 29, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 33, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 34, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32785, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32786, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32787, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_AN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_AN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 35, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, 17609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, 17611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, 17613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, 17615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2685, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2688, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, 17621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2682, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_PREPEND}, {UTF8PROC_CATEGORY_MN, 36, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2691, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2694, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2697, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17627, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 7, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32788, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17639, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17641, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17643, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 7, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32789, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2700, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17645, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17647, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32790, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17649, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17651, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17653, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17655, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17661, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17665, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32792, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2704, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32791, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32793, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2709, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32795, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2712, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2716, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32794, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2719, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 84, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 91, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32796, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2722, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32799, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2725, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2730, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32797, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32798, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32800, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2733, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2737, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17701, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_PREPEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32801, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32802, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32803, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2740, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17703, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17705, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2745, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17707, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17709, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32804, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17711, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MN, 103, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 107, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17713, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MN, 118, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17715, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 17717, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17720, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17724, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17726, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17728, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17730, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 129, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 130, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17732, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 132, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17734, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17736, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, UTF8PROC_DECOMP_TYPE_COMPAT, 17738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17740, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, UTF8PROC_DECOMP_TYPE_COMPAT, 17742, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17744, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17746, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17748, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17750, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17752, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17754, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 17756, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2748, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17758, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32805, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1376, UINT16_MAX, 1376, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1377, UINT16_MAX, 1377, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1378, UINT16_MAX, 1378, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1379, UINT16_MAX, 1379, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1380, UINT16_MAX, 1380, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1381, UINT16_MAX, 1381, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1382, UINT16_MAX, 1382, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1383, UINT16_MAX, 1383, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1384, UINT16_MAX, 1384, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1385, UINT16_MAX, 1385, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1386, UINT16_MAX, 1386, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1387, UINT16_MAX, 1387, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1388, UINT16_MAX, 1388, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1389, UINT16_MAX, 1389, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1390, UINT16_MAX, 1390, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1391, UINT16_MAX, 1391, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1392, UINT16_MAX, 1392, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1393, UINT16_MAX, 1393, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1394, UINT16_MAX, 1394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1395, UINT16_MAX, 1395, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1396, UINT16_MAX, 1396, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1397, UINT16_MAX, 1397, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1398, UINT16_MAX, 1398, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1399, UINT16_MAX, 1399, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1400, UINT16_MAX, 1400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1401, UINT16_MAX, 1401, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1402, UINT16_MAX, 1402, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1403, UINT16_MAX, 1403, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1404, UINT16_MAX, 1404, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1405, UINT16_MAX, 1405, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1406, UINT16_MAX, 1406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1407, UINT16_MAX, 1407, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1408, UINT16_MAX, 1408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1409, UINT16_MAX, 1409, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1410, UINT16_MAX, 1410, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1411, UINT16_MAX, 1411, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1412, UINT16_MAX, 1412, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1413, UINT16_MAX, 1413, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1414, UINT16_MAX, 1414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1415, UINT16_MAX, 1415, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8764, UINT16_MAX, 1446, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8765, UINT16_MAX, 1447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8766, UINT16_MAX, 1448, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8767, UINT16_MAX, 1449, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8768, UINT16_MAX, 1450, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8769, UINT16_MAX, 1451, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8770, UINT16_MAX, 1452, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8771, UINT16_MAX, 1453, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8772, UINT16_MAX, 1454, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8773, UINT16_MAX, 1455, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8774, UINT16_MAX, 1456, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8775, UINT16_MAX, 1457, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8776, UINT16_MAX, 1416, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8777, UINT16_MAX, 1458, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8778, UINT16_MAX, 1459, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8779, UINT16_MAX, 1460, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8780, UINT16_MAX, 1461, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8781, UINT16_MAX, 1462, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8782, UINT16_MAX, 1463, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8783, UINT16_MAX, 1464, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8784, UINT16_MAX, 1465, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8785, UINT16_MAX, 1466, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8786, UINT16_MAX, 1467, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8787, UINT16_MAX, 1468, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8788, UINT16_MAX, 1469, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8789, UINT16_MAX, 1470, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8790, UINT16_MAX, 1471, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8791, UINT16_MAX, 1472, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8792, UINT16_MAX, 1473, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8793, UINT16_MAX, 1474, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8794, UINT16_MAX, 1475, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8795, UINT16_MAX, 1476, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8796, UINT16_MAX, 1477, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8797, UINT16_MAX, 1478, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8798, UINT16_MAX, 1479, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8799, UINT16_MAX, 1480, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8800, UINT16_MAX, 1481, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8801, UINT16_MAX, 1482, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8802, UINT16_MAX, 1483, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8803, UINT16_MAX, 1484, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8804, UINT16_MAX, 1485, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8805, UINT16_MAX, 1486, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8806, UINT16_MAX, 1487, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1416, UINT16_MAX, 8807, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8808, UINT16_MAX, 1488, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8809, UINT16_MAX, 1489, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8810, UINT16_MAX, 1490, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_L}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 2, 0, UTF8PROC_BOUNDCLASS_L}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 1, 0, UTF8PROC_BOUNDCLASS_V}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_V}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_T}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8811, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8812, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8813, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8814, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8815, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8816, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8817, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8818, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8819, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8820, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8821, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8822, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8823, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8824, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8825, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8826, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8827, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8828, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8829, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8830, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8831, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8832, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8833, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8834, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8835, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8836, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8837, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8838, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8839, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8840, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8841, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8842, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8843, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8844, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8845, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8846, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8847, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8848, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8849, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8850, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8851, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8852, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8853, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8854, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8855, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8856, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8857, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8858, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8859, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8860, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8861, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8862, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8863, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8864, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8865, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8866, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8867, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8868, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8869, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8870, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8871, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8872, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8873, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8874, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8875, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8876, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8877, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8878, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8879, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8880, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8881, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8882, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8883, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8884, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8885, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8886, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8887, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8888, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8889, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8890, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8891, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8892, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8893, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8894, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8895, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 8896, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1417, 1417, UINT16_MAX, 1417, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1418, 1418, UINT16_MAX, 1418, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1419, 1419, UINT16_MAX, 1419, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1420, 1420, UINT16_MAX, 1420, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1421, 1421, UINT16_MAX, 1421, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1422, 1422, UINT16_MAX, 1422, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 9, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2751, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2754, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2757, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2760, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2763, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2766, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 17817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32806, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2769, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2772, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2775, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2778, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17823, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17825, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 2781, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 17827, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 955, 8577, UINT16_MAX, 8577, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 957, 8579, UINT16_MAX, 8579, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 969, 8589, UINT16_MAX, 8589, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 972, 8592, UINT16_MAX, 8592, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 973, 8593, UINT16_MAX, 8593, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 981, 8601, UINT16_MAX, 8601, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1004, 8624, UINT16_MAX, 8624, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1445, 8897, UINT16_MAX, 8897, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1446, UINT16_MAX, 1446, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1447, UINT16_MAX, 1447, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1448, UINT16_MAX, 1448, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1449, UINT16_MAX, 1449, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1450, UINT16_MAX, 1450, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1451, UINT16_MAX, 1451, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1452, UINT16_MAX, 1452, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1453, UINT16_MAX, 1453, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1454, UINT16_MAX, 1454, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1455, UINT16_MAX, 1455, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1456, UINT16_MAX, 1456, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1457, UINT16_MAX, 1457, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1416, UINT16_MAX, 1416, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1458, UINT16_MAX, 1458, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1459, UINT16_MAX, 1459, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1460, UINT16_MAX, 1460, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1461, UINT16_MAX, 1461, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1462, UINT16_MAX, 1462, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1463, UINT16_MAX, 1463, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1464, UINT16_MAX, 1464, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1465, UINT16_MAX, 1465, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1466, UINT16_MAX, 1466, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1467, UINT16_MAX, 1467, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1468, UINT16_MAX, 1468, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1469, UINT16_MAX, 1469, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1471, UINT16_MAX, 1471, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1472, UINT16_MAX, 1472, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1473, UINT16_MAX, 1473, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1474, UINT16_MAX, 1474, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1475, UINT16_MAX, 1475, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1476, UINT16_MAX, 1476, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1477, UINT16_MAX, 1477, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1479, UINT16_MAX, 1479, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1481, UINT16_MAX, 1481, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1483, UINT16_MAX, 1483, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1484, UINT16_MAX, 1484, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1485, UINT16_MAX, 1485, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1486, UINT16_MAX, 1486, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1487, UINT16_MAX, 1487, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1488, UINT16_MAX, 1488, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1489, UINT16_MAX, 1489, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1490, UINT16_MAX, 1490, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8898, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8899, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1514, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8900, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8901, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8902, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8903, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8904, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8905, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8906, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8907, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8908, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8909, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8910, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8911, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8912, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8913, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8914, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8915, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8916, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8917, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8918, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1516, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1517, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8919, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8920, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8921, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8922, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1538, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1518, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8923, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8924, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8925, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8926, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8927, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8928, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8929, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1519, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8930, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8931, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8932, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8933, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8934, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8935, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1491, UINT16_MAX, 8936, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1492, UINT16_MAX, 8937, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1493, UINT16_MAX, 8938, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8939, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1494, UINT16_MAX, 8940, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1495, UINT16_MAX, 8941, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1496, UINT16_MAX, 8942, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1497, UINT16_MAX, 8943, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1498, UINT16_MAX, 8944, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1499, UINT16_MAX, 8945, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1500, UINT16_MAX, 8946, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1501, UINT16_MAX, 8947, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1502, UINT16_MAX, 8948, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1503, UINT16_MAX, 8949, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1504, UINT16_MAX, 8950, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8951, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1505, UINT16_MAX, 8952, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1506, UINT16_MAX, 8953, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1507, UINT16_MAX, 8954, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1508, UINT16_MAX, 8955, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1509, UINT16_MAX, 8956, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1510, UINT16_MAX, 8957, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1511, UINT16_MAX, 8958, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 0, UINT16_MAX, 8959, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1512, UINT16_MAX, 8960, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1513, UINT16_MAX, 8961, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1514, UINT16_MAX, 8962, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1, UINT16_MAX, 8963, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3, UINT16_MAX, 8964, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 4, UINT16_MAX, 8965, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 485, UINT16_MAX, 8966, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 486, UINT16_MAX, 8967, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1515, UINT16_MAX, 8968, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 6, UINT16_MAX, 8969, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8970, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 10, UINT16_MAX, 8971, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 12, UINT16_MAX, 8972, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 355, UINT16_MAX, 8973, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 14, UINT16_MAX, 8974, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 479, UINT16_MAX, 8975, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1516, UINT16_MAX, 8976, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1517, UINT16_MAX, 8977, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 15, UINT16_MAX, 8978, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 19, UINT16_MAX, 8979, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 20, UINT16_MAX, 8980, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1518, UINT16_MAX, 8981, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 493, UINT16_MAX, 8982, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 21, UINT16_MAX, 8983, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1519, UINT16_MAX, 8984, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 846, UINT16_MAX, 8985, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 847, UINT16_MAX, 8986, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 848, UINT16_MAX, 8987, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 863, UINT16_MAX, 8988, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 864, UINT16_MAX, 8989, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 8, UINT16_MAX, 8990, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 17, UINT16_MAX, 8991, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 20, UINT16_MAX, 8992, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 21, UINT16_MAX, 8993, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 846, UINT16_MAX, 8994, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 847, UINT16_MAX, 8995, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 859, UINT16_MAX, 8996, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 863, UINT16_MAX, 8997, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 864, UINT16_MAX, 8998, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8999, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9000, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9001, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9002, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9003, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9004, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9005, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9006, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9007, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9008, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9009, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9010, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9011, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 968, UINT16_MAX, 9012, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9013, UINT16_MAX, 9013, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9014, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1526, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9015, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9016, UINT16_MAX, 9016, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9017, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9018, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9019, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9020, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9021, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9022, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9023, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 1529, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9024, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9025, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9026, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9027, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9028, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9029, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9030, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9031, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9032, UINT16_MAX, 9032, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9033, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9034, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7052, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9035, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9036, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9037, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9038, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9039, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9040, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9041, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9042, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9043, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1520, UINT16_MAX, 9044, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2, UINT16_MAX, 9045, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1521, UINT16_MAX, 9046, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 94, UINT16_MAX, 9047, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1515, UINT16_MAX, 9048, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5, UINT16_MAX, 9049, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1522, UINT16_MAX, 9050, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1523, UINT16_MAX, 9051, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1524, UINT16_MAX, 9052, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 491, UINT16_MAX, 9053, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 490, UINT16_MAX, 9054, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1525, UINT16_MAX, 9055, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1526, UINT16_MAX, 9056, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1527, UINT16_MAX, 9057, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1528, UINT16_MAX, 9058, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1529, UINT16_MAX, 9059, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1530, UINT16_MAX, 9060, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1531, UINT16_MAX, 9061, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1532, UINT16_MAX, 9062, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 494, UINT16_MAX, 9063, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1533, UINT16_MAX, 9064, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1534, UINT16_MAX, 9065, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 495, UINT16_MAX, 9066, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1535, UINT16_MAX, 9067, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1536, UINT16_MAX, 9068, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 505, UINT16_MAX, 9069, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1537, UINT16_MAX, 9070, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 778, UINT16_MAX, 9071, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 513, UINT16_MAX, 9072, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1538, UINT16_MAX, 9073, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 514, UINT16_MAX, 9074, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 779, UINT16_MAX, 9075, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 25, UINT16_MAX, 9076, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1539, UINT16_MAX, 9077, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1540, UINT16_MAX, 9078, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 517, UINT16_MAX, 9079, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 852, UINT16_MAX, 9080, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 214, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 218, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17925, 1543, UINT16_MAX, 1543, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17928, UINT16_MAX, 9081, UINT16_MAX, 9081, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17930, 1548, UINT16_MAX, 1548, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17933, UINT16_MAX, 9082, UINT16_MAX, 9082, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17935, 1553, UINT16_MAX, 1553, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17938, UINT16_MAX, 9083, UINT16_MAX, 9083, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17940, 1558, UINT16_MAX, 1558, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17943, UINT16_MAX, 9084, UINT16_MAX, 9084, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17945, 1563, UINT16_MAX, 1563, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17948, UINT16_MAX, 9085, UINT16_MAX, 9085, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17950, 1568, UINT16_MAX, 1568, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17953, UINT16_MAX, 9086, UINT16_MAX, 9086, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17955, 1573, UINT16_MAX, 1573, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17958, UINT16_MAX, 9087, UINT16_MAX, 9087, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17960, 1578, UINT16_MAX, 1578, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17963, UINT16_MAX, 9088, UINT16_MAX, 9088, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17965, 1583, UINT16_MAX, 1583, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17968, UINT16_MAX, 9089, UINT16_MAX, 9089, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17970, 1588, UINT16_MAX, 1588, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17973, UINT16_MAX, 9090, UINT16_MAX, 9090, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17975, 1593, UINT16_MAX, 1593, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17978, UINT16_MAX, 9091, UINT16_MAX, 9091, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17980, 1598, UINT16_MAX, 1598, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17983, UINT16_MAX, 9092, UINT16_MAX, 9092, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17985, 1603, UINT16_MAX, 1603, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17988, UINT16_MAX, 9093, UINT16_MAX, 9093, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17990, 1608, UINT16_MAX, 1608, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17993, UINT16_MAX, 9094, UINT16_MAX, 9094, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 17995, 1613, UINT16_MAX, 1613, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 17998, UINT16_MAX, 9095, UINT16_MAX, 9095, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18000, 1618, UINT16_MAX, 1618, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18003, UINT16_MAX, 9096, UINT16_MAX, 9096, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18005, 1623, UINT16_MAX, 1623, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18008, UINT16_MAX, 9097, UINT16_MAX, 9097, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18010, 1628, UINT16_MAX, 1628, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18013, UINT16_MAX, 9098, UINT16_MAX, 9098, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18015, 1633, UINT16_MAX, 1633, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18018, UINT16_MAX, 9099, UINT16_MAX, 9099, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18020, 1638, UINT16_MAX, 1638, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18023, UINT16_MAX, 9100, UINT16_MAX, 9100, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18025, 1643, UINT16_MAX, 1643, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18028, UINT16_MAX, 9101, UINT16_MAX, 9101, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18030, 1648, UINT16_MAX, 1648, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18033, UINT16_MAX, 9102, UINT16_MAX, 9102, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18035, 1653, UINT16_MAX, 1653, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18038, UINT16_MAX, 9103, UINT16_MAX, 9103, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18040, 1658, UINT16_MAX, 1658, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18043, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18045, 1663, UINT16_MAX, 1663, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18048, UINT16_MAX, 9105, UINT16_MAX, 9105, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18050, 1668, UINT16_MAX, 1668, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18053, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18055, 1673, UINT16_MAX, 1673, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18058, UINT16_MAX, 9107, UINT16_MAX, 9107, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18060, 1678, UINT16_MAX, 1678, UINT16_MAX, 2884, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18063, UINT16_MAX, 9108, UINT16_MAX, 9108, 2887, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18065, 1683, UINT16_MAX, 1683, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18068, UINT16_MAX, 9109, UINT16_MAX, 9109, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18070, 1688, UINT16_MAX, 1688, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18073, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18075, 1693, UINT16_MAX, 1693, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18078, UINT16_MAX, 9111, UINT16_MAX, 9111, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18080, 1698, UINT16_MAX, 1698, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18083, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18085, 1703, UINT16_MAX, 1703, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18088, UINT16_MAX, 9113, UINT16_MAX, 9113, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18090, 1708, UINT16_MAX, 1708, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18093, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18095, 1713, UINT16_MAX, 1713, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18098, UINT16_MAX, 9115, UINT16_MAX, 9115, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18100, 1718, UINT16_MAX, 1718, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18103, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18105, 1723, UINT16_MAX, 1723, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18108, UINT16_MAX, 9117, UINT16_MAX, 9117, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18110, 1728, UINT16_MAX, 1728, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18113, UINT16_MAX, 9118, UINT16_MAX, 9118, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18115, 1733, UINT16_MAX, 1733, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18118, UINT16_MAX, 9119, UINT16_MAX, 9119, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18120, 1738, UINT16_MAX, 1738, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18123, UINT16_MAX, 9120, UINT16_MAX, 9120, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18125, 1743, UINT16_MAX, 1743, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18128, UINT16_MAX, 9121, UINT16_MAX, 9121, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18130, 1748, UINT16_MAX, 1748, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18133, UINT16_MAX, 9122, UINT16_MAX, 9122, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18135, 1753, UINT16_MAX, 1753, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18138, UINT16_MAX, 9123, UINT16_MAX, 9123, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18140, 1758, UINT16_MAX, 1758, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18143, UINT16_MAX, 9124, UINT16_MAX, 9124, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18145, 1763, UINT16_MAX, 1763, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18148, UINT16_MAX, 9125, UINT16_MAX, 9125, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18150, 1768, UINT16_MAX, 1768, UINT16_MAX, 3006, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18153, UINT16_MAX, 9126, UINT16_MAX, 9126, 3009, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18155, 1773, UINT16_MAX, 1773, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18158, UINT16_MAX, 9127, UINT16_MAX, 9127, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18160, 1778, UINT16_MAX, 1778, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18163, UINT16_MAX, 9128, UINT16_MAX, 9128, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18165, 1783, UINT16_MAX, 1783, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18168, UINT16_MAX, 9129, UINT16_MAX, 9129, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18170, 1788, UINT16_MAX, 1788, UINT16_MAX, 3024, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18173, UINT16_MAX, 9130, UINT16_MAX, 9130, 3027, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18175, 1793, UINT16_MAX, 1793, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18178, UINT16_MAX, 9131, UINT16_MAX, 9131, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18180, 1798, UINT16_MAX, 1798, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18183, UINT16_MAX, 9132, UINT16_MAX, 9132, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18185, 1803, UINT16_MAX, 1803, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18188, UINT16_MAX, 9133, UINT16_MAX, 9133, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18190, 1808, UINT16_MAX, 1808, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18193, UINT16_MAX, 9134, UINT16_MAX, 9134, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18195, 1813, UINT16_MAX, 1813, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18198, UINT16_MAX, 9135, UINT16_MAX, 9135, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18200, 1818, UINT16_MAX, 1818, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18203, UINT16_MAX, 9136, UINT16_MAX, 9136, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18205, 1823, UINT16_MAX, 1823, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18208, UINT16_MAX, 9137, UINT16_MAX, 9137, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18210, 1828, UINT16_MAX, 1828, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18213, UINT16_MAX, 9138, UINT16_MAX, 9138, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18215, 1833, UINT16_MAX, 1833, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18218, UINT16_MAX, 9139, UINT16_MAX, 9139, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18220, 1838, UINT16_MAX, 1838, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18223, UINT16_MAX, 9140, UINT16_MAX, 9140, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18225, 1843, UINT16_MAX, 1843, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18228, UINT16_MAX, 9141, UINT16_MAX, 9141, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18230, 1848, UINT16_MAX, 1848, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18233, UINT16_MAX, 9142, UINT16_MAX, 9142, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18235, 1853, UINT16_MAX, 1853, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18238, UINT16_MAX, 9143, UINT16_MAX, 9143, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18240, 1858, UINT16_MAX, 1858, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18243, UINT16_MAX, 9144, UINT16_MAX, 9144, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18245, 1863, UINT16_MAX, 1863, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18248, UINT16_MAX, 9145, UINT16_MAX, 9145, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18250, 1868, UINT16_MAX, 1868, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18253, UINT16_MAX, 9146, UINT16_MAX, 9146, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18255, 1873, UINT16_MAX, 1873, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18258, UINT16_MAX, 9147, UINT16_MAX, 9147, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18260, 1878, UINT16_MAX, 1878, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18263, UINT16_MAX, 9148, UINT16_MAX, 9148, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18265, 1883, UINT16_MAX, 1883, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18268, UINT16_MAX, 9149, UINT16_MAX, 9149, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18270, 1888, UINT16_MAX, 1888, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18273, UINT16_MAX, 9150, UINT16_MAX, 9150, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18275, 1893, UINT16_MAX, 1893, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18278, UINT16_MAX, 9151, UINT16_MAX, 9151, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18280, 1898, UINT16_MAX, 1898, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18283, UINT16_MAX, 9152, UINT16_MAX, 9152, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18285, 1903, UINT16_MAX, 1903, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18288, UINT16_MAX, 9153, UINT16_MAX, 9153, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18290, 1908, UINT16_MAX, 1908, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18293, UINT16_MAX, 9154, UINT16_MAX, 9154, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18295, 1913, UINT16_MAX, 1913, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18298, UINT16_MAX, 9155, UINT16_MAX, 9155, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18300, 18300, 9156, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18302, 18302, 9157, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18304, 18304, 9158, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18306, 18306, 9159, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 18308, 18308, 9160, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18310, 1783, 9129, UINT16_MAX, 9129, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9161, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9162, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 16514, UINT16_MAX, 9163, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9164, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18312, 1930, UINT16_MAX, 1930, UINT16_MAX, 3241, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18315, UINT16_MAX, 9165, UINT16_MAX, 9165, 3250, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18317, 1935, UINT16_MAX, 1935, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18320, UINT16_MAX, 9166, UINT16_MAX, 9166, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18322, 1940, UINT16_MAX, 1940, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18325, UINT16_MAX, 9167, UINT16_MAX, 9167, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18327, 1945, UINT16_MAX, 1945, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18330, UINT16_MAX, 9168, UINT16_MAX, 9168, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18332, 1950, UINT16_MAX, 1950, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18335, UINT16_MAX, 9169, UINT16_MAX, 9169, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18337, 1955, UINT16_MAX, 1955, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18340, UINT16_MAX, 9170, UINT16_MAX, 9170, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18342, 1960, UINT16_MAX, 1960, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18345, UINT16_MAX, 9171, UINT16_MAX, 9171, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18347, 1965, UINT16_MAX, 1965, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18350, UINT16_MAX, 9172, UINT16_MAX, 9172, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18352, 1970, UINT16_MAX, 1970, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18355, UINT16_MAX, 9173, UINT16_MAX, 9173, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18357, 1975, UINT16_MAX, 1975, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18360, UINT16_MAX, 9174, UINT16_MAX, 9174, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18362, 1980, UINT16_MAX, 1980, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18365, UINT16_MAX, 9175, UINT16_MAX, 9175, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18367, 1985, UINT16_MAX, 1985, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18370, UINT16_MAX, 9176, UINT16_MAX, 9176, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18372, 1990, UINT16_MAX, 1990, UINT16_MAX, 3455, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18375, UINT16_MAX, 9177, UINT16_MAX, 9177, 3458, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18377, 1995, UINT16_MAX, 1995, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18380, UINT16_MAX, 9178, UINT16_MAX, 9178, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18382, 2000, UINT16_MAX, 2000, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18385, UINT16_MAX, 9179, UINT16_MAX, 9179, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18387, 2005, UINT16_MAX, 2005, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18390, UINT16_MAX, 9180, UINT16_MAX, 9180, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18392, 2010, UINT16_MAX, 2010, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18395, UINT16_MAX, 9181, UINT16_MAX, 9181, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18397, 2015, UINT16_MAX, 2015, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18400, UINT16_MAX, 9182, UINT16_MAX, 9182, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18402, 2020, UINT16_MAX, 2020, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18405, UINT16_MAX, 9183, UINT16_MAX, 9183, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18407, 2025, UINT16_MAX, 2025, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18410, UINT16_MAX, 9184, UINT16_MAX, 9184, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18412, 2030, UINT16_MAX, 2030, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18415, UINT16_MAX, 9185, UINT16_MAX, 9185, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18417, 2035, UINT16_MAX, 2035, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18420, UINT16_MAX, 9186, UINT16_MAX, 9186, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18422, 2040, UINT16_MAX, 2040, UINT16_MAX, 3559, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18425, UINT16_MAX, 9187, UINT16_MAX, 9187, 3562, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18427, 2045, UINT16_MAX, 2045, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18430, UINT16_MAX, 9188, UINT16_MAX, 9188, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18432, 2050, UINT16_MAX, 2050, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18435, UINT16_MAX, 9189, UINT16_MAX, 9189, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18437, 2055, UINT16_MAX, 2055, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18440, UINT16_MAX, 9190, UINT16_MAX, 9190, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18442, 2060, UINT16_MAX, 2060, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18445, UINT16_MAX, 9191, UINT16_MAX, 9191, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18447, 2065, UINT16_MAX, 2065, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18450, UINT16_MAX, 9192, UINT16_MAX, 9192, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18452, 2070, UINT16_MAX, 2070, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18455, UINT16_MAX, 9193, UINT16_MAX, 9193, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18457, 2075, UINT16_MAX, 2075, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18460, UINT16_MAX, 9194, UINT16_MAX, 9194, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18462, 2080, UINT16_MAX, 2080, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18465, UINT16_MAX, 9195, UINT16_MAX, 9195, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18467, 2085, UINT16_MAX, 2085, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18470, UINT16_MAX, 9196, UINT16_MAX, 9196, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18472, 2090, UINT16_MAX, 2090, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18475, UINT16_MAX, 9197, UINT16_MAX, 9197, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18477, 2095, UINT16_MAX, 2095, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18480, UINT16_MAX, 9198, UINT16_MAX, 9198, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18482, 2100, UINT16_MAX, 2100, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18485, UINT16_MAX, 9199, UINT16_MAX, 9199, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18487, 2105, UINT16_MAX, 2105, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18490, UINT16_MAX, 9200, UINT16_MAX, 9200, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18492, 2110, UINT16_MAX, 2110, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18495, UINT16_MAX, 9201, UINT16_MAX, 9201, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18497, 2115, UINT16_MAX, 2115, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18500, UINT16_MAX, 9202, UINT16_MAX, 9202, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18502, 2120, UINT16_MAX, 2120, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18505, UINT16_MAX, 9203, UINT16_MAX, 9203, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18507, 2125, UINT16_MAX, 2125, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18510, UINT16_MAX, 9204, UINT16_MAX, 9204, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18512, 2130, UINT16_MAX, 2130, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18515, UINT16_MAX, 9205, UINT16_MAX, 9205, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18517, 2135, UINT16_MAX, 2135, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18520, UINT16_MAX, 9206, UINT16_MAX, 9206, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18522, 2140, UINT16_MAX, 2140, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18525, UINT16_MAX, 9207, UINT16_MAX, 9207, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18527, 2145, UINT16_MAX, 2145, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18530, UINT16_MAX, 9208, UINT16_MAX, 9208, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18532, 2150, UINT16_MAX, 2150, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18535, UINT16_MAX, 9209, UINT16_MAX, 9209, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2153, UINT16_MAX, 2153, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9210, UINT16_MAX, 9210, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2154, UINT16_MAX, 2154, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9211, UINT16_MAX, 9211, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2155, UINT16_MAX, 2155, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9212, UINT16_MAX, 9212, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18540, UINT16_MAX, 9213, UINT16_MAX, 9213, 3761, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18542, UINT16_MAX, 9214, UINT16_MAX, 9214, 3814, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18544, UINT16_MAX, 9215, UINT16_MAX, 9215, 4793, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18546, UINT16_MAX, 9216, UINT16_MAX, 9216, 4796, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18548, UINT16_MAX, 9217, UINT16_MAX, 9217, 4799, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18550, UINT16_MAX, 9218, UINT16_MAX, 9218, 4802, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18552, UINT16_MAX, 9219, UINT16_MAX, 9219, 4805, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18554, UINT16_MAX, 9220, UINT16_MAX, 9220, 4808, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18556, 2174, UINT16_MAX, 2174, UINT16_MAX, 3867, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18559, 2177, UINT16_MAX, 2177, UINT16_MAX, 3920, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18562, 2180, UINT16_MAX, 2180, UINT16_MAX, 4811, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18565, 2183, UINT16_MAX, 2183, UINT16_MAX, 4814, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18568, 2186, UINT16_MAX, 2186, UINT16_MAX, 4817, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18571, 2189, UINT16_MAX, 2189, UINT16_MAX, 4820, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18574, 2192, UINT16_MAX, 2192, UINT16_MAX, 4823, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18577, 2195, UINT16_MAX, 2195, UINT16_MAX, 4826, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18580, UINT16_MAX, 9221, UINT16_MAX, 9221, 3973, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18582, UINT16_MAX, 9222, UINT16_MAX, 9222, 3977, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18584, UINT16_MAX, 9223, UINT16_MAX, 9223, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18586, UINT16_MAX, 9224, UINT16_MAX, 9224, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18588, UINT16_MAX, 9225, UINT16_MAX, 9225, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18590, UINT16_MAX, 9226, UINT16_MAX, 9226, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18592, 2210, UINT16_MAX, 2210, UINT16_MAX, 3981, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18595, 2213, UINT16_MAX, 2213, UINT16_MAX, 3985, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18598, 2216, UINT16_MAX, 2216, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18601, 2219, UINT16_MAX, 2219, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18604, 2222, UINT16_MAX, 2222, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18607, 2225, UINT16_MAX, 2225, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18610, UINT16_MAX, 9227, UINT16_MAX, 9227, 3989, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18612, UINT16_MAX, 9228, UINT16_MAX, 9228, 4042, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18614, UINT16_MAX, 9229, UINT16_MAX, 9229, 4829, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18616, UINT16_MAX, 9230, UINT16_MAX, 9230, 4832, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18618, UINT16_MAX, 9231, UINT16_MAX, 9231, 4835, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18620, UINT16_MAX, 9232, UINT16_MAX, 9232, 4838, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18622, UINT16_MAX, 9233, UINT16_MAX, 9233, 4841, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18624, UINT16_MAX, 9234, UINT16_MAX, 9234, 4844, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18626, 2244, UINT16_MAX, 2244, UINT16_MAX, 4095, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18629, 2247, UINT16_MAX, 2247, UINT16_MAX, 4148, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18632, 2250, UINT16_MAX, 2250, UINT16_MAX, 4847, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18635, 2253, UINT16_MAX, 2253, UINT16_MAX, 4850, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18638, 2256, UINT16_MAX, 2256, UINT16_MAX, 4853, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18641, 2259, UINT16_MAX, 2259, UINT16_MAX, 4856, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18644, 2262, UINT16_MAX, 2262, UINT16_MAX, 4859, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18647, 2265, UINT16_MAX, 2265, UINT16_MAX, 4862, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18650, UINT16_MAX, 9235, UINT16_MAX, 9235, 4201, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18652, UINT16_MAX, 9236, UINT16_MAX, 9236, 4253, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18654, UINT16_MAX, 9237, UINT16_MAX, 9237, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18656, UINT16_MAX, 9238, UINT16_MAX, 9238, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18658, UINT16_MAX, 9239, UINT16_MAX, 9239, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18660, UINT16_MAX, 9240, UINT16_MAX, 9240, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18662, UINT16_MAX, 9241, UINT16_MAX, 9241, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18664, UINT16_MAX, 9242, UINT16_MAX, 9242, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18666, 2284, UINT16_MAX, 2284, UINT16_MAX, 4305, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18669, 2287, UINT16_MAX, 2287, UINT16_MAX, 4357, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18672, 2290, UINT16_MAX, 2290, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18675, 2293, UINT16_MAX, 2293, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18678, 2296, UINT16_MAX, 2296, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18681, 2299, UINT16_MAX, 2299, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18684, 2302, UINT16_MAX, 2302, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18687, 2305, UINT16_MAX, 2305, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18690, UINT16_MAX, 9243, UINT16_MAX, 9243, 4409, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18692, UINT16_MAX, 9244, UINT16_MAX, 9244, 4413, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18694, UINT16_MAX, 9245, UINT16_MAX, 9245, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18696, UINT16_MAX, 9246, UINT16_MAX, 9246, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18698, UINT16_MAX, 9247, UINT16_MAX, 9247, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18700, UINT16_MAX, 9248, UINT16_MAX, 9248, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18702, 2320, UINT16_MAX, 2320, UINT16_MAX, 4417, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18705, 2323, UINT16_MAX, 2323, UINT16_MAX, 4421, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18708, 2326, UINT16_MAX, 2326, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18711, 2329, UINT16_MAX, 2329, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18714, 2332, UINT16_MAX, 2332, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18717, 2335, UINT16_MAX, 2335, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18720, 18720, 9249, UINT16_MAX, UINT16_MAX, 4425, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18722, UINT16_MAX, 9250, UINT16_MAX, 9250, 4477, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18724, 35110, 9251, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18729, UINT16_MAX, 9252, UINT16_MAX, 9252, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18731, 35117, 9253, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18736, UINT16_MAX, 9254, UINT16_MAX, 9254, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18738, 35124, 9255, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18743, UINT16_MAX, 9256, UINT16_MAX, 9256, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18745, 2363, UINT16_MAX, 2363, UINT16_MAX, 4529, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18748, 2366, UINT16_MAX, 2366, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18751, 2369, UINT16_MAX, 2369, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18754, 2372, UINT16_MAX, 2372, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18757, UINT16_MAX, 9257, UINT16_MAX, 9257, 4581, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18759, UINT16_MAX, 9258, UINT16_MAX, 9258, 4634, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18761, UINT16_MAX, 9259, UINT16_MAX, 9259, 4865, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18763, UINT16_MAX, 9260, UINT16_MAX, 9260, 4868, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18765, UINT16_MAX, 9261, UINT16_MAX, 9261, 4871, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18767, UINT16_MAX, 9262, UINT16_MAX, 9262, 4874, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18769, UINT16_MAX, 9263, UINT16_MAX, 9263, 4877, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18771, UINT16_MAX, 9264, UINT16_MAX, 9264, 4880, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18773, 2391, UINT16_MAX, 2391, UINT16_MAX, 4687, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18776, 2394, UINT16_MAX, 2394, UINT16_MAX, 4740, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18779, 2397, UINT16_MAX, 2397, UINT16_MAX, 4883, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18782, 2400, UINT16_MAX, 2400, UINT16_MAX, 4886, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18785, 2403, UINT16_MAX, 2403, UINT16_MAX, 4889, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18788, 2406, UINT16_MAX, 2406, UINT16_MAX, 4892, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18791, 2409, UINT16_MAX, 2409, UINT16_MAX, 4895, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18794, 2412, UINT16_MAX, 2412, UINT16_MAX, 4898, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18797, UINT16_MAX, 9265, UINT16_MAX, 9265, 4901, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 820, UINT16_MAX, 9266, UINT16_MAX, 9266, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18799, UINT16_MAX, 9267, UINT16_MAX, 9267, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 824, UINT16_MAX, 9268, UINT16_MAX, 9268, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18801, UINT16_MAX, 9269, UINT16_MAX, 9269, 4910, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 827, UINT16_MAX, 9270, UINT16_MAX, 9270, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18803, UINT16_MAX, 9271, UINT16_MAX, 9271, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 830, UINT16_MAX, 9272, UINT16_MAX, 9272, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18805, UINT16_MAX, 9273, UINT16_MAX, 9273, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 833, UINT16_MAX, 9274, UINT16_MAX, 9274, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18807, UINT16_MAX, 9275, UINT16_MAX, 9275, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 836, UINT16_MAX, 9276, UINT16_MAX, 9276, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18809, UINT16_MAX, 9277, UINT16_MAX, 9277, 5030, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 839, UINT16_MAX, 9278, UINT16_MAX, 9278, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18811, 18813, 9279, UINT16_MAX, 9279, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18815, 18817, 9280, UINT16_MAX, 9280, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18819, 18821, 9281, UINT16_MAX, 9281, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18823, 18825, 9282, UINT16_MAX, 9282, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18827, 18829, 9283, UINT16_MAX, 9283, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18831, 18833, 9284, UINT16_MAX, 9284, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18835, 18837, 9285, UINT16_MAX, 9285, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18839, 18841, 9286, UINT16_MAX, 9286, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18843, 18813, UINT16_MAX, 9287, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18845, 18817, UINT16_MAX, 9288, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18847, 18821, UINT16_MAX, 9289, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18849, 18825, UINT16_MAX, 9290, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18851, 18829, UINT16_MAX, 9291, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18853, 18833, UINT16_MAX, 9292, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18855, 18837, UINT16_MAX, 9293, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18857, 18841, UINT16_MAX, 9294, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18859, 18861, 9295, UINT16_MAX, 9295, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18863, 18865, 9296, UINT16_MAX, 9296, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18867, 18869, 9297, UINT16_MAX, 9297, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18871, 18873, 9298, UINT16_MAX, 9298, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18875, 18877, 9299, UINT16_MAX, 9299, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18879, 18881, 9300, UINT16_MAX, 9300, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18883, 18885, 9301, UINT16_MAX, 9301, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18887, 18889, 9302, UINT16_MAX, 9302, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18891, 18861, UINT16_MAX, 9303, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18893, 18865, UINT16_MAX, 9304, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18895, 18869, UINT16_MAX, 9305, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18897, 18873, UINT16_MAX, 9306, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18899, 18877, UINT16_MAX, 9307, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18901, 18881, UINT16_MAX, 9308, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18903, 18885, UINT16_MAX, 9309, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18905, 18889, UINT16_MAX, 9310, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18907, 18909, 9311, UINT16_MAX, 9311, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18911, 18913, 9312, UINT16_MAX, 9312, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18915, 18917, 9313, UINT16_MAX, 9313, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18919, 18921, 9314, UINT16_MAX, 9314, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18923, 18925, 9315, UINT16_MAX, 9315, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18927, 18929, 9316, UINT16_MAX, 9316, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18931, 18933, 9317, UINT16_MAX, 9317, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18935, 18937, 9318, UINT16_MAX, 9318, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18939, 18909, UINT16_MAX, 9319, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18941, 18913, UINT16_MAX, 9320, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18943, 18917, UINT16_MAX, 9321, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18945, 18921, UINT16_MAX, 9322, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18947, 18925, UINT16_MAX, 9323, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18949, 18929, UINT16_MAX, 9324, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18951, 18933, UINT16_MAX, 9325, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18953, 18937, UINT16_MAX, 9326, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18955, UINT16_MAX, 9327, UINT16_MAX, 9327, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18957, UINT16_MAX, 9328, UINT16_MAX, 9328, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18959, 18961, 9329, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18963, 18965, 9330, UINT16_MAX, 9330, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18967, 18969, 9331, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18971, 18971, 9332, UINT16_MAX, UINT16_MAX, 4907, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18973, 35359, 9333, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18978, 2596, UINT16_MAX, 2596, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18981, 2599, UINT16_MAX, 2599, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 18984, 2602, UINT16_MAX, 2602, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2603, 2604, UINT16_MAX, 2604, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 18989, 18965, UINT16_MAX, 9334, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 18991, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 807, 807, 7437, UINT16_MAX, 7437, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 18991, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 4919, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 18993, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 18995, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 18997, 18999, 9335, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19001, 19003, 9336, UINT16_MAX, 9336, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19005, 19007, 9337, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19009, 19009, 9338, UINT16_MAX, UINT16_MAX, 4916, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19011, 35397, 9339, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19016, 2634, UINT16_MAX, 2634, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2635, 2636, UINT16_MAX, 2636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19021, 2639, UINT16_MAX, 2639, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2640, 2641, UINT16_MAX, 2641, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 19026, 19003, UINT16_MAX, 9340, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19028, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19032, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19034, UINT16_MAX, 9341, UINT16_MAX, 9341, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19036, UINT16_MAX, 9342, UINT16_MAX, 9342, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19038, 35424, 9343, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 2659, 33610, 9344, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19044, 19044, 9345, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19046, 35432, 9346, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19051, 2669, UINT16_MAX, 2669, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19054, 2672, UINT16_MAX, 2672, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19057, 2675, UINT16_MAX, 2675, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2676, 2677, UINT16_MAX, 2677, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19062, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19064, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19066, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19068, UINT16_MAX, 9347, UINT16_MAX, 9347, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19070, UINT16_MAX, 9348, UINT16_MAX, 9348, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19072, 35458, 9349, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 2693, 33651, 9350, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19078, 19078, 9351, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19080, UINT16_MAX, 9352, UINT16_MAX, 9352, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19082, 19082, 9353, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19084, 35470, 9354, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19089, 2707, UINT16_MAX, 2707, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19092, 2710, UINT16_MAX, 2710, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19095, 2713, UINT16_MAX, 2713, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2714, 2715, UINT16_MAX, 2715, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19100, 2718, UINT16_MAX, 2718, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19103, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 2721, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 2722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19107, 19109, 9355, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19111, 19113, 9356, UINT16_MAX, 9356, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19115, 19117, 9357, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19119, 19119, 9358, UINT16_MAX, UINT16_MAX, 5036, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, 19121, 35507, 9359, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19126, 2744, UINT16_MAX, 2744, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2745, 2746, UINT16_MAX, 2746, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 19131, 2749, UINT16_MAX, 2749, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2750, 2751, UINT16_MAX, 2751, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, 19136, 19113, UINT16_MAX, 9360, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, 2754, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19139, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 4971, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, 2757, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, 2758, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_COMPAT, 26, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_NOBREAK, 26, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_ZWJ}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NOBREAK, 2759, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19144, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PI, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PF, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 2762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ZL, 0, UTF8PROC_BIDI_CLASS_WS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_ZP, 0, UTF8PROC_BIDI_CLASS_B, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_LRE, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_RLE, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_PDF, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_LRO, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_RLO, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, 19152, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, 35538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19157, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35543, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19162, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19164, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_CS, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19166, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19168, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19170, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 51940, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_LRI, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_RLI, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_FSI, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_PDI, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 8, UINT16_MAX, 9361, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUPER, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUPER, 2801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 2802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 13, UINT16_MAX, 9362, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUB, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUB, 2801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, 2802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 0, UINT16_MAX, 9363, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 4, UINT16_MAX, 9364, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 14, UINT16_MAX, 9365, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 23, UINT16_MAX, 9366, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 485, UINT16_MAX, 9367, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 7, UINT16_MAX, 9368, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 10, UINT16_MAX, 9369, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 11, UINT16_MAX, 9370, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 12, UINT16_MAX, 9371, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 13, UINT16_MAX, 9372, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 15, UINT16_MAX, 9373, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 18, UINT16_MAX, 9374, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 19, UINT16_MAX, 9375, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, 19189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35578, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 9376, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19198, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35584, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2822, UINT16_MAX, UINT16_MAX, 9377, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19207, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 9378, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 9379, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 9380, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 9381, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 9382, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 277, UINT16_MAX, 9383, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 9384, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 9385, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 9386, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 9387, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 9388, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19209, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 9389, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 9390, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 9391, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 9392, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 9393, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 19212, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35598, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 19217, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 9394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2836, 866, UINT16_MAX, 866, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 9395, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 1501, 10, UINT16_MAX, 10, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, 2837, 65, UINT16_MAX, 65, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 9396, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 9397, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 9398, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 9399, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 9400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2839, UINT16_MAX, 2839, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 9401, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 9402, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2840, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2842, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2843, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 9403, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 9404, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 9405, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 9406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 9407, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FONT, 2849, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 9408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 9409, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 9410, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 9411, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 9412, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9413, UINT16_MAX, 9413, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 52008, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35641, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35644, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35647, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35650, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35653, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 19281, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 1499, 2899, UINT16_MAX, 2899, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19284, 2902, UINT16_MAX, 2902, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35671, 2906, UINT16_MAX, 2906, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19291, 2909, UINT16_MAX, 2909, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2910, 2911, UINT16_MAX, 2911, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19296, 2914, UINT16_MAX, 2914, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35683, 2918, UINT16_MAX, 2918, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 52071, 2924, UINT16_MAX, 2924, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19309, 2927, UINT16_MAX, 2927, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2928, 2929, UINT16_MAX, 2929, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19314, 2932, UINT16_MAX, 2932, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35701, 2936, UINT16_MAX, 2936, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 1502, 2937, UINT16_MAX, 2937, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2813, 2938, UINT16_MAX, 2938, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 1494, 2939, UINT16_MAX, 2939, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 1503, 2940, UINT16_MAX, 2940, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 8, UINT16_MAX, 9414, UINT16_MAX, 9414, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19325, UINT16_MAX, 9415, UINT16_MAX, 9415, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35711, UINT16_MAX, 9416, UINT16_MAX, 9416, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19330, UINT16_MAX, 9417, UINT16_MAX, 9417, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21, UINT16_MAX, 9418, UINT16_MAX, 9418, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19332, UINT16_MAX, 9419, UINT16_MAX, 9419, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35718, UINT16_MAX, 9420, UINT16_MAX, 9420, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 52105, UINT16_MAX, 9421, UINT16_MAX, 9421, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19342, UINT16_MAX, 9422, UINT16_MAX, 9422, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 23, UINT16_MAX, 9423, UINT16_MAX, 9423, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 19344, UINT16_MAX, 9424, UINT16_MAX, 9424, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35730, UINT16_MAX, 9425, UINT16_MAX, 9425, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 11, UINT16_MAX, 9426, UINT16_MAX, 9426, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 2, UINT16_MAX, 9427, UINT16_MAX, 9427, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3, UINT16_MAX, 9428, UINT16_MAX, 9428, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 12, UINT16_MAX, 9429, UINT16_MAX, 9429, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 2965, UINT16_MAX, 2965, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9430, UINT16_MAX, 9430, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, 35734, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5039, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5042, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5045, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19357, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19363, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5048, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5054, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5051, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5057, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5060, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5063, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19369, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5066, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19371, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5069, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19373, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19375, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35766, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5072, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19385, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5075, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19387, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5078, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19389, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5081, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19391, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5090, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19393, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5087, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19395, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5099, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5102, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19397, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19399, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19401, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19403, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19405, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5105, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5108, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19407, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19409, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5111, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5114, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19411, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19413, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5117, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5120, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5147, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5150, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19415, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19417, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5123, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5126, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19419, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19421, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5129, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5132, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19423, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19425, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5153, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5156, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5135, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5138, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5141, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5144, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19427, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19429, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19431, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19433, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5159, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5162, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5165, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5168, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19435, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19437, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19439, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19441, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19443, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19445, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19447, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19449, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, 3067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, 3068, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19453, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19455, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19457, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19459, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19461, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19463, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19465, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19467, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19469, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 19473, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 35883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52270, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52275, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52280, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52290, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52295, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52300, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52305, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52310, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52315, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52320, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19561, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19563, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19565, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19567, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 19573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35959, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35962, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35965, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35968, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35971, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35974, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35977, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35980, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35983, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35986, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 35989, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35992, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35995, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 35998, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36001, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36004, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36007, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36010, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36013, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36016, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36019, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36022, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36025, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36028, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36031, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36034, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36037, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36040, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36043, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36046, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36049, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36052, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36055, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36058, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36061, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36064, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1491, 3302, UINT16_MAX, 3302, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1493, 3303, UINT16_MAX, 3303, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2813, 3304, UINT16_MAX, 3304, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1494, 3305, UINT16_MAX, 3305, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1495, 3306, UINT16_MAX, 3306, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2838, 3307, UINT16_MAX, 3307, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1497, 3308, UINT16_MAX, 3308, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1498, 3309, UINT16_MAX, 3309, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1499, 3310, UINT16_MAX, 3310, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1500, 3311, UINT16_MAX, 3311, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1501, 3312, UINT16_MAX, 3312, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1502, 3313, UINT16_MAX, 3313, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1503, 3314, UINT16_MAX, 3314, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1504, 3315, UINT16_MAX, 3315, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1505, 3316, UINT16_MAX, 3316, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1507, 3317, UINT16_MAX, 3317, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2827, 3318, UINT16_MAX, 3318, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1508, 3319, UINT16_MAX, 3319, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3320, 3321, UINT16_MAX, 3321, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1509, 3322, UINT16_MAX, 3322, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1510, 3323, UINT16_MAX, 3323, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2910, 3324, UINT16_MAX, 3324, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1511, 3325, UINT16_MAX, 3325, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2928, 3326, UINT16_MAX, 3326, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3327, 3328, UINT16_MAX, 3328, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2835, 3329, UINT16_MAX, 3329, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 0, UINT16_MAX, 9431, UINT16_MAX, 9431, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1, UINT16_MAX, 9432, UINT16_MAX, 9432, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2, UINT16_MAX, 9433, UINT16_MAX, 9433, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3, UINT16_MAX, 9434, UINT16_MAX, 9434, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4, UINT16_MAX, 9435, UINT16_MAX, 9435, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 5, UINT16_MAX, 9436, UINT16_MAX, 9436, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 6, UINT16_MAX, 9437, UINT16_MAX, 9437, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 7, UINT16_MAX, 9438, UINT16_MAX, 9438, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 8, UINT16_MAX, 9439, UINT16_MAX, 9439, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 9, UINT16_MAX, 9440, UINT16_MAX, 9440, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 10, UINT16_MAX, 9441, UINT16_MAX, 9441, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 11, UINT16_MAX, 9442, UINT16_MAX, 9442, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 12, UINT16_MAX, 9443, UINT16_MAX, 9443, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 13, UINT16_MAX, 9444, UINT16_MAX, 9444, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 14, UINT16_MAX, 9445, UINT16_MAX, 9445, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 15, UINT16_MAX, 9446, UINT16_MAX, 9446, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 16, UINT16_MAX, 9447, UINT16_MAX, 9447, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 17, UINT16_MAX, 9448, UINT16_MAX, 9448, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 18, UINT16_MAX, 9449, UINT16_MAX, 9449, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 19, UINT16_MAX, 9450, UINT16_MAX, 9450, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20, UINT16_MAX, 9451, UINT16_MAX, 9451, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 21, UINT16_MAX, 9452, UINT16_MAX, 9452, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 22, UINT16_MAX, 9453, UINT16_MAX, 9453, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 23, UINT16_MAX, 9454, UINT16_MAX, 9454, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 24, UINT16_MAX, 9455, UINT16_MAX, 9455, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 25, UINT16_MAX, 9456, UINT16_MAX, 9456, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 52482, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 36103, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 19722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 36108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, 19727, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5171, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3345, UINT16_MAX, 3345, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3346, UINT16_MAX, 3346, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3347, UINT16_MAX, 3347, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3348, UINT16_MAX, 3348, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3349, UINT16_MAX, 3349, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3350, UINT16_MAX, 3350, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3351, UINT16_MAX, 3351, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3352, UINT16_MAX, 3352, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3353, UINT16_MAX, 3353, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3354, UINT16_MAX, 3354, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3355, UINT16_MAX, 3355, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3356, UINT16_MAX, 3356, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3357, UINT16_MAX, 3357, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3358, UINT16_MAX, 3358, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3359, UINT16_MAX, 3359, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3360, UINT16_MAX, 3360, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3361, UINT16_MAX, 3361, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3362, UINT16_MAX, 3362, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3363, UINT16_MAX, 3363, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3364, UINT16_MAX, 3364, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3365, UINT16_MAX, 3365, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3366, UINT16_MAX, 3366, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3367, UINT16_MAX, 3367, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3368, UINT16_MAX, 3368, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3369, UINT16_MAX, 3369, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3370, UINT16_MAX, 3370, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3371, UINT16_MAX, 3371, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3372, UINT16_MAX, 3372, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3373, UINT16_MAX, 3373, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3374, UINT16_MAX, 3374, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3375, UINT16_MAX, 3375, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3376, UINT16_MAX, 3376, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3377, UINT16_MAX, 3377, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3378, UINT16_MAX, 3378, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3379, UINT16_MAX, 3379, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3380, UINT16_MAX, 3380, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3381, UINT16_MAX, 3381, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3382, UINT16_MAX, 3382, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3383, UINT16_MAX, 3383, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3384, UINT16_MAX, 3384, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3385, UINT16_MAX, 3385, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3386, UINT16_MAX, 3386, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3387, UINT16_MAX, 3387, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3388, UINT16_MAX, 3388, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3389, UINT16_MAX, 3389, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3390, UINT16_MAX, 3390, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3391, UINT16_MAX, 3391, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3392, UINT16_MAX, 3392, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9457, UINT16_MAX, 9457, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9458, UINT16_MAX, 9458, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9459, UINT16_MAX, 9459, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9460, UINT16_MAX, 9460, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9461, UINT16_MAX, 9461, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9462, UINT16_MAX, 9462, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9463, UINT16_MAX, 9463, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9464, UINT16_MAX, 9464, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9465, UINT16_MAX, 9465, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9466, UINT16_MAX, 9466, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9467, UINT16_MAX, 9467, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9468, UINT16_MAX, 9468, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9469, UINT16_MAX, 9469, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9470, UINT16_MAX, 9470, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9471, UINT16_MAX, 9471, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9472, UINT16_MAX, 9472, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9473, UINT16_MAX, 9473, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9474, UINT16_MAX, 9474, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9475, UINT16_MAX, 9475, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9476, UINT16_MAX, 9476, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9477, UINT16_MAX, 9477, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9478, UINT16_MAX, 9478, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9479, UINT16_MAX, 9479, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9480, UINT16_MAX, 9480, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9481, UINT16_MAX, 9481, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9482, UINT16_MAX, 9482, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9483, UINT16_MAX, 9483, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9484, UINT16_MAX, 9484, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9485, UINT16_MAX, 9485, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9486, UINT16_MAX, 9486, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9487, UINT16_MAX, 9487, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9488, UINT16_MAX, 9488, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9489, UINT16_MAX, 9489, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9490, UINT16_MAX, 9490, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9491, UINT16_MAX, 9491, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9492, UINT16_MAX, 9492, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9493, UINT16_MAX, 9493, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9494, UINT16_MAX, 9494, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9495, UINT16_MAX, 9495, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9496, UINT16_MAX, 9496, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9497, UINT16_MAX, 9497, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9498, UINT16_MAX, 9498, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9499, UINT16_MAX, 9499, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9500, UINT16_MAX, 9500, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9501, UINT16_MAX, 9501, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9502, UINT16_MAX, 9502, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9503, UINT16_MAX, 9503, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9504, UINT16_MAX, 9504, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3393, UINT16_MAX, 3393, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9505, UINT16_MAX, 9505, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3394, UINT16_MAX, 3394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3395, UINT16_MAX, 3395, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3396, UINT16_MAX, 3396, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9506, UINT16_MAX, 9506, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9507, UINT16_MAX, 9507, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3397, UINT16_MAX, 3397, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9508, UINT16_MAX, 9508, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3398, UINT16_MAX, 3398, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9509, UINT16_MAX, 9509, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3399, UINT16_MAX, 3399, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9510, UINT16_MAX, 9510, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1513, UINT16_MAX, 1513, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1531, UINT16_MAX, 1531, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1512, UINT16_MAX, 1512, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1520, UINT16_MAX, 1520, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7083, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3400, UINT16_MAX, 3400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9511, UINT16_MAX, 9511, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9512, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3401, UINT16_MAX, 3401, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9513, UINT16_MAX, 9513, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9514, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9515, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9516, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9517, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9518, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 9, UINT16_MAX, 9519, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2910, UINT16_MAX, 9520, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3402, UINT16_MAX, 3402, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3403, UINT16_MAX, 3403, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3404, UINT16_MAX, 3404, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9521, UINT16_MAX, 9521, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3405, UINT16_MAX, 3405, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9522, UINT16_MAX, 9522, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3406, UINT16_MAX, 3406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9523, UINT16_MAX, 9523, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3407, UINT16_MAX, 3407, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9524, UINT16_MAX, 9524, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3408, UINT16_MAX, 3408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9525, UINT16_MAX, 9525, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3409, UINT16_MAX, 3409, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9526, UINT16_MAX, 9526, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3410, UINT16_MAX, 3410, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9527, UINT16_MAX, 9527, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3411, UINT16_MAX, 3411, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9528, UINT16_MAX, 9528, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3412, UINT16_MAX, 3412, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9529, UINT16_MAX, 9529, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3413, UINT16_MAX, 3413, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9530, UINT16_MAX, 9530, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3414, UINT16_MAX, 3414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9531, UINT16_MAX, 9531, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3415, UINT16_MAX, 3415, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9532, UINT16_MAX, 9532, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3416, UINT16_MAX, 3416, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9533, UINT16_MAX, 9533, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3417, UINT16_MAX, 3417, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9534, UINT16_MAX, 9534, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3418, UINT16_MAX, 3418, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9535, UINT16_MAX, 9535, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3419, UINT16_MAX, 3419, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9536, UINT16_MAX, 9536, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3420, UINT16_MAX, 3420, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9537, UINT16_MAX, 9537, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3421, UINT16_MAX, 3421, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9538, UINT16_MAX, 9538, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3422, UINT16_MAX, 3422, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9539, UINT16_MAX, 9539, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3423, UINT16_MAX, 3423, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9540, UINT16_MAX, 9540, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3424, UINT16_MAX, 3424, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9541, UINT16_MAX, 9541, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3425, UINT16_MAX, 3425, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9542, UINT16_MAX, 9542, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3426, UINT16_MAX, 3426, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9543, UINT16_MAX, 9543, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3427, UINT16_MAX, 3427, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9544, UINT16_MAX, 9544, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3428, UINT16_MAX, 3428, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9545, UINT16_MAX, 9545, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3429, UINT16_MAX, 3429, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9546, UINT16_MAX, 9546, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3430, UINT16_MAX, 3430, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9547, UINT16_MAX, 9547, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3431, UINT16_MAX, 3431, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9548, UINT16_MAX, 9548, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3432, UINT16_MAX, 3432, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9549, UINT16_MAX, 9549, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3433, UINT16_MAX, 3433, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9550, UINT16_MAX, 9550, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3434, UINT16_MAX, 3434, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9551, UINT16_MAX, 9551, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3435, UINT16_MAX, 3435, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9552, UINT16_MAX, 9552, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3436, UINT16_MAX, 3436, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9553, UINT16_MAX, 9553, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3437, UINT16_MAX, 3437, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9554, UINT16_MAX, 9554, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3438, UINT16_MAX, 3438, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9555, UINT16_MAX, 9555, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3439, UINT16_MAX, 3439, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9556, UINT16_MAX, 9556, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3440, UINT16_MAX, 3440, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9557, UINT16_MAX, 9557, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3441, UINT16_MAX, 3441, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9558, UINT16_MAX, 9558, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3442, UINT16_MAX, 3442, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9559, UINT16_MAX, 9559, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3443, UINT16_MAX, 3443, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9560, UINT16_MAX, 9560, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3444, UINT16_MAX, 3444, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9561, UINT16_MAX, 9561, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3445, UINT16_MAX, 3445, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9562, UINT16_MAX, 9562, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3446, UINT16_MAX, 3446, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9563, UINT16_MAX, 9563, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3447, UINT16_MAX, 3447, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9564, UINT16_MAX, 9564, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3448, UINT16_MAX, 3448, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9565, UINT16_MAX, 9565, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3449, UINT16_MAX, 3449, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9566, UINT16_MAX, 9566, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3450, UINT16_MAX, 3450, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9567, UINT16_MAX, 9567, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3451, UINT16_MAX, 3451, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9568, UINT16_MAX, 9568, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3452, UINT16_MAX, 3452, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9569, UINT16_MAX, 9569, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3453, UINT16_MAX, 3453, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9570, UINT16_MAX, 9570, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9571, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3454, UINT16_MAX, 3454, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9572, UINT16_MAX, 9572, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3455, UINT16_MAX, 3455, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9573, UINT16_MAX, 9573, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 3456, UINT16_MAX, 3456, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9574, UINT16_MAX, 9574, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9575, UINT16_MAX, 9575, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9576, UINT16_MAX, 9576, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9577, UINT16_MAX, 9577, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9578, UINT16_MAX, 9578, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9579, UINT16_MAX, 9579, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9580, UINT16_MAX, 9580, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9581, UINT16_MAX, 9581, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9582, UINT16_MAX, 9582, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9583, UINT16_MAX, 9583, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9584, UINT16_MAX, 9584, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9585, UINT16_MAX, 9585, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9586, UINT16_MAX, 9586, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9587, UINT16_MAX, 9587, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9588, UINT16_MAX, 9588, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9589, UINT16_MAX, 9589, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9590, UINT16_MAX, 9590, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9591, UINT16_MAX, 9591, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9592, UINT16_MAX, 9592, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9593, UINT16_MAX, 9593, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9594, UINT16_MAX, 9594, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9595, UINT16_MAX, 9595, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9596, UINT16_MAX, 9596, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9597, UINT16_MAX, 9597, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9598, UINT16_MAX, 9598, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9599, UINT16_MAX, 9599, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9600, UINT16_MAX, 9600, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9601, UINT16_MAX, 9601, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9602, UINT16_MAX, 9602, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9603, UINT16_MAX, 9603, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9604, UINT16_MAX, 9604, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9605, UINT16_MAX, 9605, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9606, UINT16_MAX, 9606, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9607, UINT16_MAX, 9607, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9608, UINT16_MAX, 9608, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9609, UINT16_MAX, 9609, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9610, UINT16_MAX, 9610, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9611, UINT16_MAX, 9611, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9612, UINT16_MAX, 9612, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9613, UINT16_MAX, 9613, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9614, UINT16_MAX, 9614, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3457, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3458, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3459, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3461, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3463, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3465, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3467, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3469, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3470, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3472, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3473, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3474, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3475, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3477, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3478, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3479, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3480, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3481, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3482, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3484, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3485, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3486, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3487, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3488, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3489, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3490, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3491, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3492, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3493, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3494, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3495, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3496, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3497, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3498, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3499, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3500, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3501, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3503, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3504, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3505, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3506, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3507, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3509, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3510, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3511, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3512, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3513, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3515, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3516, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3517, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3518, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3519, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3520, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3521, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3522, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3524, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3527, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3528, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3529, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3530, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3531, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3534, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3535, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3536, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3537, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3539, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3541, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3542, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3543, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3544, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3545, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3546, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3547, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3548, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3549, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3550, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3551, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3552, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3553, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3554, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3555, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3558, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3560, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3561, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3562, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3563, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3564, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3565, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3566, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3567, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3568, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3570, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3572, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3574, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3576, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3578, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3580, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3582, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3584, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3586, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3588, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3590, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3592, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3594, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3595, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3596, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3598, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3602, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3606, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3608, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3620, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3624, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3627, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3628, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3630, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3634, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3636, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3639, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3640, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3641, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3642, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3643, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3644, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3645, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3646, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3647, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3648, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3649, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3650, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3651, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3652, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3653, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3654, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3655, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3658, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3660, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3661, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3664, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3665, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_WIDE, 26, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 224, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 3674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5239, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5174, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20061, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5177, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20063, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5180, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20065, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5183, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5186, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20069, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5189, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20071, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5192, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20073, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5195, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20075, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5198, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20077, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5201, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20079, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5204, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5207, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20083, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5210, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20085, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5213, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5216, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20089, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5219, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20091, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20093, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5223, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20095, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20097, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5227, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20099, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20101, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5231, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20103, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20105, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5235, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20107, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20109, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20111, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 8, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32820, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 8, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 32821, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 20113, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 20115, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5242, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, 20117, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_VERTICAL, 20119, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5310, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5245, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20121, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5248, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20123, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5251, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20125, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5254, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20127, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5257, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5260, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20131, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5263, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20133, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5266, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20135, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5269, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20137, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5272, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20139, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5275, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20141, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5278, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20143, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5281, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20145, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5284, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5287, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20149, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5290, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20151, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20153, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5294, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20155, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20157, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5298, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20159, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20161, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5302, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20163, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20165, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5306, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20167, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5313, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5316, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5319, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5322, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20173, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20175, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 20179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5325, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, 20181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_VERTICAL, 20183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3805, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3806, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3808, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3812, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3816, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3818, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3822, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3823, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3824, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3825, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3826, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3827, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3828, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3829, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3830, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3831, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3832, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3833, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3834, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3835, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3836, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3837, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3838, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3839, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3840, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3842, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3843, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3845, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3846, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3847, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3848, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3849, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3850, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3864, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3866, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3867, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3869, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3876, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3879, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3882, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3884, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3885, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3887, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3888, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3891, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3892, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3893, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 3894, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3896, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3897, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3899, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3900, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3901, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3902, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3903, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3904, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36703, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36706, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36709, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36712, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53099, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53104, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53109, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53114, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53119, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53124, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53134, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53139, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53144, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53149, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53154, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53159, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53164, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 53169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 53174, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 53182, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36805, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36808, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36823, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36826, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36829, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36832, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36835, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36838, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36847, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36850, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36892, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36901, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36904, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 36910, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4145, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4146, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 36916, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20535, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20537, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20539, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20541, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20543, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20545, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20547, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20549, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20551, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20553, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20555, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20561, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20563, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3818, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3823, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3824, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3826, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3827, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3828, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3829, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3830, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20565, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20567, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 20591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 53361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 53367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3896, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4222, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4223, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4224, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4225, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3545, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3544, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3534, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3491, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3531, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4226, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4227, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4229, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4230, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4231, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4232, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4233, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4234, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4235, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3497, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4236, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4237, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4238, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4239, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4240, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4241, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4242, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4243, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3897, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 3899, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4244, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4245, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4246, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4247, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4248, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4249, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4250, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4251, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4252, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4253, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20640, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20642, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20644, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20646, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20648, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20650, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20652, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20654, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20658, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20660, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20664, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, 20666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 20684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37070, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37073, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37076, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 20695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 20700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37086, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4321, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4322, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4323, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4324, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4325, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4327, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4328, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4329, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4330, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4331, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4333, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4334, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4337, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4342, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4343, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4345, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4349, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4357, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4363, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 4367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20752, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53522, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53527, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37153, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37161, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37164, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53551, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37178, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37184, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53576, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37197, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37200, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37205, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53592, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20834, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37239, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37259, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37262, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37265, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53652, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37284, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37290, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20909, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20911, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20913, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20915, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37301, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37304, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37313, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53705, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37327, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20946, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20948, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53718, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53724, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53729, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 20976, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37371, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21001, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37387, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37393, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37401, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37404, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37407, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21037, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21045, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37441, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37444, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37447, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53834, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21071, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37457, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37473, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21092, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21094, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21096, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21098, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21100, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21102, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21104, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21106, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21110, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37496, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37499, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37505, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37511, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37517, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37520, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37529, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37535, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37541, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21160, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21162, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37548, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21167, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 21171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37560, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 21179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21185, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21187, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53957, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21194, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21196, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21198, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21200, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21202, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21204, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21206, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21208, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37594, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 53981, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21218, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21220, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21222, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21224, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21226, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21230, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21244, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21246, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21248, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21250, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21252, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21254, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21256, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21258, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21260, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21262, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37648, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37651, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21270, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21281, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54057, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21294, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54076, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54082, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21321, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21323, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21325, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21327, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21329, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21331, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21333, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21337, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21343, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21345, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21349, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54125, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54136, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37757, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21376, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21378, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21384, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21388, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21394, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21399, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21401, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37787, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37790, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21409, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 54179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 37800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21419, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21421, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21423, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21425, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21433, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21435, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21437, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21439, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21441, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21443, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21445, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21447, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 21449, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37835, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37838, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37847, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37850, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37892, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 37898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, 37901, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5136, UINT16_MAX, 5136, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9615, UINT16_MAX, 9615, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5137, UINT16_MAX, 5137, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9616, UINT16_MAX, 9616, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5138, UINT16_MAX, 5138, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9617, UINT16_MAX, 9617, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5139, UINT16_MAX, 5139, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9618, UINT16_MAX, 9618, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5140, UINT16_MAX, 5140, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9619, UINT16_MAX, 9619, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1445, UINT16_MAX, 1445, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 8897, UINT16_MAX, 8897, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5141, UINT16_MAX, 5141, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9620, UINT16_MAX, 9620, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5142, UINT16_MAX, 5142, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9621, UINT16_MAX, 9621, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5143, UINT16_MAX, 5143, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9622, UINT16_MAX, 9622, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5144, UINT16_MAX, 5144, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9623, UINT16_MAX, 9623, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5145, UINT16_MAX, 5145, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9624, UINT16_MAX, 9624, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5146, UINT16_MAX, 5146, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9625, UINT16_MAX, 9625, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5147, UINT16_MAX, 5147, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9626, UINT16_MAX, 9626, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5148, UINT16_MAX, 5148, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9627, UINT16_MAX, 9627, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5149, UINT16_MAX, 5149, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9628, UINT16_MAX, 9628, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5150, UINT16_MAX, 5150, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9629, UINT16_MAX, 9629, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5151, UINT16_MAX, 5151, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9630, UINT16_MAX, 9630, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5152, UINT16_MAX, 5152, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9631, UINT16_MAX, 9631, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5153, UINT16_MAX, 5153, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9632, UINT16_MAX, 9632, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5154, UINT16_MAX, 5154, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9633, UINT16_MAX, 9633, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5155, UINT16_MAX, 5155, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9634, UINT16_MAX, 9634, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5156, UINT16_MAX, 5156, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9635, UINT16_MAX, 9635, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5157, UINT16_MAX, 5157, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9636, UINT16_MAX, 9636, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5158, UINT16_MAX, 5158, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9637, UINT16_MAX, 9637, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5159, UINT16_MAX, 5159, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9638, UINT16_MAX, 9638, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5160, UINT16_MAX, 5160, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9639, UINT16_MAX, 9639, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5161, UINT16_MAX, 5161, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9640, UINT16_MAX, 9640, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5162, UINT16_MAX, 5162, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9641, UINT16_MAX, 9641, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5163, UINT16_MAX, 5163, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9642, UINT16_MAX, 9642, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5164, UINT16_MAX, 5164, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9643, UINT16_MAX, 9643, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5165, UINT16_MAX, 5165, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9644, UINT16_MAX, 9644, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5166, UINT16_MAX, 5166, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9645, UINT16_MAX, 9645, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5167, UINT16_MAX, 5167, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9646, UINT16_MAX, 9646, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5168, UINT16_MAX, 5168, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9647, UINT16_MAX, 9647, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5169, UINT16_MAX, 5169, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9648, UINT16_MAX, 9648, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5170, UINT16_MAX, 5170, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9649, UINT16_MAX, 9649, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5171, UINT16_MAX, 5171, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9650, UINT16_MAX, 9650, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 981, UINT16_MAX, 9651, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 983, UINT16_MAX, 9652, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5172, UINT16_MAX, 5172, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9653, UINT16_MAX, 9653, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5173, UINT16_MAX, 5173, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9654, UINT16_MAX, 9654, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5174, UINT16_MAX, 5174, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9655, UINT16_MAX, 9655, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5175, UINT16_MAX, 5175, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9656, UINT16_MAX, 9656, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5176, UINT16_MAX, 5176, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9657, UINT16_MAX, 9657, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5177, UINT16_MAX, 5177, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9658, UINT16_MAX, 9658, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5178, UINT16_MAX, 5178, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9659, UINT16_MAX, 9659, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9660, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9661, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5179, UINT16_MAX, 5179, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9662, UINT16_MAX, 9662, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5180, UINT16_MAX, 5180, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9663, UINT16_MAX, 9663, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5181, UINT16_MAX, 5181, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9664, UINT16_MAX, 9664, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5182, UINT16_MAX, 5182, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9665, UINT16_MAX, 9665, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5183, UINT16_MAX, 5183, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9666, UINT16_MAX, 9666, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5184, UINT16_MAX, 5184, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9667, UINT16_MAX, 9667, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5185, UINT16_MAX, 5185, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9668, UINT16_MAX, 9668, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5186, UINT16_MAX, 5186, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9669, UINT16_MAX, 9669, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5187, UINT16_MAX, 5187, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9670, UINT16_MAX, 9670, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5188, UINT16_MAX, 5188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9671, UINT16_MAX, 9671, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5189, UINT16_MAX, 5189, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9672, UINT16_MAX, 9672, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5190, UINT16_MAX, 5190, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9673, UINT16_MAX, 9673, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5191, UINT16_MAX, 5191, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9674, UINT16_MAX, 9674, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5192, UINT16_MAX, 5192, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9675, UINT16_MAX, 9675, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5193, UINT16_MAX, 5193, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9676, UINT16_MAX, 9676, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5194, UINT16_MAX, 5194, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9677, UINT16_MAX, 9677, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5195, UINT16_MAX, 5195, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9678, UINT16_MAX, 9678, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5196, UINT16_MAX, 5196, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9679, UINT16_MAX, 9679, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5197, UINT16_MAX, 5197, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9680, UINT16_MAX, 9680, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5198, UINT16_MAX, 5198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9681, UINT16_MAX, 9681, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5199, UINT16_MAX, 5199, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9682, UINT16_MAX, 9682, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5200, UINT16_MAX, 5200, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9683, UINT16_MAX, 9683, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5201, UINT16_MAX, 5201, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9684, UINT16_MAX, 9684, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5202, UINT16_MAX, 5202, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9685, UINT16_MAX, 9685, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5203, UINT16_MAX, 5203, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9686, UINT16_MAX, 9686, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5204, UINT16_MAX, 5204, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9687, UINT16_MAX, 9687, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5205, UINT16_MAX, 5205, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9688, UINT16_MAX, 9688, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5206, UINT16_MAX, 5206, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9689, UINT16_MAX, 9689, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5207, UINT16_MAX, 5207, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9690, UINT16_MAX, 9690, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5208, UINT16_MAX, 5208, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9691, UINT16_MAX, 9691, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5209, UINT16_MAX, 5209, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9692, UINT16_MAX, 9692, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5209, UINT16_MAX, 9693, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9694, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9695, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9696, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9697, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9698, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9699, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9700, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9701, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5210, UINT16_MAX, 5210, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9702, UINT16_MAX, 9702, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5211, UINT16_MAX, 5211, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9703, UINT16_MAX, 9703, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5212, UINT16_MAX, 5212, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5213, UINT16_MAX, 5213, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9704, UINT16_MAX, 9704, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5214, UINT16_MAX, 5214, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9705, UINT16_MAX, 9705, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5215, UINT16_MAX, 5215, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9706, UINT16_MAX, 9706, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5216, UINT16_MAX, 5216, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9707, UINT16_MAX, 9707, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5217, UINT16_MAX, 5217, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9708, UINT16_MAX, 9708, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5218, UINT16_MAX, 5218, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9709, UINT16_MAX, 9709, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1524, UINT16_MAX, 1524, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7066, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5219, UINT16_MAX, 5219, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9710, UINT16_MAX, 9710, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5220, UINT16_MAX, 5220, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9711, UINT16_MAX, 9711, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9712, UINT16_MAX, 9712, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9713, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5221, UINT16_MAX, 5221, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9714, UINT16_MAX, 9714, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5222, UINT16_MAX, 5222, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9715, UINT16_MAX, 9715, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5223, UINT16_MAX, 5223, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9716, UINT16_MAX, 9716, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5224, UINT16_MAX, 5224, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9717, UINT16_MAX, 9717, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5225, UINT16_MAX, 5225, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9718, UINT16_MAX, 9718, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5226, UINT16_MAX, 5226, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9719, UINT16_MAX, 9719, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5227, UINT16_MAX, 5227, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9720, UINT16_MAX, 9720, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5228, UINT16_MAX, 5228, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9721, UINT16_MAX, 9721, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5229, UINT16_MAX, 5229, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9722, UINT16_MAX, 9722, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5230, UINT16_MAX, 5230, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9723, UINT16_MAX, 9723, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 785, UINT16_MAX, 785, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1515, UINT16_MAX, 1515, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1523, UINT16_MAX, 1523, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5231, UINT16_MAX, 5231, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1525, UINT16_MAX, 1525, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9724, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5232, UINT16_MAX, 5232, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5233, UINT16_MAX, 5233, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1527, UINT16_MAX, 1527, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5234, UINT16_MAX, 5234, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5235, UINT16_MAX, 5235, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9725, UINT16_MAX, 9725, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5236, UINT16_MAX, 5236, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9726, UINT16_MAX, 9726, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5237, UINT16_MAX, 5237, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9727, UINT16_MAX, 9727, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5238, UINT16_MAX, 5238, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9728, UINT16_MAX, 9728, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5239, UINT16_MAX, 5239, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9729, UINT16_MAX, 9729, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5240, UINT16_MAX, 5240, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9730, UINT16_MAX, 9730, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5241, UINT16_MAX, 5241, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9731, UINT16_MAX, 9731, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5242, UINT16_MAX, 5242, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9732, UINT16_MAX, 9732, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5243, UINT16_MAX, 5243, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1536, UINT16_MAX, 1536, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5244, UINT16_MAX, 5244, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5245, UINT16_MAX, 5245, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9733, UINT16_MAX, 9733, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5246, UINT16_MAX, 5246, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9734, UINT16_MAX, 9734, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5247, UINT16_MAX, 5247, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9735, UINT16_MAX, 9735, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9736, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9737, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5248, UINT16_MAX, 5248, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9738, UINT16_MAX, 9738, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5249, UINT16_MAX, 5249, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9739, UINT16_MAX, 9739, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2813, UINT16_MAX, 9740, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2838, UINT16_MAX, 9741, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 2827, UINT16_MAX, 9742, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5250, UINT16_MAX, 5250, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9743, UINT16_MAX, 9743, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5251, UINT16_MAX, 9744, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 371, UINT16_MAX, 9745, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9746, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9747, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9748, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9749, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9750, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9751, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9752, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9753, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 5252, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9754, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9755, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9756, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9757, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9758, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9759, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9760, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9761, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9762, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9763, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9764, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9765, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9766, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9767, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9768, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9769, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9770, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9771, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9772, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9773, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9774, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9775, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9776, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9777, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9778, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9779, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 5253, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9780, UINT16_MAX, 9780, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9781, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9782, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9783, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9784, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9785, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9786, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9787, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5174, UINT16_MAX, 9788, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5252, UINT16_MAX, 9789, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3394, UINT16_MAX, 9790, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5253, UINT16_MAX, 9791, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9792, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9793, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9794, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9795, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9796, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9797, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7049, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7081, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9798, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5254, UINT16_MAX, 9799, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5255, 5255, UINT16_MAX, 5255, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5256, 5256, UINT16_MAX, 5256, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5257, 5257, UINT16_MAX, 5257, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5258, 5258, UINT16_MAX, 5258, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5259, 5259, UINT16_MAX, 5259, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5260, 5260, UINT16_MAX, 5260, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5261, 5261, UINT16_MAX, 5261, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5262, 5262, UINT16_MAX, 5262, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5263, 5263, UINT16_MAX, 5263, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5264, 5264, UINT16_MAX, 5264, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5265, 5265, UINT16_MAX, 5265, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5266, 5266, UINT16_MAX, 5266, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5267, 5267, UINT16_MAX, 5267, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5268, 5268, UINT16_MAX, 5268, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5269, 5269, UINT16_MAX, 5269, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5270, 5270, UINT16_MAX, 5270, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5271, 5271, UINT16_MAX, 5271, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5272, 5272, UINT16_MAX, 5272, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5273, 5273, UINT16_MAX, 5273, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5274, 5274, UINT16_MAX, 5274, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5275, 5275, UINT16_MAX, 5275, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5276, 5276, UINT16_MAX, 5276, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5277, 5277, UINT16_MAX, 5277, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5278, 5278, UINT16_MAX, 5278, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5279, 5279, UINT16_MAX, 5279, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5280, 5280, UINT16_MAX, 5280, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5281, 5281, UINT16_MAX, 5281, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5282, 5282, UINT16_MAX, 5282, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5283, 5283, UINT16_MAX, 5283, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5284, 5284, UINT16_MAX, 5284, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5285, 5285, UINT16_MAX, 5285, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5286, 5286, UINT16_MAX, 5286, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5287, 5287, UINT16_MAX, 5287, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5288, 5288, UINT16_MAX, 5288, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5289, 5289, UINT16_MAX, 5289, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5290, 5290, UINT16_MAX, 5290, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5291, 5291, UINT16_MAX, 5291, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5292, 5292, UINT16_MAX, 5292, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5293, 5293, UINT16_MAX, 5293, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5294, 5294, UINT16_MAX, 5294, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5295, 5295, UINT16_MAX, 5295, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5296, 5296, UINT16_MAX, 5296, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5297, 5297, UINT16_MAX, 5297, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5298, 5298, UINT16_MAX, 5298, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5299, 5299, UINT16_MAX, 5299, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5300, 5300, UINT16_MAX, 5300, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5301, 5301, UINT16_MAX, 5301, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5302, 5302, UINT16_MAX, 5302, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5303, 5303, UINT16_MAX, 5303, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5304, 5304, UINT16_MAX, 5304, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5305, 5305, UINT16_MAX, 5305, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5306, 5306, UINT16_MAX, 5306, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5307, 5307, UINT16_MAX, 5307, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5308, 5308, UINT16_MAX, 5308, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5309, 5309, UINT16_MAX, 5309, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5310, 5310, UINT16_MAX, 5310, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5311, 5311, UINT16_MAX, 5311, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5312, 5312, UINT16_MAX, 5312, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5313, 5313, UINT16_MAX, 5313, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5314, 5314, UINT16_MAX, 5314, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5315, 5315, UINT16_MAX, 5315, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5316, 5316, UINT16_MAX, 5316, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5317, 5317, UINT16_MAX, 5317, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5318, 5318, UINT16_MAX, 5318, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5319, 5319, UINT16_MAX, 5319, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5320, 5320, UINT16_MAX, 5320, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5321, 5321, UINT16_MAX, 5321, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5322, 5322, UINT16_MAX, 5322, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5323, 5323, UINT16_MAX, 5323, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5324, 5324, UINT16_MAX, 5324, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5325, 5325, UINT16_MAX, 5325, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5326, 5326, UINT16_MAX, 5326, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5327, 5327, UINT16_MAX, 5327, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5328, 5328, UINT16_MAX, 5328, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5329, 5329, UINT16_MAX, 5329, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5330, 5330, UINT16_MAX, 5330, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5331, 5331, UINT16_MAX, 5331, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5332, 5332, UINT16_MAX, 5332, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5333, 5333, UINT16_MAX, 5333, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5334, 5334, UINT16_MAX, 5334, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_LV}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_LVT}, {UTF8PROC_CATEGORY_CS, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_CO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5337, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5342, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5343, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5345, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5349, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5357, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5363, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5369, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5370, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5371, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5372, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5373, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5375, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5376, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5377, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5378, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5379, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5381, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3584, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5383, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5384, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5385, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5387, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5388, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5389, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5391, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5393, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5394, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5395, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5396, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5397, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5398, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5399, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5400, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5401, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5402, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5403, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5404, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5405, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5406, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5407, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5409, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5411, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5412, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5413, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5414, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5415, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5416, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5417, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5418, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5419, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5420, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5421, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5423, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5424, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5425, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5426, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5427, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5428, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5429, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5430, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5431, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5432, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5433, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5434, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5435, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5436, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5437, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5438, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5439, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5440, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3620, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5441, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5442, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5443, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5444, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5445, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5447, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5448, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5449, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5450, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5451, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5452, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5453, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5454, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5455, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3497, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5456, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5457, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5458, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5459, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5461, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5463, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3478, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5465, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5467, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5469, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5470, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5472, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5473, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5474, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5475, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5477, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5478, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5479, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5480, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5481, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5482, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5484, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5485, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5486, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5487, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5488, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5489, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5490, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5491, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5492, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5493, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5494, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5495, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5496, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5497, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5498, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5499, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5500, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5501, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5503, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5504, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5505, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5506, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5507, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5509, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5510, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5511, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5512, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5513, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5515, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5516, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5517, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5518, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5519, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5520, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5521, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5522, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5524, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5527, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5528, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5529, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 4223, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5530, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5531, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5534, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5535, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5536, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5537, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5539, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5541, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5542, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5543, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5544, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5545, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5546, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5547, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5548, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5549, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5550, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5551, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5552, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5553, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5554, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5555, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5557, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5558, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5560, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5561, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5562, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5563, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5564, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3576, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5565, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5566, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5567, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5568, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5570, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5572, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5574, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5576, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5578, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5580, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3606, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5582, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5584, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5586, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5588, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5590, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5592, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5594, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5595, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5596, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5598, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5602, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5606, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5608, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3504, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5620, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5624, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5627, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5628, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5630, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 4228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5634, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5636, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 4232, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5638, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5639, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5640, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5641, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5642, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5643, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5644, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5645, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5646, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5647, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5648, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5649, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5650, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5651, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5652, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5653, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5654, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5655, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5656, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5657, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5658, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5660, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5664, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5665, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3537, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5701, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5702, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5703, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5704, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5705, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5706, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5707, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5708, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5709, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5710, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5711, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5712, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5713, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5714, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5715, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5716, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5717, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5718, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5719, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5720, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5721, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5723, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5724, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5725, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5726, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5727, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5728, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5729, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5730, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5731, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5733, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5735, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5737, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5739, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5740, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5742, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5744, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5746, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 5747, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22132, 22132, 9800, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22134, 22134, 9801, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22136, 22136, 9802, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 38522, 38522, 9803, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 38525, 38525, 9804, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22144, 22146, 9805, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22146, 22146, 9806, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22148, 22148, 9807, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22150, 22150, 9808, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22152, 22152, 9809, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22154, 22154, 9810, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 22156, 22156, 9811, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22158, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 26, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22160, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5778, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 2840, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 2843, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5779, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5781, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5782, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5783, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, 5784, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_FONT, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22173, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22175, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22185, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22187, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22191, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22193, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22195, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22197, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22199, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22201, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22203, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22205, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22207, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22209, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22211, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22213, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22215, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22217, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22219, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22221, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22223, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22225, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22227, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22229, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, 22231, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_COMPAT, 22233, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5854, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5856, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5861, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5863, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5864, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5864, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5866, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5866, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5867, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5867, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5869, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5869, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5875, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5876, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5876, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5879, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5879, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5882, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5882, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5884, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5884, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5885, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5887, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5887, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5888, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5888, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22275, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22275, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22277, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22277, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22279, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22279, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22281, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22281, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22283, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22283, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22289, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22289, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22289, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 5907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 5907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22292, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22294, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22296, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22298, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22300, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22302, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22304, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22306, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22308, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22310, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22312, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22314, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22316, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22318, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22320, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22322, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22324, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22328, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22330, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22334, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22342, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22370, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22372, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22376, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22378, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22384, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22388, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22394, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22396, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22398, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22400, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22402, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22404, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22406, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22412, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22414, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22416, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22418, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22420, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22424, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22426, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22428, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22430, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22432, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22434, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22436, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22438, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22440, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22442, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22444, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22448, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22450, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22452, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22454, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22456, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22458, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22470, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22472, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22474, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 38877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22496, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22498, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22296, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22500, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22298, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22504, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22306, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22506, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22308, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22310, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22510, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22318, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22512, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22320, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22322, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22516, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22518, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22328, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22330, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22388, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22390, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22396, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22398, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22400, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22412, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22414, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22424, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22426, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22520, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22434, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22522, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22524, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22526, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22448, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22450, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22528, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22530, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22532, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22470, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22292, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22294, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22534, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22296, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22536, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22300, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22302, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22304, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22306, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22312, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22314, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22316, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22318, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22334, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22542, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22366, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22370, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22372, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22376, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22378, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22382, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22384, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22394, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22402, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22404, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22406, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22416, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22418, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22420, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22544, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22428, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22430, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22432, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22434, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22440, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22442, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22444, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22546, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22452, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22454, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22548, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22464, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22550, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22296, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22536, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22306, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22538, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22318, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22540, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22552, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22554, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22558, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22408, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22410, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22422, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22446, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22546, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22550, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 38944, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 38947, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 38950, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22595, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22569, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22571, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22573, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22575, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22577, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22579, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22583, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22587, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22591, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22595, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22599, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22556, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22554, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22558, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 22368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 22370, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 22623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 22623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39009, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39012, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39012, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39015, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39018, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39021, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39024, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39027, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39033, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39036, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39039, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39042, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39045, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39048, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39048, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39051, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39054, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39054, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39057, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39057, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39060, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39063, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39063, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39066, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39069, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39069, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39072, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39072, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39075, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39078, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39078, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39084, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39090, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39093, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39093, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39096, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39099, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39102, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39105, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39111, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39114, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39117, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39120, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39123, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39126, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39126, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39132, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39132, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39135, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39138, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39141, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39144, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39150, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39153, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39156, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39159, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39162, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39165, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39168, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39174, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39180, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39186, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39192, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39195, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39198, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39201, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39204, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39207, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39210, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39213, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39216, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39219, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39222, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39225, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39231, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39234, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39237, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39240, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39243, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39246, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39249, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39111, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39117, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39252, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39255, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39258, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39261, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39264, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39267, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39264, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39258, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39270, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39273, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39276, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39279, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39282, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39267, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39090, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 39060, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 39288, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 39291, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 39294, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55701, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55706, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55711, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 39332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55719, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 55747, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6602, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6606, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6607, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6608, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6618, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6619, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6620, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 3067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 3068, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6623, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6624, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, 6626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 6627, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, 6612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, 6600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, 2762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, 6603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6610, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6616, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, 6628, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6630, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SMALL, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SMALL, 6631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 2802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6634, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, 6635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, 6636, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, 6637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23022, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23024, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23026, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23028, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23032, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23034, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23036, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23038, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23040, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23042, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23044, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23046, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 23048, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 5890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 5890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23085, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 23085, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 23087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23089, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 23089, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, 23091, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, 23091, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6709, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6628, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6635, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6636, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6629, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6710, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 2803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 2804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6630, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_WIDE, 2800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, 6600, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_WIDE, 6631, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, 2762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, 6711, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, 6603, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6632, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 2802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6633, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6637, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1491, 6712, UINT16_MAX, 6712, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1493, 6713, UINT16_MAX, 6713, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2813, 6714, UINT16_MAX, 6714, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1494, 6715, UINT16_MAX, 6715, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1495, 6716, UINT16_MAX, 6716, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2838, 6717, UINT16_MAX, 6717, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1497, 6718, UINT16_MAX, 6718, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1498, 6719, UINT16_MAX, 6719, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1499, 6720, UINT16_MAX, 6720, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1500, 6721, UINT16_MAX, 6721, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1501, 6722, UINT16_MAX, 6722, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1502, 6723, UINT16_MAX, 6723, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1503, 6724, UINT16_MAX, 6724, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1504, 6725, UINT16_MAX, 6725, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1505, 6726, UINT16_MAX, 6726, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1507, 6727, UINT16_MAX, 6727, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2827, 6728, UINT16_MAX, 6728, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1508, 6729, UINT16_MAX, 6729, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 3320, 6730, UINT16_MAX, 6730, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1509, 6731, UINT16_MAX, 6731, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1510, 6732, UINT16_MAX, 6732, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2910, 6733, UINT16_MAX, 6733, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1511, 6734, UINT16_MAX, 6734, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2928, 6735, UINT16_MAX, 6735, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 3327, 6736, UINT16_MAX, 6736, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2835, 6737, UINT16_MAX, 6737, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6634, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6626, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6738, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6612, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 2722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 0, UINT16_MAX, 9812, UINT16_MAX, 9812, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 1, UINT16_MAX, 9813, UINT16_MAX, 9813, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 2, UINT16_MAX, 9814, UINT16_MAX, 9814, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 3, UINT16_MAX, 9815, UINT16_MAX, 9815, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 4, UINT16_MAX, 9816, UINT16_MAX, 9816, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 5, UINT16_MAX, 9817, UINT16_MAX, 9817, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 6, UINT16_MAX, 9818, UINT16_MAX, 9818, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 7, UINT16_MAX, 9819, UINT16_MAX, 9819, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 8, UINT16_MAX, 9820, UINT16_MAX, 9820, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 9, UINT16_MAX, 9821, UINT16_MAX, 9821, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 10, UINT16_MAX, 9822, UINT16_MAX, 9822, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 11, UINT16_MAX, 9823, UINT16_MAX, 9823, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 12, UINT16_MAX, 9824, UINT16_MAX, 9824, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 13, UINT16_MAX, 9825, UINT16_MAX, 9825, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 14, UINT16_MAX, 9826, UINT16_MAX, 9826, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 15, UINT16_MAX, 9827, UINT16_MAX, 9827, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 16, UINT16_MAX, 9828, UINT16_MAX, 9828, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 17, UINT16_MAX, 9829, UINT16_MAX, 9829, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 18, UINT16_MAX, 9830, UINT16_MAX, 9830, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 19, UINT16_MAX, 9831, UINT16_MAX, 9831, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 20, UINT16_MAX, 9832, UINT16_MAX, 9832, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 21, UINT16_MAX, 9833, UINT16_MAX, 9833, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 22, UINT16_MAX, 9834, UINT16_MAX, 9834, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 23, UINT16_MAX, 9835, UINT16_MAX, 9835, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 24, UINT16_MAX, 9836, UINT16_MAX, 9836, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, 25, UINT16_MAX, 9837, UINT16_MAX, 9837, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6739, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6614, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6740, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6741, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6742, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6602, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6622, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6743, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4367, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6744, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6745, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6746, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6747, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6748, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6749, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6750, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6751, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6752, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6753, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4321, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4322, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4323, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4324, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4325, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4327, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4328, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4329, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4330, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4331, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4333, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4334, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4336, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4337, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4340, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4342, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4343, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4345, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4346, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4348, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4349, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4351, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4352, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4354, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4355, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4357, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4358, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4360, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4361, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4363, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 4364, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6754, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6755, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6756, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6757, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, true, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6758, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6759, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6760, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6763, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6764, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6765, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6766, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6767, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6768, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6769, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6770, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6771, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6772, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6773, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6774, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6775, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6776, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6777, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6778, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6779, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6781, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6782, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6783, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6784, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6785, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6786, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6787, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6788, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6789, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6790, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6791, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6792, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6805, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6806, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6807, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, 6808, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6812, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, 6813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, 6815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6816, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6818, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, 6822, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6823, UINT16_MAX, 6823, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6825, UINT16_MAX, 6825, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6827, UINT16_MAX, 6827, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6829, UINT16_MAX, 6829, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6831, UINT16_MAX, 6831, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6833, UINT16_MAX, 6833, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6835, UINT16_MAX, 6835, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6837, UINT16_MAX, 6837, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6839, UINT16_MAX, 6839, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6841, UINT16_MAX, 6841, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6843, UINT16_MAX, 6843, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6845, UINT16_MAX, 6845, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6847, UINT16_MAX, 6847, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6849, UINT16_MAX, 6849, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6851, UINT16_MAX, 6851, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6853, UINT16_MAX, 6853, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6855, UINT16_MAX, 6855, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6857, UINT16_MAX, 6857, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6859, UINT16_MAX, 6859, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6861, UINT16_MAX, 6861, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6863, UINT16_MAX, 6863, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6865, UINT16_MAX, 6865, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6867, UINT16_MAX, 6867, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6869, UINT16_MAX, 6869, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6871, UINT16_MAX, 6871, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6873, UINT16_MAX, 6873, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6875, UINT16_MAX, 6875, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6877, UINT16_MAX, 6877, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6879, UINT16_MAX, 6879, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6881, UINT16_MAX, 6881, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6883, UINT16_MAX, 6883, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6885, UINT16_MAX, 6885, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6887, UINT16_MAX, 6887, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6889, UINT16_MAX, 6889, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6891, UINT16_MAX, 6891, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6893, UINT16_MAX, 6893, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6895, UINT16_MAX, 6895, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6897, UINT16_MAX, 6897, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6899, UINT16_MAX, 6899, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6901, UINT16_MAX, 6901, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9838, UINT16_MAX, 9838, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9840, UINT16_MAX, 9840, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9842, UINT16_MAX, 9842, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9844, UINT16_MAX, 9844, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9846, UINT16_MAX, 9846, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9848, UINT16_MAX, 9848, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9850, UINT16_MAX, 9850, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9852, UINT16_MAX, 9852, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9854, UINT16_MAX, 9854, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9856, UINT16_MAX, 9856, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9858, UINT16_MAX, 9858, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9860, UINT16_MAX, 9860, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9862, UINT16_MAX, 9862, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9864, UINT16_MAX, 9864, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9866, UINT16_MAX, 9866, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9868, UINT16_MAX, 9868, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9870, UINT16_MAX, 9870, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9872, UINT16_MAX, 9872, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9874, UINT16_MAX, 9874, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9876, UINT16_MAX, 9876, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9878, UINT16_MAX, 9878, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9880, UINT16_MAX, 9880, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9882, UINT16_MAX, 9882, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9884, UINT16_MAX, 9884, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9886, UINT16_MAX, 9886, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9888, UINT16_MAX, 9888, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9890, UINT16_MAX, 9890, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9892, UINT16_MAX, 9892, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9894, UINT16_MAX, 9894, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9896, UINT16_MAX, 9896, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9898, UINT16_MAX, 9898, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9900, UINT16_MAX, 9900, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9902, UINT16_MAX, 9902, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9904, UINT16_MAX, 9904, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9906, UINT16_MAX, 9906, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9908, UINT16_MAX, 9908, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9910, UINT16_MAX, 9910, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9912, UINT16_MAX, 9912, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9914, UINT16_MAX, 9914, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9916, UINT16_MAX, 9916, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6903, UINT16_MAX, 6903, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6905, UINT16_MAX, 6905, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6907, UINT16_MAX, 6907, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6909, UINT16_MAX, 6909, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6911, UINT16_MAX, 6911, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6913, UINT16_MAX, 6913, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6915, UINT16_MAX, 6915, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6917, UINT16_MAX, 6917, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6919, UINT16_MAX, 6919, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6921, UINT16_MAX, 6921, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6923, UINT16_MAX, 6923, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6925, UINT16_MAX, 6925, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6927, UINT16_MAX, 6927, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6929, UINT16_MAX, 6929, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6931, UINT16_MAX, 6931, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6933, UINT16_MAX, 6933, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6935, UINT16_MAX, 6935, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6937, UINT16_MAX, 6937, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6939, UINT16_MAX, 6939, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6941, UINT16_MAX, 6941, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6943, UINT16_MAX, 6943, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6945, UINT16_MAX, 6945, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6947, UINT16_MAX, 6947, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6949, UINT16_MAX, 6949, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6951, UINT16_MAX, 6951, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6953, UINT16_MAX, 6953, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6955, UINT16_MAX, 6955, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6957, UINT16_MAX, 6957, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6959, UINT16_MAX, 6959, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6961, UINT16_MAX, 6961, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6963, UINT16_MAX, 6963, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6965, UINT16_MAX, 6965, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6967, UINT16_MAX, 6967, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6969, UINT16_MAX, 6969, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6971, UINT16_MAX, 6971, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6973, UINT16_MAX, 6973, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9918, UINT16_MAX, 9918, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9920, UINT16_MAX, 9920, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9922, UINT16_MAX, 9922, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9924, UINT16_MAX, 9924, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9926, UINT16_MAX, 9926, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9928, UINT16_MAX, 9928, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9930, UINT16_MAX, 9930, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9932, UINT16_MAX, 9932, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9934, UINT16_MAX, 9934, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9936, UINT16_MAX, 9936, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9938, UINT16_MAX, 9938, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9940, UINT16_MAX, 9940, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9942, UINT16_MAX, 9942, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9944, UINT16_MAX, 9944, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9946, UINT16_MAX, 9946, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9948, UINT16_MAX, 9948, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9950, UINT16_MAX, 9950, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9952, UINT16_MAX, 9952, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9954, UINT16_MAX, 9954, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9956, UINT16_MAX, 9956, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9958, UINT16_MAX, 9958, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9960, UINT16_MAX, 9960, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9962, UINT16_MAX, 9962, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9964, UINT16_MAX, 9964, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9966, UINT16_MAX, 9966, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9968, UINT16_MAX, 9968, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9970, UINT16_MAX, 9970, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9972, UINT16_MAX, 9972, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9974, UINT16_MAX, 9974, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9976, UINT16_MAX, 9976, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9978, UINT16_MAX, 9978, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9980, UINT16_MAX, 9980, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9982, UINT16_MAX, 9982, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9984, UINT16_MAX, 9984, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9986, UINT16_MAX, 9986, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9988, UINT16_MAX, 9988, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6975, UINT16_MAX, 6975, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6977, UINT16_MAX, 6977, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6979, UINT16_MAX, 6979, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6981, UINT16_MAX, 6981, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6983, UINT16_MAX, 6983, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6985, UINT16_MAX, 6985, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6987, UINT16_MAX, 6987, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6989, UINT16_MAX, 6989, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6991, UINT16_MAX, 6991, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6993, UINT16_MAX, 6993, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6995, UINT16_MAX, 6995, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6997, UINT16_MAX, 6997, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6999, UINT16_MAX, 6999, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7001, UINT16_MAX, 7001, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7003, UINT16_MAX, 7003, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7005, UINT16_MAX, 7005, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7007, UINT16_MAX, 7007, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7009, UINT16_MAX, 7009, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7011, UINT16_MAX, 7011, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7013, UINT16_MAX, 7013, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7015, UINT16_MAX, 7015, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7017, UINT16_MAX, 7017, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7019, UINT16_MAX, 7019, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7021, UINT16_MAX, 7021, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7023, UINT16_MAX, 7023, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7025, UINT16_MAX, 7025, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7027, UINT16_MAX, 7027, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7029, UINT16_MAX, 7029, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7031, UINT16_MAX, 7031, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7033, UINT16_MAX, 7033, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7035, UINT16_MAX, 7035, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7037, UINT16_MAX, 7037, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7039, UINT16_MAX, 7039, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7041, UINT16_MAX, 7041, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7043, UINT16_MAX, 7043, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9990, UINT16_MAX, 9990, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9992, UINT16_MAX, 9992, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9994, UINT16_MAX, 9994, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9996, UINT16_MAX, 9996, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9998, UINT16_MAX, 9998, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10000, UINT16_MAX, 10000, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10002, UINT16_MAX, 10002, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10004, UINT16_MAX, 10004, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10006, UINT16_MAX, 10006, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10008, UINT16_MAX, 10008, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10010, UINT16_MAX, 10010, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10012, UINT16_MAX, 10012, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10014, UINT16_MAX, 10014, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10016, UINT16_MAX, 10016, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10018, UINT16_MAX, 10018, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10020, UINT16_MAX, 10020, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10022, UINT16_MAX, 10022, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10024, UINT16_MAX, 10024, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10026, UINT16_MAX, 10026, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10028, UINT16_MAX, 10028, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10030, UINT16_MAX, 10030, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10032, UINT16_MAX, 10032, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10034, UINT16_MAX, 10034, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10036, UINT16_MAX, 10036, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10038, UINT16_MAX, 10038, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10040, UINT16_MAX, 10040, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10042, UINT16_MAX, 10042, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10044, UINT16_MAX, 10044, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10046, UINT16_MAX, 10046, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10048, UINT16_MAX, 10048, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10050, UINT16_MAX, 10050, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10052, UINT16_MAX, 10052, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10054, UINT16_MAX, 10054, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10056, UINT16_MAX, 10056, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10058, UINT16_MAX, 10058, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10060, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7045, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7046, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 66, UINT16_MAX, 10062, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7047, UINT16_MAX, 10064, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 476, UINT16_MAX, 10066, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7048, UINT16_MAX, 10068, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7049, UINT16_MAX, 10070, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7050, UINT16_MAX, 10072, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7051, UINT16_MAX, 10074, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 481, UINT16_MAX, 10076, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 482, UINT16_MAX, 10078, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7052, UINT16_MAX, 10080, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7053, UINT16_MAX, 10082, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7054, UINT16_MAX, 10084, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7055, UINT16_MAX, 10086, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7056, UINT16_MAX, 10088, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7057, UINT16_MAX, 10090, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 488, UINT16_MAX, 10092, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7058, UINT16_MAX, 10094, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 277, UINT16_MAX, 10096, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7059, UINT16_MAX, 10098, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7060, UINT16_MAX, 10100, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7061, UINT16_MAX, 10102, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7062, UINT16_MAX, 10104, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7063, UINT16_MAX, 10106, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5231, UINT16_MAX, 10108, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7064, UINT16_MAX, 10110, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7066, UINT16_MAX, 10112, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7067, UINT16_MAX, 10114, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7068, UINT16_MAX, 10116, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7070, UINT16_MAX, 10118, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7071, UINT16_MAX, 10120, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 113, UINT16_MAX, 10122, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7073, UINT16_MAX, 10124, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7074, UINT16_MAX, 10126, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 16, UINT16_MAX, 10128, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7075, UINT16_MAX, 10130, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7076, UINT16_MAX, 10132, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 3396, UINT16_MAX, 10134, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7078, UINT16_MAX, 10136, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 503, UINT16_MAX, 10138, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7079, UINT16_MAX, 10140, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7080, UINT16_MAX, 10142, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7081, UINT16_MAX, 10144, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7082, UINT16_MAX, 10146, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 507, UINT16_MAX, 10148, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7083, UINT16_MAX, 10150, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7084, UINT16_MAX, 10152, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7085, UINT16_MAX, 10154, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7086, UINT16_MAX, 10156, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7087, UINT16_MAX, 10158, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7088, UINT16_MAX, 10160, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7089, UINT16_MAX, 10162, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7090, UINT16_MAX, 10164, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7091, UINT16_MAX, 10166, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 7093, UINT16_MAX, 10168, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7095, UINT16_MAX, 7095, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7097, UINT16_MAX, 7097, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7099, UINT16_MAX, 7099, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7101, UINT16_MAX, 7101, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7103, UINT16_MAX, 7103, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7105, UINT16_MAX, 7105, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7107, UINT16_MAX, 7107, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7109, UINT16_MAX, 7109, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7111, UINT16_MAX, 7111, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7113, UINT16_MAX, 7113, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7115, UINT16_MAX, 7115, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7117, UINT16_MAX, 7117, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7119, UINT16_MAX, 7119, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7121, UINT16_MAX, 7121, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7123, UINT16_MAX, 7123, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7125, UINT16_MAX, 7125, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7127, UINT16_MAX, 7127, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7129, UINT16_MAX, 7129, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7131, UINT16_MAX, 7131, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7133, UINT16_MAX, 7133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7135, UINT16_MAX, 7135, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7137, UINT16_MAX, 7137, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7139, UINT16_MAX, 7139, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7141, UINT16_MAX, 7141, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7143, UINT16_MAX, 7143, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7145, UINT16_MAX, 7145, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7147, UINT16_MAX, 7147, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7149, UINT16_MAX, 7149, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7151, UINT16_MAX, 7151, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7153, UINT16_MAX, 7153, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7155, UINT16_MAX, 7155, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7157, UINT16_MAX, 7157, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7159, UINT16_MAX, 7159, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7161, UINT16_MAX, 7161, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7163, UINT16_MAX, 7163, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7165, UINT16_MAX, 7165, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7167, UINT16_MAX, 7167, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7169, UINT16_MAX, 7169, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7171, UINT16_MAX, 7171, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7173, UINT16_MAX, 7173, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7175, UINT16_MAX, 7175, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7177, UINT16_MAX, 7177, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7179, UINT16_MAX, 7179, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7181, UINT16_MAX, 7181, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7183, UINT16_MAX, 7183, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7185, UINT16_MAX, 7185, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7187, UINT16_MAX, 7187, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7189, UINT16_MAX, 7189, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7191, UINT16_MAX, 7191, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7193, UINT16_MAX, 7193, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7195, UINT16_MAX, 7195, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10170, UINT16_MAX, 10170, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10172, UINT16_MAX, 10172, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10174, UINT16_MAX, 10174, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10176, UINT16_MAX, 10176, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10178, UINT16_MAX, 10178, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10180, UINT16_MAX, 10180, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10182, UINT16_MAX, 10182, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10184, UINT16_MAX, 10184, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10186, UINT16_MAX, 10186, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10188, UINT16_MAX, 10188, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10190, UINT16_MAX, 10190, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10192, UINT16_MAX, 10192, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10194, UINT16_MAX, 10194, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10196, UINT16_MAX, 10196, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10198, UINT16_MAX, 10198, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10200, UINT16_MAX, 10200, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10202, UINT16_MAX, 10202, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10204, UINT16_MAX, 10204, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10206, UINT16_MAX, 10206, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10208, UINT16_MAX, 10208, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10210, UINT16_MAX, 10210, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10212, UINT16_MAX, 10212, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10214, UINT16_MAX, 10214, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10216, UINT16_MAX, 10216, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10218, UINT16_MAX, 10218, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10220, UINT16_MAX, 10220, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10222, UINT16_MAX, 10222, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10224, UINT16_MAX, 10224, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10226, UINT16_MAX, 10226, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10228, UINT16_MAX, 10228, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10230, UINT16_MAX, 10230, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10232, UINT16_MAX, 10232, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10234, UINT16_MAX, 10234, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10236, UINT16_MAX, 10236, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10238, UINT16_MAX, 10238, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10240, UINT16_MAX, 10240, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10242, UINT16_MAX, 10242, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10244, UINT16_MAX, 10244, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10246, UINT16_MAX, 10246, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10248, UINT16_MAX, 10248, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10250, UINT16_MAX, 10250, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10252, UINT16_MAX, 10252, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10254, UINT16_MAX, 10254, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10256, UINT16_MAX, 10256, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10258, UINT16_MAX, 10258, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10260, UINT16_MAX, 10260, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10262, UINT16_MAX, 10262, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10264, UINT16_MAX, 10264, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10266, UINT16_MAX, 10266, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10268, UINT16_MAX, 10268, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 10270, UINT16_MAX, 10270, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_AN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_AL, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5328, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23581, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5332, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23585, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5336, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23589, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MN, 7, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49206, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_PREPEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49208, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 23593, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, 23597, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5340, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5344, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49210, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5348, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23601, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23605, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49212, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49216, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5354, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49214, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23609, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23613, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49218, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23617, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49220, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5362, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5366, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23621, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23625, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7245, UINT16_MAX, 7245, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7247, UINT16_MAX, 7247, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7249, UINT16_MAX, 7249, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7251, UINT16_MAX, 7251, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7253, UINT16_MAX, 7253, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7255, UINT16_MAX, 7255, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7257, UINT16_MAX, 7257, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7259, UINT16_MAX, 7259, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7261, UINT16_MAX, 7261, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7263, UINT16_MAX, 7263, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7265, UINT16_MAX, 7265, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7267, UINT16_MAX, 7267, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7269, UINT16_MAX, 7269, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7271, UINT16_MAX, 7271, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7273, UINT16_MAX, 7273, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7275, UINT16_MAX, 7275, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7277, UINT16_MAX, 7277, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7279, UINT16_MAX, 7279, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7281, UINT16_MAX, 7281, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7283, UINT16_MAX, 7283, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7285, UINT16_MAX, 7285, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7287, UINT16_MAX, 7287, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7289, UINT16_MAX, 7289, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7291, UINT16_MAX, 7291, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7293, UINT16_MAX, 7293, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7295, UINT16_MAX, 7295, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7297, UINT16_MAX, 7297, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7299, UINT16_MAX, 7299, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7301, UINT16_MAX, 7301, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7303, UINT16_MAX, 7303, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7305, UINT16_MAX, 7305, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7307, UINT16_MAX, 7307, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10272, UINT16_MAX, 10272, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10274, UINT16_MAX, 10274, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10276, UINT16_MAX, 10276, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10278, UINT16_MAX, 10278, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10280, UINT16_MAX, 10280, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10282, UINT16_MAX, 10282, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10284, UINT16_MAX, 10284, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10286, UINT16_MAX, 10286, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10288, UINT16_MAX, 10288, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10290, UINT16_MAX, 10290, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10292, UINT16_MAX, 10292, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10294, UINT16_MAX, 10294, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10296, UINT16_MAX, 10296, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10298, UINT16_MAX, 10298, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10300, UINT16_MAX, 10300, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10302, UINT16_MAX, 10302, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10304, UINT16_MAX, 10304, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10306, UINT16_MAX, 10306, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10308, UINT16_MAX, 10308, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10310, UINT16_MAX, 10310, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10312, UINT16_MAX, 10312, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10314, UINT16_MAX, 10314, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10316, UINT16_MAX, 10316, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10318, UINT16_MAX, 10318, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10320, UINT16_MAX, 10320, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10322, UINT16_MAX, 10322, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10324, UINT16_MAX, 10324, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10326, UINT16_MAX, 10326, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10328, UINT16_MAX, 10328, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10330, UINT16_MAX, 10330, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10332, UINT16_MAX, 10332, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10334, UINT16_MAX, 10334, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49222, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5370, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, 23693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7313, UINT16_MAX, 7313, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7315, UINT16_MAX, 7315, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7317, UINT16_MAX, 7317, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7319, UINT16_MAX, 7319, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7321, UINT16_MAX, 7321, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7323, UINT16_MAX, 7323, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7325, UINT16_MAX, 7325, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7327, UINT16_MAX, 7327, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7329, UINT16_MAX, 7329, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7331, UINT16_MAX, 7331, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7333, UINT16_MAX, 7333, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7335, UINT16_MAX, 7335, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7337, UINT16_MAX, 7337, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7339, UINT16_MAX, 7339, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7341, UINT16_MAX, 7341, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7343, UINT16_MAX, 7343, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7345, UINT16_MAX, 7345, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7347, UINT16_MAX, 7347, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7349, UINT16_MAX, 7349, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7351, UINT16_MAX, 7351, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7353, UINT16_MAX, 7353, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7355, UINT16_MAX, 7355, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7357, UINT16_MAX, 7357, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7359, UINT16_MAX, 7359, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7361, UINT16_MAX, 7361, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7363, UINT16_MAX, 7363, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7365, UINT16_MAX, 7365, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7367, UINT16_MAX, 7367, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7369, UINT16_MAX, 7369, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7371, UINT16_MAX, 7371, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7373, UINT16_MAX, 7373, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 7375, UINT16_MAX, 7375, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10336, UINT16_MAX, 10336, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10338, UINT16_MAX, 10338, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10340, UINT16_MAX, 10340, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10342, UINT16_MAX, 10342, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10344, UINT16_MAX, 10344, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10346, UINT16_MAX, 10346, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10348, UINT16_MAX, 10348, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10350, UINT16_MAX, 10350, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10352, UINT16_MAX, 10352, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10354, UINT16_MAX, 10354, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10356, UINT16_MAX, 10356, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10358, UINT16_MAX, 10358, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10360, UINT16_MAX, 10360, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10362, UINT16_MAX, 10362, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10364, UINT16_MAX, 10364, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10366, UINT16_MAX, 10366, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10368, UINT16_MAX, 10368, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10370, UINT16_MAX, 10370, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10372, UINT16_MAX, 10372, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10374, UINT16_MAX, 10374, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10376, UINT16_MAX, 10376, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10378, UINT16_MAX, 10378, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10380, UINT16_MAX, 10380, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10382, UINT16_MAX, 10382, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10384, UINT16_MAX, 10384, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10386, UINT16_MAX, 10386, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10388, UINT16_MAX, 10388, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10390, UINT16_MAX, 10390, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10392, UINT16_MAX, 10392, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10394, UINT16_MAX, 10394, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10396, UINT16_MAX, 10396, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 10398, UINT16_MAX, 10398, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 6, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5374, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5378, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23765, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5382, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23769, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23773, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23777, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23781, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23785, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49224, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 226, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_SPACINGMARK}, {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49226, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49228, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49230, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49232, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 49234, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5394, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5398, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23789, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5402, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, 5408, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23805, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, 23809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10402, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10404, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10410, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10412, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 10414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 10416, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10418, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10420, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10422, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10424, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10426, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10428, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10430, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10432, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 10434, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10436, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10438, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10440, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10442, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10444, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10446, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10448, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10450, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10452, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10454, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10456, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10458, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10460, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10462, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10464, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10466, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10468, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10470, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10472, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10474, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10476, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10478, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10480, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10482, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10484, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10486, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10488, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10490, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10492, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10494, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10496, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10498, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10500, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10502, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10504, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10506, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10508, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10510, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10512, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10514, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10516, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 10518, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 10520, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10522, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10524, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10526, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10528, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10530, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10532, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10534, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10536, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 10538, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10540, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10542, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10544, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10546, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10548, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10550, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10552, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10554, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10556, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10558, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10560, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10562, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10564, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10566, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10568, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10570, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10572, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10574, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10576, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10578, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10580, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10582, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10584, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10586, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10588, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10590, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10592, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10594, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10596, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10598, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10600, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10602, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10604, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10606, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10608, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10610, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10612, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10614, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10616, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10618, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 10620, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 10622, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10624, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10626, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10628, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10630, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10632, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10634, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10638, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 10640, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10642, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10644, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10646, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10648, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10650, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10652, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10654, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10656, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10658, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10660, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10662, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10664, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10666, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10668, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10670, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10672, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10674, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10676, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10678, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10680, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10682, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10684, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10686, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10688, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10690, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10692, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10694, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10696, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10698, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10700, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10702, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10704, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10706, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10708, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10710, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10712, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10714, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10716, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10718, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10720, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10722, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10724, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10726, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10728, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10730, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10732, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10734, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10736, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10738, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10740, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10742, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10744, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10746, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10748, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10750, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10752, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10754, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10756, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10758, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10760, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10762, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10764, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10766, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10768, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10770, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10772, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10774, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10776, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10778, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10780, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10782, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10784, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10786, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10788, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10790, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10792, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10794, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 10796, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10798, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10800, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10802, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10804, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 10806, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 10808, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10810, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10812, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10814, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10816, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10818, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10820, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10822, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10824, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 10826, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10828, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10830, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10832, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10834, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10836, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10838, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10840, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 10842, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10844, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10846, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10848, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10850, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10852, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10854, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10856, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10858, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10860, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10862, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10864, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10866, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10868, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10870, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10872, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10874, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10876, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10878, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10880, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10882, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10884, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10886, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10888, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10890, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10892, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10894, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10896, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10898, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10900, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10902, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10904, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 10906, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 10908, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 10910, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 10912, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 10914, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 10916, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 10918, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 10920, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 10922, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 10924, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 10926, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 10928, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 10930, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 10932, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 10934, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 10936, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 10938, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 10940, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 10942, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 10944, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 10946, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 10948, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 10950, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 10952, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 10954, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 10956, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 10958, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 10960, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 10962, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 10964, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 10966, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 10968, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 10970, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 10972, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 10974, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 10976, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 10978, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 10980, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 10982, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 10984, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 10986, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 10988, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 10990, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 10992, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 10994, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 10996, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 10998, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11000, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11002, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11004, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11006, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11008, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11010, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11012, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11014, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11016, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11018, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11020, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11022, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11024, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11026, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11028, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11030, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11032, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11034, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11036, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11038, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11040, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11042, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11044, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11046, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11048, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11050, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11052, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11054, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11056, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11058, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11060, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11062, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11064, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11066, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11068, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11070, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11072, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11074, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11076, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11078, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11080, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11082, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11084, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11086, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11088, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11090, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11092, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11094, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11096, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11098, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11100, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11102, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11104, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11106, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11108, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11110, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11112, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11114, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11116, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11118, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11120, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11122, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11124, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11126, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11128, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11130, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11132, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11134, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11136, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11138, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11140, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11142, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11144, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11146, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11148, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11150, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11152, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11154, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11156, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11158, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11160, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11162, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11164, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11166, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11168, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11170, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11172, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11174, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11176, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11178, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11180, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11182, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11184, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11186, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11190, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11192, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11194, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11196, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11200, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11202, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11204, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11206, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11208, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11210, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11212, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11214, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11216, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11218, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11220, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11222, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11224, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11226, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11228, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11230, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11232, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11234, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11236, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11238, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11240, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11242, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11244, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11246, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11248, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11250, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11252, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11254, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11256, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11258, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11260, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11262, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11264, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11266, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11268, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11270, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11272, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11274, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11276, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11278, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11280, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11282, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11284, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11286, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11288, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11290, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11292, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11294, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11296, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11298, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11300, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11302, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11304, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11306, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11308, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11310, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11312, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11314, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11316, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11318, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11320, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11322, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11324, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11326, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11328, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11330, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11332, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11334, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11336, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11338, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11340, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11342, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11344, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11346, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11348, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11350, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11352, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11354, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11356, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11358, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11360, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11362, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11364, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11366, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11368, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11370, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11372, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11374, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11376, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11378, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11380, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11382, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11384, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11386, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11388, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11390, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11392, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11394, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11396, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11398, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11400, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11402, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11404, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11406, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11408, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11410, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11412, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11414, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11416, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11418, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11420, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11422, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11424, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11426, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11428, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11430, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11432, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11434, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11436, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11438, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11440, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11442, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11444, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11446, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11448, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11450, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11452, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11454, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11456, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11458, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11460, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11462, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11464, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11466, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11468, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11470, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11472, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11474, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11476, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11478, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11480, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11482, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11484, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11486, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11488, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11490, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11492, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11494, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11496, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11498, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11500, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11502, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11504, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11506, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11508, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11510, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11512, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11514, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11516, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11518, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11520, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11522, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11524, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11526, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11528, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11530, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11532, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11534, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11536, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11538, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11540, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11542, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11544, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11546, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11548, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11550, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11552, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11554, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11556, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11558, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11560, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11562, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11564, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11566, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11568, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11570, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11572, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11574, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11576, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11578, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11580, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11582, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11584, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11586, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11588, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11590, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11592, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11594, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11596, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11598, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1491, UINT16_MAX, UINT16_MAX, 11600, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1493, UINT16_MAX, UINT16_MAX, 11602, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2813, UINT16_MAX, UINT16_MAX, 11604, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1494, UINT16_MAX, UINT16_MAX, 11606, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1495, UINT16_MAX, UINT16_MAX, 11608, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2838, UINT16_MAX, UINT16_MAX, 11610, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1497, UINT16_MAX, UINT16_MAX, 11612, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1498, UINT16_MAX, UINT16_MAX, 11614, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1499, UINT16_MAX, UINT16_MAX, 11616, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1500, UINT16_MAX, UINT16_MAX, 11618, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1501, UINT16_MAX, UINT16_MAX, 11620, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1502, UINT16_MAX, UINT16_MAX, 11622, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1503, UINT16_MAX, UINT16_MAX, 11624, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1504, UINT16_MAX, UINT16_MAX, 11626, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1505, UINT16_MAX, UINT16_MAX, 11628, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1507, UINT16_MAX, UINT16_MAX, 11630, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2827, UINT16_MAX, UINT16_MAX, 11632, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1508, UINT16_MAX, UINT16_MAX, 11634, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3320, UINT16_MAX, UINT16_MAX, 11636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1509, UINT16_MAX, UINT16_MAX, 11638, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1510, UINT16_MAX, UINT16_MAX, 11640, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2910, UINT16_MAX, UINT16_MAX, 11642, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1511, UINT16_MAX, UINT16_MAX, 11644, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2928, UINT16_MAX, UINT16_MAX, 11646, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3327, UINT16_MAX, UINT16_MAX, 11648, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2835, UINT16_MAX, UINT16_MAX, 11650, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 0, UINT16_MAX, 11652, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 1, UINT16_MAX, 11654, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2, UINT16_MAX, 11656, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 3, UINT16_MAX, 11658, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 4, UINT16_MAX, 11660, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 5, UINT16_MAX, 11662, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 6, UINT16_MAX, 11664, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7, UINT16_MAX, 11666, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 8, UINT16_MAX, 11668, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 9, UINT16_MAX, 11670, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 10, UINT16_MAX, 11672, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 11, UINT16_MAX, 11674, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 12, UINT16_MAX, 11676, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 13, UINT16_MAX, 11678, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 14, UINT16_MAX, 11680, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 15, UINT16_MAX, 11682, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 16, UINT16_MAX, 11684, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 17, UINT16_MAX, 11686, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 18, UINT16_MAX, 11688, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 19, UINT16_MAX, 11690, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 20, UINT16_MAX, 11692, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 21, UINT16_MAX, 11694, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 22, UINT16_MAX, 11696, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 23, UINT16_MAX, 11698, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 24, UINT16_MAX, 11700, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 25, UINT16_MAX, 11702, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7429, UINT16_MAX, 11704, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7430, UINT16_MAX, 11706, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 11708, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 11710, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 11712, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 11714, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 11716, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 11718, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 11720, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 11722, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 11724, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 11726, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 11728, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 11730, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 11732, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 11734, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 11736, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 11738, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 11740, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 11742, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 11744, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 11746, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 11748, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 11750, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 11752, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 11754, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 11756, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7450, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 11758, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 11760, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 11762, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 11764, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 11766, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 11768, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 11770, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 11772, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 11774, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 11776, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 11778, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 11780, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 11782, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 11784, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 11786, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 11788, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 11790, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 11792, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 11794, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 11796, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 11798, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 11800, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 11802, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 11804, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 11806, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FONT, 7451, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 11808, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 11810, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 11812, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 11814, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 11816, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 11818, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 11820, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 11822, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 11824, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 11826, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 11828, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 11830, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 11832, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 11834, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 11836, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 11838, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 11840, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 11842, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 11844, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 11846, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 11848, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 11850, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 11852, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 11854, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 11856, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 11858, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 11860, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 11862, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 11864, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 11866, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 11868, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 11870, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 11872, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 11874, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 11876, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 11878, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 11880, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 11882, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 11884, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 11886, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 11888, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 11890, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 11892, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 11894, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 11896, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 11898, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 11900, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 11902, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 11904, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 11906, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 11908, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 11910, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 11912, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 11914, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 11916, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 11918, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 11920, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 11922, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 11924, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 11926, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 11928, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 11930, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 11932, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 11934, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 11936, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 11938, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 11940, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 11942, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 11944, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 11946, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 11948, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 11950, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 11952, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 11954, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 11956, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 11958, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 11960, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 11962, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 11964, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 11966, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 11968, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 11970, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 11972, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 11974, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 11976, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 11978, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 11980, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 11982, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 11984, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 11986, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 11988, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 11990, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 11992, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 11994, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 11996, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 11998, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 12000, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 12002, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 12004, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 12006, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 12008, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 12010, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 12012, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 12014, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 12016, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 12018, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 12020, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 12022, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 12024, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 12026, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 12028, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 12030, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 12032, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 12034, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 12036, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 12038, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 12040, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 12042, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 12044, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 12046, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 12048, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 12050, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 12052, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 12054, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 12056, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 12058, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 12060, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 12062, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 12064, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 12066, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 12068, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 12070, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 12072, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 12074, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 12076, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 12078, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 12080, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 12082, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 12084, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 12086, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 12088, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 12090, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 12092, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 12094, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 12096, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 12098, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 12100, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 12102, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 12104, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 12106, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 12108, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 12110, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 12112, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 12114, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 12116, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 12118, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 12120, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 12122, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 12124, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 12126, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 12128, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 12130, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 12132, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 12134, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 12136, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 12138, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 12140, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 12142, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 12144, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 12146, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 12148, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 12150, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 12152, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 12154, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7431, UINT16_MAX, UINT16_MAX, 12156, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7432, UINT16_MAX, UINT16_MAX, 12158, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2847, UINT16_MAX, UINT16_MAX, 12160, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7433, UINT16_MAX, UINT16_MAX, 12162, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7434, UINT16_MAX, UINT16_MAX, 12164, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7435, UINT16_MAX, UINT16_MAX, 12166, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7436, UINT16_MAX, UINT16_MAX, 12168, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 915, UINT16_MAX, UINT16_MAX, 12170, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7437, UINT16_MAX, UINT16_MAX, 12172, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7438, UINT16_MAX, UINT16_MAX, 12174, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7439, UINT16_MAX, UINT16_MAX, 12176, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7440, UINT16_MAX, UINT16_MAX, 12178, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7441, UINT16_MAX, UINT16_MAX, 12180, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7442, UINT16_MAX, UINT16_MAX, 12182, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7443, UINT16_MAX, UINT16_MAX, 12184, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2848, UINT16_MAX, UINT16_MAX, 12186, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7444, UINT16_MAX, UINT16_MAX, 12188, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7445, UINT16_MAX, UINT16_MAX, 12190, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 917, UINT16_MAX, UINT16_MAX, 12192, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7446, UINT16_MAX, UINT16_MAX, 12194, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 897, UINT16_MAX, UINT16_MAX, 12196, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7447, UINT16_MAX, UINT16_MAX, 12198, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7448, UINT16_MAX, UINT16_MAX, 12200, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7449, UINT16_MAX, UINT16_MAX, 12202, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 2836, UINT16_MAX, UINT16_MAX, 12204, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 845, UINT16_MAX, 12206, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 846, UINT16_MAX, 12208, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 847, UINT16_MAX, 12210, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 848, UINT16_MAX, 12212, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 849, UINT16_MAX, 12214, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 850, UINT16_MAX, 12216, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 851, UINT16_MAX, 12218, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 852, UINT16_MAX, 12220, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 807, UINT16_MAX, 12222, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 853, UINT16_MAX, 12224, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 854, UINT16_MAX, 12226, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 35, UINT16_MAX, 12228, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 855, UINT16_MAX, 12230, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 856, UINT16_MAX, 12232, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 857, UINT16_MAX, 12234, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 858, UINT16_MAX, 12236, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 859, UINT16_MAX, 12238, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 914, UINT16_MAX, 12240, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 860, UINT16_MAX, 12242, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 861, UINT16_MAX, 12244, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 862, UINT16_MAX, 12246, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 863, UINT16_MAX, 12248, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 864, UINT16_MAX, 12250, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 865, UINT16_MAX, 12252, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 866, UINT16_MAX, 12254, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7452, UINT16_MAX, 12256, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7453, UINT16_MAX, 12258, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7454, UINT16_MAX, 12260, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7455, UINT16_MAX, 12262, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7456, UINT16_MAX, 12264, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7457, UINT16_MAX, 12266, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 7458, UINT16_MAX, UINT16_MAX, 12268, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 904, UINT16_MAX, 12270, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 38, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 31, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 32, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2798, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, 2799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12272, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12274, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12276, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12278, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7064, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7068, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7071, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12280, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7076, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12282, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12284, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12286, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12288, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12290, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12292, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12294, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12296, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12298, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12300, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12302, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12304, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12306, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12308, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12310, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12312, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12314, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12316, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12318, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12320, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 7093, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12322, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12324, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12326, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12328, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12330, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 12332, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 953, UINT16_MAX, 12334, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 954, UINT16_MAX, 12336, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 955, UINT16_MAX, 12338, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 956, UINT16_MAX, 12340, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 957, UINT16_MAX, 12342, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 958, UINT16_MAX, 12344, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 959, UINT16_MAX, 12346, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 960, UINT16_MAX, 12348, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 961, UINT16_MAX, 12350, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 965, UINT16_MAX, 12352, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 966, UINT16_MAX, 12354, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 967, UINT16_MAX, 12356, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 969, UINT16_MAX, 12358, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 970, UINT16_MAX, 12360, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 971, UINT16_MAX, 12362, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 972, UINT16_MAX, 12364, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 973, UINT16_MAX, 12366, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 974, UINT16_MAX, 12368, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 975, UINT16_MAX, 12370, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 976, UINT16_MAX, 12372, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 977, UINT16_MAX, 12374, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 978, UINT16_MAX, 12376, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 979, UINT16_MAX, 12378, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 982, UINT16_MAX, 12380, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 984, UINT16_MAX, 12382, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 985, UINT16_MAX, 12384, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5162, UINT16_MAX, 12386, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1079, UINT16_MAX, 12388, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 935, UINT16_MAX, 12390, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 939, UINT16_MAX, 12392, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1111, UINT16_MAX, 12394, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1042, UINT16_MAX, 12396, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1051, UINT16_MAX, 12398, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 953, UINT16_MAX, 12400, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 954, UINT16_MAX, 12402, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 955, UINT16_MAX, 12404, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 956, UINT16_MAX, 12406, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 957, UINT16_MAX, 12408, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 958, UINT16_MAX, 12410, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 959, UINT16_MAX, 12412, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 960, UINT16_MAX, 12414, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 961, UINT16_MAX, 12416, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 965, UINT16_MAX, 12418, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 966, UINT16_MAX, 12420, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 969, UINT16_MAX, 12422, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 970, UINT16_MAX, 12424, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 972, UINT16_MAX, 12426, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 974, UINT16_MAX, 12428, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 975, UINT16_MAX, 12430, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 976, UINT16_MAX, 12432, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 977, UINT16_MAX, 12434, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 978, UINT16_MAX, 12436, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 979, UINT16_MAX, 12438, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 981, UINT16_MAX, 12440, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 982, UINT16_MAX, 12442, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 1027, UINT16_MAX, 12444, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 935, UINT16_MAX, 12446, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 934, UINT16_MAX, 12448, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, 952, UINT16_MAX, 12450, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1040, UINT16_MAX, 12452, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 5143, UINT16_MAX, 12454, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, 1043, UINT16_MAX, 12456, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7459, UINT16_MAX, 7459, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7461, UINT16_MAX, 7461, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7463, UINT16_MAX, 7463, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7465, UINT16_MAX, 7465, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7467, UINT16_MAX, 7467, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7469, UINT16_MAX, 7469, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7471, UINT16_MAX, 7471, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7473, UINT16_MAX, 7473, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7475, UINT16_MAX, 7475, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7477, UINT16_MAX, 7477, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7479, UINT16_MAX, 7479, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7481, UINT16_MAX, 7481, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7483, UINT16_MAX, 7483, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7485, UINT16_MAX, 7485, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7487, UINT16_MAX, 7487, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7489, UINT16_MAX, 7489, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7491, UINT16_MAX, 7491, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7493, UINT16_MAX, 7493, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7495, UINT16_MAX, 7495, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7497, UINT16_MAX, 7497, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7499, UINT16_MAX, 7499, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7501, UINT16_MAX, 7501, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7503, UINT16_MAX, 7503, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7505, UINT16_MAX, 7505, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7507, UINT16_MAX, 7507, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7509, UINT16_MAX, 7509, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7511, UINT16_MAX, 7511, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7513, UINT16_MAX, 7513, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7515, UINT16_MAX, 7515, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7517, UINT16_MAX, 7517, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7519, UINT16_MAX, 7519, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7521, UINT16_MAX, 7521, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7523, UINT16_MAX, 7523, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, 7525, UINT16_MAX, 7525, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12458, UINT16_MAX, 12458, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12460, UINT16_MAX, 12460, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12462, UINT16_MAX, 12462, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12464, UINT16_MAX, 12464, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12466, UINT16_MAX, 12466, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12468, UINT16_MAX, 12468, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12470, UINT16_MAX, 12470, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12472, UINT16_MAX, 12472, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12474, UINT16_MAX, 12474, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12476, UINT16_MAX, 12476, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12478, UINT16_MAX, 12478, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12480, UINT16_MAX, 12480, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12482, UINT16_MAX, 12482, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12484, UINT16_MAX, 12484, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12486, UINT16_MAX, 12486, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12488, UINT16_MAX, 12488, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12490, UINT16_MAX, 12490, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12492, UINT16_MAX, 12492, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12494, UINT16_MAX, 12494, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12496, UINT16_MAX, 12496, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12498, UINT16_MAX, 12498, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12500, UINT16_MAX, 12500, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12502, UINT16_MAX, 12502, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12504, UINT16_MAX, 12504, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12506, UINT16_MAX, 12506, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12508, UINT16_MAX, 12508, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12510, UINT16_MAX, 12510, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12512, UINT16_MAX, 12512, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12514, UINT16_MAX, 12514, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12516, UINT16_MAX, 12516, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12518, UINT16_MAX, 12518, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12520, UINT16_MAX, 12520, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12522, UINT16_MAX, 12522, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_R, 0, UINT16_MAX, UINT16_MAX, 12524, UINT16_MAX, 12524, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6699, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6700, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6694, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6695, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6696, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6697, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6692, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6693, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6691, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 7527, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 5874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 7528, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 7529, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FONT, 6698, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23914, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23916, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23918, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23920, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23922, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23924, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23926, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23928, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23930, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23932, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, 23934, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40320, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40323, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40326, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40329, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40332, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40338, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40341, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40344, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40347, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40350, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40353, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40356, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40359, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40362, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40365, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40368, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40371, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40374, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40377, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40380, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40383, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40386, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40389, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40392, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40395, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40398, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 2813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 1508, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 24017, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 24019, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1491, UINT16_MAX, UINT16_MAX, 12526, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1493, UINT16_MAX, UINT16_MAX, 12528, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2813, UINT16_MAX, UINT16_MAX, 12530, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1494, UINT16_MAX, UINT16_MAX, 12532, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1495, UINT16_MAX, UINT16_MAX, 12534, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2838, UINT16_MAX, UINT16_MAX, 12536, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1497, UINT16_MAX, UINT16_MAX, 12538, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1498, UINT16_MAX, UINT16_MAX, 12540, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1499, UINT16_MAX, UINT16_MAX, 12542, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1500, UINT16_MAX, UINT16_MAX, 12544, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1501, UINT16_MAX, UINT16_MAX, 12546, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1502, UINT16_MAX, UINT16_MAX, 12548, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1503, UINT16_MAX, UINT16_MAX, 12550, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1504, UINT16_MAX, UINT16_MAX, 12552, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1505, UINT16_MAX, UINT16_MAX, 12554, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1507, UINT16_MAX, UINT16_MAX, 12556, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2827, UINT16_MAX, UINT16_MAX, 12558, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1508, UINT16_MAX, UINT16_MAX, 12560, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3320, UINT16_MAX, UINT16_MAX, 12562, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1509, UINT16_MAX, UINT16_MAX, 12564, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1510, UINT16_MAX, UINT16_MAX, 12566, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2910, UINT16_MAX, UINT16_MAX, 12568, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 1511, UINT16_MAX, UINT16_MAX, 12570, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2928, UINT16_MAX, UINT16_MAX, 12572, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3327, UINT16_MAX, UINT16_MAX, 12574, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 2835, UINT16_MAX, UINT16_MAX, 12576, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24021, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 21339, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24023, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24025, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 40411, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12578, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12580, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12582, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12584, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12586, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12588, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12590, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12592, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12594, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12596, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12598, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12600, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12602, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12604, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12606, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12608, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12610, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12612, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12614, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12616, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12618, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12620, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12622, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12624, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12626, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12628, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 24032, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 24034, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, 24036, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12630, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12632, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12634, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12636, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12638, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12640, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12642, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12644, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12646, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12648, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12650, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12652, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12654, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12656, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12658, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12660, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12662, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12664, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12666, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12668, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12670, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12672, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12674, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12676, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12678, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, 12680, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24038, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24040, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 24042, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 4331, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7660, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7661, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7662, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3466, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7664, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3903, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7665, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7666, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7667, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 5513, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7669, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7671, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7672, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7673, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3559, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7674, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7675, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7676, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7677, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7678, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7679, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3460, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7680, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 4244, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3898, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 4245, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7681, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3615, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7682, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7683, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7684, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7685, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7686, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 4227, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 3533, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7687, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7689, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, 7690, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40459, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40462, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40465, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40468, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40471, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40474, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40477, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40480, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 40483, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 7718, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, 7719, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC}, {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_EXTEND}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7720, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7721, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7722, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7723, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7725, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7726, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7727, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7728, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7729, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7730, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7731, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7732, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7734, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7735, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7736, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7737, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7739, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7740, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7670, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7741, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7743, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7744, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7745, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7746, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7747, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3476, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7749, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7750, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7751, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7752, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7688, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7753, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7754, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7755, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7756, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7757, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7758, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7759, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7760, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7761, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7762, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7764, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7765, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7766, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7767, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7769, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7770, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7771, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7772, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7773, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7774, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7775, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7776, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7777, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7778, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7779, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7780, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7781, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7782, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7783, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7784, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7785, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7786, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7787, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7788, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7789, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7790, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7791, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7792, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7793, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7794, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7795, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7796, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7797, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7799, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7800, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7801, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7802, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7803, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7804, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7806, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7808, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7809, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7810, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7811, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7812, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7813, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7814, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7815, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7816, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7817, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7819, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7820, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7821, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7822, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7824, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7825, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7826, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3502, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7827, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7828, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7829, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7830, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7831, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7833, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7834, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7836, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7837, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7838, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7839, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7840, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7841, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7842, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7843, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7844, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7845, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7846, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7847, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7849, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7850, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7851, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7852, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7853, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3514, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7855, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7857, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7858, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7859, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7860, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7862, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7864, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7865, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7866, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7867, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7868, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7869, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7870, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7871, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7872, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7873, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7874, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7876, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7877, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7878, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7879, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7880, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7881, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7882, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7883, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7884, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7885, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7886, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7887, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7888, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7889, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7890, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7892, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7893, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7894, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7895, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7896, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7897, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7899, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7900, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7901, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7902, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7903, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7904, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7905, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7906, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7907, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7908, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7909, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7911, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7912, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7913, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7914, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7915, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7916, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7917, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7918, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7919, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7920, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7921, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7922, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7923, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7924, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7925, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7926, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7928, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7929, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7930, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7931, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7932, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7934, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7935, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7936, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7937, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7938, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7939, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7940, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7941, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7943, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7944, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7945, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7946, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7948, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7949, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7950, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7951, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7952, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7953, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7955, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7957, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7959, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7960, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7962, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7963, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7964, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7965, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7966, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7967, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7968, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7969, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7970, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7972, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7973, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7974, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7976, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7977, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7979, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7980, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7981, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7983, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7985, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7986, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7987, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7988, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7989, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7990, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7991, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7992, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7993, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7995, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7996, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7998, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7999, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8001, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8002, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8003, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8005, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8006, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8007, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8009, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8011, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8012, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8013, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8014, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8015, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8016, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8017, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8018, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8019, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8020, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8021, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8022, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8024, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8025, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8027, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8029, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8030, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8032, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8034, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8036, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8037, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8038, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8040, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8042, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8044, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8046, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8047, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8048, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8049, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8050, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8051, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8053, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8054, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8055, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8057, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8059, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8061, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8062, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8063, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8064, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8065, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8067, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8069, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8070, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8071, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8073, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8074, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8075, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8076, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8078, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8079, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8080, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8081, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8082, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8083, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8085, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8086, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8087, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8088, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8089, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8090, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8091, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8093, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8095, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8096, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8098, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8099, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8101, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8102, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8103, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8105, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8107, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8108, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8110, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8111, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8113, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8114, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8115, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8116, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8117, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8118, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8119, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8121, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8123, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8125, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8127, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8128, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8129, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8130, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8131, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8132, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8133, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8134, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8135, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8136, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8137, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8138, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8140, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8141, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8142, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8143, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8144, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8145, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8146, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8147, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8148, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8149, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8150, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8152, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8154, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8156, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8157, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8158, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8159, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8160, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8162, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8163, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8165, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8166, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8167, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8169, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8171, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8172, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8173, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8174, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8175, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8176, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8177, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8178, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8179, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8180, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8181, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8182, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8183, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8184, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8185, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8186, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3604, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8187, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8189, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8190, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8191, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8192, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8193, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8194, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8196, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8198, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8199, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8200, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3611, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8201, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8203, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8204, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8205, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8206, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8207, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8209, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8211, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8212, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8213, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8214, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8216, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8217, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8219, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8221, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8222, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8223, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8224, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8226, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8227, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8228, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8229, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8230, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8231, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8232, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8233, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8235, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8236, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8237, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8238, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8240, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8241, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8242, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8243, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8244, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8246, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8248, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8249, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8250, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8251, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8253, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8254, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8256, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8257, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8259, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8260, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8261, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8262, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8263, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8264, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8265, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8266, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8268, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8269, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8270, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8271, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8272, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8273, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8275, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8276, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8278, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8280, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3659, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8282, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3663, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8283, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8284, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8285, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8286, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 3668, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 8287, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER}, }; static const utf8proc_uint16_t utf8proc_combinations[] = { 0, 46, 192, 193, 194, 195, 196, 197, 0, 256, 258, 260, 550, 461, 0, 0, 512, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7680, 7840, 0, 0, 0, 0, 0, 7842, 1, 11, 262, 264, 0, 0, 0, 199, 0, 0, 0, 266, 268, 0, 46, 200, 201, 202, 7868, 203, 0, 552, 274, 276, 280, 278, 282, 0, 0, 516, 518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7864, 0, 7704, 7706, 0, 0, 7866, 0, 46, 204, 205, 206, 296, 207, 0, 0, 298, 300, 302, 304, 463, 0, 0, 520, 522, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7882, 0, 0, 7724, 0, 0, 7880, 0, 42, 504, 323, 0, 209, 0, 0, 325, 0, 0, 0, 7748, 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7750, 7752, 7754, 0, 46, 210, 211, 212, 213, 214, 0, 0, 332, 334, 490, 558, 465, 336, 416, 524, 526, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7884, 0, 0, 0, 0, 0, 7886, 0, 46, 217, 218, 219, 360, 220, 366, 0, 362, 364, 370, 0, 467, 368, 431, 532, 534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7908, 0, 7798, 7796, 0, 7794, 7910, 0, 46, 7922, 221, 374, 7928, 376, 0, 0, 562, 0, 0, 7822, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7924, 0, 0, 0, 0, 0, 7926, 0, 46, 224, 225, 226, 227, 228, 229, 0, 257, 259, 261, 551, 462, 0, 0, 513, 515, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7681, 7841, 0, 0, 0, 0, 0, 7843, 1, 11, 263, 265, 0, 0, 0, 231, 0, 0, 0, 267, 269, 0, 46, 232, 233, 234, 7869, 235, 0, 553, 275, 277, 281, 279, 283, 0, 0, 517, 519, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7865, 0, 7705, 7707, 0, 0, 7867, 0, 46, 236, 237, 238, 297, 239, 0, 0, 299, 301, 303, 0, 464, 0, 0, 521, 523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7883, 0, 0, 7725, 0, 0, 7881, 0, 42, 505, 324, 0, 241, 0, 0, 326, 0, 0, 0, 7749, 328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7751, 7753, 7755, 0, 46, 242, 243, 244, 245, 246, 0, 0, 333, 335, 491, 559, 466, 337, 417, 525, 527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7885, 0, 0, 0, 0, 0, 7887, 0, 46, 249, 250, 251, 361, 252, 367, 0, 363, 365, 371, 0, 468, 369, 432, 533, 535, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7909, 0, 7799, 7797, 0, 7795, 7911, 0, 46, 7923, 253, 375, 7929, 255, 7833, 0, 563, 0, 0, 7823, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7925, 0, 0, 0, 0, 0, 7927, 6, 42, 7696, 0, 0, 0, 7690, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7692, 7694, 7698, 6, 42, 7697, 0, 0, 0, 7691, 271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7693, 7695, 7699, 1, 11, 500, 284, 0, 0, 0, 290, 7712, 286, 0, 288, 486, 1, 11, 501, 285, 0, 0, 0, 291, 7713, 287, 0, 289, 487, 2, 44, 292, 0, 7718, 0, 7720, 0, 0, 0, 7714, 542, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7716, 0, 0, 0, 7722, 2, 44, 293, 0, 7719, 0, 7721, 0, 0, 0, 7715, 543, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7717, 7830, 0, 0, 7723, 2, 2, 308, 2, 11, 309, 0, 0, 0, 0, 0, 0, 0, 0, 496, 1, 41, 7728, 0, 0, 0, 0, 310, 0, 0, 0, 0, 488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7730, 7732, 1, 41, 7729, 0, 0, 0, 0, 311, 0, 0, 0, 0, 489, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7731, 7733, 1, 42, 313, 0, 0, 0, 0, 315, 0, 0, 0, 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7734, 7738, 7740, 1, 42, 314, 0, 0, 0, 0, 316, 0, 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7735, 7739, 7741, 1, 41, 340, 0, 0, 0, 0, 342, 0, 0, 0, 7768, 344, 0, 0, 528, 530, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7770, 7774, 1, 41, 341, 0, 0, 0, 0, 343, 0, 0, 0, 7769, 345, 0, 0, 529, 531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7771, 7775, 1, 40, 346, 348, 0, 0, 0, 350, 0, 0, 0, 7776, 352, 0, 0, 0, 0, 536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7778, 1, 40, 347, 349, 0, 0, 0, 351, 0, 0, 0, 7777, 353, 0, 0, 0, 0, 537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7779, 6, 42, 354, 0, 0, 0, 7786, 356, 0, 0, 0, 0, 538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7788, 7790, 7792, 4, 42, 7831, 0, 355, 0, 0, 0, 7787, 357, 0, 0, 0, 0, 539, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7789, 7791, 7793, 0, 40, 7808, 7810, 372, 0, 7812, 0, 0, 0, 0, 0, 7814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7816, 0, 40, 7809, 7811, 373, 0, 7813, 7832, 0, 0, 0, 0, 7815, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7817, 1, 41, 377, 7824, 0, 0, 0, 0, 0, 0, 0, 379, 381, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7826, 7828, 1, 41, 378, 7825, 0, 0, 0, 0, 0, 0, 0, 380, 382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7827, 7829, 0, 11, 475, 471, 0, 0, 0, 0, 0, 469, 0, 0, 0, 473, 0, 11, 476, 472, 0, 0, 0, 0, 0, 470, 0, 0, 0, 474, 7, 7, 478, 7, 7, 479, 7, 7, 480, 7, 7, 481, 1, 7, 508, 0, 0, 0, 0, 0, 482, 1, 7, 509, 0, 0, 0, 0, 0, 483, 7, 7, 492, 7, 7, 493, 11, 11, 494, 11, 11, 495, 1, 1, 506, 1, 1, 507, 1, 1, 510, 1, 1, 511, 7, 7, 554, 7, 7, 555, 1, 7, 7756, 0, 0, 7758, 0, 0, 556, 1, 7, 7757, 0, 0, 7759, 0, 0, 557, 7, 7, 560, 7, 7, 561, 0, 49, 8173, 901, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8129, 0, 50, 8122, 902, 0, 0, 0, 0, 0, 8121, 8120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7944, 7945, 0, 8124, 0, 48, 8136, 904, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7960, 7961, 0, 50, 8138, 905, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7976, 7977, 0, 8140, 0, 48, 8154, 906, 0, 0, 938, 0, 0, 8153, 8152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7992, 7993, 0, 48, 8184, 908, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8008, 8009, 0, 48, 8170, 910, 0, 0, 939, 0, 0, 8169, 8168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8025, 0, 50, 8186, 911, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8040, 8041, 0, 8188, 0, 49, 8146, 912, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8151, 0, 50, 8048, 940, 0, 0, 0, 0, 0, 8113, 8112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7936, 7937, 8118, 8115, 0, 48, 8050, 941, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7952, 7953, 0, 50, 8052, 942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7968, 7969, 8134, 8131, 0, 49, 8054, 943, 0, 0, 970, 0, 0, 8145, 8144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7984, 7985, 8150, 0, 49, 8162, 944, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8167, 0, 49, 8058, 973, 0, 0, 971, 0, 0, 8161, 8160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8016, 8017, 8166, 0, 48, 8056, 972, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8000, 8001, 0, 50, 8060, 974, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8032, 8033, 8182, 8179, 1, 4, 979, 0, 0, 980, 0, 8, 1024, 0, 0, 0, 1025, 0, 0, 0, 1238, 1, 1, 1027, 4, 4, 1031, 1, 1, 1036, 0, 8, 1037, 0, 0, 0, 1252, 0, 0, 1250, 1049, 4, 12, 1264, 0, 0, 1262, 1038, 0, 0, 0, 1266, 0, 8, 1117, 0, 0, 0, 1253, 0, 0, 1251, 1081, 0, 8, 1104, 0, 0, 0, 1105, 0, 0, 0, 1239, 1, 1, 1107, 4, 4, 1111, 1, 1, 1116, 4, 12, 1265, 0, 0, 1263, 1118, 0, 0, 0, 1267, 14, 14, 1142, 14, 14, 1143, 4, 8, 1244, 0, 0, 0, 1217, 4, 8, 1245, 0, 0, 0, 1218, 4, 8, 1234, 0, 0, 0, 1232, 4, 8, 1235, 0, 0, 0, 1233, 4, 4, 1242, 4, 4, 1243, 4, 4, 1246, 4, 4, 1247, 4, 4, 1254, 4, 4, 1255, 4, 4, 1258, 4, 4, 1259, 4, 4, 1260, 4, 4, 1261, 4, 4, 1268, 4, 4, 1269, 4, 4, 1272, 4, 4, 1273, 17, 19, 1570, 1571, 1573, 18, 18, 1572, 18, 18, 1574, 18, 18, 1728, 18, 18, 1730, 18, 18, 1747, 20, 20, 2345, 20, 20, 2353, 20, 20, 2356, 21, 22, 2507, 2508, 23, 25, 2888, 2891, 2892, 26, 26, 2964, 26, 27, 3020, 3018, 27, 27, 3019, 28, 28, 3144, 29, 29, 3264, 29, 31, 3271, 3272, 3274, 29, 29, 3275, 32, 33, 3402, 3404, 32, 32, 3403, 34, 36, 3546, 3548, 3550, 34, 34, 3549, 37, 37, 4134, 38, 38, 6918, 38, 38, 6920, 38, 38, 6922, 38, 38, 6924, 38, 38, 6926, 38, 38, 6930, 38, 38, 6971, 38, 38, 6973, 38, 38, 6976, 38, 38, 6977, 38, 38, 6979, 10, 41, 7682, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7684, 7686, 10, 41, 7683, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7685, 7687, 1, 1, 7688, 1, 1, 7689, 0, 1, 7700, 7702, 0, 1, 7701, 7703, 8, 8, 7708, 8, 8, 7709, 10, 10, 7710, 10, 10, 7711, 1, 1, 7726, 1, 1, 7727, 7, 7, 7736, 7, 7, 7737, 1, 40, 7742, 0, 0, 0, 0, 0, 0, 0, 0, 7744, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7746, 1, 40, 7743, 0, 0, 0, 0, 0, 0, 0, 0, 7745, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7747, 0, 1, 7760, 7762, 0, 1, 7761, 7763, 1, 10, 7764, 0, 0, 0, 0, 0, 0, 0, 0, 7766, 1, 10, 7765, 0, 0, 0, 0, 0, 0, 0, 0, 7767, 7, 7, 7772, 7, 7, 7773, 10, 10, 7780, 10, 10, 7781, 10, 10, 7782, 10, 10, 7783, 10, 10, 7784, 10, 10, 7785, 1, 1, 7800, 1, 1, 7801, 4, 4, 7802, 4, 4, 7803, 3, 40, 7804, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7806, 3, 40, 7805, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7807, 4, 10, 7820, 0, 0, 0, 0, 0, 7818, 4, 10, 7821, 0, 0, 0, 0, 0, 7819, 10, 10, 7835, 0, 46, 7846, 7844, 0, 7850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7848, 0, 46, 7847, 7845, 0, 7851, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7849, 2, 8, 7852, 0, 0, 0, 0, 0, 7862, 2, 8, 7853, 0, 0, 0, 0, 0, 7863, 0, 46, 7856, 7854, 0, 7860, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7858, 0, 46, 7857, 7855, 0, 7861, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7859, 0, 46, 7872, 7870, 0, 7876, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7874, 0, 46, 7873, 7871, 0, 7877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7875, 2, 2, 7878, 2, 2, 7879, 0, 46, 7890, 7888, 0, 7894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7892, 0, 46, 7891, 7889, 0, 7895, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7893, 2, 2, 7896, 2, 2, 7897, 0, 46, 7900, 7898, 0, 7904, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7906, 0, 0, 0, 0, 0, 7902, 0, 46, 7901, 7899, 0, 7905, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7907, 0, 0, 0, 0, 0, 7903, 0, 46, 7914, 7912, 0, 7918, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7920, 0, 0, 0, 0, 0, 7916, 0, 46, 7915, 7913, 0, 7919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7921, 0, 0, 0, 0, 0, 7917, 0, 50, 7938, 7940, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7942, 8064, 0, 50, 7939, 7941, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7943, 8065, 0, 50, 7946, 7948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7950, 8072, 0, 50, 7947, 7949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7951, 8073, 0, 1, 7954, 7956, 0, 1, 7955, 7957, 0, 1, 7962, 7964, 0, 1, 7963, 7965, 0, 50, 7970, 7972, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7974, 8080, 0, 50, 7971, 7973, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7975, 8081, 0, 50, 7978, 7980, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7982, 8088, 0, 50, 7979, 7981, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7983, 8089, 0, 49, 7986, 7988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7990, 0, 49, 7987, 7989, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7991, 0, 49, 7994, 7996, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7998, 0, 49, 7995, 7997, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7999, 0, 1, 8002, 8004, 0, 1, 8003, 8005, 0, 1, 8010, 8012, 0, 1, 8011, 8013, 0, 49, 8018, 8020, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8022, 0, 49, 8019, 8021, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8023, 0, 49, 8027, 8029, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8031, 0, 50, 8034, 8036, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8038, 8096, 0, 50, 8035, 8037, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8039, 8097, 0, 50, 8042, 8044, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8046, 8104, 0, 50, 8043, 8045, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8047, 8105, 50, 50, 8066, 50, 50, 8067, 50, 50, 8068, 50, 50, 8069, 50, 50, 8070, 50, 50, 8071, 50, 50, 8074, 50, 50, 8075, 50, 50, 8076, 50, 50, 8077, 50, 50, 8078, 50, 50, 8079, 50, 50, 8082, 50, 50, 8083, 50, 50, 8084, 50, 50, 8085, 50, 50, 8086, 50, 50, 8087, 50, 50, 8090, 50, 50, 8091, 50, 50, 8092, 50, 50, 8093, 50, 50, 8094, 50, 50, 8095, 50, 50, 8098, 50, 50, 8099, 50, 50, 8100, 50, 50, 8101, 50, 50, 8102, 50, 50, 8103, 50, 50, 8106, 50, 50, 8107, 50, 50, 8108, 50, 50, 8109, 50, 50, 8110, 50, 50, 8111, 50, 50, 8114, 50, 50, 8116, 50, 50, 8119, 50, 50, 8130, 50, 50, 8132, 50, 50, 8135, 0, 49, 8141, 8142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8143, 0, 49, 8157, 8158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8159, 47, 48, 8164, 8165, 48, 48, 8172, 50, 50, 8178, 50, 50, 8180, 50, 50, 8183, 51, 51, 8602, 51, 51, 8603, 51, 51, 8622, 51, 51, 8653, 51, 51, 8654, 51, 51, 8655, 51, 51, 8708, 51, 51, 8713, 51, 51, 8716, 51, 51, 8740, 51, 51, 8742, 51, 51, 8769, 51, 51, 8772, 51, 51, 8775, 51, 51, 8777, 51, 51, 8800, 51, 51, 8802, 51, 51, 8813, 51, 51, 8814, 51, 51, 8815, 51, 51, 8816, 51, 51, 8817, 51, 51, 8820, 51, 51, 8821, 51, 51, 8824, 51, 51, 8825, 51, 51, 8832, 51, 51, 8833, 51, 51, 8836, 51, 51, 8837, 51, 51, 8840, 51, 51, 8841, 51, 51, 8876, 51, 51, 8877, 51, 51, 8878, 51, 51, 8879, 51, 51, 8928, 51, 51, 8929, 51, 51, 8930, 51, 51, 8931, 51, 51, 8938, 51, 51, 8939, 51, 51, 8940, 51, 51, 8941, 51, 51, 10972, 52, 52, 12364, 52, 52, 12366, 52, 52, 12368, 52, 52, 12370, 52, 52, 12372, 52, 52, 12374, 52, 52, 12376, 52, 52, 12378, 52, 52, 12380, 52, 52, 12382, 52, 52, 12384, 52, 52, 12386, 52, 52, 12389, 52, 52, 12391, 52, 52, 12393, 52, 53, 12400, 12401, 52, 53, 12403, 12404, 52, 53, 12406, 12407, 52, 53, 12409, 12410, 52, 53, 12412, 12413, 52, 52, 12436, 52, 52, 12446, 52, 52, 12460, 52, 52, 12462, 52, 52, 12464, 52, 52, 12466, 52, 52, 12468, 52, 52, 12470, 52, 52, 12472, 52, 52, 12474, 52, 52, 12476, 52, 52, 12478, 52, 52, 12480, 52, 52, 12482, 52, 52, 12485, 52, 52, 12487, 52, 52, 12489, 52, 53, 12496, 12497, 52, 53, 12499, 12500, 52, 53, 12502, 12503, 52, 53, 12505, 12506, 52, 53, 12508, 12509, 52, 52, 12532, 52, 52, 12535, 52, 52, 12536, 52, 52, 12537, 52, 52, 12538, 52, 52, 12542, 54, 55, 1, 4250, 54, 55, 1, 4252, 54, 55, 1, 4267, 56, 57, 1, 4398, 56, 57, 1, 4399, 58, 61, 1, 4939, 1, 4940, 62, 67, 1, 5307, 1, 5308, 1, 5310, 68, 69, 1, 5562, 68, 69, 1, 5563, 70, 71, 1, 6456, 72, 73, 1, 53598, 72, 73, 1, 53599, 74, 83, 1, 53600, 1, 53601, 1, 53602, 1, 53603, 1, 53604, 72, 73, 1, 53691, 72, 73, 1, 53692, 74, 77, 1, 53693, 1, 53695, 74, 77, 1, 53694, 1, 53696, }; mongodb-1.21.0/src/libmongoc/src/uthash/uthash-2.3.0/uthash.h0000644000175100001660000022007214760300420020362 0ustar /* Copyright (c) 2003-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTHASH_H #define UTHASH_H #define UTHASH_VERSION 2.3.0 #include /* memcmp, memset, strlen */ #include /* ptrdiff_t */ #include /* exit */ #if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT /* This codepath is provided for backward compatibility, but I plan to remove it. */ #warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead" typedef unsigned int uint32_t; typedef unsigned char uint8_t; #elif defined(HASH_NO_STDINT) && HASH_NO_STDINT #else #include /* uint8_t, uint32_t */ #endif /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #if !defined(DECLTYPE) && !defined(NO_DECLTYPE) #if defined(_MSC_VER) /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE #else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #endif #ifdef NO_DECLTYPE #define DECLTYPE(x) #define DECLTYPE_ASSIGN(dst,src) \ do { \ char **_da_dst = (char**)(&(dst)); \ *_da_dst = (char*)(src); \ } while (0) #else #define DECLTYPE_ASSIGN(dst,src) \ do { \ (dst) = DECLTYPE(dst)(src); \ } while (0) #endif #ifndef uthash_malloc #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free #define uthash_free(ptr,sz) free(ptr) /* free fcn */ #endif #ifndef uthash_bzero #define uthash_bzero(a,n) memset(a,'\0',n) #endif #ifndef uthash_strlen #define uthash_strlen(s) strlen(s) #endif #ifndef HASH_FUNCTION #define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv) #endif #ifndef HASH_KEYCMP #define HASH_KEYCMP(a,b,n) memcmp(a,b,n) #endif #ifndef uthash_noexpand_fyi #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi #define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif #ifndef HASH_NONFATAL_OOM #define HASH_NONFATAL_OOM 0 #endif #if HASH_NONFATAL_OOM /* malloc failures can be recovered from */ #ifndef uthash_nonfatal_oom #define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ #endif #define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) #define IF_HASH_NONFATAL_OOM(x) x #else /* malloc failures result in lost memory, hash tables are unusable */ #ifndef uthash_fatal #define uthash_fatal(msg) exit(-1) /* fatal OOM error */ #endif #define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") #define IF_HASH_NONFATAL_OOM(x) #endif /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ #define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhp */ #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) /* calculate the hash handle from element address elp */ #define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) #define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ do { \ struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ unsigned _hd_bkt; \ HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ (head)->hh.tbl->buckets[_hd_bkt].count++; \ _hd_hh_item->hh_next = NULL; \ _hd_hh_item->hh_prev = NULL; \ } while (0) #define HASH_VALUE(keyptr,keylen,hashv) \ do { \ HASH_FUNCTION(keyptr, keylen, hashv); \ } while (0) #define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ do { \ (out) = NULL; \ if (head) { \ unsigned _hf_bkt; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ } \ } \ } while (0) #define HASH_FIND(hh,head,keyptr,keylen,out) \ do { \ (out) = NULL; \ if (head) { \ unsigned _hf_hashv; \ HASH_VALUE(keyptr, keylen, _hf_hashv); \ HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ } \ } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) #define HASH_BLOOM_MAKE(tbl,oomed) \ do { \ (tbl)->bloom_nbits = HASH_BLOOM; \ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ if (!(tbl)->bloom_bv) { \ HASH_RECORD_OOM(oomed); \ } else { \ uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ } \ } while (0) #define HASH_BLOOM_FREE(tbl) \ do { \ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ } while (0) #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) #define HASH_BLOOM_ADD(tbl,hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) #define HASH_BLOOM_TEST(tbl,hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) #else #define HASH_BLOOM_MAKE(tbl,oomed) #define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_TEST(tbl,hashv) (1) #define HASH_BLOOM_BYTELEN 0U #endif #define HASH_MAKE_TABLE(hh,head,oomed) \ do { \ (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ if (!(head)->hh.tbl) { \ HASH_RECORD_OOM(oomed); \ } else { \ uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ (head)->hh.tbl->tail = &((head)->hh); \ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ (head)->hh.tbl->signature = HASH_SIGNATURE; \ if (!(head)->hh.tbl->buckets) { \ HASH_RECORD_OOM(oomed); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ } else { \ uthash_bzero((head)->hh.tbl->buckets, \ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ IF_HASH_NONFATAL_OOM( \ if (oomed) { \ uthash_free((head)->hh.tbl->buckets, \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ } \ ) \ } \ } \ } while (0) #define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ do { \ (replaced) = NULL; \ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ if (replaced) { \ HASH_DELETE(hh, head, replaced); \ } \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ } while (0) #define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ do { \ (replaced) = NULL; \ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ if (replaced) { \ HASH_DELETE(hh, head, replaced); \ } \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ } while (0) #define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ do { \ unsigned _hr_hashv; \ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ } while (0) #define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ do { \ unsigned _hr_hashv; \ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ } while (0) #define HASH_APPEND_LIST(hh, head, add) \ do { \ (add)->hh.next = NULL; \ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ (head)->hh.tbl->tail->next = (add); \ (head)->hh.tbl->tail = &((add)->hh); \ } while (0) #define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ do { \ do { \ if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ break; \ } \ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ } while (0) #ifdef NO_DECLTYPE #undef HASH_AKBI_INNER_LOOP #define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ do { \ char *_hs_saved_head = (char*)(head); \ do { \ DECLTYPE_ASSIGN(head, _hs_iter); \ if (cmpfcn(head, add) > 0) { \ DECLTYPE_ASSIGN(head, _hs_saved_head); \ break; \ } \ DECLTYPE_ASSIGN(head, _hs_saved_head); \ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ } while (0) #endif #if HASH_NONFATAL_OOM #define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ do { \ if (!(oomed)) { \ unsigned _ha_bkt; \ (head)->hh.tbl->num_items++; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ if (oomed) { \ HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ HASH_DELETE_HH(hh, head, &(add)->hh); \ (add)->hh.tbl = NULL; \ uthash_nonfatal_oom(add); \ } else { \ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ } \ } else { \ (add)->hh.tbl = NULL; \ uthash_nonfatal_oom(add); \ } \ } while (0) #else #define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ do { \ unsigned _ha_bkt; \ (head)->hh.tbl->num_items++; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ } while (0) #endif #define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ do { \ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ (add)->hh.hashv = (hashval); \ (add)->hh.key = (char*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ (add)->hh.prev = NULL; \ HASH_MAKE_TABLE(hh, add, _ha_oomed); \ IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ (head) = (add); \ IF_HASH_NONFATAL_OOM( } ) \ } else { \ void *_hs_iter = (head); \ (add)->hh.tbl = (head)->hh.tbl; \ HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ if (_hs_iter) { \ (add)->hh.next = _hs_iter; \ if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ } else { \ (head) = (add); \ } \ HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ } else { \ HASH_APPEND_LIST(hh, head, add); \ } \ } \ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ } while (0) #define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ do { \ unsigned _hs_hashv; \ HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ } while (0) #define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) #define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) #define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ do { \ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ (add)->hh.hashv = (hashval); \ (add)->hh.key = (const void*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ (add)->hh.prev = NULL; \ HASH_MAKE_TABLE(hh, add, _ha_oomed); \ IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ (head) = (add); \ IF_HASH_NONFATAL_OOM( } ) \ } else { \ (add)->hh.tbl = (head)->hh.tbl; \ HASH_APPEND_LIST(hh, head, add); \ } \ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ } while (0) #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ do { \ unsigned _ha_hashv; \ HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ } while (0) #define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) #define HASH_TO_BKT(hashv,num_bkts,bkt) \ do { \ bkt = ((hashv) & ((num_bkts) - 1U)); \ } while (0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. * The use of _hd_hh_del below deserves special explanation. * These used to be expressed using (delptr) but that led to a bug * if someone used the same symbol for the head and deletee, like * HASH_DELETE(hh,users,users); * We want that to work, but by changing the head (users) below * we were forfeiting our ability to further refer to the deletee (users) * in the patch-up process. Solution: use scratch space to * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ #define HASH_DELETE(hh,head,delptr) \ HASH_DELETE_HH(hh, head, &(delptr)->hh) #define HASH_DELETE_HH(hh,head,delptrhh) \ do { \ struct UT_hash_handle *_hd_hh_del = (delptrhh); \ if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head) = NULL; \ } else { \ unsigned _hd_bkt; \ if (_hd_hh_del == (head)->hh.tbl->tail) { \ (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ } \ if (_hd_hh_del->prev != NULL) { \ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ } else { \ DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ } \ if (_hd_hh_del->next != NULL) { \ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ } \ HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ (head)->hh.tbl->num_items--; \ } \ HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ #define HASH_FIND_STR(head,findstr,out) \ do { \ unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ } while (0) #define HASH_ADD_STR(head,strfield,add) \ do { \ unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ } while (0) #define HASH_REPLACE_STR(head,strfield,add,replaced) \ do { \ unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ } while (0) #define HASH_FIND_INT(head,findint,out) \ HASH_FIND(hh,head,findint,sizeof(int),out) #define HASH_ADD_INT(head,intfield,add) \ HASH_ADD(hh,head,intfield,sizeof(int),add) #define HASH_REPLACE_INT(head,intfield,add,replaced) \ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) #define HASH_FIND_PTR(head,findptr,out) \ HASH_FIND(hh,head,findptr,sizeof(void *),out) #define HASH_ADD_PTR(head,ptrfield,add) \ HASH_ADD(hh,head,ptrfield,sizeof(void *),add) #define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) #define HASH_DEL(head,delptr) \ HASH_DELETE(hh,head,delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG #include /* fprintf, stderr */ #define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) #define HASH_FSCK(hh,head,where) \ do { \ struct UT_hash_handle *_thh; \ if (head) { \ unsigned _bkt_i; \ unsigned _count = 0; \ char *_prev; \ for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ unsigned _bkt_count = 0; \ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ _prev = NULL; \ while (_thh) { \ if (_prev != (char*)(_thh->hh_prev)) { \ HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ (where), (void*)_thh->hh_prev, (void*)_prev); \ } \ _bkt_count++; \ _prev = (char*)(_thh); \ _thh = _thh->hh_next; \ } \ _count += _bkt_count; \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ (where), (head)->hh.tbl->num_items, _count); \ } \ _count = 0; \ _prev = NULL; \ _thh = &(head)->hh; \ while (_thh) { \ _count++; \ if (_prev != (char*)_thh->prev) { \ HASH_OOPS("%s: invalid prev %p, actual %p\n", \ (where), (void*)_thh->prev, (void*)_prev); \ } \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ (where), (head)->hh.tbl->num_items, _count); \ } \ } \ } while (0) #else #define HASH_FSCK(hh,head,where) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ do { \ unsigned _klen = fieldlen; \ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ } while (0) #else #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ #define HASH_BER(key,keylen,hashv) \ do { \ unsigned _hb_keylen = (unsigned)keylen; \ const unsigned char *_hb_key = (const unsigned char*)(key); \ (hashv) = 0; \ while (_hb_keylen-- != 0U) { \ (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ } \ } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ #define HASH_SAX(key,keylen,hashv) \ do { \ unsigned _sx_i; \ const unsigned char *_hs_key = (const unsigned char*)(key); \ hashv = 0; \ for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ } \ } while (0) /* FNV-1a variation */ #define HASH_FNV(key,keylen,hashv) \ do { \ unsigned _fn_i; \ const unsigned char *_hf_key = (const unsigned char*)(key); \ (hashv) = 2166136261U; \ for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ hashv = hashv ^ _hf_key[_fn_i]; \ hashv = hashv * 16777619U; \ } \ } while (0) #define HASH_OAT(key,keylen,hashv) \ do { \ unsigned _ho_i; \ const unsigned char *_ho_key=(const unsigned char*)(key); \ hashv = 0; \ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ hashv += _ho_key[_ho_i]; \ hashv += (hashv << 10); \ hashv ^= (hashv >> 6); \ } \ hashv += (hashv << 3); \ hashv ^= (hashv >> 11); \ hashv += (hashv << 15); \ } while (0) #define HASH_JEN_MIX(a,b,c) \ do { \ a -= b; a -= c; a ^= ( c >> 13 ); \ b -= c; b -= a; b ^= ( a << 8 ); \ c -= a; c -= b; c ^= ( b >> 13 ); \ a -= b; a -= c; a ^= ( c >> 12 ); \ b -= c; b -= a; b ^= ( a << 16 ); \ c -= a; c -= b; c ^= ( b >> 5 ); \ a -= b; a -= c; a ^= ( c >> 3 ); \ b -= c; b -= a; b ^= ( a << 10 ); \ c -= a; c -= b; c ^= ( b >> 15 ); \ } while (0) #define HASH_JEN(key,keylen,hashv) \ do { \ unsigned _hj_i,_hj_j,_hj_k; \ unsigned const char *_hj_key=(unsigned const char*)(key); \ hashv = 0xfeedbeefu; \ _hj_i = _hj_j = 0x9e3779b9u; \ _hj_k = (unsigned)(keylen); \ while (_hj_k >= 12U) { \ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + ( (unsigned)_hj_key[2] << 16 ) \ + ( (unsigned)_hj_key[3] << 24 ) ); \ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + ( (unsigned)_hj_key[6] << 16 ) \ + ( (unsigned)_hj_key[7] << 24 ) ); \ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + ( (unsigned)_hj_key[10] << 16 ) \ + ( (unsigned)_hj_key[11] << 24 ) ); \ \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ \ _hj_key += 12; \ _hj_k -= 12U; \ } \ hashv += (unsigned)(keylen); \ switch ( _hj_k ) { \ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ default: ; \ } \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ } while (0) /* The Paul Hsieh hash function */ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) #define get16bits(d) (*((const uint16_t *) (d))) #endif #if !defined (get16bits) #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ +(uint32_t)(((const uint8_t *)(d))[0]) ) #endif #define HASH_SFH(key,keylen,hashv) \ do { \ unsigned const char *_sfh_key=(unsigned const char*)(key); \ uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ \ unsigned _sfh_rem = _sfh_len & 3U; \ _sfh_len >>= 2; \ hashv = 0xcafebabeu; \ \ /* Main loop */ \ for (;_sfh_len > 0U; _sfh_len--) { \ hashv += get16bits (_sfh_key); \ _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ hashv = (hashv << 16) ^ _sfh_tmp; \ _sfh_key += 2U*sizeof (uint16_t); \ hashv += hashv >> 11; \ } \ \ /* Handle end cases */ \ switch (_sfh_rem) { \ case 3: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 16; \ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ hashv += hashv >> 11; \ break; \ case 2: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 11; \ hashv += hashv >> 17; \ break; \ case 1: hashv += *_sfh_key; \ hashv ^= hashv << 10; \ hashv += hashv >> 1; \ break; \ default: ; \ } \ \ /* Force "avalanching" of final 127 bits */ \ hashv ^= hashv << 3; \ hashv += hashv >> 5; \ hashv ^= hashv << 4; \ hashv += hashv >> 17; \ hashv ^= hashv << 25; \ hashv += hashv >> 6; \ } while (0) /* iterate over items in a known bucket to find desired item */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ do { \ if ((head).hh_head != NULL) { \ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ } else { \ (out) = NULL; \ } \ while ((out) != NULL) { \ if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ break; \ } \ } \ if ((out)->hh.hh_next != NULL) { \ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ } else { \ (out) = NULL; \ } \ } \ } while (0) /* add an item to a bucket */ #define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ do { \ UT_hash_bucket *_ha_head = &(head); \ _ha_head->count++; \ (addhh)->hh_next = _ha_head->hh_head; \ (addhh)->hh_prev = NULL; \ if (_ha_head->hh_head != NULL) { \ _ha_head->hh_head->hh_prev = (addhh); \ } \ _ha_head->hh_head = (addhh); \ if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ && !(addhh)->tbl->noexpand) { \ HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ IF_HASH_NONFATAL_OOM( \ if (oomed) { \ HASH_DEL_IN_BKT(head,addhh); \ } \ ) \ } \ } while (0) /* remove an item from a given bucket */ #define HASH_DEL_IN_BKT(head,delhh) \ do { \ UT_hash_bucket *_hd_head = &(head); \ _hd_head->count--; \ if (_hd_head->hh_head == (delhh)) { \ _hd_head->hh_head = (delhh)->hh_next; \ } \ if ((delhh)->hh_prev) { \ (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ } \ if ((delhh)->hh_next) { \ (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ } \ } while (0) /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the * items will distribute more or less evenly into the new buckets * (the extent to which this is true is a measure of the quality of * the hash function as it applies to the key domain). * * With the items distributed into more buckets, the chain length * (item count) in each bucket is reduced. Thus by expanding buckets * the hash keeps a bound on the chain length. This bounded chain * length is the essence of how a hash provides constant time lookup. * * The calculation of tbl->ideal_chain_maxlen below deserves some * explanation. First, keep in mind that we're calculating the ideal * maximum chain length based on the *new* (doubled) bucket count. * In fractions this is just n/b (n=number of items,b=new num buckets). * Since the ideal chain length is an integer, we want to calculate * ceil(n/b). We don't depend on floating point arithmetic in this * hash, so to calculate ceil(n/b) with integers we could write * * ceil(n/b) = (n/b) + ((n%b)?1:0) * * and in fact a previous version of this hash did just that. * But now we have improved things a bit by recognizing that b is * always a power of two. We keep its base 2 log handy (call it lb), * so now we can write this with a bit shift and logical AND: * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ #define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ do { \ unsigned _he_bkt; \ unsigned _he_bkt_i; \ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ if (!_he_new_buckets) { \ HASH_RECORD_OOM(oomed); \ } else { \ uthash_bzero(_he_new_buckets, \ sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ (tbl)->ideal_chain_maxlen = \ ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ (tbl)->nonideal_items = 0; \ for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ while (_he_thh != NULL) { \ _he_hh_nxt = _he_thh->hh_next; \ HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ _he_newbkt = &(_he_new_buckets[_he_bkt]); \ if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ (tbl)->nonideal_items++; \ if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ _he_newbkt->expand_mult++; \ } \ } \ _he_thh->hh_prev = NULL; \ _he_thh->hh_next = _he_newbkt->hh_head; \ if (_he_newbkt->hh_head != NULL) { \ _he_newbkt->hh_head->hh_prev = _he_thh; \ } \ _he_newbkt->hh_head = _he_thh; \ _he_thh = _he_hh_nxt; \ } \ } \ uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ (tbl)->num_buckets *= 2U; \ (tbl)->log2_num_buckets++; \ (tbl)->buckets = _he_new_buckets; \ (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ ((tbl)->ineff_expands+1U) : 0U; \ if ((tbl)->ineff_expands > 1U) { \ (tbl)->noexpand = 1; \ uthash_noexpand_fyi(tbl); \ } \ uthash_expand_fyi(tbl); \ } \ } while (0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ do { \ unsigned _hs_i; \ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ if (head != NULL) { \ _hs_insize = 1; \ _hs_looping = 1; \ _hs_list = &((head)->hh); \ while (_hs_looping != 0U) { \ _hs_p = _hs_list; \ _hs_list = NULL; \ _hs_tail = NULL; \ _hs_nmerges = 0; \ while (_hs_p != NULL) { \ _hs_nmerges++; \ _hs_q = _hs_p; \ _hs_psize = 0; \ for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ _hs_psize++; \ _hs_q = ((_hs_q->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ if (_hs_q == NULL) { \ break; \ } \ } \ _hs_qsize = _hs_insize; \ while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ if (_hs_psize == 0U) { \ _hs_e = _hs_q; \ _hs_q = ((_hs_q->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ _hs_qsize--; \ } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ _hs_e = _hs_p; \ if (_hs_p != NULL) { \ _hs_p = ((_hs_p->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ } \ _hs_psize--; \ } else if ((cmpfcn( \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ )) <= 0) { \ _hs_e = _hs_p; \ if (_hs_p != NULL) { \ _hs_p = ((_hs_p->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ } \ _hs_psize--; \ } else { \ _hs_e = _hs_q; \ _hs_q = ((_hs_q->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ _hs_qsize--; \ } \ if ( _hs_tail != NULL ) { \ _hs_tail->next = ((_hs_e != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ } else { \ _hs_list = _hs_e; \ } \ if (_hs_e != NULL) { \ _hs_e->prev = ((_hs_tail != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ } \ _hs_tail = _hs_e; \ } \ _hs_p = _hs_q; \ } \ if (_hs_tail != NULL) { \ _hs_tail->next = NULL; \ } \ if (_hs_nmerges <= 1U) { \ _hs_looping = 0; \ (head)->hh.tbl->tail = _hs_tail; \ DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ } \ _hs_insize *= 2U; \ } \ HASH_FSCK(hh, head, "HASH_SRT"); \ } \ } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ unsigned _src_bkt, _dst_bkt; \ void *_last_elt = NULL, *_elt; \ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ if ((src) != NULL) { \ for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ _src_hh != NULL; \ _src_hh = _src_hh->hh_next) { \ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ if (cond(_elt)) { \ IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \ _dst_hh->key = _src_hh->key; \ _dst_hh->keylen = _src_hh->keylen; \ _dst_hh->hashv = _src_hh->hashv; \ _dst_hh->prev = _last_elt; \ _dst_hh->next = NULL; \ if (_last_elt_hh != NULL) { \ _last_elt_hh->next = _elt; \ } \ if ((dst) == NULL) { \ DECLTYPE_ASSIGN(dst, _elt); \ HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ IF_HASH_NONFATAL_OOM( \ if (_hs_oomed) { \ uthash_nonfatal_oom(_elt); \ (dst) = NULL; \ continue; \ } \ ) \ } else { \ _dst_hh->tbl = (dst)->hh_dst.tbl; \ } \ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ (dst)->hh_dst.tbl->num_items++; \ IF_HASH_NONFATAL_OOM( \ if (_hs_oomed) { \ HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ _dst_hh->tbl = NULL; \ uthash_nonfatal_oom(_elt); \ continue; \ } \ ) \ HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ _last_elt = _elt; \ _last_elt_hh = _dst_hh; \ } \ } \ } \ } \ HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ } while (0) #define HASH_CLEAR(hh,head) \ do { \ if ((head) != NULL) { \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head) = NULL; \ } \ } while (0) #define HASH_OVERHEAD(hh,head) \ (((head) != NULL) ? ( \ (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ sizeof(UT_hash_table) + \ (HASH_BLOOM_BYTELEN))) : 0U) #ifdef NO_DECLTYPE #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) #else #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) #endif /* obtain a count of items in the hash */ #define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; /* expand_mult is normally set to 0. In this situation, the max chain length * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If * the bucket's chain exceeds this length, bucket expansion is triggered). * However, setting expand_mult to a non-zero value delays bucket expansion * (that would be triggered by additions to this particular bucket) * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. * (The multiplier is simply expand_mult+1). The whole idea of this * multiplier is to reduce bucket expansions, since they are expensive, in * situations where we know that a particular bucket tends to be overused. * It is better to let its chain length grow to a longer yet-still-bounded * value, than to do an O(n) bucket expansion too often. */ unsigned expand_mult; } UT_hash_bucket; /* random signature used only to find hash tables in external analysis */ #define HASH_SIGNATURE 0xa0111fe1u #define HASH_BLOOM_SIGNATURE 0xb12220f2u typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ /* in an ideal situation (all buckets used equally), no bucket would have * more than ceil(#items/#buckets) items. that's the ideal chain length. */ unsigned ideal_chain_maxlen; /* nonideal_items is the number of items in the hash whose chain position * exceeds the ideal chain maxlen. these items pay the penalty for an uneven * hash distribution; reaching them in a chain traversal takes >ideal steps */ unsigned nonideal_items; /* ineffective expands occur when a bucket doubling was performed, but * afterward, more than half the items in the hash had nonideal chain * positions. If this happens on two consecutive expansions we inhibit any * further expansion, as it's not helping; this happens when the hash * function isn't a good fit for the key domain. When expansion is inhibited * the hash will still work, albeit no longer in constant time. */ unsigned ineff_expands, noexpand; uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ uint8_t *bloom_bv; uint8_t bloom_nbits; #endif } UT_hash_table; typedef struct UT_hash_handle { struct UT_hash_table *tbl; void *prev; /* prev element in app order */ void *next; /* next element in app order */ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ struct UT_hash_handle *hh_next; /* next hh in bucket order */ const void *key; /* ptr to enclosing struct's key */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ mongodb-1.21.0/src/libmongoc/src/uthash/uthash-2.3.0/utlist.h0000644000175100001660000023714014760300420020416 0ustar /* Copyright (c) 2007-2021, Troy D. Hanson http://troydhanson.github.com/uthash/ 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTLIST_H #define UTLIST_H #define UTLIST_VERSION 2.3.0 #include /* * This file contains macros to manipulate singly and doubly-linked lists. * * 1. LL_ macros: singly-linked lists. * 2. DL_ macros: doubly-linked lists. * 3. CDL_ macros: circular doubly-linked lists. * * To use singly-linked lists, your structure must have a "next" pointer. * To use doubly-linked lists, your structure must "prev" and "next" pointers. * Either way, the pointer to the head of the list must be initialized to NULL. * * ----------------.EXAMPLE ------------------------- * struct item { * int id; * struct item *prev, *next; * } * * struct item *list = NULL: * * int main() { * struct item *item; * ... allocate and populate item ... * DL_APPEND(list, item); * } * -------------------------------------------------- * * For doubly-linked lists, the append and delete macros are O(1) * For singly-linked lists, append and delete are O(n) but prepend is O(1) * The sort macro is O(n log(n)) for all types of single/double/circular lists. */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #if !defined(LDECLTYPE) && !defined(NO_DECLTYPE) #if defined(_MSC_VER) /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define LDECLTYPE(x) decltype(x) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE #else /* GNU, Sun and other compilers */ #define LDECLTYPE(x) __typeof(x) #endif #endif /* for VS2008 we use some workarounds to get around the lack of decltype, * namely, we always reassign our tmp variable to the list head if we need * to dereference its prev/next pointers, and save/restore the real head.*/ #ifdef NO_DECLTYPE #define IF_NO_DECLTYPE(x) x #define LDECLTYPE(x) char* #define UTLIST_SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } #define UTLIST_NEXT(elt,list,next) ((char*)((list)->next)) #define UTLIST_NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } /* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */ #define UTLIST_PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } #define UTLIST_RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } #define UTLIST_CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } #else #define IF_NO_DECLTYPE(x) #define UTLIST_SV(elt,list) #define UTLIST_NEXT(elt,list,next) ((elt)->next) #define UTLIST_NEXTASGN(elt,list,to,next) ((elt)->next)=(to) /* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */ #define UTLIST_PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) #define UTLIST_RS(list) #define UTLIST_CASTASGN(a,b) (a)=(b) #endif /****************************************************************************** * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * * Unwieldy variable names used here to avoid shadowing passed-in variables. * *****************************************************************************/ #define LL_SORT(list, cmp) \ LL_SORT2(list, cmp, next) #define LL_SORT2(list, cmp, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ UTLIST_CASTASGN(_ls_p,list); \ (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ } else { \ UTLIST_CASTASGN(list,_ls_e); \ } \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ if (_ls_tail) { \ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ } \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define DL_SORT(list, cmp) \ DL_SORT2(list, cmp, prev, next) #define DL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ UTLIST_CASTASGN(_ls_p,list); \ (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ } else if ((_ls_qsize == 0) || (!_ls_q)) { \ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ } else { \ UTLIST_CASTASGN(list,_ls_e); \ } \ UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ UTLIST_CASTASGN((list)->prev, _ls_tail); \ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define CDL_SORT(list, cmp) \ CDL_SORT2(list, cmp, prev, next) #define CDL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ LDECLTYPE(list) _ls_oldhead; \ LDECLTYPE(list) _tmp; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ UTLIST_CASTASGN(_ls_p,list); \ UTLIST_CASTASGN(_ls_oldhead,list); \ (list) = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ UTLIST_SV(_ls_q,list); \ if (UTLIST_NEXT(_ls_q,list,next) == _ls_oldhead) { \ _ls_q = NULL; \ } else { \ _ls_q = UTLIST_NEXT(_ls_q,list,next); \ } \ UTLIST_RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p = \ UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else { \ _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q = \ UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } \ if (_ls_tail) { \ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \ } else { \ UTLIST_CASTASGN(list,_ls_e); \ } \ UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ UTLIST_CASTASGN((list)->prev,_ls_tail); \ UTLIST_CASTASGN(_tmp,list); \ UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_tmp,next); UTLIST_RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) /****************************************************************************** * singly linked list macros (non-circular) * *****************************************************************************/ #define LL_PREPEND(head,add) \ LL_PREPEND2(head,add,next) #define LL_PREPEND2(head,add,next) \ do { \ (add)->next = (head); \ (head) = (add); \ } while (0) #define LL_CONCAT(head1,head2) \ LL_CONCAT2(head1,head2,next) #define LL_CONCAT2(head1,head2,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head1) { \ _tmp = (head1); \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(head2); \ } else { \ (head1)=(head2); \ } \ } while (0) #define LL_APPEND(head,add) \ LL_APPEND2(head,add,next) #define LL_APPEND2(head,add,next) \ do { \ LDECLTYPE(head) _tmp; \ (add)->next=NULL; \ if (head) { \ _tmp = (head); \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(add); \ } else { \ (head)=(add); \ } \ } while (0) #define LL_INSERT_INORDER(head,add,cmp) \ LL_INSERT_INORDER2(head,add,cmp,next) #define LL_INSERT_INORDER2(head,add,cmp,next) \ do { \ LDECLTYPE(head) _tmp; \ if (head) { \ LL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ LL_APPEND_ELEM2(head, _tmp, add, next); \ } else { \ (head) = (add); \ (head)->next = NULL; \ } \ } while (0) #define LL_LOWER_BOUND(head,elt,like,cmp) \ LL_LOWER_BOUND2(head,elt,like,cmp,next) #define LL_LOWER_BOUND2(head,elt,like,cmp,next) \ do { \ if ((head) == NULL || (cmp(head, like)) >= 0) { \ (elt) = NULL; \ } else { \ for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ if (cmp((elt)->next, like) >= 0) { \ break; \ } \ } \ } \ } while (0) #define LL_DELETE(head,del) \ LL_DELETE2(head,del,next) #define LL_DELETE2(head,del,next) \ do { \ LDECLTYPE(head) _tmp; \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ _tmp = (head); \ while (_tmp->next && (_tmp->next != (del))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (del)->next; \ } \ } \ } while (0) #define LL_COUNT(head,el,counter) \ LL_COUNT2(head,el,counter,next) \ #define LL_COUNT2(head,el,counter,next) \ do { \ (counter) = 0; \ LL_FOREACH2(head,el,next) { ++(counter); } \ } while (0) #define LL_FOREACH(head,el) \ LL_FOREACH2(head,el,next) #define LL_FOREACH2(head,el,next) \ for ((el) = (head); el; (el) = (el)->next) #define LL_FOREACH_SAFE(head,el,tmp) \ LL_FOREACH_SAFE2(head,el,tmp,next) #define LL_FOREACH_SAFE2(head,el,tmp,next) \ for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) #define LL_SEARCH_SCALAR(head,out,field,val) \ LL_SEARCH_SCALAR2(head,out,field,val,next) #define LL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while (0) #define LL_SEARCH(head,out,elt,cmp) \ LL_SEARCH2(head,out,elt,cmp,next) #define LL_SEARCH2(head,out,elt,cmp,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while (0) #define LL_REPLACE_ELEM2(head, el, add, next) \ do { \ LDECLTYPE(head) _tmp; \ assert((head) != NULL); \ assert((el) != NULL); \ assert((add) != NULL); \ (add)->next = (el)->next; \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = (head); \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } while (0) #define LL_REPLACE_ELEM(head, el, add) \ LL_REPLACE_ELEM2(head, el, add, next) #define LL_PREPEND_ELEM2(head, el, add, next) \ do { \ if (el) { \ LDECLTYPE(head) _tmp; \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = (head); \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } else { \ LL_APPEND2(head, add, next); \ } \ } while (0) \ #define LL_PREPEND_ELEM(head, el, add) \ LL_PREPEND_ELEM2(head, el, add, next) #define LL_APPEND_ELEM2(head, el, add, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el)->next; \ (el)->next = (add); \ } else { \ LL_PREPEND2(head, add, next); \ } \ } while (0) \ #define LL_APPEND_ELEM(head, el, add) \ LL_APPEND_ELEM2(head, el, add, next) #ifdef NO_DECLTYPE /* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ #undef LL_CONCAT2 #define LL_CONCAT2(head1,head2,next) \ do { \ char *_tmp; \ if (head1) { \ _tmp = (char*)(head1); \ while ((head1)->next) { (head1) = (head1)->next; } \ (head1)->next = (head2); \ UTLIST_RS(head1); \ } else { \ (head1)=(head2); \ } \ } while (0) #undef LL_APPEND2 #define LL_APPEND2(head,add,next) \ do { \ if (head) { \ (add)->next = head; /* use add->next as a temp variable */ \ while ((add)->next->next) { (add)->next = (add)->next->next; } \ (add)->next->next=(add); \ } else { \ (head)=(add); \ } \ (add)->next=NULL; \ } while (0) #undef LL_INSERT_INORDER2 #define LL_INSERT_INORDER2(head,add,cmp,next) \ do { \ if ((head) == NULL || (cmp(head, add)) >= 0) { \ (add)->next = (head); \ (head) = (add); \ } else { \ char *_tmp = (char*)(head); \ while ((head)->next != NULL && (cmp((head)->next, add)) < 0) { \ (head) = (head)->next; \ } \ (add)->next = (head)->next; \ (head)->next = (add); \ UTLIST_RS(head); \ } \ } while (0) #undef LL_DELETE2 #define LL_DELETE2(head,del,next) \ do { \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ char *_tmp = (char*)(head); \ while ((head)->next && ((head)->next != (del))) { \ (head) = (head)->next; \ } \ if ((head)->next) { \ (head)->next = ((del)->next); \ } \ UTLIST_RS(head); \ } \ } while (0) #undef LL_REPLACE_ELEM2 #define LL_REPLACE_ELEM2(head, el, add, next) \ do { \ assert((head) != NULL); \ assert((el) != NULL); \ assert((add) != NULL); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->next = head; \ while ((add)->next->next && ((add)->next->next != (el))) { \ (add)->next = (add)->next->next; \ } \ if ((add)->next->next) { \ (add)->next->next = (add); \ } \ } \ (add)->next = (el)->next; \ } while (0) #undef LL_PREPEND_ELEM2 #define LL_PREPEND_ELEM2(head, el, add, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->next = (head); \ while ((add)->next->next && ((add)->next->next != (el))) { \ (add)->next = (add)->next->next; \ } \ if ((add)->next->next) { \ (add)->next->next = (add); \ } \ } \ (add)->next = (el); \ } else { \ LL_APPEND2(head, add, next); \ } \ } while (0) \ #endif /* NO_DECLTYPE */ /****************************************************************************** * doubly linked list macros (non-circular) * *****************************************************************************/ #define DL_PREPEND(head,add) \ DL_PREPEND2(head,add,prev,next) #define DL_PREPEND2(head,add,prev,next) \ do { \ (add)->next = (head); \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev = (add); \ } else { \ (add)->prev = (add); \ } \ (head) = (add); \ } while (0) #define DL_APPEND(head,add) \ DL_APPEND2(head,add,prev,next) #define DL_APPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev->next = (add); \ (head)->prev = (add); \ (add)->next = NULL; \ } else { \ (head)=(add); \ (head)->prev = (head); \ (head)->next = NULL; \ } \ } while (0) #define DL_INSERT_INORDER(head,add,cmp) \ DL_INSERT_INORDER2(head,add,cmp,prev,next) #define DL_INSERT_INORDER2(head,add,cmp,prev,next) \ do { \ LDECLTYPE(head) _tmp; \ if (head) { \ DL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ DL_APPEND_ELEM2(head, _tmp, add, prev, next); \ } else { \ (head) = (add); \ (head)->prev = (head); \ (head)->next = NULL; \ } \ } while (0) #define DL_LOWER_BOUND(head,elt,like,cmp) \ DL_LOWER_BOUND2(head,elt,like,cmp,next) #define DL_LOWER_BOUND2(head,elt,like,cmp,next) \ do { \ if ((head) == NULL || (cmp(head, like)) >= 0) { \ (elt) = NULL; \ } else { \ for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ if ((cmp((elt)->next, like)) >= 0) { \ break; \ } \ } \ } \ } while (0) #define DL_CONCAT(head1,head2) \ DL_CONCAT2(head1,head2,prev,next) #define DL_CONCAT2(head1,head2,prev,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head2) { \ if (head1) { \ UTLIST_CASTASGN(_tmp, (head2)->prev); \ (head2)->prev = (head1)->prev; \ (head1)->prev->next = (head2); \ UTLIST_CASTASGN((head1)->prev, _tmp); \ } else { \ (head1)=(head2); \ } \ } \ } while (0) #define DL_DELETE(head,del) \ DL_DELETE2(head,del,prev,next) #define DL_DELETE2(head,del,prev,next) \ do { \ assert((head) != NULL); \ assert((del)->prev != NULL); \ if ((del)->prev == (del)) { \ (head)=NULL; \ } else if ((del)==(head)) { \ (del)->next->prev = (del)->prev; \ (head) = (del)->next; \ } else { \ (del)->prev->next = (del)->next; \ if ((del)->next) { \ (del)->next->prev = (del)->prev; \ } else { \ (head)->prev = (del)->prev; \ } \ } \ } while (0) #define DL_COUNT(head,el,counter) \ DL_COUNT2(head,el,counter,next) \ #define DL_COUNT2(head,el,counter,next) \ do { \ (counter) = 0; \ DL_FOREACH2(head,el,next) { ++(counter); } \ } while (0) #define DL_FOREACH(head,el) \ DL_FOREACH2(head,el,next) #define DL_FOREACH2(head,el,next) \ for ((el) = (head); el; (el) = (el)->next) /* this version is safe for deleting the elements during iteration */ #define DL_FOREACH_SAFE(head,el,tmp) \ DL_FOREACH_SAFE2(head,el,tmp,next) #define DL_FOREACH_SAFE2(head,el,tmp,next) \ for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) /* these are identical to their singly-linked list counterparts */ #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR #define DL_SEARCH LL_SEARCH #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 #define DL_SEARCH2 LL_SEARCH2 #define DL_REPLACE_ELEM2(head, el, add, prev, next) \ do { \ assert((head) != NULL); \ assert((el) != NULL); \ assert((add) != NULL); \ if ((head) == (el)) { \ (head) = (add); \ (add)->next = (el)->next; \ if ((el)->next == NULL) { \ (add)->prev = (add); \ } else { \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ } \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->prev->next = (add); \ if ((el)->next == NULL) { \ (head)->prev = (add); \ } else { \ (add)->next->prev = (add); \ } \ } \ } while (0) #define DL_REPLACE_ELEM(head, el, add) \ DL_REPLACE_ELEM2(head, el, add, prev, next) #define DL_PREPEND_ELEM2(head, el, add, prev, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->prev->next = (add); \ } \ } else { \ DL_APPEND2(head, add, prev, next); \ } \ } while (0) \ #define DL_PREPEND_ELEM(head, el, add) \ DL_PREPEND_ELEM2(head, el, add, prev, next) #define DL_APPEND_ELEM2(head, el, add, prev, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el)->next; \ (add)->prev = (el); \ (el)->next = (add); \ if ((add)->next) { \ (add)->next->prev = (add); \ } else { \ (head)->prev = (add); \ } \ } else { \ DL_PREPEND2(head, add, prev, next); \ } \ } while (0) \ #define DL_APPEND_ELEM(head, el, add) \ DL_APPEND_ELEM2(head, el, add, prev, next) #ifdef NO_DECLTYPE /* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ #undef DL_INSERT_INORDER2 #define DL_INSERT_INORDER2(head,add,cmp,prev,next) \ do { \ if ((head) == NULL) { \ (add)->prev = (add); \ (add)->next = NULL; \ (head) = (add); \ } else if ((cmp(head, add)) >= 0) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (head)->prev = (add); \ (head) = (add); \ } else { \ char *_tmp = (char*)(head); \ while ((head)->next && (cmp((head)->next, add)) < 0) { \ (head) = (head)->next; \ } \ (add)->prev = (head); \ (add)->next = (head)->next; \ (head)->next = (add); \ UTLIST_RS(head); \ if ((add)->next) { \ (add)->next->prev = (add); \ } else { \ (head)->prev = (add); \ } \ } \ } while (0) #endif /* NO_DECLTYPE */ /****************************************************************************** * circular doubly linked list macros * *****************************************************************************/ #define CDL_APPEND(head,add) \ CDL_APPEND2(head,add,prev,next) #define CDL_APPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (head)->prev = (add); \ (add)->prev->next = (add); \ } else { \ (add)->prev = (add); \ (add)->next = (add); \ (head) = (add); \ } \ } while (0) #define CDL_PREPEND(head,add) \ CDL_PREPEND2(head,add,prev,next) #define CDL_PREPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (head)->prev = (add); \ (add)->prev->next = (add); \ } else { \ (add)->prev = (add); \ (add)->next = (add); \ } \ (head) = (add); \ } while (0) #define CDL_INSERT_INORDER(head,add,cmp) \ CDL_INSERT_INORDER2(head,add,cmp,prev,next) #define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \ do { \ LDECLTYPE(head) _tmp; \ if (head) { \ CDL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ CDL_APPEND_ELEM2(head, _tmp, add, prev, next); \ } else { \ (head) = (add); \ (head)->next = (head); \ (head)->prev = (head); \ } \ } while (0) #define CDL_LOWER_BOUND(head,elt,like,cmp) \ CDL_LOWER_BOUND2(head,elt,like,cmp,next) #define CDL_LOWER_BOUND2(head,elt,like,cmp,next) \ do { \ if ((head) == NULL || (cmp(head, like)) >= 0) { \ (elt) = NULL; \ } else { \ for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) { \ if ((cmp((elt)->next, like)) >= 0) { \ break; \ } \ } \ } \ } while (0) #define CDL_DELETE(head,del) \ CDL_DELETE2(head,del,prev,next) #define CDL_DELETE2(head,del,prev,next) \ do { \ if (((head)==(del)) && ((head)->next == (head))) { \ (head) = NULL; \ } else { \ (del)->next->prev = (del)->prev; \ (del)->prev->next = (del)->next; \ if ((del) == (head)) (head)=(del)->next; \ } \ } while (0) #define CDL_COUNT(head,el,counter) \ CDL_COUNT2(head,el,counter,next) \ #define CDL_COUNT2(head, el, counter,next) \ do { \ (counter) = 0; \ CDL_FOREACH2(head,el,next) { ++(counter); } \ } while (0) #define CDL_FOREACH(head,el) \ CDL_FOREACH2(head,el,next) #define CDL_FOREACH2(head,el,next) \ for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next)) #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \ (el) && ((tmp2) = (el)->next, 1); \ (el) = ((el) == (tmp1) ? NULL : (tmp2))) #define CDL_SEARCH_SCALAR(head,out,field,val) \ CDL_SEARCH_SCALAR2(head,out,field,val,next) #define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while (0) #define CDL_SEARCH(head,out,elt,cmp) \ CDL_SEARCH2(head,out,elt,cmp,next) #define CDL_SEARCH2(head,out,elt,cmp,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while (0) #define CDL_REPLACE_ELEM2(head, el, add, prev, next) \ do { \ assert((head) != NULL); \ assert((el) != NULL); \ assert((add) != NULL); \ if ((el)->next == (el)) { \ (add)->next = (add); \ (add)->prev = (add); \ (head) = (add); \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } \ } while (0) #define CDL_REPLACE_ELEM(head, el, add) \ CDL_REPLACE_ELEM2(head, el, add, prev, next) #define CDL_PREPEND_ELEM2(head, el, add, prev, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } else { \ CDL_APPEND2(head, add, prev, next); \ } \ } while (0) #define CDL_PREPEND_ELEM(head, el, add) \ CDL_PREPEND_ELEM2(head, el, add, prev, next) #define CDL_APPEND_ELEM2(head, el, add, prev, next) \ do { \ if (el) { \ assert((head) != NULL); \ assert((add) != NULL); \ (add)->next = (el)->next; \ (add)->prev = (el); \ (el)->next = (add); \ (add)->next->prev = (add); \ } else { \ CDL_PREPEND2(head, add, prev, next); \ } \ } while (0) #define CDL_APPEND_ELEM(head, el, add) \ CDL_APPEND_ELEM2(head, el, add, prev, next) #ifdef NO_DECLTYPE /* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ #undef CDL_INSERT_INORDER2 #define CDL_INSERT_INORDER2(head,add,cmp,prev,next) \ do { \ if ((head) == NULL) { \ (add)->prev = (add); \ (add)->next = (add); \ (head) = (add); \ } else if ((cmp(head, add)) >= 0) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (add)->prev->next = (add); \ (head)->prev = (add); \ (head) = (add); \ } else { \ char *_tmp = (char*)(head); \ while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) { \ (head) = (head)->next; \ } \ (add)->prev = (head); \ (add)->next = (head)->next; \ (add)->next->prev = (add); \ (head)->next = (add); \ UTLIST_RS(head); \ } \ } while (0) #endif /* NO_DECLTYPE */ #endif /* UTLIST_H */ mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/adler32.c0000644000175100001660000001154414760300420016467 0ustar /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /* use NO_DIVIDE if your processor does not do division in hardware -- try it both ways to see which is faster */ #ifdef NO_DIVIDE /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 (thank you to John Reiser for pointing this out) */ # define CHOP(a) \ do { \ unsigned long tmp = a >> 16; \ a &= 0xffffUL; \ a += (tmp << 4) - tmp; \ } while (0) # define MOD28(a) \ do { \ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) # define MOD(a) \ do { \ CHOP(a); \ MOD28(a); \ } while (0) # define MOD63(a) \ do { /* this assumes a is not negative */ \ z_off64_t tmp = a >> 32; \ a &= 0xffffffffL; \ a += (tmp << 8) - (tmp << 5) + tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { return adler32_z(adler, buf, len); } /* ========================================================================= */ local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { return adler32_combine_(adler1, adler2, len2); } uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { return adler32_combine_(adler1, adler2, len2); } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/compress.c0000644000175100001660000000506514760300420017067 0ustar /* compress.c -- compress a memory buffer * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level) { z_stream stream; int err; const uInt max = (uInt)-1; uLong left; left = *destLen; *destLen = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = deflateInit(&stream, level); if (err != Z_OK) return err; stream.next_out = dest; stream.avail_out = 0; stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; do { if (stream.avail_out == 0) { stream.avail_out = left > (uLong)max ? max : (uInt)left; left -= stream.avail_out; } if (stream.avail_in == 0) { stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; sourceLen -= stream.avail_in; } err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); } while (err == Z_OK); *destLen = stream.total_out; deflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== */ int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ uLong ZEXPORT compressBound(uLong sourceLen) { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/crc32.c0000644000175100001660000007556514760300420016164 0ustar /* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * This interleaved implementation of a CRC makes use of pipelined multiple * arithmetic-logic units, commonly found in modern CPU cores. It is due to * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). MAKECRCH can be #defined to write out crc32.h. A main() routine is also produced, so that this one source file can be compiled to an executable. */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */ /* A CRC of a message is computed on N braids of words in the message, where each word consists of W bytes (4 or 8). If N is 3, for example, then three running sparse CRCs are calculated respectively on each braid, at these indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ... This is done starting at a word boundary, and continues until as many blocks of N * W bytes as are available have been processed. The results are combined into a single CRC at the end. For this code, N must be in the range 1..6 and W must be 4 or 8. The upper limit on N can be increased if desired by adding more #if blocks, extending the patterns apparent in the code. In addition, crc32.h would need to be regenerated, if the maximum N value is increased. N and W are chosen empirically by benchmarking the execution time on a given processor. The choices for N and W below were based on testing on Intel Kaby Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64 Octeon II processors. The Intel, AMD, and ARM processors were all fastest with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4. They were all tested with either gcc or clang, all using the -O3 optimization level. Your mileage may vary. */ /* Define N */ #ifdef Z_TESTN # define N Z_TESTN #else # define N 5 #endif #if N < 1 || N > 6 # error N must be in 1..6 #endif /* z_crc_t must be at least 32 bits. z_word_t must be at least as long as z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and that bytes are eight bits. */ /* Define W and the associated z_word_t type. If W is not defined, then a braided calculation is not used, and the associated tables and code are not compiled. */ #ifdef Z_TESTW # if Z_TESTW-1 != -1 # define W Z_TESTW # endif #else # ifdef MAKECRCH # define W 8 /* required for MAKECRCH */ # else # if defined(__x86_64__) || defined(__aarch64__) # define W 8 # else # define W 4 # endif # endif #endif #ifdef W # if W == 8 && defined(Z_U8) typedef Z_U8 z_word_t; # elif defined(Z_U4) # undef W # define W 4 typedef Z_U4 z_word_t; # else # undef W # endif #endif /* If available, use the ARM processor CRC32 instruction. */ #if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 # define ARMCRC32 #endif #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) /* Swap the bytes in a z_word_t to convert between little and big endian. Any self-respecting compiler will optimize this to a single machine byte-swap instruction, if one is available. This assumes that word_t is either 32 bits or 64 bits. */ local z_word_t byte_swap(z_word_t word) { # if W == 8 return (word & 0xff00000000000000) >> 56 | (word & 0xff000000000000) >> 40 | (word & 0xff0000000000) >> 24 | (word & 0xff00000000) >> 8 | (word & 0xff000000) << 8 | (word & 0xff0000) << 24 | (word & 0xff00) << 40 | (word & 0xff) << 56; # else /* W == 4 */ return (word & 0xff000000) >> 24 | (word & 0xff0000) >> 8 | (word & 0xff00) << 8 | (word & 0xff) << 24; # endif } #endif #ifdef DYNAMIC_CRC_TABLE /* ========================================================================= * Table of powers of x for combining CRC-32s, filled in by make_crc_table() * below. */ local z_crc_t FAR x2n_table[32]; #else /* ========================================================================= * Tables for byte-wise and braided CRC-32 calculations, and a table of powers * of x for combining CRC-32s, all made by make_crc_table(). */ # include "crc32.h" #endif /* CRC polynomial. */ #define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ /* Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, reflected. For speed, this requires that a not be zero. */ local z_crc_t multmodp(z_crc_t a, z_crc_t b) { z_crc_t m, p; m = (z_crc_t)1 << 31; p = 0; for (;;) { if (a & m) { p ^= b; if ((a & (m - 1)) == 0) break; } m >>= 1; b = b & 1 ? (b >> 1) ^ POLY : b >> 1; } return p; } /* Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been initialized. */ local z_crc_t x2nmodp(z_off64_t n, unsigned k) { z_crc_t p; p = (z_crc_t)1 << 31; /* x^0 == 1 */ while (n) { if (n & 1) p = multmodp(x2n_table[k & 31], p); n >>= 1; k++; } return p; } #ifdef DYNAMIC_CRC_TABLE /* ========================================================================= * Build the tables for byte-wise and braided CRC-32 calculations, and a table * of powers of x for combining CRC-32s. */ local z_crc_t FAR crc_table[256]; #ifdef W local z_word_t FAR crc_big_table[256]; local z_crc_t FAR crc_braid_table[W][256]; local z_word_t FAR crc_braid_big_table[W][256]; local void braid(z_crc_t [][256], z_word_t [][256], int, int); #endif #ifdef MAKECRCH local void write_table(FILE *, const z_crc_t FAR *, int); local void write_table32hi(FILE *, const z_word_t FAR *, int); local void write_table64(FILE *, const z_word_t FAR *, int); #endif /* MAKECRCH */ /* Define a once() function depending on the availability of atomics. If this is compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in multiple threads, and if atomics are not available, then get_crc_table() must be called to initialize the tables and must return before any threads are allowed to compute or combine CRCs. */ /* Definition of once functionality. */ typedef struct once_s once_t; /* Check for the availability of atomics. */ #if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ !defined(__STDC_NO_ATOMICS__) #include /* Structure for once(), which must be initialized with ONCE_INIT. */ struct once_s { atomic_flag begun; atomic_int done; }; #define ONCE_INIT {ATOMIC_FLAG_INIT, 0} /* Run the provided init() function exactly once, even if multiple threads invoke once() at the same time. The state must be a once_t initialized with ONCE_INIT. */ local void once(once_t *state, void (*init)(void)) { if (!atomic_load(&state->done)) { if (atomic_flag_test_and_set(&state->begun)) while (!atomic_load(&state->done)) ; else { init(); atomic_store(&state->done, 1); } } } #else /* no atomics */ /* Structure for once(), which must be initialized with ONCE_INIT. */ struct once_s { volatile int begun; volatile int done; }; #define ONCE_INIT {0, 0} /* Test and set. Alas, not atomic, but tries to minimize the period of vulnerability. */ local int test_and_set(int volatile *flag) { int was; was = *flag; *flag = 1; return was; } /* Run the provided init() function once. This is not thread-safe. */ local void once(once_t *state, void (*init)(void)) { if (!state->done) { if (test_and_set(&state->begun)) while (!state->done) ; else { init(); state->done = 1; } } } #endif /* State for once(). */ local once_t made = ONCE_INIT; /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. */ local void make_crc_table(void) { unsigned i, j, n; z_crc_t p; /* initialize the CRC of bytes tables */ for (i = 0; i < 256; i++) { p = i; for (j = 0; j < 8; j++) p = p & 1 ? (p >> 1) ^ POLY : p >> 1; crc_table[i] = p; #ifdef W crc_big_table[i] = byte_swap(p); #endif } /* initialize the x^2^n mod p(x) table */ p = (z_crc_t)1 << 30; /* x^1 */ x2n_table[0] = p; for (n = 1; n < 32; n++) x2n_table[n] = p = multmodp(p, p); #ifdef W /* initialize the braiding tables -- needs x2n_table[] */ braid(crc_braid_table, crc_braid_big_table, N, W); #endif #ifdef MAKECRCH { /* The crc32.h header file contains tables for both 32-bit and 64-bit z_word_t's, and so requires a 64-bit type be available. In that case, z_word_t must be defined to be 64-bits. This code then also generates and writes out the tables for the case that z_word_t is 32 bits. */ #if !defined(W) || W != 8 # error Need a 64-bit integer type in order to generate crc32.h. #endif FILE *out; int k, n; z_crc_t ltl[8][256]; z_word_t big[8][256]; out = fopen("crc32.h", "w"); if (out == NULL) return; /* write out little-endian CRC table to crc32.h */ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n" " * Generated automatically by crc32.c\n */\n" "\n" "local const z_crc_t FAR crc_table[] = {\n" " "); write_table(out, crc_table, 256); fprintf(out, "};\n"); /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */ fprintf(out, "\n" "#ifdef W\n" "\n" "#if W == 8\n" "\n" "local const z_word_t FAR crc_big_table[] = {\n" " "); write_table64(out, crc_big_table, 256); fprintf(out, "};\n"); /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */ fprintf(out, "\n" "#else /* W == 4 */\n" "\n" "local const z_word_t FAR crc_big_table[] = {\n" " "); write_table32hi(out, crc_big_table, 256); fprintf(out, "};\n" "\n" "#endif\n"); /* write out braid tables for each value of N */ for (n = 1; n <= 6; n++) { fprintf(out, "\n" "#if N == %d\n", n); /* compute braid tables for this N and 64-bit word_t */ braid(ltl, big, n, 8); /* write out braid tables for 64-bit z_word_t to crc32.h */ fprintf(out, "\n" "#if W == 8\n" "\n" "local const z_crc_t FAR crc_braid_table[][256] = {\n"); for (k = 0; k < 8; k++) { fprintf(out, " {"); write_table(out, ltl[k], 256); fprintf(out, "}%s", k < 7 ? ",\n" : ""); } fprintf(out, "};\n" "\n" "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); for (k = 0; k < 8; k++) { fprintf(out, " {"); write_table64(out, big[k], 256); fprintf(out, "}%s", k < 7 ? ",\n" : ""); } fprintf(out, "};\n"); /* compute braid tables for this N and 32-bit word_t */ braid(ltl, big, n, 4); /* write out braid tables for 32-bit z_word_t to crc32.h */ fprintf(out, "\n" "#else /* W == 4 */\n" "\n" "local const z_crc_t FAR crc_braid_table[][256] = {\n"); for (k = 0; k < 4; k++) { fprintf(out, " {"); write_table(out, ltl[k], 256); fprintf(out, "}%s", k < 3 ? ",\n" : ""); } fprintf(out, "};\n" "\n" "local const z_word_t FAR crc_braid_big_table[][256] = {\n"); for (k = 0; k < 4; k++) { fprintf(out, " {"); write_table32hi(out, big[k], 256); fprintf(out, "}%s", k < 3 ? ",\n" : ""); } fprintf(out, "};\n" "\n" "#endif\n" "\n" "#endif\n"); } fprintf(out, "\n" "#endif\n"); /* write out zeros operator table to crc32.h */ fprintf(out, "\n" "local const z_crc_t FAR x2n_table[] = {\n" " "); write_table(out, x2n_table, 32); fprintf(out, "};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH /* Write the 32-bit values in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ local void write_table(FILE *out, const z_crc_t FAR *table, int k) { int n; for (n = 0; n < k; n++) fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", (unsigned long)(table[n]), n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); } /* Write the high 32-bits of each value in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) { int n; for (n = 0; n < k; n++) fprintf(out, "%s0x%08lx%s", n == 0 || n % 5 ? "" : " ", (unsigned long)(table[n] >> 32), n == k - 1 ? "" : (n % 5 == 4 ? ",\n" : ", ")); } /* Write the 64-bit values in table[0..k-1] to out, three per line in hexadecimal separated by commas. This assumes that if there is a 64-bit type, then there is also a long long integer type, and it is at least 64 bits. If not, then the type cast and format string can be adjusted accordingly. */ local void write_table64(FILE *out, const z_word_t FAR *table, int k) { int n; for (n = 0; n < k; n++) fprintf(out, "%s0x%016llx%s", n == 0 || n % 3 ? "" : " ", (unsigned long long)(table[n]), n == k - 1 ? "" : (n % 3 == 2 ? ",\n" : ", ")); } /* Actually do the deed. */ int main(void) { make_crc_table(); return 0; } #endif /* MAKECRCH */ #ifdef W /* Generate the little and big-endian braid tables for the given n and z_word_t size w. Each array must have room for w blocks of 256 elements. */ local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { int k; z_crc_t i, p, q; for (k = 0; k < w; k++) { p = x2nmodp((n * w + 3 - k) << 3, 0); ltl[k][0] = 0; big[w - 1 - k][0] = 0; for (i = 1; i < 256; i++) { ltl[k][i] = q = multmodp(i << 24, p); big[w - 1 - k][i] = byte_swap(q); } } } #endif #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32(), and to force the * generation of the CRC tables in a threaded application. */ const z_crc_t FAR * ZEXPORT get_crc_table(void) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t FAR *)crc_table; } /* ========================================================================= * Use ARM machine instructions if available. This will compute the CRC about * ten times faster than the braided calculation. This code does not check for * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will * only be defined if the compilation specifies an ARM processor architecture * that has the instructions. For example, compiling with -march=armv8.1-a or * -march=armv8-a+crc, or -march=native if the compile machine has the crc32 * instructions. */ #ifdef ARMCRC32 /* Constants empirically determined to maximize speed. These values are from measurements on a Cortex-A57. Your mileage may vary. */ #define Z_BATCH 3990 /* number of words in a batch */ #define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ #define Z_BATCH_MIN 800 /* fewest words in a final batch */ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, z_size_t len) { z_crc_t val; z_word_t crc1, crc2; const z_word_t *word; z_word_t val0, val1, val2; z_size_t last, last2, i; z_size_t num; /* Return initial CRC, if requested. */ if (buf == Z_NULL) return 0; #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ crc = (~crc) & 0xffffffff; /* Compute the CRC up to a word boundary. */ while (len && ((z_size_t)buf & 7) != 0) { len--; val = *buf++; __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); } /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */ word = (z_word_t const *)buf; num = len >> 3; len &= 7; /* Do three interleaved CRCs to realize the throughput of one crc32x instruction per cycle. Each CRC is calculated on Z_BATCH words. The three CRCs are combined into a single CRC after each set of batches. */ while (num >= 3 * Z_BATCH) { crc1 = 0; crc2 = 0; for (i = 0; i < Z_BATCH; i++) { val0 = word[i]; val1 = word[i + Z_BATCH]; val2 = word[i + 2 * Z_BATCH]; __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); } word += 3 * Z_BATCH; num -= 3 * Z_BATCH; crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1; crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2; } /* Do one last smaller batch with the remaining words, if there are enough to pay for the combination of CRCs. */ last = num / 3; if (last >= Z_BATCH_MIN) { last2 = last << 1; crc1 = 0; crc2 = 0; for (i = 0; i < last; i++) { val0 = word[i]; val1 = word[i + last]; val2 = word[i + last2]; __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc1) : "r"(val1)); __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc2) : "r"(val2)); } word += 3 * last; num -= 3 * last; val = x2nmodp(last, 6); crc = multmodp(val, crc) ^ crc1; crc = multmodp(val, crc) ^ crc2; } /* Compute the CRC on any remaining words. */ for (i = 0; i < num; i++) { val0 = word[i]; __asm__ volatile("crc32x %w0, %w0, %x1" : "+r"(crc) : "r"(val0)); } word += num; /* Complete the CRC on any remaining bytes. */ buf = (const unsigned char FAR *)word; while (len) { len--; val = *buf++; __asm__ volatile("crc32b %w0, %w0, %w1" : "+r"(crc) : "r"(val)); } /* Return the CRC, post-conditioned. */ return crc ^ 0xffffffff; } #else #ifdef W /* Return the CRC of the W bytes in the word_t data, taking the least-significant byte of the word as the first byte of data, without any pre or post conditioning. This is used to combine the CRCs of each braid. */ local z_crc_t crc_word(z_word_t data) { int k; for (k = 0; k < W; k++) data = (data >> 8) ^ crc_table[data & 0xff]; return (z_crc_t)data; } local z_word_t crc_word_big(z_word_t data) { int k; for (k = 0; k < W; k++) data = (data << 8) ^ crc_big_table[(data >> ((W - 1) << 3)) & 0xff]; return data; } #endif /* ========================================================================= */ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, z_size_t len) { /* Return initial CRC, if requested. */ if (buf == Z_NULL) return 0; #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ /* Pre-condition the CRC */ crc = (~crc) & 0xffffffff; #ifdef W /* If provided enough bytes, do a braided CRC calculation. */ if (len >= N * W + W - 1) { z_size_t blks; z_word_t const *words; unsigned endian; int k; /* Compute the CRC up to a z_word_t boundary. */ while (len && ((z_size_t)buf & (W - 1)) != 0) { len--; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } /* Compute the CRC on as many N z_word_t blocks as are available. */ blks = len / (N * W); len -= blks * N * W; words = (z_word_t const *)buf; /* Do endian check at execution time instead of compile time, since ARM processors can change the endianness at execution time. If the compiler knows what the endianness will be, it can optimize out the check and the unused branch. */ endian = 1; if (*(unsigned char *)&endian) { /* Little endian. */ z_crc_t crc0; z_word_t word0; #if N > 1 z_crc_t crc1; z_word_t word1; #if N > 2 z_crc_t crc2; z_word_t word2; #if N > 3 z_crc_t crc3; z_word_t word3; #if N > 4 z_crc_t crc4; z_word_t word4; #if N > 5 z_crc_t crc5; z_word_t word5; #endif #endif #endif #endif #endif /* Initialize the CRC for each braid. */ crc0 = crc; #if N > 1 crc1 = 0; #if N > 2 crc2 = 0; #if N > 3 crc3 = 0; #if N > 4 crc4 = 0; #if N > 5 crc5 = 0; #endif #endif #endif #endif #endif /* Process the first blks-1 blocks, computing the CRCs on each braid independently. */ while (--blks) { /* Load the word for each braid into registers. */ word0 = crc0 ^ words[0]; #if N > 1 word1 = crc1 ^ words[1]; #if N > 2 word2 = crc2 ^ words[2]; #if N > 3 word3 = crc3 ^ words[3]; #if N > 4 word4 = crc4 ^ words[4]; #if N > 5 word5 = crc5 ^ words[5]; #endif #endif #endif #endif #endif words += N; /* Compute and update the CRC for each word. The loop should get unrolled. */ crc0 = crc_braid_table[0][word0 & 0xff]; #if N > 1 crc1 = crc_braid_table[0][word1 & 0xff]; #if N > 2 crc2 = crc_braid_table[0][word2 & 0xff]; #if N > 3 crc3 = crc_braid_table[0][word3 & 0xff]; #if N > 4 crc4 = crc_braid_table[0][word4 & 0xff]; #if N > 5 crc5 = crc_braid_table[0][word5 & 0xff]; #endif #endif #endif #endif #endif for (k = 1; k < W; k++) { crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff]; #if N > 1 crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff]; #if N > 2 crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff]; #if N > 3 crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff]; #if N > 4 crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff]; #if N > 5 crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff]; #endif #endif #endif #endif #endif } } /* Process the last block, combining the CRCs of the N braids at the same time. */ crc = crc_word(crc0 ^ words[0]); #if N > 1 crc = crc_word(crc1 ^ words[1] ^ crc); #if N > 2 crc = crc_word(crc2 ^ words[2] ^ crc); #if N > 3 crc = crc_word(crc3 ^ words[3] ^ crc); #if N > 4 crc = crc_word(crc4 ^ words[4] ^ crc); #if N > 5 crc = crc_word(crc5 ^ words[5] ^ crc); #endif #endif #endif #endif #endif words += N; } else { /* Big endian. */ z_word_t crc0, word0, comb; #if N > 1 z_word_t crc1, word1; #if N > 2 z_word_t crc2, word2; #if N > 3 z_word_t crc3, word3; #if N > 4 z_word_t crc4, word4; #if N > 5 z_word_t crc5, word5; #endif #endif #endif #endif #endif /* Initialize the CRC for each braid. */ crc0 = byte_swap(crc); #if N > 1 crc1 = 0; #if N > 2 crc2 = 0; #if N > 3 crc3 = 0; #if N > 4 crc4 = 0; #if N > 5 crc5 = 0; #endif #endif #endif #endif #endif /* Process the first blks-1 blocks, computing the CRCs on each braid independently. */ while (--blks) { /* Load the word for each braid into registers. */ word0 = crc0 ^ words[0]; #if N > 1 word1 = crc1 ^ words[1]; #if N > 2 word2 = crc2 ^ words[2]; #if N > 3 word3 = crc3 ^ words[3]; #if N > 4 word4 = crc4 ^ words[4]; #if N > 5 word5 = crc5 ^ words[5]; #endif #endif #endif #endif #endif words += N; /* Compute and update the CRC for each word. The loop should get unrolled. */ crc0 = crc_braid_big_table[0][word0 & 0xff]; #if N > 1 crc1 = crc_braid_big_table[0][word1 & 0xff]; #if N > 2 crc2 = crc_braid_big_table[0][word2 & 0xff]; #if N > 3 crc3 = crc_braid_big_table[0][word3 & 0xff]; #if N > 4 crc4 = crc_braid_big_table[0][word4 & 0xff]; #if N > 5 crc5 = crc_braid_big_table[0][word5 & 0xff]; #endif #endif #endif #endif #endif for (k = 1; k < W; k++) { crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff]; #if N > 1 crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff]; #if N > 2 crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff]; #if N > 3 crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff]; #if N > 4 crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff]; #if N > 5 crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff]; #endif #endif #endif #endif #endif } } /* Process the last block, combining the CRCs of the N braids at the same time. */ comb = crc_word_big(crc0 ^ words[0]); #if N > 1 comb = crc_word_big(crc1 ^ words[1] ^ comb); #if N > 2 comb = crc_word_big(crc2 ^ words[2] ^ comb); #if N > 3 comb = crc_word_big(crc3 ^ words[3] ^ comb); #if N > 4 comb = crc_word_big(crc4 ^ words[4] ^ comb); #if N > 5 comb = crc_word_big(crc5 ^ words[5] ^ comb); #endif #endif #endif #endif #endif words += N; crc = byte_swap(comb); } /* Update the pointer to the remaining bytes to process. */ buf = (unsigned char const *)words; } #endif /* W */ /* Complete the computation of the CRC on any remaining bytes. */ while (len >= 8) { len -= 8; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } while (len) { len--; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; } /* Return the CRC, post-conditioned. */ return crc ^ 0xffffffff; } #endif /* ========================================================================= */ unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, uInt len) { return crc32_z(crc, buf, len); } /* ========================================================================= */ uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff); } /* ========================================================================= */ uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { return crc32_combine64(crc1, crc2, (z_off64_t)len2); } /* ========================================================================= */ uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ return x2nmodp(len2, 3); } /* ========================================================================= */ uLong ZEXPORT crc32_combine_gen(z_off_t len2) { return crc32_combine_gen64((z_off64_t)len2); } /* ========================================================================= */ uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) { return multmodp(op, crc1) ^ (crc2 & 0xffffffff); } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/crc32.h0000644000175100001660000220360514760300420016157 0ustar /* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const z_crc_t FAR crc_table[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; #ifdef W #if W == 8 local const z_word_t FAR crc_big_table[] = { 0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, 0x8def022d00000000}; #else /* W == 4 */ local const z_word_t FAR crc_big_table[] = { 0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, 0x8def022d}; #endif #if N == 1 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6}, {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, 0x92364a30}, {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, 0xe4c4abcc}, {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, 0xca64c78c}, {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1}, {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed}, {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72}, {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000, 0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000, 0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000, 0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000, 0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000, 0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000, 0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000, 0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000, 0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000, 0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000, 0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000, 0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000, 0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000, 0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000, 0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000, 0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000, 0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000, 0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000, 0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000, 0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000, 0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000, 0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000, 0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000, 0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000, 0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000, 0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000, 0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000, 0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000, 0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000, 0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000, 0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000, 0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000, 0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000, 0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000, 0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000, 0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000, 0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000, 0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000, 0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000, 0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000, 0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000, 0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000, 0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000, 0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000, 0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000, 0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000, 0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000, 0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000, 0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000, 0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000, 0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000, 0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000, 0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000, 0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000, 0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000, 0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000, 0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000, 0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000, 0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000, 0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000, 0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000, 0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000, 0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000, 0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000, 0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000, 0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000, 0x8567077200000000, 0x1357000500000000, 0x824abf9500000000, 0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000, 0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000, 0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000, 0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000, 0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000, 0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000, 0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000, 0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000, 0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000, 0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000, 0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000, 0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000, 0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000, 0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000, 0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000, 0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000, 0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000, 0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000, 0x8def022d00000000}, {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000, 0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000, 0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000, 0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000, 0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000, 0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000, 0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000, 0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000, 0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000, 0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000, 0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000, 0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000, 0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000, 0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000, 0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000, 0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000, 0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000, 0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000, 0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000, 0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000, 0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000, 0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000, 0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000, 0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000, 0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000, 0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000, 0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000, 0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000, 0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000, 0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000, 0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000, 0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000, 0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000, 0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000, 0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000, 0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000, 0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000, 0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000, 0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000, 0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000, 0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000, 0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000, 0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000, 0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000, 0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000, 0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000, 0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000, 0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000, 0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000, 0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000, 0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000, 0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000, 0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000, 0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000, 0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000, 0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000, 0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000, 0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000, 0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000, 0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000, 0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000, 0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000, 0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000, 0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000, 0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000, 0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000, 0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000, 0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000, 0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000, 0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000, 0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000, 0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000, 0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000, 0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000, 0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000, 0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000, 0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000, 0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000, 0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000, 0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000, 0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000, 0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000, 0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000, 0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000, 0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000, 0x72fd249300000000}, {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000, 0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000, 0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000, 0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000, 0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000, 0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000, 0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000, 0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000, 0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000, 0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000, 0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000, 0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000, 0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000, 0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000, 0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000, 0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000, 0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000, 0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000, 0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000, 0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000, 0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000, 0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000, 0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000, 0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000, 0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000, 0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000, 0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000, 0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000, 0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000, 0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000, 0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000, 0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000, 0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000, 0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000, 0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000, 0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000, 0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000, 0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000, 0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000, 0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000, 0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000, 0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000, 0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000, 0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000, 0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000, 0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000, 0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000, 0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000, 0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000, 0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000, 0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000, 0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000, 0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000, 0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000, 0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000, 0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000, 0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000, 0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000, 0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000, 0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000, 0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000, 0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000, 0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000, 0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000, 0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000, 0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000, 0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000, 0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000, 0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000, 0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000, 0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000, 0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000, 0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000, 0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000, 0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000, 0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000, 0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000, 0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000, 0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000, 0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000, 0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000, 0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000, 0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000, 0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000, 0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000, 0xed3498be00000000}, {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000, 0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000, 0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000, 0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000, 0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000, 0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000, 0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000, 0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000, 0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000, 0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000, 0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000, 0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000, 0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000, 0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000, 0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000, 0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000, 0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000, 0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000, 0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000, 0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000, 0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000, 0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000, 0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000, 0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000, 0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000, 0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000, 0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000, 0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000, 0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000, 0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000, 0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000, 0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000, 0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000, 0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000, 0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000, 0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000, 0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000, 0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000, 0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000, 0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000, 0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000, 0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000, 0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000, 0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000, 0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000, 0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000, 0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000, 0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000, 0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000, 0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000, 0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000, 0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000, 0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000, 0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000, 0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000, 0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000, 0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000, 0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000, 0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000, 0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000, 0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000, 0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000, 0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000, 0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000, 0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000, 0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000, 0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000, 0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000, 0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000, 0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000, 0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000, 0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000, 0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000, 0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000, 0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000, 0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000, 0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000, 0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000, 0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000, 0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000, 0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000, 0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000, 0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000, 0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000, 0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000, 0xf10605de00000000}, {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000, 0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000, 0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000, 0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000, 0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000, 0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000, 0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000, 0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000, 0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000, 0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000, 0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000, 0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000, 0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000, 0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000, 0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000, 0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000, 0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000, 0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000, 0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000, 0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000, 0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000, 0x572f712300000000, 0x4958f35800000000, 0xf971936500000000, 0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000, 0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000, 0x8813836800000000, 0x383ae35500000000, 0xe840431200000000, 0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000, 0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000, 0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000, 0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000, 0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000, 0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000, 0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000, 0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000, 0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000, 0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000, 0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000, 0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000, 0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000, 0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000, 0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000, 0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000, 0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000, 0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000, 0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000, 0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000, 0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000, 0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000, 0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000, 0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000, 0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000, 0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000, 0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000, 0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000, 0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000, 0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000, 0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000, 0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000, 0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000, 0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000, 0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000, 0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000, 0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000, 0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000, 0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000, 0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000, 0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000, 0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000, 0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000, 0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000, 0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000, 0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000, 0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000, 0x983485b900000000, 0x281de58400000000, 0xf86745c300000000, 0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000, 0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000, 0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000, 0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000, 0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000, 0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000, 0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000, 0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000, 0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000, 0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000, 0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000, 0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000, 0x8cc764ca00000000}, {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000, 0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000, 0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000, 0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000, 0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000, 0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000, 0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000, 0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000, 0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000, 0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000, 0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000, 0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000, 0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000, 0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000, 0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000, 0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000, 0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000, 0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000, 0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000, 0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000, 0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000, 0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000, 0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000, 0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000, 0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000, 0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000, 0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000, 0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000, 0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000, 0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000, 0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000, 0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000, 0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000, 0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000, 0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000, 0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000, 0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000, 0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000, 0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000, 0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000, 0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000, 0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000, 0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000, 0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000, 0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000, 0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000, 0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000, 0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000, 0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000, 0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000, 0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000, 0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000, 0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000, 0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000, 0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000, 0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000, 0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000, 0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000, 0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000, 0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000, 0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000, 0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000, 0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000, 0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000, 0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000, 0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000, 0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000, 0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000, 0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000, 0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000, 0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000, 0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000, 0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000, 0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000, 0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000, 0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000, 0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000, 0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000, 0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000, 0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000, 0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000, 0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000, 0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000, 0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000, 0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000, 0xccabc4e400000000}, {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000, 0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000, 0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000, 0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000, 0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000, 0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000, 0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000, 0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000, 0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000, 0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000, 0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000, 0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000, 0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000, 0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000, 0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000, 0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000, 0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000, 0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000, 0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000, 0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000, 0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000, 0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000, 0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000, 0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000, 0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000, 0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000, 0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000, 0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000, 0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000, 0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000, 0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000, 0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000, 0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000, 0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000, 0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000, 0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000, 0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000, 0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000, 0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000, 0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000, 0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000, 0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000, 0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000, 0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000, 0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000, 0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000, 0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000, 0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000, 0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000, 0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000, 0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000, 0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000, 0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000, 0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000, 0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000, 0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000, 0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000, 0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000, 0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000, 0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000, 0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000, 0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000, 0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000, 0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000, 0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000, 0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000, 0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000, 0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000, 0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000, 0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000, 0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000, 0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000, 0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000, 0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000, 0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000, 0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000, 0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000, 0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000, 0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000, 0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000, 0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000, 0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000, 0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000, 0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000, 0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000, 0x304a369200000000}, {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000, 0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000, 0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000, 0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000, 0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000, 0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000, 0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000, 0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000, 0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000, 0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000, 0x1923316900000000, 0x87239ba500000000, 0x566276f900000000, 0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000, 0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000, 0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000, 0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000, 0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000, 0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000, 0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000, 0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000, 0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000, 0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000, 0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000, 0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000, 0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000, 0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000, 0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000, 0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000, 0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000, 0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000, 0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000, 0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000, 0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000, 0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000, 0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000, 0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000, 0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000, 0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000, 0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000, 0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000, 0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000, 0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000, 0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000, 0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000, 0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000, 0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000, 0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000, 0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000, 0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000, 0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000, 0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000, 0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000, 0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000, 0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000, 0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000, 0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000, 0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000, 0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000, 0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000, 0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000, 0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000, 0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000, 0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000, 0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000, 0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000, 0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000, 0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000, 0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000, 0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000, 0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000, 0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000, 0x6171384400000000, 0xff71928800000000, 0xe678578200000000, 0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000, 0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000, 0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000, 0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000, 0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000, 0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000, 0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000, 0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000, 0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000, 0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000, 0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000, 0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000, 0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000, 0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000, 0xe6064b2600000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1}, {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed}, {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72}, {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07, 0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79, 0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7, 0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84, 0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13, 0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663, 0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5, 0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5, 0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832, 0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51, 0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf, 0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1, 0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76, 0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606, 0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996, 0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6, 0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c, 0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712, 0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c, 0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4, 0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943, 0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333, 0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe, 0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce, 0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359, 0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a, 0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04, 0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a, 0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0, 0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580, 0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10, 0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060, 0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1, 0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf, 0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31, 0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852, 0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5, 0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5, 0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75, 0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005, 0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292, 0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1, 0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f, 0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111, 0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0, 0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0, 0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40, 0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530, 0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba, 0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4, 0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a, 0x8def022d}, {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64, 0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1, 0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e, 0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61, 0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82, 0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff, 0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7, 0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da, 0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139, 0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6, 0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89, 0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c, 0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0, 0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d, 0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a, 0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177, 0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de, 0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b, 0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824, 0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e, 0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad, 0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0, 0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d, 0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60, 0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83, 0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822, 0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d, 0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8, 0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171, 0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c, 0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b, 0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6, 0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca, 0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f, 0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430, 0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf, 0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c, 0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51, 0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9, 0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84, 0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67, 0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398, 0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7, 0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62, 0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e, 0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923, 0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4, 0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9, 0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070, 0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5, 0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a, 0x72fd2493}, {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907, 0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f, 0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a, 0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e, 0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512, 0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14, 0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b, 0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d, 0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731, 0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925, 0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620, 0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28, 0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70, 0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176, 0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d, 0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b, 0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b, 0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63, 0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266, 0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a, 0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446, 0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40, 0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557, 0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51, 0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d, 0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0, 0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5, 0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed, 0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd, 0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb, 0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0, 0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6, 0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de, 0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6, 0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3, 0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7, 0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb, 0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd, 0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92, 0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094, 0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598, 0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c, 0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489, 0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81, 0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9, 0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af, 0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4, 0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2, 0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2, 0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba, 0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf, 0xed3498be}, {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f, 0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d, 0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0, 0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42, 0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95, 0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2, 0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a, 0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d, 0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea, 0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748, 0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5, 0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27, 0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b, 0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac, 0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4, 0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3, 0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44, 0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6, 0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b, 0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329, 0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe, 0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9, 0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1, 0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6, 0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921, 0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555, 0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8, 0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a, 0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd, 0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a, 0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2, 0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5, 0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2, 0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330, 0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad, 0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f, 0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8, 0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef, 0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc, 0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb, 0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c, 0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e, 0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03, 0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1, 0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6, 0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1, 0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9, 0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e, 0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409, 0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb, 0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966, 0xf10605de}}; #endif #endif #if N == 2 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, 0x0d7139d7}, {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, 0x1c53e98a}, {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, 0x3f88e851}, {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, 0x3dee8ca6}, {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, 0x36197165}, {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, 0x1a3b93aa}, {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, 0xe147d714}, {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, 0x494f0c4b}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000, 0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000, 0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000, 0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000, 0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000, 0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000, 0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000, 0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000, 0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000, 0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000, 0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000, 0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000, 0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000, 0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000, 0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000, 0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000, 0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000, 0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000, 0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000, 0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000, 0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000, 0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000, 0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000, 0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000, 0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000, 0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000, 0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000, 0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000, 0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000, 0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000, 0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000, 0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000, 0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000, 0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000, 0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000, 0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000, 0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000, 0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000, 0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000, 0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000, 0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000, 0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000, 0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000, 0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000, 0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000, 0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000, 0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000, 0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000, 0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000, 0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000, 0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000, 0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000, 0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000, 0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000, 0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000, 0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000, 0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000, 0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000, 0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000, 0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000, 0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000, 0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000, 0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000, 0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000, 0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000, 0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000, 0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000, 0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000, 0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000, 0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000, 0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000, 0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000, 0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000, 0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000, 0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000, 0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000, 0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000, 0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000, 0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000, 0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000, 0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000, 0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000, 0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000, 0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000, 0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000, 0x4b0c4f4900000000}, {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000, 0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000, 0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000, 0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000, 0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000, 0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000, 0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000, 0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000, 0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000, 0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000, 0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000, 0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000, 0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000, 0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000, 0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000, 0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000, 0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000, 0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000, 0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000, 0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000, 0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000, 0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000, 0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000, 0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000, 0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000, 0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000, 0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000, 0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000, 0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000, 0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000, 0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000, 0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000, 0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000, 0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000, 0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000, 0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000, 0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000, 0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000, 0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000, 0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000, 0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000, 0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000, 0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000, 0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000, 0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000, 0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000, 0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000, 0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000, 0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000, 0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000, 0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000, 0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000, 0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000, 0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000, 0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000, 0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000, 0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000, 0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000, 0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000, 0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000, 0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000, 0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000, 0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000, 0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000, 0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000, 0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000, 0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000, 0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000, 0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000, 0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000, 0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000, 0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000, 0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000, 0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000, 0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000, 0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000, 0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000, 0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000, 0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000, 0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000, 0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000, 0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000, 0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000, 0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000, 0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000, 0x14d747e100000000}, {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000, 0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000, 0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000, 0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000, 0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000, 0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000, 0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000, 0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000, 0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000, 0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000, 0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000, 0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000, 0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000, 0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000, 0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000, 0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000, 0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000, 0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000, 0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000, 0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000, 0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000, 0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000, 0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000, 0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000, 0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000, 0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000, 0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000, 0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000, 0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000, 0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000, 0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000, 0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000, 0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000, 0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000, 0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000, 0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000, 0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000, 0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000, 0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000, 0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000, 0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000, 0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000, 0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000, 0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000, 0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000, 0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000, 0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000, 0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000, 0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000, 0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000, 0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000, 0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000, 0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000, 0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000, 0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000, 0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000, 0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000, 0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000, 0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000, 0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000, 0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000, 0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000, 0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000, 0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000, 0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000, 0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000, 0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000, 0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000, 0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000, 0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000, 0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000, 0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000, 0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000, 0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000, 0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000, 0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000, 0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000, 0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000, 0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000, 0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000, 0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000, 0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000, 0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000, 0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000, 0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000, 0xaa933b1a00000000}, {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000, 0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000, 0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000, 0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000, 0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000, 0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000, 0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000, 0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000, 0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000, 0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000, 0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000, 0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000, 0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000, 0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000, 0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000, 0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000, 0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000, 0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000, 0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000, 0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000, 0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000, 0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000, 0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000, 0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000, 0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000, 0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000, 0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000, 0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000, 0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000, 0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000, 0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000, 0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000, 0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000, 0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000, 0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000, 0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000, 0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000, 0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000, 0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000, 0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000, 0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000, 0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000, 0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000, 0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000, 0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000, 0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000, 0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000, 0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000, 0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000, 0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000, 0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000, 0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000, 0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000, 0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000, 0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000, 0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000, 0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000, 0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000, 0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000, 0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000, 0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000, 0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000, 0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000, 0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000, 0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000, 0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000, 0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000, 0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000, 0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000, 0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000, 0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000, 0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000, 0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000, 0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000, 0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000, 0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000, 0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000, 0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000, 0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000, 0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000, 0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000, 0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000, 0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000, 0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000, 0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000, 0x6571193600000000}, {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000, 0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000, 0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000, 0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000, 0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000, 0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000, 0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000, 0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000, 0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000, 0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000, 0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000, 0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000, 0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000, 0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000, 0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000, 0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000, 0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000, 0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000, 0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000, 0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000, 0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000, 0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000, 0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000, 0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000, 0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000, 0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000, 0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000, 0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000, 0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000, 0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000, 0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000, 0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000, 0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000, 0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000, 0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000, 0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000, 0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000, 0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000, 0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000, 0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000, 0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000, 0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000, 0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000, 0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000, 0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000, 0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000, 0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000, 0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000, 0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000, 0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000, 0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000, 0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000, 0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000, 0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000, 0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000, 0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000, 0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000, 0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000, 0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000, 0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000, 0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000, 0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000, 0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000, 0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000, 0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000, 0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000, 0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000, 0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000, 0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000, 0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000, 0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000, 0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000, 0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000, 0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000, 0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000, 0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000, 0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000, 0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000, 0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000, 0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000, 0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000, 0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000, 0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000, 0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000, 0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000, 0xa68cee3d00000000}, {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000, 0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000, 0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000, 0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000, 0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000, 0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000, 0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000, 0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000, 0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000, 0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000, 0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000, 0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000, 0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000, 0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000, 0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000, 0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000, 0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000, 0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000, 0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000, 0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000, 0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000, 0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000, 0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000, 0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000, 0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000, 0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000, 0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000, 0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000, 0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000, 0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000, 0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000, 0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000, 0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000, 0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000, 0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000, 0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000, 0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000, 0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000, 0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000, 0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000, 0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000, 0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000, 0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000, 0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000, 0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000, 0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000, 0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000, 0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000, 0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000, 0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000, 0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000, 0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000, 0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000, 0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000, 0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000, 0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000, 0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000, 0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000, 0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000, 0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000, 0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000, 0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000, 0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000, 0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000, 0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000, 0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000, 0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000, 0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000, 0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000, 0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000, 0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000, 0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000, 0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000, 0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000, 0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000, 0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000, 0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000, 0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000, 0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000, 0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000, 0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000, 0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000, 0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000, 0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000, 0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000, 0x51e8883f00000000}, {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000, 0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000, 0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000, 0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000, 0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000, 0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000, 0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000, 0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000, 0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000, 0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000, 0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000, 0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000, 0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000, 0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000, 0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000, 0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000, 0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000, 0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000, 0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000, 0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000, 0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000, 0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000, 0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000, 0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000, 0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000, 0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000, 0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000, 0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000, 0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000, 0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000, 0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000, 0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000, 0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000, 0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000, 0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000, 0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000, 0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000, 0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000, 0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000, 0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000, 0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000, 0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000, 0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000, 0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000, 0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000, 0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000, 0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000, 0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000, 0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000, 0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000, 0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000, 0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000, 0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000, 0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000, 0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000, 0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000, 0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000, 0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000, 0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000, 0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000, 0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000, 0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000, 0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000, 0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000, 0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000, 0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000, 0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000, 0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000, 0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000, 0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000, 0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000, 0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000, 0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000, 0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000, 0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000, 0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000, 0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000, 0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000, 0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000, 0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000, 0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000, 0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000, 0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000, 0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000, 0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000, 0x8ae9531c00000000}, {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000, 0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000, 0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000, 0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000, 0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000, 0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000, 0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000, 0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000, 0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000, 0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000, 0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000, 0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000, 0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000, 0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000, 0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000, 0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000, 0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000, 0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000, 0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000, 0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000, 0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000, 0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000, 0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000, 0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000, 0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000, 0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000, 0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000, 0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000, 0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000, 0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000, 0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000, 0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000, 0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000, 0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000, 0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000, 0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000, 0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000, 0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000, 0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000, 0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000, 0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000, 0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000, 0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000, 0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000, 0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000, 0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000, 0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000, 0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000, 0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000, 0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000, 0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000, 0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000, 0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000, 0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000, 0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000, 0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000, 0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000, 0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000, 0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000, 0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000, 0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000, 0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000, 0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000, 0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000, 0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000, 0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000, 0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000, 0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000, 0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000, 0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000, 0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000, 0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000, 0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000, 0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000, 0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000, 0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000, 0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000, 0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000, 0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000, 0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000, 0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000, 0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000, 0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000, 0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000, 0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000, 0xd739710d00000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, 0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3, 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, 0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, 0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544, 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, 0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a, 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561, 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6}, {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, 0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6, 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, 0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617, 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, 0x92364a30}, {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, 0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408, 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, 0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82, 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, 0xe4c4abcc}, {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, 0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136, 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, 0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, 0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922, 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, 0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb, 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df, 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, 0xca64c78c}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5, 0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d, 0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf, 0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027, 0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050, 0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098, 0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb, 0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173, 0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104, 0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c, 0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e, 0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6, 0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358, 0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390, 0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312, 0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da, 0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd, 0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335, 0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387, 0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de, 0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9, 0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261, 0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283, 0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b, 0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c, 0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c, 0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e, 0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6, 0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1, 0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619, 0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b, 0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653, 0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785, 0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d, 0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf, 0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757, 0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720, 0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8, 0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593, 0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b, 0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c, 0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4, 0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506, 0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe, 0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428, 0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0, 0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462, 0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa, 0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd, 0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445, 0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7, 0x8cc764ca}, {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b, 0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27, 0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a, 0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285, 0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef, 0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf, 0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a, 0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a, 0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70, 0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf, 0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2, 0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e, 0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f, 0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f, 0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae, 0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe, 0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97, 0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b, 0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436, 0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e, 0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4, 0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4, 0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46, 0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716, 0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c, 0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5, 0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8, 0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774, 0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d, 0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d, 0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc, 0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec, 0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82, 0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e, 0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623, 0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c, 0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6, 0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6, 0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c, 0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c, 0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66, 0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9, 0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4, 0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978, 0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416, 0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946, 0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7, 0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7, 0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e, 0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32, 0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f, 0xccabc4e4}, {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4, 0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895, 0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50, 0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656, 0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154, 0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906, 0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258, 0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a, 0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08, 0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e, 0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb, 0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa, 0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44, 0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316, 0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0, 0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2, 0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7, 0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6, 0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73, 0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba, 0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8, 0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea, 0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b, 0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29, 0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b, 0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e, 0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb, 0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a, 0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef, 0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd, 0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b, 0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019, 0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3, 0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2, 0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417, 0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11, 0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13, 0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241, 0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b, 0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09, 0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b, 0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d, 0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8, 0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9, 0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003, 0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851, 0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7, 0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5, 0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190, 0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1, 0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134, 0x304a3692}, {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84, 0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f, 0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15, 0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2, 0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf, 0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7, 0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb, 0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3, 0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae, 0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749, 0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243, 0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8, 0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29, 0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61, 0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8, 0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0, 0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1, 0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a, 0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40, 0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e, 0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03, 0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b, 0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee, 0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6, 0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb, 0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f, 0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495, 0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e, 0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f, 0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067, 0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be, 0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6, 0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e, 0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5, 0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf, 0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958, 0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305, 0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d, 0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338, 0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370, 0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d, 0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca, 0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0, 0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b, 0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083, 0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb, 0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012, 0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a, 0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b, 0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0, 0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea, 0xe6064b26}}; #endif #endif #if N == 3 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, 0x09cd8551}, {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, 0x7bc97a0c}, {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, 0x7851a2ca}, {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, 0x566b6848}, {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, 0xd8ac6b35}, {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, 0xa140efa8}, {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, 0x917cd6a1}, {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, 0x18ba364e}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000, 0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000, 0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000, 0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000, 0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000, 0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000, 0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000, 0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000, 0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000, 0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000, 0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000, 0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000, 0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000, 0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000, 0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000, 0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000, 0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000, 0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000, 0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000, 0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000, 0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000, 0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000, 0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000, 0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000, 0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000, 0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000, 0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000, 0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000, 0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000, 0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000, 0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000, 0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000, 0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000, 0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000, 0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000, 0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000, 0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000, 0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000, 0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000, 0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000, 0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000, 0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000, 0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000, 0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000, 0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000, 0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000, 0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000, 0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000, 0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000, 0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000, 0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000, 0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000, 0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000, 0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000, 0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000, 0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000, 0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000, 0x08eda52100000000, 0x4391370100000000, 0x005a918600000000, 0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000, 0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000, 0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000, 0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000, 0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000, 0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000, 0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000, 0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000, 0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000, 0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000, 0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000, 0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000, 0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000, 0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000, 0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000, 0x7b23114500000000, 0x305f836500000000, 0x739425e200000000, 0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000, 0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000, 0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000, 0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000, 0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000, 0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000, 0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000, 0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000, 0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000, 0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000, 0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000, 0x4e36ba1800000000}, {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000, 0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000, 0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000, 0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000, 0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000, 0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000, 0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000, 0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000, 0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000, 0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000, 0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000, 0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000, 0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000, 0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000, 0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000, 0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000, 0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000, 0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000, 0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000, 0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000, 0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000, 0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000, 0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000, 0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000, 0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000, 0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000, 0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000, 0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000, 0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000, 0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000, 0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000, 0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000, 0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000, 0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000, 0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000, 0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000, 0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000, 0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000, 0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000, 0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000, 0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000, 0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000, 0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000, 0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000, 0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000, 0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000, 0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000, 0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000, 0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000, 0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000, 0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000, 0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000, 0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000, 0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000, 0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000, 0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000, 0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000, 0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000, 0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000, 0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000, 0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000, 0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000, 0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000, 0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000, 0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000, 0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000, 0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000, 0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000, 0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000, 0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000, 0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000, 0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000, 0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000, 0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000, 0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000, 0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000, 0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000, 0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000, 0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000, 0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000, 0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000, 0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000, 0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000, 0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000, 0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000, 0xa1d67c9100000000}, {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000, 0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000, 0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000, 0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000, 0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000, 0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000, 0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000, 0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000, 0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000, 0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000, 0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000, 0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000, 0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000, 0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000, 0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000, 0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000, 0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000, 0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000, 0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000, 0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000, 0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000, 0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000, 0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000, 0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000, 0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000, 0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000, 0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000, 0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000, 0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000, 0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000, 0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000, 0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000, 0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000, 0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000, 0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000, 0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000, 0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000, 0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000, 0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000, 0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000, 0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000, 0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000, 0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000, 0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000, 0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000, 0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000, 0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000, 0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000, 0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000, 0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000, 0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000, 0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000, 0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000, 0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000, 0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000, 0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000, 0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000, 0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000, 0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000, 0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000, 0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000, 0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000, 0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000, 0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000, 0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000, 0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000, 0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000, 0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000, 0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000, 0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000, 0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000, 0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000, 0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000, 0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000, 0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000, 0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000, 0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000, 0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000, 0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000, 0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000, 0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000, 0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000, 0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000, 0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000, 0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000, 0xa8ef40a100000000}, {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000, 0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000, 0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000, 0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000, 0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000, 0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000, 0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000, 0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000, 0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000, 0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000, 0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000, 0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000, 0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000, 0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000, 0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000, 0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000, 0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000, 0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000, 0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000, 0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000, 0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000, 0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000, 0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000, 0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000, 0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000, 0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000, 0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000, 0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000, 0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000, 0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000, 0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000, 0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000, 0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000, 0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000, 0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000, 0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000, 0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000, 0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000, 0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000, 0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000, 0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000, 0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000, 0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000, 0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000, 0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000, 0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000, 0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000, 0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000, 0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000, 0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000, 0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000, 0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000, 0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000, 0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000, 0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000, 0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000, 0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000, 0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000, 0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000, 0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000, 0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000, 0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000, 0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000, 0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000, 0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000, 0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000, 0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000, 0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000, 0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000, 0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000, 0x933d017400000000, 0xd506661100000000, 0x46a022f000000000, 0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000, 0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000, 0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000, 0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000, 0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000, 0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000, 0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000, 0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000, 0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000, 0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000, 0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000, 0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000, 0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000, 0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000, 0x356bacd800000000}, {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000, 0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000, 0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000, 0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000, 0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000, 0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000, 0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000, 0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000, 0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000, 0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000, 0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000, 0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000, 0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000, 0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000, 0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000, 0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000, 0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000, 0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000, 0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000, 0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000, 0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000, 0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000, 0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000, 0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000, 0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000, 0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000, 0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000, 0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000, 0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000, 0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000, 0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000, 0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000, 0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000, 0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000, 0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000, 0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000, 0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000, 0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000, 0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000, 0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000, 0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000, 0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000, 0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000, 0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000, 0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000, 0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000, 0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000, 0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000, 0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000, 0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000, 0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000, 0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000, 0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000, 0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000, 0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000, 0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000, 0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000, 0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000, 0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000, 0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000, 0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000, 0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000, 0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000, 0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000, 0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000, 0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000, 0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000, 0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000, 0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000, 0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000, 0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000, 0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000, 0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000, 0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000, 0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000, 0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000, 0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000, 0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000, 0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000, 0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000, 0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000, 0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000, 0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000, 0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000, 0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000, 0x48686b5600000000}, {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000, 0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000, 0x805af17200000000, 0x403ed96500000000, 0x002643b900000000, 0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000, 0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000, 0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000, 0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000, 0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000, 0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000, 0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000, 0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000, 0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000, 0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000, 0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000, 0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000, 0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000, 0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000, 0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000, 0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000, 0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000, 0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000, 0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000, 0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000, 0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000, 0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000, 0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000, 0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000, 0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000, 0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000, 0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000, 0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000, 0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000, 0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000, 0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000, 0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000, 0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000, 0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000, 0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000, 0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000, 0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000, 0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000, 0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000, 0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000, 0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000, 0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000, 0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000, 0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000, 0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000, 0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000, 0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000, 0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000, 0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000, 0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000, 0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000, 0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000, 0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000, 0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000, 0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000, 0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000, 0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000, 0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000, 0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000, 0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000, 0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000, 0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000, 0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000, 0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000, 0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000, 0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000, 0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000, 0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000, 0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000, 0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000, 0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000, 0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000, 0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000, 0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000, 0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000, 0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000, 0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000, 0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000, 0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000, 0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000, 0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000, 0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000, 0xcaa2517800000000}, {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000, 0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000, 0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000, 0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000, 0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000, 0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000, 0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000, 0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000, 0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000, 0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000, 0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000, 0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000, 0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000, 0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000, 0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000, 0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000, 0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000, 0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000, 0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000, 0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000, 0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000, 0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000, 0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000, 0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000, 0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000, 0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000, 0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000, 0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000, 0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000, 0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000, 0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000, 0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000, 0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000, 0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000, 0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000, 0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000, 0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000, 0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000, 0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000, 0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000, 0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000, 0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000, 0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000, 0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000, 0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000, 0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000, 0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000, 0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000, 0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000, 0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000, 0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000, 0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000, 0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000, 0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000, 0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000, 0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000, 0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000, 0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000, 0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000, 0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000, 0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000, 0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000, 0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000, 0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000, 0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000, 0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000, 0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000, 0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000, 0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000, 0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000, 0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000, 0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000, 0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000, 0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000, 0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000, 0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000, 0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000, 0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000, 0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000, 0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000, 0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000, 0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000, 0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000, 0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000, 0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000, 0x0c7ac97b00000000}, {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000, 0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000, 0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000, 0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000, 0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000, 0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000, 0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000, 0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000, 0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000, 0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000, 0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000, 0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000, 0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000, 0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000, 0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000, 0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000, 0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000, 0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000, 0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000, 0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000, 0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000, 0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000, 0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000, 0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000, 0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000, 0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000, 0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000, 0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000, 0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000, 0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000, 0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000, 0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000, 0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000, 0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000, 0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000, 0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000, 0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000, 0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000, 0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000, 0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000, 0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000, 0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000, 0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000, 0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000, 0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000, 0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000, 0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000, 0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000, 0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000, 0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000, 0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000, 0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000, 0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000, 0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000, 0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000, 0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000, 0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000, 0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000, 0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000, 0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000, 0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000, 0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000, 0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000, 0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000, 0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000, 0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000, 0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000, 0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000, 0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000, 0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000, 0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000, 0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000, 0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000, 0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000, 0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000, 0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000, 0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000, 0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000, 0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000, 0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000, 0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000, 0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000, 0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000, 0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000, 0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000, 0x5185cd0900000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f, 0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91, 0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e, 0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c, 0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02, 0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12, 0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567, 0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277, 0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679, 0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b, 0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4, 0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a, 0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0, 0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0, 0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91, 0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881, 0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173, 0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d, 0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912, 0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8, 0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6, 0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6, 0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b, 0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b, 0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75, 0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f, 0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00, 0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee, 0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c, 0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c, 0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d, 0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d, 0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67, 0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89, 0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706, 0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14, 0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a, 0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a, 0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f, 0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f, 0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591, 0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983, 0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c, 0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2, 0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8, 0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8, 0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89, 0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99, 0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b, 0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485, 0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a, 0x36197165}, {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382, 0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85, 0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06, 0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca, 0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e, 0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc, 0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616, 0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54, 0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10, 0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc, 0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f, 0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58, 0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef, 0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad, 0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b, 0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29, 0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6, 0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1, 0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622, 0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039, 0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d, 0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f, 0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32, 0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770, 0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034, 0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f, 0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc, 0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db, 0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154, 0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16, 0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0, 0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592, 0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca, 0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd, 0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e, 0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882, 0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6, 0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384, 0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1, 0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3, 0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7, 0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b, 0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8, 0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff, 0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7, 0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5, 0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23, 0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761, 0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee, 0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9, 0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a, 0x1a3b93aa}, {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a, 0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca, 0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3, 0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb, 0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c, 0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58, 0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed, 0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9, 0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e, 0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906, 0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f, 0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf, 0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0, 0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4, 0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769, 0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d, 0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632, 0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82, 0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb, 0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73, 0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484, 0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0, 0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5, 0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1, 0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516, 0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f, 0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946, 0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6, 0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9, 0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad, 0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820, 0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364, 0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab, 0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b, 0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62, 0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a, 0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd, 0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089, 0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c, 0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8, 0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f, 0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477, 0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e, 0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be, 0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71, 0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635, 0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8, 0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc, 0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3, 0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753, 0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a, 0xe147d714}, {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c, 0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b, 0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92, 0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4, 0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069, 0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526, 0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25, 0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a, 0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7, 0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491, 0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958, 0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f, 0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307, 0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648, 0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999, 0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6, 0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a, 0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d, 0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4, 0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61, 0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc, 0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3, 0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53, 0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c, 0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1, 0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c, 0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5, 0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92, 0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e, 0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771, 0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0, 0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def, 0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0, 0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7, 0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e, 0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58, 0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285, 0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca, 0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce, 0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81, 0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c, 0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a, 0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3, 0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4, 0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb, 0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4, 0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75, 0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a, 0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296, 0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1, 0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808, 0x494f0c4b}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d, 0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac, 0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8, 0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95, 0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817, 0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d, 0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac, 0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6, 0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564, 0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39, 0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d, 0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac, 0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de, 0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594, 0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b, 0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01, 0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f, 0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de, 0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba, 0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65, 0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7, 0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad, 0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de, 0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294, 0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716, 0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71, 0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15, 0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4, 0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca, 0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280, 0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f, 0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15, 0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9, 0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748, 0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c, 0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971, 0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3, 0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9, 0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196, 0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc, 0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e, 0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03, 0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67, 0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296, 0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a, 0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170, 0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af, 0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5, 0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb, 0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a, 0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e, 0x4b0c4f49}, {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09, 0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc, 0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e, 0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc, 0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934, 0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2, 0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b, 0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad, 0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155, 0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187, 0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65, 0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390, 0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e, 0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378, 0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889, 0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f, 0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0, 0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145, 0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7, 0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a, 0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2, 0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924, 0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2, 0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514, 0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec, 0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709, 0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb, 0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e, 0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1, 0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227, 0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6, 0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030, 0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0, 0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55, 0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7, 0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165, 0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d, 0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b, 0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c, 0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a, 0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362, 0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0, 0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52, 0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7, 0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237, 0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1, 0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020, 0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6, 0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719, 0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec, 0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e, 0x14d747e1}, {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0, 0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b, 0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652, 0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437, 0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514, 0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265, 0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de, 0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af, 0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c, 0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9, 0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0, 0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b, 0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6, 0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7, 0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734, 0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045, 0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8, 0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303, 0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a, 0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9, 0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea, 0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b, 0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6, 0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7, 0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4, 0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6, 0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f, 0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054, 0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9, 0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8, 0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b, 0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a, 0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441, 0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a, 0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3, 0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6, 0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5, 0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94, 0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9, 0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288, 0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab, 0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce, 0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7, 0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c, 0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527, 0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256, 0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5, 0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4, 0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39, 0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2, 0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db, 0xaa933b1a}, {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603, 0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d, 0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9, 0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b, 0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a, 0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792, 0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4, 0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c, 0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d, 0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f, 0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb, 0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65, 0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330, 0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8, 0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da, 0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742, 0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f, 0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1, 0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5, 0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f, 0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e, 0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6, 0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8, 0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250, 0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021, 0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb, 0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f, 0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511, 0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c, 0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4, 0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886, 0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e, 0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b, 0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5, 0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791, 0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003, 0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272, 0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea, 0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc, 0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24, 0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55, 0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7, 0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3, 0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d, 0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548, 0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0, 0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2, 0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a, 0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47, 0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9, 0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad, 0x65711936}}; #endif #endif #if N == 4 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a, 0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe, 0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b, 0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656, 0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd, 0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d, 0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7, 0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47, 0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac, 0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691, 0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404, 0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0, 0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4, 0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424, 0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5, 0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65, 0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67, 0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3, 0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626, 0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9, 0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222, 0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2, 0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a, 0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a, 0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1, 0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2, 0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077, 0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3, 0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1, 0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621, 0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0, 0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60, 0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0, 0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64, 0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1, 0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc, 0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027, 0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7, 0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9, 0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79, 0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292, 0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af, 0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a, 0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee, 0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e, 0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe, 0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f, 0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff, 0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd, 0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29, 0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc, 0xe3c45916}, {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344, 0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59, 0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e, 0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463, 0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98, 0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d, 0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3, 0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656, 0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad, 0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0, 0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397, 0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a, 0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2, 0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357, 0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8, 0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d, 0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696, 0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b, 0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc, 0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0, 0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b, 0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be, 0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811, 0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384, 0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f, 0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955, 0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362, 0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f, 0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94, 0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701, 0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe, 0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b, 0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1, 0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc, 0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b, 0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986, 0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d, 0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8, 0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4, 0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371, 0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a, 0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87, 0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0, 0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad, 0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527, 0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2, 0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d, 0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998, 0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73, 0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e, 0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59, 0xa7520488}, {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20, 0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09, 0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431, 0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a, 0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203, 0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b, 0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14, 0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c, 0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25, 0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e, 0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36, 0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f, 0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649, 0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961, 0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58, 0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170, 0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b, 0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742, 0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a, 0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55, 0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c, 0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64, 0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f, 0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77, 0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e, 0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a, 0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2, 0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b, 0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090, 0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8, 0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881, 0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9, 0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6, 0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f, 0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7, 0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c, 0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695, 0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd, 0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb, 0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3, 0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa, 0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1, 0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9, 0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0, 0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df, 0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7, 0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace, 0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6, 0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd, 0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4, 0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec, 0x3522e9e4}, {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1, 0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86, 0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b, 0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669, 0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7, 0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352, 0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03, 0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6, 0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38, 0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a, 0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7, 0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80, 0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7, 0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522, 0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d, 0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8, 0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103, 0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54, 0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9, 0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0, 0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e, 0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb, 0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1, 0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624, 0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea, 0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a, 0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37, 0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360, 0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab, 0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e, 0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741, 0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4, 0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334, 0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63, 0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de, 0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c, 0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942, 0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7, 0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131, 0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4, 0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a, 0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758, 0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5, 0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2, 0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32, 0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7, 0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8, 0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d, 0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6, 0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1, 0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c, 0x97411e28}, {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474, 0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5, 0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6, 0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7, 0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938, 0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051, 0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a, 0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3, 0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c, 0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d, 0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e, 0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf, 0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740, 0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29, 0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592, 0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb, 0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4, 0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365, 0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036, 0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7, 0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08, 0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561, 0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a, 0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663, 0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac, 0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d, 0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce, 0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f, 0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50, 0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639, 0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82, 0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb, 0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954, 0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5, 0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86, 0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7, 0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418, 0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71, 0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa, 0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93, 0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c, 0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d, 0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e, 0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df, 0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60, 0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309, 0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2, 0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db, 0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4, 0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45, 0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16, 0x93c7a00b}, {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45, 0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb, 0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d, 0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696, 0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf, 0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb, 0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028, 0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c, 0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65, 0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be, 0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038, 0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6, 0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15, 0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11, 0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d, 0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19, 0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05, 0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b, 0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d, 0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c, 0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35, 0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31, 0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068, 0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c, 0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25, 0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a, 0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac, 0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22, 0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e, 0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a, 0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36, 0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32, 0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84, 0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a, 0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c, 0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057, 0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e, 0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a, 0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc, 0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8, 0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1, 0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a, 0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec, 0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62, 0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4, 0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0, 0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc, 0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8, 0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4, 0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a, 0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc, 0xce5f968d}, {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de, 0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b, 0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d, 0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680, 0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4, 0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d, 0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde, 0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97, 0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3, 0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e, 0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678, 0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d, 0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723, 0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a, 0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0, 0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9, 0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85, 0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770, 0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56, 0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a, 0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e, 0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67, 0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785, 0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc, 0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788, 0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90, 0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6, 0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843, 0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f, 0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336, 0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac, 0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5, 0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68, 0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d, 0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb, 0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36, 0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72, 0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b, 0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b, 0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402, 0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446, 0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb, 0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed, 0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418, 0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95, 0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc, 0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946, 0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f, 0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233, 0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6, 0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0, 0x3e721277}, {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb, 0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9, 0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11, 0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d, 0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9, 0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c, 0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881, 0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274, 0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790, 0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc, 0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514, 0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56, 0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9, 0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c, 0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13, 0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6, 0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c, 0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e, 0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386, 0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376, 0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692, 0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67, 0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416, 0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3, 0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07, 0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd, 0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15, 0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457, 0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd, 0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28, 0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337, 0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2, 0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594, 0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6, 0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e, 0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52, 0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6, 0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143, 0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17, 0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2, 0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306, 0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a, 0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182, 0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0, 0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496, 0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63, 0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c, 0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89, 0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903, 0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041, 0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9, 0x1c65ace7}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000, 0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000, 0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000, 0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000, 0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000, 0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000, 0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000, 0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000, 0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000, 0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000, 0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000, 0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000, 0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000, 0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000, 0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000, 0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000, 0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000, 0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000, 0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000, 0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000, 0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000, 0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000, 0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000, 0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000, 0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000, 0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000, 0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000, 0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000, 0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000, 0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000, 0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000, 0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000, 0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000, 0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000, 0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000, 0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000, 0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000, 0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000, 0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000, 0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000, 0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000, 0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000, 0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000, 0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000, 0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000, 0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000, 0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000, 0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000, 0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000, 0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000, 0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000, 0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000, 0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000, 0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000, 0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000, 0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000, 0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000, 0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000, 0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000, 0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000, 0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000, 0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000, 0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000, 0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000, 0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000, 0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000, 0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000, 0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000, 0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000, 0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000, 0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000, 0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000, 0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000, 0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000, 0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000, 0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000, 0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000, 0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000, 0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000, 0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000, 0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000, 0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000, 0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000, 0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000, 0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000, 0xe7ac651c00000000}, {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000, 0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000, 0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000, 0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000, 0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000, 0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000, 0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000, 0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000, 0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000, 0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000, 0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000, 0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000, 0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000, 0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000, 0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000, 0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000, 0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000, 0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000, 0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000, 0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000, 0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000, 0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000, 0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000, 0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000, 0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000, 0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000, 0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000, 0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000, 0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000, 0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000, 0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000, 0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000, 0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000, 0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000, 0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000, 0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000, 0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000, 0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000, 0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000, 0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000, 0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000, 0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000, 0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000, 0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000, 0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000, 0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000, 0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000, 0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000, 0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000, 0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000, 0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000, 0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000, 0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000, 0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000, 0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000, 0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000, 0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000, 0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000, 0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000, 0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000, 0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000, 0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000, 0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000, 0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000, 0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000, 0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000, 0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000, 0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000, 0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000, 0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000, 0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000, 0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000, 0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000, 0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000, 0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000, 0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000, 0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000, 0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000, 0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000, 0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000, 0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000, 0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000, 0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000, 0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000, 0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000, 0x7712723e00000000}, {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000, 0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000, 0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000, 0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000, 0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000, 0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000, 0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000, 0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000, 0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000, 0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000, 0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000, 0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000, 0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000, 0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000, 0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000, 0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000, 0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000, 0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000, 0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000, 0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000, 0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000, 0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000, 0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000, 0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000, 0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000, 0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000, 0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000, 0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000, 0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000, 0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000, 0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000, 0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000, 0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000, 0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000, 0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000, 0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000, 0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000, 0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000, 0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000, 0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000, 0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000, 0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000, 0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000, 0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000, 0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000, 0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000, 0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000, 0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000, 0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000, 0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000, 0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000, 0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000, 0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000, 0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000, 0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000, 0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000, 0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000, 0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000, 0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000, 0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000, 0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000, 0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000, 0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000, 0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000, 0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000, 0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000, 0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000, 0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000, 0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000, 0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000, 0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000, 0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000, 0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000, 0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000, 0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000, 0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000, 0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000, 0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000, 0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000, 0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000, 0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000, 0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000, 0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000, 0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000, 0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000, 0x8d965fce00000000}, {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000, 0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000, 0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000, 0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000, 0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000, 0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000, 0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000, 0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000, 0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000, 0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000, 0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000, 0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000, 0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000, 0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000, 0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000, 0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000, 0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000, 0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000, 0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000, 0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000, 0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000, 0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000, 0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000, 0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000, 0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000, 0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000, 0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000, 0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000, 0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000, 0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000, 0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000, 0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000, 0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000, 0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000, 0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000, 0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000, 0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000, 0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000, 0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000, 0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000, 0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000, 0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000, 0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000, 0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000, 0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000, 0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000, 0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000, 0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000, 0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000, 0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000, 0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000, 0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000, 0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000, 0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000, 0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000, 0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000, 0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000, 0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000, 0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000, 0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000, 0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000, 0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000, 0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000, 0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000, 0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000, 0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000, 0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000, 0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000, 0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000, 0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000, 0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000, 0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000, 0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000, 0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000, 0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000, 0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000, 0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000, 0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000, 0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000, 0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000, 0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000, 0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000, 0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000, 0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000, 0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000, 0x0ba0c79300000000}, {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000, 0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000, 0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000, 0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000, 0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000, 0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000, 0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000, 0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000, 0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000, 0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000, 0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000, 0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000, 0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000, 0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000, 0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000, 0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000, 0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000, 0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000, 0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000, 0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000, 0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000, 0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000, 0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000, 0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000, 0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000, 0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000, 0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000, 0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000, 0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000, 0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000, 0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000, 0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000, 0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000, 0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000, 0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000, 0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000, 0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000, 0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000, 0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000, 0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000, 0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000, 0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000, 0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000, 0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000, 0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000, 0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000, 0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000, 0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000, 0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000, 0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000, 0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000, 0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000, 0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000, 0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000, 0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000, 0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000, 0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000, 0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000, 0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000, 0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000, 0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000, 0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000, 0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000, 0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000, 0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000, 0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000, 0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000, 0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000, 0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000, 0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000, 0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000, 0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000, 0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000, 0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000, 0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000, 0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000, 0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000, 0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000, 0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000, 0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000, 0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000, 0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000, 0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000, 0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000, 0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000, 0x281e419700000000}, {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000, 0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000, 0x304a428900000000, 0x38a922b500000000, 0x011e763800000000, 0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000, 0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000, 0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000, 0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000, 0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000, 0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000, 0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000, 0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000, 0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000, 0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000, 0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000, 0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000, 0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000, 0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000, 0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000, 0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000, 0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000, 0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000, 0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000, 0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000, 0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000, 0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000, 0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000, 0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000, 0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000, 0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000, 0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000, 0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000, 0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000, 0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000, 0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000, 0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000, 0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000, 0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000, 0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000, 0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000, 0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000, 0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000, 0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000, 0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000, 0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000, 0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000, 0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000, 0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000, 0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000, 0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000, 0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000, 0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000, 0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000, 0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000, 0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000, 0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000, 0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000, 0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000, 0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000, 0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000, 0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000, 0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000, 0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000, 0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000, 0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000, 0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000, 0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000, 0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000, 0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000, 0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000, 0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000, 0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000, 0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000, 0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000, 0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000, 0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000, 0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000, 0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000, 0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000, 0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000, 0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000, 0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000, 0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000, 0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000, 0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000, 0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000, 0xe4e9223500000000}, {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000, 0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000, 0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000, 0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000, 0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000, 0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000, 0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000, 0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000, 0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000, 0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000, 0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000, 0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000, 0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000, 0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000, 0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000, 0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000, 0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000, 0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000, 0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000, 0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000, 0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000, 0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000, 0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000, 0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000, 0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000, 0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000, 0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000, 0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000, 0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000, 0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000, 0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000, 0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000, 0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000, 0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000, 0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000, 0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000, 0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000, 0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000, 0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000, 0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000, 0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000, 0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000, 0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000, 0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000, 0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000, 0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000, 0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000, 0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000, 0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000, 0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000, 0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000, 0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000, 0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000, 0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000, 0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000, 0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000, 0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000, 0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000, 0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000, 0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000, 0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000, 0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000, 0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000, 0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000, 0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000, 0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000, 0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000, 0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000, 0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000, 0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000, 0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000, 0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000, 0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000, 0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000, 0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000, 0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000, 0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000, 0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000, 0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000, 0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000, 0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000, 0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000, 0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000, 0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000, 0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000, 0x880452a700000000}, {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000, 0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000, 0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000, 0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000, 0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000, 0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000, 0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000, 0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000, 0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000, 0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000, 0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000, 0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000, 0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000, 0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000, 0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000, 0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000, 0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000, 0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000, 0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000, 0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000, 0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000, 0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000, 0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000, 0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000, 0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000, 0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000, 0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000, 0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000, 0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000, 0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000, 0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000, 0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000, 0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000, 0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000, 0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000, 0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000, 0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000, 0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000, 0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000, 0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000, 0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000, 0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000, 0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000, 0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000, 0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000, 0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000, 0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000, 0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000, 0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000, 0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000, 0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000, 0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000, 0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000, 0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000, 0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000, 0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000, 0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000, 0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000, 0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000, 0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000, 0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000, 0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000, 0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000, 0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000, 0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000, 0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000, 0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000, 0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000, 0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000, 0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000, 0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000, 0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000, 0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000, 0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000, 0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000, 0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000, 0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000, 0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000, 0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000, 0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000, 0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000, 0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000, 0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000, 0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000, 0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000, 0x1659c4e300000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87, 0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede, 0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab, 0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c, 0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1, 0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7, 0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e, 0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308, 0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5, 0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472, 0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07, 0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e, 0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa, 0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec, 0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6, 0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0, 0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3, 0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba, 0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf, 0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975, 0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8, 0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde, 0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a, 0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c, 0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1, 0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65, 0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410, 0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649, 0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a, 0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c, 0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946, 0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450, 0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e, 0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857, 0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022, 0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5, 0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758, 0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e, 0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d, 0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b, 0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6, 0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401, 0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74, 0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d, 0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073, 0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65, 0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f, 0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749, 0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a, 0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033, 0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846, 0x0d7139d7}, {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563, 0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f, 0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875, 0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536, 0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8, 0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43, 0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f, 0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184, 0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a, 0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39, 0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523, 0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f, 0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d, 0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6, 0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b, 0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0, 0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151, 0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d, 0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47, 0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a, 0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964, 0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef, 0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d, 0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6, 0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348, 0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53, 0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449, 0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645, 0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4, 0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f, 0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2, 0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69, 0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46, 0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a, 0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650, 0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13, 0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded, 0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366, 0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57, 0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc, 0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222, 0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61, 0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b, 0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277, 0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558, 0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3, 0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e, 0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5, 0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74, 0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78, 0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262, 0x1c53e98a}, {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b, 0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40, 0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580, 0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7, 0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a, 0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37, 0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75, 0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218, 0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5, 0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2, 0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02, 0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59, 0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1, 0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c, 0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a, 0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307, 0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486, 0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd, 0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d, 0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2, 0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f, 0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72, 0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8, 0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985, 0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268, 0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94, 0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454, 0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f, 0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e, 0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3, 0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915, 0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778, 0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821, 0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a, 0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba, 0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d, 0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560, 0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d, 0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe, 0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3, 0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e, 0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509, 0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9, 0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92, 0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb, 0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6, 0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50, 0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d, 0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc, 0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7, 0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927, 0x3f88e851}, {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96, 0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8, 0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0, 0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14, 0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7, 0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4, 0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe, 0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad, 0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e, 0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa, 0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2, 0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c, 0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab, 0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8, 0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d, 0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e, 0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7, 0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99, 0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1, 0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690, 0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933, 0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20, 0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf, 0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc, 0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f, 0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92, 0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca, 0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4, 0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd, 0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de, 0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb, 0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8, 0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474, 0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a, 0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252, 0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6, 0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55, 0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846, 0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7, 0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4, 0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47, 0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3, 0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb, 0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5, 0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49, 0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a, 0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f, 0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c, 0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305, 0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b, 0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523, 0x3dee8ca6}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0, 0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587, 0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa, 0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09, 0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee, 0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3, 0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3, 0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce, 0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429, 0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda, 0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7, 0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0, 0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd, 0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0, 0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287, 0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a, 0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9, 0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e, 0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3, 0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3, 0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054, 0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49, 0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da, 0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7, 0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20, 0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d, 0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00, 0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347, 0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14, 0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209, 0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e, 0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33, 0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3, 0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194, 0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9, 0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a, 0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd, 0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0, 0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d, 0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460, 0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87, 0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674, 0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509, 0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e, 0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae, 0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3, 0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694, 0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989, 0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da, 0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d, 0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0, 0xa68cee3d}, {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19, 0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae, 0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb, 0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a, 0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55, 0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1, 0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c, 0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8, 0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7, 0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936, 0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453, 0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4, 0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941, 0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5, 0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93, 0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17, 0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e, 0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89, 0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec, 0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0, 0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf, 0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b, 0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b, 0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f, 0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0, 0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e, 0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b, 0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc, 0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5, 0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261, 0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637, 0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3, 0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57, 0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0, 0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85, 0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454, 0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b, 0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f, 0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423, 0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7, 0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8, 0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739, 0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c, 0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb, 0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f, 0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b, 0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd, 0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59, 0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070, 0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7, 0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2, 0x51e8883f}, {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a, 0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276, 0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed, 0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55, 0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b, 0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8, 0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320, 0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413, 0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd, 0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75, 0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee, 0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312, 0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca, 0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9, 0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad, 0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e, 0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504, 0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8, 0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63, 0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353, 0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d, 0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be, 0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae, 0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d, 0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943, 0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7, 0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c, 0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390, 0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a, 0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239, 0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d, 0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e, 0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c, 0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0, 0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b, 0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93, 0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d, 0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e, 0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c, 0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f, 0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1, 0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579, 0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2, 0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e, 0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c, 0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f, 0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b, 0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158, 0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2, 0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e, 0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5, 0x8ae9531c}, {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4, 0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd, 0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220, 0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf, 0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495, 0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def, 0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90, 0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea, 0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0, 0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f, 0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2, 0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab, 0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e, 0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754, 0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda, 0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0, 0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c, 0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215, 0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8, 0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910, 0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a, 0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30, 0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658, 0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22, 0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478, 0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2, 0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f, 0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606, 0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba, 0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0, 0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e, 0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034, 0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f, 0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996, 0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b, 0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84, 0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de, 0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4, 0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5, 0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f, 0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5, 0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a, 0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7, 0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce, 0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65, 0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f, 0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91, 0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb, 0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57, 0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e, 0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3, 0xd739710d}}; #endif #endif #if N == 5 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df, 0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8, 0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef, 0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376, 0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201, 0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399, 0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372, 0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea, 0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d, 0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004, 0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353, 0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334, 0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a, 0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2, 0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a, 0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2, 0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b, 0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c, 0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b, 0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f, 0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338, 0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0, 0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6, 0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e, 0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319, 0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3, 0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4, 0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783, 0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a, 0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492, 0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a, 0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2, 0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496, 0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1, 0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6, 0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f, 0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548, 0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0, 0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741, 0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9, 0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae, 0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437, 0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760, 0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707, 0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433, 0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab, 0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703, 0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b, 0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412, 0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475, 0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722, 0xe9947565}, {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5, 0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22, 0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c, 0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed, 0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d, 0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1, 0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e, 0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32, 0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142, 0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93, 0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d, 0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a, 0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58, 0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14, 0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81, 0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd, 0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab, 0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c, 0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72, 0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f, 0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff, 0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3, 0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30, 0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c, 0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c, 0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558, 0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146, 0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581, 0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7, 0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab, 0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e, 0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272, 0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838, 0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff, 0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1, 0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330, 0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840, 0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c, 0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb, 0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7, 0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7, 0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616, 0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208, 0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf, 0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85, 0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9, 0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c, 0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10, 0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76, 0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1, 0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf, 0xf7d05006}, {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b, 0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774, 0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58, 0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a, 0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb, 0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952, 0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e, 0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7, 0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746, 0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14, 0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338, 0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907, 0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777, 0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de, 0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064, 0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd, 0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951, 0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e, 0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42, 0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b, 0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a, 0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3, 0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904, 0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad, 0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c, 0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d, 0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861, 0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e, 0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2, 0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b, 0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1, 0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78, 0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f, 0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40, 0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c, 0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e, 0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf, 0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166, 0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d, 0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4, 0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805, 0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157, 0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b, 0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644, 0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43, 0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea, 0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850, 0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9, 0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165, 0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a, 0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676, 0xb2075b94}, {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf, 0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61, 0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be, 0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd, 0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3, 0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063, 0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105, 0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5, 0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb, 0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8, 0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07, 0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9, 0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5, 0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515, 0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4, 0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014, 0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7, 0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269, 0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6, 0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af, 0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1, 0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111, 0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d, 0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad, 0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3, 0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75, 0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa, 0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74, 0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7, 0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477, 0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6, 0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176, 0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af, 0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71, 0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae, 0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd, 0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3, 0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073, 0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0, 0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400, 0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e, 0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d, 0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2, 0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c, 0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5, 0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505, 0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4, 0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004, 0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7, 0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279, 0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6, 0xba50bcb9}, {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897, 0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb, 0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2, 0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2, 0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372, 0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70, 0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92, 0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190, 0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40, 0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430, 0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759, 0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75, 0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2, 0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0, 0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7, 0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5, 0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39, 0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215, 0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c, 0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5, 0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625, 0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27, 0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c, 0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e, 0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee, 0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71, 0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18, 0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134, 0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8, 0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba, 0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd, 0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff, 0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a, 0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6, 0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf, 0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf, 0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f, 0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d, 0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d, 0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f, 0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af, 0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df, 0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6, 0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a, 0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef, 0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed, 0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa, 0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8, 0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624, 0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08, 0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861, 0x808abcf4}, {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2, 0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd, 0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76, 0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52, 0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e, 0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124, 0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147, 0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d, 0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31, 0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15, 0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae, 0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1, 0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d, 0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307, 0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9, 0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3, 0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084, 0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb, 0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850, 0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2, 0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe, 0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94, 0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261, 0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b, 0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917, 0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53, 0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8, 0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787, 0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0, 0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba, 0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404, 0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e, 0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af, 0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0, 0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b, 0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f, 0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543, 0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129, 0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627, 0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d, 0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51, 0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75, 0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce, 0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1, 0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760, 0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a, 0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4, 0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde, 0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089, 0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6, 0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d, 0xefdb3f95}, {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8, 0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7, 0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945, 0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9, 0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652, 0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc, 0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a, 0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4, 0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f, 0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3, 0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51, 0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e, 0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c, 0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362, 0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11, 0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff, 0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7, 0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8, 0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a, 0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690, 0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b, 0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5, 0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05, 0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb, 0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740, 0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f, 0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded, 0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2, 0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa, 0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714, 0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67, 0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89, 0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7, 0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8, 0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a, 0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6, 0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d, 0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3, 0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9, 0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57, 0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc, 0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540, 0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2, 0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd, 0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93, 0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d, 0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e, 0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0, 0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8, 0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7, 0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75, 0x0e2fbf43}, {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc, 0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a, 0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3, 0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7, 0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b, 0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154, 0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3, 0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc, 0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330, 0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264, 0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd, 0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b, 0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a, 0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175, 0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275, 0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a, 0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234, 0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2, 0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b, 0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a, 0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6, 0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189, 0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b, 0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204, 0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8, 0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226, 0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff, 0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219, 0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167, 0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258, 0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158, 0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267, 0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c, 0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da, 0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003, 0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157, 0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b, 0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4, 0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179, 0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246, 0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a, 0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de, 0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107, 0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1, 0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba, 0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285, 0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185, 0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba, 0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4, 0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322, 0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb, 0xf4377108}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000, 0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000, 0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000, 0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000, 0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000, 0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000, 0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000, 0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000, 0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000, 0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000, 0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000, 0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000, 0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000, 0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000, 0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000, 0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000, 0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000, 0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000, 0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000, 0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000, 0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000, 0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000, 0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000, 0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000, 0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000, 0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000, 0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000, 0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000, 0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000, 0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000, 0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000, 0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000, 0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000, 0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000, 0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000, 0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000, 0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000, 0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000, 0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000, 0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000, 0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000, 0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000, 0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000, 0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000, 0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000, 0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000, 0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000, 0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000, 0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000, 0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000, 0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000, 0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000, 0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000, 0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000, 0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000, 0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000, 0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000, 0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000, 0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000, 0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000, 0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000, 0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000, 0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000, 0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000, 0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000, 0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000, 0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000, 0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000, 0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000, 0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000, 0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000, 0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000, 0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000, 0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000, 0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000, 0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000, 0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000, 0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000, 0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000, 0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000, 0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000, 0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000, 0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000, 0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000, 0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000, 0x087137f400000000}, {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000, 0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000, 0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000, 0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000, 0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000, 0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000, 0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000, 0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000, 0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000, 0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000, 0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000, 0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000, 0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000, 0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000, 0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000, 0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000, 0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000, 0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000, 0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000, 0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000, 0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000, 0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000, 0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000, 0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000, 0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000, 0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000, 0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000, 0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000, 0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000, 0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000, 0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000, 0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000, 0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000, 0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000, 0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000, 0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000, 0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000, 0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000, 0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000, 0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000, 0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000, 0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000, 0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000, 0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000, 0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000, 0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000, 0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000, 0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000, 0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000, 0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000, 0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000, 0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000, 0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000, 0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000, 0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000, 0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000, 0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000, 0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000, 0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000, 0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000, 0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000, 0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000, 0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000, 0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000, 0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000, 0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000, 0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000, 0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000, 0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000, 0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000, 0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000, 0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000, 0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000, 0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000, 0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000, 0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000, 0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000, 0x1129fad400000000, 0x621116d400000000, 0x544094f000000000, 0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000, 0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000, 0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000, 0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000, 0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000, 0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000, 0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000, 0x43bf2f0e00000000}, {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000, 0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000, 0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000, 0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000, 0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000, 0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000, 0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000, 0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000, 0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000, 0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000, 0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000, 0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000, 0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000, 0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000, 0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000, 0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000, 0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000, 0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000, 0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000, 0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000, 0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000, 0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000, 0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000, 0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000, 0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000, 0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000, 0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000, 0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000, 0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000, 0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000, 0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000, 0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000, 0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000, 0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000, 0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000, 0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000, 0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000, 0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000, 0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000, 0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000, 0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000, 0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000, 0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000, 0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000, 0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000, 0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000, 0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000, 0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000, 0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000, 0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000, 0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000, 0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000, 0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000, 0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000, 0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000, 0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000, 0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000, 0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000, 0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000, 0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000, 0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000, 0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000, 0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000, 0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000, 0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000, 0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000, 0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000, 0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000, 0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000, 0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000, 0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000, 0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000, 0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000, 0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000, 0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000, 0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000, 0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000, 0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000, 0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000, 0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000, 0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000, 0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000, 0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000, 0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000, 0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000, 0x953fdbef00000000}, {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000, 0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000, 0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000, 0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000, 0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000, 0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000, 0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000, 0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000, 0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000, 0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000, 0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000, 0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000, 0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000, 0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000, 0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000, 0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000, 0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000, 0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000, 0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000, 0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000, 0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000, 0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000, 0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000, 0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000, 0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000, 0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000, 0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000, 0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000, 0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000, 0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000, 0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000, 0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000, 0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000, 0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000, 0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000, 0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000, 0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000, 0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000, 0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000, 0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000, 0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000, 0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000, 0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000, 0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000, 0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000, 0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000, 0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000, 0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000, 0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000, 0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000, 0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000, 0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000, 0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000, 0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000, 0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000, 0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000, 0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000, 0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000, 0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000, 0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000, 0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000, 0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000, 0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000, 0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000, 0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000, 0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000, 0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000, 0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000, 0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000, 0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000, 0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000, 0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000, 0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000, 0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000, 0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000, 0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000, 0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000, 0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000, 0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000, 0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000, 0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000, 0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000, 0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000, 0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000, 0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000, 0xf4bc8a8000000000}, {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000, 0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000, 0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000, 0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000, 0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000, 0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000, 0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000, 0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000, 0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000, 0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000, 0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000, 0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000, 0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000, 0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000, 0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000, 0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000, 0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000, 0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000, 0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000, 0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000, 0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000, 0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000, 0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000, 0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000, 0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000, 0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000, 0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000, 0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000, 0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000, 0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000, 0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000, 0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000, 0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000, 0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000, 0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000, 0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000, 0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000, 0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000, 0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000, 0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000, 0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000, 0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000, 0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000, 0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000, 0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000, 0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000, 0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000, 0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000, 0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000, 0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000, 0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000, 0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000, 0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000, 0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000, 0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000, 0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000, 0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000, 0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000, 0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000, 0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000, 0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000, 0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000, 0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000, 0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000, 0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000, 0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000, 0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000, 0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000, 0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000, 0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000, 0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000, 0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000, 0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000, 0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000, 0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000, 0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000, 0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000, 0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000, 0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000, 0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000, 0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000, 0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000, 0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000, 0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000, 0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000, 0xb9bc50ba00000000}, {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000, 0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000, 0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000, 0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000, 0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000, 0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000, 0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000, 0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000, 0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000, 0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000, 0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000, 0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000, 0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000, 0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000, 0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000, 0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000, 0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000, 0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000, 0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000, 0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000, 0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000, 0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000, 0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000, 0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000, 0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000, 0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000, 0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000, 0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000, 0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000, 0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000, 0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000, 0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000, 0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000, 0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000, 0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000, 0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000, 0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000, 0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000, 0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000, 0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000, 0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000, 0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000, 0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000, 0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000, 0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000, 0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000, 0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000, 0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000, 0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000, 0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000, 0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000, 0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000, 0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000, 0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000, 0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000, 0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000, 0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000, 0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000, 0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000, 0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000, 0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000, 0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000, 0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000, 0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000, 0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000, 0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000, 0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000, 0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000, 0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000, 0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000, 0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000, 0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000, 0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000, 0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000, 0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000, 0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000, 0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000, 0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000, 0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000, 0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000, 0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000, 0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000, 0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000, 0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000, 0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000, 0x945b07b200000000}, {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000, 0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000, 0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000, 0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000, 0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000, 0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000, 0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000, 0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000, 0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000, 0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000, 0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000, 0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000, 0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000, 0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000, 0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000, 0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000, 0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000, 0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000, 0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000, 0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000, 0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000, 0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000, 0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000, 0x149f066100000000, 0xef839db200000000, 0x468814fc00000000, 0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000, 0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000, 0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000, 0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000, 0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000, 0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000, 0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000, 0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000, 0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000, 0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000, 0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000, 0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000, 0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000, 0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000, 0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000, 0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000, 0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000, 0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000, 0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000, 0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000, 0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000, 0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000, 0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000, 0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000, 0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000, 0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000, 0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000, 0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000, 0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000, 0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000, 0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000, 0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000, 0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000, 0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000, 0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000, 0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000, 0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000, 0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000, 0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000, 0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000, 0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000, 0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000, 0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000, 0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000, 0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000, 0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000, 0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000, 0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000, 0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000, 0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000, 0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000, 0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000, 0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000, 0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000, 0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000, 0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000, 0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000, 0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000, 0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000, 0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000, 0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000, 0x0650d0f700000000}, {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000, 0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000, 0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000, 0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000, 0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000, 0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000, 0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000, 0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000, 0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000, 0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000, 0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000, 0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000, 0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000, 0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000, 0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000, 0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000, 0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000, 0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000, 0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000, 0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000, 0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000, 0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000, 0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000, 0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000, 0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000, 0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000, 0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000, 0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000, 0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000, 0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000, 0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000, 0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000, 0xc702c15700000000, 0x809085f800000000, 0x082039d200000000, 0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000, 0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000, 0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000, 0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000, 0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000, 0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000, 0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000, 0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000, 0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000, 0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000, 0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000, 0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000, 0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000, 0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000, 0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000, 0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000, 0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000, 0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000, 0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000, 0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000, 0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000, 0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000, 0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000, 0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000, 0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000, 0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000, 0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000, 0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000, 0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000, 0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000, 0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000, 0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000, 0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000, 0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000, 0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000, 0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000, 0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000, 0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000, 0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000, 0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000, 0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000, 0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000, 0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000, 0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000, 0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000, 0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000, 0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000, 0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000, 0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000, 0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000, 0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000, 0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000, 0x657594e900000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59, 0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4, 0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67, 0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef, 0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97, 0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88, 0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687, 0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698, 0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0, 0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068, 0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb, 0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056, 0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016, 0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009, 0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028, 0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037, 0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a, 0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7, 0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054, 0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7, 0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af, 0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0, 0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4, 0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab, 0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3, 0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a, 0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9, 0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54, 0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09, 0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16, 0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37, 0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28, 0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e, 0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3, 0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40, 0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8, 0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0, 0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf, 0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6, 0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9, 0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1, 0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059, 0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca, 0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067, 0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031, 0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e, 0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f, 0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010, 0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d, 0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0, 0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073, 0xd8ac6b35}, {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2, 0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd, 0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696, 0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3, 0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f, 0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35, 0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5, 0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f, 0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673, 0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46, 0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d, 0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632, 0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28, 0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192, 0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c, 0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6, 0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0, 0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff, 0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4, 0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95, 0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9, 0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03, 0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7, 0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d, 0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151, 0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808, 0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343, 0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c, 0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a, 0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0, 0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e, 0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594, 0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6, 0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399, 0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2, 0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7, 0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb, 0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571, 0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289, 0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33, 0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f, 0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a, 0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461, 0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e, 0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c, 0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6, 0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918, 0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2, 0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484, 0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb, 0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0, 0xa140efa8}, {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706, 0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed, 0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289, 0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a, 0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214, 0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3, 0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3, 0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254, 0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a, 0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9, 0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad, 0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746, 0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060, 0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187, 0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef, 0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408, 0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e, 0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495, 0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1, 0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532, 0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c, 0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb, 0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb, 0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c, 0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42, 0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060, 0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04, 0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef, 0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99, 0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e, 0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16, 0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1, 0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7, 0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c, 0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38, 0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb, 0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5, 0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42, 0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62, 0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85, 0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb, 0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18, 0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c, 0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997, 0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1, 0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36, 0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e, 0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9, 0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf, 0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24, 0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040, 0x917cd6a1}, {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf, 0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd, 0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896, 0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9, 0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3, 0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f, 0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d, 0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1, 0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab, 0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4, 0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f, 0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d, 0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4, 0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978, 0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad, 0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621, 0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46, 0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854, 0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f, 0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a, 0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890, 0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c, 0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4, 0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238, 0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622, 0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab, 0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0, 0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2, 0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295, 0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19, 0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc, 0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140, 0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd, 0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf, 0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184, 0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb, 0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1, 0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d, 0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb, 0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257, 0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d, 0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22, 0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069, 0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b, 0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6, 0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a, 0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf, 0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33, 0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254, 0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146, 0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d, 0x18ba364e}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873, 0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661, 0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441, 0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44, 0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1, 0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05, 0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa, 0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e, 0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb, 0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be, 0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e, 0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c, 0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d, 0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9, 0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f, 0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b, 0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39, 0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b, 0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b, 0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20, 0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595, 0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61, 0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0, 0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644, 0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1, 0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d, 0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d, 0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f, 0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad, 0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359, 0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f, 0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b, 0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7, 0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5, 0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5, 0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0, 0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65, 0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091, 0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633, 0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7, 0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272, 0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77, 0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57, 0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145, 0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9, 0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d, 0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb, 0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f, 0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad, 0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf, 0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f, 0x4e36ba18}, {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b, 0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8, 0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19, 0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4, 0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239, 0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd, 0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258, 0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc, 0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41, 0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c, 0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d, 0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e, 0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba, 0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e, 0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8, 0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c, 0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f, 0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c, 0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d, 0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d, 0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0, 0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014, 0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc, 0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628, 0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5, 0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941, 0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0, 0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53, 0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880, 0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264, 0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92, 0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776, 0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8, 0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b, 0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea, 0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837, 0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca, 0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e, 0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211, 0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5, 0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08, 0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5, 0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934, 0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7, 0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049, 0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad, 0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b, 0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf, 0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c, 0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f, 0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e, 0xa1d67c91}, {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9, 0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de, 0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94, 0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0, 0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a, 0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924, 0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052, 0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c, 0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6, 0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2, 0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8, 0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f, 0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d, 0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273, 0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30, 0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e, 0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7, 0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980, 0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca, 0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8, 0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62, 0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c, 0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c, 0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032, 0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798, 0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d, 0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07, 0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630, 0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389, 0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7, 0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4, 0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca, 0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55, 0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662, 0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828, 0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c, 0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6, 0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98, 0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3, 0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d, 0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037, 0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913, 0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759, 0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e, 0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1, 0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf, 0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c, 0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2, 0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b, 0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c, 0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276, 0xa8ef40a1}, {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e, 0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8, 0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819, 0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f, 0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d, 0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756, 0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0, 0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb, 0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9, 0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f, 0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e, 0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8, 0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835, 0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e, 0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62, 0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749, 0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b, 0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d, 0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc, 0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80, 0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2, 0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599, 0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05, 0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e, 0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c, 0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e, 0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef, 0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359, 0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b, 0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0, 0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc, 0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7, 0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f, 0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189, 0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568, 0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e, 0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c, 0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27, 0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794, 0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf, 0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d, 0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db, 0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a, 0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c, 0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544, 0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f, 0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013, 0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38, 0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea, 0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c, 0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd, 0x356bacd8}}; #endif #endif #if N == 6 #if W == 8 local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370, 0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d, 0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69, 0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426, 0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3, 0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f, 0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c, 0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490, 0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155, 0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a, 0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e, 0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603, 0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349, 0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5, 0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50, 0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc, 0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b, 0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76, 0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862, 0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9, 0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c, 0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0, 0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937, 0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b, 0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e, 0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e, 0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a, 0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357, 0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0, 0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c, 0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9, 0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165, 0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766, 0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b, 0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f, 0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030, 0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5, 0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59, 0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63, 0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf, 0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a, 0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845, 0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51, 0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c, 0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f, 0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3, 0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46, 0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea, 0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d, 0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60, 0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74, 0x8568a0a8}, {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5, 0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf, 0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5, 0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba, 0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf, 0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f, 0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0, 0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450, 0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55, 0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a, 0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620, 0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a, 0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454, 0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4, 0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534, 0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584, 0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694, 0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e, 0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4, 0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1, 0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4, 0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164, 0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1, 0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911, 0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314, 0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c, 0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6, 0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec, 0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc, 0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c, 0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c, 0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c, 0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716, 0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c, 0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676, 0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879, 0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c, 0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc, 0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77, 0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7, 0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2, 0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd, 0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7, 0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad, 0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897, 0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827, 0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7, 0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947, 0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57, 0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d, 0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37, 0x0d907052}, {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d, 0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89, 0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31, 0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81, 0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e, 0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0, 0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f, 0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291, 0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e, 0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e, 0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936, 0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2, 0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13, 0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d, 0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f, 0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1, 0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a, 0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae, 0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516, 0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f, 0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20, 0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe, 0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28, 0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6, 0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419, 0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5, 0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d, 0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889, 0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412, 0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c, 0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e, 0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0, 0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02, 0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986, 0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e, 0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e, 0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221, 0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf, 0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913, 0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d, 0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622, 0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592, 0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a, 0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae, 0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c, 0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82, 0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20, 0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe, 0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025, 0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1, 0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719, 0xfd1a6c8a}, {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3, 0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb, 0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d, 0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb, 0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9, 0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156, 0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045, 0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa, 0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8, 0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e, 0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8, 0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0, 0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38, 0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87, 0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46, 0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9, 0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585, 0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d, 0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb, 0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531, 0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03, 0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc, 0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33, 0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c, 0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be, 0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d, 0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b, 0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303, 0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f, 0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0, 0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801, 0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe, 0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e, 0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346, 0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620, 0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776, 0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844, 0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb, 0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0, 0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f, 0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d, 0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b, 0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d, 0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75, 0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795, 0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a, 0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb, 0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354, 0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28, 0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30, 0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856, 0x7895f01a}, {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188, 0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33, 0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d, 0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445, 0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2, 0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058, 0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43, 0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9, 0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e, 0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06, 0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228, 0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93, 0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e, 0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4, 0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b, 0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371, 0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265, 0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede, 0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0, 0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f, 0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8, 0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32, 0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae, 0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544, 0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3, 0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f, 0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911, 0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa, 0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be, 0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54, 0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b, 0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1, 0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652, 0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9, 0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7, 0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f, 0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68, 0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782, 0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797, 0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d, 0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a, 0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2, 0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc, 0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647, 0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4, 0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e, 0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41, 0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab, 0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf, 0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904, 0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a, 0x9239b848}, {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad, 0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0, 0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40, 0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b, 0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d, 0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b, 0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb, 0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d, 0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b, 0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0, 0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840, 0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d, 0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b, 0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d, 0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6, 0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0, 0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580, 0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd, 0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d, 0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b, 0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d, 0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b, 0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6, 0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0, 0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6, 0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c, 0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c, 0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461, 0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841, 0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317, 0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac, 0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa, 0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7, 0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba, 0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a, 0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161, 0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777, 0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21, 0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a, 0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc, 0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da, 0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1, 0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01, 0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c, 0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241, 0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917, 0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac, 0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa, 0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da, 0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397, 0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537, 0xeb36d3cc}, {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b, 0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059, 0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251, 0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d, 0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9, 0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c, 0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41, 0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4, 0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10, 0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c, 0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54, 0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476, 0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8, 0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d, 0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92, 0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307, 0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad, 0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f, 0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87, 0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17, 0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3, 0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46, 0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197, 0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02, 0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6, 0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e, 0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96, 0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4, 0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e, 0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b, 0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934, 0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1, 0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7, 0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5, 0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd, 0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1, 0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475, 0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0, 0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155, 0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0, 0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304, 0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348, 0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140, 0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862, 0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14, 0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181, 0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e, 0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab, 0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01, 0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523, 0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b, 0x38e5f3c5}, {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06, 0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad, 0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509, 0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba, 0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414, 0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3, 0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733, 0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994, 0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a, 0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889, 0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d, 0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386, 0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621, 0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886, 0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e, 0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389, 0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f, 0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294, 0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30, 0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3, 0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d, 0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba, 0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a, 0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad, 0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03, 0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2, 0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306, 0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad, 0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b, 0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc, 0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914, 0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3, 0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435, 0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e, 0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a, 0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589, 0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27, 0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080, 0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21, 0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586, 0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28, 0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b, 0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f, 0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94, 0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12, 0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5, 0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d, 0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba, 0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c, 0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7, 0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103, 0x3d3101a2}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000, 0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000, 0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000, 0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000, 0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000, 0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000, 0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000, 0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000, 0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000, 0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000, 0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000, 0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000, 0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000, 0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000, 0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000, 0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000, 0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000, 0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000, 0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000, 0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000, 0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000, 0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000, 0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000, 0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000, 0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000, 0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000, 0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000, 0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000, 0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000, 0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000, 0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000, 0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000, 0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000, 0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000, 0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000, 0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000, 0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000, 0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000, 0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000, 0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000, 0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000, 0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000, 0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000, 0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000, 0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000, 0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000, 0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000, 0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000, 0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000, 0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000, 0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000, 0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000, 0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000, 0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000, 0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000, 0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000, 0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000, 0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000, 0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000, 0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000, 0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000, 0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000, 0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000, 0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000, 0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000, 0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000, 0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000, 0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000, 0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000, 0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000, 0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000, 0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000, 0x3688267d00000000, 0x9718319500000000, 0x35af787600000000, 0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000, 0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000, 0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000, 0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000, 0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000, 0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000, 0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000, 0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000, 0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000, 0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000, 0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000, 0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000, 0xa201313d00000000}, {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000, 0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000, 0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000, 0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000, 0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000, 0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000, 0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000, 0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000, 0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000, 0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000, 0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000, 0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000, 0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000, 0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000, 0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000, 0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000, 0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000, 0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000, 0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000, 0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000, 0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000, 0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000, 0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000, 0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000, 0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000, 0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000, 0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000, 0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000, 0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000, 0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000, 0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000, 0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000, 0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000, 0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000, 0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000, 0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000, 0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000, 0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000, 0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000, 0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000, 0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000, 0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000, 0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000, 0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000, 0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000, 0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000, 0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000, 0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000, 0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000, 0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000, 0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000, 0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000, 0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000, 0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000, 0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000, 0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000, 0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000, 0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000, 0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000, 0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000, 0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000, 0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000, 0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000, 0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000, 0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000, 0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000, 0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000, 0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000, 0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000, 0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000, 0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000, 0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000, 0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000, 0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000, 0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000, 0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000, 0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000, 0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000, 0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000, 0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000, 0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000, 0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000, 0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000, 0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000, 0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000, 0xc5f3e53800000000}, {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000, 0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000, 0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000, 0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000, 0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000, 0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000, 0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000, 0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000, 0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000, 0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000, 0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000, 0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000, 0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000, 0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000, 0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000, 0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000, 0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000, 0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000, 0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000, 0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000, 0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000, 0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000, 0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000, 0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000, 0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000, 0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000, 0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000, 0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000, 0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000, 0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000, 0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000, 0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000, 0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000, 0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000, 0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000, 0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000, 0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000, 0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000, 0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000, 0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000, 0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000, 0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000, 0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000, 0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000, 0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000, 0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000, 0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000, 0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000, 0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000, 0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000, 0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000, 0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000, 0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000, 0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000, 0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000, 0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000, 0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000, 0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000, 0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000, 0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000, 0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000, 0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000, 0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000, 0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000, 0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000, 0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000, 0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000, 0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000, 0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000, 0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000, 0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000, 0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000, 0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000, 0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000, 0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000, 0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000, 0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000, 0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000, 0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000, 0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000, 0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000, 0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000, 0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000, 0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000, 0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000, 0xccd336eb00000000}, {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000, 0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000, 0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000, 0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000, 0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000, 0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000, 0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000, 0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000, 0xb249204500000000, 0xd071086f00000000, 0x7639701100000000, 0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000, 0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000, 0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000, 0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000, 0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000, 0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000, 0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000, 0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000, 0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000, 0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000, 0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000, 0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000, 0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000, 0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000, 0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000, 0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000, 0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000, 0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000, 0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000, 0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000, 0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000, 0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000, 0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000, 0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000, 0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000, 0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000, 0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000, 0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000, 0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000, 0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000, 0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000, 0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000, 0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000, 0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000, 0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000, 0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000, 0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000, 0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000, 0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000, 0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000, 0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000, 0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000, 0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000, 0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000, 0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000, 0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000, 0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000, 0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000, 0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000, 0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000, 0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000, 0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000, 0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000, 0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000, 0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000, 0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000, 0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000, 0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000, 0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000, 0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000, 0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000, 0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000, 0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000, 0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000, 0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000, 0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000, 0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000, 0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000, 0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000, 0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000, 0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000, 0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000, 0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000, 0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000, 0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000, 0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000, 0x48b8399200000000}, {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000, 0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000, 0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000, 0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000, 0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000, 0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000, 0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000, 0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000, 0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000, 0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000, 0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000, 0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000, 0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000, 0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000, 0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000, 0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000, 0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000, 0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000, 0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000, 0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000, 0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000, 0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000, 0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000, 0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000, 0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000, 0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000, 0xb521428400000000, 0xf909d42700000000, 0x762efede00000000, 0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000, 0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000, 0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000, 0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000, 0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000, 0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000, 0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000, 0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000, 0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000, 0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000, 0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000, 0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000, 0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000, 0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000, 0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000, 0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000, 0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000, 0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000, 0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000, 0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000, 0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000, 0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000, 0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000, 0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000, 0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000, 0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000, 0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000, 0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000, 0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000, 0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000, 0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000, 0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000, 0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000, 0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000, 0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000, 0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000, 0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000, 0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000, 0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000, 0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000, 0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000, 0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000, 0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000, 0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000, 0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000, 0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000, 0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000, 0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000, 0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000, 0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000, 0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000, 0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000, 0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000, 0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000, 0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000, 0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000, 0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000, 0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000, 0x1af0957800000000}, {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000, 0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000, 0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000, 0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000, 0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000, 0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000, 0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000, 0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000, 0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000, 0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000, 0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000, 0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000, 0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000, 0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000, 0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000, 0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000, 0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000, 0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000, 0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000, 0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000, 0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000, 0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000, 0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000, 0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000, 0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000, 0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000, 0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000, 0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000, 0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000, 0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000, 0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000, 0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000, 0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000, 0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000, 0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000, 0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000, 0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000, 0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000, 0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000, 0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000, 0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000, 0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000, 0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000, 0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000, 0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000, 0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000, 0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000, 0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000, 0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000, 0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000, 0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000, 0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000, 0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000, 0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000, 0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000, 0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000, 0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000, 0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000, 0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000, 0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000, 0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000, 0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000, 0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000, 0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000, 0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000, 0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000, 0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000, 0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000, 0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000, 0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000, 0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000, 0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000, 0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000, 0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000, 0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000, 0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000, 0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000, 0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000, 0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000, 0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000, 0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000, 0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000, 0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000, 0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000, 0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000, 0x8a6c1afd00000000}, {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000, 0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000, 0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000, 0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000, 0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000, 0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000, 0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000, 0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000, 0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000, 0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000, 0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000, 0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000, 0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000, 0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000, 0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000, 0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000, 0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000, 0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000, 0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000, 0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000, 0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000, 0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000, 0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000, 0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000, 0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000, 0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000, 0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000, 0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000, 0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000, 0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000, 0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000, 0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000, 0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000, 0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000, 0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000, 0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000, 0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000, 0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000, 0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000, 0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000, 0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000, 0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000, 0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000, 0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000, 0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000, 0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000, 0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000, 0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000, 0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000, 0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000, 0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000, 0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000, 0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000, 0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000, 0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000, 0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000, 0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000, 0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000, 0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000, 0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000, 0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000, 0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000, 0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000, 0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000, 0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000, 0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000, 0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000, 0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000, 0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000, 0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000, 0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000, 0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000, 0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000, 0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000, 0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000, 0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000, 0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000, 0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000, 0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000, 0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000, 0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000, 0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000, 0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000, 0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000, 0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000, 0x5270900d00000000}, {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000, 0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000, 0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000, 0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000, 0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000, 0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000, 0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000, 0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000, 0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000, 0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000, 0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000, 0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000, 0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000, 0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000, 0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000, 0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000, 0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000, 0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000, 0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000, 0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000, 0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000, 0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000, 0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000, 0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000, 0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000, 0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000, 0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000, 0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000, 0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000, 0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000, 0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000, 0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000, 0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000, 0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000, 0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000, 0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000, 0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000, 0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000, 0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000, 0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000, 0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000, 0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000, 0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000, 0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000, 0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000, 0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000, 0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000, 0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000, 0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000, 0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000, 0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000, 0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000, 0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000, 0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000, 0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000, 0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000, 0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000, 0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000, 0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000, 0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000, 0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000, 0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000, 0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000, 0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000, 0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000, 0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000, 0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000, 0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000, 0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000, 0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000, 0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000, 0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000, 0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000, 0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000, 0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000, 0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000, 0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000, 0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000, 0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000, 0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000, 0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000, 0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000, 0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000, 0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000, 0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000, 0xa8a0688500000000}}; #else /* W == 4 */ local const z_crc_t FAR crc_braid_table[][256] = { {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f, 0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999, 0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee, 0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615, 0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383, 0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb, 0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275, 0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d, 0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b, 0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460, 0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317, 0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1, 0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5, 0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd, 0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04, 0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c, 0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7, 0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11, 0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66, 0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7, 0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871, 0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309, 0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd, 0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85, 0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913, 0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d, 0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a, 0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc, 0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57, 0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f, 0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6, 0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e, 0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f, 0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289, 0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe, 0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05, 0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893, 0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb, 0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0, 0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8, 0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e, 0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5, 0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2, 0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574, 0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5, 0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add, 0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114, 0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c, 0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7, 0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701, 0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076, 0x09cd8551}, {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193, 0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2, 0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c, 0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71, 0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a, 0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d, 0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71, 0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436, 0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d, 0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000, 0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae, 0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf, 0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930, 0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277, 0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff, 0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8, 0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef, 0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e, 0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20, 0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95, 0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e, 0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9, 0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d, 0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a, 0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151, 0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4, 0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a, 0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b, 0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c, 0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b, 0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3, 0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4, 0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b, 0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a, 0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4, 0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189, 0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92, 0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5, 0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9, 0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe, 0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5, 0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8, 0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66, 0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707, 0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8, 0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f, 0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707, 0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40, 0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017, 0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876, 0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8, 0x7bc97a0c}, {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300, 0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0, 0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80, 0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701, 0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41, 0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81, 0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43, 0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83, 0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3, 0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42, 0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202, 0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2, 0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7, 0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407, 0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47, 0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87, 0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86, 0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46, 0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506, 0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44, 0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704, 0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4, 0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5, 0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505, 0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45, 0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f, 0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f, 0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f, 0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e, 0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e, 0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e, 0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce, 0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c, 0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc, 0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c, 0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d, 0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d, 0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d, 0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88, 0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48, 0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708, 0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89, 0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9, 0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309, 0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb, 0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b, 0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b, 0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b, 0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a, 0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a, 0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a, 0x7851a2ca}, {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb, 0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8, 0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0, 0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f, 0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a, 0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf, 0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5, 0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380, 0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815, 0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa, 0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2, 0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1, 0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1, 0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4, 0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa, 0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df, 0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6, 0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5, 0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad, 0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca, 0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f, 0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a, 0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8, 0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d, 0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708, 0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d, 0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865, 0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636, 0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f, 0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a, 0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744, 0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061, 0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0, 0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293, 0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb, 0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874, 0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1, 0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4, 0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f, 0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a, 0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f, 0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120, 0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778, 0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b, 0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a, 0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af, 0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81, 0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4, 0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd, 0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e, 0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6, 0x566b6848}}; local const z_word_t FAR crc_braid_big_table[][256] = { {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912, 0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba, 0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3, 0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30, 0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e, 0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3, 0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73, 0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe, 0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0, 0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643, 0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a, 0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082, 0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4, 0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279, 0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735, 0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8, 0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad, 0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05, 0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c, 0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718, 0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46, 0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb, 0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc, 0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41, 0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f, 0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad, 0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4, 0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c, 0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779, 0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4, 0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8, 0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235, 0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7, 0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f, 0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476, 0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195, 0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb, 0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46, 0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622, 0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af, 0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1, 0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12, 0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b, 0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3, 0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51, 0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc, 0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90, 0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d, 0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708, 0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0, 0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9, 0x48686b56}, {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c, 0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae, 0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb, 0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90, 0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410, 0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b, 0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6, 0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed, 0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d, 0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036, 0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953, 0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1, 0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca, 0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781, 0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d, 0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416, 0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f, 0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd, 0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8, 0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b, 0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb, 0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0, 0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5, 0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e, 0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e, 0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558, 0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d, 0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf, 0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6, 0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad, 0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971, 0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a, 0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b, 0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969, 0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c, 0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57, 0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7, 0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c, 0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab, 0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0, 0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160, 0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b, 0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e, 0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac, 0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d, 0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546, 0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a, 0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1, 0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8, 0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a, 0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f, 0xcaa25178}, {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00, 0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b, 0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed, 0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777, 0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01, 0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a, 0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef, 0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74, 0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002, 0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498, 0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee, 0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75, 0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05, 0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e, 0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8, 0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73, 0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404, 0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f, 0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9, 0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71, 0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607, 0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c, 0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb, 0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470, 0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806, 0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790, 0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6, 0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d, 0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a, 0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991, 0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7, 0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c, 0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09, 0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92, 0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4, 0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e, 0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08, 0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593, 0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3, 0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778, 0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e, 0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94, 0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2, 0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079, 0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c, 0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497, 0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1, 0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a, 0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d, 0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396, 0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0, 0x0c7ac97b}, {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669, 0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853, 0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062, 0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527, 0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad, 0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545, 0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27, 0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf, 0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45, 0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800, 0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031, 0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b, 0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26, 0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce, 0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d, 0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5, 0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130, 0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a, 0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b, 0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480, 0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a, 0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2, 0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e, 0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996, 0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c, 0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc, 0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd, 0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7, 0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232, 0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da, 0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439, 0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1, 0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da, 0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0, 0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1, 0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94, 0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e, 0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6, 0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2, 0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a, 0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0, 0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95, 0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4, 0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e, 0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395, 0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d, 0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e, 0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676, 0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83, 0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9, 0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888, 0x5185cd09}}; #endif #endif #endif local const z_crc_t FAR x2n_table[] = { 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, 0xc40ba6d0, 0xc4e22c3c}; mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/deflate.c0000644000175100001660000023750314760300420016644 0ustar /* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions * of the input text which are identical to earlier input (within a * sliding window trailing behind the input currently being processed). * * The most straightforward technique turns out to be the fastest for * most input files: try all possible matches and select the longest. * The key feature of this algorithm is that insertions into the string * dictionary are very simple and thus fast, and deletions are avoided * completely. Insertions are performed at each input character, whereas * string matches are performed only when the previous match ends. So it * is preferable to spend more time in matches to allow very fast string * insertions and avoid deletions. The matching algorithm for small * strings is inspired from that of Rabin & Karp. A brute force approach * is used to find longer strings when a small match has been found. * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze * (by Leonid Broukhis). * A previous version of this file used a more sophisticated algorithm * (by Fiala and Greene) which is guaranteed to run in linear amortized * time, but has a larger average cost, uses more memory and is patented. * However the F&G algorithm may be faster for some highly redundant * files if the parameter max_chain_length (described below) is too large. * * ACKNOWLEDGEMENTS * * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and * I found it in 'freeze' written by Leonid Broukhis. * Thanks to many people for bug reports and testing. * * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. * * Fiala,E.R., and Greene,D.H. * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 * */ /* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func)(deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */ local block_state deflate_stored(deflate_state *s, int flush); local block_state deflate_fast(deflate_state *s, int flush); #ifndef FASTEST local block_state deflate_slow(deflate_state *s, int flush); #endif local block_state deflate_rle(deflate_state *s, int flush); local block_state deflate_huff(deflate_state *s, int flush); /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ #ifndef TOO_FAR # define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; compress_func func; } config; #ifdef FASTEST local const config configuration_table[2] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ #else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ #endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to UPDATE_HASH are made with consecutive input * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. * IN assertion: all calls to INSERT_STRING are made with consecutive input * characters and the first MIN_MATCH bytes of str are valid (except for * the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ do { \ s->head[s->hash_size - 1] = NIL; \ zmemzero((Bytef *)s->head, \ (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ } while (0) /* =========================================================================== * Slide the hash table when sliding the window down (could be avoided with 32 * bit values at the expense of memory usage). We slide even when level == 0 to * keep the hash table consistent if we switch back to level > 0 later. */ #if defined(__has_feature) # if __has_feature(memory_sanitizer) __attribute__((no_sanitize("memory"))) # endif #endif local void slide_hash(deflate_state *s) { unsigned n, m; Posf *p; uInt wsize = s->w_size; n = s->hash_size; p = &s->head[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m - wsize : NIL); } while (--n); n = wsize; #ifndef FASTEST p = &s->prev[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m - wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, buf, len); } #endif strm->next_in += len; strm->total_in += len; return len; } /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ local void fill_window(deflate_state *s) { unsigned n; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize + MAX_DIST(s)) { zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; if (s->insert > s->strstart) s->insert = s->strstart; slide_hash(s); more += wsize; } if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead + s->insert >= MIN_MATCH) { uInt str = s->strstart - s->insert; s->ins_h = s->window[str]; UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif while (s->insert) { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; s->insert--; if (s->lookahead + s->insert < MIN_MATCH) break; } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "not enough room for search"); } /* ========================================================================= */ int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, int stream_size) { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size) { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; if (windowBits < -15) return Z_STREAM_ERROR; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; s->status = INIT_STATE; /* to pass state test in deflateReset() */ s->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = (uInt)windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ /* We overlay pending_buf and sym_buf. This works since the average size * for length/distance pairs over any compressed block is assured to be 31 * bits or less. * * Analysis: The longest fixed codes are a length code of 8 bits plus 5 * extra bits, for lengths 131 to 257. The longest fixed distance codes are * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest * possible fixed-codes length/distance pair is then 31 bits total. * * sym_buf starts one-fourth of the way into pending_buf. So there are * three bytes in sym_buf for every four bytes in pending_buf. Each symbol * in sym_buf is three bytes -- two for the distance and one for the * literal/length. As each symbol is consumed, the pointer to the next * sym_buf value to read moves forward three bytes. From that symbol, up to * 31 bits are written to pending_buf. The closest the written pending_buf * bits gets to the next sym_buf symbol to read is just before the last * code is written. At that time, 31*(n - 2) bits have been written, just * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 * symbols are written.) The closest the writing gets to what is unread is * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and * can range from 128 to 32768. * * Therefore, at a minimum, there are 142 bits of space between what is * written and what is read in the overlain buffers, so the symbols cannot * be overwritten by the compressed data. That space is actually 139 bits, * due to the three-bit fixed-code block header. * * That covers the case where either Z_FIXED is specified, forcing fixed * codes, or when the use of fixed codes is chosen, because that choice * results in a smaller compressed block than dynamic codes. That latter * condition then assures that the above analysis also covers all dynamic * blocks. A dynamic-code block will only be chosen to be emitted if it has * fewer bits than a fixed-code block would for the same set of symbols. * Therefore its average symbol length is assured to be less than 31. So * the compressed data for a dynamic block also cannot overwrite the * symbols from which it is being constructed. */ s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS); s->pending_buf_size = (ulg)s->lit_bufsize * 4; if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } #ifdef LIT_MEM s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1)); s->l_buf = s->pending_buf + (s->lit_bufsize << 2); s->sym_end = s->lit_bufsize - 1; #else s->sym_buf = s->pending_buf + s->lit_bufsize; s->sym_end = (s->lit_bufsize - 1) * 3; #endif /* We avoid equality with lit_bufsize*3 because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ local int deflateStateCheck(z_streamp strm) { deflate_state *s; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; s = strm->state; if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && #ifdef GZIP s->status != GZIP_STATE && #endif s->status != EXTRA_STATE && s->status != NAME_STATE && s->status != COMMENT_STATE && s->status != HCRC_STATE && s->status != BUSY_STATE && s->status != FINISH_STATE)) return 1; return 0; } /* ========================================================================= */ int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength) { deflate_state *s; uInt str, n; int wrap; unsigned avail; z_const unsigned char *next; if (deflateStateCheck(strm) || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) return Z_STREAM_ERROR; /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); s->wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ if (dictLength >= s->w_size) { if (wrap == 0) { /* already empty otherwise */ CLEAR_HASH(s); s->strstart = 0; s->block_start = 0L; s->insert = 0; } dictionary += dictLength - s->w_size; /* use the tail */ dictLength = s->w_size; } /* insert dictionary into window and hash */ avail = strm->avail_in; next = strm->next_in; strm->avail_in = dictLength; strm->next_in = (z_const Bytef *)dictionary; fill_window(s); while (s->lookahead >= MIN_MATCH) { str = s->strstart; n = s->lookahead - (MIN_MATCH-1); do { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; } while (--n); s->strstart = str; s->lookahead = MIN_MATCH-1; fill_window(s); } s->strstart += s->lookahead; s->block_start = (long)s->strstart; s->insert = s->lookahead; s->lookahead = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary, uInt *dictLength) { deflate_state *s; uInt len; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; len = s->strstart + s->lookahead; if (len > s->w_size) len = s->w_size; if (dictionary != Z_NULL && len) zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); if (dictLength != Z_NULL) *dictLength = len; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateResetKeep(z_streamp strm) { deflate_state *s; if (deflateStateCheck(strm)) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = #ifdef GZIP s->wrap == 2 ? GZIP_STATE : #endif INIT_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = -2; _tr_init(s); return Z_OK; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ local void lm_init(deflate_state *s) { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; } /* ========================================================================= */ int ZEXPORT deflateReset(z_streamp strm) { int ret; ret = deflateResetKeep(strm); if (ret == Z_OK) lm_init(strm->state); return ret; } /* ========================================================================= */ int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) { if (deflateStateCheck(strm) || strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) *bits = strm->state->bi_valid; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { deflate_state *s; int put; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; #ifdef LIT_MEM if (bits < 0 || bits > 16 || (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; #else if (bits < 0 || bits > 16 || s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; #endif do { put = Buf_size - s->bi_valid; if (put > bits) put = bits; s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); s->bi_valid += put; _tr_flush_bits(s); value >>= put; bits -= put; } while (bits); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) { deflate_state *s; compress_func func; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && s->last_flush != -2) { /* Flush the last buffer: */ int err = deflate(strm, Z_BLOCK); if (err == Z_STREAM_ERROR) return err; if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) return Z_BUF_ERROR; } if (s->level != level) { if (s->level == 0 && s->matches != 0) { if (s->matches == 1) slide_hash(s); else CLEAR_HASH(s); s->matches = 0; } s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; s->nice_match = configuration_table[level].nice_length; s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain) { deflate_state *s; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; s->good_match = (uInt)good_length; s->max_lazy_match = (uInt)max_lazy; s->nice_match = nice_length; s->max_chain_length = (uInt)max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns a * close to exact, as well as small, upper bound on the compressed size. This * is an expansion of ~0.03%, plus a small constant. * * For any setting other than those defaults for windowBits and memLevel, one * of two worst case bounds is returned. This is at most an expansion of ~4% or * ~13%, plus a small constant. * * Both the 0.03% and 4% derive from the overhead of stored blocks. The first * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second * is for stored blocks of 127 bytes (the worst case memLevel == 1). The * expansion results from five bytes of header for each stored block. * * The larger expansion of 13% results from a window size less than or equal to * the symbols buffer size (windowBits <= memLevel + 7). In that case some of * the data being compressed may have slid out of the sliding window, impeding * a stored block from being emitted. Then the only choice is a fixed or * dynamic block, where a fixed block limits the maximum expansion to 9 bits * per 8-bit byte, plus 10 bits for every block. The smallest block size for * which this can occur is 255 (memLevel == 2). * * Shifts are used to approximate divisions, for speed. */ uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) { deflate_state *s; uLong fixedlen, storelen, wraplen; /* upper bound for fixed blocks with 9-bit literals and length 255 (memLevel == 2, which is the lowest that may not use stored blocks) -- ~13% overhead plus a small constant */ fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + (sourceLen >> 9) + 4; /* upper bound for stored blocks with length 127 (memLevel == 1) -- ~4% overhead plus a small constant */ storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + (sourceLen >> 11) + 7; /* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) return (fixedlen > storelen ? fixedlen : storelen) + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; #ifdef GZIP case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ Bytef *str; if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; if (str != Z_NULL) do { wraplen++; } while (*str++); str = s->gzhead->comment; if (str != Z_NULL) do { wraplen++; } while (*str++); if (s->gzhead->hcrc) wraplen += 2; } break; #endif default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + wraplen; /* default settings: return tight bound for that case -- ~0.03% overhead plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ local void putShortMSB(deflate_state *s, uInt b) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output, except for * some deflate_stored() output, goes through this function so some * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ local void flush_pending(z_streamp strm) { unsigned len; deflate_state *s = strm->state; _tr_flush_bits(s); len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len; s->pending_out += len; strm->total_out += len; strm->avail_out -= len; s->pending -= len; if (s->pending == 0) { s->pending_out = s->pending_buf; } } /* =========================================================================== * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. */ #define HCRC_UPDATE(beg) \ do { \ if (s->gzhead->hcrc && s->pending > (beg)) \ strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ s->pending - (beg)); \ } while (0) /* ========================================================================= */ int ZEXPORT deflate(z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->avail_in != 0 && strm->next_in == Z_NULL) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); old_flush = s->last_flush; s->last_flush = flush; /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s->last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Write the header */ if (s->status == INIT_STATE && s->wrap == 0) s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) level_flags = 2; else level_flags = 3; header |= (level_flags << 6); if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s->strstart != 0) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } strm->adler = adler32(0L, Z_NULL, 0); s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } #ifdef GZIP if (s->status == GZIP_STATE) { /* gzip header */ strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (s->gzhead == Z_NULL) { put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + (s->gzhead->extra == Z_NULL ? 0 : 4) + (s->gzhead->name == Z_NULL ? 0 : 8) + (s->gzhead->comment == Z_NULL ? 0 : 16) ); put_byte(s, (Byte)(s->gzhead->time & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) { put_byte(s, s->gzhead->extra_len & 0xff); put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); } if (s->gzhead->hcrc) strm->adler = crc32(strm->adler, s->pending_buf, s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; while (s->pending + left > s->pending_buf_size) { uInt copy = s->pending_buf_size - s->pending; zmemcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, copy); s->pending = s->pending_buf_size; HCRC_UPDATE(beg); s->gzindex += copy; flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; left -= copy; } zmemcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, left); s->pending += left; HCRC_UPDATE(beg); s->gzindex = 0; } s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { HCRC_UPDATE(beg); flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); HCRC_UPDATE(beg); s->gzindex = 0; } s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { HCRC_UPDATE(beg); flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); HCRC_UPDATE(beg); } s->status = HCRC_STATE; } if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) { flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); strm->adler = crc32(0L, Z_NULL, 0); } s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } #endif /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; bstate = s->level == 0 ? deflate_stored(s, flush) : s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; s->insert = 0; } } } flush_pending(strm); if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); put_byte(s, (Byte)(strm->total_in & 0xff)); put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); } else #endif { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int ZEXPORT deflateEnd(z_streamp strm) { int status; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; status = strm->state->status; /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { #ifdef MAXSEG_64K (void)dest; (void)source; return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; if (deflateStateCheck(source) || dest == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS); if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); #ifdef LIT_MEM ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1)); ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2); #else ds->sym_buf = ds->pending_buf + ds->lit_bufsize; #endif ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ local uInt longest_match(deflate_state *s, IPos cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = (int)s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan + best_len - 1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len - 1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match + best_len - 1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart + 3, + 5, up to strstart + 257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && *(ushf*)(scan += 2) == *(ushf*)(match += 2) && *(ushf*)(scan += 2) == *(ushf*)(match += 2) && *(ushf*)(scan += 2) == *(ushf*)(match += 2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window + strstart + 257 */ Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend - scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len - 1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan + best_len - 1); #else scan_end1 = scan[best_len - 1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ local uInt longest_match(deflate_state *s, IPos cur_match) { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef ZLIB_DEBUG #define EQUAL 0 /* result of memcmp for equal strings */ /* =========================================================================== * Check that the match at match_start is indeed a match. */ local void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ Bytef *back = s->window + (int)match, *here = s->window + start; IPos len = length; if (match == (IPos)-1) { /* match starts one byte before the current window -- just compare the subsequent length-1 bytes */ back++; here++; len--; } if (zmemcmp(back, here, len) != EQUAL) { fprintf(stderr, " start %u, match %d, length %d\n", start, (int)match, length); do { fprintf(stderr, "(%02x %02x)", *back++, *here++); } while (--len != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* ZLIB_DEBUG */ /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ (ulg)((long)s->strstart - s->block_start), \ (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \ FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } /* Maximum stored block length in deflate format (not including header). */ #define MAX_STORED 65535 /* Minimum of a and b. */ #define MIN(a, b) ((a) > (b) ? (b) : (a)) /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * * In case deflateParams() is used to later switch to a non-zero compression * level, s->matches (otherwise unused when storing) keeps track of the number * of hash table slides to perform. If s->matches is 1, then one hash table * slide will be done when switching. If s->matches is 2, the maximum value * allowed here, then the hash table will be cleared, since two or more slides * is the same as a clear. * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which * maximizes the opportunities to have a single copy from next_in to next_out. */ local block_state deflate_stored(deflate_state *s, int flush) { /* Smallest worthy block size when not flushing or finishing. By default * this is 32K. This can be as small as 507 bytes for memLevel == 1. For * large input and output buffers, the stored block size will be larger. */ unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); /* Copy as many min_block or larger stored blocks directly to next_out as * possible. If flushing, copy the remaining available input to next_out as * stored blocks, if there is enough space. */ unsigned len, left, have, last = 0; unsigned used = s->strm->avail_in; do { /* Set len to the maximum size block that we can copy directly with the * available input data and output space. Set left to how much of that * would be copied from what's left in the window. */ len = MAX_STORED; /* maximum deflate stored block length */ have = (s->bi_valid + 42) >> 3; /* number of header bytes */ if (s->strm->avail_out < have) /* need room for header */ break; /* maximum stored block length that will fit in avail_out: */ have = s->strm->avail_out - have; left = s->strstart - s->block_start; /* bytes left in window */ if (len > (ulg)left + s->strm->avail_in) len = left + s->strm->avail_in; /* limit len to the input */ if (len > have) len = have; /* limit len to the output */ /* If the stored block would be less than min_block in length, or if * unable to copy all of the available input when flushing, then try * copying to the window and the pending buffer instead. Also don't * write an empty block when flushing -- deflate() does that. */ if (len < min_block && ((len == 0 && flush != Z_FINISH) || flush == Z_NO_FLUSH || len != left + s->strm->avail_in)) break; /* Make a dummy stored block in pending to get the header bytes, * including any pending bits. This also updates the debugging counts. */ last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; _tr_stored_block(s, (char *)0, 0L, last); /* Replace the lengths in the dummy stored block with len. */ s->pending_buf[s->pending - 4] = len; s->pending_buf[s->pending - 3] = len >> 8; s->pending_buf[s->pending - 2] = ~len; s->pending_buf[s->pending - 1] = ~len >> 8; /* Write the stored block header bytes. */ flush_pending(s->strm); #ifdef ZLIB_DEBUG /* Update debugging counts for the data about to be copied. */ s->compressed_len += len << 3; s->bits_sent += len << 3; #endif /* Copy uncompressed bytes from the window to next_out. */ if (left) { if (left > len) left = len; zmemcpy(s->strm->next_out, s->window + s->block_start, left); s->strm->next_out += left; s->strm->avail_out -= left; s->strm->total_out += left; s->block_start += left; len -= left; } /* Copy uncompressed bytes directly from next_in to next_out, updating * the check value. */ if (len) { read_buf(s->strm, s->strm->next_out, len); s->strm->next_out += len; s->strm->avail_out -= len; s->strm->total_out += len; } } while (last == 0); /* Update the sliding window with the last s->w_size bytes of the copied * data, or append all of the copied data to the existing window if less * than s->w_size bytes were copied. Also update the number of bytes to * insert in the hash tables, in the event that deflateParams() switches to * a non-zero compression level. */ used -= s->strm->avail_in; /* number of input bytes directly copied */ if (used) { /* If any input was used, then no unused input remains in the window, * therefore s->block_start == s->strstart. */ if (used >= s->w_size) { /* supplant the previous history */ s->matches = 2; /* clear hash */ zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); s->strstart = s->w_size; s->insert = s->strstart; } else { if (s->window_size - s->strstart <= used) { /* Slide the window down. */ s->strstart -= s->w_size; zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ if (s->insert > s->strstart) s->insert = s->strstart; } zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); s->strstart += used; s->insert += MIN(used, s->w_size - s->insert); } s->block_start = s->strstart; } if (s->high_water < s->strstart) s->high_water = s->strstart; /* If the last block was written to next_out, then done. */ if (last) return finish_done; /* If flushing and all input has been consumed, then done. */ if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (long)s->strstart == s->block_start) return block_done; /* Fill the window with any remaining input. */ have = s->window_size - s->strstart; if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { /* Slide the window down. */ s->block_start -= s->w_size; s->strstart -= s->w_size; zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ have += s->w_size; /* more space now */ if (s->insert > s->strstart) s->insert = s->strstart; } if (have > s->strm->avail_in) have = s->strm->avail_in; if (have) { read_buf(s->strm, s->window + s->strstart, have); s->strstart += have; s->insert += MIN(have, s->w_size - s->insert); } if (s->high_water < s->strstart) s->high_water = s->strstart; /* There was not enough avail_out to write a complete worthy or flushed * stored block to next_out. Write a stored block to pending instead, if we * have enough input for a worthy block, or if flushing and there is enough * room for the remaining input as a stored block in the pending buffer. */ have = (s->bi_valid + 42) >> 3; /* number of header bytes */ /* maximum stored block length that will fit in pending: */ have = MIN(s->pending_buf_size - have, MAX_STORED); min_block = MIN(have, s->w_size); left = s->strstart - s->block_start; if (left >= min_block || ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && s->strm->avail_in == 0 && left <= have)) { len = MIN(left, have); last = flush == Z_FINISH && s->strm->avail_in == 0 && len == left ? 1 : 0; _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); s->block_start += len; flush_pending(s->strm); } /* We've done all we can with the available input and output. */ return last ? finish_started : need_more; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ local block_state deflate_fast(deflate_state *s, int flush) { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ local block_state deflate_slow(deflate_state *s, int flush) { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED #if TOO_FAR <= 32767 || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) #endif )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart - 1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart - 1])); _tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart - 1])); _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ local block_state deflate_rle(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest run, plus one for the unrolled loop. */ if (s->lookahead <= MAX_MATCH) { fill_window(s); if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* See how many times the previous byte repeats */ s->match_length = 0; if (s->lookahead >= MIN_MATCH && s->strstart > 0) { scan = s->window + s->strstart - 1; prev = *scan; if (prev == *++scan && prev == *++scan && prev == *++scan) { strend = s->window + s->strstart + MAX_MATCH; do { } while (prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (uInt)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } Assert(scan <= s->window + (uInt)(s->window_size - 1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ local block_state deflate_huff(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/deflate.h0000644000175100001660000003333114760300420016642 0ustar /* deflate.h -- internal compression state * Copyright (C) 1995-2024 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef DEFLATE_H #define DEFLATE_H #include "zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at the cost of a larger memory footprint */ /* #define LIT_MEM */ /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256 /* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30 /* number of distance codes */ #define BL_CODES 19 /* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ #define Buf_size 16 /* size of bit buffer in bi_buf */ #define INIT_STATE 42 /* zlib header -> BUSY_STATE */ #ifdef GZIP # define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ #endif #define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ #define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ #define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ #define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ #define BUSY_STATE 113 /* deflate -> FINISH_STATE */ #define FINISH_STATE 666 /* stream complete */ /* Stream status */ /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } FAR ct_data; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ const static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; typedef Pos FAR Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to * save space in the various tables. IPos is used only for parameter passing. */ typedef struct internal_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ ulg pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ ulg gzindex; /* where in extra, name, or comment */ Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Posf *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ struct tree_desc_s l_desc; /* desc. for literal tree */ struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ #ifdef LIT_MEM # define LIT_BUFS 5 ushf *d_buf; /* buffer for distances */ uchf *l_buf; /* buffer for literals/lengths */ #else # define LIT_BUFS 4 uchf *sym_buf; /* buffer for distances and literals/lengths */ #endif uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt sym_next; /* running index in symbol buffer */ uInt sym_end; /* symbol table full when sym_next reaches this */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ #ifdef ZLIB_DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ ulg high_water; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ #define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. * See deflate.c for comments about the MIN_MATCH+1. */ #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void ZLIB_INTERNAL _tr_init(deflate_state *s); int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc); void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, ulg stored_len, int last); void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s); void ZLIB_INTERNAL _tr_align(deflate_state *s); void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, ulg stored_len, int last); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef ZLIB_DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) extern uch ZLIB_INTERNAL _length_code[]; extern uch ZLIB_INTERNAL _dist_code[]; #else extern const uch ZLIB_INTERNAL _length_code[]; extern const uch ZLIB_INTERNAL _dist_code[]; #endif #ifdef LIT_MEM # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->d_buf[s->sym_next] = 0; \ s->l_buf[s->sym_next++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->sym_next == s->sym_end); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ s->d_buf[s->sym_next] = dist; \ s->l_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->sym_next == s->sym_end); \ } #else # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->sym_buf[s->sym_next++] = 0; \ s->sym_buf[s->sym_next++] = 0; \ s->sym_buf[s->sym_next++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->sym_next == s->sym_end); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ s->sym_buf[s->sym_next++] = (uch)dist; \ s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ s->sym_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->sym_next == s->sym_end); \ } #endif #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/gzclose.c0000644000175100001660000000123414760300420016674 0ustar /* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ int ZEXPORT gzclose(gzFile file) { #ifndef NO_GZCOMPRESS gz_statep state; if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); #else return gzclose_r(file); #endif } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/gzguts.h0000644000175100001660000001502414760300420016560 0ustar /* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004-2024 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #ifdef _LARGEFILE64_SOURCE # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif # undef _FILE_OFFSET_BITS # undef _TIME_BITS #endif #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include #include "zlib.h" #ifdef STDC # include # include # include #endif #ifndef _POSIX_SOURCE # define _POSIX_SOURCE #endif #include #ifdef _WIN32 # include #endif #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include #endif #if defined(_WIN32) # define WIDECHAR #endif #ifdef WINAPI_FAMILY # define open _open # define read _read # define write _write # define close _close #endif #ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif #if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(__CYGWIN__) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #ifndef HAVE_VSNPRINTF # ifdef MSDOS /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), but for now we just assume it doesn't. */ # define NO_vsnprintf # endif # ifdef __TURBOC__ # define NO_vsnprintf # endif # ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ # if !defined(vsnprintf) && !defined(NO_vsnprintf) # if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) # define vsnprintf _vsnprintf # endif # endif # endif # ifdef __SASC # define NO_vsnprintf # endif # ifdef VMS # define NO_vsnprintf # endif # ifdef __OS400__ # define NO_vsnprintf # endif # ifdef __MVS__ # define NO_vsnprintf # endif #endif /* unlike snprintf (which is required in C99), _snprintf does not guarantee null termination of the result -- however this is only used in gzlib.c where the result is assured to fit in the space provided */ #if defined(_MSC_VER) && _MSC_VER < 1900 # define snprintf _snprintf #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ /* gz* functions always use library allocation functions */ #ifndef STDC extern voidp malloc(uInt size); extern void free(voidpf ptr); #endif /* get errno and strerror definition */ #if defined UNDER_CE # include # define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else # ifndef NO_STRERROR # include # define zstrerror() strerror(errno) # else # define zstrerror() "stdio error (consult errno)" # endif #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); #endif /* default memLevel */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default i/o buffer size -- double this for output when reading (this and twice this must be able to fit in an unsigned type) */ #define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 #define GZ_READ 7247 #define GZ_WRITE 31153 #define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ /* values for gz_state how */ #define LOOK 0 /* look for a gzip header */ #define COPY 1 /* copy input directly */ #define GZIP 2 /* decompress a gzip stream */ /* internal gzip file state data structure */ typedef struct { /* exposed contents for gzgetc() macro */ struct gzFile_s x; /* "x" for exposed */ /* x.have: number of bytes available at x.next */ /* x.next: next output data to deliver or write */ /* x.pos: current position in uncompressed data */ /* used for both reading and writing */ int mode; /* see gzip modes above */ int fd; /* file descriptor */ char *path; /* path or fd for error messages */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer (double-sized when writing) */ unsigned char *out; /* output buffer (double-sized when reading) */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ int how; /* 0: get header, 1: copy, 2: decompress */ z_off64_t start; /* where the gzip data started, for rewinding */ int eof; /* true if end of input file reached */ int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ int reset; /* true if a reset is pending after a Z_FINISH */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ /* error information */ int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; typedef gz_state FAR *gz_statep; /* shared functions */ void ZLIB_INTERNAL gz_error(gz_statep, int, const char *); #if defined UNDER_CE char ZLIB_INTERNAL *gz_strwinerror(DWORD error); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ unsigned ZLIB_INTERNAL gz_intmax(void); #define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/gzlib.c0000644000175100001660000003761614760300420016352 0ustar /* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004-2024 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" #if defined(_WIN32) && !defined(__BORLANDC__) # define LSEEK _lseeki64 #else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif #endif #if defined UNDER_CE /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to gz_strwinerror The gz_strwinerror function does not change the current setting of GetLastError. */ char ZLIB_INTERNAL *gz_strwinerror(DWORD error) { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, 0, /* Default language */ (LPVOID)&msgbuf, 0, NULL); if (chars != 0) { /* If there is an \r\n appended, zap it. */ if (chars >= 2 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { chars -= 2; msgbuf[chars] = 0; } if (chars > sizeof (buf) - 1) { chars = sizeof (buf) - 1; msgbuf[chars] = 0; } wcstombs(buf, msgbuf, chars + 1); LocalFree(msgbuf); } else { sprintf(buf, "unknown win32 error (%ld)", error); } SetLastError(lasterr); return buf; } #endif /* UNDER_CE */ /* Reset gzip file state */ local void gz_reset(gz_statep state) { state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ } else /* for writing ... */ state->reset = 0; /* no deflateReset pending */ state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ local gzFile gz_open(const void *path, int fd, const char *mode) { gz_statep state; z_size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; #endif #ifdef O_EXCL int exclusive = 0; #endif /* check input */ if (path == NULL) return NULL; /* allocate gzFile structure to return */ state = (gz_statep)malloc(sizeof(gz_state)); if (state == NULL) return NULL; state->size = 0; /* no buffers allocated yet */ state->want = GZBUFSIZE; /* requested buffer size */ state->msg = NULL; /* no error message yet */ /* interpret mode */ state->mode = GZ_NONE; state->level = Z_DEFAULT_COMPRESSION; state->strategy = Z_DEFAULT_STRATEGY; state->direct = 0; while (*mode) { if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; else switch (*mode) { case 'r': state->mode = GZ_READ; break; #ifndef NO_GZCOMPRESS case 'w': state->mode = GZ_WRITE; break; case 'a': state->mode = GZ_APPEND; break; #endif case '+': /* can't read and write at the same time */ free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; #ifdef O_CLOEXEC case 'e': cloexec = 1; break; #endif #ifdef O_EXCL case 'x': exclusive = 1; break; #endif case 'f': state->strategy = Z_FILTERED; break; case 'h': state->strategy = Z_HUFFMAN_ONLY; break; case 'R': state->strategy = Z_RLE; break; case 'F': state->strategy = Z_FIXED; break; case 'T': state->direct = 1; break; default: /* could consider as an error, but just ignore */ ; } mode++; } /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { free(state); return NULL; } /* can't force transparent read */ if (state->mode == GZ_READ) { if (state->direct) { free(state); return NULL; } state->direct = 1; /* for empty file */ } /* save the path name for error messages */ #ifdef WIDECHAR if (fd == -2) { len = wcstombs(NULL, path, 0); if (len == (z_size_t)-1) len = 0; } else #endif len = strlen((const char *)path); state->path = (char *)malloc(len + 1); if (state->path == NULL) { free(state); return NULL; } #ifdef WIDECHAR if (fd == -2) if (len) wcstombs(state->path, path, len + 1); else *(state->path) = 0; else #endif #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(state->path, len + 1, "%s", (const char *)path); #else strcpy(state->path, path); #endif /* compute the flags for open() */ oflag = #ifdef O_LARGEFILE O_LARGEFILE | #endif #ifdef O_BINARY O_BINARY | #endif #ifdef O_CLOEXEC (cloexec ? O_CLOEXEC : 0) | #endif (state->mode == GZ_READ ? O_RDONLY : (O_WRONLY | O_CREAT | #ifdef O_EXCL (exclusive ? O_EXCL : 0) | #endif (state->mode == GZ_WRITE ? O_TRUNC : O_APPEND))); /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( #ifdef WIDECHAR fd == -2 ? _wopen(path, oflag, 0666) : #endif open((const char *)path, oflag, 0666)); if (state->fd == -1) { free(state->path); free(state); return NULL; } if (state->mode == GZ_APPEND) { LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ state->mode = GZ_WRITE; /* simplify later checks */ } /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { state->start = LSEEK(state->fd, 0, SEEK_CUR); if (state->start == -1) state->start = 0; } /* initialize stream */ gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen(const char *path, const char *mode) { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen64(const char *path, const char *mode) { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzdopen(int fd, const char *mode) { char *path; /* identifier for error messages */ gzFile gz; if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); #else sprintf(path, "", fd); /* for debugging */ #endif gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ #ifdef WIDECHAR gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) { return gz_open(path, -2, mode); } #endif /* -- see zlib.h -- */ int ZEXPORT gzbuffer(gzFile file, unsigned size) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* make sure we haven't already allocated memory */ if (state->size != 0) return -1; /* check and set requested size */ if ((size << 1) < size) return -1; /* need to be able to double it */ if (size < 8) size = 8; /* needed to behave well with flushing */ state->want = size; return 0; } /* -- see zlib.h -- */ int ZEXPORT gzrewind(gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ if (LSEEK(state->fd, state->start, SEEK_SET) == -1) return -1; gz_reset(state); return 0; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) { unsigned n; z_off64_t ret; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* check that there's no error */ if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* can only seek from start or relative to current position */ if (whence != SEEK_SET && whence != SEEK_CUR) return -1; /* normalize offset to a SEEK_CUR specification */ if (whence == SEEK_SET) offset -= state->x.pos; else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; state->eof = 0; state->past = 0; state->seek = 0; gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; state->x.pos += offset; return state->x.pos; } /* calculate skip amount, rewinding if needed for back seek when reading */ if (offset < 0) { if (state->mode != GZ_READ) /* writing -- can't go backwards */ return -1; offset += state->x.pos; if (offset < 0) /* before start of file! */ return -1; if (gzrewind(file) == -1) /* rewind, then skip to offset */ return -1; } /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; offset -= n; } /* request skip (if not zero) */ if (offset) { state->seek = 1; state->skip = offset; } return state->x.pos + offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gztell64(gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* return position */ return state->x.pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ z_off_t ZEXPORT gztell(gzFile file) { z_off64_t ret; ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzoffset64(gzFile file) { z_off64_t offset; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* compute and return effective offset in file */ offset = LSEEK(state->fd, 0, SEEK_CUR); if (offset == -1) return -1; if (state->mode == GZ_READ) /* reading */ offset -= state->strm.avail_in; /* don't count buffered input */ return offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzoffset(gzFile file) { z_off64_t ret; ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ int ZEXPORT gzeof(gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; /* return end-of-file state */ return state->mode == GZ_READ ? state->past : 0; } /* -- see zlib.h -- */ const char * ZEXPORT gzerror(gzFile file, int *errnum) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); } /* -- see zlib.h -- */ void ZEXPORT gzclearerr(gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return; /* clear error and end-of-file */ if (state->mode == GZ_READ) { state->eof = 0; state->past = 0; } gz_error(state, Z_OK, NULL); } /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) free(state->msg); state->msg = NULL; } /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ if (err != Z_OK && err != Z_BUF_ERROR) state->x.have = 0; /* set error code, and if no message, then done */ state->err = err; if (msg == NULL) return; /* for an out of memory error, return literal string when requested */ if (err == Z_MEM_ERROR) return; /* construct error message with path */ if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { state->err = Z_MEM_ERROR; return; } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif } /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ unsigned ZLIB_INTERNAL gz_intmax(void) { #ifdef INT_MAX return INT_MAX; #else unsigned p = 1, q; do { q = p; p <<= 1; p++; } while (p > q); return q >> 1; #endif } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/gzread.c0000644000175100001660000004671614760300420016520 0ustar /* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ local int gz_load(gz_statep state, unsigned char *buf, unsigned len, unsigned *have) { int ret; unsigned get, max = ((unsigned)-1 >> 2) + 1; *have = 0; do { get = len - *have; if (get > max) get = max; ret = read(state->fd, buf + *have, get); if (ret <= 0) break; *have += (unsigned)ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (ret == 0) state->eof = 1; return 0; } /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ local int gz_avail(gz_statep state) { unsigned got; z_streamp strm = &(state->strm); if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; if (state->eof == 0) { if (strm->avail_in) { /* copy what's there to the start */ unsigned char *p = state->in; unsigned const char *q = strm->next_in; unsigned n = strm->avail_in; do { *p++ = *q++; } while (--n); } if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1) return -1; strm->avail_in += got; strm->next_in = state->in; } return 0; } /* Look for gzip header, set up for inflate or copy. state->x.have must be 0. If this is the first time in, allocate required memory. state->how will be left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ local int gz_look(gz_statep state) { z_streamp strm = &(state->strm); /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ state->in = (unsigned char *)malloc(state->want); state->out = (unsigned char *)malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } state->size = state->want; /* allocate inflate memory */ state->strm.zalloc = Z_NULL; state->strm.zfree = Z_NULL; state->strm.opaque = Z_NULL; state->strm.avail_in = 0; state->strm.next_in = Z_NULL; if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ free(state->out); free(state->in); state->size = 0; gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* get at least the magic bytes in the input buffer */ if (strm->avail_in < 2) { if (gz_avail(state) == -1) return -1; if (strm->avail_in == 0) return 0; } /* look for gzip magic bytes -- if there, do gzip decoding (note: there is a logical dilemma here when considering the case of a partially written gzip file, to wit, if a single 31 byte is written, then we cannot tell whether this is a single-byte file, or just a partially written gzip file -- for here we assume that if a gzip file is being written, then the header will be written in a single operation, so that reading a single byte is sufficient indication that it is not a gzip file) */ if (strm->avail_in > 1 && strm->next_in[0] == 31 && strm->next_in[1] == 139) { inflateReset(strm); state->how = GZIP; state->direct = 0; return 0; } /* no gzip header -- if we were decoding gzip before, then this is trailing garbage. Ignore the trailing garbage and finish. */ if (state->direct == 0) { strm->avail_in = 0; state->eof = 1; state->x.have = 0; return 0; } /* doing raw i/o, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; memcpy(state->x.next, strm->next_in, strm->avail_in); state->x.have = strm->avail_in; strm->avail_in = 0; state->how = COPY; state->direct = 1; return 0; } /* Decompress from input to the provided next_out and avail_out in the state. On return, state->x.have and state->x.next point to the just decompressed data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ local int gz_decomp(gz_statep state) { int ret = Z_OK; unsigned had; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; do { /* get more input for inflate() */ if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { gz_error(state, Z_BUF_ERROR, "unexpected end of file"); break; } /* decompress and handle errors */ ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { gz_error(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ gz_error(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); /* update available output */ state->x.have = had - strm->avail_out; state->x.next = strm->next_out - state->x.have; /* if the gzip stream completed successfully, look for another */ if (ret == Z_STREAM_END) state->how = LOOK; /* good decompression */ return 0; } /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ local int gz_fetch(gz_statep state) { z_streamp strm = &(state->strm); do { switch(state->how) { case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ if (gz_look(state) == -1) return -1; if (state->how == LOOK) return 0; break; case COPY: /* -> COPY */ if (gz_load(state, state->out, state->size << 1, &(state->x.have)) == -1) return -1; state->x.next = state->out; return 0; case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ strm->avail_out = state->size << 1; strm->next_out = state->out; if (gz_decomp(state) == -1) return -1; } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ local int gz_skip(gz_statep state, z_off64_t len) { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ if (state->x.have) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? (unsigned)len : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; len -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) break; /* need more data to skip -- load up output buffer */ else { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; } return 0; } /* Read len bytes into buf from file, or less than len up to the end of the input. Return the number of bytes read. If zero is returned, either the end of file was reached, or there was an error. state->err must be consulted in that case to determine which. */ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { z_size_t got; unsigned n; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return 0; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* set n to the maximum amount of len that fits in an unsigned int */ n = (unsigned)-1; if (n > len) n = (unsigned)len; /* first just try copying data from the output buffer */ if (state->x.have) { if (state->x.have < n) n = state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) { state->past = 1; /* tried to read past end */ break; } /* need output data -- for small len or new stream load up our output buffer */ else if (state->how == LOOK || n < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return 0; continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ } /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ if (gz_load(state, (unsigned char *)buf, n, &n) == -1) return 0; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ state->strm.avail_out = n; state->strm.next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) return 0; n = state->x.have; state->x.have = 0; } /* update progress */ len -= n; buf = (char *)buf + n; got += n; state->x.pos += n; } while (len); /* return number of bytes read into user buffer */ return got; } /* -- see zlib.h -- */ int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); return -1; } /* read len or fewer bytes to buf */ len = (unsigned)gz_read(state, buf, len); /* check for an error */ if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* return the number of bytes read (this is assured to fit in an int) */ return (int)len; } /* -- see zlib.h -- */ z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) { z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return 0; /* compute bytes to read -- error on overflow */ len = nitems * size; if (size && len / size != nitems) { gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); return 0; } /* read len or fewer bytes to buf, return the number of full items read */ return len ? gz_read(state, buf, len) / size : 0; } /* -- see zlib.h -- */ #ifdef Z_PREFIX_SET # undef z_gzgetc #else # undef gzgetc #endif int ZEXPORT gzgetc(gzFile file) { unsigned char buf[1]; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* try output buffer (no need to check for skip request) */ if (state->x.have) { state->x.have--; state->x.pos++; return *(state->x.next)++; } /* nothing there -- try gz_read() */ return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; } int ZEXPORT gzgetc_(gzFile file) { return gzgetc(file); } /* -- see zlib.h -- */ int ZEXPORT gzungetc(int c, gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* in case this was just opened, set up the input buffer */ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) (void)gz_look(state); /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* can't push EOF */ if (c < 0) return -1; /* if output buffer empty, put byte at end (allows more pushing) */ if (state->x.have == 0) { state->x.have = 1; state->x.next = state->out + (state->size << 1) - 1; state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; } /* if no room, give up (must have already done a gzungetc()) */ if (state->x.have == (state->size << 1)) { gz_error(state, Z_DATA_ERROR, "out of room to push characters"); return -1; } /* slide output data if needed and insert byte before existing data */ if (state->x.next == state->out) { unsigned char *src = state->out + state->x.have; unsigned char *dest = state->out + (state->size << 1); while (src > state->out) *--dest = *--src; state->x.next = dest; } state->x.have++; state->x.next--; state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; } /* -- see zlib.h -- */ char * ZEXPORT gzgets(gzFile file, char *buf, int len) { unsigned left, n; char *str; unsigned char *eol; gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) return NULL; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return NULL; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return NULL; } /* copy output bytes up to new line or len - 1, whichever comes first -- append a terminating zero to the string (we don't check for a zero in the contents, let the user worry about that) */ str = buf; left = (unsigned)len - 1; if (left) do { /* assure that something is in the output buffer */ if (state->x.have == 0 && gz_fetch(state) == -1) return NULL; /* error */ if (state->x.have == 0) { /* end of file */ state->past = 1; /* read past end */ break; /* return what we have */ } /* look for end-of-line in current output buffer */ n = state->x.have > left ? left : state->x.have; eol = (unsigned char *)memchr(state->x.next, '\n', n); if (eol != NULL) n = (unsigned)(eol - state->x.next) + 1; /* copy through end-of-line, or remainder if not found */ memcpy(buf, state->x.next, n); state->x.have -= n; state->x.next += n; state->x.pos += n; left -= n; buf += n; } while (left && eol == NULL); /* return terminated string, or if nothing, end of file */ if (buf == str) return NULL; buf[0] = 0; return str; } /* -- see zlib.h -- */ int ZEXPORT gzdirect(gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) (void)gz_look(state); /* return 1 if transparent, 0 if processing a gzip stream */ return state->direct; } /* -- see zlib.h -- */ int ZEXPORT gzclose_r(gzFile file) { int ret, err; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) return Z_STREAM_ERROR; /* free memory and close file */ if (state->size) { inflateEnd(&(state->strm)); free(state->out); free(state->in); } err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); free(state); return ret ? Z_ERRNO : err; } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/gzwrite.c0000644000175100001660000004544514760300420016735 0ustar /* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on a memory allocation failure, or 0 on success. */ local int gz_init(gz_statep state) { int ret; z_streamp strm = &(state->strm); /* allocate input buffer (double size for gzprintf) */ state->in = (unsigned char *)malloc(state->want << 1); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* only need output buffer and deflate state if compressing */ if (!state->direct) { /* allocate output buffer */ state->out = (unsigned char *)malloc(state->want); if (state->out == NULL) { free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* allocate deflate memory, set up for gzip compression */ strm->zalloc = Z_NULL; strm->zfree = Z_NULL; strm->opaque = Z_NULL; ret = deflateInit2(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); if (ret != Z_OK) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } strm->next_in = NULL; } /* mark state as initialized */ state->size = state->want; /* initialize write buffer if compressing */ if (!state->direct) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = strm->next_out; } return 0; } /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file or if gz_init() fails to allocate memory, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ local int gz_comp(gz_statep state, int flush) { int ret, writ; unsigned have, put, max = ((unsigned)-1 >> 2) + 1; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return -1; /* write directly if requested */ if (state->direct) { while (strm->avail_in) { put = strm->avail_in > max ? max : strm->avail_in; writ = write(state->fd, strm->next_in, put); if (writ < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } strm->avail_in -= (unsigned)writ; strm->next_in += writ; } return 0; } /* check for a pending reset */ if (state->reset) { /* don't start a new gzip member unless there is data to write */ if (strm->avail_in == 0) return 0; deflateReset(strm); state->reset = 0; } /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { while (strm->next_out > state->x.next) { put = strm->next_out - state->x.next > (int)max ? max : (unsigned)(strm->next_out - state->x.next); writ = write(state->fd, state->x.next, put); if (writ < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } state->x.next += writ; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = state->out; } } /* compress */ have = strm->avail_out; ret = deflate(strm, flush); if (ret == Z_STREAM_ERROR) { gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) state->reset = 1; /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on a write error or memory allocation failure by gz_comp(), or 0 on success. */ local int gz_zero(gz_statep state, z_off64_t len) { int first; unsigned n; z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return -1; /* compress len zeros (len guaranteed > 0) */ first = 1; while (len) { n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; if (first) { memset(state->in, 0, n); first = 0; } strm->avail_in = n; strm->next_in = state->in; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return -1; len -= n; } return 0; } /* Write len bytes from buf to file. Return the number of bytes written. If the returned value is less than len, then there was an error. */ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) { z_size_t put = len; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* for small len, copy to input buffer, otherwise compress directly */ if (len < state->size) { /* copy to input buffer, compress when full */ do { unsigned have, copy; if (state->strm.avail_in == 0) state->strm.next_in = state->in; have = (unsigned)((state->strm.next_in + state->strm.avail_in) - state->in); copy = state->size - have; if (copy > len) copy = (unsigned)len; memcpy(state->in + have, buf, copy); state->strm.avail_in += copy; state->x.pos += copy; buf = (const char *)buf + copy; len -= copy; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); } else { /* consume whatever's left in the input buffer */ if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ state->strm.next_in = (z_const Bytef *)buf; do { unsigned n = (unsigned)-1; if (n > len) n = (unsigned)len; state->strm.avail_in = n; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; len -= n; } while (len); } /* input was all buffered or compressed */ return put; } /* -- see zlib.h -- */ int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } /* write len bytes from buf (the return value will fit in an int) */ return (int)gz_write(state, buf, len); } /* -- see zlib.h -- */ z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems, gzFile file) { z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* compute bytes to read -- error on overflow */ len = nitems * size; if (size && len / size != nitems) { gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); return 0; } /* write len bytes to buf, return the number of full items written */ return len ? gz_write(state, buf, len) / size : 0; } /* -- see zlib.h -- */ int ZEXPORT gzputc(gzFile file, int c) { unsigned have; unsigned char buf[1]; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* try writing to input buffer for speed (state->size == 0 if buffer not initialized) */ if (state->size) { if (strm->avail_in == 0) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); if (have < state->size) { state->in[have] = (unsigned char)c; strm->avail_in++; state->x.pos++; return c & 0xff; } } /* no room in buffer or not initialized, use gz_write() */ buf[0] = (unsigned char)c; if (gz_write(state, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ int ZEXPORT gzputs(gzFile file, const char *s) { z_size_t len, put; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* write string */ len = strlen(s); if ((int)len < 0 || (unsigned)len != len) { gz_error(state, Z_STREAM_ERROR, "string length does not fit in int"); return -1; } put = gz_write(state, s, len); return put < len ? -1 : (int)len; } #if defined(STDC) || defined(Z_HAVE_STDARG_H) #include /* -- see zlib.h -- */ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { int len; unsigned left; char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return state->err; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* do the printf() into the input buffer, put length in len -- the input buffer is double-sized just for this function, so there is guaranteed to be state->size bytes available after the current contents */ if (strm->avail_in == 0) strm->next_in = state->in; next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); next[state->size - 1] = 0; #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void (void)vsprintf(next, format, va); for (len = 0; len < state->size; len++) if (next[len] == 0) break; # else len = vsprintf(next, format, va); # endif #else # ifdef HAS_vsnprintf_void (void)vsnprintf(next, state->size, format, va); len = strlen(next); # else len = vsnprintf(next, state->size, format, va); # endif #endif /* check that printf() results fit in buffer */ if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) return 0; /* update buffer and position, compress first half if past that */ strm->avail_in += (unsigned)len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; memmove(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return len; } int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { va_list va; int ret; va_start(va, format); ret = gzvprintf(file, format, va); va_end(va); return ret; } #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20) { unsigned len, left; char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that can really pass pointer in ints */ if (sizeof(int) != sizeof(void *)) return Z_STREAM_ERROR; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return state->error; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->error; } /* do the printf() into the input buffer, put length in len -- the input buffer is double-sized just for this function, so there is guaranteed to be state->size bytes available after the current contents */ if (strm->avail_in == 0) strm->next_in = state->in; next = (char *)(strm->next_in + strm->avail_in); next[state->size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) if (next[len] == 0) break; # else len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen(next); # else len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif /* check that printf() results fit in buffer */ if (len == 0 || len >= state->size || next[state->size - 1] != 0) return 0; /* update buffer and position, compress first half if past that */ strm->avail_in += len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; memmove(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return (int)len; } #endif /* -- see zlib.h -- */ int ZEXPORT gzflush(gzFile file, int flush) { gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* check flush parameter */ if (flush < 0 || flush > Z_FINISH) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* compress remaining data with requested flush */ (void)gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ int ZEXPORT gzsetparams(gzFile file, int level, int strategy) { gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ if (level == state->level && strategy == state->strategy) return Z_OK; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) return state->err; deflateParams(strm, level, strategy); } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ int ZEXPORT gzclose_w(gzFile file) { int ret = Z_OK; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing */ if (state->mode != GZ_WRITE) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) ret = state->err; } /* flush, free memory, and close file */ if (gz_comp(state, Z_FINISH) == -1) ret = state->err; if (state->size) { if (!state->direct) { (void)deflateEnd(&(state->strm)); free(state->out); } free(state->in); } gz_error(state, Z_OK, NULL); free(state->path); if (close(state->fd) == -1) ret = Z_ERRNO; free(state); return ret; } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/infback.c0000644000175100001660000005421514760300420016632 0ustar /* infback.c -- inflate using a call-back interface * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* This code is largely copied from inflate.c. Normally either infback.o or inflate.o would be linked into an application--not both. The interface with inffast.c is retained so that optimized assembler-coded versions of inflate_fast() can be used with either inflate.c or infback.c. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size) { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL || window == Z_NULL || windowBits < 8 || windowBits > 15) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; state->sane = 1; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } /* Macros for inflateBack(): */ /* Load returned state from inflate_fast() */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Set state from registers for inflate_fast() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Assure that some input is available. If input is requested, but denied, then return a Z_BUF_ERROR from inflateBack(). */ #define PULL() \ do { \ if (have == 0) { \ have = in(in_desc, &next); \ if (have == 0) { \ next = Z_NULL; \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflateBack() with an error if there is no input available. */ #define PULLBYTE() \ do { \ PULL(); \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflateBack() with an error. */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* Assure that some output space is available, by writing out the window if it's full. If the write fails, return from inflateBack() with a Z_BUF_ERROR. */ #define ROOM() \ do { \ if (left == 0) { \ put = state->window; \ left = state->wsize; \ state->whave = left; \ if (out(out_desc, put, left)) { \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* strm provides the memory allocation functions and window buffer on input, and provides information on the unused input on return. For Z_DATA_ERROR returns, strm will also provide an error message. in() and out() are the call-back input and output functions. When inflateBack() needs more input, it calls in(). When inflateBack() has filled the window with output, or when it completes with data in the window, it calls out() to write out the data. The application must not change the provided input until in() is called again or inflateBack() returns. The application must not change the window/output buffer until inflateBack() returns. in() and out() are called with a descriptor parameter provided in the inflateBack() call. This parameter can be a structure that provides the information required to do the read or write, as well as accumulated information on the input and output such as totals and check values. in() should return zero on failure. out() should return non-zero on failure. If either in() or out() fails, than inflateBack() returns a Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* Check that the strm exists and that the state was initialized */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* Reset the state */ strm->msg = Z_NULL; state->mode = TYPE; state->last = 0; state->whave = 0; next = strm->next_in; have = next != Z_NULL ? strm->avail_in : 0; hold = 0; bits = 0; put = state->window; left = state->wsize; /* Inflate until end of block marked as last */ for (;;) switch (state->mode) { case TYPE: /* determine and dispatch block type */ if (state->last) { BYTEBITS(); state->mode = DONE; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN; /* decode codes */ break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: /* get and verify stored block length */ BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); /* copy stored block from input to output */ while (state->length != 0) { copy = state->length; PULL(); ROOM(); if (copy > have) copy = have; if (copy > left) copy = left; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: /* get dynamic table entries descriptor */ NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); /* get code length code lengths (not a typo) */ state->have = 0; while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); /* get length and distance code code lengths */ state->have = 0; while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = (unsigned)(state->lens[state->have - 1]); copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; /* fallthrough */ case LEN: /* use inflate_fast() if we have enough input and output */ if (have >= 6 && left >= 258) { RESTORE(); if (state->whave < state->wsize) state->whave = state->wsize - left; inflate_fast(strm, state->wsize); LOAD(); break; } /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); state->length = (unsigned)here.val; /* process literal */ if (here.op == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); ROOM(); *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; } /* process end of block */ if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } /* invalid code */ if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } /* length code -- get extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); } Tracevv((stderr, "inflate: length %u\n", state->length)); /* get distance code */ for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; /* get distance extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); } if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } Tracevv((stderr, "inflate: distance %u\n", state->offset)); /* copy match from window to output */ do { ROOM(); copy = state->wsize - state->offset; if (copy < left) { from = put + copy; copy = left - copy; } else { from = put - state->offset; copy = left; } if (copy > state->length) copy = state->length; state->length -= copy; left -= copy; do { *put++ = *from++; } while (--copy); } while (state->length != 0); break; case DONE: /* inflate stream terminated properly */ ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; default: /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } /* Write leftover output and return unused input */ inf_leave: if (left < state->wsize) { if (out(out_desc, state->window, state->wsize - left) && ret == Z_STREAM_END) ret = Z_BUF_ERROR; } strm->next_in = next; strm->avail_in = have; return ret; } int ZEXPORT inflateBackEnd(z_streamp strm) { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/inffast.c0000644000175100001660000003117414760300420016666 0ustar /* inffast.c -- fast decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef ASMINF # pragma message("Assembler code may have bugs -- use at your own risk") #else /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code const *here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in; last = in + (strm->avail_in - 5); out = strm->next_out; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = lcode + (hold & lmask); dolen: op = (unsigned)(here->bits); hold >>= op; bits -= op; op = (unsigned)(here->op); if (op == 0) { /* literal */ Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here->val)); *out++ = (unsigned char)(here->val); } else if (op & 16) { /* length base */ len = (unsigned)(here->val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = dcode + (hold & dmask); dodist: op = (unsigned)(here->bits); hold >>= op; bits -= op; op = (unsigned)(here->op); if (op & 16) { /* distance base */ dist = (unsigned)(here->val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { *out++ = 0; } while (--len); continue; } len -= op - whave; do { *out++ = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { *out++ = *from++; } while (--len); continue; } #endif } from = window; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { *out++ = *from++; } while (--op); from = window; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { *out++ = *from++; *out++ = *from++; *out++ = *from++; len -= 3; } if (len) { *out++ = *from++; if (len > 1) *out++ = *from++; } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ *out++ = *from++; *out++ = *from++; *out++ = *from++; len -= 3; } while (len > 2); if (len) { *out++ = *from++; if (len > 1) *out++ = *from++; } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode + here->val + (hold & ((1U << op) - 1)); goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode + here->val + (hold & ((1U << op) - 1)); goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in; strm->next_out = out; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ #endif /* !ASMINF */ mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/inffast.h0000644000175100001660000000064614760300420016673 0ustar /* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/inffixed.h0000644000175100001660000001427414760300420017037 0ustar /* inffixed.h -- table for decoding fixed codes * Generated automatically by makefixed(). */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of this library and is subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {0,9,255} }; static const code distfix[32] = { {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {22,5,193},{64,5,0} }; mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/inflate.c0000644000175100001660000015433714760300420016665 0ustar /* inflate.c -- zlib decompression * Copyright (C) 1995-2022 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif local int inflateStateCheck(z_streamp strm) { struct inflate_state FAR *state; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; state = (struct inflate_state FAR *)strm->state; if (state == Z_NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC) return 1; return 0; } int ZEXPORT inflateResetKeep(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->flags = -1; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; return inflateResetKeep(strm); } int ZEXPORT inflateReset2(z_streamp strm, int windowBits) { int wrap; struct inflate_state FAR *state; /* get the state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { if (windowBits < -15) return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 5; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, const char *version, int stream_size) { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->strm = strm; state->window = Z_NULL; state->mode = HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_(z_streamp strm, const char *version, int stream_size) { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; if (bits == 0) return Z_OK; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += (unsigned)value << state->bits; state->bits += (uInt)bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed(void) { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) { struct inflate_state FAR *state; unsigned dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char FAR *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ if (copy >= state->wsize) { zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, end - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE_CHECK(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate(z_streamp strm, int flush) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (inflateStateCheck(strm) || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ if (state->wbits == 0) state->wbits = 15; state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; if (len > 15 || len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; state->flags = 0; /* indicate zlib header */ Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = TIME; /* fallthrough */ case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC4(state->check, hold); INITBITS(); state->mode = OS; /* fallthrough */ case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; /* fallthrough */ case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; /* fallthrough */ case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL && (len = state->head->extra_len - state->length) < state->head->extra_max) { zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; /* fallthrough */ case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; /* fallthrough */ case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; /* fallthrough */ case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if ((state->wrap & 4) && hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; /* fallthrough */ case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; /* fallthrough */ case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; /* fallthrough */ case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; /* fallthrough */ case COPY_: state->mode = COPY; /* fallthrough */ case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; /* fallthrough */ case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; /* fallthrough */ case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (const code FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; /* fallthrough */ case LEN_: state->mode = LEN; /* fallthrough */ case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; /* fallthrough */ case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; /* fallthrough */ case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; /* fallthrough */ case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; /* fallthrough */ case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE_CHECK(state->check, put - out, out); out = left; if ((state->wrap & 4) && ( #ifdef GUNZIP state->flags ? hold : #endif ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; /* fallthrough */ case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; /* fallthrough */ case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: /* fallthrough */ default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (out != strm->avail_out && state->mode < BAD && (state->mode < CHECK || flush != Z_FINISH))) if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE_CHECK(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, uInt *dictLength) { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ if (state->whave && dictionary != Z_NULL) { zmemcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); zmemcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); } if (dictLength != Z_NULL) *dictLength = state->whave; return Z_OK; } int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength) { struct inflate_state FAR *state; unsigned long dictid; int ret; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary identifier */ if (state->mode == DICT) { dictid = adler32(0L, Z_NULL, 0); dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; } /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ ret = updatewindow(strm, dictionary + dictLength, dictLength); if (ret) { state->mode = MEM; return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, unsigned len) { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync(z_streamp strm) { unsigned len; /* number of bytes to look at or looked at */ int flags; /* temporary to save header status */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold >>= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; if (state->flags == -1) state->wrap = 0; /* if no header yet, treat as raw */ else state->wrap &= ~4; /* no point in computing a check value now */ flags = state->flags; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->flags = flags; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (inflateStateCheck(source) || dest == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; /* allocate space */ copy = (struct inflate_state FAR *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); copy->strm = dest; if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine(z_streamp strm, int subvert) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR state->sane = !subvert; return Z_OK; #else (void)subvert; state->sane = 1; return Z_DATA_ERROR; #endif } int ZEXPORT inflateValidate(z_streamp strm, int check) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (check && state->wrap) state->wrap |= 4; else state->wrap &= ~4; return Z_OK; } long ZEXPORT inflateMark(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return -(1L << 16); state = (struct inflate_state FAR *)strm->state; return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return (unsigned long)-1; state = (struct inflate_state FAR *)strm->state; return (unsigned long)(state->next - state->codes); } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/inflate.h0000644000175100001660000001503314760300420016657 0ustar /* inflate.h -- internal inflate state definition * Copyright (C) 1995-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif /* Possible inflate modes between inflate() calls */ typedef enum { HEAD = 16180, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ EXLEN, /* i: waiting for extra length (gzip) */ EXTRA, /* i: waiting for extra bytes (gzip) */ NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ TYPEDO, /* i: same, but skip check to exit inflate on new block */ STORED, /* i: waiting for stored size (length and complement) */ COPY_, /* i/o: same as COPY below, but only first time in */ COPY, /* i/o: waiting for input or output to copy stored block */ TABLE, /* i: waiting for dynamic block table lengths */ LENLENS, /* i: waiting for code length code lengths */ CODELENS, /* i: waiting for length/lit and distance code lengths */ LEN_, /* i: same as LEN below, but only first time in */ LEN, /* i: waiting for length/lit/eob code */ LENEXT, /* i: waiting for length extra bits */ DIST, /* i: waiting for distance code */ DISTEXT, /* i: waiting for distance extra bits */ MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> HCRC -> TYPE (zlib) -> DICTID or TYPE DICTID -> DICT -> TYPE (raw) -> TYPEDO Read deflate blocks: TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK STORED -> COPY_ -> COPY -> TYPE TABLE -> LENLENS -> CODELENS -> LEN_ LEN_ -> LEN Read deflate codes in fixed or dynamic block: LEN -> LENEXT or LIT or TYPE LENEXT -> DIST -> DISTEXT -> MATCH -> LEN LIT -> LEN Process trailer: CHECK -> LENGTH -> DONE */ /* State maintained between inflate() calls -- approximately 7K bytes, not including the allocated sliding window, which is up to 32K bytes. */ struct inflate_state { z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags, 0 if zlib, or -1 if raw or no header yet */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if needed */ /* bit accumulator */ unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ /* for string and stored block copying */ unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ /* fixed and dynamic code tables */ code const FAR *lencode; /* starting table for length/literal codes */ code const FAR *distcode; /* starting table for distance codes */ unsigned lenbits; /* index bits for lencode */ unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ unsigned have; /* number of code lengths in lens[] */ code FAR *next; /* next available space in codes[] */ unsigned short lens[320]; /* temporary storage for code lengths */ unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ int sane; /* if false, allow invalid distance too far */ int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/inftrees.c0000644000175100001660000003134014760300420017046 0ustar /* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2024 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.3.1 Copyright 1995-2024 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work) { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ unsigned match; /* use base and extra for symbol >= match */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ match = 20; break; case LENS: base = lbase; extra = lext; match = 257; break; default: /* DISTS */ base = dbase; extra = dext; match = 0; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if (work[sym] + 1U < match) { here.op = (unsigned char)0; here.val = work[sym]; } else if (work[sym] >= match) { here.op = (unsigned char)(extra[work[sym] - match]); here.val = base[work[sym] - match]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ if (huff != 0) { here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; next[huff] = here; } /* set return parameters */ *table += used; *bits = root; return 0; } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/inftrees.h0000644000175100001660000000555014760300420017057 0ustar /* inftrees.h -- header to use inftrees.c * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* Structure for decoding tables. Each entry provides either the information needed to do the operation requested by the code that indexed that table entry, or it provides a pointer to another table that indexes more bits of the code. op indicates whether the entry is a pointer to another table, a literal, a length or distance, an end-of-block, or an invalid code. For a table pointer, the low four bits of op is the number of index bits of that table. For a length or distance, the low four bits of op is the number of extra bits to get after the code. bits is the number of bits in this code or part of the code to drop off of the bit buffer. val is the actual byte to output in the case of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { unsigned char op; /* operation, extra bits, table bits */ unsigned char bits; /* bits in this part of the code */ unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work); mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/trees.c0000644000175100001660000011775114760300420016364 0ustar /* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2024 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ /* @(#) $Id$ */ /* #define GEN_TREES_H */ #include "deflate.h" #ifdef ZLIB_DEBUG # include #endif /* =========================================================================== * Constants */ #define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */ #define END_BLOCK 256 /* end of block literal code */ #define REP_3_6 16 /* repeat previous bit length 3-6 times (2 bits of repeat count) */ #define REPZ_3_10 17 /* repeat a zero length 3-10 times (3 bits of repeat count) */ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; local const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; local const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ /* =========================================================================== * Local data. These are initialized only once. */ #define DIST_CODE_LEN 512 /* see definition of array dist_code below */ #if defined(GEN_TREES_H) || !defined(STDC) /* non ANSI compilers may not accept trees.h */ local ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ local ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ uch _dist_code[DIST_CODE_LEN]; /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ local int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ local int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ #else # include "trees.h" #endif /* GEN_TREES_H */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; #ifdef NO_INIT_GLOBAL_POINTERS # define TCONST #else # define TCONST const #endif local TCONST static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local TCONST static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local TCONST static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ local unsigned bi_reverse(unsigned code, int len) { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ local void bi_flush(deflate_state *s) { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ local void bi_windup(deflate_state *s) { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG s->bits_sent = (s->bits_sent + 7) & ~7; #endif } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ unsigned code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { code = (code + bl_count[bits - 1]) << 1; next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, "inconsistent bit counts"); Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); for (n = 0; n <= max_code; n++) { int len = tree[n].Len; if (len == 0) continue; /* Now reverse the bits */ tree[n].Code = (ush)bi_reverse(next_code[len]++, len); Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); } } #ifdef GEN_TREES_H local void gen_trees_header(void); #endif #ifndef ZLIB_DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* !ZLIB_DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef ZLIB_DEBUG local void send_bits(deflate_state *s, int value, int length) { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } #else /* !ZLIB_DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = (int)value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } #endif /* ZLIB_DEBUG */ /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ local void tr_static_init(void) { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ #ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1 << extra_lbits[code]); n++) { _length_code[length++] = (uch)code; } } Assert (length == 256, "tr_static_init: length != 256"); /* Note that the length 255 (match length 258) can be represented * in two different ways: code 284 + 5 bits or code 285, so we * overwrite length_code[255] to use the best encoding: */ _length_code[length - 1] = (uch)code; /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1 << extra_dbits[code]); n++) { _dist_code[dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: dist != 256"); dist >>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse((unsigned)n, 5); } static_init_done = 1; # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG # include # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width) - 1 ? ",\n" : ", ")) void gen_trees_header(void) { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { fprintf(header, "%2u%s", _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { fprintf(header, "%2u%s", _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { fprintf(header, "%1u%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "%5u%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize a new block. */ local void init_block(deflate_state *s) { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->sym_next = s->matches = 0; } /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void ZLIB_INTERNAL _tr_init(deflate_state *s) { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ local void pqdownheap(deflate_state *s, ct_data *tree, int k) { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ local void gen_bitlen(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); } if (overflow == 0) return; Tracev((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } #ifdef DUMP_BL_TREE # include #endif /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. * Update the total bit length for the current block. * IN assertion: the field freq is set for all tree elements. * OUT assertions: the fields len and code are set to the optimal bit length * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ local void build_tree(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ local void scan_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ local void send_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ local int build_bl_tree(deflate_state *s) { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except the * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ local void send_all_trees(deflate_state *s, int lcodes, int dcodes, int blcodes) { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes - 1, 5); send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, ulg stored_len, int last) { send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); if (stored_len) zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); s->pending += stored_len; #ifdef ZLIB_DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; s->bits_sent += stored_len << 3; #endif } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) { bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ void ZLIB_INTERNAL _tr_align(deflate_state *s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef ZLIB_DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ local void compress_block(deflate_state *s, const ct_data *ltree, const ct_data *dtree) { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned sx = 0; /* running index in symbol buffers */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->sym_next != 0) do { #ifdef LIT_MEM dist = s->d_buf[sx]; lc = s->l_buf[sx++]; #else dist = s->sym_buf[sx++] & 0xff; dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; lc = s->sym_buf[sx++]; #endif if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code + LITERALS + 1, ltree); /* send length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= (unsigned)base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check for no overlay of pending_buf on needed symbols */ #ifdef LIT_MEM Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow"); #else Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); #endif } while (sx < s->sym_next); send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "block list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ local int detect_data_type(deflate_state *s) { /* block_mask is the bit mask of block-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long block_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("block-listed") bytes. */ for (n = 0; n <= 31; n++, block_mask >>= 1) if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("allow-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "block-listed" or "allow-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and write out the encoded block. */ void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, ulg stored_len, int last) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len + 3 + 7) >> 3; static_lenb = (s->static_len + 3 + 7) >> 3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->sym_next / 3)); #ifndef FORCE_STATIC if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) #endif opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); } else if (static_lenb == opt_lenb) { send_bits(s, (STATIC_TREES<<1) + last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1) + last, 3); send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, max_blindex + 1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef ZLIB_DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { #ifdef LIT_MEM s->d_buf[s->sym_next] = (ush)dist; s->l_buf[s->sym_next++] = (uch)lc; #else s->sym_buf[s->sym_next++] = (uch)dist; s->sym_buf[s->sym_next++] = (uch)(dist >> 8); s->sym_buf[s->sym_next++] = (uch)lc; #endif if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } return (s->sym_next == s->sym_end); } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/trees.h0000644000175100001660000002043014760300420016354 0ustar /* header created automatically with -DGEN_TREES_H */ local const ct_data static_ltree[L_CODES+2] = { {{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, {{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, {{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, {{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, {{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, {{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, {{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, {{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, {{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, {{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, {{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, {{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, {{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, {{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, {{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, {{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, {{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, {{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, {{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, {{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, {{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, {{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, {{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, {{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, {{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, {{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, {{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, {{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, {{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, {{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, {{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, {{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, {{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, {{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, {{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, {{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, {{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, {{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, {{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, {{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, {{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, {{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, {{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, {{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, {{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, {{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, {{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, {{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, {{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, {{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, {{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, {{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, {{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, {{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, {{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, {{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, {{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, {{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} }; local const ct_data static_dtree[D_CODES] = { {{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, {{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, {{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, {{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, {{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} }; const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; local const int base_length[LENGTH_CODES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; local const int base_dist[D_CODES] = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/uncompr.c0000644000175100001660000000553714760300420016723 0ustar /* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Decompresses the source buffer into the destination buffer. *sourceLen is the byte length of the source buffer. Upon entry, *destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, *destLen is the size of the decompressed data and *sourceLen is the number of source bytes consumed. Upon return, source + *sourceLen points to the first unused input byte. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen) { z_stream stream; int err; const uInt max = (uInt)-1; uLong len, left; Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ len = *sourceLen; if (*destLen) { left = *destLen; *destLen = 0; } else { left = 1; dest = buf; } stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = inflateInit(&stream); if (err != Z_OK) return err; stream.next_out = dest; stream.avail_out = 0; do { if (stream.avail_out == 0) { stream.avail_out = left > (uLong)max ? max : (uInt)left; left -= stream.avail_out; } if (stream.avail_in == 0) { stream.avail_in = len > (uLong)max ? max : (uInt)len; len -= stream.avail_in; } err = inflate(&stream, Z_NO_FLUSH); } while (err == Z_OK); *sourceLen -= len + stream.avail_in; if (dest != buf) *destLen = stream.total_out; else if (stream.total_out && err == Z_BUF_ERROR) left = 1; inflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err == Z_NEED_DICT ? Z_DATA_ERROR : err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : err; } int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) { return uncompress2(dest, destLen, source, &sourceLen); } mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/zconf.h0000644000175100001660000004016414760300420016357 0ustar /* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. * Even better than compiling with -DZ_PREFIX would be to use configure to set * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET /* all linked symbols and init macros */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align # define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block # define _tr_tally z__tr_tally # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 # define adler32_z z_adler32_z # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_combine_gen z_crc32_combine_gen # define crc32_combine_gen64 z_crc32_combine_gen64 # define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit # define deflateInit2 z_deflateInit2 # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams # define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset # define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table # ifndef Z_SOLO # define gz_error z_gz_error # define gz_intmax z_gz_intmax # define gz_strwinerror z_gz_strwinerror # define gzbuffer z_gzbuffer # define gzclearerr z_gzclearerr # define gzclose z_gzclose # define gzclose_r z_gzclose_r # define gzclose_w z_gzclose_w # define gzdirect z_gzdirect # define gzdopen z_gzdopen # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush # define gzfread z_gzfread # define gzfwrite z_gzfwrite # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets # define gzoffset z_gzoffset # define gzoffset64 z_gzoffset64 # define gzopen z_gzopen # define gzopen64 z_gzopen64 # ifdef _WIN32 # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread # define gzrewind z_gzrewind # define gzseek z_gzseek # define gzseek64 z_gzseek64 # define gzsetparams z_gzsetparams # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc # define gzvprintf z_gzvprintf # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit z_inflateBackInit # define inflateBackInit_ z_inflateBackInit_ # define inflateCodesUsed z_inflateCodesUsed # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetDictionary z_inflateGetDictionary # define inflateGetHeader z_inflateGetHeader # define inflateInit z_inflateInit # define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflateValidate z_inflateValidate # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress # define uncompress2 z_uncompress2 # endif # define zError z_zError # ifndef Z_SOLO # define zcalloc z_zcalloc # define zcfree z_zcfree # endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion /* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte # define Bytef z_Bytef # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func # ifndef Z_SOLO # define gzFile z_gzFile # endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func # define intf z_intf # define out_func z_out_func # define uInt z_uInt # define uIntf z_uIntf # define uLong z_uLong # define uLongf z_uLongf # define voidp z_voidp # define voidpc z_voidpc # define voidpf z_voidpf /* all zlib structs in zlib.h and zconf.h */ # define gz_header_s z_gz_header_s # define internal_state z_internal_state #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) # define OS2 #endif #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) # ifndef WIN32 # define WIN32 # endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) # ifndef SYS16BIT # define SYS16BIT # endif # endif #endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ #ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # ifndef STDC99 # define STDC99 # endif # endif #endif #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC #endif #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) # define STDC #endif #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) # define STDC #endif #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) # define STDC #endif #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ # define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ # define const /* note: need a more gentle solution here */ # endif #endif #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO # ifdef _WIN64 typedef unsigned long long z_size_t; # else typedef unsigned long z_size_t; # endif #else # define z_longlong long long # if defined(NO_SIZE_T) typedef unsigned NO_SIZE_T z_size_t; # elif defined(STDC) # include typedef size_t z_size_t; # else typedef unsigned long z_size_t; # endif # undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K # define MAX_MEM_LEVEL 8 # else # define MAX_MEM_LEVEL 9 # endif #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ /* Type declarations */ #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ #ifdef SYS16BIT # if defined(M_I86SM) || defined(M_I86MM) /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER # define FAR _far # else # define FAR far # endif # endif # if (defined(__SMALL__) || defined(__MEDIUM__)) /* Turbo C small or medium model */ # define SMALL_MEDIUM # ifdef __BORLANDC__ # define FAR _far # else # define FAR far # endif # endif #endif #if defined(WINDOWS) || defined(WIN32) /* If building or using zlib as a DLL, define ZLIB_DLL. * This is not mandatory, but it offers a little performance increase. */ # ifdef ZLIB_DLL # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) # ifdef ZLIB_INTERNAL # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif # endif # endif /* ZLIB_DLL */ /* If building or using zlib with the WINAPI/WINAPIV calling convention, * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) # ifdef ZLIB_DLL # ifdef ZLIB_INTERNAL # define ZEXPORT __declspec(dllexport) # define ZEXPORTVA __declspec(dllexport) # else # define ZEXPORT __declspec(dllimport) # define ZEXPORTVA __declspec(dllimport) # endif # endif #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef FAR # define FAR #endif #if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void const *voidpc; typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte const *voidpc; typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) # include # if (UINT_MAX == 0xffffffffUL) # define Z_U4 unsigned # elif (ULONG_MAX == 0xffffffffUL) # define Z_U4 unsigned long # elif (USHRT_MAX == 0xffffffffUL) # define Z_U4 unsigned short # endif #endif #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_STDARG_H #endif #ifdef STDC # ifndef Z_SOLO # include /* for off_t */ # endif #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO # include /* for va_list */ # endif #endif #ifdef _WIN32 # ifndef Z_SOLO # include /* for wchar_t */ # endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #ifndef Z_HAVE_UNISTD_H # ifdef __WATCOMC__ # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_HAVE_UNISTD_H # if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif # endif #endif #if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 # define Z_LFS64 #endif #if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) # define Z_LARGE64 #endif #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) # define Z_WANT64 #endif #if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) #pragma map(deflateInit_,"DEIN") #pragma map(deflateInit2_,"DEIN2") #pragma map(deflateEnd,"DEEND") #pragma map(deflateBound,"DEBND") #pragma map(inflateInit_,"ININ") #pragma map(inflateInit2_,"ININ2") #pragma map(inflateEnd,"INEND") #pragma map(inflateSync,"INSY") #pragma map(inflateSetDictionary,"INSEDI") #pragma map(compressBound,"CMBND") #pragma map(inflate_table,"INTABL") #pragma map(inflate_fast,"INFA") #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/zconf.h.in0000644000175100001660000004016414760300420016764 0ustar /* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. * Even better than compiling with -DZ_PREFIX would be to use configure to set * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET /* all linked symbols and init macros */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align # define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block # define _tr_tally z__tr_tally # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 # define adler32_z z_adler32_z # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_combine_gen z_crc32_combine_gen # define crc32_combine_gen64 z_crc32_combine_gen64 # define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit # define deflateInit2 z_deflateInit2 # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams # define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset # define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table # ifndef Z_SOLO # define gz_error z_gz_error # define gz_intmax z_gz_intmax # define gz_strwinerror z_gz_strwinerror # define gzbuffer z_gzbuffer # define gzclearerr z_gzclearerr # define gzclose z_gzclose # define gzclose_r z_gzclose_r # define gzclose_w z_gzclose_w # define gzdirect z_gzdirect # define gzdopen z_gzdopen # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush # define gzfread z_gzfread # define gzfwrite z_gzfwrite # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets # define gzoffset z_gzoffset # define gzoffset64 z_gzoffset64 # define gzopen z_gzopen # define gzopen64 z_gzopen64 # ifdef _WIN32 # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread # define gzrewind z_gzrewind # define gzseek z_gzseek # define gzseek64 z_gzseek64 # define gzsetparams z_gzsetparams # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc # define gzvprintf z_gzvprintf # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit z_inflateBackInit # define inflateBackInit_ z_inflateBackInit_ # define inflateCodesUsed z_inflateCodesUsed # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetDictionary z_inflateGetDictionary # define inflateGetHeader z_inflateGetHeader # define inflateInit z_inflateInit # define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflateValidate z_inflateValidate # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress # define uncompress2 z_uncompress2 # endif # define zError z_zError # ifndef Z_SOLO # define zcalloc z_zcalloc # define zcfree z_zcfree # endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion /* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte # define Bytef z_Bytef # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func # ifndef Z_SOLO # define gzFile z_gzFile # endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func # define intf z_intf # define out_func z_out_func # define uInt z_uInt # define uIntf z_uIntf # define uLong z_uLong # define uLongf z_uLongf # define voidp z_voidp # define voidpc z_voidpc # define voidpf z_voidpf /* all zlib structs in zlib.h and zconf.h */ # define gz_header_s z_gz_header_s # define internal_state z_internal_state #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) # define OS2 #endif #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) # ifndef WIN32 # define WIN32 # endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) # ifndef SYS16BIT # define SYS16BIT # endif # endif #endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ #ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # ifndef STDC99 # define STDC99 # endif # endif #endif #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC #endif #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) # define STDC #endif #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) # define STDC #endif #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) # define STDC #endif #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ # define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ # define const /* note: need a more gentle solution here */ # endif #endif #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO # ifdef _WIN64 typedef unsigned long long z_size_t; # else typedef unsigned long z_size_t; # endif #else # define z_longlong long long # if defined(NO_SIZE_T) typedef unsigned NO_SIZE_T z_size_t; # elif defined(STDC) # include typedef size_t z_size_t; # else typedef unsigned long z_size_t; # endif # undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K # define MAX_MEM_LEVEL 8 # else # define MAX_MEM_LEVEL 9 # endif #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ /* Type declarations */ #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ #ifdef SYS16BIT # if defined(M_I86SM) || defined(M_I86MM) /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER # define FAR _far # else # define FAR far # endif # endif # if (defined(__SMALL__) || defined(__MEDIUM__)) /* Turbo C small or medium model */ # define SMALL_MEDIUM # ifdef __BORLANDC__ # define FAR _far # else # define FAR far # endif # endif #endif #if defined(WINDOWS) || defined(WIN32) /* If building or using zlib as a DLL, define ZLIB_DLL. * This is not mandatory, but it offers a little performance increase. */ # ifdef ZLIB_DLL # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) # ifdef ZLIB_INTERNAL # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif # endif # endif /* ZLIB_DLL */ /* If building or using zlib with the WINAPI/WINAPIV calling convention, * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) # ifdef ZLIB_DLL # ifdef ZLIB_INTERNAL # define ZEXPORT __declspec(dllexport) # define ZEXPORTVA __declspec(dllexport) # else # define ZEXPORT __declspec(dllimport) # define ZEXPORTVA __declspec(dllimport) # endif # endif #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef FAR # define FAR #endif #if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void const *voidpc; typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte const *voidpc; typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) # include # if (UINT_MAX == 0xffffffffUL) # define Z_U4 unsigned # elif (ULONG_MAX == 0xffffffffUL) # define Z_U4 unsigned long # elif (USHRT_MAX == 0xffffffffUL) # define Z_U4 unsigned short # endif #endif #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_STDARG_H #endif #ifdef STDC # ifndef Z_SOLO # include /* for off_t */ # endif #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO # include /* for va_list */ # endif #endif #ifdef _WIN32 # ifndef Z_SOLO # include /* for wchar_t */ # endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #ifndef Z_HAVE_UNISTD_H # ifdef __WATCOMC__ # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_HAVE_UNISTD_H # if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) # define Z_HAVE_UNISTD_H # endif #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif # endif #endif #if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 # define Z_LFS64 #endif #if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) # define Z_LARGE64 #endif #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) # define Z_WANT64 #endif #if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) #pragma map(deflateInit_,"DEIN") #pragma map(deflateInit2_,"DEIN2") #pragma map(deflateEnd,"DEEND") #pragma map(deflateBound,"DEBND") #pragma map(inflateInit_,"ININ") #pragma map(inflateInit2_,"ININ2") #pragma map(inflateEnd,"INEND") #pragma map(inflateSync,"INSY") #pragma map(inflateSetDictionary,"INSEDI") #pragma map(compressBound,"CMBND") #pragma map(inflate_table,"INTABL") #pragma map(inflate_fast,"INFA") #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/zlib.h0000644000175100001660000027507514760300420016213 0ustar /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.3.1, January 22nd, 2024 Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.3.1" #define ZLIB_VERNUM 0x1310 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 3 #define ZLIB_VER_REVISION 1 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip and raw deflate streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in the case of corrupted input. */ typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); typedef void (*free_func)(voidpf opaque, voidpf address); struct internal_state; typedef struct z_stream_s { z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte will go here */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text for deflate, or the decoding state for inflate */ uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header FAR *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. In that case, zlib is thread-safe. When zalloc and zfree are Z_NULL on entry to the initialization function, they are set to internal routines that use the standard library functions malloc() and free(). On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use by the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field for deflate() */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion(void); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. total_in, total_out, adler, and msg are initialized. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Generate more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary. Some output may be provided even if flush is zero. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), which can be used if desired to determine whether or not there is more output in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed codes block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six when the flush marker begins, in order to avoid repeated flush markers upon calling deflate() again when avail_out == 0. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used in the first deflate call after deflateInit if all the compression is to be done in a single step. In order to complete in one call, avail_out must be at least the value returned by deflateBound (see below). Then deflate is guaranteed to return Z_STREAM_END. If not enough output space is provided, deflate will not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the Adler-32 checksum of all input read so far (that is, total_in bytes). If a gzip stream is being generated, then strm->adler will be the CRC-32 checksum of the input read so far. (See deflateInit2 below.) deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL or the state was inadvertently written over by the application), or Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit(z_streamp strm); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. In the current version of inflate, the provided input is not read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the first call). If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. total_in, total_out, adler, and msg are initialized. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression. Actual decompression will be done by inflate(). So next_in, and avail_in, next_out, and avail_out are unused and unchanged. The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), then next_in and avail_in are updated accordingly, and processing will resume at this point for the next call of inflate(). - Generate more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. If the caller of inflate() does not provide both available input and available output space, it is possible that there will be no progress made. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. To assist in this, on return inflate() always sets strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the stream completes, which reduces inflate's memory footprint. If the stream does not complete, either because not all of the stream is provided or not enough output space is provided, then a sliding window will be allocated and inflate() can be called again to continue the operation as if Z_NO_FLUSH had been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the effects of the flush parameter in this implementation are on the return value of inflate() as noted below, when inflate() returns early when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed Adler-32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained unless inflateGetHeader() is used. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output produced so far. The CRC-32 is checked against the gzip trailer, as is the uncompressed length, modulo 2^32. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value, in which case strm->msg points to a string with a more specific error), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL, or the state was inadvertently written over by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress was possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is to be attempted. */ ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state was inconsistent. */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy); This is another version of deflateInit with more compression options. The fields zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. For the current implementation of deflate(), a windowBits value of 8 (a window size of 256 bytes) is not supported. As a result, a request for 8 will result in 9 (a 512-byte window). In that case, providing 8 to inflateInit2() will result in an error when the zlib header with 9 is checked against the initialization of inflate(). The remedy is to not use 8 with deflateInit2() with this initialization, or at least in that case use 9 with inflateInit2(). windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute a check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to the appropriate value, if the operating system was determined at compile time. If a gzip stream is being written, strm->adler is a CRC-32 instead of an Adler-32. For raw deflate or gzip encoding, a request for a 256-byte window is rejected as invalid, since only the zlib header provides a means of transmitting the window size to the decompressor. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been consumed and all output has been delivered when using any of the flush options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the Adler-32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The Adler-32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the Adler-32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary, uInt *dictLength); /* Returns the sliding dictionary being maintained by deflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similarly, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up to 258 bytes less in that case, due to how zlib's implementation of deflate manages the sliding window and lookahead for matches, where matches can be up to 258 bytes long. If the application needs the last window-size bytes of input, then that would need to be saved by the application outside of zlib. deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT deflateCopy(z_streamp dest, z_streamp source); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset(z_streamp strm); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been set unchanged. total_in, total_out, adler, and msg are initialized. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams(z_streamp strm, int level, int strategy); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression approach (which is a function of the level) or the strategy is changed, and if there have been any deflate() calls since the state was initialized or reset, then the input available so far is compressed with the old level and strategy using deflate(strm, Z_BLOCK). There are three approaches for the compression levels 0, 1..3, and 4..9 respectively. The new level and strategy will take effect at the next call of deflate(). If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does not have enough output space to complete, then the parameter change will not take effect. In this case, deflateParams() can be called again with the same parameters and more output space to try again. In order to assure a change in the parameters on the first try, the deflate stream should be flushed using deflate() with Z_BLOCK or other flush request until strm.avail_out is not zero, before calling deflateParams(). Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be applied to the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if there was not enough output space to complete the compression of the available input data before a change in the strategy or approach. Note that in the case of a Z_BUF_ERROR, the parameters are not changed. A return value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be retried with more output space. */ ZEXTERN int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). If that first deflate() call is provided the sourceLen input bytes, an output buffer allocated to the size returned by deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed to return Z_STREAM_END. Note that it is possible for the compressed size to be larger than the value returned by deflateBound() if flush options other than Z_FINISH or Z_NO_FLUSH are used. */ ZEXTERN int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not provided would be due to the available output space having being consumed. The number of bits of output not provided are between 0 and 7, where they await more bits to join them in order to fill out a full byte. If pending or bits are Z_NULL, then those values are not set. deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflatePrime(z_streamp strm, int bits, int value); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to the current operating system, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2(z_streamp strm, int windowBits); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an Adler-32 or a CRC-32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see below), inflate() will *not* automatically decode concatenated gzip members. inflate() will return Z_STREAM_END at the end of the gzip member. The state would need to be reset to continue decoding a subsequent gzip member. This *must* be done if there is more data after a gzip member, in order for the decompression to be compliant with the gzip standard (RFC 1952). inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the Adler-32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, uInt *dictLength); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similarly, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT inflateSync(z_streamp strm); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync searches for a 00 00 FF FF pattern in the compressed data. All full flush points have this pattern, but not all occurrences of this pattern are full flush points. inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, z_streamp source); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset(z_streamp strm); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. total_in, total_out, adler, and msg are initialized. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, int windowBits); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. If the window size is changed, then the memory allocated for the window is freed, and the window will be reallocated by inflate() if needed. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, int bits, int value); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark(z_streamp strm); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above, or -65536 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, unsigned char FAR *window); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func)(void FAR *, z_const unsigned char FAR * FAR *); typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); ZEXTERN int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than inflate() for file i/o applications, in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. inflate() can be faster on modern CPUs when used with large buffers. inflateBack() trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the default behavior of inflate(), which expects a zlib header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero -- buf is ignored in that case -- and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags(void); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: ZLIB_DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ #ifndef Z_SOLO /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress() is equivalent to compress2() with a level parameter of Z_DEFAULT_COMPRESSION. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed data. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point. */ ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen); /* Same as uncompress, except that sourceLen is a pointer, where the length of the source is *sourceLen. On return, *sourceLen is the number of source bytes consumed. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode); Open the gzip (.gz) file at path for reading and decompressing, or compressing and writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) 'T' will request transparent writing or appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. The addition of "x" when writing will create the file exclusively, which fails if the file already exists. On systems that support it, the addition of "e" when reading or writing will set the flag to close the file on an execve() call. These functions, as well as gzip, will read and decode a sequence of gzip streams in a file. The append function of gzopen() can be used to create such a file. (Also see gzflush() for another way to do this.) When appending, gzopen does not test whether the file begins with a gzip stream, nor does it look for the end of the gzip streams to begin appending. gzopen will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. When reading, this will be detected automatically by looking for the magic two- byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode); /* Associate a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. If you are using fileno() to get the file descriptor from a FILE *, then you will have to use dup() to avoid double-close()ing the file descriptor. Both gzclose() and fclose() will close the associated file descriptor, so they need to have different file descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size); /* Set the internal buffer size used by this library's functions for file to size. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Three times that size in buffer space is allocated. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy); /* Dynamically update the compression level and strategy for file. See the description of deflateInit2 for the meaning of these parameters. Previously provided data is flushed before applying the parameter changes. gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not opened for writing, Z_ERRNO if there is an error writing the flushed data, or Z_MEM_ERROR if there is a memory allocation error. */ ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len); /* Read and decompress up to len uncompressed bytes from file into buf. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream. Any number of gzip streams may be concatenated in the input file, and will all be decompressed by gzread(). If something other than a gzip stream is encountered after a gzip stream, that remaining trailing garbage is ignored (and no error is returned). gzread can be used to read a gzip file that is being concurrently written. Upon reaching the end of the input, gzread will return with the available data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then gzclearerr can be used to clear the end of file indicator in order to permit gzread to be tried again. Z_OK indicates that a gzip stream was completed on the last gzread. Z_BUF_ERROR indicates that the input file ended in the middle of a gzip stream. Note that gzread does not return -1 in the event of an incomplete gzip stream. This error is deferred until gzclose(), which will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip stream. Alternatively, gzerror can be used before gzclose to detect this case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. If len is too large to fit in an int, then nothing is read, -1 is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file); /* Read and decompress up to nitems items of size size from file into buf, otherwise operating as gzread() does. This duplicates the interface of stdio's fread(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfread() returns the number of full items read of size size, or zero if the end of the file was reached and a full item could not be read, or if there was an error. gzerror() must be consulted if zero is returned in order to determine if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is read, zero is returned, and the error state is set to Z_STREAM_ERROR. In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a multiple of size, then the final partial item is nevertheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written file, resetting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len); /* Compress and write the len uncompressed bytes at buf to file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems, gzFile file); /* Compress and write nitems items of size size from buf to file, duplicating the interface of stdio's fwrite(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfwrite() returns the number of full items written of size size, or zero if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is written, zero is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); /* Convert, format, compress, and write the arguments (...) to file under control of the string format, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or a negative zlib error code in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf(), because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s); /* Compress and write the given null-terminated string s to file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len); /* Read and decompress bytes from file into buf, until len-1 characters are read, or until a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len is one, the string is terminated with a null character. If no characters are read due to an end-of-file or len is less than one, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc(gzFile file, int c); /* Compress and write c, converted to an unsigned char, into file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc(gzFile file); /* Read and decompress one byte from file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); /* Push c back onto the stream for file to be read as the first character on the next read. At least one character of push-back is always allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush(gzFile file, int flush); /* Flush all pending output to file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatenated gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence); Set the starting position to offset relative to whence for the next gzread or gzwrite on file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind(gzFile file); /* Rewind file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). */ /* ZEXTERN z_off_t ZEXPORT gztell(gzFile file); Return the starting position for the next gzread or gzwrite on file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file); Return the current compressed (actual) read or write offset of file. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof(gzFile file); /* Return true (1) if the end-of-file indicator for file has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect(gzFile file); /* Return true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). When writing, gzdirect() returns true (1) if transparent writing was requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: gzdirect() is not needed when writing. Transparent writing must be explicitly requested, so the application already knows the answer. When linking statically, using gzdirect() will include all of the zlib code for gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose(gzFile file); /* Flush all pending output for file, if necessary, close file and deallocate the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r(gzFile file); ZEXTERN int ZEXPORT gzclose_w(gzFile file); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum); /* Return the error message for the last error which occurred on file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr(gzFile file); /* Clear the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ #endif /* !Z_SOLO */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. An Adler-32 value is in the range of a 32-bit unsigned integer. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len); /* Same as adler32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note that the z_off_t type (like off_t) is a signed integer. If len2 is negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. If buf is Z_NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf, z_size_t len); /* Same as crc32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. len2 must be non-negative. */ /* ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); Return the operator corresponding to length len2, to be used with crc32_combine_op(). len2 must be non-negative. */ ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); /* Give the same result as crc32_combine(), using op in place of len2. op is is generated from len2 by crc32_combine_gen(). This will be faster than crc32_combine() if the generated op is used more than once. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, int stream_size); ZEXTERN int ZEXPORT inflateInit_(z_streamp strm, const char *version, int stream_size); ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size); ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, const char *version, int stream_size); ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size); #ifdef Z_PREFIX_SET # define z_deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) # define z_inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #else # define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) # define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) # define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #endif #ifndef Z_SOLO /* gzgetc() macro and its supporting function and exposed data structure. Note * that the real internal state is much larger than the exposed structure. * This abbreviated structure exposes just enough for the gzgetc() macro. The * user should not mess with these exposed elements, since their names or * behavior could change in the future, perhaps even capriciously. They can * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #else # define gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t); ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t); ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) # ifdef Z_PREFIX_SET # define z_gzopen z_gzopen64 # define z_gzseek z_gzseek64 # define z_gztell z_gztell64 # define z_gzoffset z_gzoffset64 # define z_adler32_combine z_adler32_combine64 # define z_crc32_combine z_crc32_combine64 # define z_crc32_combine_gen z_crc32_combine_gen64 # else # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # define crc32_combine_gen crc32_combine_gen64 # endif # ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int); ZEXTERN z_off_t ZEXPORT gztell64(gzFile); ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile); ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); # endif #else ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *); ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int); ZEXTERN z_off_t ZEXPORT gztell(gzFile); ZEXTERN z_off_t ZEXPORT gzoffset(gzFile); ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); #endif #else /* Z_SOLO */ ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); #endif /* !Z_SOLO */ /* undocumented functions */ ZEXTERN const char * ZEXPORT zError(int); ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); #if defined(_WIN32) && !defined(Z_SOLO) ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va); # endif #endif #ifdef __cplusplus } #endif #endif /* ZLIB_H */ mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/zutil.c0000644000175100001660000001601314760300420016376 0ustar /* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2017 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #ifndef Z_SOLO # include "gzguts.h" #endif z_const char * const z_errmsg[10] = { (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ (z_const char *)"stream end", /* Z_STREAM_END 1 */ (z_const char *)"", /* Z_OK 0 */ (z_const char *)"file error", /* Z_ERRNO (-1) */ (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ (z_const char *)"" }; const char * ZEXPORT zlibVersion(void) { return ZLIB_VERSION; } uLong ZEXPORT zlibCompileFlags(void) { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef ZLIB_DEBUG flags += 1 << 8; #endif /* #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif */ #ifdef ZLIB_WINAPI flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif #ifdef NO_GZIP flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; #endif #ifdef FASTEST flags += 1L << 21; #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifdef NO_vsnprintf flags += 1L << 25; # ifdef HAS_vsprintf_void flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void flags += 1L << 26; # endif # endif #else flags += 1L << 24; # ifdef NO_snprintf flags += 1L << 25; # ifdef HAS_sprintf_void flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void flags += 1L << 26; # endif # endif #endif return flags; } #ifdef ZLIB_DEBUG #include # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; void ZLIB_INTERNAL z_error(char *m) { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char * ZEXPORT zError(int err) { return ERR_MSG(err); } #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 /* The older Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ int errno = 0; #endif #ifndef HAVE_MEMCPY void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { uInt j; for (j = 0; j < len; j++) { if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; } return 0; } void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } #endif #ifndef Z_SOLO #ifdef SYS16BIT #ifdef __TURBOC__ /* Turbo C in 16-bit mode */ # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes * and farmalloc(64K) returns a pointer with an offset of 8, so we * must fix the pointer. Warning: the pointer must be put back to its * original form in order to free it, use zcfree(). */ #define MAX_PTR 10 /* 10*64K = 640K */ local int next_ptr = 0; typedef struct ptr_table_s { voidpf org_ptr; voidpf new_ptr; } ptr_table; local ptr_table table[MAX_PTR]; /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; (void)opaque; /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ if (bsize < 65520L) { buf = farmalloc(bsize); if (*(ush*)&buf != 0) return buf; } else { buf = farmalloc(bsize + 16L); } if (buf == NULL || next_ptr >= MAX_PTR) return NULL; table[next_ptr].org_ptr = buf; /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; (void)opaque; if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; } /* Find the original pointer */ for (n = 0; n < next_ptr; n++) { if (ptr != table[n].new_ptr) continue; farfree(table[n].org_ptr); while (++n < next_ptr) { table[n-1] = table[n]; } next_ptr--; return; } Assert(0, "zcfree: ptr not found"); } #endif /* __TURBOC__ */ #ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); } #endif /* M_I86 */ #endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC extern voidp malloc(uInt size); extern voidp calloc(uInt items, uInt size); extern void free(voidpf ptr); #endif voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; free(ptr); } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ mongodb-1.21.0/src/libmongoc/src/zlib-1.3.1/zutil.h0000644000175100001660000001502514760300420016405 0ustar /* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef ZUTIL_H #define ZUTIL_H #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include "zlib.h" #if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include # endif # include # include #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; #if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) # include # if (ULONG_MAX == 0xffffffffffffffff) # define Z_U8 unsigned long # elif (ULLONG_MAX == 0xffffffffffffffff) # define Z_U8 unsigned long long # elif (UINT_MAX == 0xffffffffffffffff) # define Z_U8 unsigned # endif #endif extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ #ifndef DEF_WBITS # define DEF_WBITS MAX_WBITS #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default memLevel */ #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 /* The three kinds of block type */ #define MIN_MATCH 3 #define MAX_MATCH 258 /* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ /* target dependencies */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 # ifndef Z_SOLO # if defined(__TURBOC__) || defined(__BORLANDC__) # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) /* Allow compilation with ANSI keywords only enabled */ void _Cdecl farfree( void *block ); void *_Cdecl farmalloc( unsigned long nbytes ); # else # include # endif # else /* MSC or DJGPP */ # include # endif # endif #endif #ifdef AMIGA # define OS_CODE 1 #endif #if defined(VAXC) || defined(VMS) # define OS_CODE 2 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif #ifdef __370__ # if __TARGET_LIB__ < 0x20000000 # define OS_CODE 4 # elif __TARGET_LIB__ < 0x40000000 # define OS_CODE 11 # else # define OS_CODE 8 # endif #endif #if defined(ATARI) || defined(atarist) # define OS_CODE 5 #endif #ifdef OS2 # define OS_CODE 6 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) # define OS_CODE 7 #endif #ifdef __acorn # define OS_CODE 13 #endif #if defined(WIN32) && !defined(__CYGWIN__) # define OS_CODE 10 #endif #ifdef _BEOS_ # define OS_CODE 16 #endif #ifdef __TOS_OS400__ # define OS_CODE 18 #endif #ifdef __APPLE__ # define OS_CODE 19 #endif #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); #endif /* common defaults */ #ifndef OS_CODE # define OS_CODE 3 /* assume Unix */ #endif #ifndef F_OPEN # define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ #if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) /* Use our own functions for small and medium model with MSC <= 5.0. * You may have to use the same strategy for Borland C (untested). * The __SC__ check is for Symantec. */ # define NO_MEMCPY #endif #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) # define HAVE_MEMCPY #endif #ifdef HAVE_MEMCPY # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ # define zmemcpy _fmemcpy # define zmemcmp _fmemcmp # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len); void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len); #endif /* Diagnostic functions */ #ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error(char *m); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif #ifndef Z_SOLO voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size); void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr); #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} /* Reverse the bytes in a 32-bit value */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */ mongodb-1.21.0/src/libmongoc/VERSION_CURRENT0000644000175100001660000000000714760300420015144 0ustar 1.30.1 mongodb-1.21.0/src/libmongocrypt-compat/mongocrypt/mongocrypt.h0000644000175100001660000000204114760300420021645 0ustar /* * Copyright 2020-present MongoDB, 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. */ #ifndef PHONGO_COMPAT_MONGOCRYPT_H #define PHONGO_COMPAT_MONGOCRYPT_H /* This header forwards includes for "mongocrypt/mongocrypt.h" to the desired * header in the bundled libmongocrypt submodule. This is used when compiling * bundled versions of libmongoc and libmongocrypt and is necessary because * libmongocrypt's source directory is not named "mongocrypt/". */ #include "libmongocrypt/src/mongocrypt.h" #endif /* PHONGO_COMPAT_MONGOCRYPT_H */ mongodb-1.21.0/src/libmongocrypt-compat/mongocrypt-export.h0000644000175100001660000000232214760300420020765 0ustar /* * Copyright 2020-present MongoDB, 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. */ #ifndef MONGOCRYPT_EXPORT_H #define MONGOCRYPT_EXPORT_H /* This file would typically be generated by libmongocrypt's CMake build process * so it must exist when building libmongocrypt as a submodule via Autotools. We * need only ensure this file exists and expected constants are defined, since * libmongocrypt APIs will not actually be exported. * * See: https://cmake.org/cmake/help/latest/module/GenerateExportHeader.html */ #define MONGOCRYPT_EXPORT #define MONGOCRYPT_NO_EXPORT #define MONGOCRYPT_DEPRECATED #define MONGOCRYPT_DEPRECATED_EXPORT #define MONGOCRYPT_DEPRECATED_NO_EXPORT #endif /* MONGOCRYPT_EXPORT_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_azure_request.h0000644000175100001660000001040214760300420025033 0ustar /* * Copyright 2020-present MongoDB, 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. */ #ifndef KMS_AZURE_REQUEST_H #define KMS_AZURE_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif /* Constructs an oauth client credentials grant request for Azure. * See * https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#get-a-token. * * Parameters: * All parameters must be NULL terminated strings. * - host: The value of the Host header. This should be a custom host or * "login.microsoftonline.com". * - scope: The oauth scope. This should be a custom scope or * "https%3A%2F%2Fvault.azure.net%2F.default". Must be URL encoded. * - tenant_id: The Azure tenant ID. * - client_id: The client ID to authenticate. * - client_secret: The client secret to authenticate. * - opt: Additional options. This must have the Azure provider set via * kms_request_opt_set_provider. * * Returns: A new kms_request_t. * Always returns a new kms_request_t, even on error. * Caller must check if an error occurred by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_azure_request_oauth_new (const char *host, const char *scope, const char *tenant_id, const char *client_id, const char *client_secret, const kms_request_opt_t *opt); /* Constructs a wrapkey request for Azure. * See https://docs.microsoft.com/en-us/rest/api/keyvault/wrapkey/wrapkey * * Parameters: * All parameters must be NULL terminated strings. * - host: The value of the Host header, like "mykeyvault.vault.azure.net". * - access_token: The access_token obtained from an oauth response as a * base64url encoded string. * - key_name: The azure key name. * - key_version: An optional key version. May be NULL or empty string. * - plaintext: The plaintext key to encrypt. * - plaintext_len: The number of bytes of plaintext. * - opt: Additional options. This must have the Azure provider set via * kms_request_opt_set_provider. */ KMS_MSG_EXPORT (kms_request_t *) kms_azure_request_wrapkey_new (const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *plaintext, size_t plaintext_len, const kms_request_opt_t *opt); /* Constructs an unwrapkey request for Azure. * See https://docs.microsoft.com/en-us/rest/api/keyvault/unwrapkey/unwrapkey * * Parameters: * All parameters must be NULL terminated strings. * - host: The value of the Host header, like "mykeyvault.vault.azure.net". * - access_token: The access_token obtained from an oauth response as a * base64url encoded string. * - key_name: The azure key name. * - key_version: An optional key version. May be NULL or empty string. * - ciphertext: The ciphertext key to decrypt. * - ciphertext_len: The number of bytes of ciphertext. * - opt: Additional options. This must have the Azure provider set via * kms_request_opt_set_provider. */ KMS_MSG_EXPORT (kms_request_t *) kms_azure_request_unwrapkey_new (const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *ciphertext, size_t ciphertext_len, const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_AZURE_REQUEST_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_b64.h0000644000175100001660000000367114760300420022542 0ustar /* * Copyright 2018-present MongoDB 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. */ #ifndef KMS_MESSAGE_B64_H #define KMS_MESSAGE_B64_H #include "kms_message.h" #include #include #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (void) kms_message_b64_initialize_rmap (void); KMS_MSG_EXPORT (int) kms_message_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize); KMS_MSG_EXPORT (int) kms_message_b64_pton (char const *src, uint8_t *target, size_t targsize); /* src and target may be the same string. Assumes no whitespace in src. */ KMS_MSG_EXPORT (int) kms_message_b64_to_b64url (const char *src, size_t srclength, char *target, size_t targsize); KMS_MSG_EXPORT (int) kms_message_b64url_to_b64 (const char *src, size_t srclength, char *target, size_t targsize); /* Convenience conversions which return copies. */ char * kms_message_raw_to_b64 (const uint8_t *raw, size_t raw_len); uint8_t * kms_message_b64_to_raw (const char *b64, size_t *out); char * kms_message_raw_to_b64url (const uint8_t *raw, size_t raw_len); uint8_t * kms_message_b64url_to_raw (const char *b64url, size_t *out); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_MESSAGE_B64_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_caller_identity_request.h0000644000175100001660000000174514760300420027072 0ustar /* * Copyright 2019-present MongoDB, 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. */ #ifndef KMS_CALLER_IDENTITY_REQUEST_H #define KMS_CALLER_IDENTITY_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (kms_request_t *) kms_caller_identity_request_new (const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_CALLER_IDENTITY_REQUEST_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_decrypt_request.h0000644000175100001660000000204214760300420025360 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_DECRYPT_REQUEST_H #define KMS_DECRYPT_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (kms_request_t *) kms_decrypt_request_new (const uint8_t *ciphertext_blob, size_t len, const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_DECRYPT_REQUEST_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_encrypt_request.h0000644000175100001660000000212714760300420025376 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_ENCRYPT_REQUEST_H #define KMS_ENCRYPT_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (kms_request_t *) kms_encrypt_request_new (const uint8_t *plaintext, size_t plaintext_length, const char *key_id, const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_ENCRYPT_REQUEST_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_gcp_request.h0000644000175100001660000001162214760300420024463 0ustar /* * Copyright 2020-present MongoDB, 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. */ #ifndef KMS_GCP_REQUEST_H #define KMS_GCP_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include "kms_request_opt.h" #ifdef __cplusplus extern "C" { #endif /* Constructs an oauth client credentials request for GCP. * See https://developers.google.com/identity/protocols/oauth2/service-account * * Parameters: * - host: The host header, like "oauth2.googleapis.com". * - email: The email for the service account to authenticate. * - audience: The "aud" field in the JSON Web Token (JWT). Should be a URL * like "https://oauth2.googleapis.com/token" * - scope: The "scope" field in the JSON Web Token (JWT). Should be a URL * like "https://www.googleapis.com/auth/cloudkms". * - private_key_data: Bytes pointing to a PKCS#8 private key. * - private_key_len: The length of private_key_data. * - opt: Request options. The provider must be set to KMS_REQUEST_PROVIDER_GCP * with kms_request_opt_set_provider. Callers that want to use a custom crypto * callback to sign the request should set the callback on opt with * kms_request_opt_set_crypto_hook_rsaes_pkcs1_v1_5. * * Returns: A new kms_request_t. * Always returns a new kms_request_t, even on error. * Caller must check if an error occurred by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_gcp_request_oauth_new (const char *host, const char *email, const char *audience, const char *scope, const char *private_key_data, size_t private_key_len, const kms_request_opt_t *opt); /* Constructs the encrypt request for GCP. * See * https://cloud.google.com/kms/docs/encrypt-decrypt#kms-encrypt-symmetric-api * * Parameters: * - host: The value of the Host header, like "cloudkms.googleapis.com". * - project_id: The project id. * - location: The location id, like "global". * - key_ring_name: The key ring name. * - key_name: The key name. * - key_version: The optional key version. May be NULL. * - plaintext: The plaintext key to encrypt. * - plaintext_len: The number of bytes of plaintext. * - opt: Request options. The provider must be set to KMS_REQUEST_PROVIDER_GCP * with kms_request_opt_set_provider. * * Returns: A new kms_request_t. * Always returns a new kms_request_t, even on error. * Caller must check if an error occurred by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_gcp_request_encrypt_new (const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const char *key_version, const uint8_t *plaintext, size_t plaintext_len, const kms_request_opt_t *opt); /* Constructs the decrypt request for GCP. * See * https://cloud.google.com/kms/docs/encrypt-decrypt#kms-decrypt-symmetric-api * * Parameters: * - host: The value of the Host header, like "cloudkms.googleapis.com". * - project_id: The project id. * - location: The location id, like "global". * - key_ring_name: The key ring name. * - key_name: The key name. * - ciphertext: The ciphertext key to encrypt. * - ciphertext_len: The number of bytes of ciphertext. * - opt: Request options. The provider must be set to KMS_REQUEST_PROVIDER_GCP * with kms_request_opt_set_provider. * * Returns: A new kms_request_t. * Always returns a new kms_request_t, even on error. * Caller must check if an error occurred by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_gcp_request_decrypt_new (const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const uint8_t *ciphertext, size_t ciphertext_len, const kms_request_opt_t *opt); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_GCP_REQUEST_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_kmip_request.h0000644000175100001660000000516714760300420024661 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_REQUEST_H #define KMS_KMIP_REQUEST_H #include "kms_message_defines.h" #include "kms_request.h" #include #ifdef __cplusplus extern "C" { #endif #define KMS_KMIP_REQUEST_SECRETDATA_LENGTH 96 /* kms_kmip_request_register_secretdata_new creates a KMIP Register request with * a SecretData payload of length KMS_KMIP_REQUEST_SECRETDATA_LENGTH. * - len must be KMS_KMIP_REQUEST_SECRETDATA_LENGTH. * - Callers must check for an error by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_register_secretdata_new (void *reserved, const uint8_t *data, size_t len); /* kms_kmip_request_activate_new creates a KMIP Activate request with the * provided unique identifer. * - unique_identifier must be a NULL terminated string. * - Callers must check for an error by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_activate_new (void *reserved, const char *unique_identifier); /* kms_kmip_request_get_new creates a KMIP Get request with the provided unique * identifer. * - unique_identifier must be a NULL terminated string. * - Callers must check for an error by calling kms_request_get_error. */ KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_get_new (void *reserved, const char *unique_identifier); KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_create_new (void *reserved); KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_encrypt_new (void *reserved, const char *unique_identifier, const uint8_t *plaintext, size_t len); KMS_MSG_EXPORT (kms_request_t *) kms_kmip_request_decrypt_new (void *reserved, const char *unique_identifier, const uint8_t *ciphertext, size_t len, const uint8_t *iv, size_t iv_len); #ifdef __cplusplus } #endif #endif /* KMS_KMIP_REQUEST_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_kmip_response.h0000644000175100001660000000312714760300420025021 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESPONSE_H #define KMS_KMIP_RESPONSE_H #include "kms_message_defines.h" #include #include "kms_response.h" /* kms_kmip_response_get_unique_identifier returns the UniqueIdentifier in the * first BatchItem in a ResponseMessage. * - Returns a NULL terminated string that the caller must free. * - Returns NULL on error and sets an error on kms_response_t. */ KMS_MSG_EXPORT (char *) kms_kmip_response_get_unique_identifier (kms_response_t *res); /* kms_kmip_response_get_secretdata returns the KeyMaterial in the * first BatchItem in a ResponseMessage. * - Caller must free returned data. * - Returns NULL on error and sets an error on kms_response_t. */ KMS_MSG_EXPORT (uint8_t *) kms_kmip_response_get_secretdata (kms_response_t *res, size_t *secretdatalen); KMS_MSG_EXPORT (uint8_t *) kms_kmip_response_get_data (kms_response_t *res, size_t *datalen); KMS_MSG_EXPORT (uint8_t *) kms_kmip_response_get_iv (kms_response_t *res, size_t *datalen); #endif /* KMS_KMIP_RESPONSE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_kmip_response_parser.h0000644000175100001660000000154714760300420026401 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESPONSE_PARSER_H #define KMS_KMIP_RESPONSE_PARSER_H #include "kms_message_defines.h" #include "kms_response_parser.h" KMS_MSG_EXPORT (kms_response_parser_t *) kms_kmip_response_parser_new (void *reserved); #endif /* KMS_KMIP_RESPONSE_PARSER_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_message.h0000644000175100001660000000203514760300420023564 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_H #define KMS_MESSAGE_H #include #include "kms_message_defines.h" #include "kms_kmip_request.h" #include "kms_kmip_response.h" #include "kms_kmip_response_parser.h" #include "kms_request_opt.h" #include "kms_request.h" #include "kms_response.h" #include "kms_response_parser.h" #include "kms_caller_identity_request.h" #include "kms_decrypt_request.h" #include "kms_encrypt_request.h" #endif /* KMS_MESSAGE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_message_defines.h0000644000175100001660000000322014760300420025256 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_DEFINES_H #define KMS_MESSAGE_DEFINES_H #ifdef _MSC_VER #ifdef KMS_MSG_STATIC #define KMS_MSG_API #elif defined(KMS_MSG_COMPILATION) #define KMS_MSG_API __declspec(dllexport) #else #define KMS_MSG_API __declspec(dllimport) #endif #define KMS_MSG_CALL __cdecl #elif defined(__GNUC__) #ifdef KMS_MSG_STATIC #define KMS_MSG_API #elif defined(KMS_MSG_COMPILATION) #define KMS_MSG_API __attribute__ ((visibility ("default"))) #else #define KMS_MSG_API #endif #define KMS_MSG_CALL #endif #define KMS_MSG_EXPORT(type) KMS_MSG_API type KMS_MSG_CALL #ifdef __cplusplus extern "C" { #endif KMS_MSG_EXPORT (int) kms_message_init (void); KMS_MSG_EXPORT (void) kms_message_cleanup (void); #ifdef __cplusplus } /* extern "C" */ #endif #ifdef _MSC_VER #include #pragma warning(disable : 4142) #ifndef _SSIZE_T_DEFINED #define _SSIZE_T_DEFINED typedef SSIZE_T ssize_t; #endif #pragma warning(default : 4142) #endif #if defined(_MSC_VER) #define KMS_MSG_INLINE __inline #else #define KMS_MSG_INLINE __inline__ #endif #endif /* KMS_MESSAGE_DEFINES_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_request.h0000644000175100001660000000651514760300420023637 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_REQUEST_H #define KMS_REQUEST_H #include "kms_message_defines.h" #include "kms_request_opt.h" #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* A KMS request is general enough to create arbitrary HTTP requests, but also * supports generating AWS signature v4. */ typedef struct _kms_request_t kms_request_t; KMS_MSG_EXPORT (kms_request_t *) kms_request_new (const char *method, const char *path_and_query, const kms_request_opt_t *opt); KMS_MSG_EXPORT (void) kms_request_destroy (kms_request_t *request); KMS_MSG_EXPORT (const char *) kms_request_get_error (kms_request_t *request); /* Begin: AWS specific */ KMS_MSG_EXPORT (bool) kms_request_set_date (kms_request_t *request, const struct tm *tm); KMS_MSG_EXPORT (bool) kms_request_set_region (kms_request_t *request, const char *region); KMS_MSG_EXPORT (bool) kms_request_set_service (kms_request_t *request, const char *service); KMS_MSG_EXPORT (bool) kms_request_set_access_key_id (kms_request_t *request, const char *akid); KMS_MSG_EXPORT (bool) kms_request_set_secret_key (kms_request_t *request, const char *key); /* End: AWS specific */ KMS_MSG_EXPORT (bool) kms_request_add_header_field (kms_request_t *request, const char *field_name, const char *value); KMS_MSG_EXPORT (bool) kms_request_append_header_field_value (kms_request_t *request, const char *value, size_t len); KMS_MSG_EXPORT (bool) kms_request_append_payload (kms_request_t *request, const char *payload, size_t len); /* Begin: AWS specific */ KMS_MSG_EXPORT (char *) kms_request_get_canonical (kms_request_t *request); KMS_MSG_EXPORT (const char *) kms_request_get_canonical_header (kms_request_t *request, const char *header); KMS_MSG_EXPORT (char *) kms_request_get_string_to_sign (kms_request_t *request); KMS_MSG_EXPORT (bool) kms_request_get_signing_key (kms_request_t *request, unsigned char *key); KMS_MSG_EXPORT (char *) kms_request_get_signature (kms_request_t *request); KMS_MSG_EXPORT (char *) kms_request_get_signed (kms_request_t *request); /* End: AWS specific */ KMS_MSG_EXPORT (void) kms_request_free_string (char *ptr); /* Finalize and obtain a plain HTTP request (no signing). */ KMS_MSG_EXPORT (char *) kms_request_to_string (kms_request_t *request); /* kms_request_to_bytes returns the data for a request. * - Returns NULL on error and sets an error on request. */ KMS_MSG_EXPORT (const uint8_t *) kms_request_to_bytes (kms_request_t *request, size_t *len); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_REQUEST_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_request_opt.h0000644000175100001660000000555014760300420024517 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_REQUEST_OPT_H #define KMS_REQUEST_OPT_H #include "kms_message_defines.h" #include #include #ifdef __cplusplus extern "C" { #endif typedef struct _kms_request_opt_t kms_request_opt_t; typedef size_t kms_request_provider_t; #define KMS_REQUEST_PROVIDER_AWS 0 #define KMS_REQUEST_PROVIDER_AZURE 1 #define KMS_REQUEST_PROVIDER_GCP 2 #define KMS_REQUEST_PROVIDER_KMIP 3 KMS_MSG_EXPORT (kms_request_opt_t *) kms_request_opt_new (void); /* The default provider is AWS. This will automatically set extra headers. * Returns false if provider is invalid. */ KMS_MSG_EXPORT (bool) kms_request_opt_set_provider (kms_request_opt_t *opt, kms_request_provider_t provider); KMS_MSG_EXPORT (void) kms_request_opt_destroy (kms_request_opt_t *request); KMS_MSG_EXPORT (void) kms_request_opt_set_connection_close (kms_request_opt_t *opt, bool connection_close); KMS_MSG_EXPORT (void) kms_request_opt_set_crypto_hooks (kms_request_opt_t *opt, bool (*sha256) (void *ctx, const char *input, size_t len, unsigned char *hash_out), bool (*sha256_hmac) (void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out), void *ctx); KMS_MSG_EXPORT (void) kms_request_opt_set_crypto_hook_sign_rsaes_pkcs1_v1_5 ( kms_request_opt_t *opt, bool (*sign_rsaes_pkcs1_v1_5) (void *ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out), void *ctx); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_REQUEST_OPT_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_response.h0000644000175100001660000000230014760300420023771 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_RESPONSE_H #define KMS_RESPONSE_H #include "kms_message_defines.h" #include #include #ifdef __cplusplus extern "C" { #endif typedef struct _kms_response_t kms_response_t; KMS_MSG_EXPORT (int) kms_response_get_status (kms_response_t *response); KMS_MSG_EXPORT (const char *) kms_response_get_body (kms_response_t *response, size_t *len); KMS_MSG_EXPORT (void) kms_response_destroy (kms_response_t *response); KMS_MSG_EXPORT (const char *) kms_response_get_error (const kms_response_t *response); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_RESPONSE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message/kms_response_parser.h0000644000175100001660000000361514760300420025357 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_RESPONSE_PARSER_H #define KMS_RESPONSE_PARSER_H #include "kms_message_defines.h" #include "kms_response.h" #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct _kms_response_parser_t kms_response_parser_t; KMS_MSG_EXPORT (kms_response_parser_t *) kms_response_parser_new (void); KMS_MSG_EXPORT (int) kms_response_parser_wants_bytes (kms_response_parser_t *parser, int32_t max); KMS_MSG_EXPORT (bool) kms_response_parser_feed (kms_response_parser_t *parser, uint8_t *buf, uint32_t len); KMS_MSG_EXPORT (kms_response_t *) kms_response_parser_get_response (kms_response_parser_t *parser); /* kms_response_parser_status returns the HTTP response status if one was * parsed. * - Calling on a KMIP parser is an error. * - Returns an int for the HTTP status or 0 on error. */ KMS_MSG_EXPORT (int) kms_response_parser_status (kms_response_parser_t *parser); KMS_MSG_EXPORT (const char *) kms_response_parser_error (kms_response_parser_t *parser); KMS_MSG_EXPORT (void) kms_response_parser_destroy (kms_response_parser_t *parser); KMS_MSG_EXPORT (void) kms_response_parser_reset (kms_response_parser_t *parser); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* KMS_RESPONSE_PARSER_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/hexlify.c0000644000175100001660000000276214760300420020442 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message_private.h" #include #include #include #include char * hexlify (const uint8_t *buf, size_t len) { char *hex_chars = malloc (len * 2 + 1); KMS_ASSERT (hex_chars); char *p = hex_chars; size_t i; for (i = 0; i < len; i++) { p += sprintf (p, "%02x", buf[i]); } *p = '\0'; return hex_chars; } /* Returns -1 on error. */ int unhexlify (const char *in, size_t len) { int i; int byte; int total = 0; int multiplier = 1; for (i = (int) len - 1; i >= 0; i--) { char c = *(in + i); if (c >= '0' && c <= '9') { byte = c - 48; } else if (c >= 'a' && c <= 'f') { byte = c - 97 + 10; } else if (c >= 'A' && c <= 'F') { byte = c - 65 + 10; } else { return -1; } total += byte * multiplier; multiplier *= 16; } return total; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/hexlify.h0000644000175100001660000000134214760300420020440 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include #include char * hexlify (const uint8_t *buf, size_t len); int unhexlify (const char *in, size_t len);mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_azure_request.c0000644000175100001660000001550214760300420022536 0ustar /* * Copyright 2020-present MongoDB, 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. */ #include "kms_message/kms_azure_request.h" #include "kms_message/kms_b64.h" #include "kms_message_private.h" #include "kms_request_opt_private.h" #include "kms_request_str.h" /* * Request has the following form: * * POST /{tenant ID}/oauth2/v2.0/token HTTP/1.1 * Host: {host of identify platform URL} * Content-Type: application/x-www-form-urlencoded * * client_id={client ID} * &scope=https%3A%2F%2Fvault.azure.net%2F.default * &client_secret={client secret} * &grant_type=client_credentials */ kms_request_t * kms_azure_request_oauth_new (const char *host, const char *scope, const char *tenant_id, const char *client_id, const char *client_secret, const kms_request_opt_t *opt) { char *path_and_query = NULL; char *payload = NULL; kms_request_t *req; kms_request_str_t *str; str = kms_request_str_new (); kms_request_str_appendf (str, "/%s/oauth2/v2.0/token", tenant_id); path_and_query = kms_request_str_detach (str); str = kms_request_str_new (); kms_request_str_appendf ( str, "client_id=%s&scope=%s&client_secret=%s&grant_type=client_credentials", client_id, scope, client_secret); payload = kms_request_str_detach (str); req = kms_request_new ("POST", path_and_query, opt); if (opt->provider != KMS_REQUEST_PROVIDER_AZURE) { KMS_ERROR (req, "Expected KMS request with provider type: Azure"); goto done; } if (kms_request_get_error (req)) { goto done; } if (!kms_request_add_header_field ( req, "Content-Type", "application/x-www-form-urlencoded")) { goto done; } if (!kms_request_add_header_field (req, "Host", host)) { goto done; } if (!kms_request_add_header_field (req, "Accept", "application/json")) { goto done; } if (!kms_request_append_payload (req, payload, strlen (payload))) { goto done; } done: kms_request_free_string (path_and_query); kms_request_free_string (payload); return req; } static kms_request_t * _wrap_unwrap_common (const char *wrap_unwrap, const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *value, size_t value_len, const kms_request_opt_t *opt) { char *path_and_query = NULL; char *payload = NULL; char *bearer_token_value = NULL; char *value_base64url = NULL; kms_request_t *req; kms_request_str_t *str; str = kms_request_str_new (); /* {vaultBaseUrl}/keys/{key-name}/{key-version}/wrapkey?api-version=7.1 */ kms_request_str_appendf (str, "/keys/%s/%s/%s?api-version=7.1", key_name, key_version ? key_version : "", wrap_unwrap); path_and_query = kms_request_str_detach (str); req = kms_request_new ("POST", path_and_query, opt); if (opt->provider != KMS_REQUEST_PROVIDER_AZURE) { KMS_ERROR (req, "Expected KMS request with provider type: Azure"); goto done; } if (kms_request_get_error (req)) { goto done; } value_base64url = kms_message_raw_to_b64url (value, value_len); if (!value_base64url) { KMS_ERROR (req, "Could not bases64url-encode plaintext"); goto done; } str = kms_request_str_new (); kms_request_str_appendf ( str, "{\"alg\": \"RSA-OAEP-256\", \"value\": \"%s\"}", value_base64url); payload = kms_request_str_detach (str); str = kms_request_str_new (); kms_request_str_appendf (str, "Bearer %s", access_token); bearer_token_value = kms_request_str_detach (str); if (!kms_request_add_header_field ( req, "Authorization", bearer_token_value)) { goto done; } if (!kms_request_add_header_field ( req, "Content-Type", "application/json")) { goto done; } if (!kms_request_add_header_field (req, "Host", host)) { goto done; } if (!kms_request_add_header_field (req, "Accept", "application/json")) { goto done; } if (!kms_request_append_payload (req, payload, strlen (payload))) { goto done; } done: kms_request_free_string (path_and_query); kms_request_free_string (payload); kms_request_free_string (bearer_token_value); kms_request_free_string (value_base64url); return req; } /* * Request has the following form: * * POST /keys/{key-name}/{key-version}/wrapkey?api-version=7.1 * Host: {host of key vault endpoint} * Authentication: Bearer {token} * Content-Type: application/json * * { * "alg": "RSA-OAEP-256" * "value": "base64url encoded data" * } */ kms_request_t * kms_azure_request_wrapkey_new (const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *plaintext, size_t plaintext_len, const kms_request_opt_t *opt) { return _wrap_unwrap_common ("wrapkey", host, access_token, key_name, key_version, plaintext, plaintext_len, opt); } kms_request_t * kms_azure_request_unwrapkey_new (const char *host, const char *access_token, const char *key_name, const char *key_version, const uint8_t *ciphertext, size_t ciphertext_len, const kms_request_opt_t *opt) { return _wrap_unwrap_common ("unwrapkey", host, access_token, key_name, key_version, ciphertext, ciphertext_len, opt); }mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_b64.c0000644000175100001660000004742314760300420020242 0ustar /* * Copyright (c) 1996, 1998 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include #include #include #include #include "kms_message/kms_b64.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) * The following encoding technique is taken from RFC 1521 by Borenstein * and Freed. It is reproduced here in a slightly edited form for * convenience. * * A 65-character subset of US-ASCII is used, enabling 6 bits to be * represented per printable character. (The extra 65th character, "=", * is used to signify a special processing function.) * * The encoding process represents 24-bit groups of input bits as output * strings of 4 encoded characters. Proceeding from left to right, a * 24-bit input group is formed by concatenating 3 8-bit input groups. * These 24 bits are then treated as 4 concatenated 6-bit groups, each * of which is translated into a single digit in the base64 alphabet. * * Each 6-bit group is used as an index into an array of 64 printable * characters. The character referenced by the index is placed in the * output string. * * Table 1: The Base64 Alphabet * * Value Encoding Value Encoding Value Encoding Value Encoding * 0 A 17 R 34 i 51 z * 1 B 18 S 35 j 52 0 * 2 C 19 T 36 k 53 1 * 3 D 20 U 37 l 54 2 * 4 E 21 V 38 m 55 3 * 5 F 22 W 39 n 56 4 * 6 G 23 X 40 o 57 5 * 7 H 24 Y 41 p 58 6 * 8 I 25 Z 42 q 59 7 * 9 J 26 a 43 r 60 8 * 10 K 27 b 44 s 61 9 * 11 L 28 c 45 t 62 + * 12 M 29 d 46 u 63 / * 13 N 30 e 47 v * 14 O 31 f 48 w (pad) = * 15 P 32 g 49 x * 16 Q 33 h 50 y * * Special processing is performed if fewer than 24 bits are available * at the end of the data being encoded. A full encoding quantum is * always completed at the end of a quantity. When fewer than 24 input * bits are available in an input group, zero bits are added (on the * right) to form an integral number of 6-bit groups. Padding at the * end of the data is performed using the '=' character. * * Since all base64 input is an integral number of octets, only the * following cases can arise: * * (1) the final quantum of encoding input is an integral * multiple of 24 bits; here, the final unit of encoded * output will be an integral multiple of 4 characters * with no "=" padding, * (2) the final quantum of encoding input is exactly 8 bits; * here, the final unit of encoded output will be two * characters followed by two "=" padding characters, or * (3) the final quantum of encoding input is exactly 16 bits; * here, the final unit of encoded output will be three * characters followed by one "=" padding character. */ int kms_message_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; size_t i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = (uint8_t) (((input[0] & 0x03) << 4) + (input[1] >> 4)); output[2] = (uint8_t) (((input[1] & 0x0f) << 2) + (input[2] >> 6)); output[3] = input[2] & 0x3f; KMS_ASSERT (output[0] < 64); KMS_ASSERT (output[1] < 64); KMS_ASSERT (output[2] < 64); KMS_ASSERT (output[3] < 64); if (datalength + 4 > targsize) { return -1; } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) { input[i] = *src++; } output[0] = input[0] >> 2; output[1] = (uint8_t) (((input[0] & 0x03) << 4) + (input[1] >> 4)); output[2] = (uint8_t) (((input[1] & 0x0f) << 2) + (input[2] >> 6)); KMS_ASSERT (output[0] < 64); KMS_ASSERT (output[1] < 64); KMS_ASSERT (output[2] < 64); if (datalength + 4 > targsize) { return -1; } target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) { target[datalength++] = Pad64; } else { target[datalength++] = Base64[output[2]]; } target[datalength++] = Pad64; } if (datalength >= targsize) { return -1; } target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (int) datalength; } /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ static uint8_t b64rmap[256]; static const uint8_t b64rmap_special = 0xf0; static const uint8_t b64rmap_end = 0xfd; static const uint8_t b64rmap_space = 0xfe; static const uint8_t b64rmap_invalid = 0xff; void kms_message_b64_initialize_rmap (void) { uint16_t i; unsigned char ch; /* Null: end of string, stop parsing */ b64rmap[0] = b64rmap_end; for (i = 1; i < 256; ++i) { ch = (unsigned char) i; /* Whitespaces */ if (isspace (ch)) b64rmap[i] = b64rmap_space; /* Padding: stop parsing */ else if (ch == Pad64) b64rmap[i] = b64rmap_end; /* Non-base64 char */ else b64rmap[i] = b64rmap_invalid; } /* Fill reverse mapping for base64 chars */ for (i = 0; Base64[i] != '\0'; ++i) b64rmap[(uint8_t) Base64[i]] = (uint8_t) i; } static int b64_pton_do (char const *src, uint8_t *target, size_t targsize) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = b64rmap[ch]; if (ofs >= b64rmap_special) { /* Ignore whitespaces */ if (ofs == b64rmap_space) continue; /* End of base64 characters */ if (ofs == b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: if ((size_t) tarindex >= targsize) return (-1); target[tarindex] = (uint8_t) (ofs << 2); state = 1; break; case 1: if ((size_t) tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 4; target[tarindex + 1] = (uint8_t) ((ofs & 0x0f) << 4); tarindex++; state = 2; break; case 2: if ((size_t) tarindex + 1 >= targsize) return (-1); target[tarindex] |= ofs >> 2; target[tarindex + 1] = (uint8_t) ((ofs & 0x03) << 6); tarindex++; state = 3; break; case 3: if ((size_t) tarindex >= targsize) return (-1); target[tarindex] |= ofs; tarindex++; state = 0; break; default: abort (); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void) NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void) NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target[tarindex] != 0) return (-1); default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } static int b64_pton_len (char const *src) { int tarindex, state, ch; uint8_t ofs; state = 0; tarindex = 0; while (1) { ch = *src++; ofs = b64rmap[ch]; if (ofs >= b64rmap_special) { /* Ignore whitespaces */ if (ofs == b64rmap_space) continue; /* End of base64 characters */ if (ofs == b64rmap_end) break; /* A non-base64 character. */ return (-1); } switch (state) { case 0: state = 1; break; case 1: tarindex++; state = 2; break; case 2: tarindex++; state = 3; break; case 3: tarindex++; state = 0; break; default: abort (); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void) NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void) NULL; ch != '\0'; ch = *src++) if (b64rmap[ch] != b64rmap_space) return (-1); default: break; } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } int kms_message_b64_pton (char const *src, uint8_t *target, size_t targsize) { if (target) return b64_pton_do (src, target, targsize); else return b64_pton_len (src); } int kms_message_b64_to_b64url (const char *src, size_t srclength, char *target, size_t targsize) { size_t i; for (i = 0; i < srclength; i++) { if (i >= targsize) { return -1; } target[i] = src[i]; if (target[i] == '+') { target[i] = '-'; } else if (target[i] == '/') { target[i] = '_'; } } /* NULL terminate if room. */ if (i < targsize) { target[i] = '\0'; } return (int) i; } int kms_message_b64url_to_b64 (const char *src, size_t srclength, char *target, size_t targsize) { size_t i; size_t boundary; for (i = 0; i < srclength; i++) { if (i >= targsize) { return -1; } target[i] = src[i]; if (target[i] == '-') { target[i] = '+'; } else if (target[i] == '_') { target[i] = '/'; } } /* Pad to four byte boundary. */ boundary = 4 * ((i + 3) / 4); for (; i < boundary; i++) { if (i >= targsize) { return -1; } target[i] = '='; } /* NULL terminate if room. */ if (i < targsize) { target[i] = '\0'; } return (int) i; } char * kms_message_raw_to_b64 (const uint8_t *raw, size_t raw_len) { char *b64; size_t b64_len; b64_len = (raw_len / 3 + 1) * 4 + 1; b64 = malloc (b64_len); memset (b64, 0, b64_len); if (-1 == kms_message_b64_ntop (raw, raw_len, b64, b64_len)) { free (b64); return NULL; } return b64; } uint8_t * kms_message_b64_to_raw (const char *b64, size_t *out) { uint8_t *raw; int ret; size_t b64len; b64len = strlen (b64); raw = (uint8_t *) malloc (b64len + 1); memset (raw, 0, b64len + 1); ret = kms_message_b64_pton (b64, raw, b64len); if (ret > 0) { *out = (size_t) ret; return raw; } free (raw); return NULL; } char * kms_message_raw_to_b64url (const uint8_t *raw, size_t raw_len) { char *b64; size_t b64len; b64 = kms_message_raw_to_b64 (raw, raw_len); if (!b64) { return NULL; } b64len = strlen (b64); if (-1 == kms_message_b64_to_b64url (b64, b64len, b64, b64len)) { free (b64); return NULL; } return b64; } uint8_t * kms_message_b64url_to_raw (const char *b64url, size_t *out) { char *b64; size_t capacity; uint8_t *raw; size_t b64urllen; b64urllen = strlen(b64url); /* Add four for padding '=' characters. */ capacity = b64urllen + 4; b64 = malloc (capacity); memset (b64, 0, capacity); if (-1 == kms_message_b64url_to_b64 (b64url, b64urllen, b64, capacity)) { free (b64); return NULL; } raw = kms_message_b64_to_raw (b64, out); free (b64); return raw; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_caller_identity_request.c0000644000175100001660000000275014760300420024564 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_message/kms_b64.h" #include "kms_request_str.h" kms_request_t * kms_caller_identity_request_new (const kms_request_opt_t *opt) { kms_request_t *request; kms_request_str_t *payload = NULL; request = kms_request_new ("POST", "/", opt); if (kms_request_get_error (request)) { goto done; } if (!(kms_request_add_header_field ( request, "Content-Type", "application/x-www-form-urlencoded"))) { goto done; } payload = kms_request_str_new (); kms_request_str_appendf (payload, "Action=GetCallerIdentity&Version=2011-06-15"); if (!kms_request_append_payload (request, payload->str, payload->len)) { KMS_ERROR (request, "Could not append payload"); goto done; } done: kms_request_str_destroy (payload); return request; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_crypto.h0000644000175100001660000000436414760300420021171 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_KMS_CRYPTO_H #define KMS_MESSAGE_KMS_CRYPTO_H #include #include typedef struct { bool (*sha256) (void *ctx, const char *input, size_t len, unsigned char *hash_out); bool (*sha256_hmac) (void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out); bool (*sign_rsaes_pkcs1_v1_5) (void *sign_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out); void *ctx; void *sign_ctx; } _kms_crypto_t; int kms_crypto_init (void); void kms_crypto_cleanup (void); bool kms_sha256 (void *ctx, const char *input, size_t len, unsigned char *hash_out); bool kms_sha256_hmac (void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out); /* signature_out must be a preallocated buffer of 256 bytes (or greater). */ bool kms_sign_rsaes_pkcs1_v1_5 (void *sign_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out); #endif /* KMS_MESSAGE_KMS_CRYPTO_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_crypto_apple.c0000644000175100001660000001076714760300420022351 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #include "kms_message_private.h" /* KMS_ASSERT */ #ifdef KMS_MESSAGE_ENABLE_CRYPTO_COMMON_CRYPTO #include #include #include #include #include #include int kms_crypto_init (void) { return 0; } void kms_crypto_cleanup (void) { } bool kms_sha256 (void *unused_ctx, const char *input, size_t len, unsigned char *hash_out) { CC_SHA256_CTX ctx; CC_SHA256_Init (&ctx); KMS_ASSERT (len <= (size_t) UINT32_MAX); CC_SHA256_Update (&ctx, input, (uint32_t) len); CC_SHA256_Final (hash_out, &ctx); return true; } bool kms_sha256_hmac (void *unused_ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) { CCHmac (kCCHmacAlgSHA256, key_input, key_len, input, len, hash_out); return true; } static void safe_CFRelease (CFTypeRef ptr) { if (ptr) { CFRelease (ptr); } } bool kms_sign_rsaes_pkcs1_v1_5 (void *unused_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out) { CFDataRef key_data_ref = NULL; CFDataRef pass_ref = NULL; SecItemImportExportKeyParameters import_params; OSStatus status; /* TODO: I think the expected format should be kSecFormatWrappedPKCS8, but * GCP keys appear to only load for kSecFormatBSAFE. */ SecExternalFormat format = kSecFormatUnknown; SecExternalItemType type = kSecItemTypePrivateKey; CFArrayRef out_ref = NULL; SecKeyRef key_ref = NULL; CFDataRef data_to_sign_ref = NULL; CFErrorRef error_ref; CFDataRef signature_ref = NULL; bool ret = false; key_data_ref = CFDataCreate (NULL /* default allocator */, (const uint8_t *) private_key, (CFIndex) private_key_len); if (!key_data_ref) { goto cleanup; } memset (&import_params, 0, sizeof (SecItemImportExportKeyParameters)); import_params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; /* Give an empty password. SecItemImport returns an error expecting a * password. */ pass_ref = CFDataCreate (NULL, NULL, 0); if (!pass_ref) { goto cleanup; } import_params.passphrase = (CFTypeRef) pass_ref; status = SecItemImport (key_data_ref, NULL /* extension. */, &format, &type, 0, &import_params, NULL /* keychain */, &out_ref); if (status != errSecSuccess) { goto cleanup; } if (1 != CFArrayGetCount (out_ref)) { goto cleanup; } key_ref = (SecKeyRef) CFArrayGetValueAtIndex (out_ref, 0); KMS_ASSERT (input_len <= (size_t) LONG_MAX); data_to_sign_ref = CFDataCreate (NULL, (const uint8_t *) input, (long) input_len); if (!data_to_sign_ref) { goto cleanup; } error_ref = NULL; signature_ref = SecKeyCreateSignature (key_ref, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256, data_to_sign_ref, &error_ref); if (!signature_ref) { goto cleanup; } memcpy (signature_out, CFDataGetBytePtr (signature_ref), (size_t) CFDataGetLength (signature_ref)); ret = true; cleanup: safe_CFRelease (key_data_ref); safe_CFRelease (pass_ref); safe_CFRelease (out_ref); safe_CFRelease (data_to_sign_ref); safe_CFRelease (signature_ref); return ret; } #endif /* KMS_MESSAGE_ENABLE_CRYPTO_COMMON_CRYPTO */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_crypto_libcrypto.c0000644000175100001660000000650414760300420023251 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #include "kms_message_private.h" #ifdef KMS_MESSAGE_ENABLE_CRYPTO_LIBCRYPTO #include #include #include #include /* INT_MAX, LONG_MAX */ #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) static EVP_MD_CTX * EVP_MD_CTX_new (void) { return calloc (sizeof (EVP_MD_CTX), 1); } static void EVP_MD_CTX_free (EVP_MD_CTX *ctx) { EVP_MD_CTX_cleanup (ctx); free (ctx); } #endif int kms_crypto_init (void) { return 0; } void kms_crypto_cleanup (void) { } bool kms_sha256 (void *unused_ctx, const char *input, size_t len, unsigned char *hash_out) { EVP_MD_CTX *digest_ctxp = EVP_MD_CTX_new (); bool rval = false; if (1 != EVP_DigestInit_ex (digest_ctxp, EVP_sha256 (), NULL)) { goto cleanup; } if (1 != EVP_DigestUpdate (digest_ctxp, input, len)) { goto cleanup; } rval = (1 == EVP_DigestFinal_ex (digest_ctxp, hash_out, NULL)); cleanup: EVP_MD_CTX_free (digest_ctxp); return rval; } bool kms_sha256_hmac (void *unused_ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) { KMS_ASSERT (key_len <= INT_MAX); return HMAC (EVP_sha256 (), key_input, (int) key_len, (unsigned char *) input, len, hash_out, NULL) != NULL; } bool kms_sign_rsaes_pkcs1_v1_5 (void *unused_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out) { EVP_MD_CTX *ctx; EVP_PKEY *pkey = NULL; bool ret = false; size_t signature_out_len = 256; ctx = EVP_MD_CTX_new (); KMS_ASSERT (private_key_len <= LONG_MAX); pkey = d2i_PrivateKey (EVP_PKEY_RSA, NULL, (const unsigned char **) &private_key, (long) private_key_len); if (!pkey) { goto cleanup; } ret = EVP_DigestSignInit (ctx, NULL, EVP_sha256 (), NULL /* engine */, pkey); if (ret != 1) { goto cleanup; } ret = EVP_DigestSignUpdate (ctx, input, input_len); if (ret != 1) { goto cleanup; } ret = EVP_DigestSignFinal (ctx, signature_out, &signature_out_len); if (ret != 1) { goto cleanup; } ret = true; cleanup: EVP_MD_CTX_free (ctx); EVP_PKEY_free (pkey); return ret; } #endif /* KMS_MESSAGE_ENABLE_CRYPTO_LIBCRYPTO */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_crypto_none.c0000644000175100001660000000321314760300420022173 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #ifndef KMS_MESSAGE_ENABLE_CRYPTO int kms_crypto_init (void) { return 0; } void kms_crypto_cleanup (void) { } bool kms_sha256 (void *unused_ctx, const char *input, size_t len, unsigned char *hash_out) { /* only gets called if hooks were mistakenly not set */ return false; } bool kms_sha256_hmac (void *unused_ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) { /* only gets called if hooks were mistakenly not set */ return false; } bool kms_sign_rsaes_pkcs1_v1_5 (void *unused_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out) { /* only gets called if hooks were mistakenly not set */ return false; } #endif /* KMS_MESSAGE_ENABLE_CRYPTO */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_crypto_windows.c0000644000175100001660000001647514760300420022744 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #ifdef KMS_MESSAGE_ENABLE_CRYPTO_CNG // tell windows.h not to include a bunch of headers we don't need: #define WIN32_LEAN_AND_MEAN // Tell windows.h not to define any NT status codes, so that we can // get the definitions from ntstatus.h, which has a more complete list. #define WIN32_NO_STATUS #include #undef WIN32_NO_STATUS // Obtain a definition for the ntstatus type. #include // Add back in the status definitions so that macro expansions for // things like STILL_ACTIVE and WAIT_OBJECT_O can be resolved (they // expand to STATUS_ codes). #include #include #include static BCRYPT_ALG_HANDLE _algoSHA256 = 0; static BCRYPT_ALG_HANDLE _algoSHA256Hmac = 0; static BCRYPT_ALG_HANDLE _algoRSA = 0; #define SHA_256_HASH_LEN 32 int kms_crypto_init (void) { if (BCryptOpenAlgorithmProvider ( &_algoSHA256, BCRYPT_SHA256_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0) != STATUS_SUCCESS) { return 1; } if (BCryptOpenAlgorithmProvider (&_algoSHA256Hmac, BCRYPT_SHA256_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG) != STATUS_SUCCESS) { return 2; } if (BCryptOpenAlgorithmProvider ( &_algoRSA, BCRYPT_RSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0) != STATUS_SUCCESS) { return 3; } return 0; } void kms_crypto_cleanup (void) { (void) BCryptCloseAlgorithmProvider (_algoSHA256, 0); (void) BCryptCloseAlgorithmProvider (_algoSHA256Hmac, 0); (void) BCryptCloseAlgorithmProvider (_algoRSA, 0); } bool kms_sha256 (void *unused_ctx, const char *input, size_t len, unsigned char *hash_out) { BCRYPT_HASH_HANDLE hHash; NTSTATUS status = BCryptCreateHash (_algoSHA256, &hHash, NULL, 0, NULL, 0, 0); if (status != STATUS_SUCCESS) { return 0; } status = BCryptHashData (hHash, (PUCHAR) (input), (ULONG) len, 0); if (status != STATUS_SUCCESS) { goto cleanup; } // Hardcode output length status = BCryptFinishHash (hHash, hash_out, 256 / 8, 0); if (status != STATUS_SUCCESS) { goto cleanup; } cleanup: (void) BCryptDestroyHash (hHash); return status == STATUS_SUCCESS ? 1 : 0; } bool kms_sha256_hmac (void *unused_ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) { BCRYPT_HASH_HANDLE hHash; NTSTATUS status = BCryptCreateHash ( _algoSHA256Hmac, &hHash, NULL, 0, (PUCHAR) key_input, (ULONG) key_len, 0); if (status != STATUS_SUCCESS) { return 0; } status = BCryptHashData (hHash, (PUCHAR) input, (ULONG) len, 0); if (status != STATUS_SUCCESS) { goto cleanup; } // Hardcode output length status = BCryptFinishHash (hHash, hash_out, 256 / 8, 0); if (status != STATUS_SUCCESS) { goto cleanup; } cleanup: (void) BCryptDestroyHash (hHash); return status == STATUS_SUCCESS ? 1 : 0; } bool kms_sign_rsaes_pkcs1_v1_5 (void *unused_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out) { bool success = false; bool ret = false; LPBYTE blob_private = NULL; DWORD blob_private_len = 0; LPBYTE raw_private = NULL; DWORD raw_private_len = 0; NTSTATUS status; BCRYPT_KEY_HANDLE hKey = NULL; BCRYPT_PKCS1_PADDING_INFO padding_PKCS1; unsigned char *hash_value = NULL; DWORD hash_length = 256; success = CryptDecodeObjectEx (X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, private_key, (DWORD) private_key_len, 0, NULL, NULL, &blob_private_len); if (!success) { goto cleanup; } blob_private = (LPBYTE) calloc (1, blob_private_len); success = CryptDecodeObjectEx (X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, private_key, (DWORD) private_key_len, 0, NULL, blob_private, &blob_private_len); if (!success) { goto cleanup; } CRYPT_PRIVATE_KEY_INFO *privateKeyInfo = (CRYPT_PRIVATE_KEY_INFO *) blob_private; success = CryptDecodeObjectEx (X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, privateKeyInfo->PrivateKey.pbData, (DWORD) privateKeyInfo->PrivateKey.cbData, 0, NULL, NULL, &raw_private_len); if (!success) { goto cleanup; } raw_private = (LPBYTE) calloc (1, raw_private_len); success = CryptDecodeObjectEx (X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, privateKeyInfo->PrivateKey.pbData, (DWORD) privateKeyInfo->PrivateKey.cbData, 0, NULL, raw_private, &raw_private_len); if (!success) { goto cleanup; } status = BCryptImportKeyPair ( _algoRSA, NULL, LEGACY_RSAPRIVATE_BLOB, &hKey, raw_private, raw_private_len, 0); if (!NT_SUCCESS (status)) { goto cleanup; } hash_value = calloc (1, SHA_256_HASH_LEN); if(!kms_sha256 (NULL, input, input_len, hash_value)) { goto cleanup; } padding_PKCS1.pszAlgId = BCRYPT_SHA256_ALGORITHM; status = BCryptSignHash (hKey, &padding_PKCS1, hash_value, SHA_256_HASH_LEN, signature_out, hash_length, &hash_length, BCRYPT_PAD_PKCS1); if (!NT_SUCCESS (status)) { goto cleanup; } ret = true; cleanup: BCryptDestroyKey(hKey); free (blob_private); free (raw_private); free (hash_value); return ret; } #endif /* KMS_MESSAGE_ENABLE_CRYPTO_CNG */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_decrypt_request.c0000644000175100001660000000410014760300420023052 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_message/kms_b64.h" #include "kms_request_str.h" kms_request_t * kms_decrypt_request_new (const uint8_t *ciphertext_blob, size_t len, const kms_request_opt_t *opt) { kms_request_t *request; size_t b64_len; char *b64 = NULL; kms_request_str_t *payload = NULL; request = kms_request_new ("POST", "/", opt); if (kms_request_get_error (request)) { goto done; } if (!(kms_request_add_header_field ( request, "Content-Type", "application/x-amz-json-1.1") && kms_request_add_header_field ( request, "X-Amz-Target", "TrentService.Decrypt"))) { goto done; } b64_len = (len / 3 + 1) * 4 + 1; if (!(b64 = malloc (b64_len))) { KMS_ERROR (request, "Could not allocate %d bytes for base64-encoding payload", (int) b64_len); goto done; } if (kms_message_b64_ntop (ciphertext_blob, len, b64, b64_len) == -1) { KMS_ERROR (request, "Could not base64-encode ciphertext blob"); goto done; } payload = kms_request_str_new (); kms_request_str_appendf (payload, "{\"CiphertextBlob\": \"%s\"}", b64); if (!kms_request_append_payload (request, payload->str, payload->len)) { KMS_ERROR (request, "Could not append payload"); goto done; } done: free (b64); kms_request_str_destroy (payload); return request; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_encrypt_request.c0000644000175100001660000000427214760300420023076 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_message/kms_b64.h" #include "kms_request_str.h" kms_request_t * kms_encrypt_request_new (const uint8_t *plaintext, size_t plaintext_length, const char *key_id, const kms_request_opt_t *opt) { kms_request_t *request; size_t b64_len; char *b64 = NULL; kms_request_str_t *payload = NULL; request = kms_request_new ("POST", "/", opt); if (kms_request_get_error (request)) { goto done; } if (!(kms_request_add_header_field ( request, "Content-Type", "application/x-amz-json-1.1") && kms_request_add_header_field ( request, "X-Amz-Target", "TrentService.Encrypt"))) { goto done; } b64_len = (plaintext_length / 3 + 1) * 4 + 1; if (!(b64 = malloc (b64_len))) { KMS_ERROR (request, "Could not allocate %d bytes for base64-encoding payload", (int) b64_len); goto done; } if (kms_message_b64_ntop ( (const uint8_t *) plaintext, plaintext_length, b64, b64_len) == -1) { KMS_ERROR (request, "Could not base64-encode plaintext"); goto done; } payload = kms_request_str_new (); kms_request_str_appendf ( payload, "{\"Plaintext\": \"%s\", \"KeyId\": \"%s\"}", b64, key_id); if (!kms_request_append_payload (request, payload->str, payload->len)) { KMS_ERROR (request, "Could not append payload"); goto done; } done: free (b64); kms_request_str_destroy (payload); return request; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_endian_private.h0000644000175100001660000001213414760300420022633 0ustar /* * Copyright 2021-present MongoDB, 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. */ /* This file is copied and modified from libbson's bson-endian.h. */ #ifndef KMS_ENDIAN_PRIVATE_H #define KMS_ENDIAN_PRIVATE_H #include #include "kms_message/kms_message_defines.h" /* Define a fallback for __has_builtin for compatibility with non-clang compilers. */ #ifndef __has_builtin #define __has_builtin(x) 0 #endif #if defined(__clang__) && __has_builtin(__builtin_bswap16) && \ __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) #define KMS_UINT16_SWAP_LE_BE(v) __builtin_bswap16 (v) #define KMS_UINT32_SWAP_LE_BE(v) __builtin_bswap32 (v) #define KMS_UINT64_SWAP_LE_BE(v) __builtin_bswap64 (v) #elif defined(__GNUC__) && (__GNUC__ >= 4) #if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3) #define KMS_UINT32_SWAP_LE_BE(v) __builtin_bswap32 ((uint32_t) v) #define KMS_UINT64_SWAP_LE_BE(v) __builtin_bswap64 ((uint64_t) v) #endif #if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8) #define KMS_UINT16_SWAP_LE_BE(v) __builtin_bswap16 ((uint32_t) v) #endif #endif #ifndef KMS_UINT16_SWAP_LE_BE #define KMS_UINT16_SWAP_LE_BE(v) __kms_uint16_swap_slow ((uint16_t) v) #endif #ifndef KMS_UINT32_SWAP_LE_BE #define KMS_UINT32_SWAP_LE_BE(v) __kms_uint32_swap_slow ((uint32_t) v) #endif #ifndef KMS_UINT64_SWAP_LE_BE #define KMS_UINT64_SWAP_LE_BE(v) __kms_uint64_swap_slow ((uint64_t) v) #endif #if defined(KMS_MESSAGE_LITTLE_ENDIAN) #define KMS_UINT16_FROM_LE(v) ((uint16_t) v) #define KMS_UINT16_TO_LE(v) ((uint16_t) v) #define KMS_UINT16_FROM_BE(v) KMS_UINT16_SWAP_LE_BE (v) #define KMS_UINT16_TO_BE(v) KMS_UINT16_SWAP_LE_BE (v) #define KMS_UINT32_FROM_LE(v) ((uint32_t) v) #define KMS_UINT32_TO_LE(v) ((uint32_t) v) #define KMS_UINT32_FROM_BE(v) KMS_UINT32_SWAP_LE_BE (v) #define KMS_UINT32_TO_BE(v) KMS_UINT32_SWAP_LE_BE (v) #define KMS_UINT64_FROM_LE(v) ((uint64_t) v) #define KMS_UINT64_TO_LE(v) ((uint64_t) v) #define KMS_UINT64_FROM_BE(v) KMS_UINT64_SWAP_LE_BE (v) #define KMS_UINT64_TO_BE(v) KMS_UINT64_SWAP_LE_BE (v) #elif defined(KMS_MESSAGE_BIG_ENDIAN) #define KMS_UINT16_FROM_LE(v) KMS_UINT16_SWAP_LE_BE (v) #define KMS_UINT16_TO_LE(v) KMS_UINT16_SWAP_LE_BE (v) #define KMS_UINT16_FROM_BE(v) ((uint16_t) v) #define KMS_UINT16_TO_BE(v) ((uint16_t) v) #define KMS_UINT32_FROM_LE(v) KMS_UINT32_SWAP_LE_BE (v) #define KMS_UINT32_TO_LE(v) KMS_UINT32_SWAP_LE_BE (v) #define KMS_UINT32_FROM_BE(v) ((uint32_t) v) #define KMS_UINT32_TO_BE(v) ((uint32_t) v) #define KMS_UINT64_FROM_LE(v) KMS_UINT64_SWAP_LE_BE (v) #define KMS_UINT64_TO_LE(v) KMS_UINT64_SWAP_LE_BE (v) #define KMS_UINT64_FROM_BE(v) ((uint64_t) v) #define KMS_UINT64_TO_BE(v) ((uint64_t) v) #else #error "The endianness of target architecture is unknown." #endif /* *-------------------------------------------------------------------------- * * __kms_uint16_swap_slow -- * * Fallback endianness conversion for 16-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static KMS_MSG_INLINE uint16_t __kms_uint16_swap_slow (uint16_t v) /* IN */ { return (uint16_t) (((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8)); } /* *-------------------------------------------------------------------------- * * __kms_uint32_swap_slow -- * * Fallback endianness conversion for 32-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static KMS_MSG_INLINE uint32_t __kms_uint32_swap_slow (uint32_t v) /* IN */ { return ((v & 0x000000FFU) << 24) | ((v & 0x0000FF00U) << 8) | ((v & 0x00FF0000U) >> 8) | ((v & 0xFF000000U) >> 24); } /* *-------------------------------------------------------------------------- * * __kms_uint64_swap_slow -- * * Fallback endianness conversion for 64-bit integers. * * Returns: * The endian swapped version. * * Side effects: * None. * *-------------------------------------------------------------------------- */ static KMS_MSG_INLINE uint64_t __kms_uint64_swap_slow (uint64_t v) /* IN */ { return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) | ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) | ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) | ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56); } #endif /* KMS_ENDIAN_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_gcp_request.c0000644000175100001660000002353614760300420022167 0ustar /* * Copyright 2020-present MongoDB, 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. */ #include "kms_message/kms_gcp_request.h" #include "kms_message/kms_b64.h" #include "kms_message_private.h" #include "kms_request_opt_private.h" /* Set a default expiration of 5 minutes for JSON Web Tokens (GCP allows up to * one hour) */ #define JWT_EXPIRATION_SECS 5 * 60 #define SIGNATURE_LEN 256 kms_request_t * kms_gcp_request_oauth_new (const char *host, const char *email, const char *audience, const char *scope, const char *private_key_data, size_t private_key_len, const kms_request_opt_t *opt) { kms_request_t *req = NULL; kms_request_str_t *str = NULL; time_t issued_at; /* base64 encoding of {"alg":"RS256","typ":"JWT"} */ const char *jwt_header_b64url = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9"; char *jwt_claims_b64url = NULL; char *jwt_header_and_claims_b64url = NULL; uint8_t *jwt_signature = NULL; char *jwt_signature_b64url = NULL; char *jwt_assertion_b64url = NULL; char *payload = NULL; req = kms_request_new ("POST", "/token", opt); if (opt->provider != KMS_REQUEST_PROVIDER_GCP) { KMS_ERROR (req, "Expected KMS request with provider type: GCP"); goto done; } if (kms_request_get_error (req)) { goto done; } /* Produce the signed JWT .. */ issued_at = time (NULL); str = kms_request_str_new (); kms_request_str_appendf (str, "{\"iss\": \"%s\", \"aud\": \"%s\", \"scope\": " "\"%s\", \"iat\": %lu, \"exp\": %lu}", email, audience, scope, (unsigned long) issued_at, (unsigned long) issued_at + JWT_EXPIRATION_SECS); jwt_claims_b64url = kms_message_raw_to_b64url ((const uint8_t *) str->str, str->len); kms_request_str_destroy (str); if (!jwt_claims_b64url) { KMS_ERROR (req, "Failed to base64url encode JWT claims"); goto done; } str = kms_request_str_new (); kms_request_str_appendf (str, "%s.%s", jwt_header_b64url, jwt_claims_b64url); jwt_header_and_claims_b64url = kms_request_str_detach (str); /* Produce the signature of . */ req->crypto.sign_rsaes_pkcs1_v1_5 = kms_sign_rsaes_pkcs1_v1_5; if (opt->crypto.sign_rsaes_pkcs1_v1_5) { req->crypto.sign_rsaes_pkcs1_v1_5 = opt->crypto.sign_rsaes_pkcs1_v1_5; req->crypto.sign_ctx = opt->crypto.sign_ctx; } jwt_signature = calloc (1, SIGNATURE_LEN); if (!req->crypto.sign_rsaes_pkcs1_v1_5 ( req->crypto.sign_ctx, private_key_data, private_key_len, jwt_header_and_claims_b64url, strlen (jwt_header_and_claims_b64url), jwt_signature)) { KMS_ERROR (req, "Failed to create GCP oauth request signature"); goto done; } jwt_signature_b64url = kms_message_raw_to_b64url (jwt_signature, SIGNATURE_LEN); if (!jwt_signature_b64url) { KMS_ERROR (req, "Failed to base64url encode JWT signature"); goto done; } str = kms_request_str_new (); kms_request_str_appendf (str, "%s.%s.%s", jwt_header_b64url, jwt_claims_b64url, jwt_signature_b64url); jwt_assertion_b64url = kms_request_str_detach (str); str = kms_request_str_new_from_chars ("grant_type=urn%3Aietf%3Aparams%3Aoauth%" "3Agrant-type%3Ajwt-bearer&assertion=", -1); kms_request_str_append_chars (str, jwt_assertion_b64url, -1); payload = kms_request_str_detach (str); if (!kms_request_add_header_field ( req, "Content-Type", "application/x-www-form-urlencoded")) { goto done; } if (!kms_request_add_header_field (req, "Host", host)) { goto done; } if (!kms_request_add_header_field (req, "Accept", "application/json")) { goto done; } if (!kms_request_append_payload (req, payload, strlen (payload))) { goto done; } done: free (jwt_signature); free (jwt_signature_b64url); free (jwt_claims_b64url); free (jwt_header_and_claims_b64url); free (jwt_assertion_b64url); free (payload); return req; } static kms_request_t * _encrypt_decrypt_common (const char *encrypt_decrypt, const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const char *key_version, const uint8_t *value, size_t value_len, const kms_request_opt_t *opt) { char *path_and_query = NULL; char *payload = NULL; char *bearer_token_value = NULL; char *value_base64 = NULL; kms_request_t *req; kms_request_str_t *str; str = kms_request_str_new (); /* /v1/projects/{project-id}/locations/{location}/keyRings/{key-ring-name}/cryptoKeys/{key-name} */ kms_request_str_appendf ( str, "/v1/projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", project_id, location, key_ring_name, key_name); if (key_version && strlen (key_version) > 0) { kms_request_str_appendf (str, "/cryptoKeyVersions/%s", key_version); } kms_request_str_appendf (str, ":%s", encrypt_decrypt); path_and_query = kms_request_str_detach (str); req = kms_request_new ("POST", path_and_query, opt); if (opt->provider != KMS_REQUEST_PROVIDER_GCP) { KMS_ERROR (req, "Expected KMS request with provider type: GCP"); goto done; } if (kms_request_get_error (req)) { goto done; } value_base64 = kms_message_raw_to_b64 (value, value_len); if (!value_base64) { KMS_ERROR (req, "Could not bases64-encode plaintext"); goto done; } str = kms_request_str_new (); if (0 == strcmp ("encrypt", encrypt_decrypt)) { kms_request_str_appendf (str, "{\"plaintext\": \"%s\"}", value_base64); } else { kms_request_str_appendf (str, "{\"ciphertext\": \"%s\"}", value_base64); } payload = kms_request_str_detach (str); str = kms_request_str_new (); kms_request_str_appendf (str, "Bearer %s", access_token); bearer_token_value = kms_request_str_detach (str); if (!kms_request_add_header_field ( req, "Authorization", bearer_token_value)) { goto done; } if (!kms_request_add_header_field ( req, "Content-Type", "application/json")) { goto done; } if (!kms_request_add_header_field (req, "Host", host)) { goto done; } if (!kms_request_add_header_field (req, "Accept", "application/json")) { goto done; } if (!kms_request_append_payload (req, payload, strlen (payload))) { goto done; } done: kms_request_free_string (path_and_query); kms_request_free_string (payload); kms_request_free_string (bearer_token_value); kms_request_free_string (value_base64); return req; } kms_request_t * kms_gcp_request_encrypt_new (const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const char *key_version, const uint8_t *plaintext, size_t plaintext_len, const kms_request_opt_t *opt) { return _encrypt_decrypt_common ("encrypt", host, access_token, project_id, location, key_ring_name, key_name, key_version, plaintext, plaintext_len, opt); } kms_request_t * kms_gcp_request_decrypt_new (const char *host, const char *access_token, const char *project_id, const char *location, const char *key_ring_name, const char *key_name, const uint8_t *ciphertext, size_t ciphertext_len, const kms_request_opt_t *opt) { return _encrypt_decrypt_common ("decrypt", host, access_token, project_id, location, key_ring_name, key_name, NULL /* key_version */, ciphertext, ciphertext_len, opt); }mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_item_type_private.h0000644000175100001660000000331014760300420024410 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_ITEM_TYPE_PRIVATE_H #define KMS_KMIP_ITEM_TYPE_PRIVATE_H #include "kms_message/kms_message_defines.h" #define KMS_XMACRO \ KMS_X (Structure, 0x01) \ KMS_X (Integer, 0x02) \ KMS_X (LongInteger, 0x03) \ KMS_X (BigInteger, 0x04) \ KMS_X (Enumeration, 0x05) \ KMS_X (Boolean, 0x06) \ KMS_X (TextString, 0x07) \ KMS_X (ByteString, 0x08) \ KMS_X (DateTime, 0x09) \ KMS_X_LAST (Interval, 0x0A) /* Generate an enum with each item_type value. */ #define KMS_X(ITEM_TYPE, VAL) KMIP_ITEM_TYPE_##ITEM_TYPE = VAL, #define KMS_X_LAST(ITEM_TYPE, VAL) KMIP_ITEM_TYPE_##ITEM_TYPE = VAL typedef enum { KMS_XMACRO } kmip_item_type_t; #undef KMS_X #undef KMS_X_LAST #define KMS_X(ITEM_TYPE, VAL) \ case KMIP_ITEM_TYPE_##ITEM_TYPE: \ return #ITEM_TYPE; #define KMS_X_LAST KMS_X static KMS_MSG_INLINE const char * kmip_item_type_to_string (kmip_item_type_t item_type) { switch (item_type) { default: return "Unknown KMIP item type"; KMS_XMACRO } } #undef KMS_X #undef KMS_X_LAST #undef KMS_XMACRO #endif /* KMS_KMIP_ITEM_TYPE_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_reader_writer.c0000644000175100001660000003133314760300420023516 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "kms_kmip_reader_writer_private.h" #include "kms_endian_private.h" #include "kms_request_str.h" #include #define MAX_KMIP_WRITER_POSITIONS 10 /* KMIP encodes signed integers with two's complement. * Parsing functions read Integer / LongInteger as int32_t / int64_t by * reinterpreting byte representation. * Ensure that platform represents integers in two's complement. * See: https://stackoverflow.com/a/64843863/774658 */ #if (-1 & 3) != 3 #error Error: Twos complement integer representation is required. #endif struct _kmip_writer_t { kms_request_str_t *buffer; size_t positions[MAX_KMIP_WRITER_POSITIONS]; size_t cur_pos; }; kmip_writer_t * kmip_writer_new (void) { kmip_writer_t *writer = calloc (1, sizeof (kmip_writer_t)); writer->buffer = kms_request_str_new (); return writer; } void kmip_writer_destroy (kmip_writer_t *writer) { kms_request_str_destroy (writer->buffer); free (writer); } void kmip_writer_write_u8 (kmip_writer_t *writer, uint8_t value) { char *c = (char *) &value; kms_request_str_append_chars (writer->buffer, c, 1); } void kmip_writer_write_u16 (kmip_writer_t *writer, uint16_t value) { uint16_t v = KMS_UINT16_TO_BE (value); char *c = (char *) &v; kms_request_str_append_chars (writer->buffer, c, 2); } void kmip_writer_write_u32 (kmip_writer_t *writer, uint32_t value) { uint32_t v = KMS_UINT32_TO_BE (value); char *c = (char *) &v; kms_request_str_append_chars (writer->buffer, c, 4); } void kmip_writer_write_u64 (kmip_writer_t *writer, uint64_t value) { uint64_t v = KMS_UINT64_TO_BE (value); char *c = (char *) &v; kms_request_str_append_chars (writer->buffer, c, 8); } void kmip_writer_write_tag_enum (kmip_writer_t *writer, kmip_tag_type_t tag) { /* The 0x42 prefix is for tags built into the protocol. */ /* The 0x54 prefix is for extension tags. */ kmip_writer_write_u8 (writer, 0x42); kmip_writer_write_u16 (writer, (uint16_t) tag); } static size_t compute_padded_length (size_t len) { if (len % 8 == 0) { return len; } size_t padding = 8 - (len % 8); return len + padding; } void kmip_writer_write_string (kmip_writer_t *writer, kmip_tag_type_t tag, const char *str, size_t len) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_TextString); kmip_writer_write_u32 (writer, (uint32_t) len); size_t i; for (i = 0; i < len; i++) { kmip_writer_write_u8 (writer, (uint8_t) str[i]); } size_t padded_length = compute_padded_length (len); for (i = 0; i < padded_length - len; i++) { kmip_writer_write_u8 (writer, 0); } } void kmip_writer_write_bytes (kmip_writer_t *writer, kmip_tag_type_t tag, const char *str, size_t len) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_ByteString); kmip_writer_write_u32 (writer, (uint32_t) len); size_t i; for (i = 0; i < len; i++) { kmip_writer_write_u8 (writer, (uint8_t) str[i]); } size_t padded_length = compute_padded_length (len); for (i = 0; i < padded_length - len; i++) { kmip_writer_write_u8 (writer, 0); } } void kmip_writer_write_integer (kmip_writer_t *writer, kmip_tag_type_t tag, int32_t value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_Integer); kmip_writer_write_u32 (writer, 4); KMS_ASSERT (value >= 0); kmip_writer_write_u32 (writer, (uint32_t) value); kmip_writer_write_u32 (writer, 0); } void kmip_writer_write_long_integer (kmip_writer_t *writer, kmip_tag_type_t tag, int64_t value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_LongInteger); kmip_writer_write_u32 (writer, 8); KMS_ASSERT (value >= 0); kmip_writer_write_u64 (writer, (uint64_t) value); } void kmip_writer_write_enumeration (kmip_writer_t *writer, kmip_tag_type_t tag, int32_t value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_Enumeration); kmip_writer_write_u32 (writer, 4); KMS_ASSERT (value >= 0); kmip_writer_write_u32 (writer, (uint32_t) value); kmip_writer_write_u32 (writer, 0); } void kmip_writer_write_bool (kmip_writer_t *writer, kmip_tag_type_t tag, bool value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_Boolean); kmip_writer_write_u32 (writer, 8); kmip_writer_write_u64(writer, (uint64_t) value); } void kmip_writer_write_datetime (kmip_writer_t *writer, kmip_tag_type_t tag, int64_t value) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_DateTime); kmip_writer_write_u32 (writer, 8); KMS_ASSERT (value >= 0); kmip_writer_write_u64 (writer, (uint64_t) value); } void kmip_writer_begin_struct (kmip_writer_t *writer, kmip_tag_type_t tag) { kmip_writer_write_tag_enum (writer, tag); kmip_writer_write_u8 (writer, KMIP_ITEM_TYPE_Structure); size_t pos = writer->buffer->len; kmip_writer_write_u32 (writer, 0); KMS_ASSERT(writer->cur_pos < MAX_KMIP_WRITER_POSITIONS); writer->cur_pos++; writer->positions[writer->cur_pos] = pos; } void kmip_writer_close_struct (kmip_writer_t *writer) { size_t current_pos = writer->buffer->len; KMS_ASSERT(writer->cur_pos > 0); size_t start_pos = writer->positions[writer->cur_pos]; writer->cur_pos--; /* offset by 4 */ uint32_t len = (uint32_t) (current_pos - start_pos - 4); uint32_t v = KMS_UINT32_TO_BE (len); char *c = (char *) &v; memcpy (writer->buffer->str + start_pos, c, 4); } const uint8_t * kmip_writer_get_buffer (kmip_writer_t *writer, size_t* len) { *len = writer->buffer->len; return (const uint8_t*) writer->buffer->str; } struct _kmip_reader_t { uint8_t *ptr; size_t pos; size_t len; }; kmip_reader_t * kmip_reader_new (uint8_t *ptr, size_t len) { kmip_reader_t *reader = calloc (1, sizeof (kmip_reader_t)); reader->ptr = ptr; reader->len = len; return reader; } void kmip_reader_destroy (kmip_reader_t *reader) { free (reader); } bool kmip_reader_in_place (kmip_reader_t *reader, size_t pos, size_t len, kmip_reader_t *out_reader) { /* Everything should be padding to 8 byte boundaries. */ len = compute_padded_length (len); if ((pos + len) > reader->len) { return false; } memset (out_reader, 0, sizeof (kmip_reader_t)); out_reader->ptr = reader->ptr + reader->pos; out_reader->len = len; return true; } bool kmip_reader_has_data (kmip_reader_t *reader) { return reader->pos < reader->len; } #define CHECK_REMAINING_BUFFER_AND_RET(read_size) \ if ((reader->pos + (read_size)) > reader->len) { \ return false; \ } bool kmip_reader_read_u8 (kmip_reader_t *reader, uint8_t *value) { CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint8_t)); *value = *(reader->ptr + reader->pos); reader->pos += sizeof (uint8_t); return true; } bool kmip_reader_read_u16 (kmip_reader_t *reader, uint16_t *value) { CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint16_t)); uint16_t temp; memcpy (&temp, reader->ptr + reader->pos, sizeof (uint16_t)); *value = KMS_UINT16_FROM_BE (temp); reader->pos += sizeof (uint16_t); return true; } bool kmip_reader_read_u32 (kmip_reader_t *reader, uint32_t *value) { CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint32_t)); uint32_t temp; memcpy (&temp, reader->ptr + reader->pos, sizeof (uint32_t)); *value = KMS_UINT32_FROM_BE (temp); reader->pos += sizeof (uint32_t); return true; } bool kmip_reader_read_u64 (kmip_reader_t *reader, uint64_t *value) { CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint64_t)); uint64_t temp; memcpy (&temp, reader->ptr + reader->pos, sizeof (uint64_t)); *value = KMS_UINT64_FROM_BE (temp); reader->pos += sizeof (uint64_t); return true; } bool kmip_reader_read_bytes (kmip_reader_t *reader, uint8_t **ptr, size_t length) { size_t advance_length = compute_padded_length (length); CHECK_REMAINING_BUFFER_AND_RET (advance_length); *ptr = reader->ptr + reader->pos; reader->pos += advance_length; return true; } #define CHECK_AND_RET(x) \ if (!(x)) { \ return false; \ } bool kmip_reader_read_tag (kmip_reader_t *reader, kmip_tag_type_t *tag) { uint8_t tag_first; CHECK_AND_RET (kmip_reader_read_u8 (reader, &tag_first)); if (tag_first != 0x42) { return false; } uint16_t tag_second; CHECK_AND_RET (kmip_reader_read_u16 (reader, &tag_second)); *tag = (kmip_tag_type_t) (0x420000 + tag_second); return true; } bool kmip_reader_read_length (kmip_reader_t *reader, uint32_t *length) { return kmip_reader_read_u32 (reader, length); } bool kmip_reader_read_type (kmip_reader_t *reader, kmip_item_type_t *type) { uint8_t u8; CHECK_AND_RET (kmip_reader_read_u8 (reader, &u8)); *type = (kmip_item_type_t) u8; return true; } bool kmip_reader_read_enumeration (kmip_reader_t *reader, uint32_t *enum_value) { CHECK_AND_RET (kmip_reader_read_u32 (reader, enum_value)); /* Skip 4 bytes because enums are padded. */ uint32_t ignored; return kmip_reader_read_u32 (reader, &ignored); } bool kmip_reader_read_bool (kmip_reader_t *reader, bool *value) { uint64_t u64; CHECK_AND_RET (kmip_reader_read_u64 (reader, &u64)); *value = (bool) u64; return true; } bool kmip_reader_read_integer (kmip_reader_t *reader, int32_t *value) { CHECK_AND_RET (kmip_reader_read_u32 (reader, (uint32_t*) value)); /* Skip 4 bytes because integers are padded. */ uint32_t ignored; return kmip_reader_read_u32 (reader, &ignored); } bool kmip_reader_read_long_integer (kmip_reader_t *reader, int64_t *value) { return kmip_reader_read_u64 (reader, (uint64_t*) value); } bool kmip_reader_read_string (kmip_reader_t *reader, uint8_t **ptr, size_t length) { return kmip_reader_read_bytes (reader, ptr, length); } bool kmip_reader_find (kmip_reader_t *reader, kmip_tag_type_t search_tag, kmip_item_type_t type, size_t *pos, size_t *length) { reader->pos = 0; while (kmip_reader_has_data (reader)) { kmip_tag_type_t read_tag; CHECK_AND_RET (kmip_reader_read_tag (reader, &read_tag)); kmip_item_type_t read_type; CHECK_AND_RET (kmip_reader_read_type (reader, &read_type)); uint32_t read_length; CHECK_AND_RET (kmip_reader_read_length (reader, &read_length)); if (read_tag == search_tag && read_type == type) { *pos = reader->pos; *length = read_length; return true; } size_t advance_length = read_length; advance_length = compute_padded_length (advance_length); CHECK_REMAINING_BUFFER_AND_RET (advance_length); /* Skip to the next type. */ reader->pos += advance_length; } return false; } bool kmip_reader_find_and_recurse (kmip_reader_t *reader, kmip_tag_type_t tag) { size_t pos; size_t length; if (!kmip_reader_find (reader, tag, KMIP_ITEM_TYPE_Structure, &pos, &length)) { return false; } reader->pos = 0; reader->ptr = reader->ptr + pos; reader->len = length; return true; } bool kmip_reader_find_and_read_enum (kmip_reader_t *reader, kmip_tag_type_t tag, uint32_t *value) { size_t pos; size_t length; if (!kmip_reader_find (reader, tag, KMIP_ITEM_TYPE_Enumeration, &pos, &length)) { return false; } kmip_reader_t temp_reader; if (!kmip_reader_in_place (reader, pos, length, &temp_reader)) { return false; } return kmip_reader_read_enumeration (&temp_reader, value); } bool kmip_reader_find_and_read_bytes (kmip_reader_t *reader, kmip_tag_type_t tag, uint8_t **out_ptr, size_t *out_len) { size_t pos; if (!kmip_reader_find (reader, tag, KMIP_ITEM_TYPE_ByteString, &pos, out_len)) { return false; } kmip_reader_t temp_reader; if (!kmip_reader_in_place (reader, pos, *out_len, &temp_reader)) { return false; } return kmip_reader_read_bytes (&temp_reader, out_ptr, *out_len); } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_reader_writer_private.h0000644000175100001660000001043614760300420025256 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_READER_WRITER_PRIVATE_H #define KMS_KMIP_READER_WRITER_PRIVATE_H #include "kms_kmip_item_type_private.h" #include "kms_kmip_tag_type_private.h" #include "kms_message_private.h" #include typedef struct _kmip_writer_t kmip_writer_t; kmip_writer_t * kmip_writer_new (void); void kmip_writer_destroy (kmip_writer_t *writer); void kmip_writer_write_u8 (kmip_writer_t *writer, uint8_t value); void kmip_writer_write_u16 (kmip_writer_t *writer, uint16_t value); void kmip_writer_write_u32 (kmip_writer_t *writer, uint32_t value); void kmip_writer_write_u64 (kmip_writer_t *writer, uint64_t value); void kmip_writer_write_tag_enum (kmip_writer_t *writer, kmip_tag_type_t tag); void kmip_writer_write_string (kmip_writer_t *writer, kmip_tag_type_t tag, const char *str, size_t len); void kmip_writer_write_bytes (kmip_writer_t *writer, kmip_tag_type_t tag, const char *str, size_t len); void kmip_writer_write_integer (kmip_writer_t *writer, kmip_tag_type_t tag, int32_t value); void kmip_writer_write_long_integer (kmip_writer_t *writer, kmip_tag_type_t tag, int64_t value); void kmip_writer_write_enumeration (kmip_writer_t *writer, kmip_tag_type_t tag, int32_t value); void kmip_writer_write_bool (kmip_writer_t *writer, kmip_tag_type_t tag, bool value); void kmip_writer_write_datetime (kmip_writer_t *writer, kmip_tag_type_t tag, int64_t value); void kmip_writer_begin_struct (kmip_writer_t *writer, kmip_tag_type_t tag); void kmip_writer_close_struct (kmip_writer_t *writer); const uint8_t * kmip_writer_get_buffer (kmip_writer_t *writer, size_t* len); typedef struct _kmip_reader_t kmip_reader_t; kmip_reader_t * kmip_reader_new (uint8_t *ptr, size_t len); void kmip_reader_destroy (kmip_reader_t *reader); bool kmip_reader_in_place (kmip_reader_t *reader, size_t pos, size_t len, kmip_reader_t *out_reader); bool kmip_reader_has_data (kmip_reader_t *reader); bool kmip_reader_read_u8 (kmip_reader_t *reader, uint8_t *value); bool kmip_reader_read_u16 (kmip_reader_t *reader, uint16_t *value); bool kmip_reader_read_u32 (kmip_reader_t *reader, uint32_t *value); bool kmip_reader_read_u64 (kmip_reader_t *reader, uint64_t *value); bool kmip_reader_read_tag (kmip_reader_t *reader, kmip_tag_type_t *tag); bool kmip_reader_read_length (kmip_reader_t *reader, uint32_t *length); bool kmip_reader_read_type (kmip_reader_t *reader, kmip_item_type_t *type); bool kmip_reader_read_enumeration (kmip_reader_t *reader, uint32_t *enum_value); bool kmip_reader_read_bool (kmip_reader_t *reader, bool *value); bool kmip_reader_read_integer (kmip_reader_t *reader, int32_t *value); bool kmip_reader_read_long_integer (kmip_reader_t *reader, int64_t *value); bool kmip_reader_read_bytes (kmip_reader_t *reader, uint8_t **ptr, size_t length); bool kmip_reader_read_string (kmip_reader_t *reader, uint8_t **ptr, size_t length); /* kmip_reader_find does not descend structures. * To find and descend into a structure use kmip_reader_find_and_recurse. */ bool kmip_reader_find (kmip_reader_t *reader, kmip_tag_type_t search_tag, kmip_item_type_t type, size_t *pos, size_t *length); bool kmip_reader_find_and_recurse (kmip_reader_t *reader, kmip_tag_type_t tag); bool kmip_reader_find_and_read_enum (kmip_reader_t *reader, kmip_tag_type_t tag, uint32_t *value); bool kmip_reader_find_and_read_bytes (kmip_reader_t *reader, kmip_tag_type_t tag, uint8_t **out_ptr, size_t *out_len); #endif /* KMS_KMIP_READER_WRITER_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_request.c0000644000175100001660000004724014760300420022354 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "kms_message/kms_kmip_request.h" #include "kms_kmip_tag_type_private.h" #include "kms_message_private.h" #include "kms_kmip_reader_writer_private.h" #include #include static void copy_writer_buffer (kms_request_t *req, kmip_writer_t *writer) { const uint8_t *buf; size_t buflen; buf = kmip_writer_get_buffer (writer, &buflen); req->kmip.data = malloc (buflen); memcpy (req->kmip.data, buf, buflen); req->kmip.len = (uint32_t) buflen; } kms_request_t * kms_kmip_request_register_secretdata_new (void *reserved, const uint8_t *data, size_t len) { /* Create a KMIP Register request with a 96 byte SecretData of this form: */ kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; if (len != KMS_KMIP_REQUEST_SECRETDATA_LENGTH) { KMS_ERROR (req, "expected SecretData length of %d, got %" PRIu32, KMS_KMIP_REQUEST_SECRETDATA_LENGTH, len); return req; } writer = kmip_writer_new (); kmip_writer_begin_struct (writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 0); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x03 == Register */ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, 0x03); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); /* 0x07 == SecretData */ kmip_writer_write_enumeration (writer, KMIP_TAG_ObjectType, 0x07); kmip_writer_begin_struct (writer, KMIP_TAG_TemplateAttribute); // Add required Cryptographic Usage Mask attribute. { kmip_writer_begin_struct (writer, KMIP_TAG_Attribute); const char *cryptographicUsageMaskStr = "Cryptographic Usage Mask"; kmip_writer_write_string (writer, KMIP_TAG_AttributeName, cryptographicUsageMaskStr, strlen (cryptographicUsageMaskStr)); // Use 0 because the Secret Data object is not used in cryptographic // operations on the KMIP server. kmip_writer_write_integer (writer, KMIP_TAG_AttributeValue, 0); kmip_writer_close_struct (writer); } kmip_writer_close_struct (writer); /* KMIP_TAG_TemplateAttribute */ kmip_writer_begin_struct (writer, KMIP_TAG_SecretData); /* 0x02 = Seed */ kmip_writer_write_enumeration (writer, KMIP_TAG_SecretDataType, 0x02); kmip_writer_begin_struct (writer, KMIP_TAG_KeyBlock); /* 0x02 = Opaque */ kmip_writer_write_enumeration (writer, KMIP_TAG_KeyFormatType, 0x02); kmip_writer_begin_struct (writer, KMIP_TAG_KeyValue); kmip_writer_write_bytes ( writer, KMIP_TAG_KeyMaterial, (const char *) data, len); kmip_writer_close_struct (writer); /* KMIP_TAG_KeyValue */ kmip_writer_close_struct (writer); /* KMIP_TAG_KeyBlock */ kmip_writer_close_struct (writer); /* KMIP_TAG_SecretData */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } kms_request_t * kms_kmip_request_activate_new (void *reserved, const char *unique_identifer) { /* Create a KMIP Activate request of this form: */ kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; writer = kmip_writer_new (); kmip_writer_begin_struct (writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 0); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x12 == Activate */ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, 0x12); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); kmip_writer_write_string (writer, KMIP_TAG_UniqueIdentifier, unique_identifer, strlen (unique_identifer)); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } kms_request_t * kms_kmip_request_get_new (void *reserved, const char *unique_identifer) { /* Create a KMIP Get request of this form: */ kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; writer = kmip_writer_new (); kmip_writer_begin_struct (writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 0); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x0A == Get */ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, 0x0A); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); kmip_writer_write_string (writer, KMIP_TAG_UniqueIdentifier, unique_identifer, strlen (unique_identifer)); /* 0x01 = Raw */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ /* Copy the KMIP writer buffer to a KMIP request. */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } kms_request_t * kms_kmip_request_create_new (void *reserved) { /* Create a KMIP Create request of this form: */ kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; writer = kmip_writer_new(); kmip_writer_begin_struct(writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 2); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x01 == Create */ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, 0x01); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); /* 0x02 == symmetric key */ kmip_writer_write_enumeration(writer, KMIP_TAG_ObjectType, 0x02); { kmip_writer_begin_struct (writer, KMIP_TAG_TemplateAttribute); kmip_writer_begin_struct (writer, KMIP_TAG_Attribute); const char *cryptographicAlgorithmStr = "Cryptographic Algorithm"; kmip_writer_write_string (writer, KMIP_TAG_AttributeName, cryptographicAlgorithmStr, strlen (cryptographicAlgorithmStr)); kmip_writer_write_enumeration (writer, KMIP_TAG_AttributeValue, 3 /* AES */); kmip_writer_close_struct (writer); kmip_writer_begin_struct (writer, KMIP_TAG_Attribute); const char *cryptographicLengthStr = "Cryptographic Length"; kmip_writer_write_string (writer, KMIP_TAG_AttributeName, cryptographicLengthStr, strlen (cryptographicLengthStr)); kmip_writer_write_integer (writer, KMIP_TAG_AttributeValue, 256); kmip_writer_close_struct (writer); kmip_writer_begin_struct (writer, KMIP_TAG_Attribute); const char *cryptographicUsageMaskStr = "Cryptographic Usage Mask"; kmip_writer_write_string (writer, KMIP_TAG_AttributeName, cryptographicUsageMaskStr, strlen (cryptographicUsageMaskStr)); kmip_writer_write_integer (writer, KMIP_TAG_AttributeValue, 4 | 8 /* Encrypt | Decrypt */); kmip_writer_close_struct (writer); kmip_writer_close_struct (writer); /* KMIP_TAG_TemplateAttribute */ } kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ /* Copy the KMIP writer buffer to a KMIP request. */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } static kms_request_t * kmip_encrypt_decrypt (const char* unique_identifer, const uint8_t *data, size_t len, const uint8_t *iv_data, size_t iv_len, bool encrypt) { kmip_writer_t *writer; kms_request_t *req; req = calloc (1, sizeof (kms_request_t)); req->provider = KMS_REQUEST_PROVIDER_KMIP; writer = kmip_writer_new(); kmip_writer_begin_struct(writer, KMIP_TAG_RequestMessage); kmip_writer_begin_struct (writer, KMIP_TAG_RequestHeader); kmip_writer_begin_struct (writer, KMIP_TAG_ProtocolVersion); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMajor, 1); kmip_writer_write_integer (writer, KMIP_TAG_ProtocolVersionMinor, 2); kmip_writer_close_struct (writer); /* KMIP_TAG_ProtocolVersion */ kmip_writer_write_integer (writer, KMIP_TAG_BatchCount, 1); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestHeader */ kmip_writer_begin_struct (writer, KMIP_TAG_BatchItem); /* 0x1F == Encrypt, 0x20 == Decrypt*/ kmip_writer_write_enumeration (writer, KMIP_TAG_Operation, encrypt ? 0x1F : 0x20); kmip_writer_begin_struct (writer, KMIP_TAG_RequestPayload); kmip_writer_write_string (writer, KMIP_TAG_UniqueIdentifier, unique_identifer, strlen (unique_identifer)); kmip_writer_begin_struct (writer, KMIP_TAG_CryptographicParameters); kmip_writer_write_enumeration(writer, KMIP_TAG_BlockCipherMode, 1 /* CBC */); kmip_writer_write_enumeration(writer, KMIP_TAG_PaddingMethod, 3 /* PKCS5 */); kmip_writer_write_enumeration(writer, KMIP_TAG_CryptographicAlgorithm, 3 /* AES */); if (encrypt) kmip_writer_write_bool(writer, KMIP_TAG_RandomIV, true); kmip_writer_close_struct(writer); /* KMIP_TAG_CryptographicParameters */ kmip_writer_write_bytes(writer, KMIP_TAG_Data, (char *) data, len); if (!encrypt) kmip_writer_write_bytes(writer, KMIP_TAG_IVCounterNonce, (char *) iv_data, iv_len); kmip_writer_close_struct (writer); /* KMIP_TAG_RequestPayload */ kmip_writer_close_struct (writer); /* KMIP_TAG_BatchItem */ kmip_writer_close_struct (writer); /* KMIP_TAG_RequestMessage */ /* Copy the KMIP writer buffer to a KMIP request. */ copy_writer_buffer (req, writer); kmip_writer_destroy (writer); return req; } kms_request_t * kms_kmip_request_encrypt_new (void *reserved, const char* unique_identifer, const uint8_t *plaintext, size_t len) { /* Create a KMIP Encrypt request of this form: */ return kmip_encrypt_decrypt(unique_identifer, plaintext, len, NULL, 0, true); } kms_request_t * kms_kmip_request_decrypt_new (void *reserved, const char* unique_identifer, const uint8_t *ciphertext, size_t len, const uint8_t *iv_data, size_t iv_len) { /* Create a KMIP Decrypt request of this form: */ return kmip_encrypt_decrypt(unique_identifer, ciphertext, len, iv_data, iv_len, false); } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_response.c0000644000175100001660000003611314760300420022517 0ustar #include "kms_message/kms_kmip_response.h" #include "kms_kmip_item_type_private.h" #include "kms_kmip_tag_type_private.h" #include "kms_message_private.h" #include "kms_kmip_reader_writer_private.h" #include "kms_kmip_result_reason_private.h" #include "kms_kmip_result_status_private.h" #include #include #include /* CHAR_BIT */ static bool check_and_require_kmip (kms_response_t *res) { if (res->provider != KMS_REQUEST_PROVIDER_KMIP) { KMS_ERROR (res, "Function requires KMIP request"); return false; } return true; } /* Example of an error message: */ static bool kms_kmip_response_ok (kms_response_t *res) { kmip_reader_t *reader = NULL; size_t pos; size_t len; uint32_t result_status; uint32_t result_reason = 0; const char *result_message = ""; uint32_t result_message_len = 0; bool ok = false; reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } /* Look for optional Result Reason. */ if (kmip_reader_find (reader, KMIP_TAG_ResultReason, KMIP_ITEM_TYPE_Enumeration, &pos, &len)) { if (!kmip_reader_read_enumeration (reader, &result_reason)) { KMS_ERROR (res, "unable to read result reason value"); goto fail; } } /* Look for optional Result Message. */ if (kmip_reader_find (reader, KMIP_TAG_ResultMessage, KMIP_ITEM_TYPE_TextString, &pos, &len)) { if (!kmip_reader_read_string ( reader, (uint8_t **) &result_message, len)) { KMS_ERROR (res, "unable to read result message value"); goto fail; } result_message_len = (uint32_t) len; } /* Look for required Result Status. */ if (!kmip_reader_find (reader, KMIP_TAG_ResultStatus, KMIP_ITEM_TYPE_Enumeration, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResultStatus)); goto fail; } if (!kmip_reader_read_enumeration (reader, &result_status)) { KMS_ERROR (res, "unable to read result status value"); goto fail; } if (result_status != KMIP_RESULT_STATUS_OperationSuccess) { KMS_ERROR (res, "KMIP response error. Result Status (%" PRIu32 "): %s. Result Reason (%" PRIu32 "): %s. Result Message: %.*s", result_status, kmip_result_status_to_string (result_status), result_reason, kmip_result_reason_to_string (result_reason), result_message_len, result_message); goto fail; } ok = true; fail: kmip_reader_destroy (reader); return ok; } /* Example of a successful response to a Register request: */ char * kms_kmip_response_get_unique_identifier (kms_response_t *res) { kmip_reader_t *reader = NULL; size_t pos; size_t len; char *uid = NULL; kms_request_str_t *nullterminated = NULL; if (!check_and_require_kmip (res)) { goto fail; } if (!kms_kmip_response_ok (res)) { goto fail; } reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponsePayload)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponsePayload)); goto fail; } if (!kmip_reader_find (reader, KMIP_TAG_UniqueIdentifier, KMIP_ITEM_TYPE_TextString, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_UniqueIdentifier)); goto fail; } if (!kmip_reader_read_string (reader, (uint8_t **) &uid, len)) { KMS_ERROR (res, "unable to read unique identifier"); goto fail; } KMS_ASSERT (len <= SSIZE_MAX); nullterminated = kms_request_str_new_from_chars (uid, (ssize_t) len); fail: kmip_reader_destroy (reader); return kms_request_str_detach (nullterminated); } /* Example of a successful response to an Encrypt request: */ uint8_t * kms_kmip_response_get_iv (kms_response_t *res, size_t *datalen) { kmip_reader_t *reader = NULL; size_t pos; size_t len; uint8_t *data = NULL; uint8_t *tmp; if (!check_and_require_kmip (res)) { goto fail; } if (!kms_kmip_response_ok (res)) { goto fail; } reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponsePayload)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponsePayload)); goto fail; } if (!kmip_reader_find (reader, KMIP_TAG_IVCounterNonce, KMIP_ITEM_TYPE_ByteString, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_Data)); goto fail; } if (!kmip_reader_read_bytes (reader, &tmp, len)) { KMS_ERROR (res, "unable to read data bytes"); goto fail; } data = malloc (len); memcpy (data, tmp, len); *datalen = len; fail: kmip_reader_destroy (reader); return data; } /* Example of a successful response to a Decrypt request: */ uint8_t * kms_kmip_response_get_data (kms_response_t *res, size_t *datalen) { kmip_reader_t *reader = NULL; size_t pos; size_t len; uint8_t *data = NULL; uint8_t *tmp; if (!check_and_require_kmip (res)) { goto fail; } if (!kms_kmip_response_ok (res)) { goto fail; } reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponsePayload)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponsePayload)); goto fail; } if (!kmip_reader_find (reader, KMIP_TAG_Data, KMIP_ITEM_TYPE_ByteString, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_Data)); goto fail; } if (!kmip_reader_read_bytes (reader, &tmp, len)) { KMS_ERROR (res, "unable to read data bytes"); goto fail; } data = malloc (len); memcpy (data, tmp, len); *datalen = len; fail: kmip_reader_destroy (reader); return data; } /* Example of a successful response to a Get request: */ uint8_t * kms_kmip_response_get_secretdata (kms_response_t *res, size_t *secretdatalen) { kmip_reader_t *reader = NULL; size_t pos; size_t len; uint8_t *secretdata = NULL; uint8_t *tmp; if (!check_and_require_kmip (res)) { goto fail; } if (!kms_kmip_response_ok (res)) { goto fail; } reader = kmip_reader_new (res->kmip.data, res->kmip.len); if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponseMessage)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponseMessage)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_BatchItem)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_BatchItem)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_ResponsePayload)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_ResponsePayload)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_SecretData)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_SecretData)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_KeyBlock)) { KMS_ERROR ( res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_KeyBlock)); goto fail; } if (!kmip_reader_find_and_recurse (reader, KMIP_TAG_KeyValue)) { KMS_ERROR ( res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_KeyValue)); goto fail; } if (!kmip_reader_find (reader, KMIP_TAG_KeyMaterial, KMIP_ITEM_TYPE_ByteString, &pos, &len)) { KMS_ERROR (res, "unable to find tag: %s", kmip_tag_to_string (KMIP_TAG_KeyMaterial)); goto fail; } if (!kmip_reader_read_bytes (reader, &tmp, len)) { KMS_ERROR (res, "unable to read secretdata bytes"); goto fail; } secretdata = malloc (len); memcpy (secretdata, tmp, len); *secretdatalen = len; fail: kmip_reader_destroy (reader); return secretdata; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_response_parser.c0000644000175100001660000001050714760300420024072 0ustar /* * Copyright 2021-present MongoDB, 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. */ #include "kms_message/kms_kmip_response_parser.h" #include "kms_endian_private.h" #include "kms_kmip_response_parser_private.h" #include "kms_message_private.h" #include "kms_request_str.h" struct _kms_kmip_response_parser_t { uint32_t first_len; uint32_t bytes_fed; kms_request_str_t *buf; bool failed; char error[512]; }; /* FIRST_LENGTH_OFFSET is the offset of the first Length in a TTLV sequence. The * sequence is: Tag (3 bytes), Type (1 byte), Length (4 bytes), Value (Length * bytes). */ static const uint32_t FIRST_LENGTH_OFFSET = 4; /* _parser_destroy destroys the fields of parser, but not the parser itself. */ static void _parser_destroy (kms_kmip_response_parser_t *parser) { kms_request_str_destroy (parser->buf); } /* _parser_init initializes the members of parser. */ static void _parser_init (kms_kmip_response_parser_t *parser) { memset (parser, 0, sizeof (*parser)); parser->buf = kms_request_str_new (); } kms_response_parser_t * kms_kmip_response_parser_new (void *reserved) { kms_response_parser_t *parser = kms_response_parser_new (); parser->kmip = malloc (sizeof (kms_kmip_response_parser_t)); _parser_init (parser->kmip); return parser; } int32_t kms_kmip_response_parser_wants_bytes (const kms_kmip_response_parser_t *parser, int32_t max) { int32_t wants_bytes; uint32_t total_len; uint32_t want_bytes_pending; if (parser->bytes_fed < KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH) { wants_bytes = KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH - (int32_t) parser->bytes_fed; } else { KMS_ASSERT (parser->first_len <= UINT32_MAX - KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH); total_len = parser->first_len + KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH; KMS_ASSERT (total_len >= parser->bytes_fed); want_bytes_pending = total_len - parser->bytes_fed; KMS_ASSERT (want_bytes_pending <= (uint32_t) INT32_MAX); wants_bytes = (int32_t) want_bytes_pending; } if (max < wants_bytes) { return max; } return wants_bytes; } bool kms_kmip_response_parser_feed (kms_kmip_response_parser_t *parser, const uint8_t *buf, uint32_t len) { kms_request_str_append_chars (parser->buf, (char *) buf, len); parser->bytes_fed += len; if (parser->first_len > 0) { if (parser->bytes_fed > parser->first_len + KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH) { KMS_ERROR (parser, "KMIP parser was fed too much data"); return false; } } else if (parser->first_len == 0 && parser->bytes_fed >= KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH) { uint32_t temp; memcpy (&temp, parser->buf->str + FIRST_LENGTH_OFFSET, sizeof (uint32_t)); parser->first_len = KMS_UINT32_FROM_BE (temp); } return true; } kms_response_t * kms_kmip_response_parser_get_response (kms_kmip_response_parser_t *parser) { kms_response_t *res; if (kms_kmip_response_parser_wants_bytes (parser, 1) != 0) { KMS_ERROR (parser, "KMIP parser does not have a complete message"); return NULL; } res = calloc (1, sizeof (kms_response_t)); res->provider = KMS_REQUEST_PROVIDER_KMIP; res->kmip.len = (uint32_t) parser->buf->len; res->kmip.data = (uint8_t *) kms_request_str_detach (parser->buf); parser->buf = NULL; /* Reinitialize for reuse. */ _parser_destroy (parser); _parser_init (parser); return res; } const char * kms_kmip_response_parser_error (const kms_kmip_response_parser_t *parser) { return parser->failed ? parser->error : NULL; } void kms_kmip_response_parser_destroy (kms_kmip_response_parser_t *parser) { if (!parser) { return; } _parser_destroy (parser); free (parser); } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_response_parser_private.h0000644000175100001660000000370314760300420025631 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESPONSE_PARSER_PRIVATE_H #define KMS_KMIP_RESPONSE_PARSER_PRIVATE_H #include "kms_message/kms_response.h" #include #include /* kms_kmip_response_parser_t is a private type used for parsing a KMIP * response. */ typedef struct _kms_kmip_response_parser_t kms_kmip_response_parser_t; /* KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH is the number of bytes needed by the * parser to determine the total length of the message being parsed. * It includes the first Length in a TTLV sequence. The sequence is: Tag (3 * bytes), Type (1 byte), Length (4 bytes), Value (Length bytes). */ #define KMS_KMIP_RESPONSE_PARSER_FIRST_LENGTH 8 int32_t kms_kmip_response_parser_wants_bytes (const kms_kmip_response_parser_t *parser, int32_t max); bool kms_kmip_response_parser_feed (kms_kmip_response_parser_t *parser, const uint8_t *buf, uint32_t len); /* kms_kmip_response_parser_get_response returns a kms_response_t and resets the * parser. */ kms_response_t * kms_kmip_response_parser_get_response (kms_kmip_response_parser_t *parser); void kms_kmip_response_parser_destroy (kms_kmip_response_parser_t *parser); const char * kms_kmip_response_parser_error (const kms_kmip_response_parser_t *parser); #endif /* KMS_KMIP_RESPONSE_PARSER_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_result_reason_private.h0000644000175100001660000000765714760300420025320 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESULT_REASON_PRIVATE_H #define KMS_KMIP_RESULT_REASON_PRIVATE_H #include "kms_message/kms_message_defines.h" /* clang-format off */ #define KMS_XMACRO \ KMS_X (ItemNotFound, "Item Not Found", 0x00000001) \ KMS_X (ResponseTooLarge, "Response Too Large", 0x00000002) \ KMS_X (AuthenticationNotSuccessful, "Authentication Not Successful", 0x00000003) \ KMS_X (InvalidMessage, "Invalid Message", 0x00000004) \ KMS_X (OperationNotSupported, "Operation Not Supported", 0x00000005) \ KMS_X (MissingData, "Missing Data", 0x00000006) \ KMS_X (InvalidField, "Invalid Field", 0x00000007) \ KMS_X (FeatureNotSupported, "Feature Not Supported", 0x00000008) \ KMS_X (OperationCanceledByRequester, "Operation Canceled By Requester", 0x00000009) \ KMS_X (CryptographicFailure, "Cryptographic Failure", 0x0000000A) \ KMS_X (IllegalOperation, "Illegal Operation", 0x0000000B) \ KMS_X (PermissionDenied, "Permission Denied", 0x0000000C) \ KMS_X (Objectarchived, "Object archived", 0x0000000D) \ KMS_X (IndexOutofBounds, "Index Out of Bounds", 0x0000000E) \ KMS_X (ApplicationNamespaceNotSupported, "Application Namespace Not Supported", 0x0000000F) \ KMS_X (KeyFormatTypeNotSupported, "Key Format Type Not Supported", 0x00000010) \ KMS_X (KeyCompressionTypeNotSupported, "Key Compression Type Not Supported", 0x00000011) \ KMS_X (EncodingOptionError, "Encoding Option Error", 0x00000012) \ KMS_X (KeyValueNotPresent, "Key Value Not Present", 0x00000013) \ KMS_X (AttestationRequired, "Attestation Required", 0x00000014) \ KMS_X (AttestationFailed, "Attestation Failed", 0x00000015) \ KMS_X (Sensitive, "Sensitive", 0x00000016) \ KMS_X (NotExtractable, "Not Extractable", 0x00000017) \ KMS_X (ObjectAlreadyExists, "Object Already Exists", 0x00000018) \ KMS_X_LAST (GeneralFailure, "General Failure", 0x00000100) /* clang-format on */ /* Generate an enum with each result_reason value. */ #define KMS_X(RESULT_REASON, STR, VAL) KMIP_RESULT_REASON_##RESULT_REASON = VAL, #define KMS_X_LAST(RESULT_REASON, STR, VAL) \ KMIP_RESULT_REASON_##RESULT_REASON = VAL typedef enum { KMS_XMACRO } kmip_result_reason_t; #undef KMS_X #undef KMS_X_LAST #define KMS_X(RESULT_REASON, STR, VAL) \ case KMIP_RESULT_REASON_##RESULT_REASON: \ return STR; #define KMS_X_LAST KMS_X static KMS_MSG_INLINE const char * kmip_result_reason_to_string (kmip_result_reason_t result_reason) { switch (result_reason) { default: return "Unknown KMIP result reason"; KMS_XMACRO } } #undef KMS_X #undef KMS_X_LAST #undef KMS_XMACRO #endif /* KMS_KMIP_RESULT_REASON_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_result_status_private.h0000644000175100001660000000340714760300420025341 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_RESULT_STATUS_PRIVATE_H #define KMS_KMIP_RESULT_STATUS_PRIVATE_H #include "kms_message/kms_message_defines.h" #define KMS_XMACRO \ KMS_X (OperationSuccess, "Success", 0x00000000) \ KMS_X (OperationFailed, "Operation Failed", 0x00000001) \ KMS_X (OperationPending, "Operation Pending", 0x00000002) \ KMS_X_LAST (OperationUndone, "Operation Undone", 0x00000003) /* Generate an enum with each result_status value. */ #define KMS_X(RESULT_STATUS, STR, VAL) KMIP_RESULT_STATUS_##RESULT_STATUS = VAL, #define KMS_X_LAST(RESULT_STATUS, STR, VAL) \ KMIP_RESULT_STATUS_##RESULT_STATUS = VAL typedef enum { KMS_XMACRO } kmip_result_status_t; #undef KMS_X #undef KMS_X_LAST #define KMS_X(RESULT_STATUS, STR, VAL) \ case KMIP_RESULT_STATUS_##RESULT_STATUS: \ return STR; #define KMS_X_LAST KMS_X static KMS_MSG_INLINE const char * kmip_result_status_to_string (kmip_result_status_t result_status) { switch (result_status) { default: return "Unknown KMIP result status"; KMS_XMACRO } } #undef KMS_X #undef KMS_X_LAST #undef KMS_XMACRO #endif /* KMS_KMIP_RESULT_STATUS_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kmip_tag_type_private.h0000644000175100001660000007036614760300420024244 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef KMS_KMIP_TAG_TYPE_PRIVATE_H #define KMS_KMIP_TAG_TYPE_PRIVATE_H #include "kms_message/kms_message_defines.h" /* clang-format off */ #define KMS_XMACRO \ KMS_X (ActivationDate, 0x420001) \ KMS_X (ApplicationData, 0x420002) \ KMS_X (ApplicationNamespace, 0x420003) \ KMS_X (ApplicationSpecificInformation, 0x420004) \ KMS_X (ArchiveDate, 0x420005) \ KMS_X (AsynchronousCorrelationValue, 0x420006) \ KMS_X (AsynchronousIndicator, 0x420007) \ KMS_X (Attribute, 0x420008) \ KMS_X (AttributeIndex, 0x420009) \ KMS_X (AttributeName, 0x42000A) \ KMS_X (AttributeValue, 0x42000B) \ KMS_X (Authentication, 0x42000C) \ KMS_X (BatchCount, 0x42000D) \ KMS_X (BatchErrorContinuationOption, 0x42000E) \ KMS_X (BatchItem, 0x42000F) \ KMS_X (BatchOrderOption, 0x420010) \ KMS_X (BlockCipherMode, 0x420011) \ KMS_X (CancellationResult, 0x420012) \ KMS_X (Certificate, 0x420013) \ KMS_X (CertificateIdentifier, 0x420014) /* deprecated as of version 1.1 */ \ KMS_X (CertificateIssuer, 0x420015) /* deprecated as of version 1.1 */ \ KMS_X (CertificateIssuerAlternativeName, 0x420016) /* deprecated as of version 1.1 */ \ KMS_X (CertificateIssuerDistinguishedName, 0x420017) /* deprecated as of version 1.1 */ \ KMS_X (CertificateRequest, 0x420018) \ KMS_X (CertificateRequestType, 0x420019) \ KMS_X (CertificateSubject, 0x42001A) /* deprecated as of version 1.1 */ \ KMS_X (CertificateSubjectAlternativeName, 0x42001B) /* deprecated as of version 1.1 */ \ KMS_X (CertificateSubjectDistinguishedName, 0x42001C) /* deprecated as of version 1.1 */ \ KMS_X (CertificateType, 0x42001D) \ KMS_X (CertificateValue, 0x42001E) \ KMS_X (CommonTemplateAttribute, 0x42001F) \ KMS_X (CompromiseDate, 0x420020) \ KMS_X (CompromiseOccurrenceDate, 0x420021) \ KMS_X (ContactInformation, 0x420022) \ KMS_X (Credential, 0x420023) \ KMS_X (CredentialType, 0x420024) \ KMS_X (CredentialValue, 0x420025) \ KMS_X (CriticalityIndicator, 0x420026) \ KMS_X (CRTCoefficient, 0x420027) \ KMS_X (CryptographicAlgorithm, 0x420028) \ KMS_X (CryptographicDomainParameters, 0x420029) \ KMS_X (CryptographicLength, 0x42002A) \ KMS_X (CryptographicParameters, 0x42002B) \ KMS_X (CryptographicUsageMask, 0x42002C) \ KMS_X (CustomAttribute, 0x42002D) \ KMS_X (D, 0x42002E) \ KMS_X (DeactivationDate, 0x42002F) \ KMS_X (DerivationData, 0x420030) \ KMS_X (DerivationMethod, 0x420031) \ KMS_X (DerivationParameters, 0x420032) \ KMS_X (DestroyDate, 0x420033) \ KMS_X (Digest, 0x420034) \ KMS_X (DigestValue, 0x420035) \ KMS_X (EncryptionKeyInformation, 0x420036) \ KMS_X (G, 0x420037) \ KMS_X (HashingAlgorithm, 0x420038) \ KMS_X (InitialDate, 0x420039) \ KMS_X (InitializationVector, 0x42003A) \ KMS_X (Issuer, 0x42003B) /* deprecated as of version 1.1 */ \ KMS_X (IterationCount, 0x42003C) \ KMS_X (IVCounterNonce, 0x42003D) \ KMS_X (J, 0x42003E) \ KMS_X (Key, 0x42003F) \ KMS_X (KeyBlock, 0x420040) \ KMS_X (KeyCompressionType, 0x420041) \ KMS_X (KeyFormatType, 0x420042) \ KMS_X (KeyMaterial, 0x420043) \ KMS_X (KeyPartIdentifier, 0x420044) \ KMS_X (KeyValue, 0x420045) \ KMS_X (KeyWrappingData, 0x420046) \ KMS_X (KeyWrappingSpecification, 0x420047) \ KMS_X (LastChangeDate, 0x420048) \ KMS_X (LeaseTime, 0x420049) \ KMS_X (Link, 0x42004A) \ KMS_X (LinkType, 0x42004B) \ KMS_X (LinkedObjectIdentifier, 0x42004C) \ KMS_X (MACSignature, 0x42004D) \ KMS_X (MACSignatureKeyInformation, 0x42004E) \ KMS_X (MaximumItems, 0x42004F) \ KMS_X (MaximumResponseSize, 0x420050) \ KMS_X (MessageExtension, 0x420051) \ KMS_X (Modulus, 0x420052) \ KMS_X (Name, 0x420053) \ KMS_X (NameType, 0x420054) \ KMS_X (NameValue, 0x420055) \ KMS_X (ObjectGroup, 0x420056) \ KMS_X (ObjectType, 0x420057) \ KMS_X (Offset, 0x420058) \ KMS_X (OpaqueDataType, 0x420059) \ KMS_X (OpaqueDataValue, 0x42005A) \ KMS_X (OpaqueObject, 0x42005B) \ KMS_X (Operation, 0x42005C) \ KMS_X (OperationPolicyName, 0x42005D) /* deprecated */ \ KMS_X (P, 0x42005E) \ KMS_X (PaddingMethod, 0x42005F) \ KMS_X (PrimeExponentP, 0x420060) \ KMS_X (PrimeExponentQ, 0x420061) \ KMS_X (PrimeFieldSize, 0x420062) \ KMS_X (PrivateExponent, 0x420063) \ KMS_X (PrivateKey, 0x420064) \ KMS_X (PrivateKeyTemplateAttribute, 0x420065) \ KMS_X (PrivateKeyUniqueIdentifier, 0x420066) \ KMS_X (ProcessStartDate, 0x420067) \ KMS_X (ProtectStopDate, 0x420068) \ KMS_X (ProtocolVersion, 0x420069) \ KMS_X (ProtocolVersionMajor, 0x42006A) \ KMS_X (ProtocolVersionMinor, 0x42006B) \ KMS_X (PublicExponent, 0x42006C) \ KMS_X (PublicKey, 0x42006D) \ KMS_X (PublicKeyTemplateAttribute, 0x42006E) \ KMS_X (PublicKeyUniqueIdentifier, 0x42006F) \ KMS_X (PutFunction, 0x420070) \ KMS_X (Q, 0x420071) \ KMS_X (QString, 0x420072) \ KMS_X (Qlength, 0x420073) \ KMS_X (QueryFunction, 0x420074) \ KMS_X (RecommendedCurve, 0x420075) \ KMS_X (ReplacedUniqueIdentifier, 0x420076) \ KMS_X (RequestHeader, 0x420077) \ KMS_X (RequestMessage, 0x420078) \ KMS_X (RequestPayload, 0x420079) \ KMS_X (ResponseHeader, 0x42007A) \ KMS_X (ResponseMessage, 0x42007B) \ KMS_X (ResponsePayload, 0x42007C) \ KMS_X (ResultMessage, 0x42007D) \ KMS_X (ResultReason, 0x42007E) \ KMS_X (ResultStatus, 0x42007F) \ KMS_X (RevocationMessage, 0x420080) \ KMS_X (RevocationReason, 0x420081) \ KMS_X (RevocationReasonCode, 0x420082) \ KMS_X (KeyRoleType, 0x420083) \ KMS_X (Salt, 0x420084) \ KMS_X (SecretData, 0x420085) \ KMS_X (SecretDataType, 0x420086) \ KMS_X (SerialNumber, 0x420087) /* deprecated as of version 1.1 */ \ KMS_X (ServerInformation, 0x420088) \ KMS_X (SplitKey, 0x420089) \ KMS_X (SplitKeyMethod, 0x42008A) \ KMS_X (SplitKeyParts, 0x42008B) \ KMS_X (SplitKeyThreshold, 0x42008C) \ KMS_X (State, 0x42008D) \ KMS_X (StorageStatusMask, 0x42008E) \ KMS_X (SymmetricKey, 0x42008F) \ KMS_X (Template, 0x420090) \ KMS_X (TemplateAttribute, 0x420091) \ KMS_X (TimeStamp, 0x420092) \ KMS_X (UniqueBatchItemID, 0x420093) \ KMS_X (UniqueIdentifier, 0x420094) \ KMS_X (UsageLimits, 0x420095) \ KMS_X (UsageLimitsCount, 0x420096) \ KMS_X (UsageLimitsTotal, 0x420097) \ KMS_X (UsageLimitsUnit, 0x420098) \ KMS_X (Username, 0x420099) \ KMS_X (ValidityDate, 0x42009A) \ KMS_X (ValidityIndicator, 0x42009B) \ KMS_X (VendorExtension, 0x42009C) \ KMS_X (VendorIdentification, 0x42009D) \ KMS_X (WrappingMethod, 0x42009E) \ KMS_X (X, 0x42009F) \ KMS_X (Y, 0x4200A0) \ KMS_X (Password, 0x4200A1) \ KMS_X (DeviceIdentifier, 0x4200A2) \ KMS_X (EncodingOption, 0x4200A3) \ KMS_X (ExtensionInformation, 0x4200A4) \ KMS_X (ExtensionName, 0x4200A5) \ KMS_X (ExtensionTag, 0x4200A6) \ KMS_X (ExtensionType, 0x4200A7) \ KMS_X (Fresh, 0x4200A8) \ KMS_X (MachineIdentifier, 0x4200A9) \ KMS_X (MediaIdentifier, 0x4200AA) \ KMS_X (NetworkIdentifier, 0x4200AB) \ KMS_X (ObjectGroupMember, 0x4200AC) \ KMS_X (CertificateLength, 0x4200AD) \ KMS_X (DigitalSignatureAlgorithm, 0x4200AE) \ KMS_X (CertificateSerialNumber, 0x4200AF) \ KMS_X (DeviceSerialNumber, 0x4200B0) \ KMS_X (IssuerAlternativeName, 0x4200B1) \ KMS_X (IssuerDistinguishedName, 0x4200B2) \ KMS_X (SubjectAlternativeName, 0x4200B3) \ KMS_X (SubjectDistinguishedName, 0x4200B4) \ KMS_X (X509CertificateIdentifier, 0x4200B5) \ KMS_X (X509CertificateIssuer, 0x4200B6) \ KMS_X (X509CertificateSubject, 0x4200B7) \ KMS_X (KeyValueLocation, 0x4200B8) \ KMS_X (KeyValueLocationValue, 0x4200B9) \ KMS_X (KeyValueLocationType, 0x4200BA) \ KMS_X (KeyValuePresent, 0x4200BB) \ KMS_X (OriginalCreationDate, 0x4200BC) \ KMS_X (PGPKey, 0x4200BD) \ KMS_X (PGPKeyVersion, 0x4200BE) \ KMS_X (AlternativeName, 0x4200BF) \ KMS_X (AlternativeNameValue, 0x4200C0) \ KMS_X (AlternativeNameType, 0x4200C1) \ KMS_X (Data, 0x4200C2) \ KMS_X (SignatureData, 0x4200C3) \ KMS_X (DataLength, 0x4200C4) \ KMS_X (RandomIV, 0x4200C5) \ KMS_X (MACData, 0x4200C6) \ KMS_X (AttestationType, 0x4200C7) \ KMS_X (Nonce, 0x4200C8) \ KMS_X (NonceID, 0x4200C9) \ KMS_X (NonceValue, 0x4200CA) \ KMS_X (AttestationMeasurement, 0x4200CB) \ KMS_X (AttestationAssertion, 0x4200CC) \ KMS_X (IVLength, 0x4200CD) \ KMS_X (TagLength, 0x4200CE) \ KMS_X (FixedFieldLength, 0x4200CF) \ KMS_X (CounterLength, 0x4200D0) \ KMS_X (InitialCounterValue, 0x4200D1) \ KMS_X (InvocationFieldLength, 0x4200D2) \ KMS_X (AttestationCapableIndicator, 0x4200D3) \ KMS_X (OffsetItems, 0x4200D4) \ KMS_X (LocatedItems, 0x4200D5) \ KMS_X (CorrelationValue, 0x4200D6) \ KMS_X (InitIndicator, 0x4200D7) \ KMS_X (FinalIndicator, 0x4200D8) \ KMS_X (RNGParameters, 0x4200D9) \ KMS_X (RNGAlgorithm, 0x4200DA) \ KMS_X (DRBGAlgorithm, 0x4200DB) \ KMS_X (FIPS186Variation, 0x4200DC) \ KMS_X (PredictionResistance, 0x4200DD) \ KMS_X (RandomNumberGenerator, 0x4200DE) \ KMS_X (ValidationInformation, 0x4200DF) \ KMS_X (ValidationAuthorityType, 0x4200E0) \ KMS_X (ValidationAuthorityCountry, 0x4200E1) \ KMS_X (ValidationAuthorityURI, 0x4200E2) \ KMS_X (ValidationVersionMajor, 0x4200E3) \ KMS_X (ValidationVersionMinor, 0x4200E4) \ KMS_X (ValidationType, 0x4200E5) \ KMS_X (ValidationLevel, 0x4200E6) \ KMS_X (ValidationCertificateIdentifier, 0x4200E7) \ KMS_X (ValidationCertificateURI, 0x4200E8) \ KMS_X (ValidationVendorURI, 0x4200E9) \ KMS_X (ValidationProfile, 0x4200EA) \ KMS_X (ProfileInformation, 0x4200EB) \ KMS_X (ProfileName, 0x4200EC) \ KMS_X (ServerURI, 0x4200ED) \ KMS_X (ServerPort, 0x4200EE) \ KMS_X (StreamingCapability, 0x4200EF) \ KMS_X (AsynchronousCapability, 0x4200F0) \ KMS_X (AttestationCapability, 0x4200F1) \ KMS_X (UnwrapMode, 0x4200F2) \ KMS_X (DestroyAction, 0x4200F3) \ KMS_X (ShreddingAlgorithm, 0x4200F4) \ KMS_X (RNGMode, 0x4200F5) \ KMS_X (ClientRegistrationMethod, 0x4200F6) \ KMS_X (CapabilityInformation, 0x4200F7) \ KMS_X (KeyWrapType, 0x4200F8) \ KMS_X (BatchUndoCapability, 0x4200F9) \ KMS_X (BatchContinueCapability, 0x4200FA) \ KMS_X (PKCS12FriendlyName, 0x4200FB) \ KMS_X (Description, 0x4200FC) \ KMS_X (Comment, 0x4200FD) \ KMS_X (AuthenticatedEncryptionAdditionalData, 0x4200FE) \ KMS_X (AuthenticatedEncryptionTag, 0x4200FF) \ KMS_X (SaltLength, 0x420100) \ KMS_X (MaskGenerator, 0x420101) \ KMS_X (MaskGeneratorHashingAlgorithm, 0x420102) \ KMS_X (PSource, 0x420103) \ KMS_X (TrailerField, 0x420104) \ KMS_X (ClientCorrelationValue, 0x420105) \ KMS_X (ServerCorrelationValue, 0x420106) \ KMS_X (DigestedData, 0x420107) \ KMS_X (CertificateSubjectCN, 0x420108) \ KMS_X (CertificateSubjectO, 0x420109) \ KMS_X (CertificateSubjectOU, 0x42010A) \ KMS_X (CertificateSubjectEmail, 0x42010B) \ KMS_X (CertificateSubjectC, 0x42010C) \ KMS_X (CertificateSubjectST, 0x42010D) \ KMS_X (CertificateSubjectL, 0x42010E) \ KMS_X (CertificateSubjectUID, 0x42010F) \ KMS_X (CertificateSubjectSerialNumber, 0x420110) \ KMS_X (CertificateSubjectTitle, 0x420111) \ KMS_X (CertificateSubjectDC, 0x420112) \ KMS_X (CertificateSubjectDNQualifier, 0x420113) \ KMS_X (CertificateIssuerCN, 0x420114) \ KMS_X (CertificateIssuerO, 0x420115) \ KMS_X (CertificateIssuerOU, 0x420116) \ KMS_X (CertificateIssuerEmail, 0x420117) \ KMS_X (CertificateIssuerC, 0x420118) \ KMS_X (CertificateIssuerST, 0x420119) \ KMS_X (CertificateIssuerL, 0x42011A) \ KMS_X (CertificateIssuerUID, 0x42011B) \ KMS_X (CertificateIssuerSerialNumber, 0x42011C) \ KMS_X (CertificateIssuerTitle, 0x42011D) \ KMS_X (CertificateIssuerDC, 0x42011E) \ KMS_X (CertificateIssuerDNQualifier, 0x42011F) \ KMS_X (Sensitive, 0x420120) \ KMS_X (AlwaysSensitive, 0x420121) \ KMS_X (Extractable, 0x420122) \ KMS_X (NeverExtractable, 0x420123) \ KMS_X (ReplaceExisting, 0x420124) \ KMS_X_LAST (Attributes, 0x420125) /* clang-format on */ /* Generate an enum with each tag value. */ #define KMS_X(TAG, VAL) KMIP_TAG_##TAG = VAL, #define KMS_X_LAST(TAG, VAL) KMIP_TAG_##TAG = VAL typedef enum { KMS_XMACRO } kmip_tag_type_t; #undef KMS_X #undef KMS_X_LAST #define KMS_X(TAG, VAL) \ case KMIP_TAG_##TAG: \ return #TAG; #define KMS_X_LAST KMS_X static KMS_MSG_INLINE const char * kmip_tag_to_string (kmip_tag_type_t tag) { switch (tag) { default: return "Unknown KMIP tag"; KMS_XMACRO } } #undef KMS_X #undef KMS_X_LAST #undef KMS_XMACRO #endif /* KMS_KMIP_TAG_TYPE_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kv_list.c0000644000175100001660000000627414760300420021321 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_kv_list.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_request_str.h" #include "kms_port.h" #include "sort.h" static void kv_init (kms_kv_t *kv, kms_request_str_t *key, kms_request_str_t *value) { kv->key = kms_request_str_dup (key); kv->value = kms_request_str_dup (value); } static void kv_cleanup (kms_kv_t *kv) { kms_request_str_destroy (kv->key); kms_request_str_destroy (kv->value); } kms_kv_list_t * kms_kv_list_new (void) { kms_kv_list_t *lst = malloc (sizeof (kms_kv_list_t)); KMS_ASSERT (lst); lst->size = 16; lst->kvs = malloc (lst->size * sizeof (kms_kv_t)); KMS_ASSERT (lst->kvs); lst->len = 0; return lst; } void kms_kv_list_destroy (kms_kv_list_t *lst) { size_t i; if (!lst) { return; } for (i = 0; i < lst->len; i++) { kv_cleanup (&lst->kvs[i]); } free (lst->kvs); free (lst); } void kms_kv_list_add (kms_kv_list_t *lst, kms_request_str_t *key, kms_request_str_t *value) { if (lst->len == lst->size) { lst->size *= 2; lst->kvs = realloc (lst->kvs, lst->size * sizeof (kms_kv_t)); KMS_ASSERT (lst->kvs); } kv_init (&lst->kvs[lst->len], key, value); ++lst->len; } const kms_kv_t * kms_kv_list_find (const kms_kv_list_t *lst, const char *key) { size_t i; for (i = 0; i < lst->len; i++) { if (0 == kms_strcasecmp (lst->kvs[i].key->str, key)) { return &lst->kvs[i]; } } return NULL; } void kms_kv_list_del (kms_kv_list_t *lst, const char *key) { size_t i; for (i = 0; i < lst->len; i++) { if (0 == strcmp (lst->kvs[i].key->str, key)) { kv_cleanup (&lst->kvs[i]); memmove (&lst->kvs[i], &lst->kvs[i + 1], sizeof (kms_kv_t) * (lst->len - i - 1)); lst->len--; } } } kms_kv_list_t * kms_kv_list_dup (const kms_kv_list_t *lst) { kms_kv_list_t *dup; size_t i; if (lst->len == 0) { return kms_kv_list_new (); } dup = malloc (sizeof (kms_kv_list_t)); KMS_ASSERT (dup); dup->size = dup->len = lst->len; dup->kvs = malloc (lst->len * sizeof (kms_kv_t)); KMS_ASSERT (dup->kvs); for (i = 0; i < lst->len; i++) { kv_init (&dup->kvs[i], lst->kvs[i].key, lst->kvs[i].value); } return dup; } void kms_kv_list_sort (kms_kv_list_t *lst, int (*cmp) (const void *, const void *)) { /* A stable sort is required to sort headers when creating canonical * requests. qsort is not stable. */ insertionsort ( (unsigned char *) (lst->kvs), lst->len, sizeof (kms_kv_t), cmp); } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_kv_list.h0000644000175100001660000000272714760300420021325 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_KV_LIST_H #define KMS_KV_LIST_H #include "kms_message/kms_message.h" #include "kms_request_str.h" #include #include #include /* key-value pair */ typedef struct { kms_request_str_t *key; kms_request_str_t *value; } kms_kv_t; typedef struct { kms_kv_t *kvs; size_t len; size_t size; } kms_kv_list_t; kms_kv_list_t * kms_kv_list_new (void); void kms_kv_list_destroy (kms_kv_list_t *lst); void kms_kv_list_add (kms_kv_list_t *lst, kms_request_str_t *key, kms_request_str_t *value); const kms_kv_t * kms_kv_list_find (const kms_kv_list_t *lst, const char *key); void kms_kv_list_del (kms_kv_list_t *lst, const char *key); kms_kv_list_t * kms_kv_list_dup (const kms_kv_list_t *lst); void kms_kv_list_sort (kms_kv_list_t *lst, int (*cmp) (const void *, const void *)); #endif /* KMS_KV_LIST_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message.c0000644000175100001660000000212414760300420021260 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message/kms_b64.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_crypto.h" #include #include void set_error (char *error, size_t size, const char *fmt, ...) { va_list va; va_start (va, fmt); (void) vsnprintf (error, size, fmt, va); va_end (va); } int kms_message_init (void) { kms_message_b64_initialize_rmap (); return kms_crypto_init (); } void kms_message_cleanup (void) { kms_crypto_cleanup (); } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_message_private.h0000644000175100001660000000775514760300420023036 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_PRIVATE_H #define KMS_MESSAGE_PRIVATE_H #include #include "kms_message/kms_message.h" #include "kms_request_str.h" #include "kms_kv_list.h" #include "kms_crypto.h" #include "kms_kmip_response_parser_private.h" /* Sadly, Windows does not define SSIZE_MAX. It is defined in bson-compat.h, * but only since 1.22.x, so copy this from bson-compat.h for now. */ #ifndef SSIZE_MAX #define SSIZE_MAX \ (ssize_t) ( \ (((size_t) 0x01u) << (sizeof (ssize_t) * (size_t) CHAR_BIT - 1u)) - 1u) #endif struct _kms_request_t { char error[512]; bool failed; bool finalized; /* Begin: AWS specific */ kms_request_str_t *region; kms_request_str_t *service; kms_request_str_t *access_key_id; kms_request_str_t *secret_key; kms_request_str_t *datetime; kms_request_str_t *date; /* End: AWS specific */ kms_request_str_t *method; kms_request_str_t *path; kms_request_str_t *query; kms_request_str_t *payload; kms_kv_list_t *query_params; kms_kv_list_t *header_fields; /* turn off for tests only, not in public kms_request_opt_t API */ bool auto_content_length; _kms_crypto_t crypto; kms_request_str_t *to_string; kms_request_provider_t provider; /* TODO (MONGOCRYPT-342): make a union for each KMS provider type. kms_request_provider_t provider; union { struct {} aws; struct {} azure; struct {} gcp; struct {} kmip; } */ struct { uint8_t *data; uint32_t len; } kmip; }; struct _kms_response_t { int status; kms_kv_list_t *headers; kms_request_str_t *body; /* TODO (MONGOCRYPT-347): make a union for each KMS provider type. */ char error[512]; bool failed; kms_request_provider_t provider; struct { uint8_t *data; uint32_t len; } kmip; }; typedef enum { PARSING_STATUS_LINE, PARSING_HEADER, PARSING_BODY, PARSING_CHUNK_LENGTH, PARSING_CHUNK, PARSING_DONE } kms_response_parser_state_t; struct _kms_response_parser_t { char error[512]; bool failed; kms_response_t *response; kms_request_str_t *raw_response; int content_length; int start; /* start of the current thing getting parsed. */ /* Support two types of HTTP 1.1 responses. * - "Content-Length: x" header is present, indicating the body length. * - "Transfer-Encoding: chunked" header is present, indicating a stream of * chunks. */ bool transfer_encoding_chunked; int chunk_size; kms_response_parser_state_t state; /* TODO: MONGOCRYPT-348 reorganize this struct to better separate fields for * HTTP parsing and fields for KMIP parsing. */ kms_kmip_response_parser_t *kmip; }; #define CHECK_FAILED \ do { \ if (request->failed) { \ return false; \ } \ } while (0) void set_error (char *error, size_t size, const char *fmt, ...); #define KMS_ERROR(obj, ...) \ do { \ obj->failed = true; \ set_error (obj->error, sizeof (obj->error), __VA_ARGS__); \ } while (0) #define KMS_ASSERT(stmt) \ if (!(stmt)) { \ fprintf (stderr, "%s failed\n", #stmt); \ abort (); \ } #endif /* KMS_MESSAGE_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_port.c0000644000175100001660000000157014760300420020624 0ustar /* * Copyright 2020-present MongoDB, 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. */ #include "kms_port.h" #if defined(_WIN32) #include #include char * kms_strndup (const char *src, size_t len) { char *dst = (char *) malloc (len + 1); if (!dst) { return 0; } memcpy (dst, src, len); dst[len] = '\0'; return dst; } #endif mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_port.h0000644000175100001660000000157414760300420020635 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_PORT_H #define KMS_PORT_H #include #if defined(_WIN32) #define kms_strcasecmp _stricmp char * kms_strndup (const char *src, size_t len); #else #include #define kms_strndup strndup #define kms_strcasecmp strcasecmp #endif #endif /* KMS_PORT_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_request.c0000644000175100001660000006073314760300420021336 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_crypto.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_request_opt_private.h" #include "kms_port.h" #include /* CHAR_BIT */ static kms_kv_list_t * parse_query_params (kms_request_str_t *q) { kms_kv_list_t *lst = kms_kv_list_new (); char *p = q->str; char *end = q->str + q->len; char *amp, *equals; kms_request_str_t *k, *v; do { equals = strchr ((const char *) p, '='); if (!equals) { kms_kv_list_destroy (lst); return NULL; } amp = strchr ((const char *) equals, '&'); if (!amp) { amp = end; } k = kms_request_str_new_from_chars (p, equals - p); v = kms_request_str_new_from_chars (equals + 1, amp - equals - 1); kms_kv_list_add (lst, k, v); kms_request_str_destroy (k); kms_request_str_destroy (v); p = amp + 1; } while (p < end); return lst; } static bool check_and_prohibit_kmip (kms_request_t *req) { if (req->provider == KMS_REQUEST_PROVIDER_KMIP) { KMS_ERROR (req, "Function not applicable to KMIP"); return false; } return true; } kms_request_t * kms_request_new (const char *method, const char *path_and_query, const kms_request_opt_t *opt) { kms_request_t *request = calloc (1, sizeof (kms_request_t)); const char *question_mark; KMS_ASSERT (request); if (opt && opt->provider) { request->provider = opt->provider; } else { request->provider = KMS_REQUEST_PROVIDER_AWS; } if (!check_and_prohibit_kmip (request)) { return request; } /* parsing may set failed to true */ request->failed = false; request->finalized = false; request->region = kms_request_str_new (); request->service = kms_request_str_new (); request->access_key_id = kms_request_str_new (); request->secret_key = kms_request_str_new (); question_mark = strchr (path_and_query, '?'); if (question_mark) { request->path = kms_request_str_new_from_chars ( path_and_query, question_mark - path_and_query); request->query = kms_request_str_new_from_chars (question_mark + 1, -1); request->query_params = parse_query_params (request->query); if (!request->query_params) { KMS_ERROR (request, "Cannot parse query: %s", request->query->str); } } else { request->path = kms_request_str_new_from_chars (path_and_query, -1); request->query = kms_request_str_new (); request->query_params = kms_kv_list_new (); } request->payload = kms_request_str_new (); request->date = kms_request_str_new (); request->datetime = kms_request_str_new (); request->method = kms_request_str_new_from_chars (method, -1); request->header_fields = kms_kv_list_new (); request->auto_content_length = true; /* For AWS KMS requests, add a X-Amz-Date header. */ if (request->provider == KMS_REQUEST_PROVIDER_AWS && !kms_request_set_date (request, NULL)) { return request; } if (opt && opt->connection_close) { if (!kms_request_add_header_field (request, "Connection", "close")) { return request; } } if (opt && opt->crypto.sha256) { memcpy (&request->crypto, &opt->crypto, sizeof (opt->crypto)); } else { request->crypto.sha256 = kms_sha256; request->crypto.sha256_hmac = kms_sha256_hmac; } return request; } void kms_request_destroy (kms_request_t *request) { kms_request_str_destroy (request->region); kms_request_str_destroy (request->service); kms_request_str_destroy (request->access_key_id); kms_request_str_destroy (request->secret_key); kms_request_str_destroy (request->method); kms_request_str_destroy (request->path); kms_request_str_destroy (request->query); kms_request_str_destroy (request->payload); kms_request_str_destroy (request->datetime); kms_request_str_destroy (request->date); kms_kv_list_destroy (request->query_params); kms_kv_list_destroy (request->header_fields); kms_request_str_destroy (request->to_string); free (request->kmip.data); free (request); } const char * kms_request_get_error (kms_request_t *request) { return request->failed ? request->error : NULL; } #define AMZ_DT_FORMAT "YYYYmmDDTHHMMSSZ" bool kms_request_set_date (kms_request_t *request, const struct tm *tm) { char buf[sizeof AMZ_DT_FORMAT]; struct tm tmp_tm; if (request->failed) { return false; } if (!check_and_prohibit_kmip (request)) { return false; } if (!tm) { /* use current time */ time_t t; time (&t); #if defined(KMS_MESSAGE_HAVE_GMTIME_R) gmtime_r (&t, &tmp_tm); #elif defined(_MSC_VER) gmtime_s (&tmp_tm, &t); #else tmp_tm = *gmtime (&t); #endif tm = &tmp_tm; } if (0 == strftime (buf, sizeof AMZ_DT_FORMAT, "%Y%m%dT%H%M%SZ", tm)) { KMS_ERROR (request, "Invalid tm struct"); return false; } kms_request_str_set_chars (request->date, buf, sizeof "YYYYmmDD" - 1); kms_request_str_set_chars (request->datetime, buf, sizeof AMZ_DT_FORMAT - 1); kms_kv_list_del (request->header_fields, "X-Amz-Date"); if (!kms_request_add_header_field (request, "X-Amz-Date", buf)) { return false; } return true; } #undef AMZ_DT_FORMAT bool kms_request_set_region (kms_request_t *request, const char *region) { if (!check_and_prohibit_kmip (request)) { return false; } kms_request_str_set_chars (request->region, region, -1); return true; } bool kms_request_set_service (kms_request_t *request, const char *service) { if (!check_and_prohibit_kmip (request)) { return false; } kms_request_str_set_chars (request->service, service, -1); return true; } bool kms_request_set_access_key_id (kms_request_t *request, const char *akid) { if (!check_and_prohibit_kmip (request)) { return false; } kms_request_str_set_chars (request->access_key_id, akid, -1); return true; } bool kms_request_set_secret_key (kms_request_t *request, const char *key) { if (!check_and_prohibit_kmip (request)) { return false; } kms_request_str_set_chars (request->secret_key, key, -1); return true; } bool kms_request_add_header_field (kms_request_t *request, const char *field_name, const char *value) { kms_request_str_t *k, *v; CHECK_FAILED; if (!check_and_prohibit_kmip (request)) { return false; } k = kms_request_str_new_from_chars (field_name, -1); v = kms_request_str_new_from_chars (value, -1); kms_kv_list_add (request->header_fields, k, v); kms_request_str_destroy (k); kms_request_str_destroy (v); return true; } bool kms_request_append_header_field_value (kms_request_t *request, const char *value, size_t len) { kms_request_str_t *v; CHECK_FAILED; if (!check_and_prohibit_kmip (request)) { return false; } if (request->header_fields->len == 0) { KMS_ERROR ( request, "Ensure the request has at least one header field before calling %s", __func__); } v = request->header_fields->kvs[request->header_fields->len - 1].value; KMS_ASSERT (len <= SSIZE_MAX); kms_request_str_append_chars (v, value, (ssize_t) len); return true; } bool kms_request_append_payload (kms_request_t *request, const char *payload, size_t len) { CHECK_FAILED; if (!check_and_prohibit_kmip (request)) { return false; } KMS_ASSERT (len <= SSIZE_MAX); kms_request_str_append_chars (request->payload, payload, (ssize_t) len); return true; } /* docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html * * "Sort the parameter names by character code point in ascending order. For * example, a parameter name that begins with the uppercase letter F precedes a * parameter name that begins with a lowercase letter b." */ static int cmp_query_params (const void *a, const void *b) { int r = strcmp (((kms_kv_t *) a)->key->str, ((kms_kv_t *) b)->key->str); if (r != 0) { return r; } /* not in docs, but tested in get-vanilla-query-order-key: sort by value */ return strcmp (((kms_kv_t *) a)->value->str, ((kms_kv_t *) b)->value->str); } static void append_canonical_query (kms_request_t *request, kms_request_str_t *str) { size_t i; kms_kv_list_t *lst; if (!request->query_params->len) { return; } lst = kms_kv_list_dup (request->query_params); kms_kv_list_sort (lst, cmp_query_params); for (i = 0; i < lst->len; i++) { kms_request_str_append_escaped (str, lst->kvs[i].key, true); kms_request_str_append_char (str, '='); kms_request_str_append_escaped (str, lst->kvs[i].value, true); if (i < lst->len - 1) { kms_request_str_append_char (str, '&'); } } kms_kv_list_destroy (lst); } /* "lst" is a sorted list of headers */ static void append_canonical_headers (kms_kv_list_t *lst, kms_request_str_t *str) { size_t i; kms_kv_t *kv; const kms_request_str_t *previous_key = NULL; /* aws docs: "To create the canonical headers list, convert all header names * to lowercase and remove leading spaces and trailing spaces. Convert * sequential spaces in the header value to a single space." "Do not sort the * values in headers that have multiple values." */ for (i = 0; i < lst->len; i++) { kv = &lst->kvs[i]; if (previous_key && 0 == kms_strcasecmp (previous_key->str, kv->key->str)) { /* duplicate header */ kms_request_str_append_char (str, ','); kms_request_str_append_stripped (str, kv->value); continue; } if (i > 0) { kms_request_str_append_newline (str); } kms_request_str_append_lowercase (str, kv->key); kms_request_str_append_char (str, ':'); kms_request_str_append_stripped (str, kv->value); previous_key = kv->key; } kms_request_str_append_newline (str); } static void append_signed_headers (kms_kv_list_t *lst, kms_request_str_t *str) { size_t i; kms_kv_t *kv; const kms_request_str_t *previous_key = NULL; for (i = 0; i < lst->len; i++) { kv = &lst->kvs[i]; if (previous_key && 0 == kms_strcasecmp (previous_key->str, kv->key->str)) { /* duplicate header */ continue; } if (0 == kms_strcasecmp (kv->key->str, "connection")) { continue; } kms_request_str_append_lowercase (str, kv->key); if (i < lst->len - 1) { kms_request_str_append_char (str, ';'); } previous_key = kv->key; } } static bool finalize (kms_request_t *request) { kms_kv_list_t *lst; kms_request_str_t *k; kms_request_str_t *v; if (request->failed) { return false; } if (request->finalized) { return true; } request->finalized = true; lst = request->header_fields; if (!kms_kv_list_find (lst, "Host")) { if (request->provider != KMS_REQUEST_PROVIDER_AWS) { KMS_ERROR (request, "Required Host header not set"); return false; } /* For AWS requests, derive a default Host header from region + service. * E.g. "kms.us-east-1.amazonaws.com" */ k = kms_request_str_new_from_chars ("Host", -1); v = kms_request_str_dup (request->service); kms_request_str_append_char (v, '.'); kms_request_str_append (v, request->region); kms_request_str_append_chars (v, ".amazonaws.com", -1); kms_kv_list_add (lst, k, v); kms_request_str_destroy (k); kms_request_str_destroy (v); } if (!kms_kv_list_find (lst, "Content-Length") && request->payload->len && request->auto_content_length) { k = kms_request_str_new_from_chars ("Content-Length", -1); v = kms_request_str_new (); kms_request_str_appendf (v, "%zu", request->payload->len); kms_kv_list_add (lst, k, v); kms_request_str_destroy (k); kms_request_str_destroy (v); } return true; } /* docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html * * "Build the canonical headers list by sorting the (lowercase) headers by * character code... Do not sort the values in headers that have multiple * values." */ static int cmp_header_field_names (const void *a, const void *b) { return kms_strcasecmp (((kms_kv_t *) a)->key->str, ((kms_kv_t *) b)->key->str); } static kms_kv_list_t * canonical_headers (const kms_request_t *request) { kms_kv_list_t *lst; KMS_ASSERT (request->finalized); lst = kms_kv_list_dup (request->header_fields); kms_kv_list_sort (lst, cmp_header_field_names); kms_kv_list_del (lst, "Connection"); return lst; } char * kms_request_get_canonical (kms_request_t *request) { kms_request_str_t *canonical; kms_request_str_t *normalized; kms_kv_list_t *lst; if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } if (!finalize (request)) { return NULL; } canonical = kms_request_str_new (); kms_request_str_append (canonical, request->method); kms_request_str_append_newline (canonical); normalized = kms_request_str_path_normalized (request->path); kms_request_str_append_escaped (canonical, normalized, false); kms_request_str_destroy (normalized); kms_request_str_append_newline (canonical); append_canonical_query (request, canonical); kms_request_str_append_newline (canonical); lst = canonical_headers (request); append_canonical_headers (lst, canonical); kms_request_str_append_newline (canonical); append_signed_headers (lst, canonical); kms_kv_list_destroy (lst); kms_request_str_append_newline (canonical); if (!kms_request_str_append_hashed ( &request->crypto, canonical, request->payload)) { KMS_ERROR (request, "could not generate hash"); kms_request_str_destroy (canonical); return NULL; } return kms_request_str_detach (canonical); } const char * kms_request_get_canonical_header (kms_request_t *request, const char *header) { const kms_kv_t *value; if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } if (!finalize (request)) { return NULL; } value = kms_kv_list_find (request->header_fields, header); if (!value) { return NULL; } return value->value->str; } char * kms_request_get_string_to_sign (kms_request_t *request) { bool success = false; kms_request_str_t *sts; kms_request_str_t *creq = NULL; /* canonical request */ if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } if (!finalize (request)) { return NULL; } sts = kms_request_str_new (); kms_request_str_append_chars (sts, "AWS4-HMAC-SHA256\n", -1); kms_request_str_append (sts, request->datetime); kms_request_str_append_newline (sts); /* credential scope, like "20150830/us-east-1/service/aws4_request" */ kms_request_str_append (sts, request->date); kms_request_str_append_char (sts, '/'); kms_request_str_append (sts, request->region); kms_request_str_append_char (sts, '/'); kms_request_str_append (sts, request->service); kms_request_str_append_chars (sts, "/aws4_request\n", -1); creq = kms_request_str_wrap (kms_request_get_canonical (request), -1); if (!creq) { goto done; } if (!kms_request_str_append_hashed (&request->crypto, sts, creq)) { goto done; } success = true; done: kms_request_str_destroy (creq); if (!success) { kms_request_str_destroy (sts); sts = NULL; } return kms_request_str_detach (sts); } static bool kms_request_hmac (_kms_crypto_t *crypto, unsigned char *out, kms_request_str_t *key, kms_request_str_t *data) { return crypto->sha256_hmac ( crypto->ctx, key->str, key->len, data->str, data->len, out); } static bool kms_request_hmac_again (_kms_crypto_t *crypto, unsigned char *out, unsigned char *in, kms_request_str_t *data) { return crypto->sha256_hmac ( crypto->ctx, (const char *) in, 32, data->str, data->len, out); } bool kms_request_get_signing_key (kms_request_t *request, unsigned char *key) { bool success = false; kms_request_str_t *aws4_plus_secret = NULL; kms_request_str_t *aws4_request = NULL; unsigned char k_date[32]; unsigned char k_region[32]; unsigned char k_service[32]; if (request->failed) { return false; } if (!check_and_prohibit_kmip (request)) { return false; } /* docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html * Pseudocode for deriving a signing key * * kSecret = your secret access key * kDate = HMAC("AWS4" + kSecret, Date) * kRegion = HMAC(kDate, Region) * kService = HMAC(kRegion, Service) * kSigning = HMAC(kService, "aws4_request") */ aws4_plus_secret = kms_request_str_new_from_chars ("AWS4", -1); kms_request_str_append (aws4_plus_secret, request->secret_key); aws4_request = kms_request_str_new_from_chars ("aws4_request", -1); if (!(kms_request_hmac ( &request->crypto, k_date, aws4_plus_secret, request->date) && kms_request_hmac_again ( &request->crypto, k_region, k_date, request->region) && kms_request_hmac_again ( &request->crypto, k_service, k_region, request->service) && kms_request_hmac_again ( &request->crypto, key, k_service, aws4_request))) { goto done; } success = true; done: kms_request_str_destroy (aws4_plus_secret); kms_request_str_destroy (aws4_request); return success; } char * kms_request_get_signature (kms_request_t *request) { bool success = false; kms_kv_list_t *lst = NULL; kms_request_str_t *sig = NULL; kms_request_str_t *sts = NULL; unsigned char signing_key[32]; unsigned char signature[32]; if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return NULL; } sts = kms_request_str_wrap (kms_request_get_string_to_sign (request), -1); if (!sts) { goto done; } sig = kms_request_str_new (); kms_request_str_append_chars (sig, "AWS4-HMAC-SHA256 Credential=", -1); kms_request_str_append (sig, request->access_key_id); kms_request_str_append_char (sig, '/'); kms_request_str_append (sig, request->date); kms_request_str_append_char (sig, '/'); kms_request_str_append (sig, request->region); kms_request_str_append_char (sig, '/'); kms_request_str_append (sig, request->service); kms_request_str_append_chars (sig, "/aws4_request, SignedHeaders=", -1); lst = canonical_headers (request); append_signed_headers (lst, sig); kms_request_str_append_chars (sig, ", Signature=", -1); if (!(kms_request_get_signing_key (request, signing_key) && kms_request_hmac_again ( &request->crypto, signature, signing_key, sts))) { goto done; } kms_request_str_append_hex (sig, signature, sizeof (signature)); success = true; done: kms_kv_list_destroy (lst); kms_request_str_destroy (sts); if (!success) { kms_request_str_destroy (sig); sig = NULL; } return kms_request_str_detach (sig); } void kms_request_validate (kms_request_t *request) { if (!check_and_prohibit_kmip (request)) { return; } if (0 == request->region->len) { KMS_ERROR (request, "Region not set"); } else if (0 == request->service->len) { KMS_ERROR (request, "Service not set"); } else if (0 == request->access_key_id->len) { KMS_ERROR (request, "Access key ID not set"); } else if (0 == request->method->len) { KMS_ERROR (request, "Method not set"); } else if (0 == request->path->len) { KMS_ERROR (request, "Path not set"); } else if (0 == request->date->len) { KMS_ERROR (request, "Date not set"); } else if (0 == request->secret_key->len) { KMS_ERROR (request, "Secret key not set"); } } /* append_http_endofline appends an HTTP end-of-line marker: "\r\n". */ static void append_http_endofline (kms_request_str_t *str) { kms_request_str_append_chars (str, "\r\n", 2); } char * kms_request_get_signed (kms_request_t *request) { bool success = false; kms_kv_list_t *lst = NULL; char *signature = NULL; kms_request_str_t *sreq = NULL; size_t i; kms_request_validate (request); if (request->failed) { return NULL; } if (!check_and_prohibit_kmip (request)) { return false; } if (!finalize (request)) { return NULL; } sreq = kms_request_str_new (); /* like "POST / HTTP/1.1" */ kms_request_str_append (sreq, request->method); kms_request_str_append_char (sreq, ' '); kms_request_str_append (sreq, request->path); if (request->query->len) { kms_request_str_append_char (sreq, '?'); kms_request_str_append (sreq, request->query); } kms_request_str_append_chars (sreq, " HTTP/1.1", -1); append_http_endofline (sreq); /* headers */ lst = kms_kv_list_dup (request->header_fields); kms_kv_list_sort (lst, cmp_header_field_names); for (i = 0; i < lst->len; i++) { kms_request_str_append (sreq, lst->kvs[i].key); kms_request_str_append_char (sreq, ':'); kms_request_str_append (sreq, lst->kvs[i].value); append_http_endofline (sreq); } /* authorization header */ signature = kms_request_get_signature (request); if (!signature) { goto done; } /* note space after ':', to match test .sreq files */ kms_request_str_append_chars (sreq, "Authorization: ", -1); kms_request_str_append_chars (sreq, signature, -1); /* body */ if (request->payload->len) { append_http_endofline (sreq); append_http_endofline (sreq); kms_request_str_append (sreq, request->payload); } success = true; done: free (signature); kms_kv_list_destroy (lst); if (!success) { kms_request_str_destroy (sreq); sreq = NULL; } return kms_request_str_detach (sreq); } char * kms_request_to_string (kms_request_t *request) { kms_kv_list_t *lst = NULL; kms_request_str_t *sreq = NULL; size_t i; if (!finalize (request)) { return false; } if (!check_and_prohibit_kmip (request)) { return false; } if (request->to_string) { return kms_request_str_detach (kms_request_str_dup (request->to_string)); } sreq = kms_request_str_new (); /* like "POST / HTTP/1.1" */ kms_request_str_append (sreq, request->method); kms_request_str_append_char (sreq, ' '); kms_request_str_append (sreq, request->path); if (request->query->len) { kms_request_str_append_char (sreq, '?'); kms_request_str_append (sreq, request->query); } kms_request_str_append_chars (sreq, " HTTP/1.1", -1); append_http_endofline (sreq); /* headers */ lst = kms_kv_list_dup (request->header_fields); kms_kv_list_sort (lst, cmp_header_field_names); for (i = 0; i < lst->len; i++) { kms_request_str_append (sreq, lst->kvs[i].key); kms_request_str_append_char (sreq, ':'); kms_request_str_append (sreq, lst->kvs[i].value); append_http_endofline (sreq); } append_http_endofline (sreq); /* body */ if (request->payload->len) { kms_request_str_append (sreq, request->payload); } kms_kv_list_destroy (lst); request->to_string = kms_request_str_dup (sreq); return kms_request_str_detach (sreq); } void kms_request_free_string (char *ptr) { free (ptr); } const uint8_t * kms_request_to_bytes (kms_request_t *request, size_t *len) { if (request->provider == KMS_REQUEST_PROVIDER_KMIP) { *len = request->kmip.len; return request->kmip.data; } if (!request->to_string && !kms_request_to_string (request)) { return NULL; } KMS_ASSERT (request->to_string); *len = request->to_string->len; return (const uint8_t*) request->to_string->str; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_request_opt.c0000644000175100001660000000550114760300420022210 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_request_opt_private.h" #include kms_request_opt_t * kms_request_opt_new (void) { return calloc (1, sizeof (kms_request_opt_t)); } void kms_request_opt_destroy (kms_request_opt_t *request) { free (request); } void kms_request_opt_set_connection_close (kms_request_opt_t *opt, bool connection_close) { opt->connection_close = connection_close; } void kms_request_opt_set_crypto_hooks (kms_request_opt_t *opt, bool (*sha256) (void *ctx, const char *input, size_t len, unsigned char *hash_out), bool (*sha256_hmac) (void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out), void *ctx) { opt->crypto.sha256 = sha256; opt->crypto.sha256_hmac = sha256_hmac; opt->crypto.ctx = ctx; } bool kms_request_opt_set_provider (kms_request_opt_t *opt, kms_request_provider_t provider) { if (provider != KMS_REQUEST_PROVIDER_AWS && provider != KMS_REQUEST_PROVIDER_AZURE && provider != KMS_REQUEST_PROVIDER_GCP && provider != KMS_REQUEST_PROVIDER_KMIP) { return false; } opt->provider = provider; return true; } void kms_request_opt_set_crypto_hook_sign_rsaes_pkcs1_v1_5 ( kms_request_opt_t *opt, bool (*sign_rsaes_pkcs1_v1_5) (void *sign_ctx, const char *private_key, size_t private_key_len, const char *input, size_t input_len, unsigned char *signature_out), void *sign_ctx) { opt->crypto.sign_rsaes_pkcs1_v1_5 = sign_rsaes_pkcs1_v1_5; opt->crypto.sign_ctx = sign_ctx; }mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_request_opt_private.h0000644000175100001660000000170414760300420023750 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_REQUEST_OPT_PRIVATE_H #define KMS_REQUEST_OPT_PRIVATE_H #include "kms_message/kms_message_defines.h" #include "kms_message/kms_request_opt.h" #include "kms_crypto.h" #include struct _kms_request_opt_t { bool connection_close; _kms_crypto_t crypto; kms_request_provider_t provider; }; #endif /* KMS_REQUEST_OPT_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_request_str.c0000644000175100001660000002776314760300420022234 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "hexlify.h" #include "kms_crypto.h" #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_request_str.h" #include "kms_port.h" #include #include #include #include #include /* CHAR_BIT */ bool rfc_3986_tab[256] = {0}; bool kms_initialized = false; static void tables_init (void) { int i; if (kms_initialized) { return; } for (i = 0; i < 256; ++i) { rfc_3986_tab[i] = isalnum (i) || i == '~' || i == '-' || i == '.' || i == '_'; } kms_initialized = true; } kms_request_str_t * kms_request_str_new (void) { kms_request_str_t *s = malloc (sizeof (kms_request_str_t)); KMS_ASSERT (s); s->len = 0; s->size = 16; s->str = malloc (s->size); KMS_ASSERT (s->str); s->str[0] = '\0'; return s; } kms_request_str_t * kms_request_str_new_from_chars (const char *chars, ssize_t len) { kms_request_str_t *s = malloc (sizeof (kms_request_str_t)); KMS_ASSERT (s); size_t actual_len; actual_len = len < 0 ? strlen (chars) : (size_t) len; s->size = actual_len + 1; s->str = malloc (s->size); KMS_ASSERT (s->str); memcpy (s->str, chars, actual_len); s->str[actual_len] = '\0'; s->len = actual_len; return s; } kms_request_str_t * kms_request_str_wrap (char *chars, ssize_t len) { kms_request_str_t *s; if (!chars) { return NULL; } s = malloc (sizeof (kms_request_str_t)); KMS_ASSERT (s); s->str = chars; s->len = len < 0 ? strlen (chars) : (size_t) len; s->size = s->len; return s; } void kms_request_str_destroy (kms_request_str_t *str) { if (!str) { return; } free (str->str); free (str); } char * kms_request_str_detach (kms_request_str_t *str) { if (!str) { return NULL; } char *r = str->str; free (str); return r; } const char * kms_request_str_get (kms_request_str_t *str) { return str->str; } bool kms_request_str_reserve (kms_request_str_t *str, size_t size) { size_t next_size = str->len + size + 1; if (str->size < next_size) { /* next power of 2 */ --next_size; next_size |= next_size >> 1U; next_size |= next_size >> 2U; next_size |= next_size >> 4U; next_size |= next_size >> 8U; next_size |= next_size >> 16U; ++next_size; str->size = next_size; str->str = realloc (str->str, next_size); } return str->str != NULL; } kms_request_str_t * kms_request_str_dup (kms_request_str_t *str) { kms_request_str_t *dup = malloc (sizeof (kms_request_str_t)); KMS_ASSERT (dup); dup->str = kms_strndup (str->str, str->len); dup->len = str->len; dup->size = str->len + 1; return dup; } void kms_request_str_set_chars (kms_request_str_t *str, const char *chars, ssize_t len) { size_t actual_len = len < 0 ? strlen (chars) : (size_t) len; kms_request_str_reserve (str, actual_len); /* adds 1 for nil */ memcpy (str->str, chars, actual_len + 1); str->len = actual_len; } bool kms_request_str_ends_with (kms_request_str_t *str, kms_request_str_t *suffix) { if (str->len >= suffix->len && 0 == strncmp ( &str->str[str->len - suffix->len], suffix->str, suffix->len)) { return true; } return false; } void kms_request_str_append (kms_request_str_t *str, kms_request_str_t *appended) { size_t next_len = str->len + appended->len; kms_request_str_reserve (str, next_len); memcpy (str->str + str->len, appended->str, appended->len); str->len += appended->len; str->str[str->len] = '\0'; } void kms_request_str_append_char (kms_request_str_t *str, char c) { kms_request_str_reserve (str, 1); *(str->str + str->len) = c; ++str->len; str->str[str->len] = '\0'; } void kms_request_str_append_chars (kms_request_str_t *str, const char *appended, ssize_t len) { size_t str_len; if (len < 0) { str_len = strlen (appended); } else { str_len = (size_t) len; } kms_request_str_reserve (str, str_len); memcpy (str->str + str->len, appended, str_len); str->len += str_len; str->str[str->len] = '\0'; } void kms_request_str_append_newline (kms_request_str_t *str) { kms_request_str_append_char (str, '\n'); } void kms_request_str_append_lowercase (kms_request_str_t *str, kms_request_str_t *appended) { size_t i; char *p; i = str->len; kms_request_str_append (str, appended); /* downcase the chars from the old end to the new end of str */ for (; i < str->len; ++i) { p = &str->str[i]; /* ignore UTF-8 non-ASCII chars, which have 1 in the top bit */ if (((unsigned int) (*p) & (0x1U << 7U)) == 0) { *p = (char) tolower (*p); } } } void kms_request_str_appendf (kms_request_str_t *str, const char *format, ...) { va_list args; size_t remaining; int n; KMS_ASSERT (format); while (true) { remaining = str->size - str->len; va_start (args, format); n = vsnprintf (&str->str[str->len], remaining, format, args); va_end (args); if (n > -1 && (size_t) n < remaining) { /* success */ str->len += (size_t) n; return; } if (n > -1) { kms_request_str_reserve (str, (size_t) n); } else { /* TODO: error! */ abort (); } } } void kms_request_str_append_escaped (kms_request_str_t *str, kms_request_str_t *appended, bool escape_slash) { uint8_t *in; uint8_t *out; size_t i; tables_init (); /* might replace each input char with 3 output chars: "%AB" */ kms_request_str_reserve (str, 3 * appended->len); in = (uint8_t *) appended->str; out = (uint8_t *) str->str + str->len; for (i = 0; i < appended->len; ++i) { if (rfc_3986_tab[*in] || (*in == '/' && !escape_slash)) { *out = *in; ++out; ++str->len; } else { sprintf ((char *) out, "%%%02X", *in); out += 3; str->len += 3; } ++in; } } void kms_request_str_append_stripped (kms_request_str_t *str, kms_request_str_t *appended) { const char *src = appended->str; const char *end = appended->str + appended->len; bool space = false; bool comma = false; kms_request_str_reserve (str, appended->len); /* msvcrt is unhappy when it gets non-ANSI characters in isspace */ while (*src >= 0 && isspace (*src)) { ++src; } while (src < end) { /* replace newlines with commas. not documented but see * get-header-value-multiline.creq */ if (*src == '\n') { comma = true; space = false; } else if (*src >= 0 && isspace (*src)) { space = true; } else { if (comma) { kms_request_str_append_char (str, ','); comma = false; space = false; } /* is there a run of spaces waiting to be written as one space? */ if (space) { kms_request_str_append_char (str, ' '); space = false; } kms_request_str_append_char (str, *src); } ++src; } } bool kms_request_str_append_hashed (_kms_crypto_t *crypto, kms_request_str_t *str, kms_request_str_t *appended) { uint8_t hash[32] = {0}; char *hex_chars; if (!crypto->sha256 (crypto->ctx, appended->str, appended->len, hash)) { return false; } hex_chars = hexlify (hash, sizeof (hash)); kms_request_str_append_chars (str, hex_chars, 2 * sizeof (hash)); free (hex_chars); return true; } bool kms_request_str_append_hex (kms_request_str_t *str, unsigned char *data, size_t len) { char *hex_chars; hex_chars = hexlify (data, len); KMS_ASSERT (len <= SSIZE_MAX / 2); kms_request_str_append_chars (str, hex_chars, (ssize_t) (len * 2)); free (hex_chars); return true; } static bool starts_with (char *s, const char *prefix) { if (strstr (s, prefix) == s) { return true; } return false; } /* remove from last slash to the end, but don't remove slash from start */ static void delete_last_segment (kms_request_str_t *str, bool is_absolute) { ssize_t i; if (!str->len) { return; } KMS_ASSERT (str->len < SSIZE_MAX); for (i = (ssize_t) str->len - 1; i >= 0; --i) { if (str->str[i] == '/') { if (i == 0 && is_absolute) { str->len = 1; } else { str->len = (size_t) i; } goto done; } } /* no slashes */ str->len = 0; done: str->str[str->len] = '\0'; } /* follow algorithm in https://tools.ietf.org/html/rfc3986#section-5.2.4, * the block comments are copied from there */ kms_request_str_t * kms_request_str_path_normalized (kms_request_str_t *str) { kms_request_str_t *slash = kms_request_str_new_from_chars ("/", 1); kms_request_str_t *out = kms_request_str_new (); char *in = strdup (str->str); char *p = in; char *end = in + str->len; bool is_absolute = (*p == '/'); if (0 == strcmp (p, "/")) { goto done; } while (p < end) { /* If the input buffer begins with a prefix of "../" or "./", * then remove that prefix from the input buffer */ if (starts_with (p, "../")) { p += 3; } else if (starts_with (p, "./")) { p += 2; } /* otherwise, if the input buffer begins with a prefix of "/./" or "/.", * where "." is a complete path segment, then replace that prefix with "/" * in the input buffer */ else if (starts_with (p, "/./")) { p += 2; } else if (0 == strcmp (p, "/.")) { break; } /* otherwise, if the input buffer begins with a prefix of "/../" or "/..", * where ".." is a complete path segment, then replace that prefix with * "/" in the input buffer and remove the last segment and its preceding * "/" (if any) from the output buffer */ else if (starts_with (p, "/../")) { p += 3; delete_last_segment (out, is_absolute); } else if (0 == strcmp (p, "/..")) { delete_last_segment (out, is_absolute); break; } /* otherwise, if the input buffer consists only of "." or "..", then remove that from the input buffer */ else if (0 == strcmp (p, ".") || 0 == strcmp (p, "..")) { break; } /* otherwise, move the first path segment in the input buffer to the end * of the output buffer, including the initial "/" character (if any) and * any subsequent characters up to, but not including, the next "/" * character or the end of the input buffer. */ else { char *next_slash = strchr (p + 1, '/'); if (!next_slash) { next_slash = end; } /* fold repeated slashes */ if (kms_request_str_ends_with (out, slash) && *p == '/') { ++p; } /* normalize "a/../b" as "b", not as "/b" */ if (out->len == 0 && !is_absolute && *p == '/') { ++p; } kms_request_str_append_chars (out, p, next_slash - p); p = next_slash; } } done: free (in); kms_request_str_destroy (slash); if (!out->len) { kms_request_str_append_char (out, '/'); } return out; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_request_str.h0000644000175100001660000000640214760300420022224 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef KMS_MESSAGE_KMS_REQUEST_STR_H #define KMS_MESSAGE_KMS_REQUEST_STR_H #include "kms_message/kms_message.h" #include "kms_crypto.h" #include #include #include #include typedef struct { char *str; size_t len; size_t size; } kms_request_str_t; KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_new (void); KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_new_from_chars (const char *chars, ssize_t len); KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_wrap (char *chars, ssize_t len); KMS_MSG_EXPORT (void) kms_request_str_destroy (kms_request_str_t *str); KMS_MSG_EXPORT (char *) kms_request_str_detach (kms_request_str_t *str); KMS_MSG_EXPORT (bool) kms_request_str_reserve (kms_request_str_t *str, size_t size); KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_dup (kms_request_str_t *str); KMS_MSG_EXPORT (void) kms_request_str_set_chars (kms_request_str_t *str, const char *chars, ssize_t len); KMS_MSG_EXPORT (bool) kms_request_str_ends_with (kms_request_str_t *str, kms_request_str_t *suffix); KMS_MSG_EXPORT (void) kms_request_str_append (kms_request_str_t *str, kms_request_str_t *appended); KMS_MSG_EXPORT (void) kms_request_str_append_char (kms_request_str_t *str, char c); KMS_MSG_EXPORT (void) kms_request_str_append_chars (kms_request_str_t *str, const char *appended, ssize_t len); KMS_MSG_EXPORT (void) kms_request_str_append_newline (kms_request_str_t *str); KMS_MSG_EXPORT (void) kms_request_str_append_lowercase (kms_request_str_t *str, kms_request_str_t *appended); KMS_MSG_EXPORT (void) kms_request_str_appendf (kms_request_str_t *str, const char *format, ...); KMS_MSG_EXPORT (void) kms_request_strdupf (kms_request_str_t *str, const char *format, ...); KMS_MSG_EXPORT (void) kms_request_str_append_escaped (kms_request_str_t *str, kms_request_str_t *appended, bool escape_slash); KMS_MSG_EXPORT (void) kms_request_str_append_stripped (kms_request_str_t *str, kms_request_str_t *appended); KMS_MSG_EXPORT (bool) kms_request_str_append_hashed (_kms_crypto_t *crypto, kms_request_str_t *str, kms_request_str_t *appended); KMS_MSG_EXPORT (bool) kms_request_str_append_hex (kms_request_str_t *str, unsigned char *data, size_t len); KMS_MSG_EXPORT (kms_request_str_t *) kms_request_str_path_normalized (kms_request_str_t *str); #endif // KMS_MESSAGE_KMS_REQUEST_STR_H mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_response.c0000644000175100001660000000246314760300420021500 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "kms_message/kms_message.h" #include "kms_message_private.h" #include "kms_request_str.h" void kms_response_destroy (kms_response_t *response) { if (response == NULL) { return; } free (response->kmip.data); kms_kv_list_destroy (response->headers); kms_request_str_destroy (response->body); free (response); } const char * kms_response_get_body (kms_response_t *response, size_t *len) { if (len) { *len = response->body->len; } return response->body->str; } int kms_response_get_status (kms_response_t *response) { return response->status; } const char * kms_response_get_error (const kms_response_t *response) { return response->failed ? response->error : NULL; } mongodb-1.21.0/src/libmongocrypt/kms-message/src/kms_response_parser.c0000644000175100001660000002626514760300420023062 0ustar #include "kms_message/kms_response_parser.h" #include "kms_message_private.h" #include "kms_kmip_response_parser_private.h" #include #include #include #include #include "hexlify.h" /* destroys the members of parser, but not the parser itself. */ static void _parser_destroy (kms_response_parser_t *parser) { kms_request_str_destroy (parser->raw_response); parser->raw_response = NULL; parser->content_length = -1; kms_response_destroy (parser->response); parser->response = NULL; kms_kmip_response_parser_destroy (parser->kmip); } /* initializes the members of parser. */ static void _parser_init (kms_response_parser_t *parser) { parser->raw_response = kms_request_str_new (); parser->content_length = -1; parser->response = calloc (1, sizeof (kms_response_t)); KMS_ASSERT (parser->response); parser->response->headers = kms_kv_list_new (); parser->state = PARSING_STATUS_LINE; parser->start = 0; parser->failed = false; parser->chunk_size = 0; parser->transfer_encoding_chunked = false; parser->kmip = NULL; } void kms_response_parser_reset (kms_response_parser_t *parser) { KMS_ASSERT(!parser->kmip); // KMIP is not-yet supported. _parser_destroy(parser); _parser_init(parser); } kms_response_parser_t * kms_response_parser_new (void) { kms_response_parser_t *parser = malloc (sizeof (kms_response_parser_t)); KMS_ASSERT (parser); _parser_init (parser); return parser; } int kms_response_parser_wants_bytes (kms_response_parser_t *parser, int32_t max) { if (parser->kmip) { return kms_kmip_response_parser_wants_bytes (parser->kmip, max); } switch (parser->state) { case PARSING_DONE: return 0; case PARSING_STATUS_LINE: case PARSING_HEADER: return max; case PARSING_CHUNK_LENGTH: return max; case PARSING_CHUNK: /* add 2 for trailing \r\n */ return (parser->chunk_size + 2) - ((int) parser->raw_response->len - parser->start); case PARSING_BODY: KMS_ASSERT (parser->content_length != -1); return parser->content_length - ((int) parser->raw_response->len - parser->start); default: KMS_ASSERT (false && "Invalid kms_response_parser HTTP state"); } return -1; } static bool _parse_int (const char *str, int *result) { char *endptr = NULL; int64_t long_result; errno = 0; long_result = strtol (str, &endptr, 10); if (endptr == str) { /* No digits were parsed. Consider this an error */ return false; } if (endptr != NULL && *endptr != '\0') { /* endptr points to the first invalid character. */ return false; } if (errno == EINVAL || errno == ERANGE) { return false; } if (long_result > INT32_MAX || long_result < INT32_MIN) { return false; } *result = (int) long_result; return true; } /* parse an int from a substring inside of a string. */ static bool _parse_int_from_view (const char *str, int start, int end, int *result) { KMS_ASSERT (end >= start); char *num_str = malloc ((size_t) (end - start + 1)); KMS_ASSERT (num_str); bool ret; strncpy (num_str, str + start, (size_t) (end - start)); num_str[end - start] = '\0'; ret = _parse_int (num_str, result); free (num_str); return ret; } static bool _parse_hex_from_view (const char *str, int len, int *result) { KMS_ASSERT (len >= 0); *result = unhexlify (str, (size_t) len); if (*result < 0) { return false; } return true; } /* returns true if char is "linear white space". This *ignores* the folding case * of CRLF followed by WSP. See https://stackoverflow.com/a/21072806/774658 */ static bool _is_lwsp (char c) { return c == ' ' || c == 0x09 /* HTAB */; } /* parse a header line or status line. */ static kms_response_parser_state_t _parse_line (kms_response_parser_t *parser, int end) { int i = parser->start; const char *raw = parser->raw_response->str; kms_response_t *response = parser->response; if (parser->state == PARSING_STATUS_LINE) { /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ int j; int status; if (strncmp (raw + i, "HTTP/1.1 ", 9) != 0) { KMS_ERROR (parser, "Could not parse HTTP-Version."); return PARSING_DONE; } i += 9; for (j = i; j < end; j++) { if (raw[j] == ' ') break; } if (!_parse_int_from_view (raw, i, j, &status)) { KMS_ERROR (parser, "Could not parse Status-Code."); return PARSING_DONE; } response->status = status; /* ignore the Reason-Phrase. */ return PARSING_HEADER; } else if (parser->state == PARSING_HEADER) { /* Treating a header as: * message-header = field-name ":" [ field-value ] CRLF * This is not completely correct, and does not take folding into acct. * See https://tools.ietf.org/html/rfc822#section-3.1 */ int j; kms_request_str_t *key; kms_request_str_t *val; if (i == end) { /* empty line, this signals the start of the body. */ if (parser->transfer_encoding_chunked) { return PARSING_CHUNK_LENGTH; } return PARSING_BODY; } for (j = i; j < end; j++) { if (raw[j] == ':') break; } if (j == end) { KMS_ERROR (parser, "Could not parse header, no colon found."); return PARSING_DONE; } key = kms_request_str_new_from_chars (raw + i, j - i); i = j + 1; /* remove leading and trailing whitespace from the value. */ for (j = i; j < end; j++) { if (!_is_lwsp (raw[j])) break; } i = j; /* find the end of the header by backtracking. */ for (j = end; j > i; j--) { if (!_is_lwsp (raw[j])) break; } if (i == j) { val = kms_request_str_new (); } else { val = kms_request_str_new_from_chars (raw + i, j - i); } kms_kv_list_add (response->headers, key, val); /* if we have *not* read the Content-Length yet, check. */ if (parser->content_length == -1 && strcmp (key->str, "Content-Length") == 0) { if (!_parse_int (val->str, &parser->content_length)) { KMS_ERROR (parser, "Could not parse Content-Length header."); kms_request_str_destroy (key); kms_request_str_destroy (val); return PARSING_DONE; } } if (0 == strcmp (key->str, "Transfer-Encoding")) { if (0 == strcmp (val->str, "chunked")) { parser->transfer_encoding_chunked = true; } else { KMS_ERROR (parser, "Unsupported Transfer-Encoding: %s", val->str); kms_request_str_destroy (key); kms_request_str_destroy (val); return PARSING_DONE; } } kms_request_str_destroy (key); kms_request_str_destroy (val); return PARSING_HEADER; } else if (parser->state == PARSING_CHUNK_LENGTH) { int result = 0; if (!_parse_hex_from_view (raw + i, end - i, &result)) { KMS_ERROR (parser, "Failed to parse hex chunk length."); return PARSING_DONE; } parser->chunk_size = result; return PARSING_CHUNK; } return PARSING_DONE; } bool kms_response_parser_feed (kms_response_parser_t *parser, uint8_t *buf, uint32_t len) { kms_request_str_t *raw = parser->raw_response; int curr, body_read, chunk_read; if (parser->kmip) { return kms_kmip_response_parser_feed (parser->kmip, buf, len); } curr = (int) raw->len; kms_request_str_append_chars (raw, (char *) buf, len); /* process the new data appended. */ while (curr < (int) raw->len) { switch (parser->state) { case PARSING_STATUS_LINE: case PARSING_HEADER: case PARSING_CHUNK_LENGTH: /* find the next \r\n. */ if (curr && strncmp (raw->str + (curr - 1), "\r\n", 2) == 0) { parser->state = _parse_line (parser, curr - 1); parser->start = curr + 1; } curr++; if (parser->state == PARSING_BODY && parser->content_length <= 0) { /* Ok, no Content-Length header, or explicitly 0, so empty body */ parser->response->body = kms_request_str_new (); parser->state = PARSING_DONE; } break; case PARSING_BODY: body_read = (int) raw->len - parser->start; if (parser->content_length == -1 || body_read > parser->content_length) { KMS_ERROR (parser, "Unexpected: exceeded content length"); return false; } /* check if we have the entire body. */ if (body_read == parser->content_length) { parser->response->body = kms_request_str_new_from_chars ( raw->str + parser->start, parser->content_length); parser->state = PARSING_DONE; } curr = (int) raw->len; break; case PARSING_CHUNK: chunk_read = (int) raw->len - parser->start; /* check if we've read the full chunk and the trailing \r\n */ if (chunk_read >= parser->chunk_size + 2) { if (!parser->response->body) { parser->response->body = kms_request_str_new (); } kms_request_str_append_chars (parser->response->body, raw->str + parser->start, parser->chunk_size); curr = parser->start + parser->chunk_size + 2; parser->start = curr; if (parser->chunk_size == 0) { /* last chunk. */ parser->state = PARSING_DONE; } else { parser->state = PARSING_CHUNK_LENGTH; } } else { curr = (int) raw->len; } break; case PARSING_DONE: KMS_ERROR (parser, "Unexpected extra HTTP content"); return false; default: KMS_ASSERT (false && "Invalid kms_response_parser HTTP state"); } } if (parser->failed) { return false; } return true; } /* steals the response from the parser. */ kms_response_t * kms_response_parser_get_response (kms_response_parser_t *parser) { kms_response_t *response; if (parser->kmip) { return kms_kmip_response_parser_get_response (parser->kmip); } response = parser->response; parser->response = NULL; /* reset the parser. */ _parser_destroy (parser); _parser_init (parser); return response; } int kms_response_parser_status (kms_response_parser_t *parser) { if (!parser) { return 0; } if (parser->kmip) { KMS_ERROR (parser, "kms_response_parser_status not applicable to KMIP"); return 0; } if (!parser->response) { return 0; } return parser->response->status; } const char * kms_response_parser_error (kms_response_parser_t *parser) { if (!parser) { return NULL; } if (parser->kmip) { return kms_kmip_response_parser_error (parser->kmip); } return parser->error; } void kms_response_parser_destroy (kms_response_parser_t *parser) { _parser_destroy (parser); free (parser); } mongodb-1.21.0/src/libmongocrypt/kms-message/src/sort.c0000644000175100001660000000506614760300420017761 0ustar /* * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Peter McIlroy. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /** * This code is originally from: * https://github.com/freebsd/freebsd/blob/e7c6cef9514d3bb1f14a30a5ee871231523e43db/lib/libc/stdlib/merge.c */ #include /* * This is to avoid out-of-bounds addresses in sorting the * last 4 elements. */ typedef int (*cmp_t) (const void *, const void *); #define CMP(x, y) cmp (x, y) #define swap(a, b) \ { \ s = b; \ i = size; \ do { \ tmp = *a; \ *a++ = *s; \ *s++ = tmp; \ } while (--i); \ a -= size; \ } void insertionsort (unsigned char *a, size_t n, size_t size, cmp_t cmp) { unsigned char *ai, *s, *t, *u, tmp; size_t i; for (ai = a + size; --n >= 1; ai += size) for (t = ai; t > a; t -= size) { u = t - size; if (CMP (u, t) <= 0) break; swap (u, t); } } mongodb-1.21.0/src/libmongocrypt/kms-message/src/sort.h0000644000175100001660000000133514760300420017761 0ustar /* * Copyright 2018-present MongoDB, 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. */ typedef int (*cmp_t) (const void *, const void *); void insertionsort (unsigned char *a, size_t n, size_t size, cmp_t cmp); mongodb-1.21.0/src/libmongocrypt/src/crypto/cng.c0000644000175100001660000004411514760300420016643 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "../mongocrypt-crypto-private.h" #include "../mongocrypt-private.h" #include #ifdef MONGOCRYPT_ENABLE_CRYPTO_CNG #include static BCRYPT_ALG_HANDLE _algo_sha512_hmac = 0; static BCRYPT_ALG_HANDLE _algo_sha256_hmac = 0; static BCRYPT_ALG_HANDLE _algo_aes256_cbc = 0; static BCRYPT_ALG_HANDLE _algo_aes256_ecb = 0; static DWORD _aes256_key_blob_length; static DWORD _aes256_block_length; static BCRYPT_ALG_HANDLE _random; #define STATUS_SUCCESS 0 bool _native_crypto_initialized = false; void _native_crypto_init(void) { DWORD cbOutput; NTSTATUS nt_status; /* Note, there is no mechanism for libmongocrypt to close these providers, * If we ever add such a mechanism, call BCryptCloseAlgorithmProvider. */ nt_status = BCryptOpenAlgorithmProvider(&_algo_sha512_hmac, BCRYPT_SHA512_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG); if (nt_status != STATUS_SUCCESS) { return; } nt_status = BCryptOpenAlgorithmProvider(&_algo_sha256_hmac, BCRYPT_SHA256_ALGORITHM, MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG); if (nt_status != STATUS_SUCCESS) { return; } nt_status = BCryptOpenAlgorithmProvider(&_algo_aes256_cbc, BCRYPT_AES_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0); if (nt_status != STATUS_SUCCESS) { return; } nt_status = BCryptSetProperty(_algo_aes256_cbc, BCRYPT_CHAINING_MODE, (PUCHAR)(BCRYPT_CHAIN_MODE_CBC), (ULONG)(sizeof(wchar_t) * wcslen(BCRYPT_CHAIN_MODE_CBC)), 0); if (nt_status != STATUS_SUCCESS) { return; } nt_status = BCryptOpenAlgorithmProvider(&_algo_aes256_ecb, BCRYPT_AES_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0); if (nt_status != STATUS_SUCCESS) { return; } nt_status = BCryptSetProperty(_algo_aes256_ecb, BCRYPT_CHAINING_MODE, (PUCHAR)(BCRYPT_CHAIN_MODE_ECB), (ULONG)(sizeof(wchar_t) * wcslen(BCRYPT_CHAIN_MODE_ECB)), 0); if (nt_status != STATUS_SUCCESS) { return; } cbOutput = sizeof(_aes256_key_blob_length); nt_status = BCryptGetProperty(_algo_aes256_cbc, BCRYPT_OBJECT_LENGTH, (PUCHAR)(&_aes256_key_blob_length), cbOutput, &cbOutput, 0); if (nt_status != STATUS_SUCCESS) { return; } cbOutput = sizeof(_aes256_block_length); nt_status = BCryptGetProperty(_algo_aes256_cbc, BCRYPT_BLOCK_LENGTH, (PUCHAR)(&_aes256_block_length), cbOutput, &cbOutput, 0); if (nt_status != STATUS_SUCCESS) { return; } nt_status = BCryptOpenAlgorithmProvider(&_random, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0); if (nt_status != STATUS_SUCCESS) { return; } _native_crypto_initialized = true; } typedef struct { unsigned char *key_object; uint32_t key_object_length; BCRYPT_KEY_HANDLE key_handle; unsigned char *iv; uint32_t iv_len; } cng_encrypt_state; static void _crypto_state_destroy(cng_encrypt_state *state); static cng_encrypt_state * _crypto_state_init(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *iv, mongocrypt_status_t *status) { cng_encrypt_state *state; uint32_t keyBlobLength; unsigned char *keyBlob; BCRYPT_KEY_DATA_BLOB_HEADER blobHeader; NTSTATUS nt_status; BSON_ASSERT_PARAM(key); BSON_ASSERT_PARAM(iv); keyBlob = NULL; state = bson_malloc0(sizeof(*state)); BSON_ASSERT(state); state->key_handle = INVALID_HANDLE_VALUE; /* Initialize key storage buffer */ state->key_object = bson_malloc0(_aes256_key_blob_length); BSON_ASSERT(state->key_object); state->key_object_length = _aes256_key_blob_length; /* Allocate temporary buffer for key import */ BSON_ASSERT(sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->len <= UINT32_MAX); keyBlobLength = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->len; keyBlob = bson_malloc0(keyBlobLength); BSON_ASSERT(keyBlob); blobHeader.dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; blobHeader.dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; blobHeader.cbKeyData = key->len; memcpy(keyBlob, &blobHeader, sizeof(BCRYPT_KEY_DATA_BLOB_HEADER)); memcpy(keyBlob + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), key->data, key->len); nt_status = BCryptImportKey(_algo_aes256_cbc, NULL, BCRYPT_KEY_DATA_BLOB, &(state->key_handle), state->key_object, state->key_object_length, keyBlob, keyBlobLength, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("Import Key Failed: 0x%x", (int)nt_status); goto fail; } bson_free(keyBlob); state->iv = bson_malloc0(iv->len); BSON_ASSERT(state->iv); state->iv_len = iv->len; memcpy(state->iv, iv->data, iv->len); return state; fail: _crypto_state_destroy(state); bson_free(keyBlob); return NULL; } static void _crypto_state_destroy(cng_encrypt_state *state) { if (state) { /* Free the key handle before the key_object that contains it */ if (state->key_handle != INVALID_HANDLE_VALUE) { BCryptDestroyKey(state->key_handle); } bson_free(state->key_object); bson_free(state->iv); bson_free(state); } } bool _native_crypto_aes_256_cbc_encrypt(aes_256_args_t args) { BSON_ASSERT(args.in); BSON_ASSERT(args.out); bool ret = false; mongocrypt_status_t *status = args.status; cng_encrypt_state *state = _crypto_state_init(args.key, args.iv, status); BSON_ASSERT(state); NTSTATUS nt_status; nt_status = BCryptEncrypt(state->key_handle, (PUCHAR)(args.in->data), args.in->len, NULL, state->iv, state->iv_len, args.out->data, args.out->len, args.bytes_written, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("error initializing cipher: 0x%x", (int)nt_status); goto done; } ret = true; done: _crypto_state_destroy(state); return ret; } bool _native_crypto_aes_256_cbc_decrypt(aes_256_args_t args) { BSON_ASSERT(args.in); BSON_ASSERT(args.out); bool ret = false; mongocrypt_status_t *status = args.status; cng_encrypt_state *state = _crypto_state_init(args.key, args.iv, status); BSON_ASSERT(state); NTSTATUS nt_status; nt_status = BCryptDecrypt(state->key_handle, (PUCHAR)(args.in->data), args.in->len, NULL, state->iv, state->iv_len, args.out->data, args.out->len, args.bytes_written, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("error initializing cipher: 0x%x", (int)nt_status); goto done; } ret = true; done: _crypto_state_destroy(state); return ret; } /* _hmac_with_algorithm computes an HMAC of @in with the algorithm specified by * @hAlgorithm. * @key is the input key. * @out is the output. @out must be allocated by the caller with * the expected length @expect_out_len for the output. * Returns false and sets @status on error. @status is required. */ static bool _hmac_with_algorithm(BCRYPT_ALG_HANDLE hAlgorithm, const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, uint32_t expect_out_len, mongocrypt_status_t *status) { bool ret = false; BCRYPT_HASH_HANDLE hHash; NTSTATUS nt_status; BSON_ASSERT_PARAM(key); BSON_ASSERT_PARAM(in); BSON_ASSERT_PARAM(out); if (out->len != expect_out_len) { CLIENT_ERR("out does not contain " PRIu32 " bytes", expect_out_len); return false; } nt_status = BCryptCreateHash(hAlgorithm, &hHash, NULL, 0, (PUCHAR)key->data, (ULONG)key->len, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("error initializing hmac: 0x%x", (int)nt_status); /* Only call BCryptDestroyHash if BCryptCreateHash succeeded. */ return false; } nt_status = BCryptHashData(hHash, (PUCHAR)in->data, (ULONG)in->len, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("error hashing data: 0x%x", (int)nt_status); goto done; } nt_status = BCryptFinishHash(hHash, out->data, out->len, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("error finishing hmac: 0x%x", (int)nt_status); goto done; } ret = true; done: (void)BCryptDestroyHash(hHash); return ret; } bool _native_crypto_hmac_sha_512(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { return _hmac_with_algorithm(_algo_sha512_hmac, key, in, out, MONGOCRYPT_HMAC_SHA512_LEN, status); } bool _native_crypto_random(_mongocrypt_buffer_t *out, uint32_t count, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(out); NTSTATUS nt_status = BCryptGenRandom(_random, out->data, count, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("BCryptGenRandom Failed: 0x%x", (int)nt_status); return false; } return true; } typedef struct { BCRYPT_KEY_HANDLE key_handle; unsigned char *input_block; uint32_t input_block_len; unsigned char *output_block; uint32_t output_block_len; uint32_t output_block_ptr; } cng_ctr_encrypt_state; static bool _cng_ctr_crypto_generate(cng_ctr_encrypt_state *state, mongocrypt_status_t *status) { BSON_ASSERT(state); uint32_t bytesEncrypted = 0; NTSTATUS nt_status = BCryptEncrypt(state->key_handle, state->input_block, state->input_block_len, NULL, NULL, 0, state->output_block, state->output_block_len, &bytesEncrypted, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("error encrypting: 0x%x", (int)nt_status); return false; } BSON_ASSERT(bytesEncrypted); state->output_block_ptr = 0; return true; } static void _cng_ctr_crypto_advance(cng_ctr_encrypt_state *state) { BSON_ASSERT_PARAM(state); /* Assert rather than return false/NULL since this function's type is void */ BSON_ASSERT(sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) <= UINT32_MAX - state->input_block_len); uint32_t carry = 1; for (int i = (int)state->input_block_len - 1; i >= 0 && carry != 0; --i) { uint32_t bpp = (uint32_t)(state->input_block[i]) + carry; carry = bpp >> 8; state->input_block[i] = bpp & 0xFF; } } static bool _cng_ctr_crypto_next(cng_ctr_encrypt_state *state, mongocrypt_status_t *status, unsigned char *mask) { BSON_ASSERT_PARAM(state); BSON_ASSERT_PARAM(mask); if (state->output_block_ptr >= state->output_block_len) { _cng_ctr_crypto_advance(state); if (!_cng_ctr_crypto_generate(state, status)) { return false; }; } *mask = state->output_block[state->output_block_ptr]; ++state->output_block_ptr; return true; } static void _cng_ctr_crypto_state_destroy(cng_ctr_encrypt_state *state); static cng_ctr_encrypt_state *_cng_ctr_crypto_state_init(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *iv, mongocrypt_status_t *status) { cng_ctr_encrypt_state *state; uint32_t keyBlobLength; unsigned char *keyBlob; BCRYPT_KEY_DATA_BLOB_HEADER blobHeader; NTSTATUS nt_status; BSON_ASSERT_PARAM(key); BSON_ASSERT_PARAM(iv); keyBlob = NULL; state = bson_malloc0(sizeof(*state)); BSON_ASSERT(state); if (UINT32_MAX - key->len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER)) { CLIENT_ERR("key is too long"); goto fail; } state->key_handle = INVALID_HANDLE_VALUE; /* Initialize input storage buffer */ state->input_block = bson_malloc0(_aes256_block_length); BSON_ASSERT(state->input_block); state->input_block_len = _aes256_block_length; BSON_ASSERT(iv->len == _aes256_block_length); memcpy(state->input_block, iv->data, iv->len); /* Initialize output storage buffer */ state->output_block = bson_malloc0(_aes256_block_length); BSON_ASSERT(state->output_block); state->output_block_len = _aes256_block_length; state->output_block_ptr = 0; /* Allocate temporary buffer for key import */ keyBlobLength = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->len; keyBlob = bson_malloc0(keyBlobLength); BSON_ASSERT(keyBlob); blobHeader.dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; blobHeader.dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; blobHeader.cbKeyData = key->len; memcpy(keyBlob, &blobHeader, sizeof(BCRYPT_KEY_DATA_BLOB_HEADER)); memcpy(keyBlob + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), key->data, key->len); nt_status = BCryptImportKey(_algo_aes256_ecb, NULL, BCRYPT_KEY_DATA_BLOB, &(state->key_handle), NULL, 0, keyBlob, keyBlobLength, 0); if (nt_status != STATUS_SUCCESS) { CLIENT_ERR("Import Key Failed: 0x%x", (int)nt_status); goto fail; } bson_free(keyBlob); if (!_cng_ctr_crypto_generate(state, status)) { goto fail; } return state; fail: _cng_ctr_crypto_state_destroy(state); bson_free(keyBlob); return NULL; } static void _cng_ctr_crypto_state_destroy(cng_ctr_encrypt_state *state) { if (state) { if (state->key_handle != INVALID_HANDLE_VALUE) { BCryptDestroyKey(state->key_handle); } bson_free(state->input_block); bson_free(state->output_block); bson_free(state); } } bool _native_crypto_aes_256_ctr_encrypt(aes_256_args_t args) { bool ret = false; cng_ctr_encrypt_state *state = NULL; mongocrypt_status_t *status = args.status; BSON_ASSERT(args.in && args.in->data); BSON_ASSERT(args.out && args.out->data); if (args.out->len < args.in->len) { CLIENT_ERR("Output buffer is too small"); goto fail; } state = _cng_ctr_crypto_state_init(args.key, args.iv, status); if (!state) { goto fail; } for (uint32_t i = 0; i < args.in->len; ++i) { unsigned char mask; if (!_cng_ctr_crypto_next(state, status, &mask)) { goto fail; } args.out->data[i] = args.in->data[i] ^ mask; } if (args.bytes_written) { *args.bytes_written = args.in->len; } ret = true; fail: _cng_ctr_crypto_state_destroy(state); return ret; } bool _native_crypto_aes_256_ctr_decrypt(aes_256_args_t args) { bool ret = false; cng_ctr_encrypt_state *state = NULL; mongocrypt_status_t *status = args.status; BSON_ASSERT(args.in && args.in->data); BSON_ASSERT(args.out && args.out->data); if (args.out->len < args.in->len) { CLIENT_ERR("Output buffer is too small"); goto fail; } state = _cng_ctr_crypto_state_init(args.key, args.iv, status); if (!state) { goto fail; } for (uint32_t i = 0; i < args.in->len; ++i) { unsigned char mask; if (!_cng_ctr_crypto_next(state, status, &mask)) { goto fail; } args.out->data[i] = args.in->data[i] ^ mask; } if (args.bytes_written) { *args.bytes_written = args.in->len; } ret = true; fail: _cng_ctr_crypto_state_destroy(state); return ret; } bool _native_crypto_hmac_sha_256(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { return _hmac_with_algorithm(_algo_sha256_hmac, key, in, out, MONGOCRYPT_HMAC_SHA256_LEN, status); } #endif /* MONGOCRYPT_ENABLE_CRYPTO_CNG */ mongodb-1.21.0/src/libmongocrypt/src/crypto/commoncrypto.c0000644000175100001660000002341714760300420020627 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "../mongocrypt-crypto-private.h" #include "../mongocrypt-private.h" #ifdef MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO #include #include #include static const char *CCCryptorStatus_to_string(CCCryptorStatus status) { switch (status) { case kCCSuccess: return "Success"; case kCCParamError: return "ParamError"; case kCCBufferTooSmall: return "BufferTooSmall"; case kCCMemoryFailure: return "MemoryFailure"; case kCCAlignmentError: return "AlignmentError"; case kCCDecodeError: return "DecodeError"; case kCCUnimplemented: return "Unimplemented"; case kCCOverflow: return "Overflow"; case kCCRNGFailure: return "RNGFailure"; case kCCUnspecifiedError: return "UnspecifiedError"; case kCCCallSequenceError: return "CallSequenceError"; case kCCKeySizeError: return "KeySizeError"; case kCCInvalidKey: return "InvalidKey"; default: return "Unknown"; } } bool _native_crypto_initialized = false; void _native_crypto_init(void) { _native_crypto_initialized = true; } static bool _native_crypto_aes_256_cbc_encrypt_with_mode(aes_256_args_t args, CCMode mode) { BSON_ASSERT(args.iv); BSON_ASSERT(args.key); BSON_ASSERT(args.in); BSON_ASSERT(args.out); bool ret = false; CCCryptorRef ctx = NULL; CCCryptorStatus cc_status; size_t intermediate_bytes_written; mongocrypt_status_t *status = args.status; cc_status = CCCryptorCreateWithMode(kCCEncrypt, mode, kCCAlgorithmAES, 0 /* defaults to CBC w/ no padding */, args.iv->data, args.key->data, kCCKeySizeAES256, NULL, 0, 0, 0, &ctx); if (cc_status != kCCSuccess) { if (cc_status == kCCUnimplemented && mode == kCCModeCTR) { CLIENT_ERR("error initializing cipher: %s (%d). CTR mode is only " "supported on macOS 10.15+", CCCryptorStatus_to_string(cc_status), (int)cc_status); } else { CLIENT_ERR("error initializing cipher: %s (%d)", CCCryptorStatus_to_string(cc_status), (int)cc_status); } goto done; } *args.bytes_written = 0; cc_status = CCCryptorUpdate(ctx, args.in->data, args.in->len, args.out->data, args.out->len, &intermediate_bytes_written); if (cc_status != kCCSuccess) { CLIENT_ERR("error encrypting: %s (%d)", CCCryptorStatus_to_string(cc_status), (int)cc_status); goto done; } BSON_ASSERT(intermediate_bytes_written <= UINT32_MAX); *args.bytes_written = (uint32_t)intermediate_bytes_written; BSON_ASSERT(args.out->len >= *args.bytes_written); cc_status = CCCryptorFinal(ctx, args.out->data + *args.bytes_written, args.out->len - *args.bytes_written, &intermediate_bytes_written); BSON_ASSERT(UINT32_MAX - *args.bytes_written >= intermediate_bytes_written); *args.bytes_written += intermediate_bytes_written; if (cc_status != kCCSuccess) { CLIENT_ERR("error finalizing: %s (%d)", CCCryptorStatus_to_string(cc_status), (int)cc_status); goto done; } ret = true; done: CCCryptorRelease(ctx); return ret; } bool _native_crypto_aes_256_cbc_encrypt(aes_256_args_t args) { return _native_crypto_aes_256_cbc_encrypt_with_mode(args, kCCModeCBC); } bool _native_crypto_aes_256_ctr_encrypt(aes_256_args_t args) { return _native_crypto_aes_256_cbc_encrypt_with_mode(args, kCCModeCTR); } /* Note, the decrypt function is almost exactly the same as the encrypt * functions except for the kCCDecrypt and the error message. */ static bool _native_crypto_aes_256_cbc_decrypt_with_mode(aes_256_args_t args, CCMode mode) { BSON_ASSERT(args.iv); BSON_ASSERT(args.key); BSON_ASSERT(args.in); BSON_ASSERT(args.out); bool ret = false; CCCryptorRef ctx = NULL; CCCryptorStatus cc_status; size_t intermediate_bytes_written; mongocrypt_status_t *status = args.status; cc_status = CCCryptorCreateWithMode(kCCDecrypt, mode, kCCAlgorithmAES, 0 /* defaults to CBC w/ no padding */, args.iv->data, args.key->data, kCCKeySizeAES256, NULL, 0, 0, 0, &ctx); if (cc_status != kCCSuccess) { if (cc_status == kCCUnimplemented && mode == kCCModeCTR) { CLIENT_ERR("error initializing cipher: %s (%d). CTR mode is only " "supported on macOS 10.15+", CCCryptorStatus_to_string(cc_status), (int)cc_status); } else { CLIENT_ERR("error initializing cipher: %s (%d)", CCCryptorStatus_to_string(cc_status), (int)cc_status); } goto done; } *args.bytes_written = 0; cc_status = CCCryptorUpdate(ctx, args.in->data, args.in->len, args.out->data, args.out->len, &intermediate_bytes_written); if (cc_status != kCCSuccess) { CLIENT_ERR("error decrypting: %s (%d)", CCCryptorStatus_to_string(cc_status), (int)cc_status); goto done; } BSON_ASSERT(intermediate_bytes_written <= UINT32_MAX); *args.bytes_written = (uint32_t)intermediate_bytes_written; BSON_ASSERT(args.out->len >= *args.bytes_written); cc_status = CCCryptorFinal(ctx, args.out->data + *args.bytes_written, args.out->len - *args.bytes_written, &intermediate_bytes_written); BSON_ASSERT(UINT32_MAX - *args.bytes_written >= intermediate_bytes_written); *args.bytes_written += intermediate_bytes_written; if (cc_status != kCCSuccess) { CLIENT_ERR("error finalizing: %s (%d)", CCCryptorStatus_to_string(cc_status), (int)cc_status); goto done; } ret = true; done: CCCryptorRelease(ctx); return ret; } bool _native_crypto_aes_256_cbc_decrypt(aes_256_args_t args) { return _native_crypto_aes_256_cbc_decrypt_with_mode(args, kCCModeCBC); } bool _native_crypto_aes_256_ctr_decrypt(aes_256_args_t args) { return _native_crypto_aes_256_cbc_decrypt_with_mode(args, kCCModeCTR); } /* _hmac_with_algorithm computes an HMAC of @in with the algorithm specified by * @algorithm. * @key is the input key. * @out is the output. @out must be allocated by the caller with * the expected length @expect_out_len for the output. * Returns false and sets @status on error. @status is required. */ static bool _hmac_with_algorithm(CCHmacAlgorithm algorithm, const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, uint32_t expect_out_len, mongocrypt_status_t *status) { CCHmacContext *ctx; BSON_ASSERT_PARAM(key); BSON_ASSERT_PARAM(in); BSON_ASSERT_PARAM(out); if (out->len != expect_out_len) { CLIENT_ERR("out does not contain %" PRIu32 " bytes", expect_out_len); return false; } ctx = bson_malloc0(sizeof(*ctx)); BSON_ASSERT(ctx); /* The ->len members are uint32_t and these functions take size_t */ CCHmacInit(ctx, algorithm, key->data, key->len); CCHmacUpdate(ctx, in->data, in->len); CCHmacFinal(ctx, out->data); bson_free(ctx); return true; } bool _native_crypto_hmac_sha_512(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { return _hmac_with_algorithm(kCCHmacAlgSHA512, key, in, out, MONGOCRYPT_HMAC_SHA512_LEN, status); } bool _native_crypto_random(_mongocrypt_buffer_t *out, uint32_t count, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(out); CCRNGStatus ret = CCRandomGenerateBytes(out->data, (size_t)count); if (ret != kCCSuccess) { CLIENT_ERR("failed to generate random iv: %d", (int)ret); return false; } return true; } bool _native_crypto_hmac_sha_256(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { return _hmac_with_algorithm(kCCHmacAlgSHA256, key, in, out, MONGOCRYPT_HMAC_SHA256_LEN, status); } #endif /* MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO */ mongodb-1.21.0/src/libmongocrypt/src/crypto/libcrypto.c0000644000175100001660000002321014760300420020074 0ustar /* * Copyright 2019-present MongoDB, 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. */ /* * Comments in this implementation refer to: * [MCGREW] https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05 */ #include "../mongocrypt-crypto-private.h" #include "../mongocrypt-log-private.h" #include "../mongocrypt-private.h" #ifdef MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO #include #include #include #include #include #include #if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) static HMAC_CTX *HMAC_CTX_new(void) { return bson_malloc0(sizeof(HMAC_CTX)); } static void HMAC_CTX_free(HMAC_CTX *ctx) { HMAC_CTX_cleanup(ctx); bson_free(ctx); } #endif bool _native_crypto_initialized = false; void _native_crypto_init(void) { _native_crypto_initialized = true; } /* _encrypt_with_cipher encrypts @in with the OpenSSL cipher specified by * @cipher. * @key is the input key. @iv is the input IV. * @out is the output ciphertext. @out must be allocated by the caller with * enough room for the ciphertext. * @bytes_written is the number of bytes that were written to @out. * Returns false and sets @status on error. @status is required. */ static bool _encrypt_with_cipher(const EVP_CIPHER *cipher, aes_256_args_t args) { EVP_CIPHER_CTX *ctx; bool ret = false; int intermediate_bytes_written = 0; mongocrypt_status_t *status = args.status; ctx = EVP_CIPHER_CTX_new(); BSON_ASSERT(args.key); BSON_ASSERT(args.in); BSON_ASSERT(args.out); BSON_ASSERT(ctx); BSON_ASSERT(cipher); BSON_ASSERT(NULL == args.iv || (uint32_t)EVP_CIPHER_iv_length(cipher) == args.iv->len); BSON_ASSERT((uint32_t)EVP_CIPHER_key_length(cipher) == args.key->len); BSON_ASSERT(args.in->len <= INT_MAX); if (!EVP_EncryptInit_ex(ctx, cipher, NULL /* engine */, args.key->data, NULL == args.iv ? NULL : args.iv->data)) { CLIENT_ERR("error in EVP_EncryptInit_ex: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } /* Disable the default OpenSSL padding. */ EVP_CIPHER_CTX_set_padding(ctx, 0); *args.bytes_written = 0; if (!EVP_EncryptUpdate(ctx, args.out->data, &intermediate_bytes_written, args.in->data, (int)args.in->len)) { CLIENT_ERR("error in EVP_EncryptUpdate: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } BSON_ASSERT(intermediate_bytes_written >= 0 && (uint64_t)intermediate_bytes_written <= UINT32_MAX); /* intermediate_bytes_written cannot be negative, so int -> uint32_t is OK */ *args.bytes_written = (uint32_t)intermediate_bytes_written; if (!EVP_EncryptFinal_ex(ctx, args.out->data, &intermediate_bytes_written)) { CLIENT_ERR("error in EVP_EncryptFinal_ex: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } BSON_ASSERT(UINT32_MAX - *args.bytes_written >= (uint32_t)intermediate_bytes_written); *args.bytes_written += (uint32_t)intermediate_bytes_written; ret = true; done: EVP_CIPHER_CTX_free(ctx); return ret; } /* _decrypt_with_cipher decrypts @in with the OpenSSL cipher specified by * @cipher. * @key is the input key. @iv is the input IV. * @out is the output plaintext. @out must be allocated by the caller with * enough room for the plaintext. * @bytes_written is the number of bytes that were written to @out. * Returns false and sets @status on error. @status is required. */ static bool _decrypt_with_cipher(const EVP_CIPHER *cipher, aes_256_args_t args) { EVP_CIPHER_CTX *ctx; bool ret = false; int intermediate_bytes_written = 0; mongocrypt_status_t *status = args.status; ctx = EVP_CIPHER_CTX_new(); BSON_ASSERT(ctx); BSON_ASSERT_PARAM(cipher); BSON_ASSERT(args.iv); BSON_ASSERT(args.key); BSON_ASSERT(args.in); BSON_ASSERT(args.out); BSON_ASSERT((uint32_t)EVP_CIPHER_iv_length(cipher) == args.iv->len); BSON_ASSERT((uint32_t)EVP_CIPHER_key_length(cipher) == args.key->len); BSON_ASSERT(args.in->len <= INT_MAX); if (!EVP_DecryptInit_ex(ctx, cipher, NULL /* engine */, args.key->data, args.iv->data)) { CLIENT_ERR("error in EVP_DecryptInit_ex: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } /* Disable padding. */ EVP_CIPHER_CTX_set_padding(ctx, 0); *args.bytes_written = 0; if (!EVP_DecryptUpdate(ctx, args.out->data, &intermediate_bytes_written, args.in->data, (int)args.in->len)) { CLIENT_ERR("error in EVP_DecryptUpdate: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } BSON_ASSERT(intermediate_bytes_written >= 0 && (uint64_t)intermediate_bytes_written <= UINT32_MAX); /* intermediate_bytes_written cannot be negative, so int -> uint32_t is OK */ *args.bytes_written = (uint32_t)intermediate_bytes_written; if (!EVP_DecryptFinal_ex(ctx, args.out->data, &intermediate_bytes_written)) { CLIENT_ERR("error in EVP_DecryptFinal_ex: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } BSON_ASSERT(UINT32_MAX - *args.bytes_written >= (uint32_t)intermediate_bytes_written); *args.bytes_written += (uint32_t)intermediate_bytes_written; ret = true; done: EVP_CIPHER_CTX_free(ctx); return ret; } bool _native_crypto_aes_256_cbc_encrypt(aes_256_args_t args) { return _encrypt_with_cipher(EVP_aes_256_cbc(), args); } bool _native_crypto_aes_256_cbc_decrypt(aes_256_args_t args) { return _decrypt_with_cipher(EVP_aes_256_cbc(), args); } bool _native_crypto_aes_256_ecb_encrypt(aes_256_args_t args) { return _encrypt_with_cipher(EVP_aes_256_ecb(), args); } /* _hmac_with_hash computes an HMAC of @in with the OpenSSL hash specified by * @hash. * @key is the input key. * @out is the output. @out must be allocated by the caller with * the exact length for the output. E.g. for HMAC 256, @out->len must be 32. * Returns false and sets @status on error. @status is required. */ static bool _hmac_with_hash(const EVP_MD *hash, const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(hash); BSON_ASSERT_PARAM(key); BSON_ASSERT_PARAM(in); BSON_ASSERT_PARAM(out); BSON_ASSERT(key->len <= INT_MAX); #if OPENSSL_VERSION_NUMBER >= 0x10100000L if (!HMAC(hash, key->data, (int)key->len, in->data, in->len, out->data, NULL /* unused out len */)) { CLIENT_ERR("error initializing HMAC: %s", ERR_error_string(ERR_get_error(), NULL)); return false; } return true; #else HMAC_CTX *ctx; bool ret = false; ctx = HMAC_CTX_new(); if (out->len != (uint32_t)EVP_MD_size(hash)) { CLIENT_ERR("out does not contain %d bytes", EVP_MD_size(hash)); goto done; } if (!HMAC_Init_ex(ctx, key->data, (int)key->len, hash, NULL /* engine */)) { CLIENT_ERR("error initializing HMAC: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } if (!HMAC_Update(ctx, in->data, in->len)) { CLIENT_ERR("error updating HMAC: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } if (!HMAC_Final(ctx, out->data, NULL /* unused out len */)) { CLIENT_ERR("error finalizing: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } ret = true; done: HMAC_CTX_free(ctx); return ret; #endif } bool _native_crypto_hmac_sha_512(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { return _hmac_with_hash(EVP_sha512(), key, in, out, status); } bool _native_crypto_random(_mongocrypt_buffer_t *out, uint32_t count, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(out); BSON_ASSERT(count <= INT_MAX); int ret = RAND_bytes(out->data, (int)count); /* From man page: "RAND_bytes() and RAND_priv_bytes() return 1 on success, -1 * if not supported by the current RAND method, or 0 on other failure. The * error code can be obtained by ERR_get_error(3)" */ if (ret == -1) { CLIENT_ERR("secure random IV not supported: %s", ERR_error_string(ERR_get_error(), NULL)); return false; } else if (ret == 0) { CLIENT_ERR("failed to generate random IV: %s", ERR_error_string(ERR_get_error(), NULL)); return false; } return true; } bool _native_crypto_aes_256_ctr_encrypt(aes_256_args_t args) { return _encrypt_with_cipher(EVP_aes_256_ctr(), args); } bool _native_crypto_aes_256_ctr_decrypt(aes_256_args_t args) { return _decrypt_with_cipher(EVP_aes_256_ctr(), args); } bool _native_crypto_hmac_sha_256(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { return _hmac_with_hash(EVP_sha256(), key, in, out, status); } #endif /* MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO */ mongodb-1.21.0/src/libmongocrypt/src/crypto/none.c0000644000175100001660000000471314760300420017033 0ustar /* * Copyright 2019-present MongoDB, 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. */ /* everything is a no-op */ #include "../mongocrypt-crypto-private.h" #include "../mongocrypt-private.h" #ifndef MONGOCRYPT_ENABLE_CRYPTO bool _native_crypto_initialized = false; void _native_crypto_init(void) { _native_crypto_initialized = true; } bool _native_crypto_aes_256_cbc_encrypt(aes_256_args_t args) { mongocrypt_status_t *status = args.status; CLIENT_ERR("hook not set for aes_256_cbc_encrypt"); return false; } bool _native_crypto_aes_256_cbc_decrypt(aes_256_args_t args) { mongocrypt_status_t *status = args.status; CLIENT_ERR("hook not set for aes_256_cbc_decrypt"); return false; } bool _native_crypto_hmac_sha_512(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { CLIENT_ERR("hook not set for hmac_sha_512"); return false; } bool _native_crypto_random(_mongocrypt_buffer_t *out, uint32_t count, mongocrypt_status_t *status) { CLIENT_ERR("hook not set for random"); return false; } bool _native_crypto_aes_256_ctr_encrypt(aes_256_args_t args) { mongocrypt_status_t *status = args.status; CLIENT_ERR("hook not set for _native_crypto_aes_256_ctr_encrypt"); return false; } bool _native_crypto_aes_256_ctr_decrypt(aes_256_args_t args) { mongocrypt_status_t *status = args.status; CLIENT_ERR("hook not set for _native_crypto_aes_256_ctr_decrypt"); return false; } bool _native_crypto_hmac_sha_256(const _mongocrypt_buffer_t *key, const _mongocrypt_buffer_t *in, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { CLIENT_ERR("hook not set for _native_crypto_hmac_sha_256"); return false; } #endif /* MONGOCRYPT_ENABLE_CRYPTO */mongodb-1.21.0/src/libmongocrypt/src/mlib/endian.h0000644000175100001660000000247214760300420016742 0ustar #ifndef MLIB_ENDIAN_H_INCLUDED #define MLIB_ENDIAN_H_INCLUDED #ifdef __has_include // Some platforms require including other headers that will define the necessary // macros #if __has_include() // This may recursively include our own file in a pathological case, but that // won't cause an issue. The default will include the system's version instead: #include #endif #if __has_include() #include #endif #endif #include "./macros.h" enum mlib_endian_kind { #ifdef _MSC_VER // MSVC only targets little-endian arches at the moment MLIB_ENDIAN_LITTLE = 1234, MLIB_ENDIAN_BIG = 4321, MLIB_ENDIAN_NATIVE = MLIB_ENDIAN_LITTLE, #elif defined(__BYTE_ORDER__) // Commonly built-in defined in newer compilers MLIB_ENDIAN_LITTLE = __ORDER_LITTLE_ENDIAN__, MLIB_ENDIAN_BIG = __ORDER_BIG_ENDIAN__, MLIB_ENDIAN_NATIVE = __BYTE_ORDER__, #elif defined(__BYTE_ORDER) // Common in or MLIB_ENDIAN_LITTLE = __LITTLE_ENDIAN, MLIB_ENDIAN_BIG = __BIG_ENDIAN, MLIB_ENDIAN_NATIVE = __BYTE_ORDER, #else #error This compiler does not define an endianness macro. #endif }; enum { MLIB_IS_LITTLE_ENDIAN = MLIB_ENDIAN_NATIVE == MLIB_ENDIAN_LITTLE, MLIB_IS_BIG_ENDIAN = MLIB_ENDIAN_NATIVE == MLIB_ENDIAN_BIG, }; #endif // MLIB_ENDIAN_H_INCLUDED mongodb-1.21.0/src/libmongocrypt/src/mlib/error.h0000644000175100001660000000307014760300420016630 0ustar #ifndef MLIB_ERROR_PRIVATE_H #define MLIB_ERROR_PRIVATE_H #include "./user-check.h" #include "./str.h" #ifdef _WIN32 #include "./windows-lean.h" #else #include #endif /** * @brief Obtain a string containing an error message corresponding to an error * code from the host platform. * * @param errn An error code for the system. (e.g. GetLastError() on Windows) * @return mstr A new string containing the resulting error. Must be freed with * @ref mstr_free(). */ static inline mstr merror_system_error_string(int errn) { #ifdef _WIN32 wchar_t *wbuffer = NULL; DWORD slen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD)errn, 0, (LPWSTR)&wbuffer, 0, NULL); if (slen == 0) { return mstr_copy_cstr("[Error while getting error string from FormatMessageW()]"); } mstr_narrow_result narrow = mstr_win32_narrow(wbuffer); LocalFree(wbuffer); assert(narrow.error == 0); // Messages from FormatMessage contain an additional CR+LF if (mstr_ends_with(narrow.string.view, mstrv_lit("\r\n"))) { mstr_inplace_remove_suffix(&narrow.string, 2); } return narrow.string; #else errno = 0; char *const str = strerror(errn); if (errno) { return mstr_copy_cstr("[Error while getting error string from strerror()]"); } return mstr_copy_cstr(str); #endif } #endif // MLIB_ERROR_PRIVATE_Hmongodb-1.21.0/src/libmongocrypt/src/mlib/int128.h0000644000175100001660000005004114760300420016524 0ustar #ifndef MLIB_INT128_H_INCLUDED #define MLIB_INT128_H_INCLUDED #include "./macros.h" #include "./str.h" #include #include #include #include MLIB_C_LINKAGE_BEGIN /** * @brief A 128-bit binary integer */ typedef union { struct { uint64_t lo; uint64_t hi; } r; #if defined(__SIZEOF_INT128__) // These union members are only for the purpose of debugging visualization // and testing, and will only appear correctly on little-endian platforms. __int128_t signed_; __uint128_t unsigned_; #endif } mlib_int128; /// Define an int128 from a literal within [INT64_MIN, INT64_MAX] #define MLIB_INT128(N) MLIB_INIT(mlib_int128) MLIB_INT128_C(N) /// Define an int128 from a literal within [INT64_MIN, INT64_MAX] (usable as a /// constant init) #define MLIB_INT128_C(N) MLIB_INT128_FROM_PARTS((uint64_t)INT64_C(N), (INT64_C(N) < 0 ? UINT64_MAX : 0)) /** * @brief Cast an integral value to an mlib_int128 * * If the argument is signed and less-than zero, it will be sign-extended */ #define MLIB_INT128_CAST(N) \ MLIB_INIT(mlib_int128) \ MLIB_INT128_FROM_PARTS((uint64_t)(N), ((N) < 0 ? UINT64_MAX : 0)) /** * @brief Create an mlib_int128 from the low and high parts of the integer * * @param LowWord_u64 The low-value 64 bits of the number * @param HighWord_u64 The high-value 64 bits of the number */ #define MLIB_INT128_FROM_PARTS(LowWord_u64, HighWord_u64) \ { {LowWord_u64, HighWord_u64}, } /// Maximum value of int128 when treated as a signed integer #define MLIB_INT128_SMAX MLIB_INT128_FROM_PARTS(UINT64_MAX, UINT64_MAX & ~(UINT64_C(1) << 63)) /// Minimum value of int128, when treated as a signed integer #define MLIB_INT128_SMIN MLIB_INT128_FROM_PARTS(0, UINT64_C(1) << 63) /// Maximum value of int128, when treated as an unsigned integer #define MLIB_INT128_UMAX MLIB_INT128_FROM_PARTS(UINT64_MAX, UINT64_MAX) /** * @brief Compare two 128-bit integers as unsigned integers * * @return (R < 0) if (left < right) * @return (R > 0) if (left > right) * @return (R = 0) if (left == right) */ static mlib_constexpr_fn int mlib_int128_ucmp(mlib_int128 left, mlib_int128 right) { if (left.r.hi > right.r.hi) { return 1; } else if (left.r.hi < right.r.hi) { return -1; } else if (left.r.lo > right.r.lo) { return 1; } else if (left.r.lo < right.r.lo) { return -1; } else { return 0; } } /** * @brief Compare two 128-bit integers as signed integers * * @return (R < 0) if (left < right) * @return (R > 0) if (left > right) * @return (R = 0) if (left == right) */ static mlib_constexpr_fn int mlib_int128_scmp(mlib_int128 left, mlib_int128 right) { if ((left.r.hi & (1ull << 63)) == (right.r.hi & (1ull << 63))) { // Same signed-ness, so they are as comparable as unsigned return mlib_int128_ucmp(left, right); } else if (left.r.hi & (1ull << 63)) { // The left is negative return -1; } else { // The right is negative return 1; } } /** * @brief Determine whether the two 128-bit integers are equal * * @retval true If left == right * @retval false Otherwise */ static mlib_constexpr_fn bool mlib_int128_eq(mlib_int128 left, mlib_int128 right) { return mlib_int128_ucmp(left, right) == 0; } /** * @brief Add two 128-bit integers together * * @return mlib_int128 The sum of the two addends. Overflow will wrap. */ static mlib_constexpr_fn mlib_int128 mlib_int128_add(mlib_int128 left, mlib_int128 right) { uint64_t losum = left.r.lo + right.r.lo; // Overflow check unsigned carry = (losum < left.r.lo || losum < right.r.lo); uint64_t hisum = left.r.hi + right.r.hi + carry; return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(losum, hisum); } /** * @brief Treat the given 128-bit integer as signed, and return its * negated value */ static mlib_constexpr_fn mlib_int128 mlib_int128_negate(mlib_int128 v) { mlib_int128 r = MLIB_INT128_FROM_PARTS(~v.r.lo, ~v.r.hi); r = mlib_int128_add(r, MLIB_INT128(1)); return r; } /** * @brief Subtract two 128-bit integers * * @return mlib_int128 The difference between `from` and `less` */ static mlib_constexpr_fn mlib_int128 mlib_int128_sub(mlib_int128 from, mlib_int128 less) { unsigned borrow = from.r.lo < less.r.lo; uint64_t low = from.r.lo - less.r.lo; uint64_t high = from.r.hi - less.r.hi; high -= borrow; return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(low, high); } /** * @brief Bitwise left-shift a 128-bit integer * * @param val The value to modify * @param off The offset to shift left. If negative, shifts right * @return The result of the shift operation */ static mlib_constexpr_fn mlib_int128 mlib_int128_lshift(mlib_int128 val, int off) { if (off > 0) { if (off >= 64) { off -= 64; uint64_t high = val.r.lo << off; return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(0, high); } else { uint64_t low = val.r.lo << off; uint64_t high = val.r.hi << off; high |= val.r.lo >> (64 - off); return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(low, high); } } else if (off < 0) { off = -off; if (off >= 64) { off -= 64; uint64_t low = val.r.hi >> off; return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(low, 0); } else { uint64_t high = val.r.hi >> off; uint64_t low = val.r.lo >> off; low |= val.r.hi << (64 - off); return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(low, high); } } else { return val; } } /** * @brief Bitwise logical right-shift a 128-bit integer * * @param val The value to modify. No "sign bit" is respected. * @param off The offset to shift right. If negative, shifts left * @return The result of the shift operation */ static mlib_constexpr_fn mlib_int128 mlib_int128_rshift(mlib_int128 val, int off) { return mlib_int128_lshift(val, -off); } /** * @brief Bitwise-or two 128-bit integers */ static mlib_constexpr_fn mlib_int128 mlib_int128_bitor(mlib_int128 l, mlib_int128 r) { return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(l.r.lo | r.r.lo, l.r.hi | r.r.hi); } /** * @brief Bitwise-and two 128-bit integers */ static mlib_constexpr_fn mlib_int128 mlib_int128_bitand(mlib_int128 l, mlib_int128 r) { return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(l.r.lo & r.r.lo, l.r.hi & r.r.hi); } // Multiply two 64bit integers to get a 128-bit result without overflow static mlib_constexpr_fn mlib_int128 _mlibUnsignedMult128(uint64_t left, uint64_t right) { // Perform a Knuth 4.3.1M multiplication uint32_t u[2] = {(uint32_t)left, (uint32_t)(left >> 32)}; uint32_t v[2] = {(uint32_t)right, (uint32_t)(right >> 32)}; uint32_t w[4] = {0}; for (int j = 0; j < 2; ++j) { uint64_t t = 0; for (int i = 0; i < 2; ++i) { t += (uint64_t)(u[i]) * v[j] + w[i + j]; w[i + j] = (uint32_t)t; t >>= 32; } w[j + 2] = (uint32_t)t; } return MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(((uint64_t)w[1] << 32) | w[0], ((uint64_t)w[3] << 32) | w[2]); } /** * @brief Multiply two mlib_int128s together. Overflow will wrap. */ static mlib_constexpr_fn mlib_int128 mlib_int128_mul(mlib_int128 l, mlib_int128 r) { // Multiply the low-order word mlib_int128 ret = _mlibUnsignedMult128(l.r.lo, r.r.lo); // Accumulate the high-order parts: ret.r.hi += l.r.lo * r.r.hi; ret.r.hi += l.r.hi * r.r.lo; return ret; } /// Get the number of leading zeros in a 64bit number. static mlib_constexpr_fn int _mlibCountLeadingZeros_u64(uint64_t bits) { int n = 0; if (bits == 0) { return 64; } while (!(1ull << 63 & bits)) { ++n; bits <<= 1; } return n; } static mlib_constexpr_fn int _mlibCountLeadingZeros_u128(mlib_int128 r) { int clz_l = _mlibCountLeadingZeros_u64(r.r.hi); if (clz_l != 64) { return clz_l; } int clz_r = _mlibCountLeadingZeros_u64(r.r.lo); return clz_l + clz_r; } /// Implementation of Knuth's algorithm 4.3.1 D for unsigned integer division static mlib_constexpr_fn void _mlibKnuth431D(uint32_t *const u, const int ulen, const uint32_t *const v, const int vlen, uint32_t *quotient) { // Part D1 (normalization) is done by caller, // normalized in u and v (radix b is 2^32) typedef uint64_t u64; typedef int64_t i64; typedef uint32_t u32; const int m = ulen - vlen - 1; const int n = vlen; // 'd' is 2^32. Shifting left and right is equivalent to mult and division by // d, respectively. // D2 int j = m; for (;;) { // D3: Select two u32 as a u64: u64 two = ((u64)(u[j + n]) << 32) | u[j + n - 1]; // D3: Partial quotient: q̂ u64 q = two / v[n - 1]; // D3: Partial remainder: r̂ u64 r = two % v[n - 1]; // D3: Compute q̂ and r̂ while (q >> 32 || q * (u64)v[n - 2] > (r << 32 | u[j + n - 2])) { q--; r += v[n - 1]; if (r >> 32) { break; } } // D4: Multiply and subtract i64 k = 0; i64 t = 0; for (int i = 0; i < n; ++i) { u64 prod = (u32)q * (u64)(v[i]); t = u[i + j] - k - (u32)prod; u[i + j] = (u32)t; k = (i64)(prod >> 32) - (t >> 32); } t = u[j + n] - k; u[j + n] = (u32)t; quotient[j] = (u32)q; // D5: Test remainder if (t < 0) { // D6: Add back --quotient[j]; k = 0; for (int i = 0; i < n; ++i) { t = u[i + j] + k + v[i]; u[i + j] = (u32)(t); k = t >> 32; } u[j + n] += (u32)k; } // D7: --j; if (j < 0) { break; } } // Denormalization (D8) is done by caller. } /// The result of 128-bit division typedef struct mlib_int128_divmod_result { /// The quotient of the division operation (rounds to zero) mlib_int128 quotient; /// The remainder of the division operation mlib_int128 remainder; } mlib_int128_divmod_result; /// Divide a 128-bit number by a 64bit number. static mlib_constexpr_fn struct mlib_int128_divmod_result _mlibDivide_u128_by_u64(const mlib_int128 numer, const uint64_t denom) { mlib_int128 adjusted = numer; adjusted.r.hi %= denom; int d = _mlibCountLeadingZeros_u64(denom); typedef uint32_t u32; typedef uint64_t u64; if (d >= 32) { // jk: We're dividing by less than UINT32_MAX: We can do a simple short // division of two base32 numbers. // Treat the denominator as a single base32 digit: const u32 d0 = (u32)denom; // And the numerator as four base32 digits: const u64 n0 = (u32)(numer.r.lo); const u64 n1 = (u32)(numer.r.lo >> 32); // We don't need to split n2 and n3. (n3,n2) will be the first partial // dividend const u64 n3_n2 = numer.r.hi; // First partial remainder: (n3,n2) % d0 const u64 r1 = n3_n2 % d0; // Second partial dividend: (r1,n1) const u64 r1_n1 = (r1 << 32) + n1; // Second partial remainder: (r1,n1) % d0 const u64 r0 = r1_n1 % d0; // Final partial dividend: (r0,n0) const u64 r0_n0 = (r0 << 32) + n0; // Final remainder: (r0,n0) % d0 const u64 rem = r0_n0 % d0; // Form the quotient as four base32 digits: // Least quotient digit: (r0,n0) / d0 const u64 q0 = r0_n0 / d0; // Second quotient digit: (r1,n1) / d0 const u64 q1 = r1_n1 / d0; // Third and fourth quotient digit: (n3,n2) / d0 const u64 q3_q2 = n3_n2 / d0; // Low word of the quotient: (q1,q0) const u64 q1_q0 = (q1 << 32) + q0; return MLIB_INIT(mlib_int128_divmod_result){ MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(q1_q0, q3_q2), MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(rem, 0), }; } // Normalize for a Knuth 4.3.1D division. Convert the integers into two // base-32 numbers, with u and v being arrays of digits: u32 u[5] = { (u32)(adjusted.r.lo << d), (u32)(adjusted.r.lo >> (32 - d)), (u32)(adjusted.r.hi << d), (u32)(adjusted.r.hi >> (32 - d)), 0, }; if (d != 0) { // Extra bits from overlap: u[2] |= (u32)(adjusted.r.lo >> (64 - d)); u[4] |= (u32)(adjusted.r.hi >> (64 - d)); } u32 v[2] = { (u32)(denom << d), (u32)(denom >> (32 - d)), }; u32 qparts[3] = {0}; _mlibKnuth431D(u, 5, v, 2, qparts); u64 rem = ((u64)u[1] << (32 - d)) | (u[0] >> d); u64 quo = ((u64)qparts[1] << 32) | qparts[0]; return MLIB_INIT(mlib_int128_divmod_result){ MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(quo, numer.r.hi / denom), MLIB_INIT(mlib_int128) MLIB_INT128_FROM_PARTS(rem, 0), }; } /** * @brief Perform a combined division+remainder of two 128-bit numbers * * @param numer The dividend * @param denom The divisor * @return A struct with .quotient and .remainder results */ static mlib_constexpr_fn mlib_int128_divmod_result mlib_int128_divmod(mlib_int128 numer, mlib_int128 denom) { const uint64_t nhi = numer.r.hi; const uint64_t nlo = numer.r.lo; const uint64_t dhi = denom.r.hi; const uint64_t dlo = denom.r.lo; if (dhi > nhi) { // Denominator is definitely larger than numerator. Quotient is zero, // remainder is full numerator. return MLIB_INIT(mlib_int128_divmod_result){MLIB_INT128(0), numer}; } else if (dhi == nhi) { // High words are equal if (nhi == 0) { // Both high words are zero, so this is just a division of two 64bit // numbers return MLIB_INIT(mlib_int128_divmod_result){ MLIB_INT128_CAST(nlo / dlo), MLIB_INT128_CAST(nlo % dlo), }; } else if (nlo > dlo) { // The numerator is larger than the denom and the high word on the // denom is non-zero, so this cannot divide to anything greater than 1. return MLIB_INIT(mlib_int128_divmod_result){ MLIB_INT128(1), mlib_int128_sub(numer, denom), }; } else if (nlo < dlo) { // numer.r.lo < denom.r.lo and denom.r.hi > denom.r.lo, so the // integer division becomes zero return MLIB_INIT(mlib_int128_divmod_result){ MLIB_INT128(0), numer, }; } else { // N / N is one return MLIB_INIT(mlib_int128_divmod_result){MLIB_INT128(1), MLIB_INT128(0)}; } } else if (dhi == 0) { // No high in denominator. We can use a u128/u64 return _mlibDivide_u128_by_u64(numer, denom.r.lo); } else { // We'll need to do a full u128/u128 division // Normalize for Knuth 4.3.1D int d = _mlibCountLeadingZeros_u64(denom.r.hi); // Does the denom have only three base32 digits? const bool has_three = d >= 32; d &= 31; uint32_t u[5] = { (uint32_t)(numer.r.lo << d), (uint32_t)(numer.r.lo >> (32 - d)), (uint32_t)(numer.r.hi << d), (uint32_t)(numer.r.hi >> (32 - d)), 0, }; uint32_t v[4] = { (uint32_t)(denom.r.lo << d), (uint32_t)(denom.r.lo >> (32 - d)), (uint32_t)(denom.r.hi << d), (uint32_t)(denom.r.hi >> (32 - d)), }; if (d != 0) { u[2] |= (uint32_t)(numer.r.lo >> (64 - d)); u[4] |= (uint32_t)(numer.r.hi >> (64 - d)); v[2] |= (uint32_t)(denom.r.lo >> (64 - d)); }; uint32_t q[2] = {0}; if (has_three) { _mlibKnuth431D(u, 5, v, 3, q); } else { _mlibKnuth431D(u, 5, v, 4, q); } mlib_int128 remainder = MLIB_INT128_FROM_PARTS(((uint64_t)u[1] << 32) | u[0], ((uint64_t)u[3] << 32) | u[2]); remainder = mlib_int128_rshift(remainder, d); return MLIB_INIT(mlib_int128_divmod_result){ MLIB_INT128_CAST(q[0] | (uint64_t)q[1] << 32), remainder, }; } } /** * @brief Perform a division of two 128-bit numbers */ static mlib_constexpr_fn mlib_int128 mlib_int128_div(mlib_int128 numer, mlib_int128 denom) { return mlib_int128_divmod(numer, denom).quotient; } /** * @brief Perform a modulus of two 128-bit numbers */ static mlib_constexpr_fn mlib_int128 mlib_int128_mod(mlib_int128 numer, mlib_int128 denom) { return mlib_int128_divmod(numer, denom).remainder; } /** * @brief Get the nth power of ten as a 128-bit number */ static mlib_constexpr_fn mlib_int128 mlib_int128_pow10(uint8_t nth) { mlib_int128 r = MLIB_INT128(1); while (nth-- > 0) { r = mlib_int128_mul(r, MLIB_INT128(10)); } return r; } /** * @brief Get the Nth power of two as a 128-bit number */ static mlib_constexpr_fn mlib_int128 mlib_int128_pow2(uint8_t nth) { return mlib_int128_lshift(MLIB_INT128(1), (int)nth); } /** * @brief Read a 128-bit unsigned integer from a base-10 string */ static mlib_constexpr_fn mlib_int128 mlib_int128_from_string(const char *s, const char **end) { int radix = 10; if (mlib_strlen(s) > 2 && s[0] == '0') { // Check for a different radix char b = s[1]; if (b == 'b' || b == 'B') { radix = 2; s += 2; } else if (b == 'c' || b == 'C') { radix = 8; s += 2; } else if (b == 'x' || b == 'X') { radix = 16; s += 2; } else { radix = 8; s += 1; } } mlib_int128 ret = MLIB_INT128(0); for (; *s; ++s) { char c = *s; if (c == '\'') { // Digit separator. Skip it; continue; } if (c >= 'a') { // Uppercase (if a letter, otherwise some other punct): c = (char)(c - ('a' - 'A')); } int digit = c - '0'; if (c >= 'A') { // It's actually a letter (or garbage, which we'll catch later) digit = (c - 'A') + 10; } if (digit > radix || digit < 0) { // The digit is outside of our radix, or garbage break; } ret = mlib_int128_mul(ret, MLIB_INT128_CAST(radix)); ret = mlib_int128_add(ret, MLIB_INT128_CAST(digit)); } if (end) { *end = s; } return ret; } /** * @brief Truncate a 128-bit number to a 64-bit number */ static mlib_constexpr_fn uint64_t mlib_int128_to_u64(mlib_int128 v) { return v.r.lo; } /// The result type of formatting a 128-bit number typedef struct { /// The character array of the number as a base10 string. Null-terminated. char str[40]; } mlib_int128_charbuf; /** * @brief Format a 128-bit integer into a string of base10 digits. * * @return mlib_int128_charbuf a struct containing a .str character array */ static mlib_constexpr_fn mlib_int128_charbuf mlib_int128_format(mlib_int128 i) { mlib_int128_charbuf into = {{0}}; char *out = into.str + (sizeof into) - 1; int len = 0; if (mlib_int128_eq(i, MLIB_INT128(0))) { *out-- = '0'; len = 1; } while (!mlib_int128_eq(i, MLIB_INT128(0))) { mlib_int128_divmod_result dm = mlib_int128_divmod(i, MLIB_INT128(10)); uint64_t v = mlib_int128_to_u64(dm.remainder); char digits[] = "0123456789"; char d = digits[v]; *out = d; --out; i = dm.quotient; ++len; } for (int j = 0; j < len; ++j) { into.str[j] = out[j + 1]; } into.str[len] = 0; return into; } MLIB_C_LINKAGE_END #endif // MLIB_INT128_H_INCLUDED mongodb-1.21.0/src/libmongocrypt/src/mlib/macros.h0000644000175100001660000000265714760300420016775 0ustar #ifndef MLIB_MACROS_H_INCLUDED #define MLIB_MACROS_H_INCLUDED #include "./user-check.h" /** * @brief Cross-C/C++ compatibility for a compound initializer to be treated as * a braced initializer * */ #ifdef __cplusplus #define MLIB_INIT(T) T #else #define MLIB_INIT(T) (T) #endif #ifdef __cplusplus #define _mlibCLinkageBegin extern "C" { #define _mlibCLinkageEnd } #else #define _mlibCLinkageBegin #define _mlibCLinkageEnd #endif /// Mark the beginning of a C-language-linkage section #define MLIB_C_LINKAGE_BEGIN _mlibCLinkageBegin /// End a C-language-linkage section #define MLIB_C_LINKAGE_END _mlibCLinkageEnd #if (defined(__cpp_constexpr) && __cpp_constexpr >= 201304L) || (defined(__cplusplus) && __cplusplus >= 201402L) \ || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) #define _mlibConstexprFn constexpr inline #else #define _mlibConstexprFn inline #endif /** * @brief Mark a function as constexpr * * Expands to `constexpr inline` in C++14 and above (and someday C26...?). * "inline" otherwise. */ #define mlib_constexpr_fn _mlibConstexprFn #ifdef __GNUC__ #define MLIB_ANNOTATE_PRINTF(FStringArgAt, VarArgsStartAt) \ __attribute__((format(__printf__, FStringArgAt, VarArgsStartAt))) #else #define MLIB_ANNOTATE_PRINTF(FStringArgAt, VarArgsStartAt) /* no-op */ #endif #endif // MLIB_MACROS_H_INCLUDED mongodb-1.21.0/src/libmongocrypt/src/mlib/path.h0000644000175100001660000002437214760300420016443 0ustar #ifndef MONGOCRYPT_PATH_PRIVATE_H #define MONGOCRYPT_PATH_PRIVATE_H #include "./user-check.h" #include "./str.h" #include #ifndef _WIN32 #include #else #include "./windows-lean.h" #endif typedef enum mpath_format { /// The POSIX path format MPATH_POSIX = 'p', /// The Win32 path format MPATH_WIN32 = 'w', /// The native path format for the current platform MPATH_NATIVE = #ifdef _WIN32 MPATH_WIN32, #else MPATH_POSIX, #endif } mpath_format; /** * @brief Determine if the given character is a path separator for the given * path format * * @param c A path character * @param f The path format to use */ static inline bool mpath_is_sep(char c, mpath_format f) { if (f == MPATH_WIN32) { return c == '/' || c == '\\'; } else { return c == '/'; } } /** * @brief Obtain the preferred path separator character for the given format */ static inline char mpath_preferred_sep(mpath_format f) { if (f == MPATH_WIN32) { return '\\'; } else { return '/'; } } /** * @brief Obtain the path string denoting the application's current working * directory * * @return mstr A new string which must be freed with mstr_free() */ static inline mstr mpath_current_path(void) { #if _WIN32 while (1) { DWORD len = GetCurrentDirectoryW(0, NULL); wchar_t *wstr = calloc(sizeof(wchar_t), len); DWORD got_len = GetCurrentDirectoryW(len, wstr); if (got_len > len) { free(wstr); continue; } mstr_narrow_result nar = mstr_win32_narrow(wstr); free(wstr); assert(nar.error == 0); return nar.string; } #else mstr_mut mut = mstr_new(8096); char *p = getcwd(mut.data, mut.len); if (p == NULL) { mstr_free(mut.mstr); return MSTR_NULL; } mstr ret = mstr_copy_cstr(mut.data); mstr_free(mut.mstr); return ret; #endif } /** * @brief Determine whether the given path string has a trailing path separator */ static inline bool mpath_has_trailing_sep(mstr_view path, mpath_format f) { return path.len && mpath_is_sep(path.data[path.len - 1], f); } /** * @brief Obtain the parent path of the given path. */ static inline mstr_view mpath_parent(mstr_view path, mpath_format f) { if (mpath_has_trailing_sep(path, f)) { // Remove trailing separators: while (mpath_has_trailing_sep(path, f)) { path = mstrv_remove_suffix(path, 1); } return path; } // Remove everything that isn't a path separator: while (path.len != 0 && !mpath_has_trailing_sep(path, f)) { path = mstrv_remove_suffix(path, 1); } // Remove trailing separators again while (path.len > 1 && mpath_has_trailing_sep(path, f)) { path = mstrv_remove_suffix(path, 1); } // The result is the parent path. return path; } /** * @brief Obtain the filename denoted by the given path. * * The returned path will include no directory separators. If the given path * ends with a directory separator, the single-dot '.' path is returned instead. */ static inline mstr_view mpath_filename(mstr_view path, mpath_format f) { if (!path.len) { return path; } const char *it = path.data + path.len; while (it != path.data && !mpath_is_sep(it[-1], f)) { --it; } size_t off = (size_t)(it - path.data); mstr_view fname = mstrv_subview(path, off, path.len); if (fname.len == 0) { return mstrv_lit("."); } return fname; } /** * @brief Join the two given paths into a single path * * The two strings will be combined into a single string with a path separator * between them. If either string is empty, the other string will be copied * without modification. * * @param base The left-hand of the join * @param suffix The right-hand of the join * @param f The path format to use * @return mstr A new string resulting from the join */ static inline mstr mpath_join(mstr_view base, mstr_view suffix, mpath_format f) { if (!base.len) { return mstr_copy(suffix); } if (mpath_has_trailing_sep(base, f)) { return mstr_append(base, suffix); } if (!suffix.len) { return mstr_copy(base); } if (mpath_is_sep(suffix.data[0], f)) { return mstr_append(base, suffix); } // We must insert a path separator between the two strings assert(base.len <= SIZE_MAX - suffix.len - 1u); mstr_mut r = mstr_new(base.len + suffix.len + 1); char *p = r.data; memcpy(p, base.data, base.len); p += base.len; *p++ = mpath_preferred_sep(f); memcpy(p, suffix.data, suffix.len); return r.mstr; } /** * @brief Obtain the root name for the given path. * * For the Windows format, this will return the drive letter, if present. * Otherwise, this will return an empty string. */ static inline mstr_view mpath_root_name(mstr_view path, mpath_format f) { if (f == MPATH_WIN32 && path.len > 1) { char c = path.data[0]; if (path.len > 2 && path.data[1] == ':' && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) { return mstrv_subview(path, 0, 2); } } return mstrv_subview(path, 0, 0); } /** * @brief Return the root directory of the given path, if present. * * @note This will not include the drive letter of a Win32 path. */ static inline mstr_view mpath_root_directory(mstr_view path, mpath_format f) { mstr_view rname = mpath_root_name(path, f); path = mstrv_subview(path, rname.len, path.len); if (path.len && mpath_is_sep(path.data[0], f)) { return mstrv_subview(path, 0, 1); } else { return mstrv_subview(path, 0, 0); } } /** * @brief Obtain the root filepath of the given path. * * This will include both the root name and the root filepath, if present. */ static inline mstr_view mpath_root_path(mstr_view path, mpath_format f) { mstr_view rname = mpath_root_name(path, f); mstr_view rdir = mpath_root_directory(path, f); assert(rname.len <= SIZE_MAX - rdir.len); return mstrv_subview(path, 0, rname.len + rdir.len); } /** * @brief Determine whether the given filepath designates a single unambiguous * filesystem location. * * @note A Win32 filepath without a drive letter is not absolute! */ static inline bool mpath_is_absolute(mstr_view path, mpath_format f) { if (f == MPATH_WIN32) { // Win32 requires both a root name and a root directory for an absolute // path return mpath_root_name(path, f).len && mpath_root_directory(path, f).len; } else { // POSIX doesn't have "root names" return mpath_root_directory(path, f).len; } } /** * @brief Obtain a relative path from the given filepath * * If the path has a root path, returns the content of the path following that * root path, otherwise returns the same path itself. */ static inline mstr_view mpath_relative_path(mstr_view path, mpath_format f) { mstr_view root = mpath_root_path(path, f); return mstrv_subview(path, root.len, path.len); } /** * @brief Convert the filepath from one format to a preferred form in another * format. * * @note The return value must be freed with mstr_free() */ static inline mstr mpath_to_format(mpath_format from, mstr_view path, mpath_format to) { mstr_mut ret = mstr_new(path.len); const char *p = path.data; char *out = ret.data; const char *stop = path.data + path.len; for (; p != stop; ++p, ++out) { if (mpath_is_sep(*p, from)) { *out = mpath_preferred_sep(to); } else { *out = *p; } } return ret.mstr; } /** * @brief Determine whether the given path is relative (not absolute) */ static inline bool mpath_is_relative(mstr_view path, mpath_format f) { return !mpath_is_absolute(path, f); } /** * @brief Convert the given path to an absolute path, if it is not already. * * @note The return value must be freed with mstr_free() */ static inline mstr mpath_absolute(mstr_view path, mpath_format f); /** * @brief Resolve a path to an absolute path from the given base path. * * @note This is not the same as mpath_join(): If the given path is already * absolute, returns that path unchanged. Otherwise, resolves that path as being * relative to `base`. * * @note If `base` is also a relative path, it will also be given to * mpath_absolute() to resolve it. */ static inline mstr mpath_absolute_from(mstr_view path, mstr_view base, mpath_format f) { mstr_view rname = mpath_root_name(path, f); mstr_view rdir = mpath_root_directory(path, f); if (rname.len) { if (rdir.len) { // The path is already fully absolute return mstr_copy(path); } else { mstr abs_base = mpath_absolute(base, f); mstr_view base_rdir = mpath_root_directory(abs_base.view, f); mstr_view base_relpath = mpath_relative_path(abs_base.view, f); mstr_view relpath = mpath_relative_path(path, f); mstr ret = mstr_copy(rname); mstr_assign(&ret, mpath_join(ret.view, base_rdir, f)); mstr_assign(&ret, mpath_join(ret.view, base_relpath, f)); mstr_assign(&ret, mpath_join(ret.view, relpath, f)); mstr_free(abs_base); return ret; } } else { // No root name if (rdir.len) { if (f == MPATH_POSIX) { // No root name, but a root directory on a POSIX path indicates an // absolute path return mstr_copy(path); } mstr abs_base = mpath_absolute(base, f); mstr_view base_rname = mpath_root_name(abs_base.view, f); mstr ret = mpath_join(base_rname, path, f); mstr_free(abs_base); return ret; } else { mstr abs_base = mpath_absolute(base, f); mstr r = mpath_join(abs_base.view, path, f); mstr_free(abs_base); return r; } } } static inline mstr mpath_absolute(mstr_view path, mpath_format f) { if (mpath_is_absolute(path, f)) { return mstr_copy(path); } mstr cur = mpath_current_path(); mstr ret = mpath_absolute_from(path, cur.view, MPATH_NATIVE); mstr_assign(&ret, mpath_to_format(MPATH_NATIVE, ret.view, f)); mstr_free(cur); return ret; } #endif // MONGOCRYPT_PATH_PRIVATE_H mongodb-1.21.0/src/libmongocrypt/src/mlib/str.h0000644000175100001660000007145614760300420016324 0ustar #ifndef MONGOCRYPT_STR_PRIVATE_H #define MONGOCRYPT_STR_PRIVATE_H #include "./macros.h" #include "./user-check.h" #include #include #include /* INT_MAX */ #include #include #include #include #include #if defined(MLIB_HAVE_STRINGS_H) #include /* For strncasecmp. */ #endif MLIB_C_LINKAGE_BEGIN /** * @brief A simple non-owning string-view type. * * The viewed string can be treated as an array of char. It's pointed-to data * must not be freed or manipulated. * * @note The viewed string is NOT guaranteed to be null-terminated. It WILL * be null-terminated if: Directly created from a string literal via * @ref mstrv_lit, OR created by accessing the @ref mstr::view member of an * @ref mstr object, OR returned from @ref mstrv_view_cstr. */ typedef struct mstr_view { /** * @brief Pointer to the beginning of the code unit array. * * @note DO NOT MODIFY */ const char *data; /** * @brief Length of the pointed-to code unit array * * @note DO NOT MODIFY */ size_t len; } mstr_view; /** * @brief A simple string utility type. * * This string type has the following semantics: * * The member `data` is a pointer to the beginning of a read-only array of code * units. This array will always be null-terminated, but MAY contain * intermittent null characters. The member `len` is the length of the code unit * array (not including the null terminator). These two members should not be * modified. * * The `view` member is a union member that will view the `mstr` as an * @ref mstr_view. * * If you create an @ref mstr, it MUST eventually be passed to @ref mstr_free() * * The pointed-to code units of an mstr are immutable. To initialize the * contents of an mstr, @ref mstr_new returns an @ref mstr_mut, which can then * be "sealed" by converting it to an @ref mstr through the @ref mstr_mut::mstr * union member. * * By convention, passing/returning an `mstr` to/from a function should * relinquish ownership of that `mstr` to the callee/caller, respectively. * Passing or returning an `mstr_view` is non-owning. */ typedef struct mstr { union { struct { /** * @brief Pointer to the beginning of the code unit array. * * @note DO NOT MODIFY */ const char *data; /** * @brief Length of the pointed-to code unit array * * @note DO NOT MODIFY */ size_t len; }; /** * @brief A non-owning `mstr_view` of the string */ mstr_view view; }; } mstr; /** * @brief An interface for initializing the contents of an mstr. * * Returned by @ref mstr_new(). Once initialization is complete, the result can * be used as an @ref mstr by accessing the @ref mstr_mut::mstr member. */ typedef struct mstr_mut { union { struct { /** * @brief Pointer to the beginning of the mutable code unit array. * * @note DO NOT MODIFY THE POINTER VALUE. Only modify the pointed-to * characters. */ char *data; /** * @brief Length of the pointed-to code unit array. * * @note DO NOT MODIFY */ size_t len; }; /// Convert the mutable string to an immutable string struct mstr mstr; /// Convert the mutable string to an immutable string view mstr_view view; }; } mstr_mut; /** * @brief A null @ref mstr */ #define MSTR_NULL (MLIB_INIT(mstr){{{NULL, 0}}}) /** * @brief A null @ref mstr_view */ #define MSTRV_NULL (MLIB_INIT(mstr_view){NULL, 0}) /** * @brief Create an @ref mstr_view that views the given string literal */ #define mstrv_lit(String) (mstrv_view_data(String "", (sizeof String) - 1)) /** * @brief Create a new mutable code-unit array of the given length, * zero-initialized. The caller can then modify the code units in the array via * the @ref mstr_mut::data member. Once finished modifying, can be converted to * an immutable mstr by copying the @ref mtsr_mut::mstr union member. * * @param len The length of the new string. * @return mstr_mut A new mstr_mut * * @note The @ref mstr_mut::mstr member MUST eventually be given to * @ref mstr_free(). */ static inline mstr_mut mstr_new(size_t len) { #ifndef __clang_analyzer__ assert(len < SIZE_MAX); return MLIB_INIT(mstr_mut){{{(char *)calloc(1, len + 1), len}}}; #else // Clang-analyzer is smart enough to see the calloc(), but not smart enough // to link it to the free() in mstr_free() return MLIB_INIT(mstr_mut){}; #endif } /** * @brief Create a non-owning @ref mstr_view from the given C string and length * * @param s A pointer to the beginning of a character array. * @param len The length of the character array, in code units * @return mstr_view A non-owning string. */ static inline mstr_view mstrv_view_data(const char *s, size_t len) { return MLIB_INIT(mstr_view){s, len}; } /** * @brief Create a non-owning @ref mstr_view from a C-style null-terminated * string. * * @param s A pointer to a null-terminated character array * @return mstr_view A view of the pointed-to string */ static inline mstr_view mstrv_view_cstr(const char *s) { return mstrv_view_data(s, strlen(s)); } /** * @brief Create an @ref mstr from the given character array and length. * * @param s A pointer to a character array * @param len The length of the string to create * @return mstr A new null-terminated string with the contents copied from the * pointed-to array. * * @note The resulting string will be null-terminated. */ static inline mstr mstr_copy_data(const char *s, size_t len) { mstr_mut r = mstr_new(len); memcpy(r.data, s, len); return r.mstr; } /** * @brief Create an @ref mstr from A C-style null-terminated string. * * @param s A pointer to a null-terminated character array * @return mstr A new string copied from the pointed-to string */ static inline mstr mstr_copy_cstr(const char *s) { return mstr_copy_data(s, strlen(s)); } /** * @brief Copy the contents of the given string view * * @param s A string view to copy from * @return mstr A new string copied from the given view */ static inline mstr mstr_copy(mstr_view s) { return mstr_copy_data(s.data, s.len); } /** * @brief Free the resources of the given string * * @param s The string to free */ static inline void mstr_free(mstr s) { free((char *)s.data); } /** * @brief Resize the given mutable string, maintaining the existing content, and * zero-initializing any added characters. * * @param s The @ref mstr_mut to update * @param new_len The new length of the string */ static inline void mstrm_resize(mstr_mut *s, size_t new_len) { if (new_len <= s->len) { s->len = new_len; } else { const size_t old_len = s->len; #ifndef __clang_analyzer__ // Clang-analyzer is smart enough to see the calloc(), but not smart // enough to link it to the free() in mstr_free() assert(new_len < SIZE_MAX); s->data = (char *)realloc((char *)s->data, new_len + 1); #endif s->len = new_len; assert(new_len >= old_len); memset(s->data + old_len, 0, new_len - old_len); } s->data[new_len] = (char)0; } /** * @brief Free and re-assign the given @ref mstr * * @param s Pointer to an @ref mstr. This will be freed, then updated to the * value of @ref from * @param from An @ref mstr to take from. * * @note Ownership of the resource is handed to the pointed-to @ref s. * Equivalent to: * * ```c * mstr s = some_mstr(); * mstr another = get_another_mstr(); * mstr_free(s); * s = another; * ``` * * Intended as a convenience for rebinding an @ref mstr in a single statement * from an expression returning a new @ref mstr, which may itself use @ref s, * without requiring a temporary variable, for example: * * ```c * mstr s = get_mstr(); * mstr_assign(&s, convert_to_uppercase(s.view)); * ``` */ static inline void mstr_assign(mstr *s, mstr from) { mstr_free(*s); *s = from; } /** * @brief Find the index of the first occurrence of the given "needle" as a * substring of another string. * * @param given A string to search within * @param needle The substring to search for * @return int The zero-based index of the first instance of `needle` in * `given`, or -1 if no substring is found. */ static inline int mstr_find(mstr_view given, mstr_view needle) { const char *const scan_end = given.data + given.len; const char *const needle_end = needle.data + needle.len; for (const char *scan = given.data; scan != scan_end; ++scan) { size_t remain = (size_t)(scan_end - scan); if (remain < needle.len) { break; } const char *subscan = scan; for (const char *nscan = needle.data; nscan != needle_end; ++nscan, ++subscan) { if (*nscan == *subscan) { continue; } else { goto skip; } } // Got through the whole loop of scanning the needle return (int)(scan - given.data); skip: (void)0; } return -1; } /** * @brief Find the index of the last occurrence of the given "needle" as a * substring of another string. * * @param given A string to search within * @param needle The substring to search for * @return int The zero-based index of the last instance of `needle` in * `given`, or -1 if no substring is found. */ static inline int mstr_rfind(mstr_view given, mstr_view needle) { if (needle.len > given.len) { return -1; } const char *scan = given.data + given.len - needle.len; const char *const needle_end = needle.data + needle.len; for (; scan >= given.data; --scan) { const char *subscan = scan; for (const char *nscan = needle.data; nscan != needle_end; ++nscan, ++subscan) { if (*nscan == *subscan) { continue; } else { goto skip; } } // Got through the whole loop of scanning the needle return (int)(scan - given.data); skip: (void)0; } return -1; } /** * @brief Modify a string by deleting and/or inserting another string. * * @param s The string to modify * @param at The position at which to insert and delete characters * @param del_count The number of characters to delete. Clamped to the string * length. * @param insert The string to insert at `at`. * @return mstr A new string that is the result of the splice */ static inline mstr mstr_splice(mstr_view s, size_t at, size_t del_count, mstr_view insert) { assert(at <= s.len); const size_t remain = s.len - at; if (del_count > remain) { del_count = remain; } /* at this point, it is absolutely necessary that del_count <= s.len */ assert(s.len - del_count <= SIZE_MAX - insert.len); const size_t new_size = s.len - del_count + insert.len; mstr_mut ret = mstr_new(new_size); char *p = ret.data; memcpy(p, s.data, at); p += at; if (insert.data) { memcpy(p, insert.data, insert.len); p += insert.len; } /* 'at <= s.len' was already asserted earlier */ assert(s.len - at >= del_count); memcpy(p, s.data + at + del_count, s.len - at - del_count); return ret.mstr; } /** * @brief Append the given suffix to the given string */ static inline mstr mstr_append(mstr_view s, mstr_view suffix) { return mstr_splice(s, s.len, 0, suffix); } /** * @brief Prepend the given prefix to the given string */ static inline mstr mstr_prepend(mstr_view s, mstr_view prefix) { return mstr_splice(s, 0, 0, prefix); } /** * @brief Insert the given string into another string * * @param s The string to start with * @param at The position in `s` where `infix` will be inserted * @param infix The string to insert into `s` * @return mstr A new string with `infix` inserted */ static inline mstr mstr_insert(mstr_view s, size_t at, mstr_view infix) { return mstr_splice(s, at, 0, infix); } /** * @brief Erase characters from the given string * * @param s The string to start with * @param at The position at which to begin deleting characters * @param count The number of characters to remove * @return mstr A new string with the deletion result. */ static inline mstr mstr_erase(mstr_view s, size_t at, size_t count) { return mstr_splice(s, at, count, mstrv_view_cstr("")); } /** * @brief Erase `len` characters from the beginning of the string */ static inline mstr mstr_remove_prefix(mstr_view s, size_t len) { return mstr_erase(s, 0, len); } /** * @brief Erase `len` characters from the end of the string */ static inline mstr mstr_remove_suffix(mstr_view s, size_t len) { assert(s.len >= len); return mstr_erase(s, s.len - len, len); } /** * @brief Obtain a substring of the given string * * @param s The string to start with * @param at The beginning position of the new string * @param len The number of characters to include. Automatically clamped to the * remaining length. * @return mstr A new string that is a substring of `s` */ static inline mstr mstr_substr(mstr_view s, size_t at, size_t len) { assert(at <= s.len); const size_t remain = s.len - at; if (len > remain) { len = remain; } mstr_mut r = mstr_new(len); memcpy(r.data, s.data + at, len); return r.mstr; } /** * @brief Obtain a view of a substring of another string. * * @param s The string to view * @param at The position at which the new view will begin * @param len The number of characters to view. Automatically clamped to the * remaining length. * @return mstr_view A view of `s`. */ static inline mstr_view mstrv_subview(mstr_view s, size_t at, size_t len) { assert(at <= s.len); const size_t remain = s.len - at; if (len > remain) { len = remain; } return mstrv_view_data(s.data + at, len); } /** * @brief Obtain a view of another string by removing `len` characters from the * front */ static inline mstr_view mstrv_remove_prefix(mstr_view s, size_t len) { return mstrv_subview(s, len, s.len); } /** * @brief Obtain a view of another string by removing `len` characters from the * end. */ static inline mstr_view mstrv_remove_suffix(mstr_view s, size_t len) { assert(s.len >= len); return mstrv_subview(s, 0, s.len - len); } /** * @brief Truncate the given string to `new_len` characters. * * @param s The string to truncate * @param new_len The new length of the string * @return mstr A new string copied from the beginning of `s` */ static inline mstr mstr_trunc(mstr_view s, size_t new_len) { assert(new_len <= s.len); return mstr_remove_suffix(s, s.len - new_len); } /** * @brief Obtain a new string with all occurrences of a string replaced with a * different string * * @param string The string to start with * @param find The substring that will be replaced * @param subst The string to insert in place of `find` * @return mstr A new string modified from `string` * * @note If `find` is empty, returns a copy of `string` */ static inline mstr mstr_replace(const mstr_view string, const mstr_view find, const mstr_view subst) { if (find.len == 0) { // Finding an empty string would loop forever return mstr_copy(string); } // First copy the string mstr ret = mstr_copy(string); // Keep an index of how far we have processed size_t whence = 0; for (;;) { // Chop off the front that has already been processed mstr_view tail = mstrv_subview(ret.view, whence, SIZE_MAX); // Find where in that tail is the next needle int pos = mstr_find(tail, find); if (pos == -1) { // We're done break; } // Do the replacement assert(whence <= SIZE_MAX - (size_t)pos); mstr_assign(&ret, mstr_splice(ret.view, (size_t)pos + whence, find.len, subst)); // Advance our position by how many chars we skipped and how many we // inserted whence += (size_t)pos + subst.len; } return ret; } /** * @brief Determine whether two strings are equivalent. */ static inline bool mstr_eq(mstr_view left, mstr_view right) { if (left.len != right.len) { return false; } return memcmp(left.data, right.data, left.len) == 0; } /** * @brief Determine whether two strings are equivalent ignoring case. */ static inline bool mstr_eq_ignore_case(mstr_view left, mstr_view right) { #ifdef _WIN32 #define _mstr_strncasecmp _strnicmp #else #define _mstr_strncasecmp strncasecmp #endif if (left.len != right.len) { return false; } return _mstr_strncasecmp(left.data, right.data, left.len) == 0; #undef _mstr_strncasecmp } /// Determine whether the given character is an printable ASCII codepoint static inline bool mstr_is_printable(char c) { return (c >= ' ' && c <= '~'); } /// Write the given string to `out`, rendering non-printable characters as hex /// escapes static inline void _mstr_write_str_repr_(FILE *out, mstr_view s) { for (const char *it = s.data; it != s.data + s.len; ++it) { if (mstr_is_printable(*it)) { fputc(*it, out); } else { fprintf(out, "\\x%.2x", (unsigned)(unsigned char)*it); } } } static inline void _mstr_assert_fail_(mstr_view left, const char *predicate, mstr_view right, const char *file, int line) { fprintf(stderr, "%s:%d: ASSERTION FAILED: \"", file, line); _mstr_write_str_repr_(stderr, left); fprintf(stderr, "\" %s \"", predicate); _mstr_write_str_repr_(stderr, right); fprintf(stderr, "\"\n"); abort(); } static inline void _mstr_assert_(mstr_view left, mstr_view right, bool (*pred)(mstr_view left, mstr_view right), bool B, const char *pred_str, const char *file, int line) { if (pred(left, right) != B) { mstr pstr = mstr_copy_cstr(pred_str); if (!B) { mstr_assign(&pstr, mstr_prepend(pstr.view, mstrv_lit("not "))); } _mstr_assert_fail_(left, pstr.data, right, file, line); } } #define MSTR_ASSERT(Bool, Left, Pred, Right) \ (_mstr_assert_((Left), (Right), mstr_##Pred, (Bool), #Pred, __FILE__, __LINE__)) /** * @brief Assert that two strings are equivalent. * * Prints and error message and aborts if they are not */ #define MSTR_ASSERT_EQ(Left, Right) MSTR_ASSERT(true, Left, eq, Right) /** * @brief Determine whether the given string contains the given substring * * @param given A string to search within * @param needle A substring to search for * @return true If `given` contains at least one occurrence of `needle` * @return false Otherwise */ static inline bool mstr_contains(mstr_view given, mstr_view needle) { return mstr_find(given, needle) >= 0; } /** * @brief Determine whether `given` starts with `prefix` */ static inline bool mstr_starts_with(mstr_view given, mstr_view prefix) { given = mstrv_subview(given, 0, prefix.len); return mstr_eq(given, prefix); } /** * @brief Determine whether `given` ends with `suffix` */ static inline bool mstr_ends_with(mstr_view given, mstr_view suffix) { if (suffix.len > given.len) { return false; } given = mstrv_subview(given, given.len - suffix.len, SIZE_MAX); return mstr_eq(given, suffix); } /// Compound in-place version of @ref mstr_splice static inline void mstr_inplace_splice(mstr *s, size_t at, size_t del_count, mstr_view insert) { mstr_assign(s, mstr_splice(s->view, at, del_count, insert)); } /// Compound in-place version of @ref mstr_append static inline void mstr_inplace_append(mstr *s, mstr_view suffix) { mstr_assign(s, mstr_append(s->view, suffix)); } /// Compound in-place version of @ref mstr_prepend static inline void mstr_inplace_prepend(mstr *s, mstr_view prefix) { mstr_assign(s, mstr_prepend(s->view, prefix)); } /// Compound in-place version of @ref mstr_insert static inline void mstr_inplace_insert(mstr *s, size_t at, mstr_view infix) { mstr_assign(s, mstr_insert(s->view, at, infix)); } /// Compound in-place version of @ref mstr_erase static inline void mstr_inplace_erase(mstr *s, size_t at, size_t count) { mstr_assign(s, mstr_erase(s->view, at, count)); } /// Compound in-place version of @ref mstr_remove_prefix static inline void mstr_inplace_remove_prefix(mstr *s, size_t len) { mstr_assign(s, mstr_remove_prefix(s->view, len)); } /// Compound in-place version of @ref mstr_remove_suffix static inline void mstr_inplace_remove_suffix(mstr *s, size_t len) { mstr_assign(s, mstr_remove_suffix(s->view, len)); } /// Compound in-place version of @ref mstr_substr static inline void mstr_inplace_substr(mstr *s, size_t at, size_t count) { mstr_assign(s, mstr_substr(s->view, at, count)); } /// Compound in-place version of @ref mstr_trunc static inline void mstr_inplace_trunc(mstr *s, size_t new_len) { mstr_assign(s, mstr_trunc(s->view, new_len)); } /// Compound in-place version of @ref mstr_replace static inline void mstr_inplace_replace(mstr *s, mstr_view find, mstr_view subst) { mstr_assign(s, mstr_replace(s->view, find, subst)); } #ifdef _WIN32 #include "./windows-lean.h" /** * @brief The result type of mstr_win32_widen */ typedef struct mstr_widen_result { wchar_t *wstring; int error; } mstr_widen_result; /** * @brief Widen a UTF-8 string using Win32 MultiBytetoWideChar * * @param str The UTF-8 string to widen. * @return mstr_widen_result The result of widening, which may contain an error. * * @note The returned @ref mstr_widen_result::wstring must be given to free() */ static inline mstr_widen_result mstr_win32_widen(mstr_view str) { assert(str.len <= INT_MAX); int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data, (int)str.len, NULL, 0); if (length == 0 && str.len != 0) { return MLIB_INIT(mstr_widen_result){NULL, (int)GetLastError()}; } wchar_t *ret = (wchar_t *)calloc(length + 1, sizeof(wchar_t)); assert(length < INT_MAX); int got_length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data, (int)str.len, ret, length + 1); assert(got_length == length); return MLIB_INIT(mstr_widen_result){ret, 0}; } /** * @brief The result type of mstr_win32_narrow */ typedef struct mstr_narrow_result { mstr string; int error; } mstr_narrow_result; /** * @brief Narrow a UTF-16 string to UTF-8 using Win32 WideCharToMultiByte * * @param wstring A null-terminated UTF-16 string to narrow * @return mstr_narrow_result The result of narrowing, which may contain an * error. * * @note The returned @ref mstr_narrow_result::string must be freed with * mstr_free() */ static inline mstr_narrow_result mstr_win32_narrow(const wchar_t *wstring) { // Some older versions of MinGW fail to include the WC_ERR_INVALID_CHARS // flag, so we will specify it manually: DWORD wcflags = 0x80; // WC_ERR_INVALID_CHARS int length = WideCharToMultiByte(CP_UTF8, wcflags, wstring, -1 /* wstring is null-terminated */, NULL, 0, NULL, NULL); if (length == 0 && wstring[0] != 0) { return MLIB_INIT(mstr_narrow_result){MSTR_NULL, (int)GetLastError()}; } // Allocate a new string, not including the null terminator mstr_mut ret = mstr_new((size_t)(length - 1)); int got_len = WideCharToMultiByte(CP_UTF8, wcflags, wstring, -1, ret.data, // Plus one byte for the NUL (int)(ret.len + 1), NULL, NULL); assert(length == got_len); return MLIB_INIT(mstr_narrow_result){ret.mstr, 0}; } #endif /// Iteration state for string splitting struct _mstr_split_iter_ { /// What hasn't been parsed yet mstr_view remaining; /// The string that we split on mstr_view splitter; /// The current part mstr_view part; /// A once-var for the inner loop. Set to 1 by iter_next, then decremented int once; /// The loop state. Starts at zero. Set to one when we part the final split. /// Set to two to break out of the loop. int state; }; /// Hidden function to advance a string-split iterator static inline void _mstr_split_iter_next_(struct _mstr_split_iter_ *iter) { if (iter->once == 1) { // We only get here if the loop body hit a 'break', skipping the decrement // of the 'once'. Break out of the whole loop, as the user expects. iter->state = 2; return; } if (iter->state == 1) { // We just completed the final loop pass. iter->state = 2; return; } // Find the next occurence of the token const int pos = mstr_find(iter->remaining, iter->splitter); if (pos < 0) { // There are no more occurences. yield the remaining string iter->part = iter->remaining; iter->remaining = mstrv_subview(iter->remaining, iter->remaining.len, 0); // Set state to 1 to break on the next pass iter->state = 1; } else { // Advance our parts: iter->part = mstrv_subview(iter->remaining, 0, (size_t)pos); assert(iter->splitter.len <= SIZE_MAX - (size_t)pos); iter->remaining = mstrv_subview(iter->remaining, (size_t)pos + iter->splitter.len, SIZE_MAX); } // Prime the inner "loop" to execute once iter->once = 1; } /// init a new split iterator static inline struct _mstr_split_iter_ _mstr_split_iter_begin_(mstr_view str, mstr_view split) { struct _mstr_split_iter_ iter = {str, split}; _mstr_split_iter_next_(&iter); return iter; } /// Check whether we are done iterating static inline bool _mstr_split_iter_done_(struct _mstr_split_iter_ *iter) { return iter->state == 2; } // clang-format off #define MSTR_ITER_SPLIT(LineVar, String, SplitToken) \ /* Open the main outer loop */ \ for (/* Declare and init the iterator */ \ struct _mstr_split_iter_ _iter_var_ = \ _mstr_split_iter_begin_ ((String), (SplitToken)); \ /* Iterate until it is marked as done */ \ !_mstr_split_iter_done_ (&_iter_var_); \ _mstr_split_iter_next_ (&_iter_var_)) \ /* This inner loop will only execute once, but gives us */ \ /* a point to declare the loop variable: */ \ for (mstr_view const LineVar = _iter_var_.part; \ _iter_var_.once; \ --_iter_var_.once) // clang-format on /** * @brief Equivalent to strlen(), but has a constexpr annotation. */ static mlib_constexpr_fn size_t mlib_strlen(const char *s) { size_t r = 0; for (; *s; ++r, ++s) {} return r; } /** * @brief Copy characters into the destination, guaranteed null-terminated and * bounds checked. * * @param dst Pointer to the beginning of the destination array. * @param dst_bufsize The size of the destination array, in characters. MUST be * greater than zero. * @param src Pointer to the beginning of a null-terminated character array. * @param src_bufsize The size of the array pointed-to by `src`. * @return size_t The number `R` of characters written (NOT including the null * terminator). R is guaranteed to be less than dst_bufsize, and * less-than-or-equal-to src_bufsize. * * @note Characters beyond (dst + R) are unmodified. dst[R] is guaranteed to * be a null terminator. */ static mlib_constexpr_fn size_t mlib_strnmcopy(char *dst, size_t dst_bufsize, const char *src, size_t src_bufsize) { // No empty destination, since we *must* write a null terminator: assert(dst_bufsize > 0); // The maximum number of characters in the dest is one less than the buffer // size, since we need room for the null terminator: const size_t dstlen = dst_bufsize - 1u; // The actual maximum number of characters we can copy is the less of the // source length and the dest length: const size_t minlen = dstlen < src_bufsize ? dstlen : src_bufsize; // Track what we copy: size_t ncopied = 0; while (ncopied != minlen // Stop if we hit our character limit && *src != 0 // Or if we hit the null terminator in the source ) { // Copy: *dst = *src; // Advance: ++dst; ++src; ++ncopied; } // "dst" now points past the final character we copied (if any), and is still // in-bounds. This will be the null terminator. *dst = 0; return ncopied; } MLIB_C_LINKAGE_END #endif // MONGOCRYPT_STR_PRIVATE_H mongodb-1.21.0/src/libmongocrypt/src/mlib/thread.h0000644000175100001660000000431014760300420016744 0ustar #ifndef MLIB_THREAD_H #define MLIB_THREAD_H #include "./user-check.h" #ifdef _WIN32 #include "./windows-lean.h" #else #include #endif #include /** * @brief A status object for @ref mlib_call_once. */ typedef struct mlib_once_flag { #ifdef _WIN32 INIT_ONCE _native; #else pthread_once_t _native; #endif } mlib_once_flag; /** * @brief A literal initializer suitable for static initializing an * @ref mlib_once_flag object. Can also be used to dynamically initialize or * "reset" a flag. */ #ifdef _WIN32 #define MLIB_ONCE_INITIALIZER \ { ._native = INIT_ONCE_STATIC_INIT } #else #define MLIB_ONCE_INITIALIZER \ { ._native = PTHREAD_ONCE_INIT } #endif /** * @brief The type of an mlib_call_once callback function. */ typedef void (*mlib_init_once_fn_t)(void); #if _WIN32 /** * An indirection layer for mlib_once on Windows platforms. Do not use directly. */ static inline BOOL WINAPI _mlib_win32_once_callthru(PINIT_ONCE once, PVOID param, PVOID *ctx) { (void)once; (void)ctx; mlib_init_once_fn_t *fn = param; (*fn)(); return TRUE; } #endif /** * @brief Perform thread-safe call-once semantics. * * For each thread that calls with the same given flag, no thread shall return * from this function until the flag is in the "finished" state. If a thread * class this function with a "non-finished" flag object, then that thread MIGHT * execute the passed pointed-to function. Once any thread fully executes the * function for the flag, the flag is marked as "finished". * * @param flag A once-state flag. Should have been initialized by @ref * MLIB_ONCE_INITIALIZER. * @param fn A callback to execute if the flag is not in the "finished" state * @return true on success, false otherwise */ static inline bool mlib_call_once(mlib_once_flag *flag, mlib_init_once_fn_t fn) { #ifdef _WIN32 bool okay = InitOnceExecuteOnce(&flag->_native, &_mlib_win32_once_callthru, &fn, NULL); return okay; #else return pthread_once(&flag->_native, fn) == 0; #endif } #endif // MLIB_THREAD_H mongodb-1.21.0/src/libmongocrypt/src/mlib/user-check.h0000644000175100001660000000047414760300420017535 0ustar #ifndef MLIB_USER #error \ "The file being compiled transitively #include'd a mongo-mlib header, but is not a direct consumer of mlib, which is a private library for MongoDB C driver libraries" #endifmongodb-1.21.0/src/libmongocrypt/src/mlib/windows-lean.h0000644000175100001660000000076614760300420020117 0ustar /** * This file is simply a wrapper around and ensures that * WIN32_LEAN_AND_MEAN is defined before including it. */ #ifndef MLIB_WINDOWS_LEAN_H #define MLIB_WINDOWS_LEAN_H #ifdef __has_include #if !__has_include() #error " is only available when in available." #endif #endif #pragma push_macro("WIN32_LEAN_AND_MEAN") #define WIN32_LEAN_AND_MEAN 1 #include #pragma pop_macro("WIN32_LEAN_AND_MEAN") #endif // MLIB_WINDOWS_LEAN_H mongodb-1.21.0/src/libmongocrypt/src/os_posix/os_dll.c0000644000175100001660000000771214760300420017675 0ustar // Turn on libc extensions so that we can use dladdr() on Unix-like systems #if defined(__has_include) && !(defined(_GNU_SOURCE) || defined(_DARWIN_C_SOURCE)) #if __has_include() // We're using a glibc-compatible library #define _GNU_SOURCE #elif __has_include() // We're on Apple/Darwin #define _DARWIN_C_SOURCE #endif #else // No __has_include #if __GNUC__ < 5 // Best guess on older GCC is that we are using glibc #define _GNU_SOURCE #endif #endif #include "../mongocrypt-dll-private.h" #ifndef _WIN32 #include #include #include #include mcr_dll mcr_dll_open(const char *filepath) { void *handle = dlopen(filepath, RTLD_LAZY | RTLD_LOCAL); if (handle == NULL) { // Failed to open. Return NULL and copy the error message return (mcr_dll){ ._native_handle = NULL, .error_string = mstr_copy_cstr(dlerror()), }; } else { // Okay return (mcr_dll){ ._native_handle = handle, .error_string = MSTR_NULL, }; } } void mcr_dll_close_handle(mcr_dll dll) { if (dll._native_handle) { dlclose(dll._native_handle); } } void *mcr_dll_sym(mcr_dll dll, const char *sym) { return dlsym(dll._native_handle, sym); } #endif #ifdef __APPLE__ #include #include mcr_dll_path_result mcr_dll_path(mcr_dll dll) { // Clear the three low bits of the module handle: uintptr_t needle = ((uintptr_t)dll._native_handle & ~UINT64_C(0x3)); // Iterate each loaded dyld image /// NOTE: Not thread safe. Is there a thread-safe way to do this? for (uint32_t idx = 0; idx < _dyld_image_count(); ++idx) { // Get the filepath: /// NOTE: Between here and `dlopen`, `dyld_name` could be invalidated by /// a concurrent call to `dlclose()`. Is there a better way? const char *dyld_name = _dyld_get_image_name(idx); // Try and open it. This will return an equivalent pointer to the original // handle to the loaded image since they are deduplicated and reference // counted. void *try_handle = dlopen(dyld_name, RTLD_LAZY); if (!dyld_name) { // Ouch: `idx` was invalidated before we called _dyld_get_image_name. // This will have caused `dlopen()` to return the default handle: assert(try_handle == RTLD_DEFAULT); continue; } // Copy the string before closing, to shrink the chance of `dyld_name` // being used-after-freed. mstr ret_name = mstr_copy_cstr(dyld_name); // Mask off the mode bits: uintptr_t cur = (uintptr_t)try_handle & ~UINT64_C(0x3); // Close our reference to the image. We only care about the handle value. dlclose(try_handle); if (needle == cur) { // We've found the handle return (mcr_dll_path_result){.path = ret_name}; } // Not this name. mstr_free(ret_name); } return (mcr_dll_path_result){.error_string = mstr_copy_cstr("Handle not found in loaded modules")}; } bool mcr_dll_path_supported(void) { return true; } #elif defined(__linux__) || defined(__FreeBSD__) #include mcr_dll_path_result mcr_dll_path(mcr_dll dll) { struct link_map *map = NULL; int rc = dlinfo(dll._native_handle, RTLD_DI_LINKMAP, &map); if (rc == 0) { assert(NULL != map); return (mcr_dll_path_result){.path = mstr_copy_cstr(map->l_name)}; } else { return (mcr_dll_path_result){.error_string = mstr_copy_cstr(dlerror())}; } } bool mcr_dll_path_supported(void) { return true; } #elif defined(_WIN32) // Handled in os_win/os_dll.c #else mcr_dll_path_result mcr_dll_path(mcr_dll dll) { return (mcr_dll_path_result){.error_string = mstr_copy_cstr("Don't know how to do mcr_dll_path() on this platform")}; } bool mcr_dll_path_supported(void) { return false; } #endif mongodb-1.21.0/src/libmongocrypt/src/os_posix/os_mutex.c0000644000175100001660000000234514760300420020261 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "../mongocrypt-mutex-private.h" #ifndef _WIN32 void _mongocrypt_mutex_init(mongocrypt_mutex_t *mutex) { int ret = pthread_mutex_init(mutex, NULL); if (ret) { abort(); } } void _mongocrypt_mutex_cleanup(mongocrypt_mutex_t *mutex) { int ret = pthread_mutex_destroy(mutex); if (ret) { abort(); } } void _mongocrypt_mutex_lock(mongocrypt_mutex_t *mutex) { int ret = pthread_mutex_lock(mutex); if (ret) { abort(); } } void _mongocrypt_mutex_unlock(mongocrypt_mutex_t *mutex) { int ret = pthread_mutex_unlock(mutex); if (ret) { abort(); } } #endif /* _WIN32 */mongodb-1.21.0/src/libmongocrypt/src/os_win/os_dll.c0000644000175100001660000000537714760300420017335 0ustar #include "../mongocrypt-dll-private.h" #ifdef _WIN32 #include #include #include #include #include #include mcr_dll mcr_dll_open(const char *filepath_) { // Convert all slashes to the native Windows separator mstr filepath = mpath_to_format(MPATH_WIN32, mstrv_view_cstr(filepath_), MPATH_WIN32); // Check if the path is just a filename. bool is_just_filename = mstr_eq(mpath_filename(filepath.view, MPATH_WIN32), filepath.view); if (!is_just_filename) { // If the path is only a filename, we'll allow LoadLibrary() to do a // proper full DLL search. If the path is NOT just a filename, resolve the // given path to a single unambiguous absolute path to suppress // LoadLibrary()'s DLL search behavior. mstr_assign(&filepath, mpath_absolute(filepath.view, MPATH_WIN32)); } mstr_widen_result wide = mstr_win32_widen(filepath.view); mstr_free(filepath); if (wide.error) { return (mcr_dll){._native_handle = NULL, .error_string = merror_system_error_string(wide.error)}; } HMODULE lib = LoadLibraryW(wide.wstring); if (lib == NULL) { return (mcr_dll){._native_handle = NULL, .error_string = merror_system_error_string(GetLastError())}; } free(wide.wstring); return (mcr_dll){.error_string = NULL, ._native_handle = lib}; } void mcr_dll_close_handle(mcr_dll dll) { if (dll._native_handle) { FreeLibrary(dll._native_handle); } } void *mcr_dll_sym(mcr_dll dll, const char *sym) { return GetProcAddress(dll._native_handle, sym); } mcr_dll_path_result mcr_dll_path(mcr_dll dll) { mstr ret_str = MSTR_NULL; int ret_error = 0; DWORD acc_size = 512; while (!ret_str.data && !ret_error) { // Loop until we allocate a large enough buffer or get an error wchar_t *path = calloc((size_t)acc_size + 1u, sizeof(wchar_t)); SetLastError(0); GetModuleFileNameW(dll._native_handle, path, acc_size); if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Try again with more buffer /* DWORD is a 32-bit unsigned integer */ assert(acc_size <= UINT32_MAX / 2u); acc_size *= 2; } else if (GetLastError() != 0) { ret_error = GetLastError(); } else { mstr_narrow_result narrow = mstr_win32_narrow(path); // GetModuleFileNameW should never return invalid Unicode: assert(narrow.error == 0); ret_str = narrow.string; } free(path); } return (mcr_dll_path_result){ .path = ret_str, .error_string = merror_system_error_string(ret_error), }; } bool mcr_dll_path_supported(void) { return true; } #endif mongodb-1.21.0/src/libmongocrypt/src/os_win/os_mutex.c0000644000175100001660000000204714760300420017713 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "../mongocrypt-mutex-private.h" #ifdef _WIN32 void _mongocrypt_mutex_init(mongocrypt_mutex_t *mutex) { InitializeCriticalSection(mutex); } void _mongocrypt_mutex_cleanup(mongocrypt_mutex_t *mutex) { DeleteCriticalSection(mutex); } void _mongocrypt_mutex_lock(mongocrypt_mutex_t *mutex) { EnterCriticalSection(mutex); } void _mongocrypt_mutex_unlock(mongocrypt_mutex_t *mutex) { LeaveCriticalSection(mutex); } #endif /* _WIN32 */mongodb-1.21.0/src/libmongocrypt/src/mc-array-private.h0000644000175100001660000000260314760300420017740 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_ARRAY_PRIVATE_H #define MC_ARRAY_PRIVATE_H /* This file is copied from mongoc-array-private.h in libmongoc version 1.17.7 * at commit 200a01bb208633fe3cf395d81acc1e19492d9de4 */ #include typedef struct _mc_array_t mc_array_t; struct _mc_array_t { size_t len; size_t element_size; size_t allocated; void *data; }; #define _mc_array_append_val(a, v) _mc_array_append_vals(a, &v, 1) #define _mc_array_index(a, t, i) (((t *)(a)->data)[i]) #define _mc_array_clear(a) (a)->len = 0 void _mc_array_init(mc_array_t *array, size_t element_size); void _mc_array_copy(mc_array_t *dst, const mc_array_t *src); void _mc_array_append_vals(mc_array_t *array, const void *data, uint32_t n_elements); void _mc_array_destroy(mc_array_t *array); #endif /* MC_ARRAY_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-array.c0000644000175100001660000000514414760300420016266 0ustar /* * Copyright 2022-present MongoDB, 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. */ /* This file is copied from mongoc-array.c in libmongoc version 1.17.7 at commit * 200a01bb208633fe3cf395d81acc1e19492d9de4 */ #include "mc-array-private.h" void _mc_array_init(mc_array_t *array, size_t element_size) { BSON_ASSERT_PARAM(array); BSON_ASSERT(element_size); array->len = 0; array->element_size = element_size; array->allocated = 128; array->data = (void *)bson_malloc0(array->allocated); } /* *-------------------------------------------------------------------------- * * _mc_array_copy -- * * Destroy dst and copy src into it. Both arrays must be initialized. * * Returns: * None. * * Side effects: * None. * *-------------------------------------------------------------------------- */ void _mc_array_copy(mc_array_t *dst, const mc_array_t *src) { BSON_ASSERT_PARAM(dst); BSON_ASSERT_PARAM(src); _mc_array_destroy(dst); dst->len = src->len; dst->element_size = src->element_size; dst->allocated = src->allocated; dst->data = (void *)bson_malloc(dst->allocated); memcpy(dst->data, src->data, dst->allocated); } void _mc_array_destroy(mc_array_t *array) { if (array && array->data) { bson_free(array->data); } } void _mc_array_append_vals(mc_array_t *array, const void *data, uint32_t n_elements) { size_t len; size_t off; size_t next_size; BSON_ASSERT_PARAM(array); BSON_ASSERT_PARAM(data); BSON_ASSERT(array->len <= SIZE_MAX / array->element_size); off = array->element_size * array->len; BSON_ASSERT(n_elements <= SIZE_MAX / array->element_size); len = (size_t)n_elements * array->element_size; BSON_ASSERT(len <= SIZE_MAX - off); if ((off + len) > array->allocated) { next_size = bson_next_power_of_two(off + len); array->data = (void *)bson_realloc(array->data, next_size); array->allocated = next_size; } memcpy((uint8_t *)array->data + off, data, len); BSON_ASSERT(array->len <= SIZE_MAX - n_elements); array->len += n_elements; } mongodb-1.21.0/src/libmongocrypt/src/mc-check-conversions-private.h0000644000175100001660000000242714760300420022251 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_CHECK_CONVERSIONS_PRIVATE #define MC_CHECK_CONVERSIONS_PRIVATE // gcc 4.6 added support for "diagnostic push". #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #define MC_BEGIN_CONVERSION_IGNORE _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wconversion\"") #define MC_END_CONVERSION_IGNORE _Pragma("GCC diagnostic pop") #elif defined(__clang__) #define MC_BEGIN_CONVERSION_IGNORE _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wconversion\"") #define MC_END_CONVERSION_IGNORE _Pragma("clang diagnostic pop") #else #define MC_BEGIN_CONVERSION_IGNORE #define MC_END_CONVERSION_IGNORE #endif #endif /* MC_CHECK_CONVERSIONS_PRIVATE */ mongodb-1.21.0/src/libmongocrypt/src/mc-cmp-private.h0000644000175100001660000001606714760300420017412 0ustar /* * Copyright 2018-present MongoDB, 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. */ // `cmp.h` is a modified copy of `bson-cmp.h` from libbson 1.28.0. #ifndef MC_CMP_H #define MC_CMP_H #include /* ssize_t + BSON_CONCAT */ #include #include #include /* Sanity check: ensure ssize_t limits are as expected relative to size_t. */ BSON_STATIC_ASSERT2(ssize_t_size_min_check, SSIZE_MIN + 1 == -SSIZE_MAX); BSON_STATIC_ASSERT2(ssize_t_size_max_check, (size_t)SSIZE_MAX <= SIZE_MAX); /* Based on the "Safe Integral Comparisons" proposal merged in C++20: * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0586r2.html * * Due to lack of type deduction in C, relational comparison functions (e.g. * `cmp_less`) are defined in sets of four "functions" according to the * signedness of each value argument, e.g.: * - mc_cmp_less_ss (signed-value, signed-value) * - mc_cmp_less_uu (unsigned-value, unsigned-value) * - mc_cmp_less_su (signed-value, unsigned-value) * - mc_cmp_less_us (unsigned-value, signed-value) * * Similarly, the `in_range` function is defined as a set of two "functions" * according to the signedness of the value argument: * - mc_in_range_signed (Type, signed-value) * - mc_in_range_unsigned (Type, unsigned-value) * * The user must take care to use the correct signedness for the provided * argument(s). Enabling compiler warnings for implicit sign conversions is * recommended. */ #define MC_CMP_SET(op, ss, uu, su, us) \ static BSON_INLINE bool BSON_CONCAT3(mc_cmp_, op, _ss)(int64_t t, int64_t u) { return (ss); } \ \ static BSON_INLINE bool BSON_CONCAT3(mc_cmp_, op, _uu)(uint64_t t, uint64_t u) { return (uu); } \ \ static BSON_INLINE bool BSON_CONCAT3(mc_cmp_, op, _su)(int64_t t, uint64_t u) { return (su); } \ \ static BSON_INLINE bool BSON_CONCAT3(mc_cmp_, op, _us)(uint64_t t, int64_t u) { return (us); } MC_CMP_SET(equal, t == u, t == u, t < 0 ? false : (uint64_t)(t) == u, u < 0 ? false : t == (uint64_t)(u)) MC_CMP_SET(not_equal, !mc_cmp_equal_ss(t, u), !mc_cmp_equal_uu(t, u), !mc_cmp_equal_su(t, u), !mc_cmp_equal_us(t, u)) MC_CMP_SET(less, t < u, t < u, t < 0 ? true : (uint64_t)(t) < u, u < 0 ? false : t < (uint64_t)(u)) MC_CMP_SET(greater, mc_cmp_less_ss(u, t), mc_cmp_less_uu(u, t), mc_cmp_less_us(u, t), mc_cmp_less_su(u, t)) MC_CMP_SET(less_equal, !mc_cmp_greater_ss(t, u), !mc_cmp_greater_uu(t, u), !mc_cmp_greater_su(t, u), !mc_cmp_greater_us(t, u)) MC_CMP_SET(greater_equal, !mc_cmp_less_ss(t, u), !mc_cmp_less_uu(t, u), !mc_cmp_less_su(t, u), !mc_cmp_less_us(t, u)) #undef MC_CMP_SET /* Return true if the given value is within the range of the corresponding * signed type. The suffix must match the signedness of the given value. */ #define MC_IN_RANGE_SET_SIGNED(Type, min, max) \ static BSON_INLINE bool BSON_CONCAT3(mc_in_range, _##Type, _signed)(int64_t value) { \ return mc_cmp_greater_equal_ss(value, min) && mc_cmp_less_equal_ss(value, max); \ } \ \ static BSON_INLINE bool BSON_CONCAT3(mc_in_range, _##Type, _unsigned)(uint64_t value) { \ return mc_cmp_greater_equal_us(value, min) && mc_cmp_less_equal_us(value, max); \ } /* Return true if the given value is within the range of the corresponding * unsigned type. The suffix must match the signedness of the given value. */ #define MC_IN_RANGE_SET_UNSIGNED(Type, max) \ static BSON_INLINE bool BSON_CONCAT3(mc_in_range, _##Type, _signed)(int64_t value) { \ return mc_cmp_greater_equal_su(value, 0u) && mc_cmp_less_equal_su(value, max); \ } \ \ static BSON_INLINE bool BSON_CONCAT3(mc_in_range, _##Type, _unsigned)(uint64_t value) { \ return mc_cmp_less_equal_uu(value, max); \ } MC_IN_RANGE_SET_SIGNED(signed_char, SCHAR_MIN, SCHAR_MAX) MC_IN_RANGE_SET_SIGNED(short, SHRT_MIN, SHRT_MAX) MC_IN_RANGE_SET_SIGNED(int, INT_MIN, INT_MAX) MC_IN_RANGE_SET_SIGNED(long, LONG_MIN, LONG_MAX) MC_IN_RANGE_SET_SIGNED(long_long, LLONG_MIN, LLONG_MAX) MC_IN_RANGE_SET_UNSIGNED(unsigned_char, UCHAR_MAX) MC_IN_RANGE_SET_UNSIGNED(unsigned_short, USHRT_MAX) MC_IN_RANGE_SET_UNSIGNED(unsigned_int, UINT_MAX) MC_IN_RANGE_SET_UNSIGNED(unsigned_long, ULONG_MAX) MC_IN_RANGE_SET_UNSIGNED(unsigned_long_long, ULLONG_MAX) MC_IN_RANGE_SET_SIGNED(int8_t, INT8_MIN, INT8_MAX) MC_IN_RANGE_SET_SIGNED(int16_t, INT16_MIN, INT16_MAX) MC_IN_RANGE_SET_SIGNED(int32_t, INT32_MIN, INT32_MAX) MC_IN_RANGE_SET_SIGNED(int64_t, INT64_MIN, INT64_MAX) MC_IN_RANGE_SET_UNSIGNED(uint8_t, UINT8_MAX) MC_IN_RANGE_SET_UNSIGNED(uint16_t, UINT16_MAX) MC_IN_RANGE_SET_UNSIGNED(uint32_t, UINT32_MAX) MC_IN_RANGE_SET_UNSIGNED(uint64_t, UINT64_MAX) MC_IN_RANGE_SET_SIGNED(ssize_t, SSIZE_MIN, SSIZE_MAX) MC_IN_RANGE_SET_UNSIGNED(size_t, SIZE_MAX) #undef MC_IN_RANGE_SET_SIGNED #undef MC_IN_RANGE_SET_UNSIGNED /* Return true if the value with *signed* type is in the representable range of * Type and false otherwise. */ #define mc_in_range_signed(Type, value) BSON_CONCAT3(mc_in_range, _##Type, _signed)(value) /* Return true if the value with *unsigned* type is in the representable range * of Type and false otherwise. */ #define mc_in_range_unsigned(Type, value) BSON_CONCAT3(mc_in_range, _##Type, _unsigned)(value) #endif /* MC_CMP_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-dec128.h0000644000175100001660000005734714760300420016157 0ustar #ifndef MC_DEC128_H_INCLUDED #define MC_DEC128_H_INCLUDED #include #include #include #include // Conditional preprocessor definition set by the usage of an intel_dfp from // the ImportDFP.cmake script: #ifndef MONGOCRYPT_INTELDFP // Notify includers that Decimal128 is not available: #define MONGOCRYPT_HAVE_DECIMAL128_SUPPORT 0 #else // With IntelDFP: // Tell includers that Decimal128 is okay: #define MONGOCRYPT_HAVE_DECIMAL128_SUPPORT 1 // Include the header that declares the DFP functions, which may be macros that // expand to renamed symbols: #include #include #include #include #include #include MLIB_C_LINKAGE_BEGIN /// Rounding controls for Decimal128 operations typedef enum mc_dec128_rounding_mode { MC_DEC128_ROUND_NEAREST_EVEN = 0, MC_DEC128_ROUND_DOWNWARD = 1, MC_DEC128_ROUND_UPWARD = 2, MC_DEC128_ROUND_TOWARD_ZERO = 3, MC_DEC128_ROUND_NEAREST_AWAY = 4, MC_DEC128_ROUND_DEFAULT = MC_DEC128_ROUND_NEAREST_EVEN, } mc_dec128_rounding_mode; typedef struct mc_dec128_flagset { _IDEC_flags bits; } mc_dec128_flagset; // This alignment conditional is the same conditions used in Intel's DFP // library, ensuring we match the ABI of the library without pulling the header #if defined _MSC_VER #if defined _M_IX86 && !defined __INTEL_COMPILER #define _mcDec128Align(n) #else #define _mcDec128Align(n) __declspec(align(n)) #endif #else #if !defined HPUX_OS #define _mcDec128Align(n) __attribute__((aligned(n))) #else #define _mcDec128Align(n) #endif #endif typedef union _mcDec128Align(16) { uint64_t _words[2]; #if !defined(__INTELLISENSE__) && defined(__GNUC__) && defined(__amd64) && !defined(__APPLE__) && !defined(__clang__) // If supported by the compiler, emit a field that can be used to visualize // the value in a debugger. float value_ __attribute__((mode(TD))); #endif } mc_dec128; #undef _mcDec128Align /// Expands to a dec128 constant value. #ifdef __cplusplus #define MC_DEC128_C(N) mc_dec128 _mcDec128Const(((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0)) #else #define MC_DEC128_C(N) _mcDec128Const(((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0)) #endif #define MC_DEC128(N) MLIB_INIT(mc_dec128) MC_DEC128_C(N) #define _mcDec128Combination(Bits) ((uint64_t)(Bits) << (47)) #define _mcDec128ZeroExpCombo _mcDec128Combination(1 << 7 | 1 << 13 | 1 << 14) #define _mcDec128Const(N, Negate) _mcDec128ConstFromParts(N, (_mcDec128ZeroExpCombo | ((uint64_t)(Negate) << 63))) #define _mcDec128ConstFromParts(CoeffLow, HighWord) \ { \ { \ MLIB_IS_LITTLE_ENDIAN ? (uint64_t)(CoeffLow) : (uint64_t)(HighWord), \ MLIB_IS_LITTLE_ENDIAN ? (uint64_t)(HighWord) : (uint64_t)(CoeffLow), \ }, \ } static const mc_dec128 MC_DEC128_ZERO = MC_DEC128_C(0); static const mc_dec128 MC_DEC128_ONE = MC_DEC128_C(1); static const mc_dec128 MC_DEC128_MINUSONE = MC_DEC128_C(-1); /// The greatest-magnitude finite negative value representable in a Decimal128 #define MC_DEC128_LARGEST_NEGATIVE mc_dec128_from_string("-9999999999999999999999999999999999E6111") /// The least-magnitude non-zero negative value representable in a Decimal128 #define MC_DEC128_SMALLEST_NEGATIVE mc_dec128_from_string("-1E-6176") /// The greatest-magnitude finite positive value representable in a Decimal128 #define MC_DEC128_LARGEST_POSITIVE mc_dec128_from_string("9999999999999999999999999999999999E6111") /// The least-magnitude non-zero positive value representable in a Decimal128 #define MC_DEC128_SMALLEST_POSITIVE mc_dec128_from_string("1E-6176") /// The normalized zero of Decimal128 #define MC_DEC128_NORMALIZED_ZERO MC_DEC128_C(0) /// A zero of Decimal128 with the least exponent #define MC_DEC128_NEGATIVE_EXPONENT_ZERO mc_dec128_from_string("0E-6176") #define _mcDec128InfCombo _mcDec128Combination(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12) #define _mcDec128QuietNaNCombo _mcDec128Combination(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | 1 << 11) /// Positive infinity of Decimal128 #define MC_DEC128_POSITIVE_INFINITY _mcDec128ConstFromParts(0, _mcDec128InfCombo) /// Negative infinity of Decimal128 #define MC_DEC128_NEGATIVE_INFINITY _mcDec128ConstFromParts(0, _mcDec128InfCombo | 1ull << 63) /// Positve quiet NaN of Decimal128 #define MC_DEC128_POSITIVE_NAN _mcDec128ConstFromParts(0, _mcDec128QuietNaNCombo) /// Negative quiet NaN of Decimal128 #define MC_DEC128_NEGATIVE_NAN _mcDec128ConstFromParts(0, _mcDec128QuietNaNCombo | 1ull << 63) /// Convert an mc_dec128 value to a DFP 128-bit object static inline BID_UINT128 _mc_to_bid128(mc_dec128 d) { BID_UINT128 r; memcpy(&r, &d, sizeof d); return r; } /// Convert a DFP 128-bit object to a mc_dec128 value static inline mc_dec128 _bid128_to_mc(BID_UINT128 d) { mc_dec128 r; memcpy(&r, &d, sizeof d); return r; } /** * @brief Convert a double-precision binary floating point value into the * nearest Decimal128 value * * @param d The number to conver * @param rnd The rounding mode in case the value is not exactly representable * @param flags Out param for exception/error flags (Optional) */ static inline mc_dec128 mc_dec128_from_double_ex(double d, mc_dec128_rounding_mode rnd, mc_dec128_flagset *flags) { mc_dec128_flagset zero_flags = {0}; return _bid128_to_mc(binary64_to_bid128(d, rnd, flags ? &flags->bits : &zero_flags.bits)); } /** * @brief Convert a double-precision binary floating point value into the * nearest Decimal128 value */ static inline mc_dec128 mc_dec128_from_double(double d) { return mc_dec128_from_double_ex(d, MC_DEC128_ROUND_DEFAULT, NULL); } /** * @brief Convert a string representation of a number into the nearest * Decimal128 value * * @param s The string to parse. MUST be null-terminated * @param rnd The rounding mode to use if the result is not representable * @param flags Out param for exception/error flags (Optional) */ static inline mc_dec128 mc_dec128_from_string_ex(const char *s, mc_dec128_rounding_mode rnd, mc_dec128_flagset *flags) { mc_dec128_flagset zero_flags = {0}; return _bid128_to_mc(bid128_from_string((char *)s, rnd, flags ? &flags->bits : &zero_flags.bits)); } /** * @brief Convert a string representation of a number into the nearest * Decimal128 value */ static inline mc_dec128 mc_dec128_from_string(const char *s) { return mc_dec128_from_string_ex(s, MC_DEC128_ROUND_DEFAULT, NULL); } /** * @brief A type capable of holding a string rendering of a Decimal128 in * engineering notation. */ typedef struct mc_dec128_string { /// The character array of the rendered value. Null-terminated char str[48]; } mc_dec128_string; /** * @brief Render a Decimal128 value as a string (in engineering notation) * * @param d The number to represent * @param flags Output parameter for exception/error flags (optional) */ static inline mc_dec128_string mc_dec128_to_string_ex(mc_dec128 d, mc_dec128_flagset *flags) { mc_dec128_flagset zero_flags = {0}; mc_dec128_string out = {{0}}; bid128_to_string(out.str, _mc_to_bid128(d), flags ? &flags->bits : &zero_flags.bits); return out; } /** * @brief Render a Decimal128 value as a string (in engineering notation) */ static inline mc_dec128_string mc_dec128_to_string(mc_dec128 d) { return mc_dec128_to_string_ex(d, NULL); } /// Compare two dec128 numbers #define DECL_IDF_COMPARE_1(Oper) \ static inline bool mc_dec128_##Oper##_ex(mc_dec128 left, mc_dec128 right, mc_dec128_flagset *flags) { \ mc_dec128_flagset zero_flags = {0}; \ return 0 \ != bid128_quiet_##Oper(_mc_to_bid128(left), \ _mc_to_bid128(right), \ flags ? &flags->bits : &zero_flags.bits); \ } \ \ static inline bool mc_dec128_##Oper(mc_dec128 left, mc_dec128 right) { \ return mc_dec128_##Oper##_ex(left, right, NULL); \ } #define DECL_IDF_COMPARE(Op) DECL_IDF_COMPARE_1(Op) DECL_IDF_COMPARE(equal) DECL_IDF_COMPARE(not_equal) DECL_IDF_COMPARE(greater) DECL_IDF_COMPARE(greater_equal) DECL_IDF_COMPARE(less) DECL_IDF_COMPARE(less_equal) #undef DECL_IDF_COMPARE #undef DECL_IDF_COMPARE_1 /// Test properties of Decimal128 numbers #define DECL_PREDICATE(Name, BIDName) \ static inline bool mc_dec128_##Name(mc_dec128 d) { return 0 != bid128_##BIDName(_mc_to_bid128(d)); } DECL_PREDICATE(is_zero, isZero) DECL_PREDICATE(is_negative, isSigned) DECL_PREDICATE(is_inf, isInf) DECL_PREDICATE(is_finite, isFinite) DECL_PREDICATE(is_nan, isNaN) #undef DECL_PREDICATE /// Binary arithmetic operations on two Decimal128 numbers #define DECL_IDF_BINOP_WRAPPER(Oper) \ static inline mc_dec128 mc_dec128_##Oper##_ex(mc_dec128 left, \ mc_dec128 right, \ mc_dec128_rounding_mode mode, \ mc_dec128_flagset *flags) { \ mc_dec128_flagset zero_flags = {0}; \ return _bid128_to_mc( \ bid128_##Oper(_mc_to_bid128(left), _mc_to_bid128(right), mode, flags ? &flags->bits : &zero_flags.bits)); \ } \ \ static inline mc_dec128 mc_dec128_##Oper(mc_dec128 left, mc_dec128 right) { \ return mc_dec128_##Oper##_ex(left, right, MC_DEC128_ROUND_DEFAULT, NULL); \ } DECL_IDF_BINOP_WRAPPER(add) DECL_IDF_BINOP_WRAPPER(mul) DECL_IDF_BINOP_WRAPPER(div) DECL_IDF_BINOP_WRAPPER(sub) DECL_IDF_BINOP_WRAPPER(pow) #undef DECL_IDF_BINOP_WRAPPER /// Unary arithmetic operations on two Decimal128 numbers #define DECL_IDF_UNOP_WRAPPER(Oper) \ static inline mc_dec128 mc_dec128_##Oper##_ex(mc_dec128 operand, mc_dec128_flagset *flags) { \ mc_dec128_flagset zero_flags = {0}; \ return _bid128_to_mc( \ bid128_##Oper(_mc_to_bid128(operand), MC_DEC128_ROUND_DEFAULT, flags ? &flags->bits : &zero_flags.bits)); \ } \ \ static inline mc_dec128 mc_dec128_##Oper(mc_dec128 operand) { return mc_dec128_##Oper##_ex(operand, NULL); } DECL_IDF_UNOP_WRAPPER(log2) DECL_IDF_UNOP_WRAPPER(log10) #undef DECL_IDF_UNOP_WRAPPER static inline mc_dec128 mc_dec128_round_integral_ex(mc_dec128 value, mc_dec128_rounding_mode direction, mc_dec128_flagset *flags) { BID_UINT128 bid = _mc_to_bid128(value); mc_dec128_flagset zero_flags = {0}; _IDEC_flags *fl = flags ? &flags->bits : &zero_flags.bits; switch (direction) { case MC_DEC128_ROUND_TOWARD_ZERO: return _bid128_to_mc(bid128_round_integral_zero(bid, fl)); case MC_DEC128_ROUND_NEAREST_AWAY: return _bid128_to_mc(bid128_round_integral_nearest_away(bid, fl)); case MC_DEC128_ROUND_NEAREST_EVEN: return _bid128_to_mc(bid128_round_integral_nearest_even(bid, fl)); case MC_DEC128_ROUND_DOWNWARD: return _bid128_to_mc(bid128_round_integral_negative(bid, fl)); case MC_DEC128_ROUND_UPWARD: return _bid128_to_mc(bid128_round_integral_positive(bid, fl)); default: abort(); } } static inline mc_dec128 mc_dec128_negate(mc_dec128 operand) { return _bid128_to_mc(bid128_negate(_mc_to_bid128(operand))); } static inline mc_dec128 mc_dec128_abs(mc_dec128 operand) { return _bid128_to_mc(bid128_abs(_mc_to_bid128(operand))); } /** * @brief Scale the given Decimal128 by a power of ten * * @param fac The value being scaled * @param exp The exponent: 10^exp is the scale factor * @param rounding Rounding behavior * @param flags Control/result flags * @return mc_dec128 The product */ static inline mc_dec128 mc_dec128_scale_ex(mc_dec128 fac, long int exp, mc_dec128_rounding_mode rounding, mc_dec128_flagset *flags) { mc_dec128_flagset zero_flags = {0}; return _bid128_to_mc(bid128_scalbln(_mc_to_bid128(fac), exp, rounding, flags ? &flags->bits : &zero_flags.bits)); } /** * @brief Scale the given Decimal128 by a power of ten * * @param fac The value being scaled * @param exp The exponent: 10^exp is the scale factor * @return mc_dec128 The product */ static inline mc_dec128 mc_dec128_scale(mc_dec128 fac, long int exp) { return mc_dec128_scale_ex(fac, exp, MC_DEC128_ROUND_DEFAULT, NULL); } /// The result of a dec_128 modf operation typedef struct mc_dec128_modf_result { /// The whole part of the result mc_dec128 whole; /// The fractional part of the result mc_dec128 frac; } mc_dec128_modf_result; /** * @brief Split a Decimal128 into its whole and fractional parts. * * The "whole" value is the integral value of the Decimal128 rounded towards * zero. The "frac" part is the remainder after removing the whole. * * @param d The value to inspect * @param flags Results status flags */ static inline mc_dec128_modf_result mc_dec128_modf_ex(mc_dec128 d, mc_dec128_flagset *flags) { mc_dec128_flagset zero_flags = {0}; mc_dec128_modf_result res; BID_UINT128 whole; res.frac = _bid128_to_mc(bid128_modf(_mc_to_bid128(d), &whole, flags ? &flags->bits : &zero_flags.bits)); res.whole = _bid128_to_mc(whole); return res; } /** * @brief Split a Decimal128 into its whole and fractional parts. * * The "whole" value is the integral value of the Decimal128 rounded towards * zero. The "frac" part is the remainder after removing the whole. * * @param d The value to inspect */ static inline mc_dec128_modf_result mc_dec128_modf(mc_dec128 d) { return mc_dec128_modf_ex(d, NULL); } /** * @brief Compute the "fmod", the remainder after decimal division rounding * towards zero. * * @param numer The dividend of the modulus * @param denom The divisor of the modulus * @param flags Control/status flags */ static inline mc_dec128 mc_dec128_fmod_ex(mc_dec128 numer, mc_dec128 denom, mc_dec128_flagset *flags) { mc_dec128_flagset zero_flags = {0}; return _bid128_to_mc( bid128_fmod(_mc_to_bid128(numer), _mc_to_bid128(denom), flags ? &flags->bits : &zero_flags.bits)); } /** * @brief Compute the "fmod", the remainder after decimal division rounding * towards zero. * * @param numer The dividend of the modulus * @param denom The divisor of the modulus */ static inline mc_dec128 mc_dec128_fmod(mc_dec128 numer, mc_dec128 denom) { return mc_dec128_fmod_ex(numer, denom, NULL); } /** * @brief Obtain the a 64-bit binary integer value for the given Decimal128 * value, nearest rounding toward zero. * * @param d The value to inspect * @param flags Control/status flags */ static inline int64_t mc_dec128_to_int64_ex(mc_dec128 d, mc_dec128_flagset *flags) { mc_dec128_flagset zero_flags = {0}; return bid128_to_int64_int(_mc_to_bid128(d), flags ? &flags->bits : &zero_flags.bits); } /** * @brief Obtain the a 64-bit binary integer value for the given Decimal128 * value, nearest rounding toward zero. * * @param d The value to inspect */ static inline int64_t mc_dec128_to_int64(mc_dec128 d) { return mc_dec128_to_int64_ex(d, NULL); } /// Constants for inspection/deconstruction of Decimal128 enum { /// Least non-canonical combination bits value MC_DEC128_COMBO_NONCANONICAL = 3 << 15, /// Least combination value indicating infinity MC_DEC128_COMBO_INFINITY = 0x1e << 12, /// The greatest Decimal128 biased exponent MC_DEC128_MAX_BIASED_EXPONENT = 6143 + 6144, /// The exponent bias of Decimal128 MC_DEC128_EXPONENT_BIAS = 6143 + 33, // +33 to include the 34 decimal digits /// Minimum exponent value (without bias) MC_DEC_MIN_EXPONENT = -6143, /// Maximum exponent value (without bias) MC_DEC_MAX_EXPONENT = 6144, }; /// Obtain the value of the combination bits of a decimal128 static inline uint32_t mc_dec128_combination(mc_dec128 d) { // Grab the high 64 bits: uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0]; // Sign is the 64th bit: int signpos = 64 - 1; // Combo is the next 16 bits: int fieldpos = signpos - 17; int fieldmask = (1 << 17) - 1; return (uint32_t)((hi >> fieldpos) & (uint32_t)fieldmask); } /** * @brief Obtain the value of the high 49 bits of the Decimal128 coefficient */ static inline uint64_t mc_dec128_coeff_high(mc_dec128 d) { uint64_t hi_field_mask = (1ull << 49) - 1; uint32_t combo = mc_dec128_combination(d); if (combo < MC_DEC128_COMBO_NONCANONICAL) { uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0]; return hi & hi_field_mask; } else { return 0; } } /** * @brief Obtain the value of the low 64 bits of the Decimal128 coefficient */ static inline uint64_t mc_dec128_coeff_low(mc_dec128 d) { uint32_t combo = mc_dec128_combination(d); if (combo < MC_DEC128_COMBO_NONCANONICAL) { uint64_t lo = d._words[MLIB_IS_LITTLE_ENDIAN ? 0 : 1]; return lo; } else { return 0; } } /** * @brief Obtain the full coefficient of the given Decimal128 number. Requires a * 128-bit integer. */ static inline mlib_int128 mc_dec128_coeff(mc_dec128 d) { // Hi bits uint64_t hi = mc_dec128_coeff_high(d); // Lo bits uint64_t lo = mc_dec128_coeff_low(d); // Shift and add mlib_int128 hi_128 = mlib_int128_lshift(MLIB_INT128_CAST(hi), 64); return mlib_int128_add(hi_128, MLIB_INT128_CAST(lo)); } /** * @brief Obtain the biased value of the Decimal128 exponent. * * The value is "biased" in that its binary value not actually zero for 10^0. It * is offset by half the exponent range (the "bias") so it can encode the full * positive and negative exponent range. The bias value is defined as * MC_DEC128_EXPONENT_BIAS. */ static inline uint32_t mc_dec128_get_biased_exp(mc_dec128 d) { uint32_t combo = mc_dec128_combination(d); if (combo < MC_DEC128_COMBO_NONCANONICAL) { return combo >> 3; } if (combo >= MC_DEC128_COMBO_INFINITY) { return MC_DEC128_MAX_BIASED_EXPONENT + 1; } else { return (combo >> 1) & ((1 << 14) - 1); } } /// Create a decimal string from a dec128 number. The result must be freed. static inline char *mc_dec128_to_new_decimal_string(mc_dec128 d) { if (mc_dec128_is_zero(d)) { // Just return "0" char *s = (char *)calloc(2, 1); if (s) { s[0] = '0'; } return s; } if (mc_dec128_is_negative(d)) { // Negate the result, return a string with a '-' prefix d = mc_dec128_negate(d); char *s = mc_dec128_to_new_decimal_string(d); if (!s) { return NULL; } char *s1 = (char *)calloc(strlen(s) + 2, 1); if (s1) { s1[0] = '-'; strcpy(s1 + 1, s); } free(s); return s1; } if (mc_dec128_is_inf(d) || mc_dec128_is_nan(d)) { const char *r = mc_dec128_is_inf(d) ? "Infinity" : "NaN"; char *c = (char *)calloc(strlen(r) + 1, 1); if (c) { strcpy(c, r); } return c; } const char DIGITS[] = "0123456789"; const mc_dec128 TEN = MC_DEC128_C(10); // Format the whole and fractional part separately. mc_dec128_modf_result modf = mc_dec128_modf(d); if (mc_dec128_is_zero(modf.frac)) { // This is a non-zero integer // Allocate enough digits: mc_dec128 log10 = mc_dec128_modf(mc_dec128_log10(d)).whole; int64_t ndigits = mc_dec128_to_int64(log10) + 1; // +1 for null char *strbuf = (char *)calloc((size_t)(ndigits + 1), 1); if (strbuf) { // Write the string backwards: char *optr = strbuf + ndigits - 1; while (!mc_dec128_is_zero(modf.whole)) { mc_dec128 rem = mc_dec128_fmod(modf.whole, TEN); int64_t remi = mc_dec128_to_int64(rem); *optr-- = DIGITS[remi]; // Divide ten modf = mc_dec128_modf(mc_dec128_div(modf.whole, TEN)); } } return strbuf; } else if (mc_dec128_is_zero(modf.whole)) { // This is only a fraction (less than one, but more than zero) while (!mc_dec128_is_zero(mc_dec128_modf(d).frac)) { d = mc_dec128_mul(d, TEN); } // 'd' is now a whole number char *part = mc_dec128_to_new_decimal_string(d); if (!part) { return NULL; } char *buf = (char *)calloc(strlen(part) + 3, 1); if (buf) { buf[0] = '0'; buf[1] = '.'; strcpy(buf + 2, part); } free(part); return buf; } else { // We have both a whole part and a fractional part char *whole = mc_dec128_to_new_decimal_string(modf.whole); if (!whole) { return NULL; } char *frac = mc_dec128_to_new_decimal_string(modf.frac); if (!frac) { free(whole); return NULL; } char *ret = (char *)calloc(strlen(whole) + strlen(frac) + 1, 1); if (ret) { char *out = ret; strcpy(out, whole); out += strlen(whole); // "frac" contains a leading zero, which we don't want strcpy(out, frac + 1); } free(whole); free(frac); return ret; } } static inline mc_dec128 mc_dec128_from_bson_iter(const bson_iter_t *it) { bson_decimal128_t b; if (!bson_iter_decimal128(it, &b)) { mc_dec128 nan = MC_DEC128_POSITIVE_NAN; return nan; } mc_dec128 ret; memcpy(&ret, &b, sizeof b); return ret; } static inline bson_decimal128_t mc_dec128_to_bson_decimal128(mc_dec128 v) { bson_decimal128_t ret; memcpy(&ret, &v, sizeof ret); return ret; } MLIB_C_LINKAGE_END #endif /// defined MONGOCRYPT_INTELDFP #endif // MC_DEC128_H_INCLUDED mongodb-1.21.0/src/libmongocrypt/src/mc-efc-private.h0000644000175100001660000000425614760300420017365 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_EFC_PRIVATE_H #define MC_EFC_PRIVATE_H #include "mongocrypt-buffer-private.h" #include typedef enum _supported_query_type_flags { // No queries supported SUPPORTS_NO_QUERIES = 0, // Equality query supported SUPPORTS_EQUALITY_QUERIES = 1 << 0, // Range query supported SUPPORTS_RANGE_QUERIES = 1 << 1, // Range preview query supported SUPPORTS_RANGE_PREVIEW_DEPRECATED_QUERIES = 1 << 2, } supported_query_type_flags; typedef struct _mc_EncryptedField_t { supported_query_type_flags supported_queries; _mongocrypt_buffer_t keyId; const char *path; struct _mc_EncryptedField_t *next; } mc_EncryptedField_t; /* See * https://github.com/mongodb/mongo/blob/591f49a64e96cea68bf3501320de31c51c31f412/src/mongo/crypto/encryption_fields.idl#L48-L112 * for the server IDL definition of EncryptedFieldConfig. */ typedef struct { mc_EncryptedField_t *fields; } mc_EncryptedFieldConfig_t; /* mc_EncryptedFieldConfig_parse parses a subset of the fields from @efc_bson * into @efc. Fields are copied from @efc_bson. It is OK to free efc_bson after * this call. Fields are appended in reverse order to @efc->fields. Extra * unrecognized fields are not considered an error for forward compatibility. */ bool mc_EncryptedFieldConfig_parse(mc_EncryptedFieldConfig_t *efc, const bson_t *efc_bson, mongocrypt_status_t *status, bool use_range_v2); void mc_EncryptedFieldConfig_cleanup(mc_EncryptedFieldConfig_t *efc); #endif /* MC_EFC_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-efc.c0000644000175100001660000001654614760300420015715 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mc-efc-private.h" #include "mlib/str.h" #include "mongocrypt-private.h" #include "mongocrypt-util-private.h" // mc_iter_document_as_bson static bool _parse_query_type_string(const char *queryType, supported_query_type_flags *out) { BSON_ASSERT_PARAM(queryType); BSON_ASSERT_PARAM(out); mstr_view qtv = mstrv_view_cstr(queryType); if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_EQUALITY_STR), qtv)) { *out = SUPPORTS_EQUALITY_QUERIES; } else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_RANGE_STR), qtv)) { *out = SUPPORTS_RANGE_QUERIES; } else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED_STR), qtv)) { *out = SUPPORTS_RANGE_PREVIEW_DEPRECATED_QUERIES; } else { return false; } return true; } static bool _parse_supported_query_types(bson_iter_t *iter, supported_query_type_flags *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iter); BSON_ASSERT_PARAM(out); if (!BSON_ITER_HOLDS_DOCUMENT(iter)) { CLIENT_ERR("When parsing supported query types: Expected type document, got: %d", bson_iter_type(iter)); return false; } bson_t query_doc; if (!mc_iter_document_as_bson(iter, &query_doc, status)) { return false; } bson_iter_t query_type_iter; if (!bson_iter_init_find(&query_type_iter, &query_doc, "queryType")) { CLIENT_ERR("When parsing supported query types: Unable to find 'queryType' in query document"); return false; } if (!BSON_ITER_HOLDS_UTF8(&query_type_iter)) { CLIENT_ERR("When parsing supported query types: Expected 'queryType' to be type UTF-8, got: %d", bson_iter_type(&query_type_iter)); return false; } const char *queryType = bson_iter_utf8(&query_type_iter, NULL /* length */); if (!_parse_query_type_string(queryType, out)) { CLIENT_ERR("When parsing supported query types: Did not recognize query type '%s'", queryType); return false; } return true; } /* _parse_field parses and prepends one field document to efc->fields. */ static bool _parse_field(mc_EncryptedFieldConfig_t *efc, bson_t *field, mongocrypt_status_t *status, bool use_range_v2) { supported_query_type_flags query_types = SUPPORTS_NO_QUERIES; bson_iter_t field_iter; BSON_ASSERT_PARAM(efc); BSON_ASSERT_PARAM(field); if (!bson_iter_init_find(&field_iter, field, "keyId")) { CLIENT_ERR("unable to find 'keyId' in 'field' document"); return false; } if (!BSON_ITER_HOLDS_BINARY(&field_iter)) { CLIENT_ERR("expected 'fields.keyId' to be type binary, got: %d", bson_iter_type(&field_iter)); return false; } _mongocrypt_buffer_t field_keyid; if (!_mongocrypt_buffer_from_uuid_iter(&field_keyid, &field_iter)) { CLIENT_ERR("unable to parse uuid key from 'fields.keyId'"); return false; } const char *field_path; if (!bson_iter_init_find(&field_iter, field, "path")) { CLIENT_ERR("unable to find 'path' in 'field' document"); return false; } if (!BSON_ITER_HOLDS_UTF8(&field_iter)) { CLIENT_ERR("expected 'fields.path' to be type UTF-8, got: %d", bson_iter_type(&field_iter)); return false; } field_path = bson_iter_utf8(&field_iter, NULL /* length */); if (bson_iter_init_find(&field_iter, field, "queries")) { if (BSON_ITER_HOLDS_ARRAY(&field_iter)) { // Multiple queries, iterate through and grab all query types. uint32_t queries_buf_len; const uint8_t *queries_buf; bson_t queries_arr; bson_iter_array(&field_iter, &queries_buf_len, &queries_buf); if (!bson_init_static(&queries_arr, queries_buf, queries_buf_len)) { CLIENT_ERR("Failed to parse 'queries' field"); return false; } bson_iter_t queries_iter; bson_iter_init(&queries_iter, &queries_arr); while (bson_iter_next(&queries_iter)) { supported_query_type_flags flag; if (!_parse_supported_query_types(&queries_iter, &flag, status)) { return false; } query_types |= flag; } } else { supported_query_type_flags flag; if (!_parse_supported_query_types(&field_iter, &flag, status)) { return false; } query_types |= flag; } } if (query_types & SUPPORTS_RANGE_PREVIEW_DEPRECATED_QUERIES && use_range_v2) { // When rangev2 is enabled ("range") error if "rangePreview" is included. // This check is intended to give an easier-to-understand earlier error. CLIENT_ERR("Cannot use field '%s' with 'rangePreview' queries. 'rangePreview' is unsupported. Use 'range' " "instead. 'range' is not compatible with 'rangePreview' and requires recreating the collection.", field_path); return false; } /* Prepend a new mc_EncryptedField_t */ mc_EncryptedField_t *ef = bson_malloc0(sizeof(mc_EncryptedField_t)); _mongocrypt_buffer_copy_to(&field_keyid, &ef->keyId); ef->path = bson_strdup(field_path); ef->next = efc->fields; ef->supported_queries = query_types; efc->fields = ef; return true; } bool mc_EncryptedFieldConfig_parse(mc_EncryptedFieldConfig_t *efc, const bson_t *efc_bson, mongocrypt_status_t *status, bool use_range_v2) { bson_iter_t iter; BSON_ASSERT_PARAM(efc); BSON_ASSERT_PARAM(efc_bson); memset(efc, 0, sizeof(*efc)); if (!bson_iter_init_find(&iter, efc_bson, "fields")) { CLIENT_ERR("unable to find 'fields' in encrypted_field_config"); return false; } if (!BSON_ITER_HOLDS_ARRAY(&iter)) { CLIENT_ERR("expected 'fields' to be type array, got: %d", bson_iter_type(&iter)); return false; } if (!bson_iter_recurse(&iter, &iter)) { CLIENT_ERR("unable to recurse into encrypted_field_config 'fields'"); return false; } while (bson_iter_next(&iter)) { bson_t field; if (!mc_iter_document_as_bson(&iter, &field, status)) { return false; } if (!_parse_field(efc, &field, status, use_range_v2)) { return false; } } return true; } void mc_EncryptedFieldConfig_cleanup(mc_EncryptedFieldConfig_t *efc) { if (!efc) { return; } mc_EncryptedField_t *ptr = efc->fields; while (ptr != NULL) { mc_EncryptedField_t *ptr_next = ptr->next; _mongocrypt_buffer_cleanup(&ptr->keyId); bson_free((char *)ptr->path); bson_free(ptr); ptr = ptr_next; } } mongodb-1.21.0/src/libmongocrypt/src/mc-fle-blob-subtype-private.h0000644000175100001660000000365714760300420022007 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE_BLOB_SUBTYPE_PRIVATE_H #define MC_FLE_BLOB_SUBTYPE_PRIVATE_H /* FLE Blob Subtype is the first byte of a BSON Binary Subtype 6. * FLE1 Blob Subtypes are defined in: * https://github.com/mongodb/specifications/blob/master/source/bson-binary-encrypted/binary-encrypted.md * FLE2 Blob Subtypes are currently defined in: * https://github.com/markbenvenuto/mongo-enterprise-modules/blob/fle2/fle_protocol.md#reference-bindata-6-subtypes. */ typedef enum { MC_SUBTYPE_FLE1EncryptionPlaceholder = 0, MC_SUBTYPE_FLE1DeterministicEncryptedValue = 1, MC_SUBTYPE_FLE1RandomEncryptedValue = 2, MC_SUBTYPE_FLE2EncryptionPlaceholder = 3, MC_SUBTYPE_FLE2InsertUpdatePayload = 4, MC_SUBTYPE_FLE2FindEqualityPayload = 5, MC_SUBTYPE_FLE2UnindexedEncryptedValue = 6, MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue = 7, MC_SUBTYPE_FLE2IndexedRangeEncryptedValue = 9, MC_SUBTYPE_FLE2FindRangePayload = 10, /* Queryable Encryption Version 2 Subtypes */ MC_SUBTYPE_FLE2InsertUpdatePayloadV2 = 11, MC_SUBTYPE_FLE2FindEqualityPayloadV2 = 12, MC_SUBTYPE_FLE2FindRangePayloadV2 = 13, MC_SUBTYPE_FLE2IndexedEqualityEncryptedValueV2 = 14, MC_SUBTYPE_FLE2IndexedRangeEncryptedValueV2 = 15, MC_SUBTYPE_FLE2UnindexedEncryptedValueV2 = 16 } mc_fle_blob_subtype_t; #endif /* MC_FLE_BLOB_SUBTYPE_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-encryption-placeholder-private.h0000644000175100001660000001676614760300420024141 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE2_ENCRYPTION_PLACEHOLDER_PRIVATE_H #define MC_FLE2_ENCRYPTION_PLACEHOLDER_PRIVATE_H #include #include "mc-fle2-find-range-payload-private.h" #include "mc-optional-private.h" #include "mongocrypt-private.h" #include "mongocrypt.h" /** FLE2RangeFindSpecEdgesInfo represents the information needed to generate * edges for a range find query. It is encoded inside an FLE2RangeFindSpec. See * https://github.com/mongodb/mongo/blob/master/src/mongo/crypto/fle_field_schema.idl * for the representation in the MongoDB server. * * Bounds on range queries are referred to as lowerBound or lb, and upperBound * or ub. Bounds on an underlying range index are referred to as min and max. */ typedef struct { // lowerBound is the lower bound for an encrypted range query. bson_iter_t lowerBound; // lbIncluded indicates if the lower bound should be included in the range. bool lbIncluded; // upperBound is the upperBound for an encrypted range query. bson_iter_t upperBound; // ubIncluded indicates if the upper bound should be included in the range. bool ubIncluded; // indexMin is the minimum value for the encrypted index that this query is // using. bson_iter_t indexMin; // indexMax is the maximum value for the encrypted index that this query is // using. bson_iter_t indexMax; // precision determines the number of digits after the decimal point for // floating point values. mc_optional_int32_t precision; // trimFactor determines how many root levels of the hypergraph to trim. mc_optional_int32_t trimFactor; } mc_FLE2RangeFindSpecEdgesInfo_t; // `mc_FLE2RangeFindSpecEdgesInfo_t` inherits extended alignment from libbson. To dynamically allocate, use // aligned allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_FLE2RangeFindSpecEdgesInfo_t, BSON_ALIGNOF(mc_FLE2RangeFindSpecEdgesInfo_t) >= BSON_ALIGNOF(bson_iter_t)); /** FLE2RangeFindSpec represents the range find specification that is encoded * inside of a FLE2EncryptionPlaceholder. See * https://github.com/mongodb/mongo/blob/master/src/mongo/crypto/fle_field_schema.idl * for the representation in the MongoDB server. */ typedef struct { // edgesInfo is the information about the edges in an FLE2 find payload. struct { mc_FLE2RangeFindSpecEdgesInfo_t value; bool set; } edgesInfo; // payloadId Id of payload - must be paired with another payload. int32_t payloadId; // firstOperator represents the first query operator for which this payload // was generated. mc_FLE2RangeOperator_t firstOperator; // secondOperator represents the second query operator for which this payload // was generated. Only populated for two-sided ranges. It is 0 if unset. mc_FLE2RangeOperator_t secondOperator; } mc_FLE2RangeFindSpec_t; // `mc_FLE2RangeFindSpec_t` inherits extended alignment from libbson. To dynamically allocate, use // aligned allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_FLE2RangeFindSpec_t, BSON_ALIGNOF(mc_FLE2RangeFindSpec_t) >= BSON_ALIGNOF(mc_FLE2RangeFindSpecEdgesInfo_t)); bool mc_FLE2RangeFindSpec_parse(mc_FLE2RangeFindSpec_t *out, const bson_iter_t *in, bool use_range_v2, mongocrypt_status_t *status); /** mc_FLE2RangeInsertSpec_t represents the range insert specification that is * encoded inside of a FLE2EncryptionPlaceholder. See * https://github.com/mongodb/mongo/blob/master/src/mongo/crypto/fle_field_schema.idl#L364 * for the representation in the MongoDB server. */ typedef struct { // v is the value to encrypt. bson_iter_t v; // min is the Queryable Encryption min bound for range. bson_iter_t min; // max is the Queryable Encryption max bound for range. bson_iter_t max; // precision determines the number of digits after the decimal point for // floating point values. mc_optional_int32_t precision; // trimFactor determines how many root levels of the hypergraph to trim. mc_optional_int32_t trimFactor; } mc_FLE2RangeInsertSpec_t; // `mc_FLE2RangeInsertSpec_t` inherits extended alignment from libbson. To dynamically allocate, use // aligned allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_FLE2RangeInsertSpec_t, BSON_ALIGNOF(mc_FLE2RangeInsertSpec_t) >= BSON_ALIGNOF(bson_iter_t)); bool mc_FLE2RangeInsertSpec_parse(mc_FLE2RangeInsertSpec_t *out, const bson_iter_t *in, bool use_range_v2, mongocrypt_status_t *status); /** FLE2EncryptionPlaceholder implements Encryption BinData (subtype 6) * sub-subtype 0, the intent-to-encrypt mapping. Contains a value to encrypt and * a description of how it should be encrypted. * * For automatic encryption, FLE2EncryptionPlaceholder is created by query * analysis (mongocryptd or mongo_crypt shared library). For explicit * encryption, FLE2EncryptionPlaceholder is created by libmongocrypt. * * FLE2EncryptionPlaceholder is processed by libmongocrypt into a payload * suitable to send to the MongoDB server (mongod/mongos). * * See * https://github.com/mongodb/mongo/blob/d870dda33fb75983f628636ff8f849c7f1c90b09/src/mongo/crypto/fle_field_schema.idl#L133 * for the representation in the MongoDB server. */ typedef struct { mongocrypt_fle2_placeholder_type_t type; mongocrypt_fle2_encryption_algorithm_t algorithm; bson_iter_t v_iter; _mongocrypt_buffer_t index_key_id; _mongocrypt_buffer_t user_key_id; int64_t maxContentionFactor; // sparsity is the Queryable Encryption range hypergraph sparsity factor int64_t sparsity; } mc_FLE2EncryptionPlaceholder_t; // `mc_FLE2EncryptionPlaceholder_t` inherits extended alignment from libbson. To dynamically allocate, use // aligned allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_FLE2EncryptionPlaceholder_t, BSON_ALIGNOF(mc_FLE2EncryptionPlaceholder_t) >= BSON_ALIGNOF(bson_iter_t)); void mc_FLE2EncryptionPlaceholder_init(mc_FLE2EncryptionPlaceholder_t *placeholder); bool mc_FLE2EncryptionPlaceholder_parse(mc_FLE2EncryptionPlaceholder_t *out, const bson_t *in, mongocrypt_status_t *status); void mc_FLE2EncryptionPlaceholder_cleanup(mc_FLE2EncryptionPlaceholder_t *placeholder); /* mc_validate_contention is used to check that contention is a valid * value. contention may come from the 'cm' field in FLE2EncryptionPlaceholder * or from mongocrypt_ctx_setopt_contention_factor. */ bool mc_validate_contention(int64_t contention, mongocrypt_status_t *status); /* mc_validate_sparsity is used to check that sparsity is a valid * value. */ bool mc_validate_sparsity(int64_t sparsity, mongocrypt_status_t *status); #endif /* MC_FLE2_ENCRYPTION_PLACEHOLDER_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-encryption-placeholder.c0000644000175100001660000004031514760300420022447 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include #include // SIZE_MAX #include "mc-fle2-encryption-placeholder-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt.h" #define CLIENT_ERR_PREFIXED_HELPER(Prefix, ErrorString, ...) CLIENT_ERR(Prefix ": " ErrorString, ##__VA_ARGS__) #define CLIENT_ERR_PREFIXED(ErrorString, ...) CLIENT_ERR_PREFIXED_HELPER(ERROR_PREFIX, ErrorString, ##__VA_ARGS__) // Common logic for testing field name, tracking duplication, and presence. #define IF_FIELD(Name) \ if (0 == strcmp(field, #Name)) { \ if (has_##Name) { \ CLIENT_ERR_PREFIXED("Duplicate field '" #Name "' in placeholder bson"); \ goto fail; \ } \ has_##Name = true; #define END_IF_FIELD \ continue; \ } #define CHECK_HAS(Name) \ if (!has_##Name) { \ CLIENT_ERR_PREFIXED("Missing field '" #Name "' in placeholder"); \ goto fail; \ } void mc_FLE2EncryptionPlaceholder_init(mc_FLE2EncryptionPlaceholder_t *placeholder) { memset(placeholder, 0, sizeof(mc_FLE2EncryptionPlaceholder_t)); } #define ERROR_PREFIX "Error parsing FLE2EncryptionPlaceholder" bool mc_FLE2EncryptionPlaceholder_parse(mc_FLE2EncryptionPlaceholder_t *out, const bson_t *in, mongocrypt_status_t *status) { bson_iter_t iter = {0}; bool has_t = false, has_a = false, has_v = false, has_cm = false; bool has_ki = false, has_ku = false; bool has_s = false; BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); mc_FLE2EncryptionPlaceholder_init(out); if (!bson_validate(in, BSON_VALIDATE_NONE, NULL) || !bson_iter_init(&iter, in)) { CLIENT_ERR_PREFIXED("invalid BSON"); return false; } while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); IF_FIELD(t) { int32_t type; if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("invalid marking, 't' must be an int32"); goto fail; } type = bson_iter_int32(&iter); if ((type != MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT) && (type != MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND)) { CLIENT_ERR_PREFIXED("invalid placeholder type value: %d", type); goto fail; } out->type = (mongocrypt_fle2_placeholder_type_t)type; } END_IF_FIELD IF_FIELD(a) { int32_t algorithm; if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("invalid marking, 'a' must be an int32"); goto fail; } algorithm = bson_iter_int32(&iter); if (algorithm != MONGOCRYPT_FLE2_ALGORITHM_UNINDEXED && algorithm != MONGOCRYPT_FLE2_ALGORITHM_EQUALITY && algorithm != MONGOCRYPT_FLE2_ALGORITHM_RANGE) { CLIENT_ERR_PREFIXED("invalid algorithm value: %d", algorithm); goto fail; } out->algorithm = (mongocrypt_fle2_encryption_algorithm_t)algorithm; } END_IF_FIELD IF_FIELD(ki) { if (!_mongocrypt_buffer_from_uuid_iter(&out->index_key_id, &iter)) { CLIENT_ERR_PREFIXED("index key id must be a UUID"); goto fail; } } END_IF_FIELD IF_FIELD(ku) { if (!_mongocrypt_buffer_from_uuid_iter(&out->user_key_id, &iter)) { CLIENT_ERR_PREFIXED("user key id must be a UUID"); goto fail; } } END_IF_FIELD IF_FIELD(v) { memcpy(&out->v_iter, &iter, sizeof(bson_iter_t)); } END_IF_FIELD IF_FIELD(cm) { if (!BSON_ITER_HOLDS_INT64(&iter)) { CLIENT_ERR_PREFIXED("invalid marking, 'cm' must be an int64"); goto fail; } out->maxContentionFactor = bson_iter_int64(&iter); if (!mc_validate_contention(out->maxContentionFactor, status)) { goto fail; } } END_IF_FIELD IF_FIELD(s) { if (!BSON_ITER_HOLDS_INT64(&iter)) { CLIENT_ERR_PREFIXED("invalid marking, 's' must be an int64"); goto fail; } out->sparsity = bson_iter_int64(&iter); if (!mc_validate_sparsity(out->sparsity, status)) { goto fail; } } END_IF_FIELD } CHECK_HAS(t) CHECK_HAS(a) CHECK_HAS(ki) CHECK_HAS(ku) CHECK_HAS(v) CHECK_HAS(cm) // Do not error if sparsity (s) is not present. // 's' was added in version 6.1 of query analysis (mongocryptd or mongo_crypt // shared library). 's' is not present in query analysis 6.0. return true; fail: mc_FLE2EncryptionPlaceholder_cleanup(out); return false; } void mc_FLE2EncryptionPlaceholder_cleanup(mc_FLE2EncryptionPlaceholder_t *placeholder) { BSON_ASSERT_PARAM(placeholder); _mongocrypt_buffer_cleanup(&placeholder->index_key_id); _mongocrypt_buffer_cleanup(&placeholder->user_key_id); mc_FLE2EncryptionPlaceholder_init(placeholder); } #undef ERROR_PREFIX #define ERROR_PREFIX "Error validating contention" bool mc_validate_contention(int64_t contention, mongocrypt_status_t *status) { if (contention < 0) { CLIENT_ERR_PREFIXED("contention must be non-negative, got: %" PRId64, contention); return false; } if (contention == INT64_MAX) { CLIENT_ERR_PREFIXED("contention must be < INT64_MAX, got: %" PRId64, contention); return false; } return true; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error validating sparsity" bool mc_validate_sparsity(int64_t sparsity, mongocrypt_status_t *status) { if (sparsity < 0) { CLIENT_ERR_PREFIXED("sparsity must be non-negative, got: %" PRId64, sparsity); return false; } // mc_getEdgesInt expects a size_t sparsity. if ((uint64_t)sparsity >= SIZE_MAX) { CLIENT_ERR_PREFIXED("sparsity must be < %zu, got: %" PRId64, SIZE_MAX, sparsity); return false; } return true; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error parsing FLE2RangeFindSpecEdgesInfo" static bool mc_FLE2RangeFindSpecEdgesInfo_parse(mc_FLE2RangeFindSpecEdgesInfo_t *out, const bson_iter_t *in, bool use_range_v2, mongocrypt_status_t *status) { bson_iter_t iter; bool has_lowerBound = false, has_lbIncluded = false, has_upperBound = false, has_ubIncluded = false, has_indexMin = false, has_indexMax = false, has_precision = false, has_trimFactor = false; BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); iter = *in; if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) { CLIENT_ERR_PREFIXED("must be an iterator to a document"); return false; } bson_iter_recurse(&iter, &iter); while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); IF_FIELD(lowerBound) { out->lowerBound = iter; } END_IF_FIELD IF_FIELD(lbIncluded) { if (!BSON_ITER_HOLDS_BOOL(&iter)) { CLIENT_ERR_PREFIXED("'lbIncluded' must be a bool"); goto fail; } out->lbIncluded = bson_iter_bool(&iter); } END_IF_FIELD IF_FIELD(upperBound) { out->upperBound = iter; } END_IF_FIELD IF_FIELD(ubIncluded) { if (!BSON_ITER_HOLDS_BOOL(&iter)) { CLIENT_ERR_PREFIXED("'ubIncluded' must be a bool"); goto fail; } out->ubIncluded = bson_iter_bool(&iter); } END_IF_FIELD IF_FIELD(indexMin) { out->indexMin = iter; } END_IF_FIELD IF_FIELD(indexMax) { out->indexMax = iter; } END_IF_FIELD IF_FIELD(precision) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("'precision' must be an int32"); goto fail; } int32_t val = bson_iter_int32(&iter); if (val < 0) { CLIENT_ERR_PREFIXED("'precision' must be non-negative"); goto fail; } out->precision = OPT_I32(val); } END_IF_FIELD IF_FIELD(trimFactor) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("'trimFactor' must be an int32"); goto fail; } int32_t val = bson_iter_int32(&iter); if (val < 0) { CLIENT_ERR_PREFIXED("'trimFactor' must be non-negative"); goto fail; } out->trimFactor = OPT_I32(val); } END_IF_FIELD } CHECK_HAS(lowerBound) CHECK_HAS(lbIncluded) CHECK_HAS(upperBound) CHECK_HAS(ubIncluded) CHECK_HAS(indexMin) CHECK_HAS(indexMax) // Do not error if precision is not present. Precision optional and only // applies to double/decimal128. if (!use_range_v2 && out->trimFactor.set) { CLIENT_ERR_PREFIXED("'trimFactor' is not supported for QE range v1"); return false; } return true; fail: return false; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error parsing FLE2RangeFindSpec" bool mc_FLE2RangeFindSpec_parse(mc_FLE2RangeFindSpec_t *out, const bson_iter_t *in, bool use_range_v2, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); bson_iter_t iter = *in; bool has_edgesInfo = false, has_payloadId = false, has_firstOperator = false, has_secondOperator = false; *out = (mc_FLE2RangeFindSpec_t){{{{0}}}}; if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) { CLIENT_ERR_PREFIXED("must be an iterator to a document"); return false; } bson_iter_recurse(&iter, &iter); while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); IF_FIELD(edgesInfo) { if (!mc_FLE2RangeFindSpecEdgesInfo_parse(&out->edgesInfo.value, &iter, use_range_v2, status)) { goto fail; } out->edgesInfo.set = true; } END_IF_FIELD IF_FIELD(payloadId) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("'payloadId' must be an int32"); goto fail; } out->payloadId = bson_iter_int32(&iter); } END_IF_FIELD IF_FIELD(firstOperator) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("'firstOperator' must be an int32"); goto fail; } const int32_t first_op = bson_iter_int32(&iter); if (first_op < FLE2RangeOperator_min_val || first_op > FLE2RangeOperator_max_val) { CLIENT_ERR_PREFIXED("'firstOperator' must be between %d and %d", FLE2RangeOperator_min_val, FLE2RangeOperator_max_val); goto fail; } out->firstOperator = (mc_FLE2RangeOperator_t)first_op; } END_IF_FIELD IF_FIELD(secondOperator) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("'secondOperator' must be an int32"); goto fail; } const int32_t second_op = bson_iter_int32(&iter); if (second_op < FLE2RangeOperator_min_val || second_op > FLE2RangeOperator_max_val) { CLIENT_ERR_PREFIXED("'secondOperator' must be between %d and %d", FLE2RangeOperator_min_val, FLE2RangeOperator_max_val); goto fail; } out->secondOperator = (mc_FLE2RangeOperator_t)second_op; } END_IF_FIELD } // edgesInfo is optional. Do not require it. CHECK_HAS(payloadId) CHECK_HAS(firstOperator) // secondOperator is optional. Do not require it. return true; fail: return false; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error parsing FLE2RangeInsertSpec" bool mc_FLE2RangeInsertSpec_parse(mc_FLE2RangeInsertSpec_t *out, const bson_iter_t *in, bool use_range_v2, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); *out = (mc_FLE2RangeInsertSpec_t){{0}}; bson_iter_t iter = *in; bool has_v = false, has_min = false, has_max = false, has_precision = false, has_trimFactor = false; if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) { CLIENT_ERR_PREFIXED("must be an iterator to a document"); return false; } bson_iter_recurse(&iter, &iter); while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); IF_FIELD(v) { out->v = iter; } END_IF_FIELD IF_FIELD(min) { out->min = iter; } END_IF_FIELD IF_FIELD(max) { out->max = iter; } END_IF_FIELD IF_FIELD(precision) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("'precision' must be an int32"); goto fail; } int32_t val = bson_iter_int32(&iter); if (val < 0) { CLIENT_ERR_PREFIXED("'precision' must be non-negative"); goto fail; } out->precision = OPT_I32(val); } END_IF_FIELD IF_FIELD(trimFactor) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("'trimFactor' must be an int32"); goto fail; } int32_t val = bson_iter_int32(&iter); if (val < 0) { CLIENT_ERR_PREFIXED("'trimFactor' must be non-negative"); goto fail; } out->trimFactor = OPT_I32(val); } END_IF_FIELD } CHECK_HAS(v) CHECK_HAS(min) CHECK_HAS(max) // Do not error if precision is not present. Precision optional and only // applies to double/decimal128. if (!use_range_v2 && out->trimFactor.set) { CLIENT_ERR_PREFIXED("'trimFactor' is not supported for QE range v1"); return false; } return true; fail: return false; } #undef ERROR_PREFIX mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-find-equality-payload-private-v2.h0000644000175100001660000000312714760300420024201 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE2_FIND_EQUALITY_PAYLOAD_PRIVATE_V2_H #define MC_FLE2_FIND_EQUALITY_PAYLOAD_PRIVATE_V2_H #include "mongocrypt-buffer-private.h" #include "mongocrypt-private.h" #include "mongocrypt.h" typedef struct { _mongocrypt_buffer_t edcDerivedToken; // d _mongocrypt_buffer_t escDerivedToken; // s _mongocrypt_buffer_t serverDerivedFromDataToken; // l int64_t maxContentionFactor; // cm } mc_FLE2FindEqualityPayloadV2_t; void mc_FLE2FindEqualityPayloadV2_init(mc_FLE2FindEqualityPayloadV2_t *payload); bool mc_FLE2FindEqualityPayloadV2_parse(mc_FLE2FindEqualityPayloadV2_t *out, const bson_t *in, mongocrypt_status_t *status); bool mc_FLE2FindEqualityPayloadV2_serialize(const mc_FLE2FindEqualityPayloadV2_t *payload, bson_t *out); void mc_FLE2FindEqualityPayloadV2_cleanup(mc_FLE2FindEqualityPayloadV2_t *payload); #endif /* MC_FLE2_FIND_EQUALITY_PAYLOAD_PRIVATE_V2_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-find-equality-payload-private.h0000644000175100001660000000301514760300420023650 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE2_FIND_EQUALITY_PAYLOAD_PRIVATE_H #define MC_FLE2_FIND_EQUALITY_PAYLOAD_PRIVATE_H #include "mongocrypt-buffer-private.h" #include "mongocrypt-private.h" #include "mongocrypt.h" typedef struct { _mongocrypt_buffer_t edcDerivedToken; // d _mongocrypt_buffer_t escDerivedToken; // s _mongocrypt_buffer_t eccDerivedToken; // c _mongocrypt_buffer_t serverEncryptionToken; // e int64_t maxContentionFactor; // cm } mc_FLE2FindEqualityPayload_t; void mc_FLE2FindEqualityPayload_init(mc_FLE2FindEqualityPayload_t *payload); bool mc_FLE2FindEqualityPayload_parse(mc_FLE2FindEqualityPayload_t *out, const bson_t *in, mongocrypt_status_t *status); bool mc_FLE2FindEqualityPayload_serialize(const mc_FLE2FindEqualityPayload_t *payload, bson_t *out); void mc_FLE2FindEqualityPayload_cleanup(mc_FLE2FindEqualityPayload_t *payload); #endif /* MC_FLE2_FIND_EQUALITY_PAYLOAD_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-find-equality-payload-v2.c0000644000175100001660000001603414760300420022525 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include #include "mc-fle2-find-equality-payload-private-v2.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt.h" void mc_FLE2FindEqualityPayloadV2_init(mc_FLE2FindEqualityPayloadV2_t *payload) { memset(payload, 0, sizeof(mc_FLE2FindEqualityPayloadV2_t)); } void mc_FLE2FindEqualityPayloadV2_cleanup(mc_FLE2FindEqualityPayloadV2_t *payload) { BSON_ASSERT_PARAM(payload); _mongocrypt_buffer_cleanup(&payload->edcDerivedToken); _mongocrypt_buffer_cleanup(&payload->escDerivedToken); _mongocrypt_buffer_cleanup(&payload->serverDerivedFromDataToken); } #define IF_FIELD(Name) \ if (0 == strcmp(field, #Name)) { \ if (has_##Name) { \ CLIENT_ERR("Duplicate field '" #Name "' in payload bson"); \ goto fail; \ } \ has_##Name = true; #define END_IF_FIELD \ continue; \ } #define PARSE_BINARY(Name, Dest) \ IF_FIELD(Name) { \ bson_subtype_t subtype; \ uint32_t len; \ const uint8_t *data; \ if (bson_iter_type(&iter) != BSON_TYPE_BINARY) { \ CLIENT_ERR("Field '" #Name "' expected to be bindata, got: %d", bson_iter_type(&iter)); \ goto fail; \ } \ bson_iter_binary(&iter, &subtype, &len, &data); \ if (subtype != BSON_SUBTYPE_BINARY) { \ CLIENT_ERR("Field '" #Name "' expected to be bindata subtype %d, got: %d", BSON_SUBTYPE_BINARY, subtype); \ goto fail; \ } \ if (!_mongocrypt_buffer_copy_from_binary_iter(&out->Dest, &iter)) { \ CLIENT_ERR("Unable to create mongocrypt buffer for BSON binary " \ "field in '" #Name "'"); \ goto fail; \ } \ } \ END_IF_FIELD #define CHECK_HAS(Name) \ if (!has_##Name) { \ CLIENT_ERR("Missing field '" #Name "' in payload"); \ goto fail; \ } bool mc_FLE2FindEqualityPayloadV2_parse(mc_FLE2FindEqualityPayloadV2_t *out, const bson_t *in, mongocrypt_status_t *status) { bson_iter_t iter; bool has_d = false, has_s = false, has_l = false, has_cm = false; BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); mc_FLE2FindEqualityPayloadV2_init(out); if (!bson_validate(in, BSON_VALIDATE_NONE, NULL) || !bson_iter_init(&iter, in)) { CLIENT_ERR("invalid BSON"); return false; } while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); PARSE_BINARY(d, edcDerivedToken) PARSE_BINARY(s, escDerivedToken) PARSE_BINARY(l, serverDerivedFromDataToken) IF_FIELD(cm) { if (!BSON_ITER_HOLDS_INT64(&iter)) { CLIENT_ERR("Field 'cm' expected to hold an int64"); goto fail; } out->maxContentionFactor = bson_iter_int64(&iter); } END_IF_FIELD } CHECK_HAS(d); CHECK_HAS(s); CHECK_HAS(l); CHECK_HAS(cm); return true; fail: mc_FLE2FindEqualityPayloadV2_cleanup(out); return false; } #define APPEND_BINDATA(name, value) \ if (!_mongocrypt_buffer_append(&(value), out, name, -1)) { \ return false; \ } bool mc_FLE2FindEqualityPayloadV2_serialize(const mc_FLE2FindEqualityPayloadV2_t *payload, bson_t *out) { BSON_ASSERT_PARAM(payload); APPEND_BINDATA("d", payload->edcDerivedToken); APPEND_BINDATA("s", payload->escDerivedToken); APPEND_BINDATA("l", payload->serverDerivedFromDataToken); if (!BSON_APPEND_INT64(out, "cm", payload->maxContentionFactor)) { return false; } return true; } #undef APPEND_BINDATA mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-find-equality-payload.c0000644000175100001660000001632014760300420022176 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include #include "mc-fle2-find-equality-payload-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt.h" void mc_FLE2FindEqualityPayload_init(mc_FLE2FindEqualityPayload_t *payload) { memset(payload, 0, sizeof(mc_FLE2FindEqualityPayload_t)); } void mc_FLE2FindEqualityPayload_cleanup(mc_FLE2FindEqualityPayload_t *payload) { BSON_ASSERT_PARAM(payload); _mongocrypt_buffer_cleanup(&payload->edcDerivedToken); _mongocrypt_buffer_cleanup(&payload->escDerivedToken); _mongocrypt_buffer_cleanup(&payload->eccDerivedToken); _mongocrypt_buffer_cleanup(&payload->serverEncryptionToken); } #define IF_FIELD(Name) \ if (0 == strcmp(field, #Name)) { \ if (has_##Name) { \ CLIENT_ERR("Duplicate field '" #Name "' in payload bson"); \ goto fail; \ } \ has_##Name = true; #define END_IF_FIELD \ continue; \ } #define PARSE_BINARY(Name, Dest) \ IF_FIELD(Name) { \ bson_subtype_t subtype; \ uint32_t len; \ const uint8_t *data; \ if (bson_iter_type(&iter) != BSON_TYPE_BINARY) { \ CLIENT_ERR("Field '" #Name "' expected to be bindata, got: %d", bson_iter_type(&iter)); \ goto fail; \ } \ bson_iter_binary(&iter, &subtype, &len, &data); \ if (subtype != BSON_SUBTYPE_BINARY) { \ CLIENT_ERR("Field '" #Name "' expected to be bindata subtype %d, got: %d", BSON_SUBTYPE_BINARY, subtype); \ goto fail; \ } \ if (!_mongocrypt_buffer_copy_from_binary_iter(&out->Dest, &iter)) { \ CLIENT_ERR("Unable to create mongocrypt buffer for BSON binary " \ "field in '" #Name "'"); \ goto fail; \ } \ } \ END_IF_FIELD #define CHECK_HAS(Name) \ if (!has_##Name) { \ CLIENT_ERR("Missing field '" #Name "' in payload"); \ goto fail; \ } bool mc_FLE2FindEqualityPayload_parse(mc_FLE2FindEqualityPayload_t *out, const bson_t *in, mongocrypt_status_t *status) { bson_iter_t iter; bool has_d = false, has_s = false, has_c = false, has_e = false, has_cm = false; BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); mc_FLE2FindEqualityPayload_init(out); if (!bson_validate(in, BSON_VALIDATE_NONE, NULL) || !bson_iter_init(&iter, in)) { CLIENT_ERR("invalid BSON"); return false; } while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); PARSE_BINARY(d, edcDerivedToken) PARSE_BINARY(s, escDerivedToken) PARSE_BINARY(c, eccDerivedToken) PARSE_BINARY(e, serverEncryptionToken) IF_FIELD(cm) { if (!BSON_ITER_HOLDS_INT64(&iter)) { CLIENT_ERR("Field 'cm' expected to hold an int64"); goto fail; } out->maxContentionFactor = bson_iter_int64(&iter); } END_IF_FIELD } CHECK_HAS(d); CHECK_HAS(s); CHECK_HAS(c); CHECK_HAS(e); CHECK_HAS(cm); return true; fail: mc_FLE2FindEqualityPayload_cleanup(out); return false; } #define PAYLOAD_APPEND_BINDATA(name, value) \ if (!_mongocrypt_buffer_append(&(value), out, name, -1)) { \ return false; \ } bool mc_FLE2FindEqualityPayload_serialize(const mc_FLE2FindEqualityPayload_t *payload, bson_t *out) { BSON_ASSERT_PARAM(payload); PAYLOAD_APPEND_BINDATA("d", payload->edcDerivedToken); PAYLOAD_APPEND_BINDATA("s", payload->escDerivedToken); PAYLOAD_APPEND_BINDATA("c", payload->eccDerivedToken); PAYLOAD_APPEND_BINDATA("e", payload->serverEncryptionToken); if (!BSON_APPEND_INT64(out, "cm", payload->maxContentionFactor)) { return false; } return true; } #undef PAYLOAD_APPEND_BINDATA mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-find-range-payload-private-v2.h0000644000175100001660000000757014760300420023446 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE2_FIND_RANGE_PAYLOAD_PRIVATE_V2_H #define MC_FLE2_FIND_RANGE_PAYLOAD_PRIVATE_V2_H #include "mongocrypt-buffer-private.h" #include "mongocrypt-private.h" #include "mongocrypt.h" #include "mc-array-private.h" #include "mc-fle2-range-operator-private.h" #include "mc-optional-private.h" /** FLE2FindRangePayloadEdgesInfoV2 represents the token information for a range * find query. It is encoded inside an FLE2FindRangePayloadV2. */ typedef struct { mc_array_t edgeFindTokenSetArray; // g int64_t maxContentionFactor; // cm } mc_FLE2FindRangePayloadEdgesInfoV2_t; /** * FLE2FindRangePayloadV2 represents an FLE2 payload of a range indexed field to * query. It is created client side. * * FLE2FindRangePayloadV2 has the following data layout: * * struct { * uint8_t fle_blob_subtype = 13; * uint8_t bson[]; * } FLE2FindRangePayloadV2; * * bson is a BSON document of this form: * payload: * g: array // Array of Edges * cm: // Queryable Encryption max counter * payloadId: // Payload ID. * firstOperator: * secondOperator: * sp: optional // Sparsity. * pn: optional // Precision. * tf: optional // Trim Factor. * mn: optional // Index Min. * mx: optional // Index Max. */ typedef struct { struct { mc_FLE2FindRangePayloadEdgesInfoV2_t value; bool set; } payload; // payloadId Id of payload - must be paired with another payload. int32_t payloadId; // firstOperator represents the first query operator for which this payload // was generated. mc_FLE2RangeOperator_t firstOperator; // secondOperator represents the second query operator for which this payload // was generated. Only populated for two-sided ranges. It is 0 if unset. mc_FLE2RangeOperator_t secondOperator; mc_optional_int64_t sparsity; // sp mc_optional_int32_t precision; // pn mc_optional_int32_t trimFactor; // tf bson_value_t indexMin; // mn bson_value_t indexMax; // mx } mc_FLE2FindRangePayloadV2_t; // `mc_FLE2FindRangePayloadV2_t` inherits extended alignment from libbson. To dynamically allocate, use aligned // allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_FLE2FindRangePayloadV2_t, BSON_ALIGNOF(mc_FLE2FindRangePayloadV2_t) >= BSON_ALIGNOF(bson_value_t)); /** * EdgeFindTokenSetV2 is the following BSON document: * d: // EDCDerivedFromDataTokenAndContentionFactor * s: // ESCDerivedFromDataTokenAndContentionFactor * l: // ServerDerivedFromDataToken * * Instances of mc_EdgeFindTokenSetV2_t are expected to be owned by * mc_FLE2FindRangePayloadV2_t and are freed in * mc_FLE2FindRangePayloadV2_cleanup. */ typedef struct { _mongocrypt_buffer_t edcDerivedToken; // d _mongocrypt_buffer_t escDerivedToken; // s _mongocrypt_buffer_t serverDerivedFromDataToken; // l } mc_EdgeFindTokenSetV2_t; void mc_FLE2FindRangePayloadV2_init(mc_FLE2FindRangePayloadV2_t *payload); bool mc_FLE2FindRangePayloadV2_serialize(const mc_FLE2FindRangePayloadV2_t *payload, bson_t *out, bool use_range_v2); void mc_FLE2FindRangePayloadV2_cleanup(mc_FLE2FindRangePayloadV2_t *payload); #endif /* MC_FLE2_FIND_RANGE_PAYLOAD_PRIVATE_V2_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-find-range-payload-private.h0000644000175100001660000000634614760300420023121 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE2_FIND_RANGE_PAYLOAD_PRIVATE_H #define MC_FLE2_FIND_RANGE_PAYLOAD_PRIVATE_H #include "mongocrypt-buffer-private.h" #include "mongocrypt-private.h" #include "mongocrypt.h" #include "mc-array-private.h" #include "mc-fle2-range-operator-private.h" /** FLE2FindRangePayloadEdgesInfo represents the token information for a range * find query. It is encoded inside an FLE2FindRangePayload. See * https://github.com/mongodb/mongo/blob/master/src/mongo/crypto/fle_field_schema.idl * for the representation in the MongoDB server. */ typedef struct { mc_array_t edgeFindTokenSetArray; // g _mongocrypt_buffer_t serverEncryptionToken; // e int64_t maxContentionFactor; // cm } mc_FLE2FindRangePayloadEdgesInfo_t; /** * FLE2FindRangePayload represents an FLE2 payload of a range indexed field to * query. It is created client side. * * FLE2FindRangePayload has the following data layout: * * struct { * uint8_t fle_blob_subtype = 10; * uint8_t bson[]; * } FLE2FindRangePayload; * * bson is a BSON document of this form: * g: array // Array of Edges * e: // ServerDataEncryptionLevel1Token * cm: // Queryable Encryption max contentionFactor */ typedef struct { struct { mc_FLE2FindRangePayloadEdgesInfo_t value; bool set; } payload; // payloadId Id of payload - must be paired with another payload. int32_t payloadId; // firstOperator represents the first query operator for which this payload // was generated. mc_FLE2RangeOperator_t firstOperator; // secondOperator represents the second query operator for which this payload // was generated. Only populated for two-sided ranges. It is 0 if unset. mc_FLE2RangeOperator_t secondOperator; } mc_FLE2FindRangePayload_t; /** * EdgeFindTokenSet is the following BSON document: * d: // EDCDerivedFromDataTokenAndContentionFactor * s: // ESCDerivedFromDataTokenAndContentionFactor * c: // ECCDerivedFromDataTokenAndContentionFactor * * Instances of mc_EdgeFindTokenSet_t are expected to be owned by * mc_FLE2FindRangePayload_t and are freed in * mc_FLE2FindRangePayload_cleanup. */ typedef struct { _mongocrypt_buffer_t edcDerivedToken; // d _mongocrypt_buffer_t escDerivedToken; // s _mongocrypt_buffer_t eccDerivedToken; // c } mc_EdgeFindTokenSet_t; void mc_FLE2FindRangePayload_init(mc_FLE2FindRangePayload_t *payload); bool mc_FLE2FindRangePayload_serialize(const mc_FLE2FindRangePayload_t *payload, bson_t *out); void mc_FLE2FindRangePayload_cleanup(mc_FLE2FindRangePayload_t *payload); #endif /* MC_FLE2_FIND_RANGE_PAYLOAD_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-find-range-payload-v2.c0000644000175100001660000001366314760300420021771 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include #include "mc-fle2-find-range-payload-private-v2.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt.h" void mc_FLE2FindRangePayloadV2_init(mc_FLE2FindRangePayloadV2_t *payload) { BSON_ASSERT_PARAM(payload); *payload = (mc_FLE2FindRangePayloadV2_t){{{{0}}}}; _mc_array_init(&payload->payload.value.edgeFindTokenSetArray, sizeof(mc_EdgeFindTokenSetV2_t)); } static void mc_EdgeFindTokenSetV2_cleanup(mc_EdgeFindTokenSetV2_t *etc) { if (!etc) { return; } _mongocrypt_buffer_cleanup(&etc->edcDerivedToken); _mongocrypt_buffer_cleanup(&etc->escDerivedToken); _mongocrypt_buffer_cleanup(&etc->serverDerivedFromDataToken); } void mc_FLE2FindRangePayloadV2_cleanup(mc_FLE2FindRangePayloadV2_t *payload) { if (!payload) { return; } // Free all EdgeFindTokenSet entries. for (size_t i = 0; i < payload->payload.value.edgeFindTokenSetArray.len; i++) { mc_EdgeFindTokenSetV2_t entry = _mc_array_index(&payload->payload.value.edgeFindTokenSetArray, mc_EdgeFindTokenSetV2_t, i); mc_EdgeFindTokenSetV2_cleanup(&entry); } _mc_array_destroy(&payload->payload.value.edgeFindTokenSetArray); } #define APPEND_BINDATA(out, name, value) \ if (!_mongocrypt_buffer_append(&(value), out, name, -1)) { \ return false; \ } bool mc_FLE2FindRangePayloadV2_serialize(const mc_FLE2FindRangePayloadV2_t *payload, bson_t *out, bool use_range_v2) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(payload); // Append "payload" if this is not a stub. if (payload->payload.set) { bson_t payload_bson; if (!BSON_APPEND_DOCUMENT_BEGIN(out, "payload", &payload_bson)) { return false; } // Append "payload.g" array of EdgeTokenSets. bson_t g_bson; if (!BSON_APPEND_ARRAY_BEGIN(&payload_bson, "g", &g_bson)) { return false; } uint32_t g_index = 0; for (size_t i = 0; i < payload->payload.value.edgeFindTokenSetArray.len; i++) { mc_EdgeFindTokenSetV2_t etc = _mc_array_index(&payload->payload.value.edgeFindTokenSetArray, mc_EdgeFindTokenSetV2_t, i); bson_t etc_bson; const char *g_index_string; char storage[16]; bson_uint32_to_string(g_index, &g_index_string, storage, sizeof(storage)); if (!BSON_APPEND_DOCUMENT_BEGIN(&g_bson, g_index_string, &etc_bson)) { return false; } etc.edcDerivedToken.subtype = BSON_SUBTYPE_BINARY; etc.escDerivedToken.subtype = BSON_SUBTYPE_BINARY; etc.serverDerivedFromDataToken.subtype = BSON_SUBTYPE_BINARY; APPEND_BINDATA(&etc_bson, "d", etc.edcDerivedToken); APPEND_BINDATA(&etc_bson, "s", etc.escDerivedToken); APPEND_BINDATA(&etc_bson, "l", etc.serverDerivedFromDataToken); if (!bson_append_document_end(&g_bson, &etc_bson)) { return false; } if (g_index == UINT32_MAX) { break; } g_index++; } if (!bson_append_array_end(&payload_bson, &g_bson)) { return false; } // Append "payload.cm". if (!BSON_APPEND_INT64(&payload_bson, "cm", payload->payload.value.maxContentionFactor)) { return false; } if (!bson_append_document_end(out, &payload_bson)) { return false; } } // Append "payloadId" if (!BSON_APPEND_INT32(out, "payloadId", payload->payloadId)) { return false; } // Append "firstOperator". if (!BSON_APPEND_INT32(out, "firstOperator", payload->firstOperator)) { return false; } // Append "secondOperator" if present. if (payload->secondOperator != FLE2RangeOperator_kNone && !BSON_APPEND_INT32(out, "secondOperator", payload->secondOperator)) { return false; } if (use_range_v2) { // Encode parameters that were used to generate the mincover. // The crypto parameters are all optionally set. Find payloads may come in pairs (a lower and upper bound). // One of the pair includes the mincover. The other payload was not generated with crypto parameters. if (payload->sparsity.set) { if (!BSON_APPEND_INT64(out, "sp", payload->sparsity.value)) { return false; } } if (payload->precision.set) { if (!BSON_APPEND_INT32(out, "pn", payload->precision.value)) { return false; } } if (payload->trimFactor.set) { if (!BSON_APPEND_INT32(out, "tf", payload->trimFactor.value)) { return false; } } if (payload->indexMin.value_type != BSON_TYPE_EOD) { if (!BSON_APPEND_VALUE(out, "mn", &payload->indexMin)) { return false; } } if (payload->indexMax.value_type != BSON_TYPE_EOD) { if (!BSON_APPEND_VALUE(out, "mx", &payload->indexMax)) { return false; } } } return true; } #undef APPEND_BINDATA mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-find-range-payload.c0000644000175100001660000001154614760300420021442 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include #include "mc-fle2-find-range-payload-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt.h" void mc_FLE2FindRangePayload_init(mc_FLE2FindRangePayload_t *payload) { BSON_ASSERT_PARAM(payload); *payload = (mc_FLE2FindRangePayload_t){{{{0}}}}; _mc_array_init(&payload->payload.value.edgeFindTokenSetArray, sizeof(mc_EdgeFindTokenSet_t)); } static void mc_EdgeFindTokenSet_cleanup(mc_EdgeFindTokenSet_t *etc) { if (!etc) { return; } _mongocrypt_buffer_cleanup(&etc->edcDerivedToken); _mongocrypt_buffer_cleanup(&etc->escDerivedToken); _mongocrypt_buffer_cleanup(&etc->eccDerivedToken); } void mc_FLE2FindRangePayload_cleanup(mc_FLE2FindRangePayload_t *payload) { if (!payload) { return; } _mongocrypt_buffer_cleanup(&payload->payload.value.serverEncryptionToken); // Free all EdgeFindTokenSet entries. for (size_t i = 0; i < payload->payload.value.edgeFindTokenSetArray.len; i++) { mc_EdgeFindTokenSet_t entry = _mc_array_index(&payload->payload.value.edgeFindTokenSetArray, mc_EdgeFindTokenSet_t, i); mc_EdgeFindTokenSet_cleanup(&entry); } _mc_array_destroy(&payload->payload.value.edgeFindTokenSetArray); } #define APPEND_BINDATA(out, name, value) \ if (!_mongocrypt_buffer_append(&(value), out, name, -1)) { \ return false; \ } bool mc_FLE2FindRangePayload_serialize(const mc_FLE2FindRangePayload_t *payload, bson_t *out) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(payload); // Append "payload" if this is not a stub. if (payload->payload.set) { bson_t payload_bson; if (!BSON_APPEND_DOCUMENT_BEGIN(out, "payload", &payload_bson)) { return false; } // Append "payload.g" array of EdgeTokenSets. bson_t g_bson; if (!BSON_APPEND_ARRAY_BEGIN(&payload_bson, "g", &g_bson)) { return false; } uint32_t g_index = 0; for (size_t i = 0; i < payload->payload.value.edgeFindTokenSetArray.len; i++) { mc_EdgeFindTokenSet_t etc = _mc_array_index(&payload->payload.value.edgeFindTokenSetArray, mc_EdgeFindTokenSet_t, i); bson_t etc_bson; const char *g_index_string; char storage[16]; bson_uint32_to_string(g_index, &g_index_string, storage, sizeof(storage)); if (!BSON_APPEND_DOCUMENT_BEGIN(&g_bson, g_index_string, &etc_bson)) { return false; } etc.edcDerivedToken.subtype = BSON_SUBTYPE_BINARY; etc.escDerivedToken.subtype = BSON_SUBTYPE_BINARY; etc.eccDerivedToken.subtype = BSON_SUBTYPE_BINARY; APPEND_BINDATA(&etc_bson, "d", etc.edcDerivedToken); APPEND_BINDATA(&etc_bson, "s", etc.escDerivedToken); APPEND_BINDATA(&etc_bson, "c", etc.eccDerivedToken); if (!bson_append_document_end(&g_bson, &etc_bson)) { return false; } if (g_index == UINT32_MAX) { break; } g_index++; } if (!bson_append_array_end(&payload_bson, &g_bson)) { return false; } // Append "payload.e" and "payload.cm". APPEND_BINDATA(&payload_bson, "e", payload->payload.value.serverEncryptionToken); if (!BSON_APPEND_INT64(&payload_bson, "cm", payload->payload.value.maxContentionFactor)) { return false; } if (!bson_append_document_end(out, &payload_bson)) { return false; } } // Append "payloadId" if (!BSON_APPEND_INT32(out, "payloadId", payload->payloadId)) { return false; } // Append "firstOperator". if (!BSON_APPEND_INT32(out, "firstOperator", payload->firstOperator)) { return false; } // Append "secondOperator" if present. if (payload->secondOperator != FLE2RangeOperator_kNone && !BSON_APPEND_INT32(out, "secondOperator", payload->secondOperator)) { return false; } return true; } #undef APPEND_BINDATA mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-insert-update-payload-private-v2.h0000644000175100001660000001307614760300420024216 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE2_INSERT_UPDATE_PAYLOAD_PRIVATE_V2_H #define MC_FLE2_INSERT_UPDATE_PAYLOAD_PRIVATE_V2_H #include #include "mc-array-private.h" #include "mc-optional-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt-private.h" #include "mongocrypt.h" /** * FLE2InsertUpdatePayloadV2 represents an FLE2 payload of an indexed field to * insert or update. It is created client side. * * FLE2InsertUpdatePayloadV2 has the following data layout: * * struct { * uint8_t fle_blob_subtype = 11; * uint8_t bson[]; * } FLE2InsertUpdatePayloadV2; * * bson is a BSON document of this form: * d: // EDCDerivedFromDataTokenAndContentionFactor * s: // ESCDerivedFromDataTokenAndContentionFactor * p: // Encrypted Tokens * u: // Index KeyId * t: // Encrypted type * v: // Encrypted value * e: // ServerDataEncryptionLevel1Token * l: // ServerDerivedFromDataToken * k: // Randomly sampled contention factor value * g: array // Array of Edges. Only included for range payloads. * sp: optional // Sparsity. Only included for range payloads. * pn: optional // Precision. Only included for range payloads. * tf: optional // Trim Factor. Only included for range payloads. * mn: optional // Index Min. Only included for range payloads. * mx: optional // Index Max. Only included for range payloads. * * p is the result of: * Encrypt( * key=ECOCToken, * plaintext=( * ESCDerivedFromDataTokenAndContentionFactor) * ) * * v is the result of: * UserKeyId || EncryptAEAD( * key=UserKey, * plaintext=value * associated_data=UserKeyId) */ typedef struct { _mongocrypt_buffer_t edcDerivedToken; // d _mongocrypt_buffer_t escDerivedToken; // s _mongocrypt_buffer_t encryptedTokens; // p _mongocrypt_buffer_t indexKeyId; // u bson_type_t valueType; // t _mongocrypt_buffer_t value; // v _mongocrypt_buffer_t serverEncryptionToken; // e _mongocrypt_buffer_t serverDerivedFromDataToken; // l int64_t contentionFactor; // k mc_array_t edgeTokenSetArray; // g mc_optional_int64_t sparsity; // sp mc_optional_int32_t precision; // pn mc_optional_int32_t trimFactor; // tf bson_value_t indexMin; // mn bson_value_t indexMax; // mx _mongocrypt_buffer_t plaintext; _mongocrypt_buffer_t userKeyId; } mc_FLE2InsertUpdatePayloadV2_t; // `mc_FLE2InsertUpdatePayloadV2_t` inherits extended alignment from libbson. To dynamically allocate, use // aligned allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_FLE2InsertUpdatePayloadV2_t, BSON_ALIGNOF(mc_FLE2InsertUpdatePayloadV2_t) >= BSON_ALIGNOF(bson_value_t)); /** * EdgeTokenSetV2 is the following BSON document: * d: // EDCDerivedFromDataTokenAndContentionFactor * s: // ESCDerivedFromDataTokenAndContentionFactor * l: // ServerDerivedFromDataToken * p: // Encrypted Tokens * * Instances of mc_EdgeTokenSetV2_t are expected to be owned by * mc_FLE2InsertUpdatePayloadV2_t and are freed in * mc_FLE2InsertUpdatePayloadV2_cleanup. */ typedef struct { _mongocrypt_buffer_t edcDerivedToken; // d _mongocrypt_buffer_t escDerivedToken; // s _mongocrypt_buffer_t serverDerivedFromDataToken; // l _mongocrypt_buffer_t encryptedTokens; // p } mc_EdgeTokenSetV2_t; void mc_FLE2InsertUpdatePayloadV2_init(mc_FLE2InsertUpdatePayloadV2_t *payload); bool mc_FLE2InsertUpdatePayloadV2_parse(mc_FLE2InsertUpdatePayloadV2_t *out, const _mongocrypt_buffer_t *in, mongocrypt_status_t *status); /* mc_FLE2InsertUpdatePayloadV2_decrypt decrypts ciphertext. * Returns NULL and sets @status on error. It is an error to call before * mc_FLE2InsertUpdatePayloadV2_parse. */ const _mongocrypt_buffer_t *mc_FLE2InsertUpdatePayloadV2_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2InsertUpdatePayloadV2_t *iup, const _mongocrypt_buffer_t *user_key, mongocrypt_status_t *status); bool mc_FLE2InsertUpdatePayloadV2_serialize(const mc_FLE2InsertUpdatePayloadV2_t *payload, bson_t *out); bool mc_FLE2InsertUpdatePayloadV2_serializeForRange(const mc_FLE2InsertUpdatePayloadV2_t *payload, bson_t *out, bool use_range_v2); void mc_FLE2InsertUpdatePayloadV2_cleanup(mc_FLE2InsertUpdatePayloadV2_t *payload); #endif /* MC_FLE2_INSERT_UPDATE_PAYLOAD_PRIVATE_V2_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-insert-update-payload-private.h0000644000175100001660000001040214760300420023657 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE2_INSERT_UPDATE_PAYLOAD_PRIVATE_H #define MC_FLE2_INSERT_UPDATE_PAYLOAD_PRIVATE_H #include #include "mc-array-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt-private.h" #include "mongocrypt.h" /** * FLE2InsertUpdatePayload represents an FLE2 payload of an indexed field to * insert or update. It is created client side. * * FLE2InsertUpdatePayload has the following data layout: * * struct { * uint8_t fle_blob_subtype = 4; * uint8_t bson[]; * } FLE2InsertUpdatePayload; * * bson is a BSON document of this form: * d: // EDCDerivedFromDataTokenAndContentionFactor * s: // ESCDerivedFromDataTokenAndContentionFactor * c: // ECCDerivedFromDataTokenAndContentionFactor * p: // Encrypted Tokens * u: // Index KeyId * t: // Encrypted type * v: // Encrypted value * e: // ServerDataEncryptionLevel1Token * g: array // Array of Edges * * p is the result of: * Encrypt( * key=ECOCToken, * plaintext=( * ESCDerivedFromDataTokenAndContentionFactor || * ECCDerivedFromDataTokenAndContentionFactor) * ) * * v is the result of: * UserKeyId || EncryptAEAD( * key=UserKey, * plaintext=value * associated_data=UserKeyId) */ typedef struct { _mongocrypt_buffer_t edcDerivedToken; // d _mongocrypt_buffer_t escDerivedToken; // s _mongocrypt_buffer_t eccDerivedToken; // c _mongocrypt_buffer_t encryptedTokens; // p _mongocrypt_buffer_t indexKeyId; // u bson_type_t valueType; // t _mongocrypt_buffer_t value; // v _mongocrypt_buffer_t serverEncryptionToken; // e mc_array_t edgeTokenSetArray; // g _mongocrypt_buffer_t plaintext; _mongocrypt_buffer_t userKeyId; } mc_FLE2InsertUpdatePayload_t; /** * EdgeTokenSet is the following BSON document: * d: // EDCDerivedFromDataTokenAndContentionFactor * s: // ESCDerivedFromDataTokenAndContentionFactor * c: // ECCDerivedFromDataTokenAndContentionFactor * p: // Encrypted Tokens * * Instances of mc_EdgeTokenSet_t are expected to be owned by * mc_FLE2InsertUpdatePayload_t and are freed in * mc_FLE2InsertUpdatePayload_cleanup. */ typedef struct { _mongocrypt_buffer_t edcDerivedToken; // d _mongocrypt_buffer_t escDerivedToken; // s _mongocrypt_buffer_t eccDerivedToken; // c _mongocrypt_buffer_t encryptedTokens; // p } mc_EdgeTokenSet_t; void mc_FLE2InsertUpdatePayload_init(mc_FLE2InsertUpdatePayload_t *payload); bool mc_FLE2InsertUpdatePayload_parse(mc_FLE2InsertUpdatePayload_t *out, const _mongocrypt_buffer_t *in, mongocrypt_status_t *status); /* mc_FLE2InsertUpdatePayload_decrypt decrypts ciphertext. * Returns NULL and sets @status on error. It is an error to call before * mc_FLE2InsertUpdatePayload_parse. */ const _mongocrypt_buffer_t *mc_FLE2InsertUpdatePayload_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2InsertUpdatePayload_t *iup, const _mongocrypt_buffer_t *user_key, mongocrypt_status_t *status); bool mc_FLE2InsertUpdatePayload_serialize(const mc_FLE2InsertUpdatePayload_t *payload, bson_t *out); bool mc_FLE2InsertUpdatePayload_serializeForRange(const mc_FLE2InsertUpdatePayload_t *payload, bson_t *out); void mc_FLE2InsertUpdatePayload_cleanup(mc_FLE2InsertUpdatePayload_t *payload); #endif /* MC_FLE2_INSERT_UPDATE_PAYLOAD_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-insert-update-payload-v2.c0000644000175100001660000004006414760300420022536 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include #include "mc-fle2-insert-update-payload-private-v2.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt-util-private.h" // mc_bson_type_to_string #include "mongocrypt.h" void mc_FLE2InsertUpdatePayloadV2_init(mc_FLE2InsertUpdatePayloadV2_t *payload) { BSON_ASSERT_PARAM(payload); memset(payload, 0, sizeof(mc_FLE2InsertUpdatePayloadV2_t)); _mc_array_init(&payload->edgeTokenSetArray, sizeof(mc_EdgeTokenSetV2_t)); } static void mc_EdgeTokenSetV2_cleanup(mc_EdgeTokenSetV2_t *etc) { BSON_ASSERT_PARAM(etc); _mongocrypt_buffer_cleanup(&etc->edcDerivedToken); _mongocrypt_buffer_cleanup(&etc->escDerivedToken); _mongocrypt_buffer_cleanup(&etc->serverDerivedFromDataToken); _mongocrypt_buffer_cleanup(&etc->encryptedTokens); } void mc_FLE2InsertUpdatePayloadV2_cleanup(mc_FLE2InsertUpdatePayloadV2_t *payload) { BSON_ASSERT_PARAM(payload); _mongocrypt_buffer_cleanup(&payload->edcDerivedToken); _mongocrypt_buffer_cleanup(&payload->escDerivedToken); _mongocrypt_buffer_cleanup(&payload->encryptedTokens); _mongocrypt_buffer_cleanup(&payload->indexKeyId); _mongocrypt_buffer_cleanup(&payload->value); _mongocrypt_buffer_cleanup(&payload->serverEncryptionToken); _mongocrypt_buffer_cleanup(&payload->serverDerivedFromDataToken); _mongocrypt_buffer_cleanup(&payload->plaintext); // Free all EdgeTokenSet entries. for (size_t i = 0; i < payload->edgeTokenSetArray.len; i++) { mc_EdgeTokenSetV2_t entry = _mc_array_index(&payload->edgeTokenSetArray, mc_EdgeTokenSetV2_t, i); mc_EdgeTokenSetV2_cleanup(&entry); } _mc_array_destroy(&payload->edgeTokenSetArray); bson_value_destroy(&payload->indexMin); bson_value_destroy(&payload->indexMax); } #define IF_FIELD(Name) \ if (0 == strcmp(field, #Name)) { \ if (has_##Name) { \ CLIENT_ERR("Duplicate field '" #Name "' in payload bson"); \ goto fail; \ } \ has_##Name = true; #define END_IF_FIELD \ continue; \ } #define PARSE_BINDATA(Name, Type, Dest) \ IF_FIELD(Name) { \ bson_subtype_t subtype; \ uint32_t len; \ const uint8_t *data; \ if (bson_iter_type(&iter) != BSON_TYPE_BINARY) { \ CLIENT_ERR("Field '" #Name "' expected to be bindata, got: %d", bson_iter_type(&iter)); \ goto fail; \ } \ bson_iter_binary(&iter, &subtype, &len, &data); \ if (subtype != Type) { \ CLIENT_ERR("Field '" #Name "' expected to be bindata subtype %d, got: %d", Type, subtype); \ goto fail; \ } \ if (!_mongocrypt_buffer_copy_from_binary_iter(&out->Dest, &iter)) { \ CLIENT_ERR("Unable to create mongocrypt buffer for BSON binary " \ "field in '" #Name "'"); \ goto fail; \ } \ } \ END_IF_FIELD #define PARSE_BINARY(Name, Dest) PARSE_BINDATA(Name, BSON_SUBTYPE_BINARY, Dest) #define CHECK_HAS(Name) \ if (!has_##Name) { \ CLIENT_ERR("Missing field '" #Name "' in payload"); \ goto fail; \ } bool mc_FLE2InsertUpdatePayloadV2_parse(mc_FLE2InsertUpdatePayloadV2_t *out, const _mongocrypt_buffer_t *in, mongocrypt_status_t *status) { bson_iter_t iter; bool has_d = false, has_s = false, has_p = false; bool has_u = false, has_t = false, has_v = false; bool has_e = false, has_l = false, has_k = false; bool has_sp = false, has_pn = false, has_tf = false, has_mn = false, has_mx = false; bson_t in_bson; BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); if (in->len < 1) { CLIENT_ERR("FLE2InsertUpdatePayloadV2_parse got too short input"); return false; } if (!bson_init_static(&in_bson, in->data + 1, in->len - 1)) { CLIENT_ERR("FLE2InsertUpdatePayloadV2_parse got invalid BSON"); return false; } if (!bson_validate(&in_bson, BSON_VALIDATE_NONE, NULL) || !bson_iter_init(&iter, &in_bson)) { CLIENT_ERR("invalid BSON"); return false; } while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); PARSE_BINARY(d, edcDerivedToken) PARSE_BINARY(s, escDerivedToken) PARSE_BINARY(p, encryptedTokens) PARSE_BINDATA(u, BSON_SUBTYPE_UUID, indexKeyId) IF_FIELD(t) { int32_t type = bson_iter_int32(&iter); if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR("Field 't' expected to hold an int32"); goto fail; } if ((type < 0) || (type > 0xFF)) { CLIENT_ERR("Field 't' must be a valid BSON type, got: %d", type); goto fail; } out->valueType = (bson_type_t)type; } END_IF_FIELD IF_FIELD(k) { int64_t contention = bson_iter_int64(&iter); if (!BSON_ITER_HOLDS_INT64(&iter)) { CLIENT_ERR("Field 'k' expected to hold an int64"); goto fail; } if ((contention < 0)) { CLIENT_ERR("Field 'k' must be non-negative, got: %" PRId64, contention); goto fail; } out->contentionFactor = contention; } END_IF_FIELD PARSE_BINARY(v, value) PARSE_BINARY(e, serverEncryptionToken) PARSE_BINARY(l, serverDerivedFromDataToken) IF_FIELD(sp) { if (!BSON_ITER_HOLDS_INT64(&iter)) { CLIENT_ERR("Field 'sp' expected to hold an int64, got: %s", mc_bson_type_to_string(bson_iter_type(&iter))); goto fail; } int64_t sparsity = bson_iter_int64(&iter); out->sparsity = OPT_I64(sparsity); } END_IF_FIELD IF_FIELD(pn) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR("Field 'pn' expected to hold an int32, got: %s", mc_bson_type_to_string(bson_iter_type(&iter))); goto fail; } int32_t precision = bson_iter_int32(&iter); if (precision < 0) { CLIENT_ERR("Field 'pn' must be non-negative, got: %" PRId32, precision); goto fail; } out->precision = OPT_I32(precision); } END_IF_FIELD IF_FIELD(tf) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR("Field 'tf' expected to hold an int32, got: %s", mc_bson_type_to_string(bson_iter_type(&iter))); goto fail; } int32_t trimFactor = bson_iter_int32(&iter); if (trimFactor < 0) { CLIENT_ERR("Field 'tf' must be non-negative, got: %" PRId32, trimFactor); goto fail; } out->trimFactor = OPT_I32(trimFactor); } END_IF_FIELD IF_FIELD(mn) { bson_value_copy(bson_iter_value(&iter), &out->indexMin); } END_IF_FIELD IF_FIELD(mx) { bson_value_copy(bson_iter_value(&iter), &out->indexMax); } END_IF_FIELD } CHECK_HAS(d); CHECK_HAS(s); CHECK_HAS(p); CHECK_HAS(u); CHECK_HAS(t); CHECK_HAS(v); CHECK_HAS(e); CHECK_HAS(l); CHECK_HAS(k); // The fields `sp`, `pn`, `tf`, `mn`, and `mx` are only set for "range" payloads. if (!_mongocrypt_buffer_from_subrange(&out->userKeyId, &out->value, 0, UUID_LEN)) { CLIENT_ERR("failed to create userKeyId buffer"); goto fail; } out->userKeyId.subtype = BSON_SUBTYPE_UUID; return true; fail: mc_FLE2InsertUpdatePayloadV2_cleanup(out); return false; } #define IUPS_APPEND_BINDATA(dst, name, subtype, value) \ if (!_mongocrypt_buffer_append(&(value), dst, name, -1)) { \ return false; \ } bool mc_FLE2InsertUpdatePayloadV2_serialize(const mc_FLE2InsertUpdatePayloadV2_t *payload, bson_t *out) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(payload); IUPS_APPEND_BINDATA(out, "d", BSON_SUBTYPE_BINARY, payload->edcDerivedToken); IUPS_APPEND_BINDATA(out, "s", BSON_SUBTYPE_BINARY, payload->escDerivedToken); IUPS_APPEND_BINDATA(out, "p", BSON_SUBTYPE_BINARY, payload->encryptedTokens); IUPS_APPEND_BINDATA(out, "u", BSON_SUBTYPE_UUID, payload->indexKeyId); if (!BSON_APPEND_INT32(out, "t", payload->valueType)) { return false; } IUPS_APPEND_BINDATA(out, "v", BSON_SUBTYPE_BINARY, payload->value); IUPS_APPEND_BINDATA(out, "e", BSON_SUBTYPE_BINARY, payload->serverEncryptionToken); IUPS_APPEND_BINDATA(out, "l", BSON_SUBTYPE_BINARY, payload->serverDerivedFromDataToken); if (!BSON_APPEND_INT64(out, "k", payload->contentionFactor)) { return false; } return true; } bool mc_FLE2InsertUpdatePayloadV2_serializeForRange(const mc_FLE2InsertUpdatePayloadV2_t *payload, bson_t *out, bool use_range_v2) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(payload); if (!mc_FLE2InsertUpdatePayloadV2_serialize(payload, out)) { return false; } // Append "g" array of EdgeTokenSets. bson_t g_bson; if (!BSON_APPEND_ARRAY_BEGIN(out, "g", &g_bson)) { return false; } uint32_t g_index = 0; for (size_t i = 0; i < payload->edgeTokenSetArray.len; i++) { mc_EdgeTokenSetV2_t etc = _mc_array_index(&payload->edgeTokenSetArray, mc_EdgeTokenSetV2_t, i); bson_t etc_bson; const char *g_index_string; char storage[16]; bson_uint32_to_string(g_index, &g_index_string, storage, sizeof(storage)); if (!BSON_APPEND_DOCUMENT_BEGIN(&g_bson, g_index_string, &etc_bson)) { return false; } IUPS_APPEND_BINDATA(&etc_bson, "d", BSON_SUBTYPE_BINARY, etc.edcDerivedToken); IUPS_APPEND_BINDATA(&etc_bson, "s", BSON_SUBTYPE_BINARY, etc.escDerivedToken); IUPS_APPEND_BINDATA(&etc_bson, "l", BSON_SUBTYPE_BINARY, etc.serverDerivedFromDataToken); IUPS_APPEND_BINDATA(&etc_bson, "p", BSON_SUBTYPE_BINARY, etc.encryptedTokens); if (!bson_append_document_end(&g_bson, &etc_bson)) { return false; } if (g_index == UINT32_MAX) { break; } g_index++; } if (!bson_append_array_end(out, &g_bson)) { return false; } if (use_range_v2) { // Encode parameters that were used to generate the payload. BSON_ASSERT(payload->sparsity.set); if (!BSON_APPEND_INT64(out, "sp", payload->sparsity.value)) { return false; } // Precision may be unset. if (payload->precision.set) { if (!BSON_APPEND_INT32(out, "pn", payload->precision.value)) { return false; } } BSON_ASSERT(payload->trimFactor.set); if (!BSON_APPEND_INT32(out, "tf", payload->trimFactor.value)) { return false; } BSON_ASSERT(payload->indexMin.value_type != BSON_TYPE_EOD); if (!BSON_APPEND_VALUE(out, "mn", &payload->indexMin)) { return false; } BSON_ASSERT(payload->indexMax.value_type != BSON_TYPE_EOD); if (!BSON_APPEND_VALUE(out, "mx", &payload->indexMax)) { return false; } } return true; } #undef IUPS_APPEND_BINDATA const _mongocrypt_buffer_t *mc_FLE2InsertUpdatePayloadV2_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2InsertUpdatePayloadV2_t *iup, const _mongocrypt_buffer_t *user_key, mongocrypt_status_t *status) { const _mongocrypt_value_encryption_algorithm_t *fle2v2 = _mcFLE2v2AEADAlgorithm(); BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(iup); BSON_ASSERT_PARAM(user_key); if (iup->value.len == 0) { CLIENT_ERR("FLE2InsertUpdatePayloadV2 value not parsed"); return NULL; } _mongocrypt_buffer_t ciphertext; BSON_ASSERT(iup->value.len >= UUID_LEN); if (!_mongocrypt_buffer_from_subrange(&ciphertext, &iup->value, UUID_LEN, iup->value.len - UUID_LEN)) { CLIENT_ERR("Failed to create ciphertext buffer"); return NULL; } _mongocrypt_buffer_resize(&iup->plaintext, fle2v2->get_plaintext_len(ciphertext.len, status)); uint32_t bytes_written; if (!fle2v2->do_decrypt(crypto, &iup->userKeyId, user_key, &ciphertext, &iup->plaintext, &bytes_written, status)) { return NULL; } iup->plaintext.len = bytes_written; return &iup->plaintext; } mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-insert-update-payload.c0000644000175100001660000003035114760300420022207 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include #include "mc-fle2-insert-update-payload-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt.h" void mc_FLE2InsertUpdatePayload_init(mc_FLE2InsertUpdatePayload_t *payload) { BSON_ASSERT_PARAM(payload); memset(payload, 0, sizeof(mc_FLE2InsertUpdatePayload_t)); _mc_array_init(&payload->edgeTokenSetArray, sizeof(mc_EdgeTokenSet_t)); } static void mc_EdgeTokenSet_cleanup(mc_EdgeTokenSet_t *etc) { BSON_ASSERT_PARAM(etc); _mongocrypt_buffer_cleanup(&etc->edcDerivedToken); _mongocrypt_buffer_cleanup(&etc->escDerivedToken); _mongocrypt_buffer_cleanup(&etc->eccDerivedToken); _mongocrypt_buffer_cleanup(&etc->encryptedTokens); } void mc_FLE2InsertUpdatePayload_cleanup(mc_FLE2InsertUpdatePayload_t *payload) { BSON_ASSERT_PARAM(payload); _mongocrypt_buffer_cleanup(&payload->edcDerivedToken); _mongocrypt_buffer_cleanup(&payload->escDerivedToken); _mongocrypt_buffer_cleanup(&payload->eccDerivedToken); _mongocrypt_buffer_cleanup(&payload->encryptedTokens); _mongocrypt_buffer_cleanup(&payload->indexKeyId); _mongocrypt_buffer_cleanup(&payload->value); _mongocrypt_buffer_cleanup(&payload->serverEncryptionToken); _mongocrypt_buffer_cleanup(&payload->plaintext); // Free all EdgeTokenSet entries. for (size_t i = 0; i < payload->edgeTokenSetArray.len; i++) { mc_EdgeTokenSet_t entry = _mc_array_index(&payload->edgeTokenSetArray, mc_EdgeTokenSet_t, i); mc_EdgeTokenSet_cleanup(&entry); } _mc_array_destroy(&payload->edgeTokenSetArray); } #define IF_FIELD(Name) \ if (0 == strcmp(field, #Name)) { \ if (has_##Name) { \ CLIENT_ERR("Duplicate field '" #Name "' in payload bson"); \ goto fail; \ } \ has_##Name = true; #define END_IF_FIELD \ continue; \ } #define PARSE_BINDATA(Name, Type, Dest) \ IF_FIELD(Name) { \ bson_subtype_t subtype; \ uint32_t len; \ const uint8_t *data; \ if (bson_iter_type(&iter) != BSON_TYPE_BINARY) { \ CLIENT_ERR("Field '" #Name "' expected to be bindata, got: %d", bson_iter_type(&iter)); \ goto fail; \ } \ bson_iter_binary(&iter, &subtype, &len, &data); \ if (subtype != Type) { \ CLIENT_ERR("Field '" #Name "' expected to be bindata subtype %d, got: %d", Type, subtype); \ goto fail; \ } \ if (!_mongocrypt_buffer_copy_from_binary_iter(&out->Dest, &iter)) { \ CLIENT_ERR("Unable to create mongocrypt buffer for BSON binary " \ "field in '" #Name "'"); \ goto fail; \ } \ } \ END_IF_FIELD #define PARSE_BINARY(Name, Dest) PARSE_BINDATA(Name, BSON_SUBTYPE_BINARY, Dest) #define CHECK_HAS(Name) \ if (!has_##Name) { \ CLIENT_ERR("Missing field '" #Name "' in payload"); \ goto fail; \ } bool mc_FLE2InsertUpdatePayload_parse(mc_FLE2InsertUpdatePayload_t *out, const _mongocrypt_buffer_t *in, mongocrypt_status_t *status) { bson_iter_t iter; bool has_d = false, has_s = false, has_c = false; bool has_p = false, has_u = false, has_t = false; bool has_v = false, has_e = false; bson_t in_bson; BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); if (in->len < 1) { CLIENT_ERR("FLE2InsertUpdatePayload_parse got too short input"); return false; } if (!bson_init_static(&in_bson, in->data + 1, in->len - 1)) { CLIENT_ERR("FLE2InsertUpdatePayload_parse got invalid BSON"); return false; } if (!bson_validate(&in_bson, BSON_VALIDATE_NONE, NULL) || !bson_iter_init(&iter, &in_bson)) { CLIENT_ERR("invalid BSON"); return false; } while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); PARSE_BINARY(d, edcDerivedToken) PARSE_BINARY(s, escDerivedToken) PARSE_BINARY(c, eccDerivedToken) PARSE_BINARY(p, encryptedTokens) PARSE_BINDATA(u, BSON_SUBTYPE_UUID, indexKeyId) IF_FIELD(t) { int32_t type = bson_iter_int32(&iter); if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR("Field 't' expected to hold an int32"); goto fail; } if ((type < 0) || (type > 0xFF)) { CLIENT_ERR("Field 't' must be a valid BSON type, got: %d", type); goto fail; } out->valueType = (bson_type_t)type; } END_IF_FIELD PARSE_BINARY(v, value) PARSE_BINARY(e, serverEncryptionToken) } CHECK_HAS(d); CHECK_HAS(s); CHECK_HAS(c); CHECK_HAS(p); CHECK_HAS(u); CHECK_HAS(t); CHECK_HAS(v); CHECK_HAS(e); if (!_mongocrypt_buffer_from_subrange(&out->userKeyId, &out->value, 0, UUID_LEN)) { CLIENT_ERR("failed to create userKeyId buffer"); goto fail; } out->userKeyId.subtype = BSON_SUBTYPE_UUID; return true; fail: mc_FLE2InsertUpdatePayload_cleanup(out); return false; } #define IUPS_APPEND_BINDATA(dst, name, subtype, value) \ if (!_mongocrypt_buffer_append(&(value), dst, name, -1)) { \ return false; \ } bool mc_FLE2InsertUpdatePayload_serialize(const mc_FLE2InsertUpdatePayload_t *payload, bson_t *out) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(payload); IUPS_APPEND_BINDATA(out, "d", BSON_SUBTYPE_BINARY, payload->edcDerivedToken); IUPS_APPEND_BINDATA(out, "s", BSON_SUBTYPE_BINARY, payload->escDerivedToken); IUPS_APPEND_BINDATA(out, "c", BSON_SUBTYPE_BINARY, payload->eccDerivedToken); IUPS_APPEND_BINDATA(out, "p", BSON_SUBTYPE_BINARY, payload->encryptedTokens); IUPS_APPEND_BINDATA(out, "u", BSON_SUBTYPE_UUID, payload->indexKeyId); if (!BSON_APPEND_INT32(out, "t", payload->valueType)) { return false; } IUPS_APPEND_BINDATA(out, "v", BSON_SUBTYPE_BINARY, payload->value); IUPS_APPEND_BINDATA(out, "e", BSON_SUBTYPE_BINARY, payload->serverEncryptionToken); return true; } bool mc_FLE2InsertUpdatePayload_serializeForRange(const mc_FLE2InsertUpdatePayload_t *payload, bson_t *out) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(payload); if (!mc_FLE2InsertUpdatePayload_serialize(payload, out)) { return false; } // Append "g" array of EdgeTokenSets. bson_t g_bson; if (!BSON_APPEND_ARRAY_BEGIN(out, "g", &g_bson)) { return false; } uint32_t g_index = 0; for (size_t i = 0; i < payload->edgeTokenSetArray.len; i++) { mc_EdgeTokenSet_t etc = _mc_array_index(&payload->edgeTokenSetArray, mc_EdgeTokenSet_t, i); bson_t etc_bson; const char *g_index_string; char storage[16]; bson_uint32_to_string(g_index, &g_index_string, storage, sizeof(storage)); if (!BSON_APPEND_DOCUMENT_BEGIN(&g_bson, g_index_string, &etc_bson)) { return false; } IUPS_APPEND_BINDATA(&etc_bson, "d", BSON_SUBTYPE_BINARY, etc.edcDerivedToken); IUPS_APPEND_BINDATA(&etc_bson, "s", BSON_SUBTYPE_BINARY, etc.escDerivedToken); IUPS_APPEND_BINDATA(&etc_bson, "c", BSON_SUBTYPE_BINARY, etc.eccDerivedToken); IUPS_APPEND_BINDATA(&etc_bson, "p", BSON_SUBTYPE_BINARY, etc.encryptedTokens); if (!bson_append_document_end(&g_bson, &etc_bson)) { return false; } if (g_index == UINT32_MAX) { break; } g_index++; } if (!bson_append_array_end(out, &g_bson)) { return false; } return true; } #undef IUPS_APPEND_BINDATA const _mongocrypt_buffer_t *mc_FLE2InsertUpdatePayload_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2InsertUpdatePayload_t *iup, const _mongocrypt_buffer_t *user_key, mongocrypt_status_t *status) { const _mongocrypt_value_encryption_algorithm_t *fle2aead = _mcFLE2AEADAlgorithm(); BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(iup); BSON_ASSERT_PARAM(user_key); if (iup->value.len == 0) { CLIENT_ERR("FLE2InsertUpdatePayload value not parsed"); return NULL; } _mongocrypt_buffer_t ciphertext; BSON_ASSERT(iup->value.len >= UUID_LEN); if (!_mongocrypt_buffer_from_subrange(&ciphertext, &iup->value, UUID_LEN, iup->value.len - UUID_LEN)) { CLIENT_ERR("Failed to create ciphertext buffer"); return NULL; } _mongocrypt_buffer_resize(&iup->plaintext, fle2aead->get_plaintext_len(ciphertext.len, status)); uint32_t bytes_written; /* ignored */ if (!fle2aead ->do_decrypt(crypto, &iup->userKeyId, user_key, &ciphertext, &iup->plaintext, &bytes_written, status)) { return NULL; } return &iup->plaintext; } mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-iev-private-v2.h0000644000175100001660000001554114760300420022214 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef MONGOCRYPT_INDEXED_ENCRYPTED_VALUE_PRIVATE_V2_H #define MONGOCRYPT_INDEXED_ENCRYPTED_VALUE_PRIVATE_V2_H #include "mc-fle2-tag-and-encrypted-metadata-block-private.h" #include "mc-tokens-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt-crypto-private.h" #include "mongocrypt-status-private.h" /* * FLE2IndexedEqualityEncryptedValueV2 and FLE2IndexedRangeEncryptedValueV2 * share a common internal implementation. * * Lifecycle: * 1. mc_FLE2IndexedEncryptedValueV2_init * 2. mc_FLE2IndexedEncryptedValueV2_parse * 3. mc_FLE2IndexedEncryptedValueV2_get_S_KeyId * 4. mc_FLE2IndexedEncryptedValueV2_add_S_Key * 5. mc_FLE2IndexedEncryptedValueV2_get_K_KeyId * 6. mc_FLE2IndexedEncryptedValueV2_add_K_Key * 7. mc_FLE2IndexedEncryptedValueV2_get_ClientValue * 8. mc_FLE2IndexedEncryptedValueV2_serialize * 9. mc_FLE2IndexedEncryptedValueV2_destroy * * * FLE2IndexedEqualityEncryptedValueV2 has the following data layout: * * struct FLE2IndexedEqualityEncryptedValueV2 { * uint8_t fle_blob_subtype = 14; * uint8_t S_KeyId[16]; * uint8_t original_bson_type; * uint8_t ServerEncryptedValue[ServerEncryptedValue.length]; * FLE2TagAndEncryptedMetadataBlock metadata; * } * * ServerEncryptedValue := * EncryptCTR(ServerEncryptionToken, K_KeyId || ClientEncryptedValue) * ClientEncryptedValue := EncryptCBCAEAD(K_Key, clientValue, AD=K_KeyId) * * * struct FLE2TagAndEncryptedMetadataBlock { * uint8_t encryptedCount[32]; // EncryptCTR(countEncryptionToken, * // count || contentionFactor) * uint8_t tag[32]; // HMAC-SHA256(count, edcTwiceDerived) * uint8_t encryptedZeros[32]; // EncryptCTR(zerosEncryptionToken, 0*) * } * * * FLE2IndexedRangeEncryptedValueV2 has the following data layout: * * struct FLE2IndexedRangeEncryptedValueV2 { * uint8_t fle_blob_subtype = 15; * uint8_t S_KeyId[16]; * uint8_t original_bson_type; * uint8_t edge_count; * uint8_t ServerEncryptedValue[ServerEncryptedValue.length]; * FLE2TagAndEncryptedMetadataBlock metadata[edge_count]; * } * * Note that this format differs from FLE2IndexedEqualityEncryptedValueV2 * in only two ways: * 1/ `edge_count` is introduced as an octet following `original_bson_type`. * 2/ Rather than a single metadata block, we have {edge_count} blocks. * */ typedef struct _mc_FLE2IndexedEncryptedValueV2_t mc_FLE2IndexedEncryptedValueV2_t; mc_FLE2IndexedEncryptedValueV2_t *mc_FLE2IndexedEncryptedValueV2_new(void); bson_type_t mc_FLE2IndexedEncryptedValueV2_get_bson_value_type(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status); /* * Populates an mc_FLE2IndexedEncryptedValueV2_t from a buffer. * * Input buffer must take the form of: * fle_blob_subtype (8u) * S_KeyId (8u * 16u) * original_bson_type (8u) * if (range) * edge_count(8u) * ServerEncryptedValue (8u * SEV_len) * metadata (96u * {range ? edge_count : 1u}) * * Returns an error if the input buffer is not valid. */ bool mc_FLE2IndexedEncryptedValueV2_parse(mc_FLE2IndexedEncryptedValueV2_t *iev, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); /* * Serializes an mc_FLE2IndexedEncryptedValueV2_t into a buffer. * * The serialized output follows the same layout as the input `buf` to * mc_FLE2IndexedEncryptedValueV2_parse, allowing for round-trip * conversions between the serialized and parsed forms. * * Returns an error if the input structure is not valid, or if the buffer * provided is insufficient to hold the serialized data. */ bool mc_FLE2IndexedEncryptedValueV2_serialize(const mc_FLE2IndexedEncryptedValueV2_t *iev, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValueV2_get_S_KeyId(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status); bool mc_FLE2IndexedEncryptedValueV2_add_S_Key(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValueV2_t *iev, const _mongocrypt_buffer_t *S_Key, mongocrypt_status_t *status); const _mongocrypt_buffer_t * mc_FLE2IndexedEncryptedValueV2_get_ClientEncryptedValue(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status); const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValueV2_get_K_KeyId(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status); bool mc_FLE2IndexedEncryptedValueV2_add_K_Key(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValueV2_t *iev, const _mongocrypt_buffer_t *K_Key, mongocrypt_status_t *status); const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValueV2_get_ClientValue(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status); uint8_t mc_FLE2IndexedEncryptedValueV2_get_edge_count(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status); bool mc_FLE2IndexedEncryptedValueV2_get_edge(const mc_FLE2IndexedEncryptedValueV2_t *iev, mc_FLE2TagAndEncryptedMetadataBlock_t *out, const uint8_t edge_index, mongocrypt_status_t *status); bool mc_FLE2IndexedEncryptedValueV2_get_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev, mc_FLE2TagAndEncryptedMetadataBlock_t *out, mongocrypt_status_t *status); void mc_FLE2IndexedEncryptedValueV2_destroy(mc_FLE2IndexedEncryptedValueV2_t *iev); #endif /* MONGOCRYPT_INDEXED_ENCRYPTED_VALUE_PRIVATE_V2_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-iev-private.h0000644000175100001660000002132514760300420021664 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MONGOCRYPT_INDEXED_ENCRYPTED_VALUE_PRIVATE_H #define MONGOCRYPT_INDEXED_ENCRYPTED_VALUE_PRIVATE_H #include "mc-tokens-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt-crypto-private.h" #include "mongocrypt-status-private.h" /** * FLE2IndexedEncryptedValue represents an FLE2 encrypted value. It is * created server side. * * FLE2IndexedEncryptedValue represents one of the following payloads: * - FLE2IndexedEqualityEncryptedValue * - FLE2IndexedRangeEncryptedValue * * Both payloads share a common prefix. libmongocrypt does not need to parse the * edges in FLE2IndexedRangeEncryptedValue. */ /* clang-format off */ /* * FLE2IndexedEqualityEncryptedValue has the following data layout: * * struct { * uint8_t fle_blob_subtype = 7; * uint8_t S_KeyId[16]; * uint8_t original_bson_type; * uint8_t InnerEncrypted[InnerEncrypted_length]; * } FLE2IndexedEqualityEncryptedValue * * InnerEncrypted is the output of: Encrypt(key=ServerDataLevel1Token, plaintext=Inner) * ServerDataLevel1Token is created from the key identified by S_KeyId. * * struct { * uint64_t length; // sizeof(K_KeyId) + ClientEncryptedValue_length; * uint8_t K_KeyId[16]; * uint8_t ClientEncryptedValue[ClientEncryptedValue_length]; * uint64_t counter; * uint8_t edc[32]; // EDCDerivedFromDataTokenAndContentionFactorToken * uint8_t esc[32]; // ESCDerivedFromDataTokenAndContentionFactorToken * uint8_t ecc[32]; // ECCDerivedFromDataTokenAndContentionFactorToken *} Inner * * ClientEncryptedValue is the output of: EncryptAEAD(key=K_Key, plaintext=ClientValue, associated_data=K_KeyId) * K_Key is the key identified by K_KeyId. * * See https://github.com/mongodb/mongo/blob/fa94f5fb6216a1cc1e23f5ad4df05295b380070e/src/mongo/crypto/fle_crypto.h#L897 * for the server representation of FLE2IndexedEqualityEncryptedPayload. */ /* * FLE2IndexedRangeEncryptedPayload shares the data layout with * FLE2IndexedEqualityEncryptedValue with the following additional data appended to Inner: * * uint32_t edgeCount; * struct { * uint64_t counter; * uint8_t[32] edc; // EDCDerivedFromDataTokenAndContentionFactorToken * uint8_t[32] esc; // ESCDerivedFromDataTokenAndContentionFactorToken * uint8_t[32] ecc; // ECCDerivedFromDataTokenAndContentionFactorToken * } edges[edgeCount]; * * libmongocrypt ignores the edges. * * See https://github.com/mongodb/mongo/blob/fa94f5fb6216a1cc1e23f5ad4df05295b380070e/src/mongo/crypto/fle_crypto.h#L897 * for the server representation of FLE2IndexedEqualityEncryptedPayload. */ /* clang-format on */ typedef struct _mc_FLE2IndexedEqualityEncryptedValue_t mc_FLE2IndexedEncryptedValue_t; struct _mc_FLE2IndexedEqualityEncryptedValueTokens { uint64_t counter; _mongocrypt_buffer_t edc; _mongocrypt_buffer_t esc; _mongocrypt_buffer_t ecc; }; typedef struct _mc_FLE2IndexedEqualityEncryptedValueTokens mc_FLE2IndexedEqualityEncryptedValueTokens; mc_FLE2IndexedEncryptedValue_t *mc_FLE2IndexedEncryptedValue_new(void); mc_FLE2IndexedEqualityEncryptedValueTokens *mc_FLE2IndexedEqualityEncryptedValueTokens_new(void); /** * This function is used by the server codebase. */ bool mc_FLE2IndexedEqualityEncryptedValueTokens_init_from_buffer(mc_FLE2IndexedEqualityEncryptedValueTokens *tokens, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); bool mc_FLE2IndexedEncryptedValue_parse(mc_FLE2IndexedEncryptedValue_t *iev, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); /** * This function is used by the server codebase. */ bool mc_FLE2IndexedEncryptedValue_write(_mongocrypt_crypto_t *crypto, const bson_type_t original_bson_type, const _mongocrypt_buffer_t *S_KeyId, const _mongocrypt_buffer_t *ClientEncryptedValue, mc_ServerDataEncryptionLevel1Token_t *token, mc_FLE2IndexedEqualityEncryptedValueTokens *index_tokens, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); /* mc_FLE2IndexedEncryptedValue_get_original_bson_type returns * original_bson_type. Returns 0 and sets @status on error. * It is an error to call before mc_FLE2IndexedEncryptedValue_parse. */ bson_type_t mc_FLE2IndexedEncryptedValue_get_original_bson_type(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status); /* mc_FLE2IndexedEncryptedValue_get_S_KeyId returns S_KeyId. Returns * NULL and sets @status on error. It is an error to call before * mc_FLE2IndexedEncryptedValue_parse. */ const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValue_get_S_KeyId(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status); /* mc_FLE2IndexedEncryptedValue_add_S_Key decrypts InnerEncrypted. * Returns false and sets @status on error. It is an error to call before * mc_FLE2IndexedEncryptedValue_parse. */ bool mc_FLE2IndexedEncryptedValue_add_S_Key(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValue_t *iev, const _mongocrypt_buffer_t *S_Key, mongocrypt_status_t *status); /* mc_FLE2IndexedEncryptedValue_decrypt decrypts InnerEncrypted with the * ServerDataEncryptionLevel1Token on the server-side. Returns false and sets * @status on error. It is an error to call before * mc_FLE2IndexedEncryptedValue_parse. * * This function is used by the server codebase. */ bool mc_FLE2IndexedEncryptedValue_decrypt_equality(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValue_t *iev, mc_ServerDataEncryptionLevel1Token_t *token, mc_FLE2IndexedEqualityEncryptedValueTokens *indexed_tokens, mongocrypt_status_t *status); /* mc_FLE2IndexedEncryptedValue_get_K_KeyId returns Inner.K_KeyId. * Returns NULL and sets @status on error. It is an error to call before * mc_FLE2IndexedEncryptedValue_add_S_Key. */ const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValue_get_K_KeyId(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status); /* mc_FLE2IndexedEncryptedValue_add_K_Key decrypts * Inner.ClientEncryptedValue. Returns false and sets @status on error. Must * not be called before mc_FLE2IndexedEncryptedValue_add_S_Key. */ bool mc_FLE2IndexedEncryptedValue_add_K_Key(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValue_t *iev, const _mongocrypt_buffer_t *K_Key, mongocrypt_status_t *status); /* mc_FLE2IndexedEncryptedValue_get_ClientValue returns the decrypted * Inner.ClientEncryptedValue. Returns NULL and sets @status on error. * It is an error to call before mc_FLE2IndexedEncryptedValue_add_K_Key. */ const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValue_get_ClientValue(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status); /** * This function is used by the server codebase. */ const _mongocrypt_buffer_t * mc_FLE2IndexedEncryptedValue_get_ClientEncryptedValue(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status); void mc_FLE2IndexedEncryptedValue_destroy(mc_FLE2IndexedEncryptedValue_t *iev); void mc_FLE2IndexedEqualityEncryptedValueTokens_destroy(mc_FLE2IndexedEqualityEncryptedValueTokens *tokens); #endif /* MONGOCRYPT_INDEXED_ENCRYPTED_VALUE_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-iev-v2.c0000644000175100001660000004542614760300420020544 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mongocrypt-buffer-private.h" #include "mongocrypt-private.h" #include "mc-fle-blob-subtype-private.h" #include "mc-fle2-payload-iev-private-v2.h" #include "mc-fle2-tag-and-encrypted-metadata-block-private.h" #include "mc-reader-private.h" #include "mc-tokens-private.h" #include "mc-writer-private.h" #include typedef enum { kTypeInit, kTypeEquality, kTypeRange, } _mc_fle2_iev_v2_type; struct _mc_FLE2IndexedEncryptedValueV2_t { // Raw payload values uint8_t fle_blob_subtype; uint8_t bson_value_type; uint8_t edge_count; _mongocrypt_buffer_t S_KeyId; _mongocrypt_buffer_t ServerEncryptedValue; // Decode State _mc_fle2_iev_v2_type type; bool ClientEncryptedValueDecoded; bool ClientValueDecoded; // Populated during _add_S_Key // DecryptedServerEncryptedValue := DecryptCTR(S_Key, ServerEncryptedValue) _mongocrypt_buffer_t DecryptedServerEncryptedValue; // Views on DecryptedServerEncryptedValue (DSEV) _mongocrypt_buffer_t K_KeyId; // First 16 octets, UUID _mongocrypt_buffer_t ClientEncryptedValue; // Remainder of DSEV // Populated during _add_K_Key // ClientValue := DecryptCBCAEAD(K_Key, ClientEncryptedValue, AD=K_KeyId) _mongocrypt_buffer_t ClientValue; mc_FLE2TagAndEncryptedMetadataBlock_t *metadata; }; #define kMetadataLen 96U // encCount(32) + tag(32) + encZeros(32) #define kMinServerEncryptedValueLen 17U // IV(16) + EncryptCTR(1byte) #define kMinSEVAndMetadataLen (kMinServerEncryptedValueLen + kMetadataLen) #define CHECK_AND_RETURN(x) \ if (!(x)) { \ return false; \ } mc_FLE2IndexedEncryptedValueV2_t *mc_FLE2IndexedEncryptedValueV2_new(void) { return bson_malloc0(sizeof(mc_FLE2IndexedEncryptedValueV2_t)); } bson_type_t mc_FLE2IndexedEncryptedValueV2_get_bson_value_type(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (iev->type == kTypeInit) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_bson_value_type " "must be called after " "mc_FLE2IndexedEncryptedValueV2_parse"); return BSON_TYPE_EOD; } return (bson_type_t)iev->bson_value_type; } const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValueV2_get_S_KeyId(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (iev->type == kTypeInit) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_S_KeyId " "must be called after " "mc_FLE2IndexedEncryptedValueV2_parse"); return NULL; } return &iev->S_KeyId; } bool mc_FLE2IndexedEncryptedValueV2_add_S_Key(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValueV2_t *iev, const _mongocrypt_buffer_t *S_Key, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(S_Key); BSON_ASSERT_PARAM(status); if (iev->type == kTypeInit) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_add_S_Key must " "be called after " "mc_FLE2IndexedEncryptedValueV2_parse"); return false; } if (iev->ClientEncryptedValueDecoded) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_add_S_Key must " "not be called twice"); return false; } if (S_Key->len != MONGOCRYPT_KEY_LEN) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_add_S_Key expected " "S_Key to be %d bytes, got: %" PRIu32, MONGOCRYPT_KEY_LEN, S_Key->len); return false; } /* Get the TokenKey from the last 32 bytes of S_Key */ _mongocrypt_buffer_t TokenKey; if (!_mongocrypt_buffer_from_subrange(&TokenKey, S_Key, S_Key->len - MONGOCRYPT_TOKEN_KEY_LEN, MONGOCRYPT_TOKEN_KEY_LEN)) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_add_S_Key unable to " "parse TokenKey from S_Key"); return false; } /* Use TokenKey to create ServerDataEncryptionLevel1Token and decrypt * ServerEncryptedValue into ClientEncryptedValue */ mc_ServerDataEncryptionLevel1Token_t *token = mc_ServerDataEncryptionLevel1Token_new(crypto, &TokenKey, status); if (!token) { return false; } bool ret = false; const _mongocrypt_value_encryption_algorithm_t *fle2alg = _mcFLE2Algorithm(); const uint32_t DecryptedServerEncryptedValueLen = fle2alg->get_plaintext_len(iev->ServerEncryptedValue.len, status); if (!mongocrypt_status_ok(status)) { goto fail; } if (DecryptedServerEncryptedValueLen <= UUID_LEN) { CLIENT_ERR("Invalid ServerEncryptedValue length, got %" PRIu32 ", expected more than %d", DecryptedServerEncryptedValueLen, UUID_LEN); goto fail; } _mongocrypt_buffer_resize(&iev->DecryptedServerEncryptedValue, DecryptedServerEncryptedValueLen); uint32_t bytes_written = 0; if (!fle2alg->do_decrypt(crypto, NULL /* aad */, mc_ServerDataEncryptionLevel1Token_get(token), &iev->ServerEncryptedValue, &iev->DecryptedServerEncryptedValue, &bytes_written, status)) { goto fail; } BSON_ASSERT(bytes_written == DecryptedServerEncryptedValueLen); if (!_mongocrypt_buffer_from_subrange(&iev->K_KeyId, &iev->DecryptedServerEncryptedValue, 0, UUID_LEN)) { CLIENT_ERR("Error creating K_KeyId subrange from DecryptedServerEncryptedValue"); goto fail; } iev->K_KeyId.subtype = BSON_SUBTYPE_UUID; BSON_ASSERT(iev->DecryptedServerEncryptedValue.len > UUID_LEN); if (!_mongocrypt_buffer_from_subrange(&iev->ClientEncryptedValue, &iev->DecryptedServerEncryptedValue, UUID_LEN, iev->DecryptedServerEncryptedValue.len - UUID_LEN)) { CLIENT_ERR("Error creating ClientEncryptedValue subrange from " "DecryptedServerEncryptedValue"); goto fail; } iev->ClientEncryptedValueDecoded = true; ret = true; fail: mc_ServerDataEncryptionLevel1Token_destroy(token); return ret; } const _mongocrypt_buffer_t * mc_FLE2IndexedEncryptedValueV2_get_ClientEncryptedValue(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (!iev->ClientEncryptedValueDecoded) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_" "ClientEncryptedValue must be called after " "mc_FLE2IndexedEncryptedValueV2_add_S_Key"); return NULL; } return &iev->ClientEncryptedValue; } const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValueV2_get_K_KeyId(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (!iev->ClientEncryptedValueDecoded) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_K_KeyID " "must be called after " "mc_FLE2IndexedEncryptedValueV2_add_S_Key"); return NULL; } return &iev->K_KeyId; } bool mc_FLE2IndexedEncryptedValueV2_add_K_Key(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValueV2_t *iev, const _mongocrypt_buffer_t *K_Key, mongocrypt_status_t *status) { const _mongocrypt_value_encryption_algorithm_t *fle2v2aead = _mcFLE2v2AEADAlgorithm(); BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(K_Key); BSON_ASSERT_PARAM(status); if (!iev->ClientEncryptedValueDecoded) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_add_K_Key must be " "called after " "mc_FLE2IndexedEncryptedValueV2_add_S_Key"); return false; } if (iev->ClientValueDecoded) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_add_K_Key must not " "be called twice"); return false; } /* Attempt to decrypt ClientEncryptedValue */ const uint32_t ClientValueLen = fle2v2aead->get_plaintext_len(iev->ClientEncryptedValue.len, status); if (!mongocrypt_status_ok(status)) { return false; } _mongocrypt_buffer_t clientValue; _mongocrypt_buffer_init_size(&clientValue, ClientValueLen); uint32_t bytes_written = 0; if (!fle2v2aead->do_decrypt(crypto, &iev->K_KeyId, K_Key, &iev->ClientEncryptedValue, &clientValue, &bytes_written, status)) { _mongocrypt_buffer_cleanup(&clientValue); return false; } BSON_ASSERT(bytes_written > 0); BSON_ASSERT(bytes_written <= ClientValueLen); _mongocrypt_buffer_steal(&iev->ClientValue, &clientValue); iev->ClientValue.len = bytes_written; iev->ClientValueDecoded = true; return true; } const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValueV2_get_ClientValue(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (!iev->ClientValueDecoded) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_ClientValue must " "be called after " "mc_FLE2IndexedEncryptedValueV2_add_K_Key"); return NULL; } return &iev->ClientValue; } void mc_FLE2IndexedEncryptedValueV2_destroy(mc_FLE2IndexedEncryptedValueV2_t *iev) { if (!iev) { return; } _mongocrypt_buffer_cleanup(&iev->ClientValue); _mongocrypt_buffer_cleanup(&iev->DecryptedServerEncryptedValue); _mongocrypt_buffer_cleanup(&iev->ServerEncryptedValue); _mongocrypt_buffer_cleanup(&iev->S_KeyId); for (int i = 0; i < iev->edge_count; i++) { mc_FLE2TagAndEncryptedMetadataBlock_cleanup(&iev->metadata[i]); } // Metadata array is dynamically allocated bson_free(iev->metadata); bson_free(iev); } uint8_t mc_FLE2IndexedEncryptedValueV2_get_edge_count(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (iev->type == kTypeInit) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_edge_count " "must be called after " "mc_FLE2IndexedEncryptedValueV2_parse"); return 0; } if (iev->type != kTypeRange) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_edge_count must be called with type range"); return 0; } return iev->edge_count; } bool mc_FLE2IndexedEncryptedValueV2_get_edge(const mc_FLE2IndexedEncryptedValueV2_t *iev, mc_FLE2TagAndEncryptedMetadataBlock_t *out, const uint8_t edge_index, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(out); if (iev->type == kTypeInit) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_edge " "must be called after " "mc_FLE2IndexedEncryptedValueV2_parse"); return false; } if (iev->type != kTypeRange) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_edge must be called with type range"); return false; } if (edge_index >= iev->edge_count) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_edge must be called with index edge_index less than edge count"); return false; } // Write edge into out struct *out = iev->metadata[edge_index]; return true; } bool mc_FLE2IndexedEncryptedValueV2_get_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev, mc_FLE2TagAndEncryptedMetadataBlock_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(out); if (iev->type == kTypeInit) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_metadata " "must be called after " "mc_FLE2IndexedEncryptedValueV2_parse"); return false; } if (iev->type != kTypeEquality) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_metadata must be called with type equality"); return false; } // Write edge into out struct *out = *iev->metadata; return true; } bool mc_FLE2IndexedEncryptedValueV2_parse(mc_FLE2IndexedEncryptedValueV2_t *iev, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(buf); if ((buf->data == NULL) || (buf->len == 0)) { CLIENT_ERR("Empty buffer passed to mc_FLE2IndexedEncryptedValueV2_parse"); return false; } if (iev->type != kTypeInit) { CLIENT_ERR("mc_FLE2IndexedRangeEncryptedValueV2_parse must not be " "called twice"); return false; } mc_reader_t reader; mc_reader_init_from_buffer(&reader, buf, __FUNCTION__); CHECK_AND_RETURN(mc_reader_read_u8(&reader, &iev->fle_blob_subtype, status)); if (iev->fle_blob_subtype == MC_SUBTYPE_FLE2IndexedEqualityEncryptedValueV2) { iev->type = kTypeEquality; } else if (iev->fle_blob_subtype == MC_SUBTYPE_FLE2IndexedRangeEncryptedValueV2) { iev->type = kTypeRange; } else { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_parse expected " "fle_blob_subtype MC_SUBTYPE_FLE2Indexed(Equality|Range)EncryptedValueV2 got: %" PRIu8, iev->fle_blob_subtype); return false; } /* Read S_KeyId. */ CHECK_AND_RETURN(mc_reader_read_uuid_buffer(&reader, &iev->S_KeyId, status)); /* Read original_bson_type. */ CHECK_AND_RETURN(mc_reader_read_u8(&reader, &iev->bson_value_type, status)); /* Read edge_count */ // Set equality edge_count to 1 as it doesn't technically exist but // there will be a singular metadata block if (iev->type == kTypeEquality) { iev->edge_count = 1; } else { CHECK_AND_RETURN(mc_reader_read_u8(&reader, &iev->edge_count, status)); } // Maximum edge_count(255) times kMetadataLen(96) fits easily without // overflow. const uint64_t metadata_len = iev->edge_count * kMetadataLen; /* Read ServerEncryptedValue. */ const uint64_t min_required_len = kMinServerEncryptedValueLen + metadata_len; const uint64_t SEV_and_metadata_len = mc_reader_get_remaining_length(&reader); if (SEV_and_metadata_len < min_required_len) { CLIENT_ERR("Invalid payload size %" PRIu64 ", smaller than minimum length %" PRIu64, SEV_and_metadata_len, min_required_len); return false; } const uint64_t SEV_len = SEV_and_metadata_len - metadata_len; CHECK_AND_RETURN(mc_reader_read_buffer(&reader, &iev->ServerEncryptedValue, SEV_len, status)); iev->metadata = (mc_FLE2TagAndEncryptedMetadataBlock_t *)bson_malloc0( iev->edge_count * sizeof(mc_FLE2TagAndEncryptedMetadataBlock_t)); // Read each metadata element for (uint8_t i = 0; i < iev->edge_count; i++) { _mongocrypt_buffer_t tmp_buf; CHECK_AND_RETURN(mc_reader_read_buffer(&reader, &tmp_buf, kMetadataLen, status)); CHECK_AND_RETURN(mc_FLE2TagAndEncryptedMetadataBlock_parse(&iev->metadata[i], &tmp_buf, status)); _mongocrypt_buffer_cleanup(&tmp_buf); } return true; } bool mc_FLE2IndexedEncryptedValueV2_serialize(const mc_FLE2IndexedEncryptedValueV2_t *iev, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(buf); if (iev->type != kTypeRange && iev->type != kTypeEquality) { CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_serialize must be called with type equality or range"); return false; } mc_writer_t writer; mc_writer_init_from_buffer(&writer, buf, __FUNCTION__); // Serialize fle_blob_subtype CHECK_AND_RETURN(mc_writer_write_u8(&writer, iev->fle_blob_subtype, status)); // Serialize S_KeyId CHECK_AND_RETURN(mc_writer_write_uuid_buffer(&writer, &iev->S_KeyId, status)); // Serialize bson_value_type CHECK_AND_RETURN(mc_writer_write_u8(&writer, iev->bson_value_type, status)); // Serialize edge_count (only serialized for type range) if (iev->type == kTypeRange) { CHECK_AND_RETURN(mc_writer_write_u8(&writer, iev->edge_count, status)); } // Serialize encrypted value CHECK_AND_RETURN( mc_writer_write_buffer(&writer, &iev->ServerEncryptedValue, iev->ServerEncryptedValue.len, status)); // Serialize metadata for (int i = 0; i < iev->edge_count; ++i) { _mongocrypt_buffer_t tmp_buf; _mongocrypt_buffer_init_size(&tmp_buf, kMetadataLen); CHECK_AND_RETURN(mc_FLE2TagAndEncryptedMetadataBlock_serialize(&iev->metadata[i], &tmp_buf, status)); CHECK_AND_RETURN(mc_writer_write_buffer(&writer, &tmp_buf, kMetadataLen, status)); _mongocrypt_buffer_cleanup(&tmp_buf); } return true; }mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-iev.c0000644000175100001660000005101414760300420020205 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mongocrypt-buffer-private.h" #include "mongocrypt-private.h" #include "mc-fle-blob-subtype-private.h" #include "mc-fle2-payload-iev-private.h" #include "mc-reader-private.h" #include "mc-tokens-private.h" #include "mc-writer-private.h" #include #define CHECK_AND_RETURN(x) \ if (!(x)) { \ return false; \ } struct _mc_FLE2IndexedEqualityEncryptedValue_t { _mongocrypt_buffer_t S_KeyId; _mongocrypt_buffer_t InnerEncrypted; _mongocrypt_buffer_t Inner; _mongocrypt_buffer_t K_KeyId; _mongocrypt_buffer_t ClientValue; _mongocrypt_buffer_t ClientEncryptedValue; uint8_t original_bson_type; uint8_t fle_blob_subtype; bool parsed; bool inner_decrypted; bool client_value_decrypted; }; mc_FLE2IndexedEncryptedValue_t *mc_FLE2IndexedEncryptedValue_new(void) { return bson_malloc0(sizeof(mc_FLE2IndexedEncryptedValue_t)); } mc_FLE2IndexedEqualityEncryptedValueTokens *mc_FLE2IndexedEqualityEncryptedValueTokens_new(void) { return bson_malloc0(sizeof(mc_FLE2IndexedEqualityEncryptedValueTokens)); } bool mc_FLE2IndexedEqualityEncryptedValueTokens_init_from_buffer(mc_FLE2IndexedEqualityEncryptedValueTokens *tokens, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(tokens); BSON_ASSERT_PARAM(buf); mc_reader_t reader; mc_reader_init_from_buffer(&reader, buf, __FUNCTION__); CHECK_AND_RETURN(mc_reader_read_u64(&reader, &tokens->counter, status)); CHECK_AND_RETURN(mc_reader_read_prfblock_buffer(&reader, &tokens->edc, status)); CHECK_AND_RETURN(mc_reader_read_prfblock_buffer(&reader, &tokens->esc, status)); CHECK_AND_RETURN(mc_reader_read_prfblock_buffer(&reader, &tokens->ecc, status)); return true; } static bool mc_fle2IndexedEncryptedValue_encrypt(_mongocrypt_crypto_t *crypto, const _mongocrypt_buffer_t *ClientEncryptedValue, mc_ServerDataEncryptionLevel1Token_t *token, mc_FLE2IndexedEqualityEncryptedValueTokens *index_tokens, _mongocrypt_buffer_t *out, mongocrypt_status_t *status); bool safe_uint32_t_sum(const uint32_t a, const uint32_t b, uint32_t *out, mongocrypt_status_t *status) { if (a > UINT32_MAX - b) { CLIENT_ERR("safe_uint32_t_sum overflow, %" PRIu32 ", %" PRIu32, a, b); return false; } *out = a + b; return true; } bool mc_FLE2IndexedEncryptedValue_write(_mongocrypt_crypto_t *crypto, const bson_type_t original_bson_type, const _mongocrypt_buffer_t *S_KeyId, const _mongocrypt_buffer_t *ClientEncryptedValue, mc_ServerDataEncryptionLevel1Token_t *token, mc_FLE2IndexedEqualityEncryptedValueTokens *index_tokens, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { #define CHECK_AND_GOTO(x) \ if (!(x)) { \ goto cleanup; \ } bool ok = false; BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(index_tokens); BSON_ASSERT_PARAM(S_KeyId); BSON_ASSERT_PARAM(ClientEncryptedValue); BSON_ASSERT_PARAM(token); BSON_ASSERT_PARAM(index_tokens); BSON_ASSERT_PARAM(buf); if (ClientEncryptedValue->len == 0) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_write iev must have an encrypted value"); return ok; } if (S_KeyId->len == 0) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_write iev SKeyId must have value"); return ok; } _mongocrypt_buffer_t encryption_out; _mongocrypt_buffer_init(&encryption_out); CHECK_AND_GOTO(mc_fle2IndexedEncryptedValue_encrypt(crypto, ClientEncryptedValue, token, index_tokens, &encryption_out, status)); mc_writer_t writer; mc_writer_init_from_buffer(&writer, buf, __FUNCTION__); const uint8_t subtype = (uint8_t)MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue; if (((int)original_bson_type < 0) || ((int)original_bson_type > 0xFF)) { CLIENT_ERR("Field 't' must be a valid BSON type, got: %d", original_bson_type); CHECK_AND_GOTO(false); } const uint8_t bson_type = (uint8_t)original_bson_type; CHECK_AND_GOTO(mc_writer_write_u8(&writer, subtype, status)); CHECK_AND_GOTO(mc_writer_write_buffer(&writer, S_KeyId, S_KeyId->len, status)); CHECK_AND_GOTO(mc_writer_write_u8(&writer, bson_type, status)); CHECK_AND_GOTO(mc_writer_write_buffer(&writer, &encryption_out, encryption_out.len, status)); ok = true; cleanup: _mongocrypt_buffer_cleanup(&encryption_out); return ok; #undef CHECK_AND_GOTO } static bool mc_fle2IndexedEncryptedValue_encrypt(_mongocrypt_crypto_t *crypto, const _mongocrypt_buffer_t *ClientEncryptedValue, mc_ServerDataEncryptionLevel1Token_t *token, mc_FLE2IndexedEqualityEncryptedValueTokens *index_tokens, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { #define CHECK_AND_GOTO(x) \ if (!(x)) { \ goto cleanup; \ } const _mongocrypt_value_encryption_algorithm_t *fle2alg = _mcFLE2Algorithm(); bool ok = false; _mongocrypt_buffer_t in; _mongocrypt_buffer_t iv; _mongocrypt_buffer_init(&in); _mongocrypt_buffer_init_size(&iv, MONGOCRYPT_IV_LEN); uint32_t expected_buf_size = 0; CHECK_AND_GOTO(safe_uint32_t_sum(ClientEncryptedValue->len, (uint32_t)(sizeof(uint64_t) * 2 + (32 * 3)), &expected_buf_size, status)); _mongocrypt_buffer_resize(&in, expected_buf_size); uint32_t ciphertext_len = fle2alg->get_ciphertext_len(expected_buf_size, status); if (ciphertext_len == 0) { goto cleanup; } _mongocrypt_buffer_resize(out, ciphertext_len); mc_writer_t writer; mc_writer_init_from_buffer(&writer, &in, __FUNCTION__); uint64_t length; length = ClientEncryptedValue->len; CHECK_AND_GOTO(mc_writer_write_u64(&writer, length, status)); CHECK_AND_GOTO(mc_writer_write_buffer(&writer, ClientEncryptedValue, ClientEncryptedValue->len, status)); CHECK_AND_GOTO(mc_writer_write_u64(&writer, index_tokens->counter, status)); CHECK_AND_GOTO(mc_writer_write_prfblock_buffer(&writer, &index_tokens->edc, status)); CHECK_AND_GOTO(mc_writer_write_prfblock_buffer(&writer, &index_tokens->esc, status)); CHECK_AND_GOTO(mc_writer_write_prfblock_buffer(&writer, &index_tokens->ecc, status)); const _mongocrypt_buffer_t *token_buf = mc_ServerDataEncryptionLevel1Token_get(token); uint32_t bytes_written; CHECK_AND_GOTO(_mongocrypt_random(crypto, &iv, MONGOCRYPT_IV_LEN, status)); CHECK_AND_GOTO(fle2alg->do_encrypt(crypto, &iv, NULL /* aad */, token_buf, &in, out, &bytes_written, status)); ok = true; cleanup: _mongocrypt_buffer_cleanup(&iv); _mongocrypt_buffer_cleanup(&in); return ok; #undef CHECK_AND_GOTO } bool mc_FLE2IndexedEncryptedValue_parse(mc_FLE2IndexedEncryptedValue_t *iev, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(buf); if (iev->parsed) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_parse must not be called twice"); return false; } mc_reader_t reader; mc_reader_init_from_buffer(&reader, buf, __FUNCTION__); CHECK_AND_RETURN(mc_reader_read_u8(&reader, &iev->fle_blob_subtype, status)); if (iev->fle_blob_subtype != MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue && iev->fle_blob_subtype != MC_SUBTYPE_FLE2IndexedRangeEncryptedValue) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_parse expected " "fle_blob_subtype %d or %d got: %" PRIu8, MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue, MC_SUBTYPE_FLE2IndexedRangeEncryptedValue, iev->fle_blob_subtype); return false; } /* Read S_KeyId. */ CHECK_AND_RETURN(mc_reader_read_uuid_buffer(&reader, &iev->S_KeyId, status)); /* Read original_bson_type. */ CHECK_AND_RETURN(mc_reader_read_u8(&reader, &iev->original_bson_type, status)); /* Read InnerEncrypted. */ CHECK_AND_RETURN(mc_reader_read_buffer_to_end(&reader, &iev->InnerEncrypted, status)); iev->parsed = true; return true; } const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValue_get_S_KeyId(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (!iev->parsed) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_get_S_KeyId must be " "called after mc_FLE2IndexedEncryptedValue_parse"); return NULL; } return &iev->S_KeyId; } static bool mc_FLE2IndexedEncryptedValue_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValue_t *iev, mc_ServerDataEncryptionLevel1Token_t *token, mc_FLE2IndexedEqualityEncryptedValueTokens *indexed_tokens, mongocrypt_status_t *status); bool mc_FLE2IndexedEncryptedValue_add_S_Key(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValue_t *iev, const _mongocrypt_buffer_t *S_Key, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(S_Key); /* Attempt to decrypt InnerEncrypted */ if (S_Key->len != MONGOCRYPT_KEY_LEN) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_add_S_Key expected " "S_Key to be %d bytes, got: %" PRIu32, MONGOCRYPT_KEY_LEN, S_Key->len); return false; } /* Get the TokenKey from the last 32 bytes of S_Key */ _mongocrypt_buffer_t TokenKey; if (!_mongocrypt_buffer_from_subrange(&TokenKey, S_Key, S_Key->len - MONGOCRYPT_TOKEN_KEY_LEN, MONGOCRYPT_TOKEN_KEY_LEN)) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_add_S_Key unable to " "parse TokenKey from S_Key"); return false; } /* Use TokenKey to create ServerDataEncryptionLevel1Token and decrypt * InnerEncrypted. */ mc_ServerDataEncryptionLevel1Token_t *token = mc_ServerDataEncryptionLevel1Token_new(crypto, &TokenKey, status); if (!token) { return false; } bool ret = mc_FLE2IndexedEncryptedValue_decrypt(crypto, iev, token, NULL, status); mc_ServerDataEncryptionLevel1Token_destroy(token); return ret; } static bool mc_FLE2IndexedEncryptedValue_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValue_t *iev, mc_ServerDataEncryptionLevel1Token_t *token, mc_FLE2IndexedEqualityEncryptedValueTokens *indexed_tokens, mongocrypt_status_t *status) { const _mongocrypt_value_encryption_algorithm_t *fle2alg = _mcFLE2Algorithm(); BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(token); if (!iev->parsed) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_decrypt must be " "called after mc_FLE2IndexedEncryptedValue_parse"); return false; } if (iev->inner_decrypted) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_decrypt must not be " "called twice"); return false; } const _mongocrypt_buffer_t *token_buf = mc_ServerDataEncryptionLevel1Token_get(token); uint32_t bytes_written; _mongocrypt_buffer_resize(&iev->Inner, fle2alg->get_plaintext_len(iev->InnerEncrypted.len, status)); /* Decrypt InnerEncrypted. */ if (!fle2alg->do_decrypt(crypto, NULL /* aad */, token_buf, &iev->InnerEncrypted, &iev->Inner, &bytes_written, status)) { return false; } mc_reader_t reader; mc_reader_init_from_buffer(&reader, &iev->Inner, __FUNCTION__); /* Parse Inner for K_KeyId. */ uint64_t length; /* length is sizeof(K_KeyId) + ClientEncryptedValue_length. */ CHECK_AND_RETURN(mc_reader_read_u64(&reader, &length, status)); /* Read K_KeyId. */ CHECK_AND_RETURN(mc_reader_read_uuid_buffer(&reader, &iev->K_KeyId, status)); /* Read ClientEncryptedValue. */ uint64_t expected_length = mc_reader_get_consumed_length(&reader) + length - 16; if (length > iev->Inner.len || expected_length > iev->Inner.len) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_decrypt expected " "byte length >= %" PRIu64 " got: %" PRIu32, expected_length, iev->Inner.len); return false; } CHECK_AND_RETURN(mc_reader_read_buffer(&reader, &iev->ClientEncryptedValue, length - 16, status)); // Caller has asked us to parse the other tokens if (indexed_tokens != NULL) { CHECK_AND_RETURN(mc_reader_read_u64(&reader, &indexed_tokens->counter, status)); CHECK_AND_RETURN(mc_reader_read_prfblock_buffer(&reader, &indexed_tokens->edc, status)); CHECK_AND_RETURN(mc_reader_read_prfblock_buffer(&reader, &indexed_tokens->esc, status)); CHECK_AND_RETURN(mc_reader_read_prfblock_buffer(&reader, &indexed_tokens->ecc, status)); } iev->inner_decrypted = true; return true; } bool mc_FLE2IndexedEncryptedValue_decrypt_equality(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValue_t *iev, mc_ServerDataEncryptionLevel1Token_t *token, mc_FLE2IndexedEqualityEncryptedValueTokens *indexed_tokens, mongocrypt_status_t *status) { BSON_ASSERT(iev->fle_blob_subtype == MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue); return mc_FLE2IndexedEncryptedValue_decrypt(crypto, iev, token, indexed_tokens, status); } const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValue_get_K_KeyId(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (!iev->inner_decrypted) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_get_K_KeyId must be called " "after mc_FLE2IndexedEncryptedValue_add_S_Key"); return NULL; } return &iev->K_KeyId; } bool mc_FLE2IndexedEncryptedValue_add_K_Key(_mongocrypt_crypto_t *crypto, mc_FLE2IndexedEncryptedValue_t *iev, const _mongocrypt_buffer_t *K_Key, mongocrypt_status_t *status) { const _mongocrypt_value_encryption_algorithm_t *fle2aead = _mcFLE2AEADAlgorithm(); BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(iev); BSON_ASSERT_PARAM(K_Key); if (!iev->inner_decrypted) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_add_K_Key must be called after " "mc_FLE2IndexedEncryptedValue_add_S_Key"); return false; } if (iev->client_value_decrypted) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_add_K_Key must not be " "called twice"); return false; } /* Attempt to decrypt ClientEncryptedValue */ _mongocrypt_buffer_resize(&iev->ClientValue, fle2aead->get_plaintext_len(iev->ClientEncryptedValue.len, status)); uint32_t bytes_written; if (!fle2aead->do_decrypt(crypto, &iev->K_KeyId, K_Key, &iev->ClientEncryptedValue, &iev->ClientValue, &bytes_written, status)) { return false; } iev->client_value_decrypted = true; return true; } const _mongocrypt_buffer_t * mc_FLE2IndexedEncryptedValue_get_ClientEncryptedValue(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); return &iev->ClientEncryptedValue; } const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValue_get_ClientValue(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (!iev->client_value_decrypted) { CLIENT_ERR("mc_FLE2IndexedEqualityEncryptedValue_getClientValue must be called " "after mc_FLE2IndexedEncryptedValue_add_K_Key"); return NULL; } return &iev->ClientValue; } void mc_FLE2IndexedEncryptedValue_destroy(mc_FLE2IndexedEncryptedValue_t *iev) { if (!iev) { return; } _mongocrypt_buffer_cleanup(&iev->S_KeyId); _mongocrypt_buffer_cleanup(&iev->InnerEncrypted); _mongocrypt_buffer_cleanup(&iev->Inner); _mongocrypt_buffer_cleanup(&iev->K_KeyId); _mongocrypt_buffer_cleanup(&iev->ClientValue); _mongocrypt_buffer_cleanup(&iev->ClientEncryptedValue); bson_free(iev); } void mc_FLE2IndexedEqualityEncryptedValueTokens_destroy(mc_FLE2IndexedEqualityEncryptedValueTokens *tokens) { if (!tokens) { return; } _mongocrypt_buffer_cleanup(&tokens->edc); _mongocrypt_buffer_cleanup(&tokens->esc); _mongocrypt_buffer_cleanup(&tokens->ecc); bson_free(tokens); } bson_type_t mc_FLE2IndexedEncryptedValue_get_original_bson_type(const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(iev); if (!iev->parsed) { CLIENT_ERR("mc_FLE2IndexedEncryptedValue_get_original_bson_type must be " "called after mc_FLE2IndexedEncryptedValue_parse"); return 0; } return iev->original_bson_type; } mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-uev-common-private.h0000644000175100001660000000730014760300420023163 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_COMMON_PRIVATE_H #define MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_COMMON_PRIVATE_H #include "mc-fle-blob-subtype-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt-crypto-private.h" #include "mongocrypt-status-private.h" /** * Deserializes the data in @buf and assigns the parsed values to * to the output parameters. * Callers are expected to call _mongocrypt_buffer_init() on the * @key_uuid and @ciphertext output buffers prior to this call, and * call _mongocrypt_buffer_cleanup() afterwards. * Returns false and sets @status on error. */ bool _mc_FLE2UnindexedEncryptedValueCommon_parse(const _mongocrypt_buffer_t *buf, uint8_t *fle_blob_subtype, uint8_t *original_bson_type, _mongocrypt_buffer_t *key_uuid, _mongocrypt_buffer_t *ciphertext, mongocrypt_status_t *status); /** * Decrypts @ciphertext onto the @plaintext buffer. The @plaintext * pointer is returned on success. The @fle_blob_subtype must be an * unindexed type, and determines the decryption algorithm to use. * Returns NULL and sets @status on error. */ const _mongocrypt_buffer_t *_mc_FLE2UnindexedEncryptedValueCommon_decrypt(_mongocrypt_crypto_t *crypto, mc_fle_blob_subtype_t fle_blob_subtype, const _mongocrypt_buffer_t *key_uuid, bson_type_t original_bson_type, const _mongocrypt_buffer_t *ciphertext, const _mongocrypt_buffer_t *key, _mongocrypt_buffer_t *plaintext, mongocrypt_status_t *status); /** * Encrypts @plaintext onto the @out buffer. The @fle_blob_subtype must * be an unindexed type, and determines the encryption algorithm to use. * Returns false and sets @status on error. */ bool _mc_FLE2UnindexedEncryptedValueCommon_encrypt(_mongocrypt_crypto_t *crypto, mc_fle_blob_subtype_t fle_blob_subtype, const _mongocrypt_buffer_t *key_uuid, bson_type_t original_bson_type, const _mongocrypt_buffer_t *plaintext, const _mongocrypt_buffer_t *key, _mongocrypt_buffer_t *out, mongocrypt_status_t *status); #endif /* MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_COMMON_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-uev-common.c0000644000175100001660000001735214760300420021516 0ustar /* * Copyright 2023-present MongoDB, 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. */ #include "mc-fle2-payload-uev-common-private.h" #include "mc-reader-private.h" #include "mongocrypt-private.h" #define CHECK_AND_RETURN(x) \ if (!(x)) { \ return false; \ } bool _mc_FLE2UnindexedEncryptedValueCommon_parse(const _mongocrypt_buffer_t *buf, uint8_t *fle_blob_subtype, uint8_t *original_bson_type, _mongocrypt_buffer_t *key_uuid, _mongocrypt_buffer_t *ciphertext, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(fle_blob_subtype); BSON_ASSERT_PARAM(original_bson_type); BSON_ASSERT_PARAM(key_uuid); BSON_ASSERT_PARAM(ciphertext); mc_reader_t reader; mc_reader_init_from_buffer(&reader, buf, __FUNCTION__); /* Read fle_blob_subtype. */ CHECK_AND_RETURN(mc_reader_read_u8(&reader, fle_blob_subtype, status)); /* Read key_uuid. */ CHECK_AND_RETURN(mc_reader_read_buffer(&reader, key_uuid, 16, status)); key_uuid->subtype = BSON_SUBTYPE_UUID; /* Read original_bson_type. */ CHECK_AND_RETURN(mc_reader_read_u8(&reader, original_bson_type, status)); /* Read ciphertext. */ CHECK_AND_RETURN(mc_reader_read_buffer(&reader, ciphertext, mc_reader_get_remaining_length(&reader), status)); return true; } const _mongocrypt_buffer_t *_mc_FLE2UnindexedEncryptedValueCommon_decrypt(_mongocrypt_crypto_t *crypto, mc_fle_blob_subtype_t fle_blob_subtype, const _mongocrypt_buffer_t *key_uuid, bson_type_t original_bson_type, const _mongocrypt_buffer_t *ciphertext, const _mongocrypt_buffer_t *key, _mongocrypt_buffer_t *plaintext, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(key_uuid); BSON_ASSERT_PARAM(ciphertext); BSON_ASSERT_PARAM(key); BSON_ASSERT_PARAM(plaintext); BSON_ASSERT(MC_SUBTYPE_FLE2UnindexedEncryptedValue == fle_blob_subtype || MC_SUBTYPE_FLE2UnindexedEncryptedValueV2 == fle_blob_subtype); const _mongocrypt_value_encryption_algorithm_t *fle2aead = (MC_SUBTYPE_FLE2UnindexedEncryptedValue == fle_blob_subtype) ? _mcFLE2AEADAlgorithm() : _mcFLE2v2AEADAlgorithm(); /* Serialize associated data: fle_blob_subtype || key_uuid || * original_bson_type */ _mongocrypt_buffer_t AD; _mongocrypt_buffer_init(&AD); if (key_uuid->len > UINT32_MAX - 2) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValueCommon_decrypt expected " "key UUID length <= %" PRIu32 " got: %" PRIu32, UINT32_MAX - 2u, key_uuid->len); return NULL; } _mongocrypt_buffer_resize(&AD, 1 + key_uuid->len + 1); AD.data[0] = (uint8_t)fle_blob_subtype; memcpy(AD.data + 1, key_uuid->data, key_uuid->len); AD.data[1 + key_uuid->len] = (uint8_t)original_bson_type; const uint32_t plaintext_len = fle2aead->get_plaintext_len(ciphertext->len, status); if (plaintext_len == 0) { _mongocrypt_buffer_cleanup(&AD); return NULL; } _mongocrypt_buffer_resize(plaintext, plaintext_len); uint32_t bytes_written; if (!fle2aead->do_decrypt(crypto, &AD, key, ciphertext, plaintext, &bytes_written, status)) { _mongocrypt_buffer_cleanup(&AD); return NULL; } // Some block cipher modes (eg. CBC) may write fewer bytes than the size // estimate that the plaintext buffer was allocated with. Therefore, the // plaintext buffer length must be updated to the actual size written. plaintext->len = bytes_written; _mongocrypt_buffer_cleanup(&AD); return plaintext; } bool _mc_FLE2UnindexedEncryptedValueCommon_encrypt(_mongocrypt_crypto_t *crypto, mc_fle_blob_subtype_t fle_blob_subtype, const _mongocrypt_buffer_t *key_uuid, bson_type_t original_bson_type, const _mongocrypt_buffer_t *plaintext, const _mongocrypt_buffer_t *key, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { _mongocrypt_buffer_t iv = {0}; _mongocrypt_buffer_t AD = {0}; bool res = false; BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(key_uuid); BSON_ASSERT_PARAM(plaintext); BSON_ASSERT_PARAM(key); BSON_ASSERT_PARAM(out); BSON_ASSERT(MC_SUBTYPE_FLE2UnindexedEncryptedValue == fle_blob_subtype || MC_SUBTYPE_FLE2UnindexedEncryptedValueV2 == fle_blob_subtype); const _mongocrypt_value_encryption_algorithm_t *fle2aead = (MC_SUBTYPE_FLE2UnindexedEncryptedValue == fle_blob_subtype) ? _mcFLE2AEADAlgorithm() : _mcFLE2v2AEADAlgorithm(); _mongocrypt_buffer_resize(&iv, MONGOCRYPT_IV_LEN); if (!_mongocrypt_random(crypto, &iv, MONGOCRYPT_IV_LEN, status)) { goto fail; } /* Serialize associated data: fle_blob_subtype || key_uuid || * original_bson_type */ { if (key_uuid->len > UINT32_MAX - 2) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValueCommon_encrypt expected " "key UUID length <= %" PRIu32 " got: %" PRIu32, UINT32_MAX - 2u, key_uuid->len); goto fail; } _mongocrypt_buffer_resize(&AD, 1 + key_uuid->len + 1); AD.data[0] = (uint8_t)fle_blob_subtype; memcpy(AD.data + 1, key_uuid->data, key_uuid->len); AD.data[1 + key_uuid->len] = (uint8_t)original_bson_type; } /* Encrypt. */ { const uint32_t cipherlen = fle2aead->get_ciphertext_len(plaintext->len, status); if (cipherlen == 0) { goto fail; } _mongocrypt_buffer_resize(out, cipherlen); uint32_t bytes_written; /* unused. */ if (!fle2aead->do_encrypt(crypto, &iv, &AD, key, plaintext, out, &bytes_written, status)) { goto fail; } } res = true; fail: _mongocrypt_buffer_cleanup(&AD); _mongocrypt_buffer_cleanup(&iv); return res; } mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-uev-private.h0000644000175100001660000000772414760300420021707 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_PRIVATE_H #define MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_PRIVATE_H #include "mongocrypt-buffer-private.h" #include "mongocrypt-crypto-private.h" #include "mongocrypt-status-private.h" /** * FLE2UnindexedEncryptedValue represents an FLE2 unindexed encrypted value. * It is created client side. * * FLE2UnindexedEncryptedValue has the following data layout: * * struct { * uint8_t fle_blob_subtype = 6; * uint8_t key_uuid[16]; * uint8_t original_bson_type; * uint8_t ciphertext[ciphertext_length]; * } FLE2UnindexedEncryptedValue; * * ciphertext is the output of: * EncryptAEAD_AES_256_CTR_HMAC_SHA_256( * key=K_Key, * plaintext=ClientValue, * associated_data=(fle_blob_subtype || key_uuid || original_bson_type)) */ typedef struct _mc_FLE2UnindexedEncryptedValue_t mc_FLE2UnindexedEncryptedValue_t; mc_FLE2UnindexedEncryptedValue_t *mc_FLE2UnindexedEncryptedValue_new(void); bool mc_FLE2UnindexedEncryptedValue_parse(mc_FLE2UnindexedEncryptedValue_t *uev, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); /* mc_FLE2UnindexedEncryptedValue_get_original_bson_type returns * original_bson_type. Returns 0 and sets @status on error. * It is an error to call before mc_FLE2UnindexedEncryptedValue_parse. */ bson_type_t mc_FLE2UnindexedEncryptedValue_get_original_bson_type(const mc_FLE2UnindexedEncryptedValue_t *uev, mongocrypt_status_t *status); /* mc_FLE2UnindexedEncryptedValue_get_key_uuid returns key_uuid. Returns * NULL and sets @status on error. It is an error to call before * mc_FLE2UnindexedEncryptedValue_parse. */ const _mongocrypt_buffer_t *mc_FLE2UnindexedEncryptedValue_get_key_uuid(const mc_FLE2UnindexedEncryptedValue_t *uev, mongocrypt_status_t *status); /* mc_FLE2UnindexedEncryptedValue_decrypt decrypts ciphertext. * Returns NULL and sets @status on error. It is an error to call before * mc_FLE2UnindexedEncryptedValue_parse. */ const _mongocrypt_buffer_t *mc_FLE2UnindexedEncryptedValue_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2UnindexedEncryptedValue_t *uev, const _mongocrypt_buffer_t *key, mongocrypt_status_t *status); /* mc_FLE2UnindexedEncryptedValue_encrypt outputs the ciphertext field of * FLEUnindexedEncryptedValue into @out. Returns false and sets @status on * error. */ bool mc_FLE2UnindexedEncryptedValue_encrypt(_mongocrypt_crypto_t *crypto, const _mongocrypt_buffer_t *key_uuid, bson_type_t original_bson_type, const _mongocrypt_buffer_t *plaintext, const _mongocrypt_buffer_t *key, _mongocrypt_buffer_t *out, mongocrypt_status_t *status); void mc_FLE2UnindexedEncryptedValue_destroy(mc_FLE2UnindexedEncryptedValue_t *uev); #endif /* MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-uev-v2-private.h0000644000175100001660000001007614760300420022226 0ustar /* * Copyright 2023-present MongoDB, 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. */ #ifndef MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_V2_PRIVATE_H #define MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_V2_PRIVATE_H #include "mongocrypt-buffer-private.h" #include "mongocrypt-crypto-private.h" #include "mongocrypt-status-private.h" /** * FLE2UnindexedEncryptedValueV2 represents a FLE2 protocol version 2 * unindexed encrypted value. It is created client side. * * FLE2UnindexedEncryptedValueV2 has the following data layout: * * struct { * uint8_t fle_blob_subtype = 16; * uint8_t key_uuid[16]; * uint8_t original_bson_type; * uint8_t ciphertext[ciphertext_length]; * } FLE2UnindexedEncryptedValueV2; * * ciphertext is the output of: * EncryptAEAD_AES_256_CBC_HMAC_SHA_256( * key=K_Key, * plaintext=ClientValue, * associated_data=(fle_blob_subtype || key_uuid || original_bson_type)) */ typedef struct _mc_FLE2UnindexedEncryptedValueV2_t mc_FLE2UnindexedEncryptedValueV2_t; mc_FLE2UnindexedEncryptedValueV2_t *mc_FLE2UnindexedEncryptedValueV2_new(void); bool mc_FLE2UnindexedEncryptedValueV2_parse(mc_FLE2UnindexedEncryptedValueV2_t *uev, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); /* mc_FLE2UnindexedEncryptedValueV2_get_original_bson_type returns * original_bson_type. Returns 0 and sets @status on error. * It is an error to call before mc_FLE2UnindexedEncryptedValueV2_parse. */ bson_type_t mc_FLE2UnindexedEncryptedValueV2_get_original_bson_type(const mc_FLE2UnindexedEncryptedValueV2_t *uev, mongocrypt_status_t *status); /* mc_FLE2UnindexedEncryptedValueV2_get_key_uuid returns key_uuid. Returns * NULL and sets @status on error. It is an error to call before * mc_FLE2UnindexedEncryptedValueV2_parse. */ const _mongocrypt_buffer_t *mc_FLE2UnindexedEncryptedValueV2_get_key_uuid(const mc_FLE2UnindexedEncryptedValueV2_t *uev, mongocrypt_status_t *status); /* mc_FLE2UnindexedEncryptedValueV2_decrypt decrypts ciphertext. * Returns NULL and sets @status on error. It is an error to call before * mc_FLE2UnindexedEncryptedValueV2_parse. */ const _mongocrypt_buffer_t *mc_FLE2UnindexedEncryptedValueV2_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2UnindexedEncryptedValueV2_t *uev, const _mongocrypt_buffer_t *key, mongocrypt_status_t *status); /* mc_FLE2UnindexedEncryptedValueV2_encrypt outputs the ciphertext field of * FLEUnindexedEncryptedValueV2 into @out. Returns false and sets @status on * error. */ bool mc_FLE2UnindexedEncryptedValueV2_encrypt(_mongocrypt_crypto_t *crypto, const _mongocrypt_buffer_t *key_uuid, bson_type_t original_bson_type, const _mongocrypt_buffer_t *plaintext, const _mongocrypt_buffer_t *key, _mongocrypt_buffer_t *out, mongocrypt_status_t *status); void mc_FLE2UnindexedEncryptedValueV2_destroy(mc_FLE2UnindexedEncryptedValueV2_t *uev); #endif /* MONGOCRYPT_FLE2_UNINDEXED_ENCRYPTED_VALUE_V2_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-uev-v2.c0000644000175100001660000001374114760300420020553 0ustar /* * Copyright 2023-present MongoDB, 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. */ #include "mc-fle2-payload-uev-common-private.h" #include "mc-fle2-payload-uev-v2-private.h" #include "mongocrypt-private.h" struct _mc_FLE2UnindexedEncryptedValueV2_t { _mongocrypt_buffer_t key_uuid; uint8_t original_bson_type; _mongocrypt_buffer_t ciphertext; _mongocrypt_buffer_t plaintext; bool parsed; }; mc_FLE2UnindexedEncryptedValueV2_t *mc_FLE2UnindexedEncryptedValueV2_new(void) { mc_FLE2UnindexedEncryptedValueV2_t *uev = bson_malloc0(sizeof(mc_FLE2UnindexedEncryptedValueV2_t)); return uev; } bool mc_FLE2UnindexedEncryptedValueV2_parse(mc_FLE2UnindexedEncryptedValueV2_t *uev, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(uev); BSON_ASSERT_PARAM(buf); if (uev->parsed) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValueV2_parse must not be called twice"); return false; } uint8_t fle_blob_subtype; if (!_mc_FLE2UnindexedEncryptedValueCommon_parse(buf, &fle_blob_subtype, &uev->original_bson_type, &uev->key_uuid, &uev->ciphertext, status)) { return false; } if (MC_SUBTYPE_FLE2UnindexedEncryptedValueV2 != fle_blob_subtype) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValueV2_parse expected " "fle_blob_subtype=%d got: %" PRIu8, MC_SUBTYPE_FLE2UnindexedEncryptedValueV2, fle_blob_subtype); return false; } uev->parsed = true; return true; } bson_type_t mc_FLE2UnindexedEncryptedValueV2_get_original_bson_type(const mc_FLE2UnindexedEncryptedValueV2_t *uev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(uev); if (!uev->parsed) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValueV2_get_original_bson_type must be " "called after mc_FLE2UnindexedEncryptedValueV2_parse"); return 0; } return uev->original_bson_type; } const _mongocrypt_buffer_t *mc_FLE2UnindexedEncryptedValueV2_get_key_uuid(const mc_FLE2UnindexedEncryptedValueV2_t *uev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(uev); if (!uev->parsed) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValueV2_get_key_uuid must be " "called after mc_FLE2UnindexedEncryptedValueV2_parse"); return NULL; } return &uev->key_uuid; } const _mongocrypt_buffer_t *mc_FLE2UnindexedEncryptedValueV2_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2UnindexedEncryptedValueV2_t *uev, const _mongocrypt_buffer_t *key, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(uev); BSON_ASSERT_PARAM(key); if (!uev->parsed) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValueV2_decrypt must be " "called after mc_FLE2UnindexedEncryptedValueV2_parse"); return NULL; } return _mc_FLE2UnindexedEncryptedValueCommon_decrypt(crypto, MC_SUBTYPE_FLE2UnindexedEncryptedValueV2, &uev->key_uuid, uev->original_bson_type, &uev->ciphertext, key, &uev->plaintext, status); } bool mc_FLE2UnindexedEncryptedValueV2_encrypt(_mongocrypt_crypto_t *crypto, const _mongocrypt_buffer_t *key_uuid, bson_type_t original_bson_type, const _mongocrypt_buffer_t *plaintext, const _mongocrypt_buffer_t *key, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { return _mc_FLE2UnindexedEncryptedValueCommon_encrypt(crypto, MC_SUBTYPE_FLE2UnindexedEncryptedValueV2, key_uuid, original_bson_type, plaintext, key, out, status); } void mc_FLE2UnindexedEncryptedValueV2_destroy(mc_FLE2UnindexedEncryptedValueV2_t *uev) { if (NULL == uev) { return; } _mongocrypt_buffer_cleanup(&uev->key_uuid); _mongocrypt_buffer_cleanup(&uev->ciphertext); _mongocrypt_buffer_cleanup(&uev->plaintext); bson_free(uev); } mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-payload-uev.c0000644000175100001660000001361414760300420020225 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mc-fle2-payload-uev-common-private.h" #include "mc-fle2-payload-uev-private.h" #include "mongocrypt-private.h" struct _mc_FLE2UnindexedEncryptedValue_t { _mongocrypt_buffer_t key_uuid; uint8_t original_bson_type; _mongocrypt_buffer_t ciphertext; _mongocrypt_buffer_t plaintext; bool parsed; }; mc_FLE2UnindexedEncryptedValue_t *mc_FLE2UnindexedEncryptedValue_new(void) { mc_FLE2UnindexedEncryptedValue_t *uev = bson_malloc0(sizeof(mc_FLE2UnindexedEncryptedValue_t)); return uev; } bool mc_FLE2UnindexedEncryptedValue_parse(mc_FLE2UnindexedEncryptedValue_t *uev, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(uev); BSON_ASSERT_PARAM(buf); if (uev->parsed) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValue_parse must not be called twice"); return false; } uint8_t fle_blob_subtype; if (!_mc_FLE2UnindexedEncryptedValueCommon_parse(buf, &fle_blob_subtype, &uev->original_bson_type, &uev->key_uuid, &uev->ciphertext, status)) { return false; } if (fle_blob_subtype != MC_SUBTYPE_FLE2UnindexedEncryptedValue) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValue_parse expected " "fle_blob_subtype=%d got: %" PRIu8, MC_SUBTYPE_FLE2UnindexedEncryptedValue, fle_blob_subtype); return false; } uev->parsed = true; return true; } bson_type_t mc_FLE2UnindexedEncryptedValue_get_original_bson_type(const mc_FLE2UnindexedEncryptedValue_t *uev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(uev); if (!uev->parsed) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValue_get_original_bson_type must be " "called after mc_FLE2UnindexedEncryptedValue_parse"); return 0; } return uev->original_bson_type; } const _mongocrypt_buffer_t *mc_FLE2UnindexedEncryptedValue_get_key_uuid(const mc_FLE2UnindexedEncryptedValue_t *uev, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(uev); if (!uev->parsed) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValue_get_key_uuid must be " "called after mc_FLE2UnindexedEncryptedValue_parse"); return NULL; } return &uev->key_uuid; } const _mongocrypt_buffer_t *mc_FLE2UnindexedEncryptedValue_decrypt(_mongocrypt_crypto_t *crypto, mc_FLE2UnindexedEncryptedValue_t *uev, const _mongocrypt_buffer_t *key, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(uev); BSON_ASSERT_PARAM(key); if (!uev->parsed) { CLIENT_ERR("mc_FLE2UnindexedEncryptedValue_decrypt must be " "called after mc_FLE2UnindexedEncryptedValue_parse"); return NULL; } return _mc_FLE2UnindexedEncryptedValueCommon_decrypt(crypto, MC_SUBTYPE_FLE2UnindexedEncryptedValue, &uev->key_uuid, uev->original_bson_type, &uev->ciphertext, key, &uev->plaintext, status); } bool mc_FLE2UnindexedEncryptedValue_encrypt(_mongocrypt_crypto_t *crypto, const _mongocrypt_buffer_t *key_uuid, bson_type_t original_bson_type, const _mongocrypt_buffer_t *plaintext, const _mongocrypt_buffer_t *key, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { return _mc_FLE2UnindexedEncryptedValueCommon_encrypt(crypto, MC_SUBTYPE_FLE2UnindexedEncryptedValue, key_uuid, original_bson_type, plaintext, key, out, status); } void mc_FLE2UnindexedEncryptedValue_destroy(mc_FLE2UnindexedEncryptedValue_t *uev) { if (NULL == uev) { return; } _mongocrypt_buffer_cleanup(&uev->key_uuid); _mongocrypt_buffer_cleanup(&uev->ciphertext); _mongocrypt_buffer_cleanup(&uev->plaintext); bson_free(uev); } mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-range-operator-private.h0000644000175100001660000000202314760300420022371 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_FLE2_RANGE_OPERATOR_PRIVATE_H #define MC_FLE2_RANGE_OPERATOR_PRIVATE_H typedef enum { FLE2RangeOperator_kNone = 0, FLE2RangeOperator_kGt = 1, FLE2RangeOperator_kGte = 2, FLE2RangeOperator_kLt = 3, FLE2RangeOperator_kLte = 4, FLE2RangeOperator_min_val = FLE2RangeOperator_kNone, FLE2RangeOperator_max_val = FLE2RangeOperator_kLte } mc_FLE2RangeOperator_t; #endif // MC_FLE2_RANGE_OPERATOR_PRIVATE_H mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-rfds-private.h0000644000175100001660000000754214760300420020415 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mc-fle2-range-operator-private.h" #include "mc-rangeopts-private.h" #include "mongocrypt-buffer-private.h" #include #include typedef struct { const char *field; struct { bool set; bson_iter_t value; bool included; } lower; struct { bool set; bson_iter_t value; bool included; } upper; bool isAggregateExpression; int nOps; mc_FLE2RangeOperator_t firstOp; mc_FLE2RangeOperator_t secondOp; } mc_FLE2RangeFindDriverSpec_t; // `mc_FLE2RangeFindDriverSpec_t` inherits extended alignment from libbson. To dynamically allocate, use // aligned allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_FLE2RangeFindDriverSpec_t, BSON_ALIGNOF(mc_FLE2RangeFindDriverSpec_t) >= BSON_ALIGNOF(bson_iter_t)); // mc_FLE2RangeFindDriverSpec_parse parses a FLE2RangeFindDriverSpec document. bool mc_FLE2RangeFindDriverSpec_parse(mc_FLE2RangeFindDriverSpec_t *spec, const bson_t *in, mongocrypt_status_t *status); // mc_FLE2RangeFindDriverSpec_to_placeholders creates a new document with // placeholders to encrypt. // // `out` must be initialized by caller. bool mc_FLE2RangeFindDriverSpec_to_placeholders(mc_FLE2RangeFindDriverSpec_t *spec, const mc_RangeOpts_t *range_opts, int64_t maxContentionFactor, const _mongocrypt_buffer_t *user_key_id, const _mongocrypt_buffer_t *index_key_id, int32_t payloadId, bson_t *out, mongocrypt_status_t *status); typedef struct { // isStub is true when edgesInfo is not appended. bool isStub; const _mongocrypt_buffer_t *user_key_id; const _mongocrypt_buffer_t *index_key_id; bson_iter_t lowerBound; bool lbIncluded; bson_iter_t upperBound; bool ubIncluded; int32_t payloadId; mc_FLE2RangeOperator_t firstOp; mc_FLE2RangeOperator_t secondOp; bson_iter_t indexMin; bson_iter_t indexMax; int64_t maxContentionFactor; int64_t sparsity; mc_optional_int32_t precision; mc_optional_int32_t trimFactor; } mc_makeRangeFindPlaceholder_args_t; // `mc_makeRangeFindPlaceholder_args_t` inherits extended alignment from libbson. To dynamically allocate, use // aligned allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_makeRangeFindPlaceholder_args_t, BSON_ALIGNOF(mc_makeRangeFindPlaceholder_args_t) >= BSON_ALIGNOF(bson_iter_t)); // mc_makeRangeFindPlaceholder creates a placeholder to be consumed by // libmongocrypt to encrypt a range find query. It is included in the header to // be used by tests. bool mc_makeRangeFindPlaceholder(mc_makeRangeFindPlaceholder_args_t *args, _mongocrypt_buffer_t *out, mongocrypt_status_t *status); // mc_getNextPayloadId returns a payload ID. It is thread safe. It resets to 0 // after reaching INT32_MAX. int32_t mc_getNextPayloadId(void); mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-rfds.c0000644000175100001660000005344014760300420016736 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mc-fle2-rfds-private.h" #include "mc-check-conversions-private.h" #include "mc-fle-blob-subtype-private.h" // MC_SUBTYPE_FLE2EncryptionPlaceholder #include "mongocrypt-private.h" // CLIENT_ERR #include "mlib/thread.h" // mlib_once_flag #include // INFINITY static mc_FLE2RangeOperator_t get_operator_type(const char *key) { BSON_ASSERT_PARAM(key); if (0 == strcmp(key, "$gt")) { return FLE2RangeOperator_kGt; } else if (0 == strcmp(key, "$gte")) { return FLE2RangeOperator_kGte; } else if (0 == strcmp(key, "$lt")) { return FLE2RangeOperator_kLt; } else if (0 == strcmp(key, "$lte")) { return FLE2RangeOperator_kLte; } else { return FLE2RangeOperator_kNone; } } static const char *mc_FLE2RangeOperator_to_string(mc_FLE2RangeOperator_t op) { switch (op) { case FLE2RangeOperator_kGt: return "$gt"; case FLE2RangeOperator_kGte: return "$gte"; case FLE2RangeOperator_kLt: return "$lt"; case FLE2RangeOperator_kLte: return "$lte"; case FLE2RangeOperator_kNone: return "none"; default: return "Unknown"; } } static bool is_supported_operator(const char *key) { BSON_ASSERT_PARAM(key); return get_operator_type(key) != FLE2RangeOperator_kNone; } // Suffix an error message with the JSON string form of bson. #define ERR_WITH_BSON(bson, fmt, ...) \ if (1) { \ char *_str = bson_as_canonical_extended_json((bson), NULL); \ CLIENT_ERR(fmt ": %s", __VA_ARGS__, _str); \ bson_free(_str); \ } else \ (void)0 // Parses a document like {$and: []} and outputs an iterator to the array. static bool parse_and(const bson_t *in, bson_iter_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(in); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); bson_iter_t and = {0}; if (!bson_iter_init(&and, in) || !bson_iter_next(&and) || 0 != strcmp(bson_iter_key(&and), "$and")) { ERR_WITH_BSON(in, "%s", "error unable to find '$and'"); return false; } if (!BSON_ITER_HOLDS_ARRAY(&and)) { ERR_WITH_BSON(in, "%s", "expected '$and' to be array"); return false; } *out = and; if (bson_iter_next(&and)) { ERR_WITH_BSON(in, "unexpected extra key '%s' after '$and'", bson_iter_key(&and)); return false; } return true; } typedef struct { const char *op_type_str; const char *field; bson_iter_t value; mc_FLE2RangeOperator_t op_type; } operator_value_t; // Parses a document like {$gt: ["$age", 5]}. static bool parse_aggregate_expression(const bson_t *orig, bson_iter_t *in, operator_value_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(orig); BSON_ASSERT_PARAM(in); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); bson_iter_t array = {0}, value; const char *op_type_str = bson_iter_key(in); bool ok = false; const char *field; if (!BSON_ITER_HOLDS_ARRAY(in)) { ERR_WITH_BSON(orig, "%s", "expected argument to be array"); goto fail; } if (!bson_iter_recurse(in, &array)) { ERR_WITH_BSON(orig, "%s", "failed to recurse into array"); goto fail; } // Expect exactly 2 elements, like ["$age", 5]. The first element is the // field path. The second element is the value. if (!bson_iter_next(&array)) { ERR_WITH_BSON(orig, "expected 2 elements in operand %s, got 0", op_type_str); goto fail; } if (!BSON_ITER_HOLDS_UTF8(&array)) { ERR_WITH_BSON(orig, "expected UTF-8 as first element in %s", op_type_str); goto fail; } field = bson_iter_utf8(&array, NULL); if (!bson_iter_next(&array)) { ERR_WITH_BSON(orig, "expected 2 elements in operand %s, got 1", op_type_str); goto fail; } value = array; if (bson_iter_next(&array)) { ERR_WITH_BSON(orig, "expected 2 elements in operand %s, got > 2", op_type_str); goto fail; } *out = (operator_value_t){ .field = field, .op_type_str = op_type_str, .op_type = get_operator_type(op_type_str), .value = value, }; ok = true; fail: return ok; } // Parses a document like {age: {$gt: 5}}. static bool parse_match_expression(const bson_t *orig, bson_iter_t *in, operator_value_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(orig); BSON_ASSERT_PARAM(in); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); bson_iter_t document = {0}, value; const char *op_type_str; bool ok = false; const char *field = bson_iter_key(in); if (!BSON_ITER_HOLDS_DOCUMENT(in)) { ERR_WITH_BSON(orig, "%s", "expected argument to be document"); goto fail; } if (!bson_iter_recurse(in, &document)) { ERR_WITH_BSON(orig, "%s", "failed to recurse into document"); goto fail; } // Expect exactly 1 elements, like {$gt: 5}. if (!bson_iter_next(&document)) { ERR_WITH_BSON(orig, "expected 1 elements in operand %s, got 0", field); goto fail; } op_type_str = bson_iter_key(&document); if (!is_supported_operator(op_type_str)) { ERR_WITH_BSON(orig, "unsupported operator: %s", op_type_str); goto fail; } value = document; if (bson_iter_next(&document)) { ERR_WITH_BSON(orig, "expected 1 elements in operand %s, got > 1", field); goto fail; } *out = (operator_value_t){ .field = field, .op_type_str = op_type_str, .op_type = get_operator_type(op_type_str), .value = value, }; ok = true; fail: return ok; } bool mc_FLE2RangeFindDriverSpec_parse(mc_FLE2RangeFindDriverSpec_t *spec, const bson_t *in, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(in); BSON_ASSERT(status || true); *spec = (mc_FLE2RangeFindDriverSpec_t){0}; // `in` may be an Aggregate Expression with this form: // {$and: [{$gt: ["$age", 5]}, {$lt:["$age", 50]}]} // Or `in` may be a Match Expression with this form: // {$and: [{age: {$gt: 5}}, {age: {$lt: 50}} ]} bson_iter_t and = {0}, array = {0}; bool ok = false; if (!parse_and(in, &and, status)) { goto fail; } // Iterate over array elements. if (!bson_iter_recurse(&and, &array)) { ERR_WITH_BSON(in, "%s", "failed to recurse into '$and'"); goto fail; } enum { UNKNOWN, MATCH_EXPRESSION, AGGREGATE_EXPRESSION } arg_type = UNKNOWN; while (bson_iter_next(&array)) { bson_iter_t doc; if (!BSON_ITER_HOLDS_DOCUMENT(&array)) { ERR_WITH_BSON(in, "%s", "expected document in '$and' array"); goto fail; } if (!bson_iter_recurse(&array, &doc)) { ERR_WITH_BSON(in, "%s", "failed to recurse into '$and' element"); goto fail; } if (!bson_iter_next(&doc)) { ERR_WITH_BSON(in, "%s", "unexpected empty '$and' array document"); goto fail; } if (arg_type == UNKNOWN) { // Attempt to determine argument type by inspecting first key. if (is_supported_operator(bson_iter_key(&doc))) { // Assume the document is part of an Aggregate Expression, like: // {$gt: ["$age", 5]} arg_type = AGGREGATE_EXPRESSION; spec->isAggregateExpression = true; } else { // Assume the document is part of a Match Expression, like: // {age: {$gt: 5}} arg_type = MATCH_EXPRESSION; } } operator_value_t op = {0}; switch (arg_type) { case AGGREGATE_EXPRESSION: if (!parse_aggregate_expression(in, &doc, &op, status)) { goto fail; } break; case MATCH_EXPRESSION: if (!parse_match_expression(in, &doc, &op, status)) { goto fail; } break; case UNKNOWN: default: ERR_WITH_BSON(in, "%s", "unexpected unknown expression type"); goto fail; } switch (op.op_type) { case FLE2RangeOperator_kGt: case FLE2RangeOperator_kGte: if (spec->lower.set) { ERR_WITH_BSON(in, "unexpected duplicate bound %s", op.op_type_str); goto fail; } spec->lower.set = true; spec->lower.value = op.value; spec->lower.included = op.op_type == FLE2RangeOperator_kGte; break; case FLE2RangeOperator_kLt: case FLE2RangeOperator_kLte: if (spec->upper.set) { ERR_WITH_BSON(in, "unexpected duplicate bound %s", op.op_type_str); goto fail; } spec->upper.set = true; spec->upper.value = op.value; spec->upper.included = op.op_type == FLE2RangeOperator_kLte; break; case FLE2RangeOperator_kNone: default: ERR_WITH_BSON(in, "unsupported operator type %s", op.op_type_str); goto fail; break; } if (spec->field && 0 != strcmp(spec->field, op.field)) { ERR_WITH_BSON(in, "unexpected field mismatch. Expected all fields to be " "%s, but got %s", spec->field, op.field); goto fail; } spec->nOps++; switch (spec->nOps) { case 1: spec->firstOp = op.op_type; break; case 2: spec->secondOp = op.op_type; break; default: ERR_WITH_BSON(in, "expected 1 or 2 operators, got > 2: %s", op.op_type_str); goto fail; } spec->field = op.field; } ok = true; fail: return ok; } // mc_makeRangeFindPlaceholder creates a placeholder to be consumed by // libmongocrypt for encryption. bool mc_makeRangeFindPlaceholder(mc_makeRangeFindPlaceholder_args_t *args, _mongocrypt_buffer_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(args); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); bool ok = false; bson_t *edgesInfo = bson_new(); bson_t *v = bson_new(); bson_t *p = bson_new(); _mongocrypt_buffer_init(out); #define TRY(stmt) \ if (!(stmt)) { \ CLIENT_ERR("error appending BSON for placeholder"); \ goto fail; \ } // create edgesInfo. if (!args->isStub) { TRY(bson_append_iter(edgesInfo, "lowerBound", -1, &args->lowerBound)); TRY(BSON_APPEND_BOOL(edgesInfo, "lbIncluded", args->lbIncluded)); TRY(bson_append_iter(edgesInfo, "upperBound", -1, &args->upperBound)); TRY(BSON_APPEND_BOOL(edgesInfo, "ubIncluded", args->ubIncluded)); TRY(bson_append_iter(edgesInfo, "indexMin", -1, &args->indexMin)); TRY(bson_append_iter(edgesInfo, "indexMax", -1, &args->indexMax)); if (args->precision.set) { TRY(BSON_APPEND_INT32(edgesInfo, "precision", args->precision.value)); } if (args->trimFactor.set) { TRY(BSON_APPEND_INT32(edgesInfo, "trimFactor", args->trimFactor.value)); } TRY(BSON_APPEND_DOCUMENT(v, "edgesInfo", edgesInfo)); } // create v. TRY(BSON_APPEND_INT32(v, "payloadId", args->payloadId)); TRY(BSON_APPEND_INT32(v, "firstOperator", (int32_t)args->firstOp)); if (args->secondOp) { TRY(BSON_APPEND_INT32(v, "secondOperator", (int32_t)args->secondOp)); } // create placeholder. TRY(BSON_APPEND_INT32(p, "t", MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND)); TRY(BSON_APPEND_INT32(p, "a", MONGOCRYPT_FLE2_ALGORITHM_RANGE)); TRY(_mongocrypt_buffer_append(args->index_key_id, p, "ki", 2)); TRY(_mongocrypt_buffer_append(args->user_key_id, p, "ku", 2)); TRY(BSON_APPEND_DOCUMENT(p, "v", v)); TRY(BSON_APPEND_INT64(p, "cm", args->maxContentionFactor)); TRY(BSON_APPEND_INT64(p, "s", args->sparsity)); #undef TRY BSON_ASSERT(p->len < UINT32_MAX); _mongocrypt_buffer_resize(out, p->len + 1u); out->subtype = BSON_SUBTYPE_ENCRYPTED; out->data[0] = MC_SUBTYPE_FLE2EncryptionPlaceholder; memcpy(out->data + 1, bson_get_data(p), p->len); ok = true; fail: bson_destroy(p); bson_destroy(v); bson_destroy(edgesInfo); return ok; } bool mc_FLE2RangeFindDriverSpec_to_placeholders(mc_FLE2RangeFindDriverSpec_t *spec, const mc_RangeOpts_t *range_opts, int64_t maxContentionFactor, const _mongocrypt_buffer_t *user_key_id, const _mongocrypt_buffer_t *index_key_id, int32_t payloadId, bson_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(spec); BSON_ASSERT_PARAM(range_opts); BSON_ASSERT_PARAM(user_key_id); BSON_ASSERT_PARAM(index_key_id); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); _mongocrypt_buffer_t p1 = {0}, p2 = {0}; bson_t infDoc = BSON_INITIALIZER; bson_iter_t negInf, posInf; bson_t minMaxDoc = BSON_INITIALIZER; bson_iter_t indexMin, indexMax; bool ok = false; BCON_APPEND(&infDoc, "p", BCON_DOUBLE(INFINITY), "n", BCON_DOUBLE(-INFINITY)); #define TRY(stmt) \ if (!(stmt)) { \ CLIENT_ERR("error transforming BSON for FLE2RangeFindDriverSpec: %s", #stmt); \ goto fail; \ } TRY(bson_iter_init_find(&posInf, &infDoc, "p")); TRY(bson_iter_init_find(&negInf, &infDoc, "n")); // Apply default index min/max values. { bson_type_t index_type; if (spec->lower.set) { index_type = bson_iter_type(&spec->lower.value); } else if (spec->upper.set) { index_type = bson_iter_type(&spec->upper.value); } else { CLIENT_ERR("expected lower or upper bound to be set"); goto fail; } if (!mc_RangeOpts_appendMin(range_opts, index_type, "indexMin", &minMaxDoc, status)) { goto fail; } if (!mc_RangeOpts_appendMax(range_opts, index_type, "indexMax", &minMaxDoc, status)) { goto fail; } TRY(bson_iter_init_find(&indexMin, &minMaxDoc, "indexMin")); TRY(bson_iter_init_find(&indexMax, &minMaxDoc, "indexMax")); } mc_makeRangeFindPlaceholder_args_t args = {.isStub = false, .user_key_id = user_key_id, .index_key_id = index_key_id, .lowerBound = spec->lower.set ? spec->lower.value : negInf, .lbIncluded = spec->lower.set ? spec->lower.included : true, .upperBound = spec->upper.set ? spec->upper.value : posInf, .ubIncluded = spec->upper.set ? spec->upper.included : true, .payloadId = payloadId, .firstOp = spec->firstOp, .secondOp = spec->secondOp, .indexMin = indexMin, .indexMax = indexMax, .precision = range_opts->precision, .maxContentionFactor = maxContentionFactor, .sparsity = range_opts->sparsity, .trimFactor = range_opts->trimFactor}; // First operator is the non-stub. if (!mc_makeRangeFindPlaceholder(&args, &p1, status)) { goto fail; } // Second operator (if required) is a stub. if (spec->nOps == 2) { mc_makeRangeFindPlaceholder_args_t args = {.isStub = true, .user_key_id = user_key_id, .index_key_id = index_key_id, .payloadId = payloadId, .firstOp = spec->firstOp, .secondOp = spec->secondOp, .maxContentionFactor = maxContentionFactor, .sparsity = range_opts->sparsity}; // First operator is the non-stub. if (!mc_makeRangeFindPlaceholder(&args, &p2, status)) { goto fail; } } if (spec->isAggregateExpression) { /* Create an Aggregate Expression document like: { "$and" : [ {"$gt" : [ "$age", "" ]}, {"$lt" : [ "$age", "" ]} ] } */ bson_t and; TRY(BSON_APPEND_ARRAY_BEGIN(out, "$and", &and)); bson_t elem; TRY(BSON_APPEND_DOCUMENT_BEGIN(&and, "0", &elem)); bson_t operator; TRY(BSON_APPEND_ARRAY_BEGIN(&elem, mc_FLE2RangeOperator_to_string(spec->firstOp), &operator)); TRY(BSON_APPEND_UTF8(&operator, "0", spec->field)); TRY(_mongocrypt_buffer_append(&p1, &operator, "1", 1)); TRY(bson_append_array_end(&elem, &operator)); TRY(bson_append_document_end(&and, &elem)); if (spec->nOps == 2) { TRY(BSON_APPEND_DOCUMENT_BEGIN(&and, "1", &elem)); TRY(BSON_APPEND_ARRAY_BEGIN(&elem, mc_FLE2RangeOperator_to_string(spec->secondOp), &operator)); TRY(BSON_APPEND_UTF8(&operator, "0", spec->field)); TRY(_mongocrypt_buffer_append(&p2, &operator, "1", 1)); TRY(bson_append_array_end(&elem, &operator)); TRY(bson_append_document_end(&and, &elem)); } TRY(bson_append_array_end(out, &and)); } else { /* Create a Match Expression document like: { "$and" : [ {"age" : { "$gt": "" }}, {"age" : { "$lt": "" }} ] } */ bson_t and; TRY(BSON_APPEND_ARRAY_BEGIN(out, "$and", &and)); bson_t elem; TRY(BSON_APPEND_DOCUMENT_BEGIN(&and, "0", &elem)); bson_t operator; TRY(BSON_APPEND_DOCUMENT_BEGIN(&elem, spec->field, &operator)); const char *op_str = mc_FLE2RangeOperator_to_string(spec->firstOp); TRY(_mongocrypt_buffer_append(&p1, &operator, op_str, -1)); TRY(bson_append_document_end(&elem, &operator)); TRY(bson_append_document_end(&and, &elem)); if (spec->nOps == 2) { TRY(BSON_APPEND_DOCUMENT_BEGIN(&and, "1", &elem)); TRY(BSON_APPEND_DOCUMENT_BEGIN(&elem, spec->field, &operator)); const char *op_str = mc_FLE2RangeOperator_to_string(spec->secondOp); TRY(_mongocrypt_buffer_append(&p2, &operator, op_str, -1)); TRY(bson_append_document_end(&elem, &operator)); TRY(bson_append_document_end(&and, &elem)); } TRY(bson_append_array_end(out, &and)); } #undef TRY ok = true; fail: _mongocrypt_buffer_cleanup(&p2); _mongocrypt_buffer_cleanup(&p1); bson_destroy(&minMaxDoc); bson_destroy(&infDoc); return ok; } static mlib_once_flag payloadId_init_flag = MLIB_ONCE_INITIALIZER; static mongocrypt_mutex_t payloadId_mutex; static int32_t payloadId = 0; static void payloadId_init_mutex(void) { _mongocrypt_mutex_init(&payloadId_mutex); } void mc_reset_payloadId_for_testing(void) { mlib_call_once(&payloadId_init_flag, payloadId_init_mutex); MONGOCRYPT_WITH_MUTEX(payloadId_mutex) { payloadId = 0; } } // mc_getNextPayloadId is thread safe. int32_t mc_getNextPayloadId(void) { mlib_call_once(&payloadId_init_flag, payloadId_init_mutex); int32_t ret; MONGOCRYPT_WITH_MUTEX(payloadId_mutex) { ret = payloadId; payloadId = payloadId < INT32_MAX ? payloadId + 1 : 0; } return ret; } mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-tag-and-encrypted-metadata-block-private.h0000644000175100001660000000335014760300420025624 0ustar /* * Copyright 2024-present MongoDB, 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. */ #ifndef MC_FLE2_TAG_AND_ENCRYPTED_METADATA_BLOCK_H #define MC_FLE2_TAG_AND_ENCRYPTED_METADATA_BLOCK_H #include "mc-reader-private.h" #include "mc-writer-private.h" #include "mongocrypt-private.h" typedef struct { _mongocrypt_buffer_t encryptedCount; _mongocrypt_buffer_t tag; _mongocrypt_buffer_t encryptedZeros; } mc_FLE2TagAndEncryptedMetadataBlock_t; #define kFieldLen 32U void mc_FLE2TagAndEncryptedMetadataBlock_init(mc_FLE2TagAndEncryptedMetadataBlock_t *metadata); void mc_FLE2TagAndEncryptedMetadataBlock_cleanup(mc_FLE2TagAndEncryptedMetadataBlock_t *metadata); bool mc_FLE2TagAndEncryptedMetadataBlock_parse(mc_FLE2TagAndEncryptedMetadataBlock_t *metadata, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); bool mc_FLE2TagAndEncryptedMetadataBlock_serialize(const mc_FLE2TagAndEncryptedMetadataBlock_t *metadata, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); #endif /* MC_FLE2_TAG_AND_ENCRYPTED_METADATA_BLOCK_H */mongodb-1.21.0/src/libmongocrypt/src/mc-fle2-tag-and-encrypted-metadata-block.c0000644000175100001660000000634214760300420024153 0ustar /* * Copyright 2024-present MongoDB, 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. */ #include "mc-fle2-tag-and-encrypted-metadata-block-private.h" #include "mc-reader-private.h" #include "mc-writer-private.h" #include "mongocrypt-private.h" #define CHECK_AND_RETURN(x) \ if (!(x)) { \ return false; \ } void mc_FLE2TagAndEncryptedMetadataBlock_init(mc_FLE2TagAndEncryptedMetadataBlock_t *metadata) { BSON_ASSERT_PARAM(metadata); memset(metadata, 0, sizeof(mc_FLE2TagAndEncryptedMetadataBlock_t)); } void mc_FLE2TagAndEncryptedMetadataBlock_cleanup(mc_FLE2TagAndEncryptedMetadataBlock_t *metadata) { BSON_ASSERT_PARAM(metadata); _mongocrypt_buffer_cleanup(&metadata->encryptedCount); _mongocrypt_buffer_cleanup(&metadata->tag); _mongocrypt_buffer_cleanup(&metadata->encryptedZeros); } bool mc_FLE2TagAndEncryptedMetadataBlock_parse(mc_FLE2TagAndEncryptedMetadataBlock_t *metadata, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(metadata); BSON_ASSERT_PARAM(buf); if ((buf->data == NULL) || (buf->len == 0)) { CLIENT_ERR("Empty buffer passed to mc_FLE2IndexedEncryptedValueV2_parse"); return false; } mc_reader_t reader; mc_reader_init_from_buffer(&reader, buf, __FUNCTION__); mc_FLE2TagAndEncryptedMetadataBlock_init(metadata); CHECK_AND_RETURN(mc_reader_read_buffer(&reader, &metadata->encryptedCount, kFieldLen, status)); CHECK_AND_RETURN(mc_reader_read_buffer(&reader, &metadata->tag, kFieldLen, status)); CHECK_AND_RETURN(mc_reader_read_buffer(&reader, &metadata->encryptedZeros, kFieldLen, status)); return true; } bool mc_FLE2TagAndEncryptedMetadataBlock_serialize(const mc_FLE2TagAndEncryptedMetadataBlock_t *metadata, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(metadata); BSON_ASSERT_PARAM(buf); mc_writer_t writer; mc_writer_init_from_buffer(&writer, buf, __FUNCTION__); CHECK_AND_RETURN(mc_writer_write_buffer(&writer, &metadata->encryptedCount, kFieldLen, status)); CHECK_AND_RETURN(mc_writer_write_buffer(&writer, &metadata->tag, kFieldLen, status)); CHECK_AND_RETURN(mc_writer_write_buffer(&writer, &metadata->encryptedZeros, kFieldLen, status)); return true; } mongodb-1.21.0/src/libmongocrypt/src/mc-optional-private.h0000644000175100001660000000723014760300420020450 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_OPTIONAL_PRIVATE_H #define MC_OPTIONAL_PRIVATE_H #include #include #include "./mc-dec128.h" #include "./mlib/int128.h" typedef struct { bool set; bool value; } mc_optional_bool_t; #define OPT_BOOL(val) \ (mc_optional_bool_t) { .set = true, .value = val } #define OPT_BOOL_C(val) \ { .set = true, .value = val } typedef struct { bool set; int32_t value; } mc_optional_int32_t; #define OPT_I32(val) \ (mc_optional_int32_t) { .set = true, .value = val } #define OPT_I32_C(val) \ { .set = true, .value = val } typedef struct { bool set; uint32_t value; } mc_optional_uint32_t; #define OPT_U32(val) \ (mc_optional_uint32_t) { .set = true, .value = val } #define OPT_U32_C(val) \ { .set = true, .value = val } typedef struct { bool set; int64_t value; } mc_optional_int64_t; #define OPT_I64(val) \ (mc_optional_int64_t) { .set = true, .value = val } #define OPT_I64_C(val) \ { .set = true, .value = val } typedef struct { bool set; uint64_t value; } mc_optional_uint64_t; #define OPT_U64(val) \ (mc_optional_uint64_t) { .set = true, .value = val } #define OPT_U64_C(val) \ { .set = true, .value = val } typedef struct { bool set; double value; } mc_optional_double_t; #define OPT_DOUBLE(val) \ (mc_optional_double_t) { .set = true, .value = val } #define OPT_DOUBLE_C(val) \ { .set = true, .value = val } #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT typedef struct { bool set; mc_dec128 value; } mc_optional_dec128_t; #define OPT_MC_DEC128(...) \ (mc_optional_dec128_t) { .set = true, .value = __VA_ARGS__ } #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT #define OPT_NULLOPT \ { .set = false } #endif /* MC_OPTIONAL_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-range-edge-generation-private.h0000644000175100001660000001157414760300420022760 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_RANGE_EDGE_GENERATION_PRIVATE_H #define MC_RANGE_EDGE_GENERATION_PRIVATE_H #include "mc-dec128.h" #include "mc-optional-private.h" #include "mongocrypt-status-private.h" #include #include // size_t #include // mc_edges_t represents a list of edges. typedef struct _mc_edges_t mc_edges_t; // mc_edges_get returns edge at an index. // Returns NULL if `index` is out of range. const char *mc_edges_get(mc_edges_t *edges, size_t index); // mc_edges_len returns the number of represented edges. size_t mc_edges_len(mc_edges_t *edges); // mc_edges_destroys frees `edges`. void mc_edges_destroy(mc_edges_t *edges); // mc_edges_is_leaf returns whether the given edge is the leaf node of the edge set. bool mc_edges_is_leaf(const mc_edges_t *edges, const char *edge); // Return the trimFactor that was used to generate these edges. int32_t mc_edges_get_used_trimFactor(const mc_edges_t *edges); typedef struct { int32_t value; mc_optional_int32_t min; mc_optional_int32_t max; size_t sparsity; mc_optional_int32_t trimFactor; } mc_getEdgesInt32_args_t; // mc_getEdgesInt32 implements the Edge Generation algorithm described in // SERVER-67751 for int32_t. mc_edges_t *mc_getEdgesInt32(mc_getEdgesInt32_args_t args, mongocrypt_status_t *status, bool use_range_v2); typedef struct { int64_t value; mc_optional_int64_t min; mc_optional_int64_t max; size_t sparsity; mc_optional_int32_t trimFactor; } mc_getEdgesInt64_args_t; // mc_getEdgesInt64 implements the Edge Generation algorithm described in // SERVER-67751 for int64_t. mc_edges_t *mc_getEdgesInt64(mc_getEdgesInt64_args_t args, mongocrypt_status_t *status, bool use_range_v2); typedef struct { double value; size_t sparsity; mc_optional_double_t min; mc_optional_double_t max; mc_optional_int32_t precision; mc_optional_int32_t trimFactor; } mc_getEdgesDouble_args_t; // mc_getEdgesDouble implements the Edge Generation algorithm described in // SERVER-67751 for double. mc_edges_t *mc_getEdgesDouble(mc_getEdgesDouble_args_t args, mongocrypt_status_t *status, bool use_range_v2); #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT typedef struct { mc_dec128 value; size_t sparsity; mc_optional_dec128_t min, max; mc_optional_int32_t precision; mc_optional_int32_t trimFactor; } mc_getEdgesDecimal128_args_t; mc_edges_t *mc_getEdgesDecimal128(mc_getEdgesDecimal128_args_t args, mongocrypt_status_t *status, bool use_range_v2); #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT BSON_STATIC_ASSERT2(ull_is_u64, sizeof(uint64_t) == sizeof(unsigned long long)); // count_leading_zeros_u64 returns the number of leading 0 bits of `in`. static inline size_t mc_count_leading_zeros_u64(uint64_t in) { #ifdef __has_builtin #if __has_builtin(__builtin_clzll) unsigned long long ull = in; return (size_t)(in ? __builtin_clzll(ull) : 64); #endif #endif uint64_t bit = UINT64_C(1) << 63; size_t count = 0; while ((bit & in) == 0 && bit > 0) { bit >>= 1; ++count; } return count; } // count_leading_zeros_u32 returns the number of leading 0 bits of `in`. static inline size_t mc_count_leading_zeros_u32(uint32_t in) { #ifdef __has_builtin #if __has_builtin(__builtin_clz) // Pointer-cast to ensure we are speaking the right type unsigned int *p = ∈ return (size_t)(in ? __builtin_clz(*p) : 32); #endif #endif uint32_t bit = UINT32_C(1) << 31; int count = 0; while ((bit & in) == 0 && bit > 0) { bit >>= 1; ++count; } return (size_t)count; } static inline size_t mc_count_leading_zeros_u128(mlib_int128 in) { size_t hi = mc_count_leading_zeros_u64(mlib_int128_to_u64(mlib_int128_rshift(in, 64))); size_t lo = mc_count_leading_zeros_u64(mlib_int128_to_u64(in)); return hi + ((hi == 64 ? 1u : 0u) * lo); } typedef struct mc_bitstring { char str[129]; } mc_bitstring; // mc_convert_to_bitstring_u64 returns a 64 character string of 1's and 0's // representing the bits of `in` mc_bitstring mc_convert_to_bitstring_u64(uint64_t in); // mc_convert_to_bitstring_u32 returns a 32 character string of 1's and 0's // representing the bits of `in`. mc_bitstring mc_convert_to_bitstring_u32(uint32_t in); mc_bitstring mc_convert_to_bitstring_u128(mlib_int128 i); #endif /* MC_RANGE_EDGE_GENERATION_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-range-edge-generation.c0000644000175100001660000002174514760300420021304 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mc-optional-private.h" #include "mc-range-edge-generation-private.h" #include "mc-array-private.h" #include "mc-check-conversions-private.h" #include "mc-cmp-private.h" #include "mc-range-encoding-private.h" #include "mongocrypt-private.h" struct _mc_edges_t { size_t sparsity; /* edges is an array of `char*` edge strings. */ mc_array_t edges; char *leaf; int32_t usedTrimFactor; // The `trimFactor` that was used to produce these edges. }; int32_t mc_edges_get_used_trimFactor(const mc_edges_t *edges) { return edges->usedTrimFactor; } static mc_edges_t *mc_edges_new(const char *leaf, size_t sparsity, mc_optional_int32_t opt_trimFactor, mongocrypt_status_t *status, bool use_range_v2) { BSON_ASSERT_PARAM(leaf); if (sparsity < 1) { CLIENT_ERR("sparsity must be 1 or larger"); return NULL; } const size_t leaf_len = strlen(leaf); const int32_t trimFactor = trimFactorDefault(leaf_len, opt_trimFactor, use_range_v2); if (trimFactor != 0 && mc_cmp_greater_equal_su(trimFactor, leaf_len)) { // We append a total of leaf_len + 1 (for the root) - trimFactor edges. When this number is equal to 1, we // degenerate into equality, which is not desired, so trimFactor must be less than leaf_len. CLIENT_ERR("trimFactor must be less than the number of bits (%ld) used to represent an element of the domain, " "but got %" PRId32, leaf_len, trimFactor); return NULL; } if (trimFactor < 0) { CLIENT_ERR("trimFactor must be >= 0, but got %" PRId32, trimFactor); return NULL; } mc_edges_t *edges = bson_malloc0(sizeof(mc_edges_t)); edges->usedTrimFactor = trimFactor; edges->sparsity = sparsity; _mc_array_init(&edges->edges, sizeof(char *)); edges->leaf = bson_strdup(leaf); if (trimFactor == 0) { char *root = bson_strdup("root"); _mc_array_append_val(&edges->edges, root); } char *leaf_copy = bson_strdup(leaf); _mc_array_append_val(&edges->edges, leaf_copy); // Start loop at max(trimFactor, 1). The full leaf is unconditionally appended after loop. BSON_ASSERT(mc_in_range_size_t_signed(trimFactor)); size_t trimFactor_sz = (size_t)trimFactor; size_t startLevel = trimFactor > 0 ? trimFactor_sz : 1; for (size_t i = startLevel; i < leaf_len; i++) { if (i % sparsity == 0) { char *edge = bson_malloc(i + 1); bson_strncpy(edge, leaf, i + 1); _mc_array_append_val(&edges->edges, edge); } } return edges; } const char *mc_edges_get(mc_edges_t *edges, size_t index) { BSON_ASSERT_PARAM(edges); if (edges->edges.len == 0 || index > edges->edges.len - 1u) { return NULL; } return _mc_array_index(&edges->edges, char *, index); } size_t mc_edges_len(mc_edges_t *edges) { BSON_ASSERT_PARAM(edges); return edges->edges.len; } void mc_edges_destroy(mc_edges_t *edges) { if (NULL == edges) { return; } for (size_t i = 0; i < edges->edges.len; i++) { char *val = _mc_array_index(&edges->edges, char *, i); bson_free(val); } _mc_array_destroy(&edges->edges); bson_free(edges->leaf); bson_free(edges); } bool mc_edges_is_leaf(const mc_edges_t *edges, const char *edge) { BSON_ASSERT_PARAM(edges); BSON_ASSERT_PARAM(edge); return strcmp(edge, edges->leaf) == 0; } mc_bitstring mc_convert_to_bitstring_u64(uint64_t in) { mc_bitstring ret = {{0}}; char *out = ret.str; uint64_t bit = UINT64_C(1) << 63; int loops = 0; // used to determine a bit shift while (bit > 0) { *out++ = (char)('0' + ((bit & in) >> (63 - loops))); bit >>= 1; loops++; } return ret; } mc_bitstring mc_convert_to_bitstring_u32(uint32_t in) { mc_bitstring ret = {{0}}; char *out = ret.str; uint32_t bit = UINT32_C(1) << 31; while (bit > 0) { if (bit & in) { *out++ = '1'; } else { *out++ = '0'; } bit >>= 1; } return ret; } mc_bitstring mc_convert_to_bitstring_u128(mlib_int128 i) { const uint64_t lo = mlib_int128_to_u64(i); const uint64_t hi = mlib_int128_to_u64(mlib_int128_rshift(i, 64)); mc_bitstring his = mc_convert_to_bitstring_u64(hi); mc_bitstring los = mc_convert_to_bitstring_u64(lo); mc_bitstring ret = {{0}}; const size_t off = mlib_strnmcopy(ret.str, sizeof ret.str, his.str, sizeof his.str); mlib_strnmcopy(ret.str + off, (sizeof ret.str) - off, los.str, sizeof los.str); return ret; } mc_edges_t *mc_getEdgesInt32(mc_getEdgesInt32_args_t args, mongocrypt_status_t *status, bool use_range_v2) { mc_OSTType_Int32 got; if (!mc_getTypeInfo32((mc_getTypeInfo32_args_t){.value = args.value, .min = args.min, .max = args.max}, &got, status)) { return NULL; } // `max` is the domain of values. `max` is used to determine the maximum bit // length. `min` is expected to be zero. The `min` and `max` terms are kept // for consistency with the server implementation. BSON_ASSERT(got.min == 0); mc_bitstring valueBin = mc_convert_to_bitstring_u32(got.value); size_t offset = mc_count_leading_zeros_u32(got.max); const char *leaf = valueBin.str + offset; mc_edges_t *ret = mc_edges_new(leaf, args.sparsity, args.trimFactor, status, use_range_v2); return ret; } mc_edges_t *mc_getEdgesInt64(mc_getEdgesInt64_args_t args, mongocrypt_status_t *status, bool use_range_v2) { mc_OSTType_Int64 got; if (!mc_getTypeInfo64((mc_getTypeInfo64_args_t){.value = args.value, .min = args.min, .max = args.max}, &got, status)) { return NULL; } // `max` is the domain of values. `max` is used to determine the maximum bit // length. `min` is expected to be zero. The `min` and `max` terms are kept // for consistency with the server implementation. BSON_ASSERT(got.min == 0); mc_bitstring valueBin = mc_convert_to_bitstring_u64(got.value); size_t offset = mc_count_leading_zeros_u64(got.max); const char *leaf = valueBin.str + offset; mc_edges_t *ret = mc_edges_new(leaf, args.sparsity, args.trimFactor, status, use_range_v2); return ret; } mc_edges_t *mc_getEdgesDouble(mc_getEdgesDouble_args_t args, mongocrypt_status_t *status, bool use_range_v2) { mc_OSTType_Double got; if (!mc_getTypeInfoDouble((mc_getTypeInfoDouble_args_t){.value = args.value, .min = args.min, .max = args.max, .precision = args.precision}, &got, status, use_range_v2)) { return NULL; } // `max` is the domain of values. `max` is used to determine the maximum bit // length. `min` is expected to be zero. The `min` and `max` terms are kept // for consistency with the server implementation. BSON_ASSERT(got.min == 0); mc_bitstring valueBin = mc_convert_to_bitstring_u64(got.value); size_t offset = mc_count_leading_zeros_u64(got.max); const char *leaf = valueBin.str + offset; mc_edges_t *ret = mc_edges_new(leaf, args.sparsity, args.trimFactor, status, use_range_v2); return ret; } #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT mc_edges_t *mc_getEdgesDecimal128(mc_getEdgesDecimal128_args_t args, mongocrypt_status_t *status, bool use_range_v2) { mc_OSTType_Decimal128 got; if (!mc_getTypeInfoDecimal128( (mc_getTypeInfoDecimal128_args_t){ .value = args.value, .min = args.min, .max = args.max, .precision = args.precision, }, &got, status, use_range_v2)) { return NULL; } BSON_ASSERT(mlib_int128_eq(got.min, MLIB_INT128(0))); mc_bitstring bits = mc_convert_to_bitstring_u128(got.value); size_t offset = mc_count_leading_zeros_u128(got.max); const char *leaf = bits.str + offset; mc_edges_t *ret = mc_edges_new(leaf, args.sparsity, args.trimFactor, status, use_range_v2); return ret; } #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT mongodb-1.21.0/src/libmongocrypt/src/mc-range-encoding-private.h0000644000175100001660000001145714760300420021511 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_RANGE_ENCODING_PRIVATE_H #define MC_RANGE_ENCODING_PRIVATE_H #include "mc-dec128.h" #include "mc-optional-private.h" #include "mongocrypt-status-private.h" #include #include /* mc-range-encoding-private.h has functions to encode numeric types for * Queryable Encryption Range queries. It is a translation from server code: * https://github.com/mongodb/mongo/blob/1364f5c5004ac5503837ac5b315c189625f97269/src/mongo/crypto/fle_crypto.h#L1194-L1196 * "OST" is an abbreviation taken from server code. It stands for "Outsourced * STate". */ /* mc_OSTType_Int32 describes the encoding of a BSON int32. */ typedef struct { uint32_t value; uint32_t min; uint32_t max; } mc_OSTType_Int32; typedef struct { int32_t value; mc_optional_int32_t min; mc_optional_int32_t max; } mc_getTypeInfo32_args_t; /* mc_getTypeInfo32 encodes the int32_t `args.value` into an OSTType_Int32 * `out`. `args.min` and `args.max` may be unset. Returns false and sets * `status` on error. */ bool mc_getTypeInfo32(mc_getTypeInfo32_args_t args, mc_OSTType_Int32 *out, mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT; /* mc_OSTType_Int64 describes the encoding of a BSON int64. */ typedef struct { uint64_t value; uint64_t min; uint64_t max; } mc_OSTType_Int64; typedef struct { int64_t value; mc_optional_int64_t min; mc_optional_int64_t max; } mc_getTypeInfo64_args_t; /* mc_getTypeInfo64 encodes the int64_t `args.value` into an OSTType_Int64 * `out`. `args.min` and `args.max` may be unset. Returns false and sets * `status` on error. */ bool mc_getTypeInfo64(mc_getTypeInfo64_args_t args, mc_OSTType_Int64 *out, mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT; /* mc_OSTType_Double describes the encoding of a BSON double. */ typedef struct { uint64_t value; uint64_t min; uint64_t max; } mc_OSTType_Double; typedef struct { double value; mc_optional_double_t min; mc_optional_double_t max; mc_optional_int32_t precision; } mc_getTypeInfoDouble_args_t; // `mc_canUsePrecisionModeDouble` returns true if the domain can be represented in fewer than 64 bits. bool mc_canUsePrecisionModeDouble(double min, double max, int32_t precision, uint32_t *maxBitsOut, mongocrypt_status_t *status); /* mc_getTypeInfoDouble encodes the double `args.value` into an OSTType_Double * `out`. Returns false and sets `status` on error. */ bool mc_getTypeInfoDouble(mc_getTypeInfoDouble_args_t args, mc_OSTType_Double *out, mongocrypt_status_t *status, bool use_range_v2) MONGOCRYPT_WARN_UNUSED_RESULT; #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT /** * @brief OST-encoding of a Decimal128 */ typedef struct { mlib_int128 value, min, max; } mc_OSTType_Decimal128; typedef struct { mc_dec128 value; mc_optional_dec128_t min, max; mc_optional_int32_t precision; } mc_getTypeInfoDecimal128_args_t; // `mc_canUsePrecisionModeDecimal` returns true if the domain can be represented in fewer than 128 bits. bool mc_canUsePrecisionModeDecimal(mc_dec128 min, mc_dec128 max, int32_t precision, uint32_t *maxBitsOut, mongocrypt_status_t *status); /** * @brief Obtain the OST encoding of a finite Decimal128 value. * * @param out Output for the result * @param status Output for status on error * @retval true On success * @retval false Otherwise */ bool mc_getTypeInfoDecimal128(mc_getTypeInfoDecimal128_args_t args, mc_OSTType_Decimal128 *out, mongocrypt_status_t *status, bool use_range_v2) MONGOCRYPT_WARN_UNUSED_RESULT; #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT extern const int64_t mc_FLERangeSparsityDefault; int32_t trimFactorDefault(size_t maxlen, mc_optional_int32_t trimFactor, bool use_range_v2); #endif /* MC_RANGE_ENCODING_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-range-encoding.c0000644000175100001660000007702414760300420020036 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mc-check-conversions-private.h" #include "mc-cmp-private.h" #include "mc-range-encoding-private.h" #include "mongocrypt-private.h" #include "mongocrypt-util-private.h" // mc_isinf #include // pow /* mc-range-encoding.c assumes integers are encoded with two's complement for * correctness. */ #if (-1 & 3) != 3 #error Error: Twos complement integer representation is required. #endif /** * Encode a signed 32-bit integer as an unsigned 32-bit integer by adding 2^31. * Some documentation references this as making the value "unbiased". */ static uint32_t encodeInt32(int32_t v) { // Shift the int32_t range [-2^31, 2^31 - 1] to the uint32_t range [0, 2^32]. // new_zero is the mapped 0 value. uint32_t new_zero = (UINT32_C(1) << 31); if (v < 0) { // Signed integers have a value that there is no positive equivalent and // must be handled specially if (v == INT32_MIN) { return 0; } int32_t v_pos = v * -1; uint32_t v_u32 = (uint32_t)v_pos; return new_zero - v_u32; } uint32_t v_u32 = (uint32_t)v; return new_zero + v_u32; } bool mc_getTypeInfo32(mc_getTypeInfo32_args_t args, mc_OSTType_Int32 *out, mongocrypt_status_t *status) { if (args.min.set != args.max.set) { CLIENT_ERR("Must specify both a lower and upper bound or no bounds."); return false; } if (!args.min.set) { uint32_t v_u32 = encodeInt32(args.value); *out = (mc_OSTType_Int32){v_u32, 0, UINT32_MAX}; return true; } if (args.min.value >= args.max.value) { CLIENT_ERR("The minimum value must be less than the maximum value, got " "min: %" PRId32 ", max: %" PRId32, args.min.value, args.max.value); return false; } if (args.value > args.max.value || args.value < args.min.value) { CLIENT_ERR("Value must be greater than or equal to the minimum value " "and less than or equal to the maximum value, got min: %" PRId32 ", max: %" PRId32 ", value: %" PRId32, args.min.value, args.max.value, args.value); return false; } // Convert to unbiased uint32. Then subtract the min value. uint32_t v_u32 = encodeInt32(args.value); uint32_t min_u32 = encodeInt32(args.min.value); uint32_t max_u32 = encodeInt32(args.max.value); v_u32 -= min_u32; max_u32 -= min_u32; *out = (mc_OSTType_Int32){v_u32, 0, max_u32}; return true; } /** * Encode a signed 64-bit integer as an unsigned 64-bit integer by adding 2^63. * Some documentation references this as making the value "unbiased". */ static uint64_t encodeInt64(int64_t v) { // Shift the int64_t range [-2^63, 2^63 - 1] to the uint64_t range [0, 2^64]. // new_zero is the mapped 0 value. uint64_t new_zero = (UINT64_C(1) << 63); if (v < 0) { // Signed integers have a value that there is no positive equivalent and // must be handled specially if (v == INT64_MIN) { return 0; } int64_t v_pos = v * -1; uint64_t v_u64 = (uint64_t)v_pos; return new_zero - v_u64; } uint64_t v_u64 = (uint64_t)v; return new_zero + v_u64; } bool mc_getTypeInfo64(mc_getTypeInfo64_args_t args, mc_OSTType_Int64 *out, mongocrypt_status_t *status) { if (args.min.set != args.max.set) { CLIENT_ERR("Must specify both a lower and upper bound or no bounds."); return false; } if (!args.min.set) { uint64_t v_u64 = encodeInt64(args.value); *out = (mc_OSTType_Int64){v_u64, 0, UINT64_MAX}; return true; } if (args.min.value >= args.max.value) { CLIENT_ERR("The minimum value must be less than the maximum value, got " "min: %" PRId64 ", max: %" PRId64, args.min.value, args.max.value); return false; } if (args.value > args.max.value || args.value < args.min.value) { CLIENT_ERR("Value must be greater than or equal to the minimum value " "and less than or equal to the maximum value, got " "min: %" PRId64 ", max: %" PRId64 ", value: %" PRId64, args.min.value, args.max.value, args.value); return false; } // Convert to unbiased uint64. Then subtract the min value. uint64_t v_u64 = encodeInt64(args.value); uint64_t min_u64 = encodeInt64(args.min.value); uint64_t max_u64 = encodeInt64(args.max.value); v_u64 -= min_u64; max_u64 -= min_u64; *out = (mc_OSTType_Int64){v_u64, 0, max_u64}; return true; } #define exp10Double(x) pow(10, x) #define SCALED_DOUBLE_BOUNDS 9007199254740992.0 // 2^53 uint64_t subtract_int64_t(int64_t max, int64_t min) { BSON_ASSERT(max > min); // If the values have the same sign, then simple subtraction // will work because we know max > min. if ((max > 0 && min > 0) || (max < 0 && min < 0)) { return (uint64_t)(max - min); } // If they are opposite signs, then we can just invert // min to be positive and return the sum. uint64_t u_return = (uint64_t)max; u_return += (uint64_t)(~min + 1); return u_return; } bool ceil_log2_double(uint64_t i, uint32_t *maxBitsOut, mongocrypt_status_t *status) { if (i == 0) { CLIENT_ERR("Invalid input to ceil_log2_double function. Input cannot be 0."); return false; } uint32_t clz = (uint32_t)_mlibCountLeadingZeros_u64(i); uint32_t bits; if ((i & (i - 1)) == 0) { bits = 64 - clz - 1; } else { bits = 64 - clz; } *maxBitsOut = bits; return true; } bool mc_canUsePrecisionModeDouble(double min, double max, int32_t precision, uint32_t *maxBitsOut, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(maxBitsOut); BSON_ASSERT(precision >= 0); if (min >= max) { CLIENT_ERR("Invalid bounds for double range precision, min must be less than max. min: %g, max: %g", min, max); return false; } const double scaled_prc = exp10Double(precision); const double scaled_max = max * scaled_prc; const double scaled_min = min * scaled_prc; if (scaled_max != trunc(scaled_max)) { CLIENT_ERR("Invalid upper bound for double precision. Fractional digits must be less than the specified " "precision value. max: %g", max); return false; } if (scaled_min != trunc(scaled_min)) { CLIENT_ERR("Invalid lower bound for double precision. Fractional digits must be less than the specified " "precision value. min: %g", min); return false; } if (fabs(scaled_max) >= SCALED_DOUBLE_BOUNDS) { CLIENT_ERR( "Invalid upper bound for double precision. Absolute scaled value of max must be less than %g. max: %g", SCALED_DOUBLE_BOUNDS, max); return false; } if (fabs(scaled_min) >= SCALED_DOUBLE_BOUNDS) { CLIENT_ERR( "Invalid lower bound for double precision. Absolute scaled value of min must be less than %g. min: %g", SCALED_DOUBLE_BOUNDS, min); return false; } const double t_1 = scaled_max - scaled_min; const double t_4 = (double)UINT64_MAX - t_1; const double t_5 = floor(log10(t_4)) - 1; if ((double)precision > t_5) { CLIENT_ERR("Invalid value for precision. precision: %" PRId32, precision); return false; } const int64_t i_1 = (int64_t)(scaled_max); const int64_t i_2 = (int64_t)(scaled_min); const uint64_t range = subtract_int64_t(i_1, i_2); if (((uint64_t)scaled_prc) > UINT64_MAX - range) { CLIENT_ERR("Invalid value for min, max, and precision. The calculated domain size is too large. min: %g, max: " "%g, precision: %" PRId32, min, max, precision); return false; } const uint64_t i_3 = range + (uint64_t)(scaled_prc); if (!ceil_log2_double(i_3, maxBitsOut, status)) { return false; } // Integers between -2^53 and 2^53 can be exactly represented. Outside this range, doubles lose precision by a // multiple of 2^(n-52) where n = #bits. We disallow users from using precision mode when the bounds exceed 2^53 to // prevent the users from being surprised by how floating point math works. if (*maxBitsOut >= 53) { return false; } return true; } bool mc_getTypeInfoDouble(mc_getTypeInfoDouble_args_t args, mc_OSTType_Double *out, mongocrypt_status_t *status, bool use_range_v2) { if (args.min.set != args.max.set || args.min.set != args.precision.set) { CLIENT_ERR("min, max, and precision must all be set or must all be unset"); return false; } if (mc_isinf(args.value) || mc_isnan(args.value)) { CLIENT_ERR("Infinity and NaN double values are not supported."); return false; } if (args.min.set) { if (args.min.value >= args.max.value) { CLIENT_ERR("The minimum value must be less than the maximum value, got " "min: %g, max: %g", args.min.value, args.max.value); return false; } if (args.value > args.max.value || args.value < args.min.value) { CLIENT_ERR("Value must be greater than or equal to the minimum value " "and less than or equal to the maximum value, got " "min: %g, max: %g, value: %g", args.min.value, args.max.value, args.value); return false; } } if (args.precision.set) { if (args.precision.value < 0) { CLIENT_ERR("Precision must be non-negative, but got %" PRId32, args.precision.value); return false; } double scaled = exp10Double(args.precision.value); if (!mc_isfinite(scaled)) { CLIENT_ERR("Precision is too large and cannot be used to calculate the scaled range bounds"); return false; } } const bool is_neg = args.value < 0.0; // Map negative 0 to zero so sign bit is 0. if (args.value == 0.0) { args.value = 0.0; } // When we use precision mode, we try to represent as a double value that // fits in [-2^63, 2^63] (i.e. is a valid int64) // // This check determines if we can represent the precision truncated value as // a 64-bit integer I.e. Is ((ub - lb) * 10^precision) < 64 bits. // bool use_precision_mode = false; uint32_t bits_range; if (args.precision.set) { use_precision_mode = mc_canUsePrecisionModeDouble(args.min.value, args.max.value, args.precision.value, &bits_range, status); if (!use_precision_mode && use_range_v2) { if (!mongocrypt_status_ok(status)) { return false; } CLIENT_ERR("The domain of double values specified by the min, max, and precision cannot be represented in " "fewer than 53 bits. min: %g, max: %g, precision: %" PRId32, args.min.value, args.max.value, args.precision.value); return false; } // If we are not in range_v2, then we don't care about the error returned // from canUsePrecisionMode so we can reset the status. _mongocrypt_status_reset(status); } if (use_precision_mode) { // Take a number of xxxx.ppppp and truncate it xxxx.ppp if precision = 3. // We do not change the digits before the decimal place. int64_t v_prime = (int64_t)(trunc(args.value * exp10Double(args.precision.value))); int64_t scaled_min = (int64_t)(args.min.value * exp10Double(args.precision.value)); int64_t v_prime2 = v_prime - scaled_min; BSON_ASSERT(v_prime2 < INT64_MAX && v_prime2 >= 0); uint64_t ret = (uint64_t)v_prime2; // Adjust maximum value to be the max bit range. This will be used by // getEdges/minCover to trim bits. uint64_t max_value = (UINT64_C(1) << bits_range) - 1; BSON_ASSERT(ret <= max_value); *out = (mc_OSTType_Double){ret, 0, max_value}; return true; } // Translate double to uint64 by modifying the bit representation and copying // into a uint64. Double is assumed to be a IEEE 754 Binary 64. // It is bit-encoded as sign, exponent, and fraction: // s eeeeeeee ffffffffffffffffffffffffffffffffffffffffffffffffffff // When we translate the double into "bits", the sign bit means that the // negative numbers get mapped into the higher 63 bits of a 64-bit integer. // We want them to map into the lower 64-bits so we invert the sign bit. args.value *= -1.0; // On Endianness, we support two sets of architectures // 1. Little Endian (ppc64le, x64, aarch64) - in these architectures, int64 // and double are both 64-bits and both arranged in little endian byte order. // 2. Big Endian (s390x) - in these architectures, int64 and double are both // 64-bits and both arranged in big endian byte order. // // Therefore, since the order of bytes on each platform is consistent with // itself, the conversion below converts a double into correct 64-bit integer // that produces the same behavior across plaforms. uint64_t uv; memcpy(&uv, &args.value, sizeof(uint64_t)); if (is_neg) { uint64_t new_zero = UINT64_C(1) << 63; BSON_ASSERT(uv <= new_zero); uv = new_zero - uv; } *out = (mc_OSTType_Double){.min = 0, .max = UINT64_MAX, .value = uv}; return true; } #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT /** * @brief There is no shipped algorithm for creating a full 128-bit integer from * a Decimal128, but it's easy enough to write one of our own. * * @param dec * @return mlib_int128 */ static mlib_int128 dec128_to_uint128(mc_dec128 dec) { // Only normal numbers BSON_ASSERT(mc_dec128_is_finite(dec)); BSON_ASSERT(!mc_dec128_is_nan(dec)); // We don't support negative numbers BSON_ASSERT(!mc_dec128_is_negative(dec)); // There is no fractional part: BSON_ASSERT(mc_dec128_is_zero(mc_dec128_modf(dec).frac)); mlib_int128 ret = mc_dec128_coeff(dec); // Scale the resulting number by a power of ten matching the exponent of the // Decimal128: int32_t exp = ((int32_t)mc_dec128_get_biased_exp(dec)) - MC_DEC128_EXPONENT_BIAS; // We will scale up/down based on whether it is negative: BSON_ASSERT(abs(exp) <= UINT8_MAX); mlib_int128 e1 = mlib_int128_pow10((uint8_t)abs(exp)); if (exp < 0) { ret = mlib_int128_div(ret, e1); } else { ret = mlib_int128_mul(ret, e1); } return ret; } // (2^127 - 1) = the maximum signed 128-bit integer value, as a decimal128 #define INT_128_MAX_AS_DECIMAL mc_dec128_from_string("170141183460469231731687303715884105727") // (2^128 - 1) = the max unsigned 128-bit integer value, as a decimal128 #define UINT_128_MAX_AS_DECIMAL mc_dec128_from_string("340282366920938463463374607431768211455") static mlib_int128 dec128_to_int128(mc_dec128 dec) { BSON_ASSERT(mc_dec128_less(dec, INT_128_MAX_AS_DECIMAL)); bool negative = false; if (mc_dec128_is_negative(dec)) { negative = true; dec = mc_dec128_mul(MC_DEC128(-1), dec); } mlib_int128 ret_val = dec128_to_uint128(dec); if (negative) { ret_val = mlib_int128_mul(MLIB_INT128(-1), ret_val); } return ret_val; } bool ceil_log2_int128(mlib_int128 i, uint32_t *maxBitsOut, mongocrypt_status_t *status) { if (mlib_int128_eq(i, MLIB_INT128(0))) { CLIENT_ERR("Invalid input to ceil_log2_int128 function. Input cannot be 0."); return false; } uint32_t clz = (uint32_t)_mlibCountLeadingZeros_u128(i); uint32_t bits; // if i & (i - 1) == 0 if (mlib_int128_eq((mlib_int128_bitand(i, (mlib_int128_sub(i, MLIB_INT128(1))))), MLIB_INT128(0))) { bits = 128 - clz - 1; } else { bits = 128 - clz; } *maxBitsOut = bits; return true; } bool mc_canUsePrecisionModeDecimal(mc_dec128 min, mc_dec128 max, int32_t precision, uint32_t *maxBitsOut, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(maxBitsOut); BSON_ASSERT(precision >= 0); if (!mc_dec128_is_finite(max)) { CLIENT_ERR("Invalid upper bound for Decimal128 precision. Max is infinite."); return false; } if (!mc_dec128_is_finite(min)) { CLIENT_ERR("Invalid lower bound for Decimal128 precision. Min is infinite."); return false; } if (mc_dec128_greater_equal(min, max)) { CLIENT_ERR("Invalid upper and lower bounds for Decimal128 precision. Min must be strictly less than max. min: " "%s, max: %s", mc_dec128_to_string(min).str, mc_dec128_to_string(max).str); return false; } mc_dec128 scaled_max = mc_dec128_scale(max, precision); mc_dec128 scaled_min = mc_dec128_scale(min, precision); mc_dec128 scaled_max_trunc = mc_dec128_round_integral_ex(scaled_max, MC_DEC128_ROUND_TOWARD_ZERO, NULL); mc_dec128 scaled_min_trunc = mc_dec128_round_integral_ex(scaled_min, MC_DEC128_ROUND_TOWARD_ZERO, NULL); if (mc_dec128_not_equal(scaled_max, scaled_max_trunc)) { CLIENT_ERR("Invalid upper bound for Decimal128 precision. Fractional digits must be less than " "the specified precision value. max: %s, precision: %" PRId32, mc_dec128_to_string(max).str, precision); return false; } if (mc_dec128_not_equal(scaled_min, scaled_min_trunc)) { CLIENT_ERR("Invalid lower bound for Decimal128 precision. Fractional digits must be less than " "the specified precision value. min: %s, precision: %" PRId32, mc_dec128_to_string(min).str, precision); return false; } if (mc_dec128_greater(mc_dec128_abs(scaled_max), INT_128_MAX_AS_DECIMAL)) { CLIENT_ERR("Invalid upper bound for Decimal128 precision. Absolute scaled value must be less than " "or equal to %s. max: %s", mc_dec128_to_string(INT_128_MAX_AS_DECIMAL).str, mc_dec128_to_string(max).str); return false; } if (mc_dec128_greater(mc_dec128_abs(scaled_min), INT_128_MAX_AS_DECIMAL)) { CLIENT_ERR("Invalid lower bound for Decimal128 precision. Absolute scaled value must be less than " "or equal to %s. min: %s", mc_dec128_to_string(INT_128_MAX_AS_DECIMAL).str, mc_dec128_to_string(min).str); return false; } mc_dec128 t_1 = mc_dec128_sub(scaled_max, scaled_min); mc_dec128 t_4 = mc_dec128_sub(UINT_128_MAX_AS_DECIMAL, t_1); // t_5 = floor(log10(t_4)) - 1; mc_dec128 t_5 = mc_dec128_sub(mc_dec128_round_integral_ex(mc_dec128_log10(t_4), MC_DEC128_ROUND_TOWARD_ZERO, NULL), MC_DEC128(1)); // We convert precision to a double so we can avoid warning C4146 on Windows. mc_dec128 prc_dec = mc_dec128_from_double((double)precision); if (mc_dec128_less(t_5, prc_dec)) { CLIENT_ERR("Invalid value for precision. precision: %" PRId32, precision); return false; } mlib_int128 i_1 = dec128_to_int128(scaled_max); mlib_int128 i_2 = dec128_to_int128(scaled_min); // Because we have guaranteed earlier that max is greater than min, we can // subtract these values and guarantee that taking their unsigned // representation will yield the actual range result. mlib_int128 range128 = mlib_int128_sub(i_1, i_2); if (precision > UINT8_MAX) { CLIENT_ERR("Invalid value for precision. Must be less than 255. precision: %" PRId32, precision); return false; } mlib_int128 i_3 = mlib_int128_add(range128, mlib_int128_pow10((uint8_t)precision)); if (!ceil_log2_int128(i_3, maxBitsOut, status)) { return false; } if (*maxBitsOut >= 128) { return false; } return true; } bool mc_getTypeInfoDecimal128(mc_getTypeInfoDecimal128_args_t args, mc_OSTType_Decimal128 *out, mongocrypt_status_t *status, bool use_range_v2) { /// Basic param checks if (args.min.set != args.max.set || args.min.set != args.precision.set) { CLIENT_ERR("min, max, and precision must all be set or must all be unset"); return false; } if (args.precision.set) { if (args.precision.value < 0) { CLIENT_ERR("Precision must be non-negative, but got %" PRId32, args.precision.value); return false; } mc_dec128 scaled = mc_dec128_scale(MC_DEC128(1), args.precision.value); if (!mc_dec128_is_finite(scaled)) { CLIENT_ERR("Precision is too large and cannot be used to calculate the scaled range bounds"); return false; } } // We only accept normal numbers if (mc_dec128_is_inf(args.value) || mc_dec128_is_nan(args.value)) { CLIENT_ERR("Infinity and Nan Decimal128 values are not supported."); return false; } // Check boundary if a range is set if (args.min.set) { // [min,max] must be valid if (mc_dec128_greater_equal(args.min.value, args.max.value)) { CLIENT_ERR("The minimum value must be less than the maximum value, got " "min: %s, max: %s", mc_dec128_to_string(args.min.value).str, mc_dec128_to_string(args.max.value).str); return false; } // Value must be within [min,max) if (mc_dec128_greater(args.value, args.max.value) || mc_dec128_less(args.value, args.min.value)) { CLIENT_ERR("Value must be greater than or equal to the minimum value " "and less than or equal to the maximum value, got " "min: %s, max: %s, value: %s", mc_dec128_to_string(args.min.value).str, mc_dec128_to_string(args.max.value).str, mc_dec128_to_string(args.value).str); return false; } } // Should we use precision mode? // // When we use precision mode, we try to represent as a decimal128 value that // fits in [-2^127, 2^127] (i.e. is a valid int128) // // This check determines if we can represent any precision-truncated value as // a 128-bit integer I.e. Is ((ub - lb) * 10^precision) < 128 bits. // // It is important that we determine whether a range and its precision would // fit, regardless of the value to be encoded, because the encoding for // precision-truncated-decimal128 is incompatible with the encoding of the // full range. bool use_precision_mode = false; // The number of bits required to hold the result (used for precision mode) uint32_t bits_range = 0; if (args.precision.set) { use_precision_mode = mc_canUsePrecisionModeDecimal(args.min.value, args.max.value, args.precision.value, &bits_range, status); if (use_range_v2 && !use_precision_mode) { if (!mongocrypt_status_ok(status)) { return false; } CLIENT_ERR("The domain of decimal values specified by the min, max, and precision cannot be represented in " "fewer than 128 bits. min: %s, max: %s, precision: %" PRIu32, mc_dec128_to_string(args.min.value).str, mc_dec128_to_string(args.max.value).str, args.precision.value); return false; } // If we are not in range_v2, then we don't care about the error returned // from canUsePrecisionMode so we can reset the status. _mongocrypt_status_reset(status); } // Constant zero const mlib_int128 i128_zero = MLIB_INT128(0); // Constant 1 const mlib_int128 i128_one = MLIB_INT128(1); // Constant 10 const mlib_int128 i128_ten = MLIB_INT128(10); // Constant: 2^127 const mlib_int128 i128_2pow127 = mlib_int128_lshift(i128_one, 127); // ↑ Coincidentally has the same bit pattern as INT128_SMIN, but we're // treating it as an unsigned number here, so don't get confused! if (use_precision_mode) { BSON_ASSERT(args.precision.set); // Example value: 31.4159 // Example Precision = 2 // Shift the number up // Returns: 3141.9 mc_dec128 valScaled = mc_dec128_scale(args.value, args.precision.value); // Round the number down // Returns 3141.0 mc_dec128 valTrunc = mc_dec128_round_integral_ex(valScaled, MC_DEC128_ROUND_TOWARD_ZERO, NULL); // Shift the number down // Returns: 31.41 mc_dec128 v_prime = mc_dec128_scale(valTrunc, -(int32_t)args.precision.value); // Adjust the number by the lower bound // Make it an integer by scaling the number // // Returns 3141.0 mc_dec128 v_prime2 = mc_dec128_scale(mc_dec128_sub(v_prime, args.min.value), args.precision.value); // Round the number down again. min may have a fractional value with more // decimal places than the precision (e.g. .001). Subtracting min may have // resulted in v_prime2 with a non-zero fraction. v_prime2 is expected to // have no fractional value when converting to int128. v_prime2 = mc_dec128_round_integral_ex(v_prime2, MC_DEC128_ROUND_TOWARD_ZERO, NULL); BSON_ASSERT(mc_dec128_less(mc_dec128_log2(v_prime2), MC_DEC128(128))); BSON_ASSERT(bits_range < 128); // Resulting OST maximum mlib_int128 ost_max = mlib_int128_sub(mlib_int128_pow2((uint8_t)bits_range), i128_one); // Now we need to get the Decimal128 out as a 128-bit integer // But Decimal128 does not support conversion to Int128. // // If we think the Decimal128 fits in the range, based on the maximum // value, we try to convert to int64 directly. if (bits_range < 64) { // Try conversion to int64, it may fail but since it is easy we try // this first. mc_dec128_flagset flags = {0}; int64_t as64 = mc_dec128_to_int64_ex(v_prime2, &flags); if (flags.bits == 0) { // No error. It fits *out = (mc_OSTType_Decimal128){ .value = MLIB_INT128_CAST(as64), .min = i128_zero, .max = ost_max, }; return true; } else { // Conversion failure to 64-bit. Possible overflow, imprecision, // etc. Fallback to slower dec128_to_int128 } } mlib_int128 u_ret = dec128_to_int128(v_prime2); *out = (mc_OSTType_Decimal128){ .value = u_ret, .min = i128_zero, .max = ost_max, }; return true; } // The coefficient of the number, without exponent/sign const mlib_int128 coeff = mc_dec128_coeff(args.value); if (mlib_int128_eq(coeff, i128_zero)) { // If the coefficient is zero, the result is encoded as the midpoint // between zero and 2^128-1 *out = (mc_OSTType_Decimal128){ .value = i128_2pow127, .min = i128_zero, .max = MLIB_INT128_UMAX, }; return true; } // Coefficient is an unsigned value. We'll later scale our answer based on // the sign of the actual Decimal128 const bool isNegative = mc_dec128_is_negative(args.value); // cMax = 10^34 - 1 (The largest integer representable in Decimal128) const mlib_int128 cMax = mlib_int128_sub(mlib_int128_pow10(34), MLIB_INT128_CAST(1)); const mlib_int128 cMax_div_ten = mlib_int128_div(cMax, i128_ten); // The biased exponent from the decimal number. The paper refers to the // expression (e - e_min), which is the value of the biased exponent. const uint32_t exp_biased = mc_dec128_get_biased_exp(args.value); // Ï (rho) is the greatest integer such that: coeff×10^Ï <= cMax unsigned rho = 0; // Keep track of the subexpression coeff×10^Ï rather than recalculating it // time. // Initially: (Ï = 0) -> (10^Ï = 1) -> (coeff×10^Ï = coeff×1 = coeff): mlib_int128 coeff_scaled = coeff; // Calculate Ï: This could be done using a log10 with a division, but that // is far more work than just a few multiplications. // While: coeff×ten^Ï < cMax/10: while (mlib_int128_ucmp(coeff_scaled, cMax_div_ten) < 0) { // Increase rho until we pass cMax/10 rho++; // Scale our computed subexpression rather than fully recomputing it coeff_scaled = mlib_int128_mul(coeff_scaled, i128_ten); } // No multiplication by 10 should ever send us from N < cMax/10 to N > cMax BSON_ASSERT(mlib_int128_ucmp(coeff_scaled, cMax) <= 0); mlib_int128 result; if (rho <= exp_biased) { // Ï is less-than/equal to the exponent with bias. // Diff between the biased exponent and Ï. // Value in paper is spelled "e - e_min - Ï" const uint32_t exp_diff = exp_biased - (uint32_t)rho; // cMax * (exp_diff) const mlib_int128 cmax_scaled = mlib_int128_mul(cMax, MLIB_INT128_CAST(exp_diff)); // coeff * 10^rho * cMax * (exp_biased - rho) result = mlib_int128_add(coeff_scaled, cmax_scaled); } else { const mlib_int128 biased_scale = mlib_int128_pow10((uint8_t)exp_biased); result = mlib_int128_mul(biased_scale, coeff); } // Always add 2^127: result = mlib_int128_add(result, i128_2pow127); if (isNegative) { // We calculated the value of the positive coefficient, but the decimal is // negative. That's okay: Just flip the sign of the encoded result: result = mlib_int128_negate(result); } *out = (mc_OSTType_Decimal128){ .value = result, .min = i128_zero, .max = MLIB_INT128_UMAX, }; return true; } #endif // defined MONGOCRYPT_HAVE_DECIMAL128_SUPPORT const int64_t mc_FLERangeSparsityDefault = 2; const int32_t mc_FLERangeTrimFactorDefault = 6; int32_t trimFactorDefault(size_t maxlen, mc_optional_int32_t trimFactor, bool use_range_v2) { if (trimFactor.set) { return trimFactor.value; } if (!use_range_v2) { // Preserve old default. return 0; } if (mc_cmp_greater_su(mc_FLERangeTrimFactorDefault, maxlen - 1)) { return (int32_t)(maxlen - 1); } else { return mc_FLERangeTrimFactorDefault; } } mongodb-1.21.0/src/libmongocrypt/src/mc-range-mincover-generator.template.h0000644000175100001660000002334614760300420023673 0ustar /* * Copyright 2022-present MongoDB, 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. */ // mc-range-mincover-generator.template.h is meant to be included in another // source file. #if !(defined(UINT_T) && defined(UINT_C) && defined(UINT_FMT_S) && defined(DECORATE_NAME)) #ifdef __INTELLISENSE__ #define UINT_T uint32_t #define UINT_C UINT32_C #define UINT_FMT_S PRIu32 #define DECORATE_NAME(Name) Name##_u32 #else #error All of UINT_T, UINT_C, UINT_FMT_S, UINT_FMT_ARG, and DECORATE_NAME must be defined before #including this file #endif #endif #define BITS (sizeof(UINT_T) * CHAR_BIT) #define ZERO UINT_C(0) // Default for UINT_FMT_ARG #ifndef UINT_FMT_ARG #define UINT_FMT_ARG(X) X #endif // Default comparison #ifndef UINT_LESSTHAN #define UINT_LESSTHAN(A, B) ((A) < (B)) #endif #ifndef MC_UINT_MAX #define MC_UINT_MAX ~(UINT_C(0)) #endif // Default addition #ifndef UINT_ADD #define UINT_ADD(A, B) ((A) + (B)) #endif #ifndef UINT_SUB #define UINT_SUB(A, B) ((A) - (B)) #endif // Default lshift (also handles negatives as right-shift) #ifndef UINT_LSHIFT static inline UINT_T DECORATE_NAME(_mc_default_lshift)(UINT_T lhs, int off) { if (off < 0) { return lhs >> -off; } else { return lhs << off; } } #define UINT_LSHIFT DECORATE_NAME(_mc_default_lshift) #endif #ifndef UINT_BITOR #define UINT_BITOR(A, B) ((A) | (B)) #endif static inline int DECORATE_NAME(_mc_compare)(UINT_T lhs, UINT_T rhs) { if (UINT_LESSTHAN(lhs, rhs)) { return -1; } else if (UINT_LESSTHAN(rhs, lhs)) { return 1; } else { return 0; } } #define UINT_COMPARE DECORATE_NAME(_mc_compare) // MinCoverGenerator models the MinCoverGenerator type added in // SERVER-68600. typedef struct { UINT_T _rangeMin; UINT_T _rangeMax; size_t _sparsity; int32_t _trimFactor; // _maxlen is the maximum bit length of edges in the mincover. size_t _maxlen; } DECORATE_NAME(MinCoverGenerator); static inline DECORATE_NAME(MinCoverGenerator) * DECORATE_NAME(MinCoverGenerator_new)(UINT_T rangeMin, UINT_T rangeMax, UINT_T max, size_t sparsity, mc_optional_int32_t opt_trimFactor, mongocrypt_status_t *status, bool use_range_v2) { BSON_ASSERT_PARAM(status); if (UINT_COMPARE(rangeMin, rangeMax) > 0) { CLIENT_ERR("Range min (%" UINT_FMT_S ") must be less than or equal to range max (%" UINT_FMT_S ") for range search", UINT_FMT_ARG(rangeMin), UINT_FMT_ARG(rangeMax)); return NULL; } if (UINT_COMPARE(rangeMax, max) > 0) { CLIENT_ERR("Range max (%" UINT_FMT_S ") must be less than or equal to max (%" UINT_FMT_S ") for range search", UINT_FMT_ARG(rangeMax), UINT_FMT_ARG(max)); return NULL; } if (sparsity == 0) { CLIENT_ERR("Sparsity must be > 0"); return NULL; } size_t maxlen = (size_t)BITS - DECORATE_NAME(mc_count_leading_zeros)(max); int32_t trimFactor = trimFactorDefault(maxlen, opt_trimFactor, use_range_v2); if (trimFactor != 0 && mc_cmp_greater_equal_su(trimFactor, maxlen)) { CLIENT_ERR("Trim factor must be less than the number of bits (%ld) used to represent an element of the domain, " "but got %" PRId32, maxlen, trimFactor); return NULL; } if (trimFactor < 0) { CLIENT_ERR("Trim factor must be >= 0, but got (%" PRId32 ")", trimFactor); return NULL; } DECORATE_NAME(MinCoverGenerator) *mcg = bson_malloc0(sizeof(DECORATE_NAME(MinCoverGenerator))); mcg->_rangeMin = rangeMin; mcg->_rangeMax = rangeMax; mcg->_maxlen = (size_t)BITS - DECORATE_NAME(mc_count_leading_zeros)(max); mcg->_sparsity = sparsity; mcg->_trimFactor = trimFactor; return mcg; } static inline void DECORATE_NAME(MinCoverGenerator_destroy)(DECORATE_NAME(MinCoverGenerator) * mcg) { bson_free(mcg); } // applyMask applies a mask of 1 bits starting from the right. // Bits 0 to bit-1 are replaced with 1. Other bits are left as-is. static inline UINT_T DECORATE_NAME(applyMask)(UINT_T value, size_t maskedBits) { const UINT_T ones = MC_UINT_MAX; BSON_ASSERT(maskedBits <= (size_t)BITS); BSON_ASSERT(maskedBits >= 0); if (maskedBits == 0) { return value; } const size_t shift = ((size_t)BITS - maskedBits); const UINT_T mask = UINT_LSHIFT(ones, -(int)shift); return UINT_BITOR(value, mask); } static inline bool DECORATE_NAME(MinCoverGenerator_isLevelStored)(DECORATE_NAME(MinCoverGenerator) * mcg, size_t maskedBits) { BSON_ASSERT_PARAM(mcg); size_t level = mcg->_maxlen - maskedBits; BSON_ASSERT(mc_in_range_size_t_signed(mcg->_trimFactor)); size_t trimFactor_sz = (size_t)mcg->_trimFactor; return 0 == maskedBits || (level >= trimFactor_sz && 0 == (level % mcg->_sparsity)); } char * DECORATE_NAME(MinCoverGenerator_toString)(DECORATE_NAME(MinCoverGenerator) * mcg, UINT_T start, size_t maskedBits) { BSON_ASSERT_PARAM(mcg); BSON_ASSERT(maskedBits <= mcg->_maxlen); BSON_ASSERT(maskedBits <= (size_t)BITS); BSON_ASSERT(maskedBits >= 0); if (maskedBits == mcg->_maxlen) { return bson_strdup("root"); } UINT_T shifted = UINT_LSHIFT(start, -(int)maskedBits); mc_bitstring valueBin = DECORATE_NAME(mc_convert_to_bitstring)(shifted); char *ret = bson_strndup(valueBin.str + ((size_t)BITS - mcg->_maxlen + maskedBits), mcg->_maxlen + maskedBits); return ret; } static inline void DECORATE_NAME(MinCoverGenerator_minCoverRec)(DECORATE_NAME(MinCoverGenerator) * mcg, mc_array_t *c, UINT_T blockStart, size_t maskedBits) { BSON_ASSERT_PARAM(mcg); BSON_ASSERT_PARAM(c); const UINT_T blockEnd = DECORATE_NAME(applyMask)(blockStart, maskedBits); if (UINT_COMPARE(blockEnd, mcg->_rangeMin) < 0 || UINT_COMPARE(blockStart, mcg->_rangeMax) > 0) { return; } if (UINT_COMPARE(blockStart, mcg->_rangeMin) >= 0 && UINT_COMPARE(blockEnd, mcg->_rangeMax) <= 0 && DECORATE_NAME(MinCoverGenerator_isLevelStored)(mcg, maskedBits)) { char *edge = DECORATE_NAME(MinCoverGenerator_toString)(mcg, blockStart, maskedBits); _mc_array_append_val(c, edge); return; } BSON_ASSERT(maskedBits > 0); const size_t newBits = maskedBits - 1u; DECORATE_NAME(MinCoverGenerator_minCoverRec)(mcg, c, blockStart, newBits); DECORATE_NAME(MinCoverGenerator_minCoverRec) (mcg, c, UINT_BITOR(blockStart, UINT_LSHIFT(UINT_C(1), (int)newBits)), newBits); } static inline mc_mincover_t *DECORATE_NAME(MinCoverGenerator_minCover)(DECORATE_NAME(MinCoverGenerator) * mcg) { BSON_ASSERT_PARAM(mcg); mc_mincover_t *mc = mc_mincover_new(); DECORATE_NAME(MinCoverGenerator_minCoverRec) (mcg, &mc->mincover, ZERO, mcg->_maxlen); return mc; } static inline int32_t DECORATE_NAME(MinCoverGenerator_usedTrimFactor)(DECORATE_NAME(MinCoverGenerator) * mcg) { BSON_ASSERT_PARAM(mcg); return mcg->_trimFactor; } // adjustBounds increments *lowerBound if includeLowerBound is false and // decrements *upperBound if includeUpperBound is false. // lowerBound, min, upperBound, and max are expected to come from the result // of mc_getTypeInfo. static bool DECORATE_NAME(adjustBounds)(UINT_T *lowerBound, bool includeLowerBound, UINT_T min, UINT_T *upperBound, bool includeUpperBound, UINT_T max, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(lowerBound); BSON_ASSERT_PARAM(upperBound); if (!includeLowerBound) { if (UINT_COMPARE(*lowerBound, max) >= 0) { CLIENT_ERR("Lower bound (%" UINT_FMT_S ") must be less than the range maximum (%" UINT_FMT_S ") if lower bound is excluded from range.", UINT_FMT_ARG(*lowerBound), UINT_FMT_ARG(max)); return false; } *lowerBound = UINT_ADD(*lowerBound, UINT_C(1)); } if (!includeUpperBound) { if (UINT_COMPARE(*upperBound, min) <= 0) { CLIENT_ERR("Upper bound (%" UINT_FMT_S ") must be greater than the range minimum (%" UINT_FMT_S ") if upper bound is excluded from range.", UINT_FMT_ARG(*upperBound), UINT_FMT_ARG(min)); return false; } *upperBound = UINT_SUB(*upperBound, UINT_C(1)); } return true; } #undef UINT_T #undef UINT_C #undef UINT_FMT_S #undef UINT_FMT_ARG #undef DECORATE_NAME #undef BITS #undef UINT_COMPARE #undef UINT_ADD #undef UINT_SUB #undef UINT_LSHIFT #undef UINT_BITOR #undef MC_UINT_MAX #undef ZERO #undef UINT_LESSTHAN mongodb-1.21.0/src/libmongocrypt/src/mc-range-mincover-private.h0000644000175100001660000000772114760300420021544 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_RANGE_MINCOVER_PRIVATE_H #define MC_RANGE_MINCOVER_PRIVATE_H #include "mc-dec128.h" #include "mc-optional-private.h" #include "mongocrypt-status-private.h" #include // size_t #include // mc_mincover_t represents the results of the mincover algorithm. typedef struct _mc_mincover_t mc_mincover_t; // mc_mincover_get returns edge at an index. // Returns NULL if `index` is out of range. const char *mc_mincover_get(mc_mincover_t *mincover, size_t index); // mc_mincover_len returns the number of represented mincover. size_t mc_mincover_len(mc_mincover_t *mincover); // Return the trimFactor that was used to generate this mincover. int32_t mc_mincover_get_used_trimFactor(const mc_mincover_t *mincover); // mc_mincover_destroys frees `mincover`. void mc_mincover_destroy(mc_mincover_t *mincover); typedef struct { int32_t lowerBound; bool includeLowerBound; int32_t upperBound; bool includeUpperBound; mc_optional_int32_t min; mc_optional_int32_t max; size_t sparsity; mc_optional_int32_t trimFactor; } mc_getMincoverInt32_args_t; // mc_getMincoverInt32 implements the Mincover Generation algorithm described in // SERVER-68600 for int32_t. mc_mincover_t *mc_getMincoverInt32(mc_getMincoverInt32_args_t args, mongocrypt_status_t *status, bool use_range_v2) MONGOCRYPT_WARN_UNUSED_RESULT; typedef struct { int64_t lowerBound; bool includeLowerBound; int64_t upperBound; bool includeUpperBound; mc_optional_int64_t min; mc_optional_int64_t max; size_t sparsity; mc_optional_int32_t trimFactor; } mc_getMincoverInt64_args_t; // mc_getMincoverInt64 implements the Mincover Generation algorithm described in // SERVER-68600 for int64_t. mc_mincover_t *mc_getMincoverInt64(mc_getMincoverInt64_args_t args, mongocrypt_status_t *status, bool use_range_v2) MONGOCRYPT_WARN_UNUSED_RESULT; typedef struct { double lowerBound; bool includeLowerBound; double upperBound; bool includeUpperBound; size_t sparsity; mc_optional_double_t min; mc_optional_double_t max; mc_optional_int32_t precision; mc_optional_int32_t trimFactor; } mc_getMincoverDouble_args_t; // mc_getMincoverDouble implements the Mincover Generation algorithm described // in SERVER-68600 for double. mc_mincover_t *mc_getMincoverDouble(mc_getMincoverDouble_args_t args, mongocrypt_status_t *status, bool use_range_v2) MONGOCRYPT_WARN_UNUSED_RESULT; #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT typedef struct { mc_dec128 lowerBound; bool includeLowerBound; mc_dec128 upperBound; bool includeUpperBound; size_t sparsity; mc_optional_dec128_t min, max; mc_optional_int32_t precision; mc_optional_int32_t trimFactor; } mc_getMincoverDecimal128_args_t; // mc_getMincoverDecimal128 implements the Mincover Generation algorithm // described in SERVER-68600 for Decimal128 (as mc_dec128). mc_mincover_t *mc_getMincoverDecimal128(mc_getMincoverDecimal128_args_t args, mongocrypt_status_t *status, bool use_range_v2) MONGOCRYPT_WARN_UNUSED_RESULT; #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT #endif /* MC_RANGE_MINCOVER_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-range-mincover.c0000644000175100001660000003256314760300420020071 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include #include "mc-check-conversions-private.h" #include "mc-array-private.h" #include "mc-cmp-private.h" #include "mc-range-edge-generation-private.h" // mc_count_leading_zeros_u32 #include "mc-range-encoding-private.h" // mc_getTypeInfo32, trimFactorDefault #include "mc-range-mincover-private.h" #include "mongocrypt-private.h" struct _mc_mincover_t { /* mincover is an array of `char*` edge strings. */ mc_array_t mincover; int32_t usedTrimFactor; // The `trimFactor` that was used to produce this mincover. }; static mc_mincover_t *mc_mincover_new(void) { mc_mincover_t *mincover = bson_malloc0(sizeof(mc_mincover_t)); _mc_array_init(&mincover->mincover, sizeof(char *)); return mincover; } const char *mc_mincover_get(mc_mincover_t *mincover, size_t index) { BSON_ASSERT_PARAM(mincover); if (mincover->mincover.len == 0 || index > mincover->mincover.len - 1u) { return NULL; } return _mc_array_index(&mincover->mincover, char *, index); } size_t mc_mincover_len(mc_mincover_t *mincover) { BSON_ASSERT_PARAM(mincover); return mincover->mincover.len; } int32_t mc_mincover_get_used_trimFactor(const mc_mincover_t *mincover) { return mincover->usedTrimFactor; } void mc_mincover_destroy(mc_mincover_t *mincover) { if (NULL == mincover) { return; } for (size_t i = 0; i < mincover->mincover.len; i++) { char *val = _mc_array_index(&mincover->mincover, char *, i); bson_free(val); } _mc_array_destroy(&mincover->mincover); bson_free(mincover); } #define UINT_T uint32_t #define UINT_C UINT32_C #define UINT_FMT_S PRIu32 #define DECORATE_NAME(N) N##_u32 #include "mc-range-mincover-generator.template.h" #define UINT_T uint64_t #define UINT_C UINT64_C #define UINT_FMT_S PRIu64 #define DECORATE_NAME(N) N##_u64 #include "mc-range-mincover-generator.template.h" // The 128-bit version is only required for Decimal128, otherwise generates // unused-fn warnings #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT #define UINT_T mlib_int128 #define UINT_C MLIB_INT128 #define UINT_FMT_S "s" #define UINT_FMT_ARG(X) (mlib_int128_format(X).str) #define DECORATE_NAME(N) N##_u128 #define UINT_LESSTHAN(L, R) (mlib_int128_ucmp(L, R) < 0) #define UINT_ADD mlib_int128_add #define UINT_SUB mlib_int128_sub #define UINT_LSHIFT mlib_int128_lshift #define MC_UINT_MAX MLIB_INT128_UMAX #define UINT_BITOR mlib_int128_bitor #include "mc-range-mincover-generator.template.h" #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT // Check bounds and return an error message including the original inputs. #define IDENTITY(X) X #define LESSTHAN(L, R) ((L) < (R)) #define CHECK_BOUNDS(args, FMT, FormatArg, LessThan) \ if (1) { \ if ((args).min.set) { \ if (LessThan((args).upperBound, (args).min.value)) { \ CLIENT_ERR("Upper bound (%" FMT ") must be greater than or equal to the range minimum (%" FMT ")", \ FormatArg((args).upperBound), \ FormatArg((args).min.value)); \ return false; \ } \ if (!(args).includeUpperBound && !LessThan((args.min.value), (args.upperBound))) { \ CLIENT_ERR("Upper bound (%" FMT ") must be greater than the range minimum (%" FMT \ ") if upper bound is excluded from range", \ FormatArg((args).upperBound), \ FormatArg((args).min.value)); \ return false; \ } \ } \ if ((args).max.set) { \ if (LessThan((args).max.value, (args).lowerBound)) { \ CLIENT_ERR("Lower bound (%" FMT ") must be less than or equal to the range maximum (%" FMT ")", \ FormatArg((args).lowerBound), \ FormatArg((args).max.value)); \ return false; \ } \ if (!(args).includeLowerBound && !LessThan((args).lowerBound, (args).max.value)) { \ CLIENT_ERR("Lower bound (%" FMT ") must be less than the range maximum (%" FMT \ ") if lower bound is excluded from range", \ FormatArg((args).lowerBound), \ FormatArg((args).max.value)); \ return false; \ } \ } \ } else \ (void)0 mc_mincover_t *mc_getMincoverInt32(mc_getMincoverInt32_args_t args, mongocrypt_status_t *status, bool use_range_v2) { BSON_ASSERT_PARAM(status); CHECK_BOUNDS(args, PRId32, IDENTITY, LESSTHAN); mc_OSTType_Int32 a, b; if (!mc_getTypeInfo32((mc_getTypeInfo32_args_t){.min = args.min, .max = args.max, .value = args.lowerBound}, &a, status)) { return NULL; } if (!mc_getTypeInfo32((mc_getTypeInfo32_args_t){.min = args.min, .max = args.max, .value = args.upperBound}, &b, status)) { return NULL; } BSON_ASSERT(a.min == b.min); BSON_ASSERT(a.max == b.max); if (!adjustBounds_u32(&a.value, args.includeLowerBound, a.min, &b.value, args.includeUpperBound, b.max, status)) { return NULL; } MinCoverGenerator_u32 *mcg = MinCoverGenerator_new_u32(a.value, b.value, a.max, args.sparsity, args.trimFactor, status, use_range_v2); if (!mcg) { return NULL; } mc_mincover_t *mc = MinCoverGenerator_minCover_u32(mcg); mc->usedTrimFactor = MinCoverGenerator_usedTrimFactor_u32(mcg); MinCoverGenerator_destroy_u32(mcg); return mc; } mc_mincover_t *mc_getMincoverInt64(mc_getMincoverInt64_args_t args, mongocrypt_status_t *status, bool use_range_v2) { BSON_ASSERT_PARAM(status); CHECK_BOUNDS(args, PRId64, IDENTITY, LESSTHAN); mc_OSTType_Int64 a, b; if (!mc_getTypeInfo64((mc_getTypeInfo64_args_t){.min = args.min, .max = args.max, .value = args.lowerBound}, &a, status)) { return NULL; } if (!mc_getTypeInfo64((mc_getTypeInfo64_args_t){.min = args.min, .max = args.max, .value = args.upperBound}, &b, status)) { return NULL; } BSON_ASSERT(a.min == b.min); BSON_ASSERT(a.max == b.max); if (!adjustBounds_u64(&a.value, args.includeLowerBound, a.min, &b.value, args.includeUpperBound, b.max, status)) { return NULL; } MinCoverGenerator_u64 *mcg = MinCoverGenerator_new_u64(a.value, b.value, a.max, args.sparsity, args.trimFactor, status, use_range_v2); if (!mcg) { return NULL; } mc_mincover_t *mc = MinCoverGenerator_minCover_u64(mcg); mc->usedTrimFactor = MinCoverGenerator_usedTrimFactor_u64(mcg); MinCoverGenerator_destroy_u64(mcg); return mc; } // mc_getMincoverDouble implements the Mincover Generation algorithm described // in SERVER-68600 for double. mc_mincover_t *mc_getMincoverDouble(mc_getMincoverDouble_args_t args, mongocrypt_status_t *status, bool use_range_v2) { BSON_ASSERT_PARAM(status); CHECK_BOUNDS(args, "g", IDENTITY, LESSTHAN); mc_OSTType_Double a, b; if (!mc_getTypeInfoDouble((mc_getTypeInfoDouble_args_t){.value = args.lowerBound, .min = args.min, .max = args.max, .precision = args.precision}, &a, status, use_range_v2)) { return NULL; } if (!mc_getTypeInfoDouble((mc_getTypeInfoDouble_args_t){.value = args.upperBound, .min = args.min, .max = args.max, .precision = args.precision}, &b, status, use_range_v2)) { return NULL; } BSON_ASSERT(a.min == b.min); BSON_ASSERT(a.max == b.max); if (!adjustBounds_u64(&a.value, args.includeLowerBound, a.min, &b.value, args.includeUpperBound, b.max, status)) { return NULL; } MinCoverGenerator_u64 *mcg = MinCoverGenerator_new_u64(a.value, b.value, a.max, args.sparsity, args.trimFactor, status, use_range_v2); if (!mcg) { return NULL; } mc_mincover_t *mc = MinCoverGenerator_minCover_u64(mcg); mc->usedTrimFactor = MinCoverGenerator_usedTrimFactor_u64(mcg); MinCoverGenerator_destroy_u64(mcg); return mc; } #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT mc_mincover_t * mc_getMincoverDecimal128(mc_getMincoverDecimal128_args_t args, mongocrypt_status_t *status, bool use_range_v2) { BSON_ASSERT_PARAM(status); #define ToString(Dec) (mc_dec128_to_string(Dec).str) CHECK_BOUNDS(args, "s", ToString, mc_dec128_less); mc_OSTType_Decimal128 a, b; if (!mc_getTypeInfoDecimal128((mc_getTypeInfoDecimal128_args_t){.value = args.lowerBound, .min = args.min, .max = args.max, .precision = args.precision}, &a, status, use_range_v2)) { return NULL; } if (!mc_getTypeInfoDecimal128((mc_getTypeInfoDecimal128_args_t){.value = args.upperBound, .min = args.min, .max = args.max, .precision = args.precision}, &b, status, use_range_v2)) { return NULL; } BSON_ASSERT(mlib_int128_eq(a.min, b.min)); BSON_ASSERT(mlib_int128_eq(a.max, b.max)); if (!adjustBounds_u128(&a.value, args.includeLowerBound, a.min, &b.value, args.includeUpperBound, b.max, status)) { return NULL; } MinCoverGenerator_u128 *mcg = MinCoverGenerator_new_u128(a.value, b.value, a.max, args.sparsity, args.trimFactor, status, use_range_v2); if (!mcg) { return NULL; } mc_mincover_t *mc = MinCoverGenerator_minCover_u128(mcg); mc->usedTrimFactor = MinCoverGenerator_usedTrimFactor_u128(mcg); MinCoverGenerator_destroy_u128(mcg); return mc; } #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT mongodb-1.21.0/src/libmongocrypt/src/mc-rangeopts-private.h0000644000175100001660000001014714760300420020626 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MC_RANGEOPTS_PRIVATE_H #define MC_RANGEOPTS_PRIVATE_H #include #include "mc-optional-private.h" #include "mongocrypt-status-private.h" typedef struct { bson_t *bson; struct { bson_iter_t value; bool set; } min; struct { bson_iter_t value; bool set; } max; int64_t sparsity; mc_optional_int32_t precision; mc_optional_int32_t trimFactor; } mc_RangeOpts_t; // `mc_RangeOpts_t` inherits extended alignment from libbson. To dynamically allocate, use // aligned allocation (e.g. BSON_ALIGNED_ALLOC) BSON_STATIC_ASSERT2(alignof_mc_RangeOpts_t, BSON_ALIGNOF(mc_RangeOpts_t) >= BSON_MAX(BSON_ALIGNOF(bson_t), BSON_ALIGNOF(bson_iter_t))); /* mc_RangeOpts_parse parses a BSON document into mc_RangeOpts_t. * The document is expected to have the form: * { * "min": BSON value, * "max": BSON value, * "sparsity": Optional, * "precision": Optional, * "trimFactor": Optional, * } */ bool mc_RangeOpts_parse(mc_RangeOpts_t *ro, const bson_t *in, bool use_range_v2, mongocrypt_status_t *status); /* * mc_RangeOpts_to_FLE2RangeInsertSpec creates a placeholder value to be * encrypted. It is only expected to be called when query_type is unset. The * output FLE2RangeInsertSpec is a BSON document of the form: * { * "v": BSON value to encrypt, * "min": BSON value, * "max": BSON value, * "precision": Optional * } * * v is expect to be a BSON document of the form: * { "v": BSON value to encrypt }. * * Preconditions: out must be initialized by caller. */ bool mc_RangeOpts_to_FLE2RangeInsertSpec(const mc_RangeOpts_t *ro, const bson_t *v, bson_t *out, bool use_range_v2, mongocrypt_status_t *status); /* mc_RangeOpts_appendMin appends the minimum value of the range for a given * type. If `ro->min` is unset, uses the lowest representable value of the value * type. Errors if `valueType` does not match the type of `ro->min`. */ bool mc_RangeOpts_appendMin(const mc_RangeOpts_t *ro, bson_type_t valueType, const char *fieldName, bson_t *out, mongocrypt_status_t *status); /* mc_RangeOpts_appendMax appends the maximum value of the range for a given * type. If `ro->max` is unset, uses the highest representable value of the * value type. Errors if `valueType` does not match the type of `ro->max`. */ bool mc_RangeOpts_appendMax(const mc_RangeOpts_t *ro, bson_type_t valueType, const char *fieldName, bson_t *out, mongocrypt_status_t *status); /* mc_RangeOpts_appendTrimFactor appends the trim factor of the field. If `ro->trimFactor` is unset, * defaults to 0. Errors if `ro->trimFactor` is out of bounds based on the size of the domain * computed from `valueType`, `ro->min` and `ro->max`. */ bool mc_RangeOpts_appendTrimFactor(const mc_RangeOpts_t *ro, bson_type_t valueType, const char *fieldName, bson_t *out, mongocrypt_status_t *status, bool use_range_v2); void mc_RangeOpts_cleanup(mc_RangeOpts_t *ro); #endif // MC_RANGEOPTS_PRIVATE_H mongodb-1.21.0/src/libmongocrypt/src/mc-rangeopts.c0000644000175100001660000005106214760300420017152 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mc-rangeopts-private.h" #include "mc-check-conversions-private.h" #include "mc-cmp-private.h" #include "mc-range-edge-generation-private.h" // mc_count_leading_zeros_XX #include "mc-range-encoding-private.h" // mc_getTypeInfoXX #include "mongocrypt-private.h" #include "mongocrypt-util-private.h" // mc_bson_type_to_string #include // DBL_MAX #define CLIENT_ERR_PREFIXED_HELPER(Prefix, ErrorString, ...) CLIENT_ERR(Prefix ": " ErrorString, ##__VA_ARGS__) #define CLIENT_ERR_PREFIXED(ErrorString, ...) CLIENT_ERR_PREFIXED_HELPER(ERROR_PREFIX, ErrorString, ##__VA_ARGS__) // Common logic for testing field name, tracking duplication, and presence. #define IF_FIELD(Name) \ if (0 == strcmp(field, #Name)) { \ if (has_##Name) { \ CLIENT_ERR_PREFIXED("Unexpected duplicate field '" #Name "'"); \ return false; \ } \ has_##Name = true; #define END_IF_FIELD \ continue; \ } #define CHECK_HAS(Name) \ if (!has_##Name) { \ CLIENT_ERR_PREFIXED("Missing field '" #Name "'"); \ return false; \ } #define ERROR_PREFIX "Error parsing RangeOpts" bool mc_RangeOpts_parse(mc_RangeOpts_t *ro, const bson_t *in, bool use_range_v2, mongocrypt_status_t *status) { bson_iter_t iter = {0}; bool has_min = false, has_max = false, has_sparsity = false, has_precision = false, has_trimFactor = false; BSON_ASSERT_PARAM(ro); BSON_ASSERT_PARAM(in); BSON_ASSERT(status || true); *ro = (mc_RangeOpts_t){0}; ro->bson = bson_copy(in); if (!bson_iter_init(&iter, ro->bson)) { CLIENT_ERR_PREFIXED("Invalid BSON"); return false; } while (bson_iter_next(&iter)) { const char *field = bson_iter_key(&iter); BSON_ASSERT(field); IF_FIELD(min) ro->min.set = true; ro->min.value = iter; END_IF_FIELD IF_FIELD(max) ro->max.set = true; ro->max.value = iter; END_IF_FIELD IF_FIELD(sparsity) if (!BSON_ITER_HOLDS_INT64(&iter)) { CLIENT_ERR_PREFIXED("Expected int64 for sparsity, got: %s", mc_bson_type_to_string(bson_iter_type(&iter))); return false; }; ro->sparsity = bson_iter_int64(&iter); END_IF_FIELD IF_FIELD(precision) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("'precision' must be an int32"); return false; } int32_t val = bson_iter_int32(&iter); if (val < 0) { CLIENT_ERR_PREFIXED("'precision' must be non-negative"); return false; } ro->precision = OPT_I32(val); } END_IF_FIELD IF_FIELD(trimFactor) { if (!BSON_ITER_HOLDS_INT32(&iter)) { CLIENT_ERR_PREFIXED("Expected int32 for trimFactor, got: %s", mc_bson_type_to_string(bson_iter_type(&iter))); return false; }; int32_t val = bson_iter_int32(&iter); if (val < 0) { CLIENT_ERR_PREFIXED("'trimFactor' must be non-negative"); return false; } ro->trimFactor = OPT_I32(val); } END_IF_FIELD CLIENT_ERR_PREFIXED("Unrecognized field: '%s'", field); return false; } // Do not error if min/max are not present. min/max are optional. // Do not error if precision is not present. Precision is optional and only // applies to double/decimal128. // Do not error if trimFactor is not present. It is optional. if (!has_sparsity && use_range_v2) { ro->sparsity = mc_FLERangeSparsityDefault; } // Expect precision only to be set for double or decimal128. if (has_precision) { if (!ro->min.set) { CLIENT_ERR_PREFIXED("setting precision requires min"); return false; } bson_type_t minType = bson_iter_type(&ro->min.value); if (minType != BSON_TYPE_DOUBLE && minType != BSON_TYPE_DECIMAL128) { CLIENT_ERR_PREFIXED("expected 'precision' to be set with double or decimal128 " "index, but got: %s min", mc_bson_type_to_string(minType)); return false; } if (!ro->max.set) { CLIENT_ERR_PREFIXED("setting precision requires max"); return false; } bson_type_t maxType = bson_iter_type(&ro->max.value); if (maxType != BSON_TYPE_DOUBLE && maxType != BSON_TYPE_DECIMAL128) { CLIENT_ERR_PREFIXED("expected 'precision' to be set with double or decimal128 " "index, but got: %s max", mc_bson_type_to_string(maxType)); return false; } } // Expect min and max to match types. if (ro->min.set && ro->max.set) { bson_type_t minType = bson_iter_type(&ro->min.value), maxType = bson_iter_type(&ro->max.value); if (minType != maxType) { CLIENT_ERR_PREFIXED("expected 'min' and 'max' to be same type, but got: %s " "min and %s max", mc_bson_type_to_string(minType), mc_bson_type_to_string(maxType)); return false; } } if (ro->min.set || ro->max.set) { // Setting min/max without precision is error for double and decimal128. if (ro->min.set) { bson_type_t minType = bson_iter_type(&ro->min.value); if (minType == BSON_TYPE_DOUBLE || minType == BSON_TYPE_DECIMAL128) { if (!has_precision) { CLIENT_ERR_PREFIXED("expected 'precision' to be set with 'min' for %s", mc_bson_type_to_string(minType)); return false; } } } if (ro->max.set) { bson_type_t maxType = bson_iter_type(&ro->max.value); if (maxType == BSON_TYPE_DOUBLE || maxType == BSON_TYPE_DECIMAL128) { if (!has_precision) { CLIENT_ERR_PREFIXED("expected 'precision' to be set with 'max' for %s", mc_bson_type_to_string(maxType)); return false; } } } } if (ro->trimFactor.set) { if (!use_range_v2) { // Once `use_range_v2` is default true, this block may be removed. CLIENT_ERR_PREFIXED("'trimFactor' is not supported for QE range v1"); return false; } // At this point, we do not know the type of the field if min and max are unspecified. Wait to // validate the value of trimFactor. } return true; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error making FLE2RangeInsertSpec" bool mc_RangeOpts_to_FLE2RangeInsertSpec(const mc_RangeOpts_t *ro, const bson_t *v, bson_t *out, bool use_range_v2, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(ro); BSON_ASSERT_PARAM(v); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); bson_iter_t v_iter; if (!bson_iter_init_find(&v_iter, v, "v")) { CLIENT_ERR_PREFIXED("Unable to find 'v' in input"); return false; } bson_t child; if (!BSON_APPEND_DOCUMENT_BEGIN(out, "v", &child)) { CLIENT_ERR_PREFIXED("Error appending to BSON"); return false; } if (!bson_append_iter(&child, "v", 1, &v_iter)) { CLIENT_ERR_PREFIXED("Error appending to BSON"); return false; } if (!mc_RangeOpts_appendMin(ro, bson_iter_type(&v_iter), "min", &child, status)) { return false; } if (!mc_RangeOpts_appendMax(ro, bson_iter_type(&v_iter), "max", &child, status)) { return false; } if (ro->precision.set) { BSON_ASSERT(ro->precision.value <= INT32_MAX); if (!BSON_APPEND_INT32(&child, "precision", (int32_t)ro->precision.value)) { CLIENT_ERR_PREFIXED("Error appending to BSON"); return false; } } if (use_range_v2) { if (!mc_RangeOpts_appendTrimFactor(ro, bson_iter_type(&v_iter), "trimFactor", &child, status, use_range_v2)) { return false; } } if (!bson_append_document_end(out, &child)) { CLIENT_ERR_PREFIXED("Error appending to BSON"); return false; } return true; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error appending min to FLE2RangeInsertSpec" bool mc_RangeOpts_appendMin(const mc_RangeOpts_t *ro, bson_type_t valueType, const char *fieldName, bson_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(ro); BSON_ASSERT_PARAM(fieldName); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); if (ro->min.set) { if (bson_iter_type(&ro->min.value) != valueType) { CLIENT_ERR_PREFIXED("expected matching 'min' and value type. Got range option " "'min' of type %s and value of type %s", mc_bson_type_to_string(bson_iter_type(&ro->min.value)), mc_bson_type_to_string(valueType)); return false; } if (!bson_append_iter(out, fieldName, -1, &ro->min.value)) { CLIENT_ERR_PREFIXED("failed to append BSON"); return false; } return true; } if (valueType == BSON_TYPE_INT32 || valueType == BSON_TYPE_INT64 || valueType == BSON_TYPE_DATE_TIME) { CLIENT_ERR_PREFIXED("Range option 'min' is required for type: %s", mc_bson_type_to_string(valueType)); return false; } else if (valueType == BSON_TYPE_DOUBLE) { if (!BSON_APPEND_DOUBLE(out, fieldName, -DBL_MAX)) { CLIENT_ERR_PREFIXED("failed to append BSON"); return false; } } else if (valueType == BSON_TYPE_DECIMAL128) { #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT const bson_decimal128_t min = mc_dec128_to_bson_decimal128(MC_DEC128_LARGEST_NEGATIVE); if (!BSON_APPEND_DECIMAL128(out, fieldName, &min)) { CLIENT_ERR_PREFIXED("failed to append BSON"); return false; } #else // ↑↑↑↑↑↑↑↑ With Decimal128 / Without ↓↓↓↓↓↓↓↓↓↓ CLIENT_ERR_PREFIXED("unsupported BSON type (Decimal128) for range: libmongocrypt " "was built without extended Decimal128 support"); return false; #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT } else { CLIENT_ERR_PREFIXED("unsupported BSON type: %s for range", mc_bson_type_to_string(valueType)); return false; } return true; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error appending max to FLE2RangeInsertSpec" bool mc_RangeOpts_appendMax(const mc_RangeOpts_t *ro, bson_type_t valueType, const char *fieldName, bson_t *out, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(ro); BSON_ASSERT_PARAM(fieldName); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); if (ro->max.set) { if (bson_iter_type(&ro->max.value) != valueType) { CLIENT_ERR_PREFIXED("expected matching 'max' and value type. Got range option " "'max' of type %s and value of type %s", mc_bson_type_to_string(bson_iter_type(&ro->max.value)), mc_bson_type_to_string(valueType)); return false; } if (!bson_append_iter(out, fieldName, -1, &ro->max.value)) { CLIENT_ERR_PREFIXED("failed to append BSON"); return false; } return true; } if (valueType == BSON_TYPE_INT32 || valueType == BSON_TYPE_INT64 || valueType == BSON_TYPE_DATE_TIME) { CLIENT_ERR_PREFIXED("Range option 'max' is required for type: %s", mc_bson_type_to_string(valueType)); return false; } else if (valueType == BSON_TYPE_DOUBLE) { if (!BSON_APPEND_DOUBLE(out, fieldName, DBL_MAX)) { CLIENT_ERR_PREFIXED("failed to append BSON"); return false; } } else if (valueType == BSON_TYPE_DECIMAL128) { #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT const bson_decimal128_t max = mc_dec128_to_bson_decimal128(MC_DEC128_LARGEST_POSITIVE); if (!BSON_APPEND_DECIMAL128(out, fieldName, &max)) { CLIENT_ERR_PREFIXED("failed to append BSON"); return false; } #else // ↑↑↑↑↑↑↑↑ With Decimal128 / Without ↓↓↓↓↓↓↓↓↓↓ CLIENT_ERR_PREFIXED("unsupported BSON type (Decimal128) for range: libmongocrypt " "was built without extended Decimal128 support"); return false; #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT } else { CLIENT_ERR_PREFIXED("unsupported BSON type: %s for range", mc_bson_type_to_string(valueType)); return false; } return true; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error in getNumberOfBits" // Used to calculate max trim factor. Returns the number of bits required to represent any number in // the domain. bool mc_getNumberOfBits(const mc_RangeOpts_t *ro, bson_type_t valueType, uint32_t *bitsOut, mongocrypt_status_t *status, bool use_range_v2) { BSON_ASSERT_PARAM(ro); BSON_ASSERT_PARAM(bitsOut); // For each type, we use getTypeInfo to get the total number of values in the domain (-1) // which tells us how many bits are needed to represent the whole domain. // note - can't use a switch statement because of -Werror=switch-enum if (valueType == BSON_TYPE_INT32) { int32_t value = 0; mc_optional_int32_t rmin = {false, 0}, rmax = {false, 0}; if (ro->min.set) { BSON_ASSERT(ro->max.set); value = bson_iter_int32(&ro->min.value); rmin = OPT_I32(value); rmax = OPT_I32(bson_iter_int32(&ro->max.value)); } mc_getTypeInfo32_args_t args = {value, rmin, rmax}; mc_OSTType_Int32 out; if (!mc_getTypeInfo32(args, &out, status)) { return false; } *bitsOut = 32 - (uint32_t)mc_count_leading_zeros_u32(out.max); return true; } else if (valueType == BSON_TYPE_INT64) { int64_t value = 0; mc_optional_int64_t rmin = {false, 0}, rmax = {false, 0}; if (ro->min.set) { BSON_ASSERT(ro->max.set); value = bson_iter_int64(&ro->min.value); rmin = OPT_I64(value); rmax = OPT_I64(bson_iter_int64(&ro->max.value)); } mc_getTypeInfo64_args_t args = {value, rmin, rmax}; mc_OSTType_Int64 out; if (!mc_getTypeInfo64(args, &out, status)) { return false; } *bitsOut = 64 - (uint32_t)mc_count_leading_zeros_u64(out.max); return true; } else if (valueType == BSON_TYPE_DATE_TIME) { int64_t value = 0; mc_optional_int64_t rmin = {false, 0}, rmax = {false, 0}; if (ro->min.set) { BSON_ASSERT(ro->max.set); value = bson_iter_date_time(&ro->min.value); rmin = OPT_I64(value); rmax = OPT_I64(bson_iter_date_time(&ro->max.value)); } mc_getTypeInfo64_args_t args = {value, rmin, rmax}; mc_OSTType_Int64 out; if (!mc_getTypeInfo64(args, &out, status)) { return false; } *bitsOut = 64 - (uint32_t)mc_count_leading_zeros_u64(out.max); return true; } else if (valueType == BSON_TYPE_DOUBLE) { double value = 0; mc_optional_double_t rmin = {false, 0}, rmax = {false, 0}; mc_optional_int32_t prec = ro->precision; if (ro->min.set) { BSON_ASSERT(ro->max.set); value = bson_iter_double(&ro->min.value); rmin = OPT_DOUBLE(value); rmax = OPT_DOUBLE(bson_iter_double(&ro->max.value)); } mc_getTypeInfoDouble_args_t args = {value, rmin, rmax, prec}; mc_OSTType_Double out; if (!mc_getTypeInfoDouble(args, &out, status, use_range_v2)) { return false; } *bitsOut = 64 - (uint32_t)mc_count_leading_zeros_u64(out.max); return true; } #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT else if (valueType == BSON_TYPE_DECIMAL128) { mc_dec128 value = MC_DEC128_ZERO; mc_optional_dec128_t rmin = {false, MC_DEC128_ZERO}, rmax = {false, MC_DEC128_ZERO}; mc_optional_int32_t prec = ro->precision; if (ro->min.set) { BSON_ASSERT(ro->max.set); value = mc_dec128_from_bson_iter(&ro->min.value); rmin = OPT_MC_DEC128(value); rmax = OPT_MC_DEC128(mc_dec128_from_bson_iter(&ro->max.value)); } mc_getTypeInfoDecimal128_args_t args = {value, rmin, rmax, prec}; mc_OSTType_Decimal128 out; if (!mc_getTypeInfoDecimal128(args, &out, status, use_range_v2)) { return false; } *bitsOut = 128 - (uint32_t)mc_count_leading_zeros_u128(out.max); return true; } #endif CLIENT_ERR_PREFIXED("unsupported BSON type: %s for range", mc_bson_type_to_string(valueType)); return false; } #undef ERROR_PREFIX #define ERROR_PREFIX "Error appending trim factor to FLE2RangeInsertSpec" bool mc_RangeOpts_appendTrimFactor(const mc_RangeOpts_t *ro, bson_type_t valueType, const char *fieldName, bson_t *out, mongocrypt_status_t *status, bool use_range_v2) { BSON_ASSERT_PARAM(ro); BSON_ASSERT_PARAM(fieldName); BSON_ASSERT_PARAM(out); BSON_ASSERT(status || true); if (!ro->trimFactor.set) { // A default `trimFactor` will be selected later with `trimFactorDefault` return true; } uint32_t nbits; if (!mc_getNumberOfBits(ro, valueType, &nbits, status, use_range_v2)) { return false; } // if nbits = 0, we want to allow trim factor = 0. uint32_t test = nbits ? nbits : 1; if (mc_cmp_greater_equal_su(ro->trimFactor.value, test)) { CLIENT_ERR_PREFIXED("Trim factor (%d) must be less than the total number of bits (%d) used to represent " "any element in the domain.", ro->trimFactor.value, nbits); return false; } if (!BSON_APPEND_INT32(out, fieldName, ro->trimFactor.value)) { CLIENT_ERR_PREFIXED("failed to append BSON"); return false; } return true; } #undef ERROR_PREFIX void mc_RangeOpts_cleanup(mc_RangeOpts_t *ro) { if (!ro) { return; } bson_destroy(ro->bson); } mongodb-1.21.0/src/libmongocrypt/src/mc-reader-private.h0000644000175100001660000000613414760300420020067 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MONGOCRYPT_READER_PRIVATE_H #define MONGOCRYPT_READER_PRIVATE_H #include "mongocrypt-buffer-private.h" #include #include /** * A non-owning forward-only cursor api to read a buffer. * * Tracks length of buffer and current position of buffer. parser_name is * typically __FUNCTION__ to provide useful error messages automatically. * * All numbers are read as little endian. * * Functions return false on error and set mongocrypt_status_t to an error. * * Example: * * const _mongocrypt_buffer_t *buf; * mongocrypt_status_t *status * * mc_reader_t reader; * mc_reader_init_from_buffer (&reader, buf, __FUNCTION__); * * _mongocrypt_buffer_t in; * if (!mc_reader_read_uuid_buffer (&reader, &in, status)) { * abort (); * } * * uint8_t value; * if (!mc_reader_read_u8 (&reader, value, status)) { * abort (); * } */ struct _mc_reader_t { const uint8_t *ptr; uint64_t pos; uint64_t len; const char *parser_name; }; typedef struct _mc_reader_t mc_reader_t; void mc_reader_init(mc_reader_t *reader, const uint8_t *ptr, uint64_t len, const char *parser_name); void mc_reader_init_from_buffer(mc_reader_t *reader, const _mongocrypt_buffer_t *buf, const char *parser_name); mc_reader_t *mc_reader_new(const uint8_t *ptr, uint64_t len, const char *parser_name); void mc_reader_destroy(mc_reader_t *reader); bool mc_reader_has_data(const mc_reader_t *reader); uint64_t mc_reader_get_remaining_length(const mc_reader_t *reader); uint64_t mc_reader_get_consumed_length(const mc_reader_t *reader); bool mc_reader_read_u8(mc_reader_t *reader, uint8_t *value, mongocrypt_status_t *status); bool mc_reader_read_u32(mc_reader_t *reader, uint32_t *value, mongocrypt_status_t *status); bool mc_reader_read_u64(mc_reader_t *reader, uint64_t *value, mongocrypt_status_t *status); bool mc_reader_read_bytes(mc_reader_t *reader, const uint8_t **ptr, uint64_t length, mongocrypt_status_t *status); bool mc_reader_read_buffer(mc_reader_t *reader, _mongocrypt_buffer_t *buf, uint64_t length, mongocrypt_status_t *status); bool mc_reader_read_uuid_buffer(mc_reader_t *reader, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); bool mc_reader_read_prfblock_buffer(mc_reader_t *reader, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); bool mc_reader_read_buffer_to_end(mc_reader_t *reader, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); #endif /* MONGOCRYPT_READER_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-reader.c0000644000175100001660000001422614760300420016413 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mongocrypt-private.h" #include "mc-reader-private.h" #define CHECK_AND_RETURN(x) \ if (!(x)) { \ return false; \ } #define CHECK_REMAINING_BUFFER_AND_RET(read_size) \ if ((reader->pos + (read_size)) > reader->len) { \ CLIENT_ERR("%s expected byte " \ "length >= %" PRIu64 " got: %" PRIu64, \ reader->parser_name, \ reader->pos + (read_size), \ reader->len); \ return false; \ } void mc_reader_init(mc_reader_t *reader, const uint8_t *ptr, uint64_t len, const char *parser_name) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(ptr); BSON_ASSERT_PARAM(parser_name); *reader = (mc_reader_t){.pos = 0u, .ptr = ptr, .len = len, .parser_name = parser_name}; } void mc_reader_init_from_buffer(mc_reader_t *reader, const _mongocrypt_buffer_t *buf, const char *parser_name) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(parser_name); mc_reader_init(reader, buf->data, buf->len, parser_name); } mc_reader_t *mc_reader_new(const uint8_t *ptr, uint64_t len, const char *parser_name) { BSON_ASSERT_PARAM(ptr); BSON_ASSERT_PARAM(parser_name); mc_reader_t *reader = bson_malloc(sizeof(mc_reader_t)); mc_reader_init(reader, ptr, len, parser_name); return reader; } void mc_reader_destroy(mc_reader_t *reader) { bson_free(reader); } bool mc_reader_has_data(const mc_reader_t *reader) { BSON_ASSERT_PARAM(reader); return reader->pos < reader->len; } uint64_t mc_reader_get_remaining_length(const mc_reader_t *reader) { BSON_ASSERT_PARAM(reader); return reader->len - reader->pos; } uint64_t mc_reader_get_consumed_length(const mc_reader_t *reader) { BSON_ASSERT_PARAM(reader); return reader->pos; } bool mc_reader_read_u8(mc_reader_t *reader, uint8_t *value, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(value); CHECK_REMAINING_BUFFER_AND_RET(sizeof(uint8_t)); *value = *(reader->ptr + reader->pos); reader->pos += sizeof(uint8_t); return true; } bool mc_reader_read_u32(mc_reader_t *reader, uint32_t *value, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(value); CHECK_REMAINING_BUFFER_AND_RET(sizeof(uint32_t)); uint32_t temp; memcpy(&temp, reader->ptr + reader->pos, sizeof(uint32_t)); *value = BSON_UINT32_FROM_LE(temp); reader->pos += sizeof(uint32_t); return true; } bool mc_reader_read_u64(mc_reader_t *reader, uint64_t *value, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(value); CHECK_REMAINING_BUFFER_AND_RET(sizeof(uint64_t)); uint64_t temp; memcpy(&temp, reader->ptr + reader->pos, sizeof(uint64_t)); *value = BSON_UINT64_FROM_LE(temp); reader->pos += sizeof(uint64_t); return true; } bool mc_reader_read_bytes(mc_reader_t *reader, const uint8_t **ptr, uint64_t length, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(ptr); CHECK_REMAINING_BUFFER_AND_RET(length); *ptr = reader->ptr + reader->pos; reader->pos += length; return true; } bool mc_reader_read_buffer(mc_reader_t *reader, _mongocrypt_buffer_t *buf, uint64_t length, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(buf); const uint8_t *ptr; CHECK_AND_RETURN(mc_reader_read_bytes(reader, &ptr, length, status)); if (length > SIZE_MAX || !_mongocrypt_buffer_copy_from_data_and_size(buf, ptr, (size_t)length)) { CLIENT_ERR("%s failed to copy " "data of length %" PRIu64, reader->parser_name, length); return false; } return true; } bool mc_reader_read_uuid_buffer(mc_reader_t *reader, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(buf); CHECK_AND_RETURN(mc_reader_read_buffer(reader, buf, 16, status)); buf->subtype = BSON_SUBTYPE_UUID; return true; } bool mc_reader_read_prfblock_buffer(mc_reader_t *reader, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(buf); CHECK_AND_RETURN(mc_reader_read_buffer(reader, buf, 32, status)); buf->subtype = BSON_SUBTYPE_ENCRYPTED; return true; } bool mc_reader_read_buffer_to_end(mc_reader_t *reader, _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(reader); BSON_ASSERT_PARAM(buf); uint64_t length = reader->len - reader->pos; return mc_reader_read_buffer(reader, buf, length, status); } mongodb-1.21.0/src/libmongocrypt/src/mc-tokens-private.h0000644000175100001660000001637614760300420020141 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MONGOCRYPT_TOKENS_PRIVATE_H #define MONGOCRYPT_TOKENS_PRIVATE_H #include "mongocrypt-buffer-private.h" #include "mongocrypt-crypto-private.h" /* * ======================= Begin: FLE 2 Token Reference ======================= * * v is a BSON value. It is the bytes after "e_name" in "element" in * https://bsonspec.org/spec.html. * u is a "contention factor". It is a uint64_t. * HMAC is the HMAC-SHA-256 function. * Integers are represented as uint64_t in little-endian. * * CollectionsLevel1Token = HMAC(RootKey, 1) * ServerDataEncryptionLevel1Token = HMAC(RootKey, 3) * * EDCToken = HMAC(CollectionsLevel1Token, 1) * ESCToken = HMAC(CollectionsLevel1Token, 2) * ECCToken = HMAC(CollectionsLevel1Token, 3) * ECOCToken = HMAC(CollectionsLevel1Token, 4) * * EDCDerivedFromDataToken = HMAC(EDCToken, v) * ESCDerivedFromDataToken = HMAC(ESCToken, v) * ECCDerivedFromDataToken = HMAC(ECCToken, v) * * EDCDerivedFromDataTokenAndContentionFactor = HMAC(EDCDerivedFromDataToken, u) * ESCDerivedFromDataTokenAndContentionFactor = HMAC(ESCDerivedFromDataToken, u) * ECCDerivedFromDataTokenAndContentionFactor = HMAC(ECCDerivedFromDataToken, u) * * EDCTwiceDerivedToken = HMAC(EDCDerivedFromDataTokenAndContentionFactor, 1) * ESCTwiceDerivedTagToken = HMAC(ESCDerivedFromDataTokenAndContentionFactor, 1) * ESCTwiceDerivedValueToken = HMAC(ESCDerivedFromDataTokenAndContentionFactor, 2) * ECCTwiceDerivedTagToken = HMAC(ECCDerivedFromDataTokenAndContentionFactor, 1) * ECCTwiceDerivedValueToken = HMAC(ECCDerivedFromDataTokenAndContentionFactor, 2) * * Note: ECC related tokens are used in FLE2v1 only. * Further, ECCTwiceDerivedValue(Tag|Token) have been omitted entirely. * The above comment describing derivation is for doc purposes only. * ---------------------------------------------------------------------------- * Added in FLE2v2: * * ServerTokenDerivationLevel1Token = HMAC(RootKey, 2) * ServerDerivedFromDataToken = HMAC(ServerTokenDerivationLevel1Token, v) * * ServerCountAndContentionFactorEncryptionToken = * HMAC(ServerDerivedFromDataToken, 1) * ServerZerosEncryptionToken = HMAC(ServerDerivedFromDataToken, 2) * ---------------------------------------------------------------------------- * Added in Range V2: * * d is a 17-byte blob of zeros. * * AnchorPaddingTokenRoot = HMAC(ESCToken, d) * Server-side: * AnchorPaddingTokenKey = HMAC(AnchorPaddingTokenRoot, 1) * AnchorPaddingTokenValue = HMAC(AnchorPaddingTokenRoot, 2) * ======================== End: FLE 2 Token Reference ======================== */ /// Declare a token type named 'Name', with constructor parameters given by the /// remaining arguments. Each constructor will also have the implicit first /// argument '_mongocrypt_crypto_t* crypto' and a final argument /// 'mongocrypt_status_t* status' #define DECL_TOKEN_TYPE(Name, ...) DECL_TOKEN_TYPE_1(Name, BSON_CONCAT(Name, _t), __VA_ARGS__) #define DECL_TOKEN_TYPE_1(Prefix, T, ...) \ /* Opaque typedef the struct */ \ typedef struct T T; \ /* Data-getter */ \ extern const _mongocrypt_buffer_t *BSON_CONCAT(Prefix, _get)(const T *t); \ /* Destructor */ \ extern void BSON_CONCAT(Prefix, _destroy)(T * t); \ /* Constructor for server to create tokens from raw buffer */ \ extern T *BSON_CONCAT(Prefix, _new_from_buffer)(_mongocrypt_buffer_t * buf); \ /* Constructor. Parameter list given as variadic args */ \ extern T *BSON_CONCAT(Prefix, _new)(_mongocrypt_crypto_t * crypto, __VA_ARGS__, mongocrypt_status_t * status) DECL_TOKEN_TYPE(mc_CollectionsLevel1Token, const _mongocrypt_buffer_t *); DECL_TOKEN_TYPE(mc_ServerTokenDerivationLevel1Token, const _mongocrypt_buffer_t *); DECL_TOKEN_TYPE(mc_ServerDataEncryptionLevel1Token, const _mongocrypt_buffer_t *); DECL_TOKEN_TYPE(mc_EDCToken, const mc_CollectionsLevel1Token_t *CollectionsLevel1Token); DECL_TOKEN_TYPE(mc_ESCToken, const mc_CollectionsLevel1Token_t *CollectionsLevel1Token); DECL_TOKEN_TYPE(mc_ECCToken, const mc_CollectionsLevel1Token_t *CollectionsLevel1Token); DECL_TOKEN_TYPE(mc_ECOCToken, const mc_CollectionsLevel1Token_t *CollectionsLevel1Token); DECL_TOKEN_TYPE(mc_EDCDerivedFromDataToken, const mc_EDCToken_t *EDCToken, const _mongocrypt_buffer_t *v); DECL_TOKEN_TYPE(mc_ECCDerivedFromDataToken, const mc_ECCToken_t *ECCToken, const _mongocrypt_buffer_t *v); DECL_TOKEN_TYPE(mc_ESCDerivedFromDataToken, const mc_ESCToken_t *ESCToken, const _mongocrypt_buffer_t *v); DECL_TOKEN_TYPE(mc_EDCDerivedFromDataTokenAndContentionFactor, const mc_EDCDerivedFromDataToken_t *EDCDerivedFromDataToken, uint64_t u); DECL_TOKEN_TYPE(mc_ESCDerivedFromDataTokenAndContentionFactor, const mc_ESCDerivedFromDataToken_t *ESCDerivedFromDataToken, uint64_t u); DECL_TOKEN_TYPE(mc_ECCDerivedFromDataTokenAndContentionFactor, const mc_ECCDerivedFromDataToken_t *ECCDerivedFromDataToken, uint64_t u); DECL_TOKEN_TYPE(mc_EDCTwiceDerivedToken, const mc_EDCDerivedFromDataTokenAndContentionFactor_t *EDCDerivedFromDataTokenAndContentionFactor); DECL_TOKEN_TYPE(mc_ESCTwiceDerivedTagToken, const mc_ESCDerivedFromDataTokenAndContentionFactor_t *ESCDerivedFromDataTokenAndContentionFactor); DECL_TOKEN_TYPE(mc_ESCTwiceDerivedValueToken, const mc_ESCDerivedFromDataTokenAndContentionFactor_t *ESCDerivedFromDataTokenAndContentionFactor); DECL_TOKEN_TYPE(mc_ServerDerivedFromDataToken, const mc_ServerTokenDerivationLevel1Token_t *ServerTokenDerivationToken, const _mongocrypt_buffer_t *v); DECL_TOKEN_TYPE(mc_ServerCountAndContentionFactorEncryptionToken, const mc_ServerDerivedFromDataToken_t *serverDerivedFromDataToken); DECL_TOKEN_TYPE(mc_ServerZerosEncryptionToken, const mc_ServerDerivedFromDataToken_t *serverDerivedFromDataToken); DECL_TOKEN_TYPE(mc_AnchorPaddingTokenRoot, const mc_ESCToken_t *ESCToken); #undef DECL_TOKEN_TYPE #undef DECL_TOKEN_TYPE_1 #endif /* MONGOCRYPT_TOKENS_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-tokens.c0000644000175100001660000002707014760300420016455 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mc-tokens-private.h" #include "mongocrypt-buffer-private.h" /// Define a token type of the given name, with constructor parameters given as /// the remaining arguments. This macro usage should be followed by the /// constructor body, with the implicit first argument '_mongocrypt_crypto_t* /// crypto' and final argument 'mongocrypt_status_t* status' #define DEF_TOKEN_TYPE(Name, ...) DEF_TOKEN_TYPE_1(Name, BSON_CONCAT(Name, _t), __VA_ARGS__) #define DEF_TOKEN_TYPE_1(Prefix, T, ...) \ /* Define the struct for the token */ \ struct T { \ _mongocrypt_buffer_t data; \ }; \ /* Data-getter */ \ const _mongocrypt_buffer_t *BSON_CONCAT(Prefix, _get)(const T *self) { return &self->data; } \ /* Destructor */ \ void BSON_CONCAT(Prefix, _destroy)(T * self) { \ if (!self) { \ return; \ } \ _mongocrypt_buffer_cleanup(&self->data); \ bson_free(self); \ } \ /* Constructor. From raw buffer */ \ T *BSON_CONCAT(Prefix, _new_from_buffer)(_mongocrypt_buffer_t * buf) { \ BSON_ASSERT(buf->len == MONGOCRYPT_HMAC_SHA256_LEN); \ T *t = bson_malloc(sizeof(T)); \ _mongocrypt_buffer_set_to(buf, &t->data); \ return t; \ } \ /* Constructor. Parameter list given as variadic args. */ \ T *BSON_CONCAT(Prefix, _new)(_mongocrypt_crypto_t * crypto, __VA_ARGS__, mongocrypt_status_t * status) #define IMPL_TOKEN_NEW_1(Name, Key, Arg, Clean) \ { \ BSON_CONCAT(Name, _t) *t = bson_malloc(sizeof(BSON_CONCAT(Name, _t))); \ _mongocrypt_buffer_init(&t->data); \ _mongocrypt_buffer_resize(&t->data, MONGOCRYPT_HMAC_SHA256_LEN); \ \ if (!_mongocrypt_hmac_sha_256(crypto, Key, Arg, &t->data, status)) { \ BSON_CONCAT(Name, _destroy)(t); \ Clean; \ return NULL; \ } \ Clean; \ return t; \ } // Define the implementation of a token where Arg is a _mongocrypt_buffer_t. #define IMPL_TOKEN_NEW(Name, Key, Arg) IMPL_TOKEN_NEW_1(Name, Key, Arg, (void)0) // Define the implementation of a token where Arg is a uint64_t. #define IMPL_TOKEN_NEW_CONST(Name, Key, Arg) \ { \ _mongocrypt_buffer_t to_hash; \ _mongocrypt_buffer_copy_from_uint64_le(&to_hash, Arg); \ IMPL_TOKEN_NEW_1(Name, Key, &to_hash, _mongocrypt_buffer_cleanup(&to_hash)) \ } DEF_TOKEN_TYPE(mc_CollectionsLevel1Token, const _mongocrypt_buffer_t *RootKey) IMPL_TOKEN_NEW_CONST(mc_CollectionsLevel1Token, RootKey, 1) DEF_TOKEN_TYPE(mc_EDCToken, const mc_CollectionsLevel1Token_t *CollectionsLevel1Token) IMPL_TOKEN_NEW_CONST(mc_EDCToken, mc_CollectionsLevel1Token_get(CollectionsLevel1Token), 1) DEF_TOKEN_TYPE(mc_ESCToken, const mc_CollectionsLevel1Token_t *CollectionsLevel1Token) IMPL_TOKEN_NEW_CONST(mc_ESCToken, mc_CollectionsLevel1Token_get(CollectionsLevel1Token), 2) DEF_TOKEN_TYPE(mc_ECCToken, const mc_CollectionsLevel1Token_t *CollectionsLevel1Token) IMPL_TOKEN_NEW_CONST(mc_ECCToken, mc_CollectionsLevel1Token_get(CollectionsLevel1Token), 3) DEF_TOKEN_TYPE(mc_ECOCToken, const mc_CollectionsLevel1Token_t *CollectionsLevel1Token) IMPL_TOKEN_NEW_CONST(mc_ECOCToken, mc_CollectionsLevel1Token_get(CollectionsLevel1Token), 4) DEF_TOKEN_TYPE(mc_EDCDerivedFromDataToken, const mc_EDCToken_t *EDCToken, const _mongocrypt_buffer_t *v) IMPL_TOKEN_NEW(mc_EDCDerivedFromDataToken, mc_EDCToken_get(EDCToken), v) DEF_TOKEN_TYPE(mc_ESCDerivedFromDataToken, const mc_ESCToken_t *ESCToken, const _mongocrypt_buffer_t *v) IMPL_TOKEN_NEW(mc_ESCDerivedFromDataToken, mc_ESCToken_get(ESCToken), v) DEF_TOKEN_TYPE(mc_ECCDerivedFromDataToken, const mc_ECCToken_t *ECCToken, const _mongocrypt_buffer_t *v) IMPL_TOKEN_NEW(mc_ECCDerivedFromDataToken, mc_ECCToken_get(ECCToken), v) DEF_TOKEN_TYPE(mc_EDCTwiceDerivedToken, const mc_EDCDerivedFromDataTokenAndContentionFactor_t *EDCDerivedFromDataTokenAndContentionFactor) IMPL_TOKEN_NEW_CONST(mc_EDCTwiceDerivedToken, mc_EDCDerivedFromDataTokenAndContentionFactor_get(EDCDerivedFromDataTokenAndContentionFactor), 1) DEF_TOKEN_TYPE(mc_ESCTwiceDerivedTagToken, const mc_ESCDerivedFromDataTokenAndContentionFactor_t *ESCDerivedFromDataTokenAndContentionFactor) IMPL_TOKEN_NEW_CONST(mc_ESCTwiceDerivedTagToken, mc_ESCDerivedFromDataTokenAndContentionFactor_get(ESCDerivedFromDataTokenAndContentionFactor), 1) DEF_TOKEN_TYPE(mc_ESCTwiceDerivedValueToken, const mc_ESCDerivedFromDataTokenAndContentionFactor_t *ESCDerivedFromDataTokenAndContentionFactor) IMPL_TOKEN_NEW_CONST(mc_ESCTwiceDerivedValueToken, mc_ESCDerivedFromDataTokenAndContentionFactor_get(ESCDerivedFromDataTokenAndContentionFactor), 2) DEF_TOKEN_TYPE(mc_ServerDataEncryptionLevel1Token, const _mongocrypt_buffer_t *RootKey) IMPL_TOKEN_NEW_CONST(mc_ServerDataEncryptionLevel1Token, RootKey, 3) DEF_TOKEN_TYPE(mc_EDCDerivedFromDataTokenAndContentionFactor, const mc_EDCDerivedFromDataToken_t *EDCDerivedFromDataToken, uint64_t u) IMPL_TOKEN_NEW_CONST(mc_EDCDerivedFromDataTokenAndContentionFactor, mc_EDCDerivedFromDataToken_get(EDCDerivedFromDataToken), u) DEF_TOKEN_TYPE(mc_ESCDerivedFromDataTokenAndContentionFactor, const mc_ESCDerivedFromDataToken_t *ESCDerivedFromDataToken, uint64_t u) IMPL_TOKEN_NEW_CONST(mc_ESCDerivedFromDataTokenAndContentionFactor, mc_ESCDerivedFromDataToken_get(ESCDerivedFromDataToken), u) DEF_TOKEN_TYPE(mc_ECCDerivedFromDataTokenAndContentionFactor, const mc_ECCDerivedFromDataToken_t *ECCDerivedFromDataToken, uint64_t u) IMPL_TOKEN_NEW_CONST(mc_ECCDerivedFromDataTokenAndContentionFactor, mc_ECCDerivedFromDataToken_get(ECCDerivedFromDataToken), u) /* FLE2v2 */ DEF_TOKEN_TYPE(mc_ServerTokenDerivationLevel1Token, const _mongocrypt_buffer_t *RootKey) IMPL_TOKEN_NEW_CONST(mc_ServerTokenDerivationLevel1Token, RootKey, 2) DEF_TOKEN_TYPE(mc_ServerDerivedFromDataToken, const mc_ServerTokenDerivationLevel1Token_t *ServerTokenDerivationToken, const _mongocrypt_buffer_t *v) IMPL_TOKEN_NEW(mc_ServerDerivedFromDataToken, mc_ServerTokenDerivationLevel1Token_get(ServerTokenDerivationToken), v) DEF_TOKEN_TYPE(mc_ServerCountAndContentionFactorEncryptionToken, const mc_ServerDerivedFromDataToken_t *serverDerivedFromDataToken) IMPL_TOKEN_NEW_CONST(mc_ServerCountAndContentionFactorEncryptionToken, mc_ServerDerivedFromDataToken_get(serverDerivedFromDataToken), 1) DEF_TOKEN_TYPE(mc_ServerZerosEncryptionToken, const mc_ServerDerivedFromDataToken_t *serverDerivedFromDataToken) IMPL_TOKEN_NEW_CONST(mc_ServerZerosEncryptionToken, mc_ServerDerivedFromDataToken_get(serverDerivedFromDataToken), 2) // d = 17 bytes of 0, AnchorPaddingTokenRoot = HMAC(ESCToken, d) #define ANCHOR_PADDING_TOKEN_D_LENGTH 17 const uint8_t mc_AnchorPaddingTokenDValue[ANCHOR_PADDING_TOKEN_D_LENGTH] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; DEF_TOKEN_TYPE(mc_AnchorPaddingTokenRoot, const mc_ESCToken_t *ESCToken) { _mongocrypt_buffer_t to_hash; if (!_mongocrypt_buffer_copy_from_data_and_size(&to_hash, mc_AnchorPaddingTokenDValue, ANCHOR_PADDING_TOKEN_D_LENGTH)) { return NULL; } IMPL_TOKEN_NEW_1(mc_AnchorPaddingTokenRoot, mc_ESCToken_get(ESCToken), &to_hash, _mongocrypt_buffer_cleanup(&to_hash)) } #undef ANCHOR_PADDING_TOKEN_D_LENGTH mongodb-1.21.0/src/libmongocrypt/src/mc-writer-private.h0000644000175100001660000000437414760300420020145 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef MONGOCRYPT_WRITER_PRIVATE_H #define MONGOCRYPT_WRITER_PRIVATE_H #include "mongocrypt-buffer-private.h" #include #include /** * A non-owning forward-only cursor api to write to a buffer. * * Tracks length of buffer and current position of buffer. parser_name is * typically __FUNCTION__ to provide useful error messages automatically. * * All numbers are written as little endian. */ struct _mc_writer_t { uint8_t *ptr; uint64_t pos; uint64_t len; const char *parser_name; }; typedef struct _mc_writer_t mc_writer_t; void mc_writer_init(mc_writer_t *writer, uint8_t *ptr, uint64_t len, const char *parser_name); void mc_writer_init_from_buffer(mc_writer_t *writer, _mongocrypt_buffer_t *buf, const char *parser_name); mc_writer_t *mc_writer_new(uint8_t *ptr, uint64_t len, const char *parser_name); void mc_writer_destroy(mc_writer_t *writer); bool mc_writer_write_u8(mc_writer_t *writer, const uint8_t value, mongocrypt_status_t *status); bool mc_writer_write_u32(mc_writer_t *writer, const uint32_t value, mongocrypt_status_t *status); bool mc_writer_write_u64(mc_writer_t *writer, const uint64_t value, mongocrypt_status_t *status); bool mc_writer_write_buffer(mc_writer_t *writer, const _mongocrypt_buffer_t *buf, uint64_t length, mongocrypt_status_t *status); bool mc_writer_write_uuid_buffer(mc_writer_t *writer, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); bool mc_writer_write_prfblock_buffer(mc_writer_t *writer, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status); #endif /* MONGOCRYPT_READER_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mc-writer.c0000644000175100001660000001221614760300420016462 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "mongocrypt-private.h" #include "mc-writer-private.h" #define CHECK_AND_RETURN(x) \ if (!(x)) { \ return false; \ } #define CHECK_REMAINING_BUFFER_AND_RET(write_size) \ if ((write_size) > writer->len - writer->pos) { \ CLIENT_ERR("%s expected at most %" PRIu64 " bytes, got: %" PRIu64, \ writer->parser_name, \ (writer->len - writer->pos), \ (uint64_t)(write_size)); \ return false; \ } void mc_writer_init(mc_writer_t *writer, uint8_t *ptr, uint64_t len, const char *parser_name) { BSON_ASSERT_PARAM(writer); BSON_ASSERT_PARAM(ptr); BSON_ASSERT_PARAM(parser_name); *writer = (mc_writer_t){.pos = 0u, .ptr = ptr, .len = len, .parser_name = parser_name}; } void mc_writer_init_from_buffer(mc_writer_t *writer, _mongocrypt_buffer_t *buf, const char *parser_name) { BSON_ASSERT_PARAM(writer); BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(parser_name); mc_writer_init(writer, buf->data, buf->len, parser_name); } mc_writer_t *mc_writer_new(uint8_t *ptr, uint64_t len, const char *parser_name) { BSON_ASSERT_PARAM(ptr); BSON_ASSERT_PARAM(parser_name); mc_writer_t *writer = bson_malloc(sizeof(mc_writer_t)); mc_writer_init(writer, ptr, len, parser_name); return writer; } void mc_writer_destroy(mc_writer_t *writer) { bson_free(writer); } bool mc_writer_write_u8(mc_writer_t *writer, const uint8_t value, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(writer); CHECK_REMAINING_BUFFER_AND_RET(sizeof(uint8_t)); memcpy(writer->ptr + writer->pos, &value, sizeof(uint8_t)); writer->pos += sizeof(uint8_t); return true; } bool mc_writer_write_u32(mc_writer_t *writer, const uint32_t value, mongocrypt_status_t *status) { CHECK_REMAINING_BUFFER_AND_RET(sizeof(uint32_t)); uint32_t temp = BSON_UINT32_TO_LE(value); memcpy(writer->ptr + writer->pos, &temp, sizeof(uint32_t)); writer->pos += sizeof(uint32_t); return true; } bool mc_writer_write_u64(mc_writer_t *writer, const uint64_t value, mongocrypt_status_t *status) { CHECK_REMAINING_BUFFER_AND_RET(sizeof(uint64_t)); uint64_t temp = BSON_UINT64_TO_LE(value); memcpy(writer->ptr + writer->pos, &temp, sizeof(uint64_t)); writer->pos += sizeof(uint64_t); return true; } bool mc_writer_write_buffer(mc_writer_t *writer, const _mongocrypt_buffer_t *buf, uint64_t length, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(writer); BSON_ASSERT_PARAM(buf); if (length > buf->len) { CLIENT_ERR("%s cannot write %" PRIu64 " bytes from buffer with length %" PRIu32, writer->parser_name, length, buf->len); return false; } CHECK_REMAINING_BUFFER_AND_RET(length); if (length > SIZE_MAX) { CLIENT_ERR("%s failed to copy " "data of length %" PRIu64, writer->parser_name, length); return false; } memcpy(writer->ptr + writer->pos, buf->data, (size_t)length); writer->pos += length; return true; } bool mc_writer_write_uuid_buffer(mc_writer_t *writer, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(writer); BSON_ASSERT_PARAM(buf); CHECK_AND_RETURN(mc_writer_write_buffer(writer, buf, UUID_LEN, status)); return true; } bool mc_writer_write_prfblock_buffer(mc_writer_t *writer, const _mongocrypt_buffer_t *buf, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(writer); BSON_ASSERT_PARAM(buf); CHECK_AND_RETURN(mc_writer_write_buffer(writer, buf, PRF_LEN, status)); return true; } mongodb-1.21.0/src/libmongocrypt/src/mongo_crypt-v1.h0000644000175100001660000003027514760300420017447 0ustar /** * Copyright (C) 2021-present MongoDB, Inc. */ // clang-format off #ifndef MONGO_CRYPT_SUPPORT_H #define MONGO_CRYPT_SUPPORT_H #include #include #pragma push_macro("MONGO_API_CALL") #undef MONGO_API_CALL #pragma push_macro("MONGO_API_IMPORT") #undef MONGO_API_IMPORT #pragma push_macro("MONGO_API_EXPORT") #undef MONGO_API_EXPORT #pragma push_macro("MONGO_CRYPT_SUPPORT_API") #undef MONGO_CRYPT_SUPPORT_API #if defined(_WIN32) #define MONGO_API_CALL __cdecl #define MONGO_API_IMPORT __declspec(dllimport) #define MONGO_API_EXPORT __declspec(dllexport) #else #define MONGO_API_CALL #define MONGO_API_IMPORT __attribute__((visibility("default"))) #define MONGO_API_EXPORT __attribute__((used, visibility("default"))) #endif #if defined(MONGO_CRYPT_SUPPORT_STATIC) #define MONGO_CRYPT_API #else #if defined(MONGO_CRYPT_SUPPORT_COMPILING) #define MONGO_CRYPT_API MONGO_API_EXPORT #else #define MONGO_CRYPT_API MONGO_API_IMPORT #endif #endif #ifdef __cplusplus extern "C" { #endif /** * An object which describes the details of the failure of an operation. * * The Mongo Crypt Shared Library uses allocated objects of this type to report the details of any * failure, when an operation cannot be completed. Several `mongo_crypt_v1_status` functions are * provided which permit observing the details of these failures. Further a construction function * and a destruction function for these objects are also provided. * * The use of status objects from multiple threads is not thread safe unless all of the threads * accessing a single status object are passing that object as a const-qualified (const * mongo_crypt_v1_status *) pointer. If a single thread is passing a status object to a function * taking it by non-const-qualified (mongo_crypt_v1_status*) pointer, then no other thread may * access the status object. * * The `status` parameter is optional for all `mongo_crypt_v1_` functions that can take a status * pointer. The caller may pass NULL instead of a valid `status` object, in which case the function * will execute normally but will not provide any detailed error information in the caes of a * failure. * * All `mongo_crypt_v1_status` functions can be used before the Mongo Crypt Shared library is * initialized. This facilitates detailed error reporting from all library functions. */ typedef struct mongo_crypt_v1_status mongo_crypt_v1_status; /** * Allocate and construct an API-return-status buffer object. * * Returns NULL when construction of a mongo_crypt_v1_status object fails. * * This function may be called before mongo_crypt_v1_lib_create(). */ MONGO_CRYPT_API mongo_crypt_v1_status* MONGO_API_CALL mongo_crypt_v1_status_create(void); /** * Destroys a valid status object. * * The status object must be a valid mongo_crypt_v1_status object or NULL. * * This function is not thread safe, and it must not execute concurrently with any other function * that accesses the status object being destroyed. It is, however, safe to destroy distinct status * objects on distinct threads. * * This function does not report failures. * * This function may be called before `mongo_crypt_v1_lib_create()`. * * This function causes all storage associated with the specified status object to be released, * including the storage referenced by functions that returned observable storage buffers from this * status, such as strings. */ MONGO_CRYPT_API void MONGO_API_CALL mongo_crypt_v1_status_destroy(mongo_crypt_v1_status* status); /** * The error codes reported by `mongo_crypt_v1` functions will be given the symbolic names as * mapped by this enum. * * When a `mongo_crypt_v1` function fails (and it has been documented to report errors) it will * report that error in the form of an `int` status code. That status code will always be returned * as the type `int`; however, the values in this enum can be used to classify the failure. */ typedef enum { MONGO_CRYPT_V1_ERROR_IN_REPORTING_ERROR = -2, MONGO_CRYPT_V1_ERROR_UNKNOWN = -1, MONGO_CRYPT_V1_SUCCESS = 0, MONGO_CRYPT_V1_ERROR_ENOMEM = 1, MONGO_CRYPT_V1_ERROR_EXCEPTION = 2, MONGO_CRYPT_V1_ERROR_LIBRARY_ALREADY_INITIALIZED = 3, MONGO_CRYPT_V1_ERROR_LIBRARY_NOT_INITIALIZED = 4, MONGO_CRYPT_V1_ERROR_INVALID_LIB_HANDLE = 5, MONGO_CRYPT_V1_ERROR_REENTRANCY_NOT_ALLOWED = 6, } mongo_crypt_v1_error; /** * Gets an error code from a `mongo_crypt_v1_status` object. * * When a `mongo_crypt_v1` function fails (and it has been documented to report errors) it will * report its error in the form of an `int` status code which is stored into a supplied * `mongo_crypt_v1_status` object, if provided. Some of these functions may also report extra * information, which will be reported by other observer functions. Every `mongo_crypt_v1` * function which reports errors will always update the `Error` code stored in a * `mongo_crypt_v1_status` object, even upon success. * * This function does not report its own failures. */ MONGO_CRYPT_API int MONGO_API_CALL mongo_crypt_v1_status_get_error(const mongo_crypt_v1_status* status); /** * Gets a descriptive error message from a `mongo_crypt_v1_status` object. * * For failures where the error is MONGO_CRYPT_V1_ERROR_EXCEPTION, this returns a string * representation of the internal C++ exception. * * The function to which the specified status object was passed must not have returned * MONGO_CRYPT_V1_SUCCESS as its error code. * * The storage for the returned string is associated with the specified status object, and therefore * it will be deallocated when the status is destroyed using mongo_crypt_v1_status_destroy(). * * This function does not report its own failures. */ MONGO_CRYPT_API const char* MONGO_API_CALL mongo_crypt_v1_status_get_explanation(const mongo_crypt_v1_status* status); /** * Gets a status code from a `mongo_crypt_v1_status` object. * * Returns a numeric status code associated with the status parameter which indicates a sub-category * of failure. * * For any status object that does not have MONGO_CRYPT_V1_ERROR_EXCEPTION as its error, the * value of this code is unspecified. * * This function does not report its own failures. */ MONGO_CRYPT_API int MONGO_API_CALL mongo_crypt_v1_status_get_code(const mongo_crypt_v1_status* status); /** * An object which describes the runtime state of the Mongo Crypt Shared Library. * * The Mongo Crypt Shared Library uses allocated objects of this type to indicate the present state * of the library. Some operations which the library provides need access to this object. Further a * construction function and a destruction function for these objects are also provided. No more * than a single object instance of this type may exist at any given time. * * The use of `mongo_crypt_v1_lib` objects from multiple threads is not thread safe unless all of * the threads accessing a single `mongo_crypt_v1_lib` object are not destroying this object. If * a single thread is passing a `mongo_crypt_v1_lib` to its destruction function, then no other * thread may access the `mongo_crypt_v1_lib` object. */ typedef struct mongo_crypt_v1_lib mongo_crypt_v1_lib; /** * Creates a mongo_crypt_v1_lib object, which stores context for the Mongo Crypt Shared library. A * process should only ever have one mongo_crypt_v1_lib instance. * * On failure, returns NULL and populates the 'status' object if it is not NULL. */ MONGO_CRYPT_API mongo_crypt_v1_lib* MONGO_API_CALL mongo_crypt_v1_lib_create(mongo_crypt_v1_status* status); /** * Tears down the state of this library. Existing mongo_crypt_v1_status objects remain valid. * Existing mongo_crypt_v1_query_analyzer objects created from this library MUST BE destroyed * before destroying the library object. * * The 'lib' parameter must be a valid mongo_crypt_v1_lib instance and must not be NULL. * * The 'status' parameter may be NULL, but must be a valid mongo_crypt_v1_status instance if it * is not NULL. * * Returns MONGO_CRYPT_V1_SUCCESS on success. * * Returns MONGO_CRYPT_V1_ERROR_LIBRARY_NOT_INITIALIZED and modifies 'status' if * mongo_crypt_v1_lib_create() has not been called previously. */ MONGO_CRYPT_API int MONGO_API_CALL mongo_crypt_v1_lib_destroy(mongo_crypt_v1_lib* lib, mongo_crypt_v1_status* status); /** * Returns a product version in 64-bit integer in four 16-bit words, from high to low: * * - Major version * - Minor version * - Revision * - Reserved * * For example, version 6.2.1 would be encoded as: 0x0006000200010000 * */ MONGO_CRYPT_API uint64_t MONGO_API_CALL mongo_crypt_v1_get_version(void); /** * Returns a product version as a text string. The string should not be modified or released * * Examples: * Dev Build/patch: mongo_crypt_v1-rhel80-6.2.1-alpha4-284-g8662e7d * Release build: mongo_crypt_v1-rhel80-6.2.1 */ MONGO_CRYPT_API const char* MONGO_API_CALL mongo_crypt_v1_get_version_str(void); /** * A single query analyzer can be used across repeated calls to mongo_crypt_v1_analyze_query. * * It is not safe to simultaneously invoke mongo_crypt_v1_query_analyzer_create on the same * query analyzer from multiple threads * * It is the client's responsibility to call mongo_crypt_v1_query_analyzer_destroy() to free up * resources used by the query analyzer. Once a query analyzer is destroyed, it is not safe to * call mongo_crypt_v1_analyze_query. */ typedef struct mongo_crypt_v1_query_analyzer mongo_crypt_v1_query_analyzer; /** * Creates a mongo_crypt_v1_query_analyzer object, which stores a parsed collation. * * The 'lib' parameter must be a valid mongo_crypt_v1_lib instance and must not be NULL. * * On failure, it returns NULL and populates the 'status' object if it is not NULL. */ MONGO_CRYPT_API mongo_crypt_v1_query_analyzer* MONGO_API_CALL mongo_crypt_v1_query_analyzer_create(mongo_crypt_v1_lib* lib, mongo_crypt_v1_status* status); /** * Destroys a valid mongo_crypt_v1_query_analyzer object. * * This function is not thread safe, and it must not execute concurrently with any other function * that accesses the collation object being destroyed including those that access a matcher, * projection or update object which references the collation object. * * This function does not report failures. */ MONGO_CRYPT_API void MONGO_API_CALL mongo_crypt_v1_query_analyzer_destroy(mongo_crypt_v1_query_analyzer* analyzer); /** * Analyzes the 'documentBSON' input document which includes a JSON schema for namespace 'ns_str' * and returns a new BSON document that replaces fields that need encryption with BinData * (subtype 6, first byte 0) placeholders. * * The input document must be a valid OP_MSG document supports aggregate, count, delete, distinct, * explain, find, findAndModify, insert and update. * In addition, the input document must include two additional top-level fields: * - jsonSchema : document - contains a valid JSON schema * - isRemoteSchema : bool - true if schema comes from MongoD as opposed to client-side * * The 'analyzer' and 'documentBSON' parameters must point to initialized objects of their * respective types. * * When the analysis is successful, this function returns non-null value which points to a valid * BSON document and updates bson_len with the length of the BSON document */ MONGO_CRYPT_API uint8_t* MONGO_API_CALL mongo_crypt_v1_analyze_query(mongo_crypt_v1_query_analyzer* analyzer, const uint8_t* documentBSON, const char* ns_str, uint32_t ns_len, uint32_t* bson_len, mongo_crypt_v1_status* status); /** * Free the memory of a BSON buffer returned by mongo_crypt_v1_analyze_query(). This function can be * safely called on a NULL pointer. * * This function can be called at any time to deallocate a BSON buffer and will not invalidate any * library object. */ MONGO_CRYPT_API void MONGO_API_CALL mongo_crypt_v1_bson_free(uint8_t* bson); #ifdef __cplusplus } // extern "C" #endif #undef MONGO_CRYPT_SUPPORT_API #pragma pop_macro("MONGO_CRYPT_SUPPORT_API") #undef MONGO_API_EXPORT #pragma push_macro("MONGO_API_EXPORT") #undef MONGO_API_IMPORT #pragma push_macro("MONGO_API_IMPORT") #undef MONGO_API_CALL #pragma pop_macro("MONGO_API_CALL") #endif // MONGO_CRYPT_SUPPORT_H mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-binary-private.h0000644000175100001660000000155114760300420021711 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef MONGOCRYPT_BINARY_PRIVATE_H #define MONGOCRYPT_BINARY_PRIVATE_H #include #include "mongocrypt.h" bool _mongocrypt_binary_to_bson(mongocrypt_binary_t *binary, bson_t *out) MONGOCRYPT_WARN_UNUSED_RESULT; #endif /* MONGOCRYPT_BINARY_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-binary.c0000644000175100001660000000341114760300420020231 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include #include "mongocrypt-binary-private.h" #include "mongocrypt-buffer-private.h" mongocrypt_binary_t *mongocrypt_binary_new(void) { mongocrypt_binary_t *binary; binary = (mongocrypt_binary_t *)bson_malloc0(sizeof *binary); return binary; } mongocrypt_binary_t *mongocrypt_binary_new_from_data(uint8_t *data, uint32_t len) { mongocrypt_binary_t *binary; BSON_ASSERT_PARAM(data); binary = (mongocrypt_binary_t *)bson_malloc0(sizeof *binary); BSON_ASSERT(binary); binary->data = data; binary->len = len; return binary; } bool _mongocrypt_binary_to_bson(mongocrypt_binary_t *binary, bson_t *out) { BSON_ASSERT_PARAM(binary); BSON_ASSERT_PARAM(out); return bson_init_static(out, binary->data, binary->len); } uint8_t *mongocrypt_binary_data(const mongocrypt_binary_t *binary) { if (!binary) { return NULL; } return binary->data; } uint32_t mongocrypt_binary_len(const mongocrypt_binary_t *binary) { if (!binary) { return 0; } return binary->len; } void mongocrypt_binary_destroy(mongocrypt_binary_t *binary) { if (!binary) { return; } bson_free(binary); } mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-buffer-private.h0000644000175100001660000001556614760300420021711 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef MONGOCRYPT_BUFFER_H #define MONGOCRYPT_BUFFER_H #include "mongocrypt-binary-private.h" #include "mongocrypt-compat.h" #include #define UUID_LEN 16 #define PRF_LEN 32 struct _mongocrypt_binary_t; /* An internal struct to make working with binary values more convenient. * - a non-owning buffer can be constructed from a bson_iter_t. * - a non-owning buffer can become an owned buffer by copying. * - a buffer can be appended as a BSON binary in a bson_t. */ typedef struct __mongocrypt_buffer_t { uint8_t *data; uint32_t len; bool owned; bson_subtype_t subtype; mongocrypt_binary_t bin; } _mongocrypt_buffer_t; void _mongocrypt_buffer_init(_mongocrypt_buffer_t *buf); void _mongocrypt_buffer_resize(_mongocrypt_buffer_t *buf, uint32_t len); void _mongocrypt_buffer_init_size(_mongocrypt_buffer_t *buf, uint32_t len); void _mongocrypt_buffer_steal(_mongocrypt_buffer_t *buf, _mongocrypt_buffer_t *src); /* @iter is iterated to a BSON binary value. */ bool _mongocrypt_buffer_copy_from_binary_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) MONGOCRYPT_WARN_UNUSED_RESULT; /* @iter is iterated to a BSON binary value. */ bool _mongocrypt_buffer_from_binary_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) MONGOCRYPT_WARN_UNUSED_RESULT; /* @iter is iterated to a BSON document value. */ bool _mongocrypt_buffer_from_document_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) MONGOCRYPT_WARN_UNUSED_RESULT; /* @iter is iterated to a BSON document value. */ bool _mongocrypt_buffer_copy_from_document_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) MONGOCRYPT_WARN_UNUSED_RESULT; void _mongocrypt_buffer_steal_from_bson(_mongocrypt_buffer_t *buf, bson_t *bson); void _mongocrypt_buffer_from_bson(_mongocrypt_buffer_t *buf, const bson_t *bson); bool _mongocrypt_buffer_to_bson(const _mongocrypt_buffer_t *buf, bson_t *bson) MONGOCRYPT_WARN_UNUSED_RESULT; bool _mongocrypt_buffer_append(const _mongocrypt_buffer_t *buf, bson_t *bson, const char *key, int key_len) MONGOCRYPT_WARN_UNUSED_RESULT; void _mongocrypt_buffer_from_binary(_mongocrypt_buffer_t *buf, const struct _mongocrypt_binary_t *binary); void _mongocrypt_buffer_copy_from_binary(_mongocrypt_buffer_t *buf, const struct _mongocrypt_binary_t *binary); void _mongocrypt_buffer_to_binary(const _mongocrypt_buffer_t *buf, struct _mongocrypt_binary_t *binary); void _mongocrypt_buffer_copy_to(const _mongocrypt_buffer_t *src, _mongocrypt_buffer_t *dst); void _mongocrypt_buffer_set_to(const _mongocrypt_buffer_t *src, _mongocrypt_buffer_t *dst); int _mongocrypt_buffer_cmp(const _mongocrypt_buffer_t *a, const _mongocrypt_buffer_t *b); void _mongocrypt_buffer_cleanup(_mongocrypt_buffer_t *buf); bool _mongocrypt_buffer_empty(const _mongocrypt_buffer_t *buf); bool _mongocrypt_buffer_to_bson_value(_mongocrypt_buffer_t *plaintext, uint8_t type, bson_value_t *out) MONGOCRYPT_WARN_UNUSED_RESULT; void _mongocrypt_buffer_from_iter(_mongocrypt_buffer_t *plaintext, bson_iter_t *iter); bool _mongocrypt_buffer_from_uuid_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) MONGOCRYPT_WARN_UNUSED_RESULT; bool _mongocrypt_buffer_copy_from_uuid_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) MONGOCRYPT_WARN_UNUSED_RESULT; bool _mongocrypt_buffer_is_uuid(_mongocrypt_buffer_t *buf) MONGOCRYPT_WARN_UNUSED_RESULT; void _mongocrypt_buffer_copy_from_hex(_mongocrypt_buffer_t *buf, const char *hex); int _mongocrypt_buffer_cmp_hex(_mongocrypt_buffer_t *buf, const char *hex); char *_mongocrypt_buffer_to_hex(_mongocrypt_buffer_t *buf) MONGOCRYPT_WARN_UNUSED_RESULT; bool _mongocrypt_buffer_concat(_mongocrypt_buffer_t *dst, const _mongocrypt_buffer_t *srcs, uint32_t num_srcs); struct _mongocrypt_binary_t *_mongocrypt_buffer_as_binary(_mongocrypt_buffer_t *buf); /* _mongocrypt_buffer_copy_from_data_and_size initializes @buf and copies @len * bytes from @data. * - Returns false on error. * - Caller must call _mongocrypt_buffer_cleanup. */ bool _mongocrypt_buffer_copy_from_data_and_size(_mongocrypt_buffer_t *buf, const uint8_t *data, size_t len) MONGOCRYPT_WARN_UNUSED_RESULT; /* _mongocrypt_buffer_steal_from_data_and_size initializes @buf from @data and * @len and takes ownership of @data. * - Returns false on error. * - @buf does not take ownership of @str on error. * - Caller must call _mongocrypt_buffer_cleanup. */ bool _mongocrypt_buffer_steal_from_data_and_size(_mongocrypt_buffer_t *buf, uint8_t *data, size_t len) MONGOCRYPT_WARN_UNUSED_RESULT; /* _mongocrypt_buffer_steal_from_string initializes @buf from @str and takes * ownership of @str. * @buf retains a pointer to @str. * @str must be NULL terminated. * - Returns false on error. * - @buf does not take ownership of @str on error. * - Caller must call _mongocrypt_buffer_cleanup. */ bool _mongocrypt_buffer_steal_from_string(_mongocrypt_buffer_t *buf, char *str) MONGOCRYPT_WARN_UNUSED_RESULT; /* _mongocrypt_buffer_from_string initializes @buf from @str. * @buf retains a pointer to @str. * @str must outlive @buf. * @str must be NULL terminated. * - Returns false on error. * - Caller must call _mongocrypt_buffer_cleanup. */ bool _mongocrypt_buffer_from_string(_mongocrypt_buffer_t *buf, const char *str) MONGOCRYPT_WARN_UNUSED_RESULT; /* _mongocrypt_buffer_copy_from_uint64_le initializes @buf from the * little-endian byte representation of @value. Caller must call * _mongocrypt_buffer_cleanup. * @value is expected to be in machine's native endianness. */ void _mongocrypt_buffer_copy_from_uint64_le(_mongocrypt_buffer_t *buf, uint64_t value); /* _mongocrypt_buffer_from_subrange initializes @out as a non-owning buffer to a * range of data from @in specified by @offset and @len. Returns false on error. */ bool _mongocrypt_buffer_from_subrange(_mongocrypt_buffer_t *out, const _mongocrypt_buffer_t *in, uint32_t offset, uint32_t len) MONGOCRYPT_WARN_UNUSED_RESULT; #endif /* MONGOCRYPT_BUFFER_H */ mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-buffer.c0000644000175100001660000003605014760300420020223 0ustar /* * Copyright 2018-present MongoDB, 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. */ #include "mongocrypt-buffer-private.h" #include "mongocrypt-endian-private.h" #include "mongocrypt-util-private.h" #include // Require libbson 1.16.0 or newer. Fix for CDRIVER-3360 is needed. #if !BSON_CHECK_VERSION(1, 16, 0) #error "libbson 1.16.0 or newer is required." #endif #define INT32_LEN 4 #define TYPE_LEN 1 #define NULL_BYTE_LEN 1 #define NULL_BYTE_VAL 0x00 /* if a buffer is not owned, copy the data and make it owned. */ static void _make_owned(_mongocrypt_buffer_t *buf) { uint8_t *tmp; BSON_ASSERT_PARAM(buf); if (buf->owned) { return; } tmp = buf->data; if (buf->len > 0) { buf->data = bson_malloc(buf->len); BSON_ASSERT(buf->data); memcpy(buf->data, tmp, buf->len); } else { buf->data = NULL; } buf->owned = true; } /* TODO CDRIVER-2990 have buffer operations require initialized buffer to * prevent leaky code. */ void _mongocrypt_buffer_init(_mongocrypt_buffer_t *buf) { BSON_ASSERT_PARAM(buf); memset(buf, 0, sizeof(*buf)); } void _mongocrypt_buffer_resize(_mongocrypt_buffer_t *buf, uint32_t len) { BSON_ASSERT_PARAM(buf); /* Currently this just wipes whatever was in data before, but a fancier implementation could copy over up to 'len' bytes from the old buffer to the new one. */ if (buf->owned) { buf->data = bson_realloc(buf->data, len); buf->len = len; return; } buf->data = bson_malloc(len); BSON_ASSERT(buf->data); buf->len = len; buf->owned = true; } void _mongocrypt_buffer_init_size(_mongocrypt_buffer_t *buf, uint32_t len) { BSON_ASSERT_PARAM(buf); _mongocrypt_buffer_init(buf); _mongocrypt_buffer_resize(buf, len); } void _mongocrypt_buffer_steal(_mongocrypt_buffer_t *buf, _mongocrypt_buffer_t *src) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(src); if (!src->owned) { _mongocrypt_buffer_copy_to(src, buf); _mongocrypt_buffer_init(src); return; } buf->data = src->data; buf->len = src->len; buf->owned = true; _mongocrypt_buffer_init(src); } bool _mongocrypt_buffer_from_binary_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(iter); if (!BSON_ITER_HOLDS_BINARY(iter)) { return false; } _mongocrypt_buffer_init(buf); bson_iter_binary(iter, &buf->subtype, &buf->len, (const uint8_t **)&buf->data); buf->owned = false; return true; } bool _mongocrypt_buffer_copy_from_binary_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(iter); if (!_mongocrypt_buffer_from_binary_iter(buf, iter)) { return false; } _make_owned(buf); return true; } bool _mongocrypt_buffer_from_document_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(iter); if (!BSON_ITER_HOLDS_DOCUMENT(iter)) { return false; } _mongocrypt_buffer_init(buf); bson_iter_document(iter, &buf->len, (const uint8_t **)&buf->data); buf->owned = false; return true; } bool _mongocrypt_buffer_copy_from_document_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(iter); if (!_mongocrypt_buffer_from_document_iter(buf, iter)) { return false; } _make_owned(buf); return true; } void _mongocrypt_buffer_steal_from_bson(_mongocrypt_buffer_t *buf, bson_t *bson) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(bson); _mongocrypt_buffer_init(buf); buf->data = bson_destroy_with_steal(bson, true, &buf->len); buf->owned = true; } void _mongocrypt_buffer_from_bson(_mongocrypt_buffer_t *buf, const bson_t *bson) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(bson); _mongocrypt_buffer_init(buf); buf->data = (uint8_t *)bson_get_data(bson); buf->len = bson->len; buf->owned = false; } bool _mongocrypt_buffer_to_bson(const _mongocrypt_buffer_t *buf, bson_t *bson) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(bson); return bson_init_static(bson, buf->data, buf->len); } bool _mongocrypt_buffer_append(const _mongocrypt_buffer_t *buf, bson_t *bson, const char *key, int key_len) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(bson); BSON_ASSERT_PARAM(key); return bson_append_binary(bson, key, key_len, buf->subtype, buf->data, buf->len); } void _mongocrypt_buffer_from_binary(_mongocrypt_buffer_t *buf, const mongocrypt_binary_t *binary) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(binary); _mongocrypt_buffer_init(buf); buf->data = binary->data; buf->len = binary->len; buf->owned = false; } void _mongocrypt_buffer_copy_from_binary(_mongocrypt_buffer_t *buf, const struct _mongocrypt_binary_t *binary) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(binary); _mongocrypt_buffer_from_binary(buf, binary); _make_owned(buf); } void _mongocrypt_buffer_to_binary(const _mongocrypt_buffer_t *buf, mongocrypt_binary_t *binary) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(binary); binary->data = buf->data; binary->len = buf->len; } void _mongocrypt_buffer_copy_to(const _mongocrypt_buffer_t *src, _mongocrypt_buffer_t *dst) { if (src == dst) { return; } BSON_ASSERT_PARAM(src); BSON_ASSERT_PARAM(dst); _mongocrypt_buffer_cleanup(dst); if (src->len == 0) { return; } dst->data = bson_malloc((size_t)src->len); BSON_ASSERT(dst->data); memcpy(dst->data, src->data, src->len); dst->len = src->len; dst->subtype = src->subtype; dst->owned = true; } void _mongocrypt_buffer_set_to(const _mongocrypt_buffer_t *src, _mongocrypt_buffer_t *dst) { if (src == dst) { return; } BSON_ASSERT_PARAM(src); BSON_ASSERT_PARAM(dst); dst->data = src->data; dst->len = src->len; dst->subtype = src->subtype; dst->owned = false; } int _mongocrypt_buffer_cmp(const _mongocrypt_buffer_t *a, const _mongocrypt_buffer_t *b) { BSON_ASSERT_PARAM(a); BSON_ASSERT_PARAM(b); if (a->len != b->len) { return a->len > b->len ? 1 : -1; } if (0 == a->len) { return 0; } return memcmp(a->data, b->data, a->len); } void _mongocrypt_buffer_cleanup(_mongocrypt_buffer_t *buf) { if (buf && buf->owned) { bson_free(buf->data); } } bool _mongocrypt_buffer_empty(const _mongocrypt_buffer_t *buf) { BSON_ASSERT_PARAM(buf); return buf->data == NULL; } bool _mongocrypt_buffer_to_bson_value(_mongocrypt_buffer_t *plaintext, uint8_t type, bson_value_t *out) { bool ret = false; bson_iter_t iter; bson_t wrapper; uint32_t data_len; uint32_t le_data_len; uint8_t *data; uint8_t data_prefix; BSON_ASSERT_PARAM(plaintext); BSON_ASSERT_PARAM(out); data_prefix = INT32_LEN /* adds document size */ + TYPE_LEN /* element type */ + NULL_BYTE_LEN; /* and doc's null byte terminator */ BSON_ASSERT(plaintext->len <= UINT32_MAX - data_prefix - NULL_BYTE_LEN); data_len = (plaintext->len + data_prefix + NULL_BYTE_LEN); le_data_len = BSON_UINT32_TO_LE(data_len); data = bson_malloc0(data_len); BSON_ASSERT(data); memcpy(data + data_prefix, plaintext->data, plaintext->len); memcpy(data, &le_data_len, INT32_LEN); memcpy(data + INT32_LEN, &type, TYPE_LEN); data[data_len - 1] = NULL_BYTE_VAL; if (!bson_init_static(&wrapper, data, data_len)) { goto fail; } if (!bson_validate(&wrapper, BSON_VALIDATE_NONE, NULL)) { goto fail; } if (!bson_iter_init_find(&iter, &wrapper, "")) { goto fail; } bson_value_copy(bson_iter_value(&iter), out); ret = true; fail: bson_free(data); return ret; } void _mongocrypt_buffer_from_iter(_mongocrypt_buffer_t *plaintext, bson_iter_t *iter) { bson_t wrapper = BSON_INITIALIZER; int32_t offset = INT32_LEN /* skips document size */ + TYPE_LEN /* element type */ + NULL_BYTE_LEN; /* and the key's null byte terminator */ uint8_t *wrapper_data; BSON_ASSERT_PARAM(plaintext); BSON_ASSERT_PARAM(iter); /* It is not straightforward to transform a bson_value_t to a string of * bytes. As a workaround, we wrap the value in a bson document with an empty * key, then use the raw buffer from inside the new bson_t, skipping the * length and type header information and the key name. */ bson_append_iter(&wrapper, "", 0, iter); wrapper_data = ((uint8_t *)bson_get_data(&wrapper)); BSON_ASSERT(wrapper.len >= (uint32_t)offset + NULL_BYTE_LEN); plaintext->len = wrapper.len - (uint32_t)offset - NULL_BYTE_LEN; /* the final null byte */ plaintext->data = bson_malloc(plaintext->len); BSON_ASSERT(plaintext->data); plaintext->owned = true; memcpy(plaintext->data, wrapper_data + offset, plaintext->len); bson_destroy(&wrapper); } bool _mongocrypt_buffer_from_uuid_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) { const uint8_t *data; bson_subtype_t subtype; uint32_t len; BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(iter); if (!BSON_ITER_HOLDS_BINARY(iter)) { return false; } bson_iter_binary(iter, &subtype, &len, &data); if (subtype != BSON_SUBTYPE_UUID) { return false; } if (len != UUID_LEN) { return false; } _mongocrypt_buffer_init(buf); buf->data = (uint8_t *)data; buf->len = len; buf->subtype = subtype; buf->owned = false; return true; } bool _mongocrypt_buffer_copy_from_uuid_iter(_mongocrypt_buffer_t *buf, bson_iter_t *iter) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(iter); if (!_mongocrypt_buffer_from_uuid_iter(buf, iter)) { return false; } _make_owned(buf); return true; } bool _mongocrypt_buffer_is_uuid(_mongocrypt_buffer_t *buf) { BSON_ASSERT_PARAM(buf); return buf->len == UUID_LEN && buf->subtype == BSON_SUBTYPE_UUID; } void _mongocrypt_buffer_copy_from_hex(_mongocrypt_buffer_t *buf, const char *hex) { uint32_t i; size_t hex_len; BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(hex); hex_len = strlen(hex); if (hex_len == 0) { _mongocrypt_buffer_init(buf); return; } BSON_ASSERT(hex_len / 2u <= UINT32_MAX); buf->len = (uint32_t)(hex_len / 2u); buf->data = bson_malloc(buf->len); BSON_ASSERT(buf->data); buf->owned = true; for (i = 0; i < buf->len; i++) { uint32_t tmp; BSON_ASSERT(i <= UINT32_MAX / 2); BSON_ASSERT(sscanf(hex + (2 * i), "%02x", &tmp)); *(buf->data + i) = (uint8_t)tmp; } } int _mongocrypt_buffer_cmp_hex(_mongocrypt_buffer_t *buf, const char *hex) { _mongocrypt_buffer_t tmp; int res; BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(hex); _mongocrypt_buffer_copy_from_hex(&tmp, hex); res = _mongocrypt_buffer_cmp(buf, &tmp); _mongocrypt_buffer_cleanup(&tmp); return res; } char *_mongocrypt_buffer_to_hex(_mongocrypt_buffer_t *buf) { BSON_ASSERT_PARAM(buf); /* since buf->len is a uint32_t, even doubling it won't bring it anywhere * near to SIZE_MAX */ char *hex = bson_malloc0(buf->len * 2 + 1); BSON_ASSERT(hex); char *out = hex; for (uint32_t i = 0; i < buf->len; i++, out += 2) { sprintf(out, "%02X", buf->data[i]); } return hex; } bool _mongocrypt_buffer_concat(_mongocrypt_buffer_t *dst, const _mongocrypt_buffer_t *srcs, uint32_t num_srcs) { uint32_t total = 0; uint32_t offset; uint32_t i; BSON_ASSERT_PARAM(dst); BSON_ASSERT_PARAM(srcs); for (i = 0; i < num_srcs; i++) { uint32_t old_total = total; total += srcs[i].len; /* If the previous operation overflowed, then total will have a smaller * value than previously. */ if (total < old_total) { return false; } } _mongocrypt_buffer_init(dst); _mongocrypt_buffer_resize(dst, total); offset = 0; for (i = 0; i < num_srcs; i++) { if (srcs[i].len) { memcpy(dst->data + offset, srcs[i].data, srcs[i].len); } offset += srcs[i].len; } return true; } struct _mongocrypt_binary_t *_mongocrypt_buffer_as_binary(_mongocrypt_buffer_t *buf) { BSON_ASSERT_PARAM(buf); buf->bin.data = buf->data; buf->bin.len = buf->len; return &buf->bin; } bool _mongocrypt_buffer_copy_from_data_and_size(_mongocrypt_buffer_t *buf, const uint8_t *data, size_t len) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(data); _mongocrypt_buffer_init(buf); if (!size_to_uint32(len, &buf->len)) { return false; } if ((buf->data = bson_malloc(len))) { memcpy(buf->data, data, len); buf->owned = true; } return true; } bool _mongocrypt_buffer_steal_from_data_and_size(_mongocrypt_buffer_t *buf, uint8_t *data, size_t len) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(data); _mongocrypt_buffer_init(buf); if (!size_to_uint32(len, &buf->len)) { return false; } buf->data = data; buf->owned = true; return true; } bool _mongocrypt_buffer_steal_from_string(_mongocrypt_buffer_t *buf, char *str) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(str); _mongocrypt_buffer_init(buf); if (!size_to_uint32(strlen(str), &buf->len)) { return false; } buf->data = (uint8_t *)str; buf->owned = true; return true; } bool _mongocrypt_buffer_from_string(_mongocrypt_buffer_t *buf, const char *str) { BSON_ASSERT_PARAM(buf); BSON_ASSERT_PARAM(str); _mongocrypt_buffer_init(buf); if (!size_to_uint32(strlen(str), &buf->len)) { return false; } buf->data = (uint8_t *)str; buf->owned = false; return true; } void _mongocrypt_buffer_copy_from_uint64_le(_mongocrypt_buffer_t *buf, uint64_t value) { uint64_t value_le = MONGOCRYPT_UINT64_TO_LE(value); BSON_ASSERT_PARAM(buf); _mongocrypt_buffer_init(buf); _mongocrypt_buffer_resize(buf, sizeof(value)); memcpy(buf->data, &value_le, buf->len); } bool _mongocrypt_buffer_from_subrange(_mongocrypt_buffer_t *out, const _mongocrypt_buffer_t *in, uint32_t offset, uint32_t len) { BSON_ASSERT_PARAM(out); BSON_ASSERT_PARAM(in); _mongocrypt_buffer_init(out); BSON_ASSERT(offset <= UINT32_MAX - len); if (offset + len > in->len) { return false; } out->data = in->data + offset; out->len = len; return true; } mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-cache-collinfo-private.h0000644000175100001660000000151614760300420023274 0ustar /* * Copyright 2019-present MongoDB, 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. */ #ifndef MONGOCRYPT_CACHE_COLLINFO_PRIVATE_H #define MONGOCRYPT_CACHE_COLLINFO_PRIVATE_H #include "mongocrypt-cache-private.h" void _mongocrypt_cache_collinfo_init(_mongocrypt_cache_t *cache); #endif /* MONGOCRYPT_CACHE_COLLINFO_PRIVATE_H */mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-cache-collinfo.c0000644000175100001660000000327414760300420021622 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "mongocrypt-cache-private.h" /* The collinfo cache. * * Attribute is a null terminated namespace. * Value is a collection info doc (response to listCollections). */ static bool _cmp_attr(void *a, void *b, int *out) { BSON_ASSERT_PARAM(a); BSON_ASSERT_PARAM(b); BSON_ASSERT_PARAM(out); *out = strcmp((char *)a, (char *)b); return true; } static void *_copy_attr(void *ns) { BSON_ASSERT_PARAM(ns); return bson_strdup((const char *)ns); } static void _destroy_attr(void *ns) { bson_free(ns); } static void *_copy_value(void *bson) { BSON_ASSERT_PARAM(bson); return bson_copy(bson); } static void _destroy_value(void *bson) { bson_destroy(bson); } void _mongocrypt_cache_collinfo_init(_mongocrypt_cache_t *cache) { BSON_ASSERT_PARAM(cache); cache->cmp_attr = _cmp_attr; cache->copy_attr = _copy_attr; cache->destroy_attr = _destroy_attr; cache->copy_value = _copy_value; cache->destroy_value = _destroy_value; _mongocrypt_mutex_init(&cache->mutex); cache->pair = NULL; cache->expiration = CACHE_EXPIRATION_MS_DEFAULT; } mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-cache-key-private.h0000644000175100001660000000347714760300420022267 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef MONGOCRYPT_CACHE_KEY_PRIVATE_H #define MONGOCRYPT_CACHE_KEY_PRIVATE_H #include "mongocrypt-buffer-private.h" #include "mongocrypt-cache-private.h" #include "mongocrypt-key-private.h" #include "mongocrypt-mutex-private.h" #include "mongocrypt-opts-private.h" #include "mongocrypt-status-private.h" typedef struct { _mongocrypt_key_doc_t *key_doc; _mongocrypt_buffer_t decrypted_key_material; } _mongocrypt_cache_key_value_t; typedef struct { _mongocrypt_buffer_t id; /* may be empty */ _mongocrypt_key_alt_name_t *alt_names; /* may be NULL */ } _mongocrypt_cache_key_attr_t; void _mongocrypt_cache_key_init(_mongocrypt_cache_t *cache); _mongocrypt_cache_key_attr_t *_mongocrypt_cache_key_attr_new(_mongocrypt_buffer_t *id, _mongocrypt_key_alt_name_t *alt_names); _mongocrypt_cache_key_value_t *_mongocrypt_cache_key_value_new(_mongocrypt_key_doc_t *key_doc, _mongocrypt_buffer_t *decrypted_key_material); void _mongocrypt_cache_key_value_destroy(void *value); void _mongocrypt_cache_key_attr_destroy(_mongocrypt_cache_key_attr_t *attr); #endif /* MONGOCRYPT_CACHE_KEY_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-cache-key.c0000644000175100001660000001156314760300420020605 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "mongocrypt-cache-key-private.h" /* The key cache. * * Attribute is a UUID in the form of a _mongocrypt_buffer_t. * Value contains a key document and decrypted key material. */ /* returns true on success. out is set to 0 if equal, non-zero otherwise. */ static bool _cmp_attr(void *a, void *b, int *out) { _mongocrypt_cache_key_attr_t *attr_a, *attr_b; BSON_ASSERT_PARAM(a); BSON_ASSERT_PARAM(b); BSON_ASSERT_PARAM(out); *out = 1; attr_a = (_mongocrypt_cache_key_attr_t *)a; attr_b = (_mongocrypt_cache_key_attr_t *)b; if (!_mongocrypt_buffer_empty(&attr_a->id) && !_mongocrypt_buffer_empty(&attr_b->id)) { if (0 == _mongocrypt_buffer_cmp(&attr_a->id, &attr_b->id)) { *out = 0; } } if (_mongocrypt_key_alt_name_intersects(attr_a->alt_names, attr_b->alt_names)) { *out = 0; } /* No error. */ return true; } static void *_copy_attr(void *attr) { _mongocrypt_cache_key_attr_t *src; BSON_ASSERT_PARAM(attr); src = (_mongocrypt_cache_key_attr_t *)attr; return _mongocrypt_cache_key_attr_new(&src->id, src->alt_names); } static void _destroy_attr(void *attr) { _mongocrypt_cache_key_attr_destroy(attr); } static void *_copy_contents(void *value) { _mongocrypt_cache_key_value_t *key_value; BSON_ASSERT_PARAM(value); key_value = (_mongocrypt_cache_key_value_t *)value; return _mongocrypt_cache_key_value_new(key_value->key_doc, &key_value->decrypted_key_material); } static void _dump_attr(void *attr_in) { _mongocrypt_cache_key_attr_t *attr; _mongocrypt_key_alt_name_t *altname; char *hex; BSON_ASSERT_PARAM(attr_in); attr = (_mongocrypt_cache_key_attr_t *)attr_in; hex = _mongocrypt_buffer_to_hex(&attr->id); printf("_id=%s,", hex); printf("keyAltNames="); for (altname = attr->alt_names; NULL != altname; altname = altname->next) { printf("%s\n", _mongocrypt_key_alt_name_get_string(altname)); } bson_free(hex); } _mongocrypt_cache_key_value_t *_mongocrypt_cache_key_value_new(_mongocrypt_key_doc_t *key_doc, _mongocrypt_buffer_t *decrypted_key_material) { _mongocrypt_cache_key_value_t *key_value; BSON_ASSERT_PARAM(key_doc); BSON_ASSERT_PARAM(decrypted_key_material); key_value = bson_malloc0(sizeof(*key_value)); BSON_ASSERT(key_value); _mongocrypt_buffer_copy_to(decrypted_key_material, &key_value->decrypted_key_material); key_value->key_doc = _mongocrypt_key_new(); _mongocrypt_key_doc_copy_to(key_doc, key_value->key_doc); return key_value; } void _mongocrypt_cache_key_value_destroy(void *value) { _mongocrypt_cache_key_value_t *key_value; if (!value) { return; } key_value = (_mongocrypt_cache_key_value_t *)value; _mongocrypt_key_destroy(key_value->key_doc); _mongocrypt_buffer_cleanup(&key_value->decrypted_key_material); bson_free(key_value); } void _mongocrypt_cache_key_init(_mongocrypt_cache_t *cache) { BSON_ASSERT_PARAM(cache); cache->cmp_attr = _cmp_attr; cache->copy_attr = _copy_attr; cache->destroy_attr = _destroy_attr; cache->copy_value = _copy_contents; cache->destroy_value = _mongocrypt_cache_key_value_destroy; cache->dump_attr = _dump_attr; _mongocrypt_mutex_init(&cache->mutex); cache->pair = NULL; cache->expiration = CACHE_EXPIRATION_MS_DEFAULT; } /* Since key cache may be looked up by either _id or keyAltName, * "id" or "alt_names" may be NULL, but not both. Returns NULL on error. */ _mongocrypt_cache_key_attr_t *_mongocrypt_cache_key_attr_new(_mongocrypt_buffer_t *id, _mongocrypt_key_alt_name_t *alt_names) { _mongocrypt_cache_key_attr_t *attr; if (NULL == id && NULL == alt_names) { return NULL; } attr = bson_malloc0(sizeof(*attr)); BSON_ASSERT(attr); if (id) { _mongocrypt_buffer_copy_to(id, &attr->id); } attr->alt_names = _mongocrypt_key_alt_name_copy_all(alt_names); return attr; } void _mongocrypt_cache_key_attr_destroy(_mongocrypt_cache_key_attr_t *attr) { if (!attr) { return; } _mongocrypt_buffer_cleanup(&attr->id); _mongocrypt_key_alt_name_destroy_all(attr->alt_names); bson_free(attr); } mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-cache-oauth-private.h0000644000175100001660000000322214760300420022603 0ustar /* * Copyright 2020-present MongoDB, 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. */ #ifndef MONGOCRYPT_CACHE_OAUTH_PRIVATE_H #define MONGOCRYPT_CACHE_OAUTH_PRIVATE_H #include "mongocrypt-mutex-private.h" #include "mongocrypt-status-private.h" // `mc_mapof_kmsid_to_token_t` maps a KMS ID (e.g. `azure` or `azure:myname`) to an OAuth token. typedef struct _mc_mapof_kmsid_to_token_t mc_mapof_kmsid_to_token_t; mc_mapof_kmsid_to_token_t *mc_mapof_kmsid_to_token_new(void); void mc_mapof_kmsid_to_token_destroy(mc_mapof_kmsid_to_token_t *k2t); // `mc_mapof_kmsid_to_token_get_token` returns a copy of the base64 encoded oauth token, or NULL. // Thread-safe. char *mc_mapof_kmsid_to_token_get_token(mc_mapof_kmsid_to_token_t *k2t, const char *kmsid); // `mc_mapof_kmsid_to_token_add_response` overwrites an entry if `kms_id` exists. // Thread-safe. bool mc_mapof_kmsid_to_token_add_response(mc_mapof_kmsid_to_token_t *k2t, const char *kmsid, bson_t *response, mongocrypt_status_t *status); #endif /* MONGOCRYPT_CACHE_OAUTH_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-cache-oauth.c0000644000175100001660000001252114760300420021130 0ustar /* * Copyright 2020-present MongoDB, 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. */ #include "mongocrypt-cache-oauth-private.h" #include "mc-array-private.h" #include "mongocrypt-private.h" /* How long before the reported "expires_in" time cache entries get evicted. * This is intended to prevent use of an oauth token too close to the expiration * time. */ #define MONGOCRYPT_OAUTH_CACHE_EVICTION_PERIOD_US 5000 * 1000 typedef struct { char *kmsid; char *access_token; int64_t expiration_time_us; } mc_mapof_kmsid_to_token_entry_t; struct _mc_mapof_kmsid_to_token_t { mc_array_t entries; mongocrypt_mutex_t mutex; // Guards `entries`. }; mc_mapof_kmsid_to_token_t *mc_mapof_kmsid_to_token_new(void) { mc_mapof_kmsid_to_token_t *k2t = bson_malloc0(sizeof(mc_mapof_kmsid_to_token_t)); _mc_array_init(&k2t->entries, sizeof(mc_mapof_kmsid_to_token_entry_t)); _mongocrypt_mutex_init(&k2t->mutex); return k2t; } void mc_mapof_kmsid_to_token_destroy(mc_mapof_kmsid_to_token_t *k2t) { if (!k2t) { return; } _mongocrypt_mutex_cleanup(&k2t->mutex); for (size_t i = 0; i < k2t->entries.len; i++) { mc_mapof_kmsid_to_token_entry_t k2te = _mc_array_index(&k2t->entries, mc_mapof_kmsid_to_token_entry_t, i); bson_free(k2te.kmsid); bson_free(k2te.access_token); } _mc_array_destroy(&k2t->entries); bson_free(k2t); } char *mc_mapof_kmsid_to_token_get_token(mc_mapof_kmsid_to_token_t *k2t, const char *kmsid) { BSON_ASSERT_PARAM(k2t); BSON_ASSERT_PARAM(kmsid); _mongocrypt_mutex_lock(&k2t->mutex); for (size_t i = 0; i < k2t->entries.len; i++) { mc_mapof_kmsid_to_token_entry_t k2te = _mc_array_index(&k2t->entries, mc_mapof_kmsid_to_token_entry_t, i); if (0 == strcmp(k2te.kmsid, kmsid)) { if (bson_get_monotonic_time() >= k2te.expiration_time_us) { // Expired. _mongocrypt_mutex_unlock(&k2t->mutex); return NULL; } char *access_token = bson_strdup(k2te.access_token); _mongocrypt_mutex_unlock(&k2t->mutex); return access_token; } } _mongocrypt_mutex_unlock(&k2t->mutex); return NULL; } bool mc_mapof_kmsid_to_token_add_response(mc_mapof_kmsid_to_token_t *k2t, const char *kmsid, bson_t *response, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(k2t); BSON_ASSERT_PARAM(kmsid); BSON_ASSERT_PARAM(response); // Parse access token before locking. const char *access_token; int64_t expiration_time_us; { bson_iter_t iter; int64_t cache_time_us; int64_t expires_in_s; int64_t expires_in_us; /* The OAuth spec strongly implies that the value of expires_in is positive, * so the overflow checks in this function don't consider negative values. */ if (!bson_iter_init_find(&iter, response, "expires_in") || !BSON_ITER_HOLDS_INT(&iter)) { CLIENT_ERR("OAuth response invalid, no 'expires_in' field."); return false; } cache_time_us = bson_get_monotonic_time(); expires_in_s = bson_iter_as_int64(&iter); BSON_ASSERT(expires_in_s <= INT64_MAX / 1000 / 1000); expires_in_us = expires_in_s * 1000 * 1000; BSON_ASSERT(expires_in_us <= INT64_MAX - cache_time_us && expires_in_us + cache_time_us > MONGOCRYPT_OAUTH_CACHE_EVICTION_PERIOD_US); expiration_time_us = expires_in_us + cache_time_us - MONGOCRYPT_OAUTH_CACHE_EVICTION_PERIOD_US; if (!bson_iter_init_find(&iter, response, "access_token") || !BSON_ITER_HOLDS_UTF8(&iter)) { CLIENT_ERR("OAuth response invalid, no 'access_token' field."); return false; } access_token = bson_iter_utf8(&iter, NULL); } _mongocrypt_mutex_lock(&k2t->mutex); // Check if there is an existing entry. for (size_t i = 0; i < k2t->entries.len; i++) { mc_mapof_kmsid_to_token_entry_t *k2te = &_mc_array_index(&k2t->entries, mc_mapof_kmsid_to_token_entry_t, i); if (0 == strcmp(k2te->kmsid, kmsid)) { // Update entry. bson_free(k2te->access_token); k2te->access_token = bson_strdup(access_token); k2te->expiration_time_us = expiration_time_us; _mongocrypt_mutex_unlock(&k2t->mutex); return true; } } // Create an entry. mc_mapof_kmsid_to_token_entry_t to_put = {.kmsid = bson_strdup(kmsid), .access_token = bson_strdup(access_token), .expiration_time_us = expiration_time_us}; _mc_array_append_val(&k2t->entries, to_put); _mongocrypt_mutex_unlock(&k2t->mutex); return true; } mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-cache-private.h0000644000175100001660000000526714760300420021500 0ustar /* * Copyright 2019-present MongoDB, 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. */ #ifndef MONGOCRYPT_CACHE_PRIVATE #define MONGOCRYPT_CACHE_PRIVATE #include "mongocrypt-buffer-private.h" #include "mongocrypt-mutex-private.h" #include "mongocrypt-status-private.h" #define CACHE_EXPIRATION_MS_DEFAULT 60000 /* A generic simple cache. * To avoid overusing the names "key" or "id", the cache contains * "attribute-value" pairs. * https://en.wikipedia.org/wiki/Attribute%E2%80%93value_pair */ typedef bool (*cache_compare_fn)(void *thing_a, void *thing_b, int *out); typedef void (*cache_destroy_fn)(void *thing); typedef void *(*cache_copy_fn)(void *thing); typedef void (*cache_dump_fn)(void *thing); typedef struct __mongocrypt_cache_pair_t { void *attr; void *value; struct __mongocrypt_cache_pair_t *next; int64_t last_updated; } _mongocrypt_cache_pair_t; typedef struct { cache_dump_fn dump_attr; cache_compare_fn cmp_attr; cache_copy_fn copy_attr; cache_destroy_fn destroy_attr; cache_copy_fn copy_value; cache_destroy_fn destroy_value; _mongocrypt_cache_pair_t *pair; mongocrypt_mutex_t mutex; /* global lock of cache. */ uint64_t expiration; } _mongocrypt_cache_t; /* Attempt to get an entry. * Returns boolean indicating success. */ bool _mongocrypt_cache_get(_mongocrypt_cache_t *cache, void *attr, void **value) MONGOCRYPT_WARN_UNUSED_RESULT; bool _mongocrypt_cache_add_copy(_mongocrypt_cache_t *cache, void *attr, void *value, mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT; /* Steals the value instead of copying. Caller relinquishes value when calling. */ bool _mongocrypt_cache_add_stolen(_mongocrypt_cache_t *cache, void *attr, void *value, mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT; void _mongocrypt_cache_cleanup(_mongocrypt_cache_t *cache); /* A helper debug function to dump the state of the cache. */ void _mongocrypt_cache_dump(_mongocrypt_cache_t *cache); /* Tests may override the default expiration */ void _mongocrypt_cache_set_expiration(_mongocrypt_cache_t *cache, uint64_t milli); uint32_t _mongocrypt_cache_num_entries(_mongocrypt_cache_t *cache); #endif /* MONGOCRYPT_CACHE_PRIVATE */ mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-cache.c0000644000175100001660000001716014760300420020016 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "mongocrypt-cache-private.h" #include "mongocrypt-private.h" /* Did the cache pair expire? Caller must hold lock. */ static bool _pair_expired(_mongocrypt_cache_t *cache, _mongocrypt_cache_pair_t *pair) { int64_t current; BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(pair); current = bson_get_monotonic_time() / 1000; BSON_ASSERT(current >= INT64_MIN + pair->last_updated); BSON_ASSERT(cache->expiration <= INT64_MAX); return cache->expiration > 0 && (current - pair->last_updated) > (int64_t)cache->expiration; } /* Return the pair after the one being destroyed. */ static _mongocrypt_cache_pair_t * _destroy_pair(_mongocrypt_cache_t *cache, _mongocrypt_cache_pair_t *prev, _mongocrypt_cache_pair_t *pair) { _mongocrypt_cache_pair_t *tmp; BSON_ASSERT_PARAM(cache); /* prev is checked before being used, so it can be NULL */ BSON_ASSERT_PARAM(pair); tmp = pair->next; /* Unlink */ if (!prev) { cache->pair = cache->pair->next; } else { prev->next = pair->next; } /* Destroy pair */ cache->destroy_attr(pair->attr); cache->destroy_value(pair->value); bson_free(pair); return tmp; } /* Caller must hold mutex. */ static void _mongocrypt_cache_evict(_mongocrypt_cache_t *cache) { _mongocrypt_cache_pair_t *pair, *prev; BSON_ASSERT_PARAM(cache); prev = NULL; pair = cache->pair; while (pair) { if (_pair_expired(cache, pair)) { pair = _destroy_pair(cache, prev, pair); continue; } prev = pair; pair = pair->next; } } /* Caller must hold mutex. */ static bool _mongocrypt_remove_matches(_mongocrypt_cache_t *cache, void *attr) { _mongocrypt_cache_pair_t *pair, *prev; BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(attr); prev = NULL; pair = cache->pair; while (pair) { int res; if (!cache->cmp_attr(pair->attr, attr, &res)) { return false; } if (0 == res) { pair = _destroy_pair(cache, prev, pair); continue; } prev = pair; pair = pair->next; } return true; } void _mongocrypt_cache_set_expiration(_mongocrypt_cache_t *cache, uint64_t milli) { BSON_ASSERT_PARAM(cache); cache->expiration = milli; } /* caller must hold lock. */ static bool _find_pair(_mongocrypt_cache_t *cache, void *attr, _mongocrypt_cache_pair_t **out) { _mongocrypt_cache_pair_t *pair; BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(attr); BSON_ASSERT_PARAM(out); *out = NULL; pair = cache->pair; while (pair) { int res; /* TODO: this is a naive O(n) lookup. Consider optimizing with a hash map (possibly vendor one). */ if (!cache->cmp_attr(pair->attr, attr, &res)) { return false; } if (res == 0) { *out = pair; return true; } pair = pair->next; } return true; } /* Create a new pair on linked list. Caller must hold lock. */ static _mongocrypt_cache_pair_t *_pair_new(_mongocrypt_cache_t *cache, void *attr) { _mongocrypt_cache_pair_t *pair; BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(attr); pair = bson_malloc0(sizeof(_mongocrypt_cache_pair_t)); BSON_ASSERT(pair); pair->attr = cache->copy_attr(attr); /* add rest of values. */ pair->next = cache->pair; pair->last_updated = bson_get_monotonic_time() / 1000; cache->pair = pair; return pair; } /* Caller must hold lock. */ static void _cache_pair_destroy(_mongocrypt_cache_t *cache, _mongocrypt_cache_pair_t *pair) { BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(pair); cache->destroy_attr(pair->attr); cache->destroy_value(pair->value); bson_free(pair); } bool _mongocrypt_cache_get(_mongocrypt_cache_t *cache, void *attr, /* attr of cache item */ void **value /* copied to. */) { _mongocrypt_cache_pair_t *match; BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(attr); BSON_ASSERT_PARAM(value); *value = NULL; _mongocrypt_mutex_lock(&cache->mutex); /* TODO CDRIVER-3120: optimize the eviction algorithm to avoid unnecessary * O(n) traversal */ _mongocrypt_cache_evict(cache); if (!_find_pair(cache, attr, &match)) { _mongocrypt_mutex_unlock(&cache->mutex); return false; } if (match) { *value = cache->copy_value(match->value); } _mongocrypt_mutex_unlock(&cache->mutex); return true; } static bool _cache_add(_mongocrypt_cache_t *cache, void *attr, void *value, mongocrypt_status_t *status, bool steal_value) { _mongocrypt_cache_pair_t *pair; BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(attr); BSON_ASSERT_PARAM(value); _mongocrypt_mutex_lock(&cache->mutex); _mongocrypt_cache_evict(cache); if (!_mongocrypt_remove_matches(cache, attr)) { CLIENT_ERR("error removing from cache"); _mongocrypt_mutex_unlock(&cache->mutex); return false; } pair = _pair_new(cache, attr); if (steal_value) { pair->value = value; } else { pair->value = cache->copy_value(value); } _mongocrypt_mutex_unlock(&cache->mutex); return true; } bool _mongocrypt_cache_add_copy(_mongocrypt_cache_t *cache, void *attr, void *value, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(attr); BSON_ASSERT_PARAM(value); return _cache_add(cache, attr, value, status, false); } bool _mongocrypt_cache_add_stolen(_mongocrypt_cache_t *cache, void *attr, void *value, mongocrypt_status_t *status) { BSON_ASSERT_PARAM(cache); BSON_ASSERT_PARAM(attr); BSON_ASSERT_PARAM(value); return _cache_add(cache, attr, value, status, true); } void _mongocrypt_cache_cleanup(_mongocrypt_cache_t *cache) { _mongocrypt_cache_pair_t *pair, *tmp; if (!cache) { return; } pair = cache->pair; while (pair) { tmp = pair->next; _cache_pair_destroy(cache, pair); pair = tmp; } } /* Print the contents of the cache (for debugging purposes) */ void _mongocrypt_cache_dump(_mongocrypt_cache_t *cache) { _mongocrypt_cache_pair_t *pair; int count; BSON_ASSERT_PARAM(cache); _mongocrypt_mutex_lock(&cache->mutex); count = 0; for (pair = cache->pair; pair != NULL; pair = pair->next) { /* don't check that int64_t fits in int, since this is only diagnostic */ printf("entry:%d last_updated:%d\n", count, (int)pair->last_updated); if (cache->dump_attr) { printf("- attr:"); cache->dump_attr(pair->attr); } count++; } _mongocrypt_mutex_unlock(&cache->mutex); } uint32_t _mongocrypt_cache_num_entries(_mongocrypt_cache_t *cache) { _mongocrypt_cache_pair_t *pair; uint32_t count; BSON_ASSERT_PARAM(cache); _mongocrypt_mutex_lock(&cache->mutex); count = 0; for (pair = cache->pair; pair != NULL; pair = pair->next) { count++; } _mongocrypt_mutex_unlock(&cache->mutex); return count; } mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-ciphertext-private.h0000644000175100001660000000373714760300420022614 0ustar /* * Copyright 2019-present MongoDB, 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. */ #ifndef MONGOCRYPT_CIPHERTEXT_PRIVATE_H #define MONGOCRYPT_CIPHERTEXT_PRIVATE_H #include "mc-fle-blob-subtype-private.h" #include "mongocrypt-buffer-private.h" #include "mongocrypt.h" /** * Produced by mongocrypt-marking.c from _mongocrypt_marking_t * as encrypted payloads for blob_subtypes: * FLE1DeterministicEncryptedValue(1) * FLE1RandomEncryptedValue(2) * FLE2InsertUpdatePayload(4) */ typedef struct { _mongocrypt_buffer_t key_id; mc_fle_blob_subtype_t blob_subtype; uint8_t original_bson_type; _mongocrypt_buffer_t data; } _mongocrypt_ciphertext_t; void _mongocrypt_ciphertext_init(_mongocrypt_ciphertext_t *ciphertext); void _mongocrypt_ciphertext_cleanup(_mongocrypt_ciphertext_t *ciphertext); bool _mongocrypt_ciphertext_parse_unowned(_mongocrypt_buffer_t *in, _mongocrypt_ciphertext_t *ciphertext, mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT; bool _mongocrypt_serialize_ciphertext(_mongocrypt_ciphertext_t *ciphertext, _mongocrypt_buffer_t *out) MONGOCRYPT_WARN_UNUSED_RESULT; bool _mongocrypt_ciphertext_serialize_associated_data(_mongocrypt_ciphertext_t *ciphertext, _mongocrypt_buffer_t *out) MONGOCRYPT_WARN_UNUSED_RESULT; #endif /* MONGOCRYPT_CIPHERTEXT_PRIVATE_H */ mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-ciphertext.c0000644000175100001660000001245714760300420021136 0ustar /* * Copyright 2019-present MongoDB, 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. */ #include "mongocrypt-ciphertext-private.h" #include "mongocrypt-private.h" void _mongocrypt_ciphertext_init(_mongocrypt_ciphertext_t *ciphertext) { BSON_ASSERT_PARAM(ciphertext); memset(ciphertext, 0, sizeof(*ciphertext)); } void _mongocrypt_ciphertext_cleanup(_mongocrypt_ciphertext_t *ciphertext) { if (!ciphertext) { return; } _mongocrypt_buffer_cleanup(&ciphertext->key_id); _mongocrypt_buffer_cleanup(&ciphertext->data); } bool _mongocrypt_ciphertext_parse_unowned(_mongocrypt_buffer_t *in, _mongocrypt_ciphertext_t *ciphertext, mongocrypt_status_t *status) { uint32_t offset; /* From BSON Binary subtype 6 specification: struct fle_blob { uint8 fle_blob_subtype = (1 or 2); uint8 key_uuid[16]; uint8 original_bson_type; uint8 ciphertext[ciphertext_length]; } */ if (!ciphertext) { CLIENT_ERR("ciphertext cannot be null"); return false; } if (!in) { CLIENT_ERR("in parameter cannot be null"); return false; } if (!status) { CLIENT_ERR("status cannot be null"); return false; } offset = 0; /* At a minimum, a ciphertext must be 19 bytes: * fle_blob_subtype (1) + * key_uuid (16) + * original_bson_type (1) + * ciphertext (> 0) */ if (in->len < 19) { CLIENT_ERR("malformed ciphertext, too small"); return false; } ciphertext->blob_subtype = in->data[0]; offset += 1; /* TODO: merge new changes. */ if (ciphertext->blob_subtype != 1 && ciphertext->blob_subtype != 2) { CLIENT_ERR("malformed ciphertext, expected blob subtype of 1 or 2"); return false; } _mongocrypt_buffer_init(&ciphertext->key_id); ciphertext->key_id.data = in->data + offset; ciphertext->key_id.len = 16; ciphertext->key_id.subtype = BSON_SUBTYPE_UUID; offset += 16; ciphertext->original_bson_type = in->data[offset]; offset += 1; _mongocrypt_buffer_init(&ciphertext->data); ciphertext->data.data = in->data + offset; ciphertext->data.len = in->len - offset; return true; } bool _mongocrypt_serialize_ciphertext(_mongocrypt_ciphertext_t *ciphertext, _mongocrypt_buffer_t *out) { uint32_t offset; /* From BSON Binary subtype 6 specification: struct fle_blob { uint8 fle_blob_subtype = (1 or 2); uint8 key_uuid[16]; uint8 original_bson_type; uint8 ciphertext[ciphertext_length]; } */ if (!ciphertext || !out) { return false; } if (ciphertext->key_id.len != 16) { return false; } if (ciphertext->key_id.len > (UINT32_MAX - ciphertext->data.len - 1) || ciphertext->key_id.len > (SIZE_MAX - ciphertext->data.len - 1)) { return false; } _mongocrypt_buffer_init(out); offset = 0; out->len = 1 + ciphertext->key_id.len + 1 + ciphertext->data.len; out->data = bson_malloc0(out->len); BSON_ASSERT(out->data); out->owned = true; /* ciphertext->blob_subtype is an enum and easily fits in uint8_t */ out->data[offset] = (uint8_t)ciphertext->blob_subtype; offset += 1; memcpy(out->data + offset, ciphertext->key_id.data, ciphertext->key_id.len); offset += ciphertext->key_id.len; out->data[offset] = ciphertext->original_bson_type; offset += 1; memcpy(out->data + offset, ciphertext->data.data, ciphertext->data.len); return true; } /* From "FLE and AEAD" doc: A = Associated Data = fle_blob_subtype + key_uuid[16] + original_bson_type */ bool _mongocrypt_ciphertext_serialize_associated_data(_mongocrypt_ciphertext_t *ciphertext, _mongocrypt_buffer_t *out) { BSON_ASSERT_PARAM(ciphertext); uint32_t bytes_written = 0; if (!out) { return false; } _mongocrypt_buffer_init(out); if (!ciphertext->original_bson_type) { return false; } if (!_mongocrypt_buffer_is_uuid(&ciphertext->key_id)) { return false; } if ((ciphertext->blob_subtype != MC_SUBTYPE_FLE1DeterministicEncryptedValue) && (ciphertext->blob_subtype != MC_SUBTYPE_FLE1RandomEncryptedValue)) { return false; } if (ciphertext->key_id.len > (UINT32_MAX - 2)) { return false; } out->len = 1 + ciphertext->key_id.len + 1; out->data = bson_malloc(out->len); BSON_ASSERT(out->data); out->owned = true; out->data[bytes_written++] = (uint8_t)ciphertext->blob_subtype; memcpy(out->data + bytes_written, ciphertext->key_id.data, ciphertext->key_id.len); bytes_written += ciphertext->key_id.len; out->data[bytes_written++] = (uint8_t)ciphertext->original_bson_type; return true; } mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-compat.h0000644000175100001660000000246314760300420020243 0ustar /* * Copyright 2018-present MongoDB, 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. */ #ifndef MONGOCRYPT_COMPAT_H #define MONGOCRYPT_COMPAT_H /* Utilities for cross-platform and C89 compatibility */ /* Copied from bson-compat.h from the C driver. */ #include #include #ifdef MONGOCRYPT_HAVE_STDBOOL_H /* TODO - check for stdbool.h if we need to support older compilers and reconile with kms-message's rules for including stdbool.h */ #elif !defined(__bool_true_false_are_defined) #ifndef __cplusplus typedef signed char bool; #define false 0 #define true 1 #endif #define __bool_true_false_are_defined 1 #endif #ifdef __GNUC__ #define MONGOCRYPT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define MONGOCRYPT_WARN_UNUSED_RESULT #endif #endif /* MONGOCRYPT_COMPAT_H */ mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-config.h0000644000175100001660000000440514760300420020223 0ustar /* * Copyright 2019-present MongoDB 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. */ #ifndef MONGOCRYPT_CONFIG_H #define MONGOCRYPT_CONFIG_H /* clang-format off */ /** * @def MONGOCRYPT_VERSION * @brief The version string describing libmongocrypt. * Has the form x.y.z-
++git.
 */
#define MONGOCRYPT_VERSION "1.12.0"

/*
 * MONGOCRYPT_ENABLE_CRYPTO_CNG is set from configure to determine if we are
 * compiled with Native Crypto support on Windows
 */
#define MONGOCRYPT_ENABLE_CRYPTO_CNG 0

#if MONGOCRYPT_ENABLE_CRYPTO_CNG != 1
#  undef MONGOCRYPT_ENABLE_CRYPTO_CNG
#endif


/*
 * MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO is set from configure to determine if we are
 * compiled with Native Crypto support on Darwin
 */
#define MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO 0

#if MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO != 1
#  undef MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO
#endif


/*
 * MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO is set from configure to determine if we are
 * compiled with OpenSSL/LibreSSL (which both use libcrypto) support.
 */
#define MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO 1
#define MONGOCRYPT_ENABLE_CRYPTO_OPENSSL 1

#if MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO != 1
#  undef MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO
#  undef MONGOCRYPT_ENABLE_CRYPTO_OPENSSL
#endif


/*
 * MONGOCRYPT_ENABLE_CRYPTO is set from configure to determine if we are
 * compiled with any crypto support.
 */
#define MONGOCRYPT_ENABLE_CRYPTO 1

#if MONGOCRYPT_ENABLE_CRYPTO != 1
#  undef MONGOCRYPT_ENABLE_CRYPTO
#endif


/*
 * MONGOCRYPT_ENABLE_TRACE is set from configure to determine if we are
 * compiled with tracing support.
 */
#define MONGOCRYPT_ENABLE_TRACE 1

#if MONGOCRYPT_ENABLE_TRACE != 1
#  undef MONGOCRYPT_ENABLE_TRACE
#endif

/* clang-format on */

#endif /* MONGOCRYPT_CONFIG_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-config.h.in0000644000175100001660000000472414760300420020634 0ustar  /*
 * Copyright 2019-present MongoDB 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.
 */

#ifndef MONGOCRYPT_CONFIG_H
#define MONGOCRYPT_CONFIG_H

/* clang-format off */

/**
 * @def MONGOCRYPT_VERSION
 * @brief The version string describing libmongocrypt.
 * Has the form x.y.z-
++git.
 */
#define MONGOCRYPT_VERSION "@MONGOCRYPT_BUILD_VERSION@"

/*
 * MONGOCRYPT_ENABLE_CRYPTO_CNG is set from configure to determine if we are
 * compiled with Native Crypto support on Windows
 */
#define MONGOCRYPT_ENABLE_CRYPTO_CNG @MONGOCRYPT_ENABLE_CRYPTO_CNG@

#if MONGOCRYPT_ENABLE_CRYPTO_CNG != 1
#  undef MONGOCRYPT_ENABLE_CRYPTO_CNG
#endif


/*
 * MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO is set from configure to determine if we are
 * compiled with Native Crypto support on Darwin
 */
#define MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO @MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO@

#if MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO != 1
#  undef MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO
#endif


/*
 * MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO is set from configure to determine if we are
 * compiled with OpenSSL/LibreSSL (which both use libcrypto) support.
 */
#define MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO @MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO@
#define MONGOCRYPT_ENABLE_CRYPTO_OPENSSL @MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO@

#if MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO != 1
#  undef MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO
#  undef MONGOCRYPT_ENABLE_CRYPTO_OPENSSL
#endif


/*
 * MONGOCRYPT_ENABLE_CRYPTO is set from configure to determine if we are
 * compiled with any crypto support.
 */
#define MONGOCRYPT_ENABLE_CRYPTO @MONGOCRYPT_ENABLE_CRYPTO@

#if MONGOCRYPT_ENABLE_CRYPTO != 1
#  undef MONGOCRYPT_ENABLE_CRYPTO
#endif


/*
 * MONGOCRYPT_ENABLE_TRACE is set from configure to determine if we are
 * compiled with tracing support.
 */
#define MONGOCRYPT_ENABLE_TRACE @MONGOCRYPT_ENABLE_TRACE@

#if MONGOCRYPT_ENABLE_TRACE != 1
#  undef MONGOCRYPT_ENABLE_TRACE
#endif

/* clang-format on */

#endif /* MONGOCRYPT_CONFIG_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-crypto-private.h0000644000175100001660000002203614760300420021746 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_CRYPTO_PRIVATE_H
#define MONGOCRYPT_CRYPTO_PRIVATE_H

#include "mongocrypt-buffer-private.h"
#include "mongocrypt.h"

#define MONGOCRYPT_KEY_LEN 96
#define MONGOCRYPT_IV_KEY_LEN 32
#define MONGOCRYPT_MAC_KEY_LEN 32
#define MONGOCRYPT_ENC_KEY_LEN 32
#define MONGOCRYPT_IV_LEN 16
#define MONGOCRYPT_HMAC_SHA512_LEN 64
#define MONGOCRYPT_HMAC_LEN 32
#define MONGOCRYPT_BLOCK_SIZE 16
#define MONGOCRYPT_HMAC_SHA256_LEN 32
#define MONGOCRYPT_TOKEN_KEY_LEN 32

typedef struct {
    int hooks_enabled;
    mongocrypt_crypto_fn aes_256_cbc_encrypt;
    mongocrypt_crypto_fn aes_256_cbc_decrypt;
    mongocrypt_crypto_fn aes_256_ctr_encrypt;
    mongocrypt_crypto_fn aes_256_ctr_decrypt;
    mongocrypt_crypto_fn aes_256_ecb_encrypt;
    mongocrypt_random_fn random;
    mongocrypt_hmac_fn hmac_sha_512;
    mongocrypt_hmac_fn hmac_sha_256;
    mongocrypt_hash_fn sha_256;
    void *ctx;
} _mongocrypt_crypto_t;

typedef uint32_t (*_mongocrypt_ciphertextlen_fn)(uint32_t plaintext_len, mongocrypt_status_t *status);
typedef uint32_t (*_mongocrypt_plaintextlen_fn)(uint32_t ciphertext_len, mongocrypt_status_t *status);
typedef bool (*_mongocrypt_do_encryption_fn)(_mongocrypt_crypto_t *crypto,
                                             const _mongocrypt_buffer_t *iv,
                                             const _mongocrypt_buffer_t *associated_data,
                                             const _mongocrypt_buffer_t *key,
                                             const _mongocrypt_buffer_t *plaintext,
                                             _mongocrypt_buffer_t *ciphertext,
                                             uint32_t *bytes_written,
                                             mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;
typedef bool (*_mongocrypt_do_decryption_fn)(_mongocrypt_crypto_t *crypto,
                                             const _mongocrypt_buffer_t *associated_data,
                                             const _mongocrypt_buffer_t *key,
                                             const _mongocrypt_buffer_t *ciphertext,
                                             _mongocrypt_buffer_t *plaintext,
                                             uint32_t *bytes_written,
                                             mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

/**
 * Defines the application layer protocol to use when
 * encrypting client data values.
 */
typedef struct {
    _mongocrypt_ciphertextlen_fn get_ciphertext_len;
    _mongocrypt_plaintextlen_fn get_plaintext_len;
    _mongocrypt_do_encryption_fn do_encrypt;
    _mongocrypt_do_decryption_fn do_decrypt;
} _mongocrypt_value_encryption_algorithm_t;

// FLE1 algorithm: AES-256-CBC HMAC/SHA-512-256 (SHA-512 truncated to 256 bits)
// Algorithm is documented in [FLE and
// AEAD](https://docs.google.com/document/d/1D8xTXWo1B1dunO0bDZhPdolKTMbbD5fUIgsERubWRmY)
const _mongocrypt_value_encryption_algorithm_t *_mcFLE1Algorithm();

// FLE2 general algorithm: AES-256-CTR HMAC/SHA-256
// Algorithm is documented in [AEAD with
// CTR](https://docs.google.com/document/d/1eCU7R8Kjr-mdyz6eKvhNIDVmhyYQcAaLtTfHeK7a_vE/).
const _mongocrypt_value_encryption_algorithm_t *_mcFLE2AEADAlgorithm();

// FLE2 used with FLE2IndexedEncryptedValue: AES-256-CTR no HMAC
const _mongocrypt_value_encryption_algorithm_t *_mcFLE2Algorithm();

// FLE2AEAD general algorithm: AES-256-CBC HMAC/SHA-256
const _mongocrypt_value_encryption_algorithm_t *_mcFLE2v2AEADAlgorithm();

bool _mongocrypt_random(_mongocrypt_crypto_t *crypto,
                        _mongocrypt_buffer_t *out,
                        uint32_t count,
                        mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Generates a random number in the range [0, exclusive_upper_bound) in out. */
bool _mongocrypt_random_uint64(_mongocrypt_crypto_t *crypto,
                               uint64_t exclusive_upper_bound,
                               uint64_t *out,
                               mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Generates a random number in the range [0, exclusive_upper_bound) in out. */
bool _mongocrypt_random_int64(_mongocrypt_crypto_t *crypto,
                              int64_t exclusive_upper_bound,
                              int64_t *out,
                              mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Returns 0 if equal, non-zero otherwise */
int _mongocrypt_memequal(const void *const b1, const void *const b2, size_t len);

/*
 * _mongocrypt_wrap_key encrypts a DEK with a KEK.

 * kek is an input Key Encryption Key.
 * dek is an input Data Encryption Key.
 * encrypted_dek the result of encrypting dek with kek.
 * encrypted_dek is always initialized.
 * Returns true if no error occurred.
 * Returns false and sets @status if an error occurred.
 */
bool _mongocrypt_wrap_key(_mongocrypt_crypto_t *crypto,
                          _mongocrypt_buffer_t *kek,
                          _mongocrypt_buffer_t *dek,
                          _mongocrypt_buffer_t *encrypted_dek,
                          mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

/*
 * _mongocrypt_unwrap_key decrypts an encrypted DEK with a KEK.
 *
 * kek is an input Key Encryption Key.
 * encrypted_dek is an input encrypted Data Encryption Key.
 * dek is the result of decrypting encrypted_dek with kek.
 * dek is always initialized.
 * Returns true if no error occurred.
 * Returns false and sets @status if an error occurred.
 */
bool _mongocrypt_unwrap_key(_mongocrypt_crypto_t *crypto,
                            _mongocrypt_buffer_t *kek,
                            _mongocrypt_buffer_t *encrypted_dek,
                            _mongocrypt_buffer_t *dek,
                            mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_calculate_deterministic_iv(_mongocrypt_crypto_t *crypto,
                                            const _mongocrypt_buffer_t *key,
                                            const _mongocrypt_buffer_t *plaintext,
                                            const _mongocrypt_buffer_t *associated_data,
                                            _mongocrypt_buffer_t *out,
                                            mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

/*
 * _mongocrypt_hmac_sha_256 computes the HMAC SHA-256.
 *
 * Uses the hmac_sha_256 hook set on @crypto if set, and otherwise
 * calls the native implementation.
 *
 * @out must have length 32 bytes.
 *
 * Returns true if no error occurred.
 * Returns false sets @status if an error occurred.
 */
bool _mongocrypt_hmac_sha_256(_mongocrypt_crypto_t *crypto,
                              const _mongocrypt_buffer_t *key,
                              const _mongocrypt_buffer_t *in,
                              _mongocrypt_buffer_t *out,
                              mongocrypt_status_t *status);

/* Crypto implementations must implement these functions. */

/* This variable must be defined in implementation
   files, and must be set to true when _crypto_init
   is successful. */
extern bool _native_crypto_initialized;

void _native_crypto_init(void);

typedef struct {
    const _mongocrypt_buffer_t *key;
    const _mongocrypt_buffer_t *iv;
    const _mongocrypt_buffer_t *in;
    _mongocrypt_buffer_t *out;
    uint32_t *bytes_written;
    mongocrypt_status_t *status;
} aes_256_args_t;

bool _native_crypto_aes_256_cbc_encrypt(aes_256_args_t args) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _native_crypto_aes_256_cbc_decrypt(aes_256_args_t args) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _native_crypto_hmac_sha_512(const _mongocrypt_buffer_t *key,
                                 const _mongocrypt_buffer_t *in,
                                 _mongocrypt_buffer_t *out,
                                 mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _native_crypto_random(_mongocrypt_buffer_t *out,
                           uint32_t count,
                           mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _native_crypto_aes_256_ctr_encrypt(aes_256_args_t args) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _native_crypto_aes_256_ctr_decrypt(aes_256_args_t args) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _native_crypto_hmac_sha_256(const _mongocrypt_buffer_t *key,
                                 const _mongocrypt_buffer_t *in,
                                 _mongocrypt_buffer_t *out,
                                 mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

#endif /* MONGOCRYPT_CRYPTO_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-crypto.c0000644000175100001660000016011314760300420020270 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

/*
 * Comments in this implementation refer to:
 * [MCGREW] https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05
 */

#include 

#include "mongocrypt-binary-private.h"
#include "mongocrypt-buffer-private.h"
#include "mongocrypt-crypto-private.h"
#include "mongocrypt-log-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt-status-private.h"

#include 

/* This function uses ECB callback to simulate CTR encrypt and decrypt
 *
 * Note: the same function performs both encrypt and decrypt using same ECB
 * encryption function
 */

static bool _crypto_aes_256_ctr_encrypt_decrypt_via_ecb(void *ctx,
                                                        mongocrypt_crypto_fn aes_256_ecb_encrypt,
                                                        aes_256_args_t args,
                                                        mongocrypt_status_t *status) {
    BSON_ASSERT(args.iv && args.iv->len);
    BSON_ASSERT(args.in);
    BSON_ASSERT(args.out);

    if (args.out->len < args.in->len) {
        CLIENT_ERR("output buffer too small");
        return false;
    }

    _mongocrypt_buffer_t ctr, tmp;
    mongocrypt_binary_t key_bin, out_bin, in_bin, ctr_bin, tmp_bin;
    bool ret;

    _mongocrypt_buffer_to_binary(args.key, &key_bin);
    _mongocrypt_buffer_init(&ctr);
    _mongocrypt_buffer_copy_to(args.iv, &ctr);
    _mongocrypt_buffer_to_binary(&ctr, &ctr_bin);
    _mongocrypt_buffer_to_binary(args.out, &out_bin);
    _mongocrypt_buffer_to_binary(args.in, &in_bin);
    _mongocrypt_buffer_init_size(&tmp, args.iv->len);
    _mongocrypt_buffer_to_binary(&tmp, &tmp_bin);

    for (uint32_t ptr = 0; ptr < args.in->len;) {
        /* Encrypt value in CTR buffer */
        uint32_t bytes_written = 0;
        if (!aes_256_ecb_encrypt(ctx, &key_bin, NULL, &ctr_bin, &tmp_bin, &bytes_written, status)) {
            ret = false;
            goto cleanup;
        }

        if (bytes_written != tmp_bin.len) {
            CLIENT_ERR("encryption hook returned unexpected length");
            ret = false;
            goto cleanup;
        }

        /* XOR resulting stream with original data */
        for (uint32_t i = 0; i < bytes_written && ptr < args.in->len; i++, ptr++) {
            uint8_t *in_bin_u8 = in_bin.data;
            uint8_t *out_bin_u8 = out_bin.data;
            uint8_t *tmp_bin_u8 = tmp_bin.data;
            out_bin_u8[ptr] = in_bin_u8[ptr] ^ tmp_bin_u8[i];
        }

        /* Increment value in CTR buffer */
        uint32_t carry = 1;
        /* assert rather than return since this should never happen */
        BSON_ASSERT(ctr_bin.len == 0u || ctr_bin.len - 1u <= INT_MAX);
        for (int i = (int)ctr_bin.len - 1; i >= 0 && carry != 0; --i) {
            uint8_t *ctr_bin_u8 = ctr_bin.data;
            uint32_t bpp = carry + ctr_bin_u8[i];
            carry = bpp >> 8;
            ctr_bin_u8[i] = bpp & 0xFF;
        }
    }

    if (args.bytes_written) {
        *args.bytes_written = args.in->len;
    }

    ret = true;

cleanup:
    _mongocrypt_buffer_cleanup(&ctr);
    _mongocrypt_buffer_cleanup(&tmp);
    return ret;
}

/* Crypto primitives. These either call the native built in crypto primitives or
 * user supplied hooks. */
static bool _crypto_aes_256_cbc_encrypt(_mongocrypt_crypto_t *crypto, aes_256_args_t args) {
    mongocrypt_status_t *status = args.status;

    BSON_ASSERT_PARAM(crypto);

    BSON_ASSERT(args.key);
    if (args.key->len != MONGOCRYPT_ENC_KEY_LEN) {
        CLIENT_ERR("invalid encryption key length");
        return false;
    }

    BSON_ASSERT(args.iv);
    if (args.iv->len != MONGOCRYPT_IV_LEN) {
        CLIENT_ERR("invalid iv length");
        return false;
    }

    if (crypto->hooks_enabled) {
        mongocrypt_binary_t enc_key_bin, iv_bin, out_bin, in_bin;
        bool ret;

        _mongocrypt_buffer_to_binary(args.key, &enc_key_bin);
        _mongocrypt_buffer_to_binary(args.iv, &iv_bin);
        _mongocrypt_buffer_to_binary(args.out, &out_bin);
        _mongocrypt_buffer_to_binary(args.in, &in_bin);

        ret = crypto->aes_256_cbc_encrypt(crypto->ctx,
                                          &enc_key_bin,
                                          &iv_bin,
                                          &in_bin,
                                          &out_bin,
                                          args.bytes_written,
                                          status);
        return ret;
    }
    return _native_crypto_aes_256_cbc_encrypt(args);
}

static bool _crypto_aes_256_ctr_encrypt(_mongocrypt_crypto_t *crypto, aes_256_args_t args) {
    mongocrypt_status_t *status = args.status;

    BSON_ASSERT_PARAM(crypto);

    BSON_ASSERT(args.key);
    if (args.key->len != MONGOCRYPT_ENC_KEY_LEN) {
        CLIENT_ERR("invalid encryption key length");
        return false;
    }

    BSON_ASSERT(args.iv);
    if (args.iv->len != MONGOCRYPT_IV_LEN) {
        CLIENT_ERR("invalid iv length");
        return false;
    }

    if (crypto->aes_256_ctr_encrypt) {
        mongocrypt_binary_t enc_key_bin, iv_bin, out_bin, in_bin;
        bool ret;

        _mongocrypt_buffer_to_binary(args.key, &enc_key_bin);
        _mongocrypt_buffer_to_binary(args.iv, &iv_bin);
        _mongocrypt_buffer_to_binary(args.out, &out_bin);
        _mongocrypt_buffer_to_binary(args.in, &in_bin);

        ret = crypto->aes_256_ctr_encrypt(crypto->ctx,
                                          &enc_key_bin,
                                          &iv_bin,
                                          &in_bin,
                                          &out_bin,
                                          args.bytes_written,
                                          status);
        return ret;
    }

    if (crypto->aes_256_ecb_encrypt) {
        return _crypto_aes_256_ctr_encrypt_decrypt_via_ecb(crypto->ctx, crypto->aes_256_ecb_encrypt, args, status);
    }

    return _native_crypto_aes_256_ctr_encrypt(args);
}

static bool _crypto_aes_256_cbc_decrypt(_mongocrypt_crypto_t *crypto, aes_256_args_t args) {
    mongocrypt_status_t *status = args.status;

    BSON_ASSERT_PARAM(crypto);

    BSON_ASSERT(args.key);
    if (args.key->len != MONGOCRYPT_ENC_KEY_LEN) {
        CLIENT_ERR("invalid encryption key length");
        return false;
    }

    if (crypto->hooks_enabled) {
        mongocrypt_binary_t enc_key_bin, iv_bin, out_bin, in_bin;
        bool ret;

        _mongocrypt_buffer_to_binary(args.key, &enc_key_bin);
        _mongocrypt_buffer_to_binary(args.iv, &iv_bin);
        _mongocrypt_buffer_to_binary(args.out, &out_bin);
        _mongocrypt_buffer_to_binary(args.in, &in_bin);

        ret = crypto->aes_256_cbc_decrypt(crypto->ctx,
                                          &enc_key_bin,
                                          &iv_bin,
                                          &in_bin,
                                          &out_bin,
                                          args.bytes_written,
                                          status);
        return ret;
    }
    return _native_crypto_aes_256_cbc_decrypt(args);
}

static bool _crypto_aes_256_ctr_decrypt(_mongocrypt_crypto_t *crypto, aes_256_args_t args) {
    mongocrypt_status_t *status = args.status;

    BSON_ASSERT_PARAM(crypto);

    BSON_ASSERT(args.key);
    if (args.key->len != MONGOCRYPT_ENC_KEY_LEN) {
        CLIENT_ERR("invalid encryption key length");
        return false;
    }

    if (crypto->aes_256_ctr_decrypt) {
        mongocrypt_binary_t enc_key_bin, iv_bin, out_bin, in_bin;
        bool ret;

        _mongocrypt_buffer_to_binary(args.key, &enc_key_bin);
        _mongocrypt_buffer_to_binary(args.iv, &iv_bin);
        _mongocrypt_buffer_to_binary(args.out, &out_bin);
        _mongocrypt_buffer_to_binary(args.in, &in_bin);

        ret = crypto->aes_256_ctr_decrypt(crypto->ctx,
                                          &enc_key_bin,
                                          &iv_bin,
                                          &in_bin,
                                          &out_bin,
                                          args.bytes_written,
                                          status);
        return ret;
    }

    if (crypto->aes_256_ecb_encrypt) {
        return _crypto_aes_256_ctr_encrypt_decrypt_via_ecb(crypto->ctx, crypto->aes_256_ecb_encrypt, args, status);
    }

    return _native_crypto_aes_256_ctr_decrypt(args);
}

static bool _crypto_hmac_sha_512(_mongocrypt_crypto_t *crypto,
                                 const _mongocrypt_buffer_t *hmac_key,
                                 const _mongocrypt_buffer_t *in,
                                 _mongocrypt_buffer_t *out,
                                 mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(hmac_key);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    if (hmac_key->len != MONGOCRYPT_MAC_KEY_LEN) {
        CLIENT_ERR("invalid hmac key length");
        return false;
    }

    if (out->len != MONGOCRYPT_HMAC_SHA512_LEN) {
        CLIENT_ERR("out does not contain %d bytes", MONGOCRYPT_HMAC_SHA512_LEN);
        return false;
    }

    if (crypto->hooks_enabled) {
        mongocrypt_binary_t hmac_key_bin, out_bin, in_bin;
        bool ret;

        _mongocrypt_buffer_to_binary(hmac_key, &hmac_key_bin);
        _mongocrypt_buffer_to_binary(out, &out_bin);
        _mongocrypt_buffer_to_binary(in, &in_bin);

        ret = crypto->hmac_sha_512(crypto->ctx, &hmac_key_bin, &in_bin, &out_bin, status);
        return ret;
    }
    return _native_crypto_hmac_sha_512(hmac_key, in, out, status);
}

bool _mongocrypt_hmac_sha_256(_mongocrypt_crypto_t *crypto,
                              const _mongocrypt_buffer_t *key,
                              const _mongocrypt_buffer_t *in,
                              _mongocrypt_buffer_t *out,
                              mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(key);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    if (key->len != MONGOCRYPT_MAC_KEY_LEN) {
        CLIENT_ERR("invalid hmac_sha_256 key length. Got %" PRIu32 ", expected: %" PRIu32,
                   key->len,
                   MONGOCRYPT_MAC_KEY_LEN);
        return false;
    }

    if (crypto->hooks_enabled) {
        mongocrypt_binary_t key_bin, out_bin, in_bin;
        _mongocrypt_buffer_to_binary(key, &key_bin);
        _mongocrypt_buffer_to_binary(out, &out_bin);
        _mongocrypt_buffer_to_binary(in, &in_bin);

        return crypto->hmac_sha_256(crypto->ctx, &key_bin, &in_bin, &out_bin, status);
    }
    return _native_crypto_hmac_sha_256(key, in, out, status);
}

static bool
_crypto_random(_mongocrypt_crypto_t *crypto, _mongocrypt_buffer_t *out, uint32_t count, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(out);

    if (out->len != count) {
        CLIENT_ERR("out does not contain %u bytes", count);
        return false;
    }

    if (crypto->hooks_enabled) {
        mongocrypt_binary_t out_bin;

        _mongocrypt_buffer_to_binary(out, &out_bin);
        return crypto->random(crypto->ctx, &out_bin, count, status);
    }
    return _native_crypto_random(out, count, status);
}

/*
 * Secure memcmp copied from the C driver.
 */
int _mongocrypt_memequal(const void *const b1, const void *const b2, size_t len) {
    const unsigned char *p1 = b1, *p2 = b2;
    int ret = 0;

    BSON_ASSERT_PARAM(b1);
    BSON_ASSERT_PARAM(b2);

    for (; len > 0; len--) {
        ret |= *p1++ ^ *p2++;
    }

    return ret;
}

typedef enum {
    MODE_CBC,
    MODE_CTR,
} _mongocrypt_encryption_mode_t;

typedef enum {
    HMAC_NONE,
    HMAC_SHA_512_256, // sha512 truncated to 256 bits
    HMAC_SHA_256,
} _mongocrypt_hmac_type_t;

typedef enum {
    KEY_FORMAT_FLE1,       // 32 octets MAC key, 32 DATA key, 32 IV key (ignored)
    KEY_FORMAT_FLE2,       // 32 octets DATA key
    KEY_FORMAT_FLE2AEAD,   // 32 octets DATA key, 32 MAC key, 32 IV key (ignored)
    KEY_FORMAT_FLE2v2AEAD, // 32 octets DATA key, 32 MAC key, 32 IV key (ignored)
} _mongocrypt_key_format_t;

typedef enum {
    MAC_FORMAT_FLE1,       // HMAC(AAD || IV || S || LEN(AAD) as uint64be)
    MAC_FORMAT_FLE2,       // NONE
    MAC_FORMAT_FLE2AEAD,   // HMAC(AAD || IV || S)
    MAC_FORMAT_FLE2v2AEAD, // HMAC(AAD || IV || S)
} _mongocrypt_mac_format_t;

/* ----------------------------------------------------------------------------
 *
 * _mongocrypt_calculate_ciphertext_len
 *
 * Calculate the space needed for a ciphertext payload of a given size
 * and using fixed iv/hmac lengths.
 *
 * MODE_CBC: Assumes the ciphertext will be padded according to PKCS#7
 * which rounds up to the next block size, adding up to a complete block
 * for block aligned input payloads.
 *
 * MODE_CTR: Assumes no additional padding since CTR is a streaming cipher.
 *
 * Assumes all algorithms use identical IV length and blocksizes.
 *
 * ----------------------------------------------------------------------------
 */
static uint32_t _mongocrypt_calculate_ciphertext_len(uint32_t inlen,
                                                     _mongocrypt_encryption_mode_t mode,
                                                     _mongocrypt_hmac_type_t hmac,
                                                     mongocrypt_status_t *status) {
    const uint32_t hmaclen = (hmac == HMAC_NONE) ? 0 : MONGOCRYPT_HMAC_LEN;
    const uint32_t maxinlen = UINT32_MAX - (MONGOCRYPT_IV_LEN + MONGOCRYPT_BLOCK_SIZE + hmaclen);
    uint32_t fill;
    if (inlen > maxinlen) {
        CLIENT_ERR("plaintext too long");
        return 0;
    }

    if (mode == MODE_CBC) {
        fill = MONGOCRYPT_BLOCK_SIZE - (inlen % MONGOCRYPT_BLOCK_SIZE);
    } else {
        BSON_ASSERT(mode == MODE_CTR);
        fill = 0;
    }

    return MONGOCRYPT_IV_LEN + inlen + fill + hmaclen;
}

/* ----------------------------------------------------------------------------
 *
 * _mongocrypt_calculate_plaintext_len
 *
 * Calculate the space needed for a plaintext payload of a given size
 * and using fixed iv/hmac lengths.
 *
 * MODE_CBC: In practice, plaintext will be between 1 and {blocksize} bytes
 * shorter
 * than the input ciphertext, but it's easier and safer to assume the
 * full ciphertext length and waste a few bytes.
 *
 * MODE_CTR: Assumes no additional padding since CTR is a streaming cipher.
 *
 * Assumes all algorithms use identical IV length and blocksizes.
 *
 * ----------------------------------------------------------------------------
 */
static uint32_t _mongocrypt_calculate_plaintext_len(uint32_t inlen,
                                                    _mongocrypt_encryption_mode_t mode,
                                                    _mongocrypt_hmac_type_t hmac,
                                                    mongocrypt_status_t *status) {
    const uint32_t hmaclen = (hmac == HMAC_NONE) ? 0 : MONGOCRYPT_HMAC_LEN;
    const uint32_t mincipher = (mode == MODE_CTR) ? 0 : MONGOCRYPT_BLOCK_SIZE;
    if (inlen < (MONGOCRYPT_IV_LEN + mincipher + hmaclen)) {
        CLIENT_ERR("input ciphertext too small. Must be at least %" PRIu32 " bytes",
                   MONGOCRYPT_IV_LEN + mincipher + hmaclen);
        return 0;
    }
    return inlen - (MONGOCRYPT_IV_LEN + hmaclen);
}

/* ----------------------------------------------------------------------------
 *
 * _aes256_cbc_encrypt --
 *
 *    Encrypts using AES256 CBC using a secret key and a known IV.
 *
 * Parameters:
 *    @iv a 16 byte IV.
 *    @enc_key a 32 byte key.
 *    @plaintext the plaintext to encrypt.
 *    @ciphertext the resulting ciphertext.
 *    @bytes_written a location for the resulting number of bytes written into
 *    ciphertext->data.
 *    @status set on error.
 *
 * Returns:
 *    True on success. On error, sets @status and returns false.
 *
 * Preconditions:
 *    1. ciphertext->data has been pre-allocated with enough space for the
 *    resulting ciphertext.
 *
 * Postconditions:
 *    1. bytes_written is set to the length of the written ciphertext. This
 *    is the same as
 *    _mongocrypt_calculate_ciphertext_len (plaintext->len, mode, hmac, status).
 *
 * ----------------------------------------------------------------------------
 */
static bool _encrypt_step(_mongocrypt_crypto_t *crypto,
                          _mongocrypt_encryption_mode_t mode,
                          const _mongocrypt_buffer_t *iv,
                          const _mongocrypt_buffer_t *enc_key,
                          const _mongocrypt_buffer_t *plaintext,
                          _mongocrypt_buffer_t *ciphertext,
                          uint32_t *bytes_written,
                          mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(iv);
    BSON_ASSERT_PARAM(enc_key);
    BSON_ASSERT_PARAM(plaintext);
    BSON_ASSERT_PARAM(ciphertext);

    BSON_ASSERT_PARAM(bytes_written);
    *bytes_written = 0;

    if (MONGOCRYPT_IV_LEN != iv->len) {
        CLIENT_ERR("IV should have length %d, but has length %d", MONGOCRYPT_IV_LEN, iv->len);
        return false;
    }

    if (MONGOCRYPT_ENC_KEY_LEN != enc_key->len) {
        CLIENT_ERR("Encryption key should have length %d, but has length %d", MONGOCRYPT_ENC_KEY_LEN, enc_key->len);
        return false;
    }

    if (mode == MODE_CTR) {
        // Streaming cipher, no padding required.
        return _crypto_aes_256_ctr_encrypt(crypto,
                                           (aes_256_args_t){.key = enc_key,
                                                            .iv = iv,
                                                            .in = plaintext,
                                                            .out = ciphertext,
                                                            .bytes_written = bytes_written,
                                                            .status = status});
    }

    BSON_ASSERT(mode == MODE_CBC);

    /* calculate how many extra bytes there are after a block boundary */
    const uint32_t unaligned = plaintext->len % MONGOCRYPT_BLOCK_SIZE;
    uint32_t padding_byte = MONGOCRYPT_BLOCK_SIZE - unaligned;
    _mongocrypt_buffer_t intermediates[2], to_encrypt;
    uint8_t final_block_storage[MONGOCRYPT_BLOCK_SIZE];
    bool ret;

    BSON_ASSERT(MONGOCRYPT_BLOCK_SIZE >= unaligned);

    /* Some crypto providers disallow variable length inputs, and require
     * the input to be a multiple of the block size. So add everything up
     * to but excluding the last block if not block aligned, then add
     * the last block with padding. */
    _mongocrypt_buffer_init(&intermediates[0]);
    _mongocrypt_buffer_init(&intermediates[1]);
    intermediates[0].data = (uint8_t *)plaintext->data;
    /* don't check plaintext->len, as the above modulo operation guarantees
     * that unaligned will be smaller */
    intermediates[0].len = plaintext->len - unaligned;
    intermediates[1].data = final_block_storage;
    intermediates[1].len = sizeof(final_block_storage);

    /* [MCGREW]: "Prior to CBC encryption, the plaintext P is padded by appending
     * a padding string PS to that data, to ensure that len(P || PS) is a
     * multiple of 128". This is also known as PKCS #7 padding. */
    if (unaligned) {
        /* Copy the unaligned bytes. */
        memcpy(intermediates[1].data, plaintext->data + (plaintext->len - unaligned), unaligned);
    }
    /* Fill out block remained or whole block with padding_byte */
    memset(intermediates[1].data + unaligned, (int)padding_byte, padding_byte);

    _mongocrypt_buffer_init(&to_encrypt);
    if (!_mongocrypt_buffer_concat(&to_encrypt, intermediates, 2)) {
        CLIENT_ERR("failed to allocate buffer");
        _mongocrypt_buffer_cleanup(&to_encrypt);
        return false;
    }

    ret = _crypto_aes_256_cbc_encrypt(crypto,
                                      (aes_256_args_t){.key = enc_key,
                                                       .iv = iv,
                                                       .in = &to_encrypt,
                                                       .out = ciphertext,
                                                       .bytes_written = bytes_written,
                                                       .status = status});
    _mongocrypt_buffer_cleanup(&to_encrypt);
    if (!ret) {
        return false;
    }

    if (*bytes_written % MONGOCRYPT_BLOCK_SIZE != 0) {
        CLIENT_ERR("encryption failure, wrote %d bytes, not a multiple of %d", *bytes_written, MONGOCRYPT_BLOCK_SIZE);
        return false;
    }

    return true;
}

/* ----------------------------------------------------------------------------
 *
 * _hmac_step --
 *
 *    Compute the selected HMAC with a secret key.
 *
 * Parameters:
 *    @Km a 32 byte key.
 *    @AAD associated data to add into the HMAC. This may be
 *    an empty buffer.
 *    @iv_and_ciphertext the IV and S components to add into the HMAC.
 *    @out a location for the resulting HMAC tag.
 *    @status set on error.
 *
 * Returns:
 *    True on success. On error, sets @status and returns false.
 *
 * Preconditions:
 *    1. out->data has been pre-allocated with at least 64 bytes.
 *
 * Postconditions:
 *    1. out->data will have a 64 byte tag appended.
 *
 * ----------------------------------------------------------------------------
 */
static bool _hmac_step(_mongocrypt_crypto_t *crypto,
                       _mongocrypt_mac_format_t mac_format,
                       _mongocrypt_hmac_type_t hmac,
                       const _mongocrypt_buffer_t *Km,
                       const _mongocrypt_buffer_t *AAD,
                       const _mongocrypt_buffer_t *iv_and_ciphertext,
                       _mongocrypt_buffer_t *out,
                       mongocrypt_status_t *status) {
    _mongocrypt_buffer_t to_hmac = {0};
    bool ret = false;

    BSON_ASSERT(hmac != HMAC_NONE);
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(Km);
    // AAD may be NULL
    BSON_ASSERT_PARAM(iv_and_ciphertext);
    BSON_ASSERT_PARAM(out);

    _mongocrypt_buffer_init(&to_hmac);

    if (MONGOCRYPT_MAC_KEY_LEN != Km->len) {
        CLIENT_ERR("HMAC key wrong length: %d", Km->len);
        goto done;
    }

    if (out->len != MONGOCRYPT_HMAC_LEN) {
        CLIENT_ERR("out wrong length: %d", out->len);
        goto done;
    }

    /* Construct the input to the HMAC */
    uint32_t num_intermediates = 0;
    _mongocrypt_buffer_t intermediates[3];
    if (AAD && !_mongocrypt_buffer_from_subrange(&intermediates[num_intermediates++], AAD, 0, AAD->len)) {
        CLIENT_ERR("Failed creating MAC subrange on AD");
        goto done;
    }
    if (!_mongocrypt_buffer_from_subrange(&intermediates[num_intermediates++],
                                          iv_and_ciphertext,
                                          0,
                                          iv_and_ciphertext->len)) {
        CLIENT_ERR("Failed creating MAC subrange on IV and S");
        goto done;
    }

    // {AL} must be stored in the function's lexical scope so that
    // {intermediates}'s reference to it survives until the
    // _mongocrypt_buffer_concat operation later.
    uint64_t AL;
    if (mac_format == MAC_FORMAT_FLE1) {
        /* T := HMAC(AAD || IV || S || AL)
         * AL is equal to the number of bits in AAD expressed
         * as a 64bit unsigned big-endian integer.
         * Multiplying a uint32_t by 8 won't bring it anywhere close to
         * UINT64_MAX.
         */
        AL = AAD ? BSON_UINT64_TO_BE(8 * (uint64_t)AAD->len) : 0;
        _mongocrypt_buffer_init(&intermediates[num_intermediates]);
        intermediates[num_intermediates].data = (uint8_t *)&AL;
        intermediates[num_intermediates++].len = sizeof(uint64_t);

    } else {
        /* T := HMAC(AAD || IV || S) */
        BSON_ASSERT((mac_format == MAC_FORMAT_FLE2AEAD) || (mac_format == MAC_FORMAT_FLE2v2AEAD));
    }

    if (!_mongocrypt_buffer_concat(&to_hmac, intermediates, num_intermediates)) {
        CLIENT_ERR("failed to allocate buffer");
        goto done;
    }

    if (hmac == HMAC_SHA_512_256) {
        uint8_t storage[64];
        _mongocrypt_buffer_t tag = {.data = storage, .len = sizeof(storage)};

        if (!_crypto_hmac_sha_512(crypto, Km, &to_hmac, &tag, status)) {
            goto done;
        }

        // Truncate sha512 to first 256 bits.
        memcpy(out->data, tag.data, MONGOCRYPT_HMAC_LEN);

    } else {
        BSON_ASSERT(hmac == HMAC_SHA_256);
        if (!_mongocrypt_hmac_sha_256(crypto, Km, &to_hmac, out, status)) {
            goto done;
        }
    }

    ret = true;
done:
    _mongocrypt_buffer_cleanup(&to_hmac);
    return ret;
}

/* ----------------------------------------------------------------------------
 *
 * _mongocrypt_do_encryption --
 *
 *    Defer encryption to whichever crypto library libmongocrypt is using.
 *
 * Parameters:
 *    @iv a 16 byte IV.
 *    @associated_data associated data for the HMAC. May be NULL.
 *    @key is the encryption key. The size depends on @key_format.
 *    @plaintext the plaintext to encrypt.
 *    @ciphertext a location for the resulting ciphertext and HMAC tag.
 *    @bytes_written a location for the resulting bytes written.
 *    @status set on error.
 *
 * Returns:
 *    True on success. On error, sets @status and returns false.
 *
 * Preconditions:
 *    1. ciphertext->data has been pre-allocated with enough space for the
 *    resulting ciphertext. Use _mongocrypt_calculate_ciphertext_len.
 *
 * Postconditions:
 *    1. bytes_written is set to the length of the written ciphertext. This
 *    is the same as
 *    _mongocrypt_calculate_ciphertext_len (plaintext->len, mode, hmac, status).
 *
 * ----------------------------------------------------------------------------
 */
static bool _mongocrypt_do_encryption(_mongocrypt_crypto_t *crypto,
                                      _mongocrypt_key_format_t key_format,
                                      _mongocrypt_mac_format_t mac_format,
                                      _mongocrypt_encryption_mode_t mode,
                                      _mongocrypt_hmac_type_t hmac,
                                      const _mongocrypt_buffer_t *iv,
                                      const _mongocrypt_buffer_t *associated_data,
                                      const _mongocrypt_buffer_t *key,
                                      const _mongocrypt_buffer_t *plaintext,
                                      _mongocrypt_buffer_t *ciphertext,
                                      uint32_t *bytes_written,
                                      mongocrypt_status_t *status) {
    _mongocrypt_buffer_t Ke = {0}; // Ke == Key for Encryption
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(iv);
    /* associated_data is checked at the point it is used, so it can be NULL */
    BSON_ASSERT_PARAM(key);
    BSON_ASSERT_PARAM(plaintext);
    BSON_ASSERT_PARAM(ciphertext);

    if (plaintext->len <= 0) {
        CLIENT_ERR("input plaintext too small. Must be more than zero bytes.");
        return false;
    }

    const uint32_t expect_ciphertext_len = _mongocrypt_calculate_ciphertext_len(plaintext->len, mode, hmac, status);
    if (mongocrypt_status_type(status) != MONGOCRYPT_STATUS_OK) {
        return false;
    }
    if (expect_ciphertext_len != ciphertext->len) {
        CLIENT_ERR("output ciphertext should have been allocated with %d bytes", expect_ciphertext_len);
        return false;
    }

    if (MONGOCRYPT_IV_LEN != iv->len) {
        CLIENT_ERR("IV should have length %d, but has length %d", MONGOCRYPT_IV_LEN, iv->len);
        return false;
    }

    const uint32_t expected_key_len = (key_format == KEY_FORMAT_FLE2) ? MONGOCRYPT_ENC_KEY_LEN : MONGOCRYPT_KEY_LEN;
    if (key->len != expected_key_len) {
        CLIENT_ERR("key should have length %d, but has length %d", expected_key_len, key->len);
        return false;
    }

    // Copy IV into the output, and clear remainder.
    memmove(ciphertext->data, iv->data, MONGOCRYPT_IV_LEN);
    memset(ciphertext->data + MONGOCRYPT_IV_LEN, 0, ciphertext->len - MONGOCRYPT_IV_LEN);

    // S is the encryption payload without IV or HMAC
    _mongocrypt_buffer_t S;
    if (!_mongocrypt_buffer_from_subrange(&S, ciphertext, MONGOCRYPT_IV_LEN, ciphertext->len - MONGOCRYPT_IV_LEN)) {
        CLIENT_ERR("unable to create S subrange from C");
        return false;
    }
    if (hmac != HMAC_NONE) {
        S.len -= MONGOCRYPT_HMAC_LEN;
    }

    // Ke is the key used for payload encryption
    const uint32_t Ke_offset = (key_format == KEY_FORMAT_FLE1) ? MONGOCRYPT_MAC_KEY_LEN : 0;
    if (!_mongocrypt_buffer_from_subrange(&Ke, key, Ke_offset, MONGOCRYPT_ENC_KEY_LEN)) {
        CLIENT_ERR("unable to create Ke subrange from key");
        return false;
    }

    uint32_t S_bytes_written = 0;
    if (!_encrypt_step(crypto, mode, iv, &Ke, plaintext, &S, &S_bytes_written, status)) {
        return false;
    }
    BSON_ASSERT_PARAM(bytes_written);
    BSON_ASSERT((UINT32_MAX - S_bytes_written) > MONGOCRYPT_IV_LEN);
    *bytes_written = MONGOCRYPT_IV_LEN + S_bytes_written;

    if (hmac != HMAC_NONE) {
        // Km == Key for MAC
        const uint32_t Km_offset = (key_format == KEY_FORMAT_FLE1) ? 0 : MONGOCRYPT_ENC_KEY_LEN;

        // Km is the HMAC Key.
        _mongocrypt_buffer_t Km;
        if (!_mongocrypt_buffer_from_subrange(&Km, key, Km_offset, MONGOCRYPT_MAC_KEY_LEN)) {
            CLIENT_ERR("unable to create Km subrange from key");
            return false;
        }

        /* Primary payload to MAC. */
        _mongocrypt_buffer_t iv_and_ciphertext;
        if (!_mongocrypt_buffer_from_subrange(&iv_and_ciphertext, ciphertext, 0, *bytes_written)) {
            CLIENT_ERR("unable to create IV || S subrange from C");
            return false;
        }

        // T == HMAC Tag
        _mongocrypt_buffer_t T;
        if (!_mongocrypt_buffer_from_subrange(&T, ciphertext, *bytes_written, MONGOCRYPT_HMAC_LEN)) {
            CLIENT_ERR("unable to create T subrange from C");
            return false;
        }

        if (!_hmac_step(crypto, mac_format, hmac, &Km, associated_data, &iv_and_ciphertext, &T, status)) {
            return false;
        }

        *bytes_written += MONGOCRYPT_HMAC_LEN;
    }

    return true;
}

/* ----------------------------------------------------------------------------
 *
 * _decrypt_step --
 *
 *    Decrypts using AES256 using a secret key and a known IV.
 *
 * Parameters:
 *    @enc_key a 32 byte key.
 *    @ciphertext the ciphertext to decrypt.
 *    @plaintext the resulting plaintext.
 *    @bytes_written a location for the resulting number of bytes written into
 *    plaintext->data.
 *    @status set on error.
 *
 * Returns:
 *    True on success. On error, sets @status and returns false.
 *
 * Preconditions:
 *    1. plaintext->data has been pre-allocated with enough space for the
 *    resulting plaintext.
 *
 * Postconditions:
 *    1. bytes_written is set to the length of the written plaintext, excluding
 *    padding. This may be less than
 *    _mongocrypt_calculate_plaintext_len (ciphertext->len, home, hmac, status).
 *
 * ----------------------------------------------------------------------------
 */
static bool _decrypt_step(_mongocrypt_crypto_t *crypto,
                          _mongocrypt_encryption_mode_t mode,
                          const _mongocrypt_buffer_t *iv,
                          const _mongocrypt_buffer_t *enc_key,
                          const _mongocrypt_buffer_t *ciphertext,
                          _mongocrypt_buffer_t *plaintext,
                          uint32_t *bytes_written,
                          mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(iv);
    BSON_ASSERT_PARAM(enc_key);
    BSON_ASSERT_PARAM(ciphertext);
    BSON_ASSERT_PARAM(plaintext);

    BSON_ASSERT_PARAM(bytes_written);
    *bytes_written = 0;

    if (MONGOCRYPT_IV_LEN != iv->len) {
        CLIENT_ERR("IV should have length %d, but has length %d", MONGOCRYPT_IV_LEN, iv->len);
        return false;
    }
    if (MONGOCRYPT_ENC_KEY_LEN != enc_key->len) {
        CLIENT_ERR("encryption key should have length %d, but has length %d", MONGOCRYPT_ENC_KEY_LEN, enc_key->len);
        return false;
    }

    if (mode == MODE_CBC) {
        if (ciphertext->len % MONGOCRYPT_BLOCK_SIZE > 0) {
            CLIENT_ERR("error, ciphertext length is not a multiple of block size");
            return false;
        }

        if (!_crypto_aes_256_cbc_decrypt(crypto,
                                         (aes_256_args_t){.iv = iv,
                                                          .key = enc_key,
                                                          .in = ciphertext,
                                                          .out = plaintext,
                                                          .bytes_written = bytes_written,
                                                          .status = status})) {
            return false;
        }

        BSON_ASSERT(*bytes_written > 0);
        uint8_t padding_byte = plaintext->data[*bytes_written - 1];
        if (padding_byte > 16) {
            CLIENT_ERR("error, ciphertext malformed padding");
            return false;
        }
        *bytes_written -= padding_byte;

    } else {
        BSON_ASSERT(mode == MODE_CTR);
        if (!_crypto_aes_256_ctr_decrypt(crypto,
                                         (aes_256_args_t){.iv = iv,
                                                          .key = enc_key,
                                                          .in = ciphertext,
                                                          .out = plaintext,
                                                          .bytes_written = bytes_written,
                                                          .status = status})) {
            return false;
        }
        BSON_ASSERT(*bytes_written == plaintext->len);
    }

    return true;
}

/* ----------------------------------------------------------------------------
 *
 * _mongocrypt_do_decryption --
 *
 *    Defer decryption to whichever crypto library libmongocrypt is using.
 *
 * Parameters:
 *    @associated_data associated data for the HMAC. May be NULL.
 *    @key a 96 byte key.
 *    @ciphertext the ciphertext to decrypt. This contains the IV prepended.
 *    @plaintext a location for the resulting plaintext.
 *    @bytes_written a location for the resulting bytes written.
 *    @status set on error.
 *
 * Returns:
 *    True on success. On error, sets @status and returns false.
 *
 *  Preconditions:
 *    1. plaintext->data has been pre-allocated with enough space for the
 *    resulting plaintext and padding. See _mongocrypt_calculate_plaintext_len.
 *
 *  Postconditions:
 *    1. bytes_written is set to the length of the written plaintext, excluding
 *    padding. This may be less than
 *    _mongocrypt_calculate_plaintext_len (ciphertext->len, mode, hmac, status).
 *
 * ----------------------------------------------------------------------------
 */
static bool _mongocrypt_do_decryption(_mongocrypt_crypto_t *crypto,
                                      _mongocrypt_key_format_t key_format,
                                      _mongocrypt_mac_format_t mac_format,
                                      _mongocrypt_encryption_mode_t mode,
                                      _mongocrypt_hmac_type_t hmac,
                                      const _mongocrypt_buffer_t *associated_data,
                                      const _mongocrypt_buffer_t *key,
                                      const _mongocrypt_buffer_t *ciphertext,
                                      _mongocrypt_buffer_t *plaintext,
                                      uint32_t *bytes_written,
                                      mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    /* associated_data is checked at the point it is used, so it can be NULL */
    BSON_ASSERT_PARAM(key);
    BSON_ASSERT_PARAM(ciphertext);
    BSON_ASSERT_PARAM(plaintext);
    BSON_ASSERT_PARAM(bytes_written);

    const uint32_t expect_plaintext_len = _mongocrypt_calculate_plaintext_len(ciphertext->len, mode, hmac, status);
    if (mongocrypt_status_type(status) != MONGOCRYPT_STATUS_OK) {
        return false;
    }
    if (plaintext->len != expect_plaintext_len) {
        CLIENT_ERR("output plaintext should have been allocated with %d bytes, "
                   "but has: %d",
                   expect_plaintext_len,
                   plaintext->len);
        return false;
    }
    if (expect_plaintext_len == 0) {
        // While a ciphertext string describing a zero length plaintext is
        // technically valid,
        // it's not actually particularly useful in the context of FLE where such
        // values aren't encoded.
        CLIENT_ERR("input ciphertext too small. Must be more than %" PRIu32 " bytes",
                   _mongocrypt_calculate_ciphertext_len(0, mode, hmac, NULL));
        return false;
    }

    const uint32_t expected_key_len = (key_format == KEY_FORMAT_FLE2) ? MONGOCRYPT_ENC_KEY_LEN : MONGOCRYPT_KEY_LEN;
    if (expected_key_len != key->len) {
        CLIENT_ERR("key should have length %d, but has length %d", expected_key_len, key->len);
        return false;
    }

    const uint32_t min_cipherlen = _mongocrypt_calculate_ciphertext_len(0, mode, hmac, NULL);
    if (ciphertext->len < min_cipherlen) {
        CLIENT_ERR("corrupt ciphertext - must be >= %d bytes", min_cipherlen);
        return false;
    }

    _mongocrypt_buffer_t Ke;
    const uint32_t Ke_offset = (key_format == KEY_FORMAT_FLE1) ? MONGOCRYPT_MAC_KEY_LEN : 0;
    if (!_mongocrypt_buffer_from_subrange(&Ke, key, Ke_offset, MONGOCRYPT_ENC_KEY_LEN)) {
        CLIENT_ERR("unable to create Ke subrange from key");
        return false;
    }

    _mongocrypt_buffer_t IV;
    if (!_mongocrypt_buffer_from_subrange(&IV, ciphertext, 0, MONGOCRYPT_IV_LEN)) {
        CLIENT_ERR("unable to create IV subrange from ciphertext");
        return false;
    }

    if (hmac == HMAC_NONE) {
        BSON_ASSERT(key_format == KEY_FORMAT_FLE2);

    } else {
        BSON_ASSERT(key_format != KEY_FORMAT_FLE2);

        uint8_t hmac_tag_storage[MONGOCRYPT_HMAC_LEN];
        const uint32_t mac_key_offset = (key_format == KEY_FORMAT_FLE1) ? 0 : MONGOCRYPT_ENC_KEY_LEN;
        _mongocrypt_buffer_t Km;
        if (!_mongocrypt_buffer_from_subrange(&Km, key, mac_key_offset, MONGOCRYPT_MAC_KEY_LEN)) {
            CLIENT_ERR("unable to create Km subrange from key");
            return false;
        }

        _mongocrypt_buffer_t iv_and_ciphertext;
        if (!_mongocrypt_buffer_from_subrange(&iv_and_ciphertext,
                                              ciphertext,
                                              0,
                                              ciphertext->len - MONGOCRYPT_HMAC_LEN)) {
            CLIENT_ERR("unable to create IV || S subrange from C");
            return false;
        }

        _mongocrypt_buffer_t hmac_tag = {.data = hmac_tag_storage, .len = MONGOCRYPT_HMAC_LEN};

        if (!_hmac_step(crypto, mac_format, hmac, &Km, associated_data, &iv_and_ciphertext, &hmac_tag, status)) {
            return false;
        }

        /* Constant time compare. */
        _mongocrypt_buffer_t T;
        if (!_mongocrypt_buffer_from_subrange(&T,
                                              ciphertext,
                                              ciphertext->len - MONGOCRYPT_HMAC_LEN,
                                              MONGOCRYPT_HMAC_LEN)) {
            CLIENT_ERR("unable to create T subrange from C");
            return false;
        }
        if (0 != _mongocrypt_memequal(hmac_tag.data, T.data, MONGOCRYPT_HMAC_LEN)) {
            CLIENT_ERR("HMAC validation failure");
            return false;
        }
    }

    /* Decrypt data excluding IV + HMAC. */
    const uint32_t hmac_len = (hmac == HMAC_NONE) ? 0 : MONGOCRYPT_HMAC_LEN;
    _mongocrypt_buffer_t S;
    if (!_mongocrypt_buffer_from_subrange(&S,
                                          ciphertext,
                                          MONGOCRYPT_IV_LEN,
                                          ciphertext->len - MONGOCRYPT_IV_LEN - hmac_len)) {
        CLIENT_ERR("unable to create S subrange from C");
        return false;
    }

    return _decrypt_step(crypto, mode, &IV, &Ke, &S, plaintext, bytes_written, status);
}

#define DECLARE_ALGORITHM(name, mode, hmac)                                                                            \
    static uint32_t _mc_##name##_ciphertext_len(uint32_t plaintext_len, mongocrypt_status_t *status) {                 \
        return _mongocrypt_calculate_ciphertext_len(plaintext_len, MODE_##mode, HMAC_##hmac, status);                  \
    }                                                                                                                  \
    static uint32_t _mc_##name##_plaintext_len(uint32_t ciphertext_len, mongocrypt_status_t *status) {                 \
        return _mongocrypt_calculate_plaintext_len(ciphertext_len, MODE_##mode, HMAC_##hmac, status);                  \
    }                                                                                                                  \
    static bool _mc_##name##_do_encryption(_mongocrypt_crypto_t *crypto,                                               \
                                           const _mongocrypt_buffer_t *iv,                                             \
                                           const _mongocrypt_buffer_t *aad,                                            \
                                           const _mongocrypt_buffer_t *key,                                            \
                                           const _mongocrypt_buffer_t *plaintext,                                      \
                                           _mongocrypt_buffer_t *ciphertext,                                           \
                                           uint32_t *written,                                                          \
                                           mongocrypt_status_t *status) {                                              \
        return _mongocrypt_do_encryption(crypto,                                                                       \
                                         KEY_FORMAT_##name,                                                            \
                                         MAC_FORMAT_##name,                                                            \
                                         MODE_##mode,                                                                  \
                                         HMAC_##hmac,                                                                  \
                                         iv,                                                                           \
                                         aad,                                                                          \
                                         key,                                                                          \
                                         plaintext,                                                                    \
                                         ciphertext,                                                                   \
                                         written,                                                                      \
                                         status);                                                                      \
    }                                                                                                                  \
    static bool _mc_##name##_do_decryption(_mongocrypt_crypto_t *crypto,                                               \
                                           const _mongocrypt_buffer_t *aad,                                            \
                                           const _mongocrypt_buffer_t *key,                                            \
                                           const _mongocrypt_buffer_t *ciphertext,                                     \
                                           _mongocrypt_buffer_t *plaintext,                                            \
                                           uint32_t *written,                                                          \
                                           mongocrypt_status_t *status) {                                              \
        return _mongocrypt_do_decryption(crypto,                                                                       \
                                         KEY_FORMAT_##name,                                                            \
                                         MAC_FORMAT_##name,                                                            \
                                         MODE_##mode,                                                                  \
                                         HMAC_##hmac,                                                                  \
                                         aad,                                                                          \
                                         key,                                                                          \
                                         ciphertext,                                                                   \
                                         plaintext,                                                                    \
                                         written,                                                                      \
                                         status);                                                                      \
    }                                                                                                                  \
    static const _mongocrypt_value_encryption_algorithm_t _mc##name##Algorithm_definition = {                          \
        _mc_##name##_ciphertext_len,                                                                                   \
        _mc_##name##_plaintext_len,                                                                                    \
        _mc_##name##_do_encryption,                                                                                    \
        _mc_##name##_do_decryption,                                                                                    \
    };                                                                                                                 \
    const _mongocrypt_value_encryption_algorithm_t *_mc##name##Algorithm() { return &_mc##name##Algorithm_definition; }

// FLE1 algorithm: AES-256-CBC HMAC/SHA-512-256 (SHA-512 truncated to 256 bits)
DECLARE_ALGORITHM(FLE1, CBC, SHA_512_256)

// FLE2 AEAD used value algorithm: AES-256-CTR HMAC/SHA-256
DECLARE_ALGORITHM(FLE2AEAD, CTR, SHA_256)

// FLE2 used with ESC/ECOC tokens: AES-256-CTR no HMAC
DECLARE_ALGORITHM(FLE2, CTR, NONE)

// FLE2v2 AEAD general algorithm: AES-256-CBC HMAC/SHA-256
DECLARE_ALGORITHM(FLE2v2AEAD, CBC, SHA_256)

#undef DECLARE_ALGORITHM

/* ----------------------------------------------------------------------------
 *
 * _mongocrypt_random --
 *
 *    Generates a string of random bytes.
 *
 * Parameters:
 *    @out an output buffer that has been pre-allocated.
 *    @status set on error.
 *    @count the size of the random string in bytes.
 *
 * Returns:
 *    True on success. On error, sets @status and returns false.
 *
 *  Preconditions:
 *    1. out has been pre-allocated with at least 'count' bytes of space.
 *
 * ----------------------------------------------------------------------------
 */
bool _mongocrypt_random(_mongocrypt_crypto_t *crypto,
                        _mongocrypt_buffer_t *out,
                        uint32_t count,
                        mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(out);

    if (count != out->len) {
        CLIENT_ERR("out should have length %d, but has length %d", count, out->len);
        return false;
    }

    return _crypto_random(crypto, out, count, status);
}

/* ----------------------------------------------------------------------------
 *
 * _mongocrypt_calculate_deterministic_iv --
 *
 *    Compute the IV for deterministic encryption from the plaintext and IV
 *    key by using HMAC function.
 *
 * Parameters:
 *    @key the 96 byte key. The last 32 represent the IV key.
 *    @plaintext the plaintext to be encrypted.
 *    @associated_data associated data to include in the HMAC.
 *    @out an output buffer that has been pre-allocated.
 *    @status set on error.
 *
 * Returns:
 *    True on success. On error, sets @status and returns false.
 *
 *  Preconditions:
 *    1. out has been pre-allocated with at least MONGOCRYPT_IV_LEN bytes.
 *
 * ----------------------------------------------------------------------------
 */
bool _mongocrypt_calculate_deterministic_iv(_mongocrypt_crypto_t *crypto,
                                            const _mongocrypt_buffer_t *key,
                                            const _mongocrypt_buffer_t *plaintext,
                                            const _mongocrypt_buffer_t *associated_data,
                                            _mongocrypt_buffer_t *out,
                                            mongocrypt_status_t *status) {
    _mongocrypt_buffer_t intermediates[3];
    _mongocrypt_buffer_t to_hmac;
    _mongocrypt_buffer_t iv_key;
    uint64_t associated_data_len_be;
    uint8_t tag_storage[64];
    _mongocrypt_buffer_t tag;
    bool ret = false;

    _mongocrypt_buffer_init(&to_hmac);

    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(key);
    BSON_ASSERT_PARAM(plaintext);
    BSON_ASSERT_PARAM(associated_data);
    BSON_ASSERT_PARAM(out);

    if (MONGOCRYPT_KEY_LEN != key->len) {
        CLIENT_ERR("key should have length %d, but has length %d\n", MONGOCRYPT_KEY_LEN, key->len);
        goto done;
    }
    if (MONGOCRYPT_IV_LEN != out->len) {
        CLIENT_ERR("out should have length %d, but has length %d\n", MONGOCRYPT_IV_LEN, out->len);
        goto done;
    }

    _mongocrypt_buffer_init(&iv_key);
    iv_key.data = key->data + MONGOCRYPT_ENC_KEY_LEN + MONGOCRYPT_MAC_KEY_LEN;
    iv_key.len = MONGOCRYPT_IV_KEY_LEN;

    _mongocrypt_buffer_init(&intermediates[0]);
    _mongocrypt_buffer_init(&intermediates[1]);
    _mongocrypt_buffer_init(&intermediates[2]);
    /* Add associated data. */
    intermediates[0].data = associated_data->data;
    intermediates[0].len = associated_data->len;
    /* Add associated data length in bits. */
    /* multiplying a uint32_t by 8 won't bring it anywhere close to UINT64_MAX */
    associated_data_len_be = 8 * (uint64_t)associated_data->len;
    associated_data_len_be = BSON_UINT64_TO_BE(associated_data_len_be);
    intermediates[1].data = (uint8_t *)&associated_data_len_be;
    intermediates[1].len = sizeof(uint64_t);
    /* Add plaintext. */
    intermediates[2].data = (uint8_t *)plaintext->data;
    intermediates[2].len = plaintext->len;

    tag.data = tag_storage;
    tag.len = sizeof(tag_storage);

    if (!_mongocrypt_buffer_concat(&to_hmac, intermediates, 3)) {
        CLIENT_ERR("failed to allocate buffer");
        goto done;
    }

    if (!_crypto_hmac_sha_512(crypto, &iv_key, &to_hmac, &tag, status)) {
        goto done;
    }

    /* Truncate to IV length */
    memcpy(out->data, tag.data, MONGOCRYPT_IV_LEN);

    ret = true;
done:
    _mongocrypt_buffer_cleanup(&to_hmac);
    return ret;
}

bool _mongocrypt_wrap_key(_mongocrypt_crypto_t *crypto,
                          _mongocrypt_buffer_t *kek,
                          _mongocrypt_buffer_t *dek,
                          _mongocrypt_buffer_t *encrypted_dek,
                          mongocrypt_status_t *status) {
    const _mongocrypt_value_encryption_algorithm_t *fle1alg = _mcFLE1Algorithm();
    uint32_t bytes_written;
    _mongocrypt_buffer_t iv = {0};
    bool ret = false;

    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(kek);
    BSON_ASSERT_PARAM(dek);
    BSON_ASSERT_PARAM(encrypted_dek);

    _mongocrypt_buffer_init(encrypted_dek);

    if (dek->len != MONGOCRYPT_KEY_LEN) {
        CLIENT_ERR("data encryption key is incorrect length, expected: %" PRIu32 ", got: %" PRIu32,
                   MONGOCRYPT_KEY_LEN,
                   dek->len);
        goto done;
    }

    // _mongocrypt_wrap_key() uses FLE1 algorithm parameters.
    _mongocrypt_buffer_resize(encrypted_dek, fle1alg->get_ciphertext_len(dek->len, status));
    _mongocrypt_buffer_resize(&iv, MONGOCRYPT_IV_LEN);

    if (!_mongocrypt_random(crypto, &iv, MONGOCRYPT_IV_LEN, status)) {
        goto done;
    }

    if (!fle1alg
             ->do_encrypt(crypto, &iv, NULL /* associated data. */, kek, dek, encrypted_dek, &bytes_written, status)) {
        goto done;
    }

    ret = true;
done:
    _mongocrypt_buffer_cleanup(&iv);
    return ret;
}

bool _mongocrypt_unwrap_key(_mongocrypt_crypto_t *crypto,
                            _mongocrypt_buffer_t *kek,
                            _mongocrypt_buffer_t *encrypted_dek,
                            _mongocrypt_buffer_t *dek,
                            mongocrypt_status_t *status) {
    const _mongocrypt_value_encryption_algorithm_t *fle1alg = _mcFLE1Algorithm();
    uint32_t bytes_written;

    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(kek);
    BSON_ASSERT_PARAM(dek);
    BSON_ASSERT_PARAM(encrypted_dek);

    // _mongocrypt_wrap_key() uses FLE1 algorithm parameters.
    _mongocrypt_buffer_init(dek);
    _mongocrypt_buffer_resize(dek, fle1alg->get_plaintext_len(encrypted_dek->len, status));

    if (!fle1alg->do_decrypt(crypto, NULL /* associated data. */, kek, encrypted_dek, dek, &bytes_written, status)) {
        return false;
    }
    dek->len = bytes_written;

    if (dek->len != MONGOCRYPT_KEY_LEN) {
        CLIENT_ERR("decrypted key is incorrect length, expected: %" PRIu32 ", got: %" PRIu32,
                   MONGOCRYPT_KEY_LEN,
                   dek->len);
        return false;
    }
    return true;
}

/* This implementation avoids modulo bias. It is based on arc4random_uniform:
https://github.com/openbsd/src/blob/2207c4325726fdc5c4bcd0011af0fdf7d3dab137/lib/libc/crypt/arc4random_uniform.c#L33
*/
bool _mongocrypt_random_uint64(_mongocrypt_crypto_t *crypto,
                               uint64_t exclusive_upper_bound,
                               uint64_t *out,
                               mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(out);

    *out = 0;

    if (exclusive_upper_bound < 2) {
        *out = 0;
        return true;
    }

    /* 2**64 % x == (2**64 - x) % x */
    uint64_t min = (0 - exclusive_upper_bound) % exclusive_upper_bound;

    _mongocrypt_buffer_t rand_u64_buf;
    _mongocrypt_buffer_init(&rand_u64_buf);
    _mongocrypt_buffer_resize(&rand_u64_buf, (uint32_t)sizeof(uint64_t));

    uint64_t rand_u64;
    for (;;) {
        if (!_mongocrypt_random(crypto, &rand_u64_buf, rand_u64_buf.len, status)) {
            _mongocrypt_buffer_cleanup(&rand_u64_buf);
            return false;
        }

        memcpy(&rand_u64, rand_u64_buf.data, rand_u64_buf.len);
        // Use little-endian to enable deterministic tests on big-endian machines.
        rand_u64 = BSON_UINT64_FROM_LE(rand_u64);

        if (rand_u64 >= min) {
            break;
        }
    }

    *out = rand_u64 % exclusive_upper_bound;

    _mongocrypt_buffer_cleanup(&rand_u64_buf);
    return true;
}

bool _mongocrypt_random_int64(_mongocrypt_crypto_t *crypto,
                              int64_t exclusive_upper_bound,
                              int64_t *out,
                              mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(out);

    if (exclusive_upper_bound <= 0) {
        CLIENT_ERR("Expected exclusive_upper_bound > 0");
        return false;
    }

    uint64_t u64_exclusive_upper_bound = (uint64_t)exclusive_upper_bound;
    uint64_t u64_out;

    if (!_mongocrypt_random_uint64(crypto, u64_exclusive_upper_bound, &u64_out, status)) {
        return false;
    }

    /* Zero the leading bit to ensure rand_i64 is non-negative. */
    u64_out &= (~(1ull << 63));
    *out = (int64_t)u64_out;
    return true;
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-ctx-datakey.c0000644000175100001660000005601114760300420021167 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include "mongocrypt-crypto-private.h"
#include "mongocrypt-ctx-private.h"
#include "mongocrypt-kms-ctx-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt.h"

static void _cleanup(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_datakey_t *dkctx;

    BSON_ASSERT_PARAM(ctx);

    dkctx = (_mongocrypt_ctx_datakey_t *)ctx;
    _mongocrypt_buffer_cleanup(&dkctx->key_doc);
    _mongocrypt_kms_ctx_cleanup(&dkctx->kms);
    _mongocrypt_buffer_cleanup(&dkctx->encrypted_key_material);
    _mongocrypt_buffer_cleanup(&dkctx->plaintext_key_material);
    _mongocrypt_buffer_cleanup(&dkctx->kmip_secretdata);
    bson_free((void *)dkctx->kmip_unique_identifier);
}

static mongocrypt_kms_ctx_t *_next_kms_ctx(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_datakey_t *dkctx;

    BSON_ASSERT_PARAM(ctx);

    dkctx = (_mongocrypt_ctx_datakey_t *)ctx;
    if (!dkctx->kms.should_retry && dkctx->kms_returned) {
        return NULL;
    }
    dkctx->kms.should_retry = false; // Reset retry state.
    dkctx->kms_returned = true;
    return &dkctx->kms;
}

static bool _kms_kmip_start(mongocrypt_ctx_t *ctx, const mc_kms_creds_t *kc) {
    bool ret = false;
    _mongocrypt_ctx_datakey_t *dkctx = (_mongocrypt_ctx_datakey_t *)ctx;
    char *user_supplied_keyid = NULL;
    const _mongocrypt_endpoint_t *endpoint = NULL;
    mongocrypt_status_t *status = ctx->status;
    _mongocrypt_buffer_t secretdata = {0};

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(kc);
    BSON_ASSERT(kc->type == MONGOCRYPT_KMS_PROVIDER_KMIP);

    if (ctx->opts.kek.kms_provider != MONGOCRYPT_KMS_PROVIDER_KMIP) {
        CLIENT_ERR("KMS provider is not KMIP");
        goto fail;
    }
    const bool delegated = ctx->opts.kek.provider.kmip.delegated;

    user_supplied_keyid = ctx->opts.kek.provider.kmip.key_id;

    if (ctx->opts.kek.provider.kmip.endpoint) {
        endpoint = ctx->opts.kek.provider.kmip.endpoint;
    } else if (kc->value.kmip.endpoint) {
        endpoint = kc->value.kmip.endpoint;
    } else {
        CLIENT_ERR("endpoint not set for KMIP request");
        goto fail;
    }

    if (user_supplied_keyid && !dkctx->kmip_unique_identifier) {
        /* User set a 'keyId'. */
        dkctx->kmip_unique_identifier = bson_strdup(user_supplied_keyid);
        dkctx->kmip_activated = true;
    }

    if (delegated) {
        /*
         * The KMIP delegated createDataKey flow is the following:
         * 1. Send a KMIP Create request (symmetric key) (returns keyId)
         * 2. Send a KMIP Activate request with that keyId
         * 3. Send a KMIP Encrypt request to encrypt the DEK
         *
         * Steps 1 and 2 are skipped if the user provided a keyId
         */

        if (!dkctx->kmip_unique_identifier) {
            /* User did not set a 'keyId'. */
            /* Step 1. Send a KMIP Create request for a new AES-256 symmetric key. */
            if (!_mongocrypt_kms_ctx_init_kmip_create(&dkctx->kms, endpoint, ctx->opts.kek.kmsid, &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                goto fail;
            }
            ctx->state = MONGOCRYPT_CTX_NEED_KMS;
            goto success;
        }

        if (!dkctx->kmip_activated) {
            /* Step 2. Send a KMIP Activate request. */
            if (!_mongocrypt_kms_ctx_init_kmip_activate(&dkctx->kms,
                                                        endpoint,
                                                        dkctx->kmip_unique_identifier,
                                                        ctx->opts.kek.kmsid,
                                                        &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                goto fail;
            }
            ctx->state = MONGOCRYPT_CTX_NEED_KMS;
            goto success;
        }

        if (!dkctx->encrypted_key_material.data) {
            /* Step 3. Have the KMS encrypt a new DEK. */
            if (!_mongocrypt_kms_ctx_init_kmip_encrypt(&dkctx->kms,
                                                       endpoint,
                                                       dkctx->kmip_unique_identifier,
                                                       ctx->opts.kek.kmsid,
                                                       &dkctx->plaintext_key_material,
                                                       &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                goto fail;
            }
            ctx->state = MONGOCRYPT_CTX_NEED_KMS;
            goto success;
        }
    } else {
        /* The KMIP createDataKey flow is the following:
         *
         * 1. Send a KMIP Register request with a new 96 byte key as a SecretData
         *    managed object. This returns a Unique Identifier.
         * 2. Send a KMIP Activate request with the Unique Identifier.
         *    This returns the same Unique Identifier.
         * 3. Send a KMIP Get request with the Unique Identifier.
         *    This returns the 96 byte SecretData.
         * 4. Use the 96 byte SecretData to encrypt a new DEK.
         *
         * If the user set a 'keyId' to use, the flow begins at step 3.
         */
        if (!dkctx->kmip_unique_identifier) {
            /* User did not set a 'keyId'. */
            /* Step 1. Send a KMIP Register request with a new 96 byte SecretData. */
            _mongocrypt_buffer_init(&secretdata);
            _mongocrypt_buffer_resize(&secretdata, MONGOCRYPT_KEY_LEN);
            if (!_mongocrypt_random(ctx->crypt->crypto, &secretdata, MONGOCRYPT_KEY_LEN, ctx->status)) {
                goto fail;
            }

            if (!_mongocrypt_kms_ctx_init_kmip_register(&dkctx->kms,
                                                        endpoint,
                                                        secretdata.data,
                                                        secretdata.len,
                                                        ctx->opts.kek.kmsid,
                                                        &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                goto fail;
            }
            ctx->state = MONGOCRYPT_CTX_NEED_KMS;
            goto success;
        }

        if (!dkctx->kmip_activated) {
            /* Step 2. Send a KMIP Activate request. */
            if (!_mongocrypt_kms_ctx_init_kmip_activate(&dkctx->kms,
                                                        endpoint,
                                                        dkctx->kmip_unique_identifier,
                                                        ctx->opts.kek.kmsid,
                                                        &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                goto fail;
            }
            ctx->state = MONGOCRYPT_CTX_NEED_KMS;
            goto success;
        }

        if (!dkctx->kmip_secretdata.data) {
            /* Step 3. Send a KMIP Get request with the Unique Identifier. */
            if (!_mongocrypt_kms_ctx_init_kmip_get(&dkctx->kms,
                                                   endpoint,
                                                   dkctx->kmip_unique_identifier,
                                                   ctx->opts.kek.kmsid,
                                                   &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                goto fail;
            }
            ctx->state = MONGOCRYPT_CTX_NEED_KMS;
            goto success;
        }

        /* Step 4. Use the 96 byte SecretData to encrypt a new DEK. */
        if (!_mongocrypt_wrap_key(ctx->crypt->crypto,
                                  &dkctx->kmip_secretdata,
                                  &dkctx->plaintext_key_material,
                                  &dkctx->encrypted_key_material,
                                  ctx->status)) {
            goto fail;
        }
    }

    if (!ctx->opts.kek.provider.kmip.key_id) {
        /* If there was no user supplied key_id, set it from the
         * UniqueIdentifer of the newly registered SecretData. */
        ctx->opts.kek.provider.kmip.key_id = bson_strdup(dkctx->kmip_unique_identifier);
    }
    ctx->state = MONGOCRYPT_CTX_READY;

success:
    ret = true;
fail:
    if (!ret) {
        _mongocrypt_ctx_fail(ctx);
    }
    _mongocrypt_buffer_cleanup(&secretdata);
    return ret;
}

/* For local, immediately encrypt.
 * For AWS, create the KMS request to encrypt.
 * For Azure/GCP, auth first if needed, otherwise encrypt.
 */
static bool _kms_start(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    bool ret = false;
    _mongocrypt_ctx_datakey_t *dkctx;
    char *access_token = NULL;
    _mongocrypt_opts_kms_providers_t *const kms_providers = _mongocrypt_ctx_kms_providers(ctx);

    dkctx = (_mongocrypt_ctx_datakey_t *)ctx;

    mc_kms_creds_t kc;
    if (!_mongocrypt_opts_kms_providers_lookup(kms_providers, ctx->opts.kek.kmsid, &kc)) {
        mongocrypt_status_t *status = ctx->status;
        CLIENT_ERR("KMS provider `%s` is not configured", ctx->opts.kek.kmsid);
        _mongocrypt_ctx_fail(ctx);
        goto done;
    }

    /* Clear out any pre-existing initialized KMS context, and zero it (so it is
     * safe to call cleanup again). */
    _mongocrypt_kms_ctx_cleanup(&dkctx->kms);
    memset(&dkctx->kms, 0, sizeof(dkctx->kms));
    dkctx->kms_returned = false;
    if (ctx->opts.kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_LOCAL) {
        BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_LOCAL);
        if (!_mongocrypt_wrap_key(ctx->crypt->crypto,
                                  &kc.value.local.key,
                                  &dkctx->plaintext_key_material,
                                  &dkctx->encrypted_key_material,
                                  ctx->status)) {
            _mongocrypt_ctx_fail(ctx);
            goto done;
        }
        ctx->state = MONGOCRYPT_CTX_READY;
    } else if (ctx->opts.kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_AWS) {
        /* For AWS provider, AWS credentials are supplied in
         * mongocrypt_setopt_kms_provider_aws. Data keys are encrypted with an
         * "encrypt" HTTP message to KMS. */
        if (!_mongocrypt_kms_ctx_init_aws_encrypt(&dkctx->kms,
                                                  kms_providers,
                                                  &ctx->opts,
                                                  &dkctx->plaintext_key_material,
                                                  ctx->crypt->crypto,
                                                  ctx->opts.kek.kmsid,
                                                  &ctx->crypt->log)) {
            mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
            _mongocrypt_ctx_fail(ctx);
            goto done;
        }

        ctx->state = MONGOCRYPT_CTX_NEED_KMS;
    } else if (ctx->opts.kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_AZURE) {
        BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_AZURE);
        if (kc.value.azure.access_token) {
            access_token = bson_strdup(kc.value.azure.access_token);
        } else {
            access_token = mc_mapof_kmsid_to_token_get_token(ctx->crypt->cache_oauth, ctx->opts.kek.kmsid);
        }
        if (access_token) {
            if (!_mongocrypt_kms_ctx_init_azure_wrapkey(&dkctx->kms,
                                                        kms_providers,
                                                        &ctx->opts,
                                                        access_token,
                                                        &dkctx->plaintext_key_material,
                                                        ctx->opts.kek.kmsid,
                                                        &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                _mongocrypt_ctx_fail(ctx);
                goto done;
            }
        } else {
            if (!_mongocrypt_kms_ctx_init_azure_auth(&dkctx->kms,
                                                     &kc,
                                                     ctx->opts.kek.provider.azure.key_vault_endpoint,
                                                     ctx->opts.kek.kmsid,
                                                     &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                _mongocrypt_ctx_fail(ctx);
                goto done;
            }
        }
        ctx->state = MONGOCRYPT_CTX_NEED_KMS;
    } else if (ctx->opts.kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_GCP) {
        BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_GCP);
        if (NULL != kc.value.gcp.access_token) {
            access_token = bson_strdup(kc.value.gcp.access_token);
        } else {
            access_token = mc_mapof_kmsid_to_token_get_token(ctx->crypt->cache_oauth, ctx->opts.kek.kmsid);
        }
        if (access_token) {
            if (!_mongocrypt_kms_ctx_init_gcp_encrypt(&dkctx->kms,
                                                      kms_providers,
                                                      &ctx->opts,
                                                      access_token,
                                                      &dkctx->plaintext_key_material,
                                                      ctx->opts.kek.kmsid,
                                                      &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                _mongocrypt_ctx_fail(ctx);
                goto done;
            }
        } else {
            if (!_mongocrypt_kms_ctx_init_gcp_auth(&dkctx->kms,
                                                   &ctx->crypt->opts,
                                                   &kc,
                                                   ctx->opts.kek.provider.gcp.endpoint,
                                                   ctx->opts.kek.kmsid,
                                                   &ctx->crypt->log)) {
                mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status);
                _mongocrypt_ctx_fail(ctx);
                goto done;
            }
        }
        ctx->state = MONGOCRYPT_CTX_NEED_KMS;
    } else if (ctx->opts.kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_KMIP) {
        if (!_kms_kmip_start(ctx, &kc)) {
            goto done;
        }
    } else {
        _mongocrypt_ctx_fail_w_msg(ctx, "unsupported KMS provider");
        goto done;
    }

    ret = true;
done:
    bson_free(access_token);
    return ret;
}

static bool _kms_done(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_datakey_t *dkctx;
    mongocrypt_status_t *status;

    BSON_ASSERT_PARAM(ctx);

    dkctx = (_mongocrypt_ctx_datakey_t *)ctx;
    status = ctx->status;
    if (!mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    if (mongocrypt_kms_ctx_bytes_needed(&dkctx->kms) != 0) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "KMS response unfinished");
    }

    /* If this was an oauth request, store the response and proceed to encrypt.
     */
    if (dkctx->kms.req_type == MONGOCRYPT_KMS_AZURE_OAUTH) {
        bson_t oauth_response;

        BSON_ASSERT(_mongocrypt_buffer_to_bson(&dkctx->kms.result, &oauth_response));
        if (!mc_mapof_kmsid_to_token_add_response(ctx->crypt->cache_oauth,
                                                  ctx->opts.kek.kmsid,
                                                  &oauth_response,
                                                  status)) {
            return _mongocrypt_ctx_fail(ctx);
        }
        return _kms_start(ctx);
    } else if (dkctx->kms.req_type == MONGOCRYPT_KMS_GCP_OAUTH) {
        bson_t oauth_response;

        BSON_ASSERT(_mongocrypt_buffer_to_bson(&dkctx->kms.result, &oauth_response));
        if (!mc_mapof_kmsid_to_token_add_response(ctx->crypt->cache_oauth,
                                                  ctx->opts.kek.kmsid,
                                                  &oauth_response,
                                                  status)) {
            return _mongocrypt_ctx_fail(ctx);
        }
        return _kms_start(ctx);
    } else if (dkctx->kms.req_type == MONGOCRYPT_KMS_KMIP_REGISTER
               || dkctx->kms.req_type == MONGOCRYPT_KMS_KMIP_CREATE) {
        dkctx->kmip_unique_identifier = bson_strdup((const char *)dkctx->kms.result.data);
        return _kms_start(ctx);
    } else if (dkctx->kms.req_type == MONGOCRYPT_KMS_KMIP_ACTIVATE) {
        dkctx->kmip_activated = true;
        return _kms_start(ctx);
    } else if (dkctx->kms.req_type == MONGOCRYPT_KMS_KMIP_GET) {
        _mongocrypt_buffer_copy_to(&dkctx->kms.result, &dkctx->kmip_secretdata);
        return _kms_start(ctx);
    } else if (dkctx->kms.req_type == MONGOCRYPT_KMS_KMIP_ENCRYPT) {
        _mongocrypt_buffer_copy_to(&dkctx->kms.result, &dkctx->encrypted_key_material);
        return _kms_start(ctx);
    }

    /* Store the result. */
    if (!_mongocrypt_kms_ctx_result(&dkctx->kms, &dkctx->encrypted_key_material)) {
        BSON_ASSERT(!mongocrypt_kms_ctx_status(&dkctx->kms, ctx->status));
        return _mongocrypt_ctx_fail(ctx);
    }

    /* The encrypted key material must be at least as large as the plaintext. */
    if (dkctx->encrypted_key_material.len < MONGOCRYPT_KEY_LEN) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "key material not expected length");
    }

    ctx->state = MONGOCRYPT_CTX_READY;
    return true;
}

/* Append a UUID _id. Confer with libmongoc's `_mongoc_server_session_uuid`. */
static bool _append_id(mongocrypt_t *crypt, bson_t *bson, mongocrypt_status_t *status) {
    _mongocrypt_buffer_t uuid;

    BSON_ASSERT_PARAM(crypt);
    BSON_ASSERT_PARAM(bson);

    _mongocrypt_buffer_init(&uuid);
    uuid.data = bson_malloc(UUID_LEN);
    BSON_ASSERT(uuid.data);

    uuid.len = UUID_LEN;
    uuid.subtype = BSON_SUBTYPE_UUID;
    uuid.owned = true;

    if (!_mongocrypt_random(crypt->crypto, &uuid, UUID_LEN, status)) {
        _mongocrypt_buffer_cleanup(&uuid);
        return false;
    }

    uuid.data[6] = (uint8_t)(0x40 | (uuid.data[6] & 0xf));
    uuid.data[8] = (uint8_t)(0x80 | (uuid.data[8] & 0x3f));
    if (!_mongocrypt_buffer_append(&uuid, bson, "_id", 3)) {
        _mongocrypt_buffer_cleanup(&uuid);
        return false;
    }

    _mongocrypt_buffer_cleanup(&uuid);

    return true;
}

static bool _finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    _mongocrypt_ctx_datakey_t *dkctx;
    bson_t key_doc, child;
    struct timeval tp;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

#define BSON_CHECK(_stmt)                                                                                              \
    if (!(_stmt)) {                                                                                                    \
        bson_destroy(&key_doc);                                                                                        \
        return _mongocrypt_ctx_fail_w_msg(ctx, "unable to construct BSON doc");                                        \
    }

    dkctx = (_mongocrypt_ctx_datakey_t *)ctx;

    bson_init(&key_doc);
    if (!_append_id(ctx->crypt, &key_doc, ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    if (ctx->opts.key_alt_names) {
        _mongocrypt_key_alt_name_t *alt_name = ctx->opts.key_alt_names;
        int i;

        bson_append_array_begin(&key_doc, "keyAltNames", -1, &child);
        for (i = 0; alt_name; i++) {
            char *key = bson_strdup_printf("%d", i);
            bson_append_value(&child, key, -1, &alt_name->value);
            bson_free(key);
            alt_name = alt_name->next;
        }
        bson_append_array_end(&key_doc, &child);
    }
    if (!_mongocrypt_buffer_append(&dkctx->encrypted_key_material, &key_doc, MONGOCRYPT_STR_AND_LEN("keyMaterial"))) {
        bson_destroy(&key_doc);
        return _mongocrypt_ctx_fail_w_msg(ctx, "could not append keyMaterial");
    }
    bson_gettimeofday(&tp);
    BSON_CHECK(bson_append_timeval(&key_doc, MONGOCRYPT_STR_AND_LEN("creationDate"), &tp));
    BSON_CHECK(bson_append_timeval(&key_doc, MONGOCRYPT_STR_AND_LEN("updateDate"), &tp));
    BSON_CHECK(bson_append_int32(&key_doc, MONGOCRYPT_STR_AND_LEN("status"), 0)); /* 0 = enabled. */
    BSON_CHECK(bson_append_document_begin(&key_doc, MONGOCRYPT_STR_AND_LEN("masterKey"), &child));
    if (!_mongocrypt_kek_append(&ctx->opts.kek, &child, ctx->status)) {
        bson_destroy(&key_doc);
        return _mongocrypt_ctx_fail(ctx);
    }
    BSON_CHECK(bson_append_document_end(&key_doc, &child));
    _mongocrypt_buffer_steal_from_bson(&dkctx->key_doc, &key_doc);
    _mongocrypt_buffer_to_binary(&dkctx->key_doc, out);
    ctx->state = MONGOCRYPT_CTX_DONE;
    return true;
}

bool mongocrypt_ctx_datakey_init(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_datakey_t *dkctx;
    _mongocrypt_ctx_opts_spec_t opts_spec;
    bool ret;

    if (!ctx) {
        return false;
    }
    ret = false;
    memset(&opts_spec, 0, sizeof(opts_spec));
    opts_spec.kek = OPT_REQUIRED;
    opts_spec.key_alt_names = OPT_OPTIONAL;
    opts_spec.key_material = OPT_OPTIONAL;

    if (!_mongocrypt_ctx_init(ctx, &opts_spec)) {
        return false;
    }

    dkctx = (_mongocrypt_ctx_datakey_t *)ctx;
    ctx->type = _MONGOCRYPT_TYPE_CREATE_DATA_KEY;
    ctx->vtable.mongo_op_keys = NULL;
    ctx->vtable.mongo_feed_keys = NULL;
    ctx->vtable.mongo_done_keys = NULL;
    ctx->vtable.next_kms_ctx = _next_kms_ctx;
    ctx->vtable.after_kms_credentials_provided = _kms_start;
    ctx->vtable.kms_done = _kms_done;
    ctx->vtable.finalize = _finalize;
    ctx->vtable.cleanup = _cleanup;

    _mongocrypt_buffer_init(&dkctx->plaintext_key_material);

    if (ctx->opts.key_material.owned) {
        /* Use keyMaterial provided by user via DataKeyOpts. */
        _mongocrypt_buffer_steal(&dkctx->plaintext_key_material, &ctx->opts.key_material);
    } else {
        /* Generate keyMaterial instead. */
        dkctx->plaintext_key_material.data = bson_malloc(MONGOCRYPT_KEY_LEN);
        BSON_ASSERT(dkctx->plaintext_key_material.data);
        dkctx->plaintext_key_material.len = MONGOCRYPT_KEY_LEN;
        dkctx->plaintext_key_material.owned = true;
        if (!_mongocrypt_random(ctx->crypt->crypto, &dkctx->plaintext_key_material, MONGOCRYPT_KEY_LEN, ctx->status)) {
            _mongocrypt_ctx_fail(ctx);
            goto done;
        }
    }

    if (_mongocrypt_needs_credentials_for_provider(ctx->crypt, ctx->opts.kek.kms_provider, ctx->opts.kek.kmsid_name)) {
        ctx->state = MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS;
    } else if (!_kms_start(ctx)) {
        goto done;
    }

    ret = true;
done:
    return ret;
}mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-ctx-decrypt.c0000644000175100001660000010477014760300420021225 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include "mc-fle-blob-subtype-private.h"
#include "mc-fle2-insert-update-payload-private-v2.h"
#include "mc-fle2-insert-update-payload-private.h"
#include "mc-fle2-payload-iev-private-v2.h"
#include "mc-fle2-payload-iev-private.h"
#include "mc-fle2-payload-uev-private.h"
#include "mc-fle2-payload-uev-v2-private.h"
#include "mongocrypt-ciphertext-private.h"
#include "mongocrypt-crypto-private.h"
#include "mongocrypt-ctx-private.h"
#include "mongocrypt-traverse-util-private.h"

#define CHECK_AND_RETURN(cond)                                                                                         \
    if (!(cond)) {                                                                                                     \
        goto fail;                                                                                                     \
    }

#define CHECK_AND_RETURN_STATUS(cond, msg)                                                                             \
    if (!(cond)) {                                                                                                     \
        CLIENT_ERR(msg);                                                                                               \
        goto fail;                                                                                                     \
    }

#define CHECK_AND_RETURN_KB_STATUS(cond)                                                                               \
    if (!(cond)) {                                                                                                     \
        _mongocrypt_key_broker_status(kb, status);                                                                     \
        goto fail;                                                                                                     \
    }

static bool _replace_FLE2IndexedEncryptedValue_with_plaintext(void *ctx,
                                                              _mongocrypt_buffer_t *in,
                                                              bson_value_t *out,
                                                              mongocrypt_status_t *providedStatus) {
    bool ret = false;
    _mongocrypt_key_broker_t *kb = ctx;
    mc_FLE2IndexedEncryptedValue_t *iev = mc_FLE2IndexedEncryptedValue_new();
    _mongocrypt_buffer_t S_Key = {0};
    _mongocrypt_buffer_t K_Key = {0};
    mongocrypt_status_t *status = providedStatus;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    if (providedStatus == NULL) {
        // We accept a NULL status, but add_[SK]_Key require non-NULL.
        // Make a temporary status object as needed.
        status = mongocrypt_status_new();
    }

    // Parse the IEV payload to get S_KeyId.
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValue_parse(iev, in, status));
    const _mongocrypt_buffer_t *S_KeyId = mc_FLE2IndexedEncryptedValue_get_S_KeyId(iev, status);
    CHECK_AND_RETURN(S_KeyId);

    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, S_KeyId, &S_Key));

    // Use S_Key to decrypt envelope and get to K_KeyId.
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValue_add_S_Key(kb->crypt->crypto, iev, &S_Key, status));
    const _mongocrypt_buffer_t *K_KeyId = mc_FLE2IndexedEncryptedValue_get_K_KeyId(iev, status);
    CHECK_AND_RETURN(K_KeyId);

    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, K_KeyId, &K_Key));

    // Decrypt the actual data value using K_Key.
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValue_add_K_Key(kb->crypt->crypto, iev, &K_Key, status));
    const _mongocrypt_buffer_t *clientValue = mc_FLE2IndexedEncryptedValue_get_ClientValue(iev, status);
    CHECK_AND_RETURN(clientValue);

    // Marshal BSON value and type into a usable bson_value_t.
    bson_type_t original_bson_type = mc_FLE2IndexedEncryptedValue_get_original_bson_type(iev, status);
    CHECK_AND_RETURN(original_bson_type != BSON_TYPE_EOD);
    CHECK_AND_RETURN_STATUS(
        _mongocrypt_buffer_to_bson_value((_mongocrypt_buffer_t *)clientValue, (uint8_t)original_bson_type, out),
        "decrypted clientValue is not valid BSON");

    ret = true;
fail:
    if (status != providedStatus) {
        mongocrypt_status_destroy(status);
    }
    _mongocrypt_buffer_cleanup(&K_Key);
    _mongocrypt_buffer_cleanup(&S_Key);
    mc_FLE2IndexedEncryptedValue_destroy(iev);
    return ret;
}

static bool _replace_FLE2IndexedEncryptedValueV2_with_plaintext(void *ctx,
                                                                _mongocrypt_buffer_t *in,
                                                                bson_value_t *out,
                                                                mongocrypt_status_t *providedStatus) {
    bool ret = false;
    _mongocrypt_key_broker_t *kb = ctx;
    mc_FLE2IndexedEncryptedValueV2_t *iev = mc_FLE2IndexedEncryptedValueV2_new();
    _mongocrypt_buffer_t S_Key = {0};
    _mongocrypt_buffer_t K_Key = {0};
    mongocrypt_status_t *status = providedStatus;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    if (providedStatus == NULL) {
        // We accept a NULL status, but add_[SK]_Key require non-NULL.
        // Make a temporary status object as needed.
        status = mongocrypt_status_new();
    }

    // Parse the IEV payload to get S_KeyId.
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValueV2_parse(iev, in, status));
    const _mongocrypt_buffer_t *S_KeyId = mc_FLE2IndexedEncryptedValueV2_get_S_KeyId(iev, status);
    CHECK_AND_RETURN(S_KeyId);
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, S_KeyId, &S_Key));

    // Use S_Key to decrypt envelope and get to K_KeyId.
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValueV2_add_S_Key(kb->crypt->crypto, iev, &S_Key, status));
    const _mongocrypt_buffer_t *K_KeyId = mc_FLE2IndexedEncryptedValueV2_get_K_KeyId(iev, status);
    CHECK_AND_RETURN(K_KeyId);
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, K_KeyId, &K_Key));

    // Decrypt the actual data value using K_Key.
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValueV2_add_K_Key(kb->crypt->crypto, iev, &K_Key, status));
    const _mongocrypt_buffer_t *clientValue = mc_FLE2IndexedEncryptedValueV2_get_ClientValue(iev, status);
    CHECK_AND_RETURN(clientValue);

    // Marshal BSON value and type into a usable bson_value_t.
    bson_type_t bson_type = mc_FLE2IndexedEncryptedValueV2_get_bson_value_type(iev, status);
    CHECK_AND_RETURN(bson_type != BSON_TYPE_EOD);
    CHECK_AND_RETURN_STATUS(
        _mongocrypt_buffer_to_bson_value((_mongocrypt_buffer_t *)clientValue, (uint8_t)bson_type, out),
        "decrypted clientValue is not valid BSON");

    ret = true;
fail:
    if (status != providedStatus) {
        mongocrypt_status_destroy(status);
    }
    _mongocrypt_buffer_cleanup(&K_Key);
    _mongocrypt_buffer_cleanup(&S_Key);
    mc_FLE2IndexedEncryptedValueV2_destroy(iev);
    return ret;
}

static bool _replace_FLE2UnindexedEncryptedValue_with_plaintext(void *ctx,
                                                                _mongocrypt_buffer_t *in,
                                                                bson_value_t *out,
                                                                mongocrypt_status_t *status) {
    bool ret = false;
    _mongocrypt_key_broker_t *kb = ctx;
    mc_FLE2UnindexedEncryptedValue_t *uev = mc_FLE2UnindexedEncryptedValue_new();
    _mongocrypt_buffer_t key = {0};

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    // Parse the UEV payload to get the encryption key.
    CHECK_AND_RETURN(mc_FLE2UnindexedEncryptedValue_parse(uev, in, status));

    const _mongocrypt_buffer_t *key_uuid = mc_FLE2UnindexedEncryptedValue_get_key_uuid(uev, status);
    CHECK_AND_RETURN(key_uuid);

    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, key_uuid, &key));

    // Decrypt the actual data value using encryption key.
    const _mongocrypt_buffer_t *plaintext =
        mc_FLE2UnindexedEncryptedValue_decrypt(kb->crypt->crypto, uev, &key, status);
    CHECK_AND_RETURN(plaintext);

    // Marshal BSON value and type into a usable bson_value_t.
    bson_type_t original_bson_type = mc_FLE2UnindexedEncryptedValue_get_original_bson_type(uev, status);
    CHECK_AND_RETURN(original_bson_type != BSON_TYPE_EOD);

    CHECK_AND_RETURN_STATUS(
        _mongocrypt_buffer_to_bson_value((_mongocrypt_buffer_t *)plaintext, (uint8_t)original_bson_type, out),
        "decrypted plaintext is not valid BSON");

    ret = true;
fail:
    _mongocrypt_buffer_cleanup(&key);
    mc_FLE2UnindexedEncryptedValue_destroy(uev);
    return ret;
}

static bool _replace_FLE2UnindexedEncryptedValueV2_with_plaintext(void *ctx,
                                                                  _mongocrypt_buffer_t *in,
                                                                  bson_value_t *out,
                                                                  mongocrypt_status_t *status) {
    bool ret = false;
    _mongocrypt_key_broker_t *kb = ctx;
    mc_FLE2UnindexedEncryptedValueV2_t *uev = mc_FLE2UnindexedEncryptedValueV2_new();
    _mongocrypt_buffer_t key = {0};

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    // Parse the UEV payload to get the encryption key.
    CHECK_AND_RETURN(mc_FLE2UnindexedEncryptedValueV2_parse(uev, in, status));

    const _mongocrypt_buffer_t *key_uuid = mc_FLE2UnindexedEncryptedValueV2_get_key_uuid(uev, status);
    CHECK_AND_RETURN(key_uuid);

    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, key_uuid, &key));

    // Decrypt the actual data value using encryption key.
    const _mongocrypt_buffer_t *plaintext =
        mc_FLE2UnindexedEncryptedValueV2_decrypt(kb->crypt->crypto, uev, &key, status);
    CHECK_AND_RETURN(plaintext);

    // Marshal BSON value and type into a usable bson_value_t.
    bson_type_t original_bson_type = mc_FLE2UnindexedEncryptedValueV2_get_original_bson_type(uev, status);
    CHECK_AND_RETURN(original_bson_type != BSON_TYPE_EOD);

    CHECK_AND_RETURN_STATUS(
        _mongocrypt_buffer_to_bson_value((_mongocrypt_buffer_t *)plaintext, (uint8_t)original_bson_type, out),
        "decrypted plaintext is not valid BSON");

    ret = true;
fail:
    _mongocrypt_buffer_cleanup(&key);
    mc_FLE2UnindexedEncryptedValueV2_destroy(uev);
    return ret;
}

static bool _replace_FLE2InsertUpdatePayload_with_plaintext(void *ctx,
                                                            _mongocrypt_buffer_t *in,
                                                            bson_value_t *out,
                                                            mongocrypt_status_t *status) {
    bool ret = false;
    _mongocrypt_key_broker_t *kb = ctx;
    mc_FLE2InsertUpdatePayload_t iup;
    _mongocrypt_buffer_t key = {0};

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    mc_FLE2InsertUpdatePayload_init(&iup);

    // Parse the IUP payload to get the encryption key.
    CHECK_AND_RETURN(mc_FLE2InsertUpdatePayload_parse(&iup, in, status));
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, &iup.userKeyId, &key));

    // Decrypt the actual data value using encryption key.
    const _mongocrypt_buffer_t *plaintext = mc_FLE2InsertUpdatePayload_decrypt(kb->crypt->crypto, &iup, &key, status);
    CHECK_AND_RETURN(plaintext);

    // Marshal BSON value and type into a usable bson_value_t.
    bson_type_t original_bson_type = iup.valueType;
    CHECK_AND_RETURN_STATUS(
        _mongocrypt_buffer_to_bson_value((_mongocrypt_buffer_t *)plaintext, (uint8_t)original_bson_type, out),
        "decrypted plaintext is not valid BSON");

    ret = true;
fail:
    _mongocrypt_buffer_cleanup(&key);
    mc_FLE2InsertUpdatePayload_cleanup(&iup);
    return ret;
}

static bool _replace_FLE2InsertUpdatePayloadV2_with_plaintext(void *ctx,
                                                              _mongocrypt_buffer_t *in,
                                                              bson_value_t *out,
                                                              mongocrypt_status_t *status) {
    bool ret = false;
    _mongocrypt_key_broker_t *kb = ctx;
    mc_FLE2InsertUpdatePayloadV2_t iup;
    _mongocrypt_buffer_t key = {0};

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    mc_FLE2InsertUpdatePayloadV2_init(&iup);

    // Parse the IUP payload to get the encryption key.
    CHECK_AND_RETURN(mc_FLE2InsertUpdatePayloadV2_parse(&iup, in, status));
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, &iup.userKeyId, &key));

    // Decrypt the actual data value using encryption key.
    const _mongocrypt_buffer_t *plaintext = mc_FLE2InsertUpdatePayloadV2_decrypt(kb->crypt->crypto, &iup, &key, status);
    CHECK_AND_RETURN(plaintext);

    // Marshal BSON value and type into a usable bson_value_t.
    bson_type_t original_bson_type = iup.valueType;
    CHECK_AND_RETURN_STATUS(
        _mongocrypt_buffer_to_bson_value((_mongocrypt_buffer_t *)plaintext, (uint8_t)original_bson_type, out),
        "decrypted plaintext is not valid BSON");

    ret = true;
fail:
    _mongocrypt_buffer_cleanup(&key);
    mc_FLE2InsertUpdatePayloadV2_cleanup(&iup);
    return ret;
}

static bool _replace_FLE1Payload_with_plaintext(void *ctx,
                                                _mongocrypt_buffer_t *in,
                                                bson_value_t *out,
                                                mongocrypt_status_t *status) {
    _mongocrypt_key_broker_t *kb;
    _mongocrypt_ciphertext_t ciphertext;
    _mongocrypt_buffer_t plaintext;
    _mongocrypt_buffer_t key_material;
    _mongocrypt_buffer_t associated_data;
    uint32_t bytes_written;
    bool ret = false;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);
    BSON_ASSERT(in->data);

    _mongocrypt_buffer_init(&plaintext);
    _mongocrypt_buffer_init(&associated_data);
    _mongocrypt_buffer_init(&key_material);
    kb = (_mongocrypt_key_broker_t *)ctx;

    CHECK_AND_RETURN(_mongocrypt_ciphertext_parse_unowned(in, &ciphertext, status));

    /* look up the key */
    CHECK_AND_RETURN_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, &ciphertext.key_id, &key_material),
                            "key not found");

    const _mongocrypt_value_encryption_algorithm_t *fle1alg = _mcFLE1Algorithm();
    plaintext.len = fle1alg->get_plaintext_len(ciphertext.data.len, status);
    CHECK_AND_RETURN(plaintext.len != 0);
    plaintext.data = bson_malloc0(plaintext.len);
    BSON_ASSERT(plaintext.data);

    plaintext.owned = true;

    CHECK_AND_RETURN_STATUS(_mongocrypt_ciphertext_serialize_associated_data(&ciphertext, &associated_data),
                            "could not serialize associated data");

    CHECK_AND_RETURN(fle1alg->do_decrypt(kb->crypt->crypto,
                                         &associated_data,
                                         &key_material,
                                         &ciphertext.data,
                                         &plaintext,
                                         &bytes_written,
                                         status));

    plaintext.len = bytes_written;

    CHECK_AND_RETURN_STATUS(_mongocrypt_buffer_to_bson_value(&plaintext, ciphertext.original_bson_type, out),
                            "malformed encrypted bson");

    ret = true;
fail:
    _mongocrypt_buffer_cleanup(&plaintext);
    _mongocrypt_buffer_cleanup(&associated_data);
    _mongocrypt_buffer_cleanup(&key_material);
    return ret;
}

static bool _replace_ciphertext_with_plaintext(void *ctx,
                                               _mongocrypt_buffer_t *in,
                                               bson_value_t *out,
                                               mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);
    BSON_ASSERT(in->data);

    switch (in->data[0]) {
    // FLE2v2
    case MC_SUBTYPE_FLE2IndexedEqualityEncryptedValueV2:
    case MC_SUBTYPE_FLE2IndexedRangeEncryptedValueV2:
        return _replace_FLE2IndexedEncryptedValueV2_with_plaintext(ctx, in, out, status);
    case MC_SUBTYPE_FLE2InsertUpdatePayloadV2:
        return _replace_FLE2InsertUpdatePayloadV2_with_plaintext(ctx, in, out, status);
    case MC_SUBTYPE_FLE2UnindexedEncryptedValueV2:
        return _replace_FLE2UnindexedEncryptedValueV2_with_plaintext(ctx, in, out, status);

    // FLE2v1
    case MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue:
    case MC_SUBTYPE_FLE2IndexedRangeEncryptedValue:
        return _replace_FLE2IndexedEncryptedValue_with_plaintext(ctx, in, out, status);
    case MC_SUBTYPE_FLE2InsertUpdatePayload:
        return _replace_FLE2InsertUpdatePayload_with_plaintext(ctx, in, out, status);
    case MC_SUBTYPE_FLE2UnindexedEncryptedValue:
        return _replace_FLE2UnindexedEncryptedValue_with_plaintext(ctx, in, out, status);

    // FLE1
    default: return _replace_FLE1Payload_with_plaintext(ctx, in, out, status);
    }
}

static bool _finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    bson_t as_bson, final_bson;
    bson_iter_t iter = {0};
    _mongocrypt_ctx_decrypt_t *dctx;
    bool res;

    if (!ctx) {
        return false;
    }

    if (!out) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "null out parameter");
    }

    dctx = (_mongocrypt_ctx_decrypt_t *)ctx;

    if (ctx->nothing_to_do) {
        _mongocrypt_buffer_to_binary(&dctx->original_doc, out);
        ctx->state = MONGOCRYPT_CTX_DONE;
        return true;
    }

    if (!_mongocrypt_buffer_to_bson(&dctx->original_doc, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson");
    }

    bson_iter_init(&iter, &as_bson);
    bson_init(&final_bson);
    res = _mongocrypt_transform_binary_in_bson(_replace_ciphertext_with_plaintext,
                                               &ctx->kb,
                                               TRAVERSE_MATCH_CIPHERTEXT,
                                               &iter,
                                               &final_bson,
                                               ctx->status);
    if (!res) {
        bson_destroy(&final_bson);
        return _mongocrypt_ctx_fail(ctx);
    }

    _mongocrypt_buffer_steal_from_bson(&dctx->decrypted_doc, &final_bson);
    out->data = dctx->decrypted_doc.data;
    out->len = dctx->decrypted_doc.len;
    ctx->state = MONGOCRYPT_CTX_DONE;
    return true;
}

static bool _collect_S_KeyID_from_FLE2IndexedEncryptedValue(void *ctx,
                                                            const _mongocrypt_buffer_t *in,
                                                            mongocrypt_status_t *status) {
    bool ret = false;
    _mongocrypt_key_broker_t *kb = ctx;
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(in);

    mc_FLE2IndexedEncryptedValue_t *iev = mc_FLE2IndexedEncryptedValue_new();
    CHECK_AND_RETURN(iev);
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValue_parse(iev, in, status));
    const _mongocrypt_buffer_t *S_KeyId = mc_FLE2IndexedEncryptedValue_get_S_KeyId(iev, status);
    CHECK_AND_RETURN(S_KeyId);
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, S_KeyId));

    ret = true;
fail:
    mc_FLE2IndexedEncryptedValue_destroy(iev);
    return ret;
}

static bool _collect_S_KeyID_from_FLE2IndexedEncryptedValueV2(void *ctx,
                                                              const _mongocrypt_buffer_t *in,
                                                              mongocrypt_status_t *status) {
    bool ret = false;
    _mongocrypt_key_broker_t *kb = ctx;
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(in);

    mc_FLE2IndexedEncryptedValueV2_t *iev = mc_FLE2IndexedEncryptedValueV2_new();
    CHECK_AND_RETURN(iev);
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValueV2_parse(iev, in, status));
    const _mongocrypt_buffer_t *S_KeyId = mc_FLE2IndexedEncryptedValueV2_get_S_KeyId(iev, status);
    CHECK_AND_RETURN(S_KeyId);
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, S_KeyId));

    ret = true;
fail:
    mc_FLE2IndexedEncryptedValueV2_destroy(iev);
    return ret;
}

static bool _collect_K_KeyID_from_FLE2IndexedEncryptedValueV2(void *ctx,
                                                              const _mongocrypt_buffer_t *in,
                                                              mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT(in->data);
    bool ret = false;

    BSON_ASSERT((in->data[0] == MC_SUBTYPE_FLE2IndexedEqualityEncryptedValueV2)
                || (in->data[0] == MC_SUBTYPE_FLE2IndexedRangeEncryptedValueV2));

    mc_FLE2IndexedEncryptedValueV2_t *iev = mc_FLE2IndexedEncryptedValueV2_new();
    _mongocrypt_buffer_t S_Key = {0};
    CHECK_AND_RETURN(iev);
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValueV2_parse(iev, in, status));

    const _mongocrypt_buffer_t *S_KeyId = mc_FLE2IndexedEncryptedValueV2_get_S_KeyId(iev, status);
    CHECK_AND_RETURN(S_KeyId);

    _mongocrypt_key_broker_t *kb = ctx;
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, S_KeyId, &S_Key));

    /* Decrypt InnerEncrypted to get K_KeyId. */
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValueV2_add_S_Key(kb->crypt->crypto, iev, &S_Key, status));

    /* Add request for K_KeyId. */
    const _mongocrypt_buffer_t *K_KeyId = mc_FLE2IndexedEncryptedValueV2_get_K_KeyId(iev, status);
    CHECK_AND_RETURN(K_KeyId);

    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, K_KeyId));

    ret = true;
fail:
    _mongocrypt_buffer_cleanup(&S_Key);
    mc_FLE2IndexedEncryptedValueV2_destroy(iev);
    return ret;
}

static bool _collect_K_KeyID_from_FLE2IndexedEncryptedValue(void *ctx,
                                                            const _mongocrypt_buffer_t *in,
                                                            mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT(in->data);
    bool ret = false;
    _mongocrypt_buffer_t S_Key = {0};

    BSON_ASSERT((in->data[0] == MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue)
                || (in->data[0] == MC_SUBTYPE_FLE2IndexedRangeEncryptedValue));

    mc_FLE2IndexedEncryptedValue_t *iev = mc_FLE2IndexedEncryptedValue_new();
    CHECK_AND_RETURN(iev);
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValue_parse(iev, in, status));

    const _mongocrypt_buffer_t *S_KeyId = mc_FLE2IndexedEncryptedValue_get_S_KeyId(iev, status);
    CHECK_AND_RETURN(S_KeyId);

    _mongocrypt_key_broker_t *kb = ctx;
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_decrypted_key_by_id(kb, S_KeyId, &S_Key));

    /* Decrypt InnerEncrypted to get K_KeyId. */
    CHECK_AND_RETURN(mc_FLE2IndexedEncryptedValue_add_S_Key(kb->crypt->crypto, iev, &S_Key, status));

    /* Add request for K_KeyId. */
    const _mongocrypt_buffer_t *K_KeyId = mc_FLE2IndexedEncryptedValue_get_K_KeyId(iev, status);
    CHECK_AND_RETURN(K_KeyId);

    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, K_KeyId));

    ret = true;
fail:
    _mongocrypt_buffer_cleanup(&S_Key);
    mc_FLE2IndexedEncryptedValue_destroy(iev);
    return ret;
}

static bool _collect_K_KeyIDs(void *ctx, _mongocrypt_buffer_t *in, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT(in->data);

    switch (in->data[0]) {
    // FLE2v2
    case MC_SUBTYPE_FLE2IndexedEqualityEncryptedValueV2:
    case MC_SUBTYPE_FLE2IndexedRangeEncryptedValueV2:
        return _collect_K_KeyID_from_FLE2IndexedEncryptedValueV2(ctx, in, status);

    // FLE2v1
    case MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue:
    case MC_SUBTYPE_FLE2IndexedRangeEncryptedValue:
        return _collect_K_KeyID_from_FLE2IndexedEncryptedValue(ctx, in, status);

    default:
        // Ignore other types.
        return true;
    }
}

/* _check_for_K_KeyId must be called after requests for all S_KeyId are
 * satisfied. */
static bool _check_for_K_KeyId(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    if (ctx->kb.state != KB_DONE) {
        return true;
    }

    if (!_mongocrypt_key_broker_restart(&ctx->kb)) {
        _mongocrypt_key_broker_status(&ctx->kb, ctx->status);
        return _mongocrypt_ctx_fail(ctx);
    }

    bson_t as_bson;
    bson_iter_t iter = {0};
    _mongocrypt_ctx_decrypt_t *dctx = (_mongocrypt_ctx_decrypt_t *)ctx;
    if (!_mongocrypt_buffer_to_bson(&dctx->original_doc, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "error converting original_doc to bson");
    }
    bson_iter_init(&iter, &as_bson);

    if (!_mongocrypt_traverse_binary_in_bson(_collect_K_KeyIDs,
                                             &ctx->kb,
                                             TRAVERSE_MATCH_CIPHERTEXT,
                                             &iter,
                                             ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    if (!_mongocrypt_key_broker_requests_done(&ctx->kb)) {
        _mongocrypt_key_broker_status(&ctx->kb, ctx->status);
        return _mongocrypt_ctx_fail(ctx);
    }
    return true;
}

static bool _collect_key_uuid_from_FLE2UnindexedEncryptedValue(void *ctx,
                                                               const _mongocrypt_buffer_t *in,
                                                               mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    bool ret = false;

    mc_FLE2UnindexedEncryptedValue_t *uev = mc_FLE2UnindexedEncryptedValue_new();
    CHECK_AND_RETURN(uev);
    CHECK_AND_RETURN(mc_FLE2UnindexedEncryptedValue_parse(uev, in, status));

    const _mongocrypt_buffer_t *key_uuid = mc_FLE2UnindexedEncryptedValue_get_key_uuid(uev, status);
    CHECK_AND_RETURN(key_uuid);
    _mongocrypt_key_broker_t *kb = ctx;
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, key_uuid));

    ret = true;
fail:
    mc_FLE2UnindexedEncryptedValue_destroy(uev);
    return ret;
}

static bool _collect_key_uuid_from_FLE2UnindexedEncryptedValueV2(void *ctx,
                                                                 const _mongocrypt_buffer_t *in,
                                                                 mongocrypt_status_t *status) {
    bool ret = false;
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);

    mc_FLE2UnindexedEncryptedValueV2_t *uev = mc_FLE2UnindexedEncryptedValueV2_new();
    CHECK_AND_RETURN(uev);
    CHECK_AND_RETURN(mc_FLE2UnindexedEncryptedValueV2_parse(uev, in, status));

    const _mongocrypt_buffer_t *key_uuid = mc_FLE2UnindexedEncryptedValueV2_get_key_uuid(uev, status);
    CHECK_AND_RETURN(key_uuid);
    _mongocrypt_key_broker_t *kb = ctx;
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, key_uuid));

    ret = true;
fail:
    mc_FLE2UnindexedEncryptedValueV2_destroy(uev);
    return ret;
}

static bool
_collect_key_uuid_from_FLE2InsertUpdatePayload(void *ctx, const _mongocrypt_buffer_t *in, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    bool ret = false;

    mc_FLE2InsertUpdatePayload_t iup;
    mc_FLE2InsertUpdatePayload_init(&iup);

    CHECK_AND_RETURN(mc_FLE2InsertUpdatePayload_parse(&iup, in, status));
    _mongocrypt_key_broker_t *kb = ctx;
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, &iup.userKeyId));

    ret = true;
fail:
    mc_FLE2InsertUpdatePayload_cleanup(&iup);
    return ret;
}

static bool _collect_key_uuid_from_FLE2InsertUpdatePayloadV2(void *ctx,
                                                             const _mongocrypt_buffer_t *in,
                                                             mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    bool ret = false;

    mc_FLE2InsertUpdatePayloadV2_t iup;
    mc_FLE2InsertUpdatePayloadV2_init(&iup);

    CHECK_AND_RETURN(mc_FLE2InsertUpdatePayloadV2_parse(&iup, in, status));
    _mongocrypt_key_broker_t *kb = ctx;
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, &iup.userKeyId));

    ret = true;
fail:
    mc_FLE2InsertUpdatePayloadV2_cleanup(&iup);
    return ret;
}

static bool _collect_key_uuid_from_FLE1(void *ctx, _mongocrypt_buffer_t *in, mongocrypt_status_t *status) {
    _mongocrypt_ciphertext_t ciphertext;
    _mongocrypt_key_broker_t *kb = (_mongocrypt_key_broker_t *)ctx;

    CHECK_AND_RETURN(_mongocrypt_ciphertext_parse_unowned(in, &ciphertext, status));
    CHECK_AND_RETURN_KB_STATUS(_mongocrypt_key_broker_request_id(kb, &ciphertext.key_id));

    return true;
fail:
    return false;
}

static bool _collect_key_from_ciphertext(void *ctx, _mongocrypt_buffer_t *in, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT(in->data);

    switch (in->data[0]) {
    // FLE2v2
    case MC_SUBTYPE_FLE2IndexedEqualityEncryptedValueV2:
    case MC_SUBTYPE_FLE2IndexedRangeEncryptedValueV2:
        return _collect_S_KeyID_from_FLE2IndexedEncryptedValueV2(ctx, in, status);
    case MC_SUBTYPE_FLE2UnindexedEncryptedValueV2:
        return _collect_key_uuid_from_FLE2UnindexedEncryptedValueV2(ctx, in, status);
    case MC_SUBTYPE_FLE2InsertUpdatePayloadV2: return _collect_key_uuid_from_FLE2InsertUpdatePayloadV2(ctx, in, status);

    // FLE2v1
    case MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue:
    case MC_SUBTYPE_FLE2IndexedRangeEncryptedValue:
        return _collect_S_KeyID_from_FLE2IndexedEncryptedValue(ctx, in, status);
    case MC_SUBTYPE_FLE2UnindexedEncryptedValue:
        return _collect_key_uuid_from_FLE2UnindexedEncryptedValue(ctx, in, status);
    case MC_SUBTYPE_FLE2InsertUpdatePayload: return _collect_key_uuid_from_FLE2InsertUpdatePayload(ctx, in, status);

    // FLE1
    default: return _collect_key_uuid_from_FLE1(ctx, in, status);
    }
}

static void _cleanup(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_decrypt_t *dctx;

    if (!ctx) {
        return;
    }
    dctx = (_mongocrypt_ctx_decrypt_t *)ctx;
    _mongocrypt_buffer_cleanup(&dctx->original_doc);
    _mongocrypt_buffer_cleanup(&dctx->decrypted_doc);
}

bool mongocrypt_ctx_explicit_decrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg) {
    bson_iter_t iter;
    bson_t as_bson;

    if (!ctx) {
        return false;
    }

    if (!msg || !msg->data) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid msg");
    }

    if (ctx->crypt->log.trace_enabled) {
        char *msg_val;
        msg_val = _mongocrypt_new_json_string_from_binary(msg);
        _mongocrypt_log(&ctx->crypt->log, MONGOCRYPT_LOG_LEVEL_TRACE, "%s (%s=\"%s\")", BSON_FUNC, "msg", msg_val);

        bson_free(msg_val);
    }

    /* Expect msg to be the BSON a document of the form:
       { "v" : (BSON BINARY value of subtype 6) }
    */
    if (!_mongocrypt_binary_to_bson(msg, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson");
    }

    if (!bson_iter_init_find(&iter, &as_bson, "v")) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid msg, must contain 'v'");
    }

    if (!BSON_ITER_HOLDS_BINARY(&iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid msg, 'v' must contain a binary");
    }

    {
        bson_subtype_t subtype;
        const uint8_t *binary;
        uint32_t binary_len;
        mongocrypt_status_t *status = ctx->status;

        bson_iter_binary(&iter, &subtype, &binary_len, &binary);
        if (subtype != BSON_SUBTYPE_ENCRYPTED) {
            CLIENT_ERR("decryption expected BSON binary subtype %d, got %d", (int)BSON_SUBTYPE_ENCRYPTED, (int)subtype);
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    if (!mongocrypt_ctx_decrypt_init(ctx, msg)) {
        return false;
    }
    return true;
}

static bool _mongo_done_keys(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    (void)_mongocrypt_key_broker_docs_done(&ctx->kb);
    if (!_check_for_K_KeyId(ctx)) {
        return false;
    }
    return _mongocrypt_ctx_state_from_key_broker(ctx);
}

static bool _kms_done(mongocrypt_ctx_t *ctx) {
    _mongocrypt_opts_kms_providers_t *kms_providers;

    BSON_ASSERT_PARAM(ctx);

    kms_providers = _mongocrypt_ctx_kms_providers(ctx);

    if (!_mongocrypt_key_broker_kms_done(&ctx->kb, kms_providers)) {
        BSON_ASSERT(!_mongocrypt_key_broker_status(&ctx->kb, ctx->status));
        return _mongocrypt_ctx_fail(ctx);
    }
    if (!_check_for_K_KeyId(ctx)) {
        return false;
    }
    return _mongocrypt_ctx_state_from_key_broker(ctx);
}

bool mongocrypt_ctx_decrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *doc) {
    _mongocrypt_ctx_decrypt_t *dctx;
    bson_t as_bson;
    bson_iter_t iter = {0};
    _mongocrypt_ctx_opts_spec_t opts_spec;

    memset(&opts_spec, 0, sizeof(opts_spec));
    if (!ctx) {
        return false;
    }

    if (!_mongocrypt_ctx_init(ctx, &opts_spec)) {
        return false;
    }

    if (!doc || !doc->data) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid doc");
    }

    if (ctx->crypt->log.trace_enabled) {
        char *doc_val;
        doc_val = _mongocrypt_new_json_string_from_binary(doc);
        _mongocrypt_log(&ctx->crypt->log, MONGOCRYPT_LOG_LEVEL_TRACE, "%s (%s=\"%s\")", BSON_FUNC, "doc", doc_val);
        bson_free(doc_val);
    }
    dctx = (_mongocrypt_ctx_decrypt_t *)ctx;
    ctx->type = _MONGOCRYPT_TYPE_DECRYPT;
    ctx->vtable.finalize = _finalize;
    ctx->vtable.cleanup = _cleanup;
    ctx->vtable.mongo_done_keys = _mongo_done_keys;
    ctx->vtable.kms_done = _kms_done;

    _mongocrypt_buffer_copy_from_binary(&dctx->original_doc, doc);
    /* get keys. */
    if (!_mongocrypt_buffer_to_bson(&dctx->original_doc, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson");
    }

    bson_iter_init(&iter, &as_bson);
    if (!_mongocrypt_traverse_binary_in_bson(_collect_key_from_ciphertext,
                                             &ctx->kb,
                                             TRAVERSE_MATCH_CIPHERTEXT,
                                             &iter,
                                             ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    (void)_mongocrypt_key_broker_requests_done(&ctx->kb);

    if (!_check_for_K_KeyId(ctx)) {
        return false;
    }
    return _mongocrypt_ctx_state_from_key_broker(ctx);
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-ctx-encrypt.c0000644000175100001660000034114514760300420021236 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include "mc-efc-private.h"
#include "mc-fle2-rfds-private.h"
#include "mc-tokens-private.h"
#include "mongocrypt-ciphertext-private.h"
#include "mongocrypt-crypto-private.h"
#include "mongocrypt-ctx-private.h"
#include "mongocrypt-key-broker-private.h"
#include "mongocrypt-marking-private.h"
#include "mongocrypt-traverse-util-private.h"
#include "mongocrypt-util-private.h" // mc_iter_document_as_bson
#include "mongocrypt.h"

/* _fle2_append_encryptedFieldConfig copies encryptedFieldConfig and applies
 * default state collection names for escCollection, eccCollection, and
 * ecocCollection if required. */
static bool _fle2_append_encryptedFieldConfig(const mongocrypt_ctx_t *ctx,
                                              bson_t *dst,
                                              bson_t *encryptedFieldConfig,
                                              const char *target_coll,
                                              mongocrypt_status_t *status) {
    bson_iter_t iter;
    bool has_escCollection = false;
    bool has_eccCollection = false;
    bool has_ecocCollection = false;

    BSON_ASSERT_PARAM(dst);
    BSON_ASSERT_PARAM(encryptedFieldConfig);
    BSON_ASSERT_PARAM(target_coll);

    if (!bson_iter_init(&iter, encryptedFieldConfig)) {
        CLIENT_ERR("unable to iterate encryptedFieldConfig");
        return false;
    }

    while (bson_iter_next(&iter)) {
        if (strcmp(bson_iter_key(&iter), "escCollection") == 0) {
            has_escCollection = true;
        }
        if (strcmp(bson_iter_key(&iter), "eccCollection") == 0) {
            has_eccCollection = true;
        }
        if (strcmp(bson_iter_key(&iter), "ecocCollection") == 0) {
            has_ecocCollection = true;
        }
        if (!BSON_APPEND_VALUE(dst, bson_iter_key(&iter), bson_iter_value(&iter))) {
            CLIENT_ERR("unable to append field: %s", bson_iter_key(&iter));
            return false;
        }
    }

    if (!has_escCollection) {
        char *default_escCollection = bson_strdup_printf("enxcol_.%s.esc", target_coll);
        if (!BSON_APPEND_UTF8(dst, "escCollection", default_escCollection)) {
            CLIENT_ERR("unable to append escCollection");
            bson_free(default_escCollection);
            return false;
        }
        bson_free(default_escCollection);
    }
    if (!has_eccCollection && !ctx->crypt->opts.use_fle2_v2) {
        char *default_eccCollection = bson_strdup_printf("enxcol_.%s.ecc", target_coll);
        if (!BSON_APPEND_UTF8(dst, "eccCollection", default_eccCollection)) {
            CLIENT_ERR("unable to append eccCollection");
            bson_free(default_eccCollection);
            return false;
        }
        bson_free(default_eccCollection);
    }
    if (!has_ecocCollection) {
        char *default_ecocCollection = bson_strdup_printf("enxcol_.%s.ecoc", target_coll);
        if (!BSON_APPEND_UTF8(dst, "ecocCollection", default_ecocCollection)) {
            CLIENT_ERR("unable to append ecocCollection");
            bson_free(default_ecocCollection);
            return false;
        }
        bson_free(default_ecocCollection);
    }
    return true;
}

static bool _fle2_append_encryptionInformation(const mongocrypt_ctx_t *ctx,
                                               bson_t *dst,
                                               const char *target_ns,
                                               bson_t *encryptedFieldConfig,
                                               bson_t *deleteTokens,
                                               const char *target_coll,
                                               mongocrypt_status_t *status) {
    bson_t encryption_information_bson;
    bson_t schema_bson;
    bson_t encrypted_field_config_bson;

    BSON_ASSERT_PARAM(dst);
    BSON_ASSERT_PARAM(target_ns);
    BSON_ASSERT_PARAM(encryptedFieldConfig);
    /* deleteTokens may be NULL */
    BSON_ASSERT_PARAM(target_coll);

    if (!BSON_APPEND_DOCUMENT_BEGIN(dst, "encryptionInformation", &encryption_information_bson)) {
        CLIENT_ERR("unable to begin appending 'encryptionInformation'");
        return false;
    }
    if (!BSON_APPEND_INT32(&encryption_information_bson, "type", 1)) {
        CLIENT_ERR("unable to append type to 'encryptionInformation'");
        return false;
    }
    if (!BSON_APPEND_DOCUMENT_BEGIN(&encryption_information_bson, "schema", &schema_bson)) {
        CLIENT_ERR("unable to begin appending 'schema' to 'encryptionInformation'");
        return false;
    }

    if (!BSON_APPEND_DOCUMENT_BEGIN(&schema_bson, target_ns, &encrypted_field_config_bson)) {
        CLIENT_ERR("unable to begin appending 'encryptedFieldConfig' to "
                   "'encryptionInformation'.'schema'");
        return false;
    }

    if (!_fle2_append_encryptedFieldConfig(ctx,
                                           &encrypted_field_config_bson,
                                           encryptedFieldConfig,
                                           target_coll,
                                           status)) {
        return false;
    }

    if (!bson_append_document_end(&schema_bson, &encrypted_field_config_bson)) {
        CLIENT_ERR("unable to end appending 'encryptedFieldConfig' to "
                   "'encryptionInformation'.'schema'");
        return false;
    }
    if (!bson_append_document_end(&encryption_information_bson, &schema_bson)) {
        CLIENT_ERR("unable to end appending 'schema' to 'encryptionInformation'");
        return false;
    }

    if (deleteTokens != NULL) {
        bson_t delete_tokens_bson;
        if (!BSON_APPEND_DOCUMENT_BEGIN(&encryption_information_bson, "deleteTokens", &delete_tokens_bson)) {
            CLIENT_ERR("unable to begin appending 'deleteTokens' to "
                       "'encryptionInformation'");
            return false;
        }
        if (!BSON_APPEND_DOCUMENT(&delete_tokens_bson, target_ns, deleteTokens)) {
            CLIENT_ERR("unable to append '%s' to 'deleteTokens'", target_ns);
            return false;
        }
        if (!bson_append_document_end(&encryption_information_bson, &delete_tokens_bson)) {
            CLIENT_ERR("unable to end appending 'deleteTokens' to "
                       "'encryptionInformation'");
            return false;
        }
    }

    if (!bson_append_document_end(dst, &encryption_information_bson)) {
        CLIENT_ERR("unable to end appending 'encryptionInformation'");
        return false;
    }
    return true;
}

typedef enum { MC_TO_CSFLE, MC_TO_MONGOCRYPTD, MC_TO_MONGOD } mc_cmd_target_t;

/**
 * @brief Add "encryptionInformation" to a command.
 *
 * @param cmd_name The name of the command.
 * @param cmd The command being rewritten. It is an input and output.
 * @param target_ns The . namespace for the command.
 * @param encryptedFieldConfig The "encryptedFields" document for the
 * collection.
 * @param deleteTokens Delete tokens to append to "encryptionInformation". May
 * be NULL.
 * @param target_coll The collection name.
 * @param cmd_target The intended destination of the command. csfle,
 * mongocryptd, and mongod have different requirements for the location of
 * "encryptionInformation".
 * @param status Output status.
 * @return true On success
 * @return false Otherwise. Sets a failing status message in this case.
 */
static bool _fle2_insert_encryptionInformation(const mongocrypt_ctx_t *ctx,
                                               const char *cmd_name,
                                               bson_t *cmd /* in and out */,
                                               const char *target_ns,
                                               bson_t *encryptedFieldConfig,
                                               bson_t *deleteTokens,
                                               const char *target_coll,
                                               mc_cmd_target_t cmd_target,
                                               mongocrypt_status_t *status) {
    bson_t out = BSON_INITIALIZER;
    bson_t explain = BSON_INITIALIZER;
    bson_iter_t iter;
    bool ok = false;

    BSON_ASSERT_PARAM(cmd_name);
    BSON_ASSERT_PARAM(cmd);
    BSON_ASSERT_PARAM(target_ns);
    BSON_ASSERT_PARAM(encryptedFieldConfig);
    /* deleteTokens may be NULL */
    BSON_ASSERT_PARAM(target_coll);

    // For `bulkWrite`, append `encryptionInformation` inside the `nsInfo.0` document.
    if (0 == strcmp(cmd_name, "bulkWrite")) {
        // Get the single `nsInfo` document from the input command.
        bson_t nsInfo; // Non-owning.
        {
            bson_iter_t nsInfo_iter;
            if (!bson_iter_init(&nsInfo_iter, cmd)) {
                CLIENT_ERR("failed to iterate command");
                goto fail;
            }
            if (!bson_iter_find_descendant(&nsInfo_iter, "nsInfo.0", &nsInfo_iter)) {
                CLIENT_ERR("expected one namespace in `bulkWrite`, but found zero.");
                goto fail;
            }
            if (bson_has_field(cmd, "nsInfo.1")) {
                CLIENT_ERR(
                    "expected one namespace in `bulkWrite`, but found more than one. Only one namespace is supported.");
                goto fail;
            }
            if (!mc_iter_document_as_bson(&nsInfo_iter, &nsInfo, status)) {
                goto fail;
            }
            // Ensure `nsInfo` does not already have an `encryptionInformation` field.
            if (bson_has_field(&nsInfo, "encryptionInformation")) {
                CLIENT_ERR("unexpected `encryptionInformation` present in input `nsInfo`.");
                goto fail;
            }
        }

        // Copy input and append `encryptionInformation` to `nsInfo`.
        {
            // Append everything from input except `nsInfo`.
            bson_copy_to_excluding_noinit(cmd, &out, "nsInfo", NULL);
            // Append `nsInfo` array.
            bson_t nsInfo_array;
            if (!BSON_APPEND_ARRAY_BEGIN(&out, "nsInfo", &nsInfo_array)) {
                CLIENT_ERR("unable to begin appending 'nsInfo' array");
                goto fail;
            }
            bson_t nsInfo_array_0;
            if (!BSON_APPEND_DOCUMENT_BEGIN(&nsInfo_array, "0", &nsInfo_array_0)) {
                CLIENT_ERR("unable to append 'nsInfo.0' document");
                goto fail;
            }
            // Copy everything from input `nsInfo`.
            bson_concat(&nsInfo_array_0, &nsInfo);
            // And append `encryptionInformation`.
            if (!_fle2_append_encryptionInformation(ctx,
                                                    &nsInfo_array_0,
                                                    target_ns,
                                                    encryptedFieldConfig,
                                                    deleteTokens,
                                                    target_coll,
                                                    status)) {
                goto fail;
            }
            if (!bson_append_document_end(&nsInfo_array, &nsInfo_array_0)) {
                CLIENT_ERR("unable to end appending 'nsInfo' document in array");
            }
            if (!bson_append_array_end(&out, &nsInfo_array)) {
                CLIENT_ERR("unable to end appending 'nsInfo' array");
                goto fail;
            }
            // Overwrite `cmd`.
            bson_destroy(cmd);
            if (!bson_steal(cmd, &out)) {
                CLIENT_ERR("failed to steal BSON with encryptionInformation");
                goto fail;
            }
        }

        goto success;
    }

    if (0 != strcmp(cmd_name, "explain") || cmd_target == MC_TO_MONGOCRYPTD) {
        // All commands except "explain" and "bulkWrite" expect "encryptionInformation"
        // at top-level. "explain" sent to mongocryptd expects
        // "encryptionInformation" at top-level.
        if (!_fle2_append_encryptionInformation(ctx,
                                                cmd,
                                                target_ns,
                                                encryptedFieldConfig,
                                                deleteTokens,
                                                target_coll,
                                                status)) {
            goto fail;
        }
        bson_destroy(&out);
        goto success;
    }

    // The "explain" command for csfle is a special case.
    // mongocryptd expects "encryptionInformation" to be a sibling of the
    // "explain" document. Example:
    // {
    //    "explain": { "find": "to-mongocryptd" },
    //    "encryptionInformation": {}
    // }
    // csfle and mongod expect "encryptionInformation" to be nested in the
    // "explain" document. Example:
    // {
    //    "explain": {
    //       "find": "to-csfle-or-mongod"
    //       "encryptionInformation": {}
    //    }
    // }
    BSON_ASSERT(bson_iter_init_find(&iter, cmd, "explain"));
    if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
        CLIENT_ERR("expected 'explain' to be document");
        goto fail;
    }

    {
        bson_t tmp;
        if (!mc_iter_document_as_bson(&iter, &tmp, status)) {
            goto fail;
        }
        bson_destroy(&explain);
        bson_copy_to(&tmp, &explain);
    }

    if (!_fle2_append_encryptionInformation(ctx,
                                            &explain,
                                            target_ns,
                                            encryptedFieldConfig,
                                            deleteTokens,
                                            target_coll,
                                            status)) {
        goto fail;
    }

    if (!BSON_APPEND_DOCUMENT(&out, "explain", &explain)) {
        CLIENT_ERR("unable to append 'explain' document");
        goto fail;
    }

    bson_copy_to_excluding_noinit(cmd, &out, "explain", NULL);
    bson_destroy(cmd);
    if (!bson_steal(cmd, &out)) {
        CLIENT_ERR("failed to steal BSON with encryptionInformation");
        goto fail;
    }

success:
    ok = true;
fail:
    bson_destroy(&explain);
    if (!ok) {
        bson_destroy(&out);
    }
    return ok;
}

/* Construct the list collections command to send. */
static bool _mongo_op_collinfo(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    _mongocrypt_ctx_encrypt_t *ectx;
    bson_t *cmd;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    cmd = BCON_NEW("name", BCON_UTF8(ectx->target_coll));
    CRYPT_TRACEF(&ectx->parent.crypt->log, "constructed: %s\n", tmp_json(cmd));
    _mongocrypt_buffer_steal_from_bson(&ectx->list_collections_filter, cmd);
    out->data = ectx->list_collections_filter.data;
    out->len = ectx->list_collections_filter.len;
    return true;
}

static bool _set_schema_from_collinfo(mongocrypt_ctx_t *ctx, bson_t *collinfo) {
    bson_iter_t iter;
    _mongocrypt_ctx_encrypt_t *ectx;
    bool found_jsonschema = false;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(collinfo);

    /* Parse out the schema. */
    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    /* Disallow views. */
    if (bson_iter_init_find(&iter, collinfo, "type") && BSON_ITER_HOLDS_UTF8(&iter) && bson_iter_utf8(&iter, NULL)
        && 0 == strcmp("view", bson_iter_utf8(&iter, NULL))) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot auto encrypt a view");
    }

    if (!bson_iter_init(&iter, collinfo)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "BSON malformed");
    }

    if (bson_iter_find_descendant(&iter, "options.encryptedFields", &iter)) {
        if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "options.encryptedFields is not a BSON document");
        }
        if (!_mongocrypt_buffer_copy_from_document_iter(&ectx->encrypted_field_config, &iter)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "unable to copy options.encryptedFields");
        }
        bson_t efc_bson;
        if (!_mongocrypt_buffer_to_bson(&ectx->encrypted_field_config, &efc_bson)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "unable to create BSON from encrypted_field_config");
        }
        if (!mc_EncryptedFieldConfig_parse(&ectx->efc, &efc_bson, ctx->status, ctx->crypt->opts.use_range_v2)) {
            _mongocrypt_ctx_fail(ctx);
            return false;
        }
    } else if (0 == strcmp(ectx->cmd_name, "bulkWrite")) {
        ectx->used_empty_encryptedFields = true;
        // `bulkWrite` is a special case. Sending `bulkWrite` with `jsonSchema` to query analysis results in an error:
        // `The bulkWrite command only supports Queryable Encryption`
        //
        // Add an empty encryptedFields (rather than an empty JSON schema) to ensure `bulkWrite` can be sent to query
        // analysis.
        bson_t empty_encryptedFields = BSON_INITIALIZER;
        {
            char *escCollection = bson_strdup_printf("enxcol_.%s.esc", ectx->target_coll);
            char *ecocCollection = bson_strdup_printf("enxcol_.%s.ecoc", ectx->target_coll);
            bson_t empty_array = BSON_INITIALIZER;
            if (!BSON_APPEND_UTF8(&empty_encryptedFields, "escCollection", escCollection)) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "failed to append `escCollection`");
            }
            if (!BSON_APPEND_UTF8(&empty_encryptedFields, "ecocCollection", ecocCollection)) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "failed to append `ecocCollection`");
            }
            if (!BSON_APPEND_ARRAY(&empty_encryptedFields, "fields", &empty_array)) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "failed to append `fields`");
            }

            bson_destroy(&empty_array);
            bson_free(escCollection);
            bson_free(ecocCollection);
        }

        if (!mc_EncryptedFieldConfig_parse(&ectx->efc,
                                           &empty_encryptedFields,
                                           ctx->status,
                                           ctx->crypt->opts.use_range_v2)) {
            bson_destroy(&empty_encryptedFields);
            _mongocrypt_ctx_fail(ctx);
            return false;
        }
        _mongocrypt_buffer_steal_from_bson(&ectx->encrypted_field_config, &empty_encryptedFields);
    }

    BSON_ASSERT(bson_iter_init(&iter, collinfo));

    if (bson_iter_find_descendant(&iter, "options.validator", &iter) && BSON_ITER_HOLDS_DOCUMENT(&iter)) {
        if (!bson_iter_recurse(&iter, &iter)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "BSON malformed");
        }
        while (bson_iter_next(&iter)) {
            const char *key;

            key = bson_iter_key(&iter);
            BSON_ASSERT(key);
            if (0 == strcmp("$jsonSchema", key)) {
                if (found_jsonschema) {
                    return _mongocrypt_ctx_fail_w_msg(ctx, "duplicate $jsonSchema fields found");
                }
                if (!_mongocrypt_buffer_copy_from_document_iter(&ectx->schema, &iter)) {
                    return _mongocrypt_ctx_fail_w_msg(ctx, "malformed $jsonSchema");
                }
                found_jsonschema = true;
            } else {
                ectx->collinfo_has_siblings = true;
            }
        }
    }

    if (!found_jsonschema) {
        bson_t empty = BSON_INITIALIZER;

        _mongocrypt_buffer_steal_from_bson(&ectx->schema, &empty);
    }

    return true;
}

/* get_command_name returns the name of a command. The command name is the first
 * field. For example, the command name of: {"find": "foo", "filter": {"bar":
 * 1}} is "find". */
static const char *get_command_name(_mongocrypt_buffer_t *cmd, mongocrypt_status_t *status) {
    bson_t cmd_bson;
    bson_iter_t iter;
    const char *cmd_name;

    BSON_ASSERT_PARAM(cmd);

    if (!_mongocrypt_buffer_to_bson(cmd, &cmd_bson)) {
        CLIENT_ERR("unable to convert command buffer to BSON");
        return NULL;
    }

    if (!bson_iter_init(&iter, &cmd_bson)) {
        CLIENT_ERR("unable to iterate over command BSON");
        return NULL;
    }

    /* The command name is the first key. */
    if (!bson_iter_next(&iter)) {
        CLIENT_ERR("unexpected empty BSON for command");
        return NULL;
    }

    cmd_name = bson_iter_key(&iter);
    if (!cmd_name) {
        CLIENT_ERR("unable to get command name from BSON");
        return NULL;
    }
    return cmd_name;
}

static bool command_needs_deleteTokens(mongocrypt_ctx_t *ctx, const char *command_name) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(command_name);
    BSON_ASSERT(ctx->kb.crypt);

    if (ctx->crypt->opts.use_fle2_v2) {
        return false;
    }

    const char *cmds_needing_deleteTokens[] = {"delete", "update", "findAndModify"};

    BSON_ASSERT_PARAM(command_name);

    size_t i;
    for (i = 0; i < sizeof(cmds_needing_deleteTokens) / sizeof(cmds_needing_deleteTokens[0]); i++) {
        if (0 == strcmp(cmds_needing_deleteTokens[i], command_name)) {
            return true;
        }
    }

    return false;
}

/* context_uses_fle2 returns true if the context uses FLE 2 behavior.
 * If a collection has an encryptedFields document, it uses FLE 2.
 */
static bool context_uses_fle2(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    return !_mongocrypt_buffer_empty(&ectx->encrypted_field_config);
}

/* _fle2_collect_keys_for_deleteTokens requests keys required to produce
 * deleteTokens. deleteTokens is only applicable to FLE 2. */
static bool _fle2_collect_keys_for_deleteTokens(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    /* deleteTokens are only appended for FLE 2. */
    if (!context_uses_fle2(ctx)) {
        return true;
    }

    const char *cmd_name = ectx->cmd_name;

    if (!command_needs_deleteTokens(ctx, cmd_name)) {
        /* Command does not require deleteTokens. */
        return true;
    }

    mc_EncryptedField_t *field;

    for (field = ectx->efc.fields; field != NULL; field = field->next) {
        if (field->supported_queries) {
            if (!_mongocrypt_key_broker_request_id(&ctx->kb, &field->keyId)) {
                _mongocrypt_key_broker_status(&ctx->kb, ctx->status);
                _mongocrypt_ctx_fail(ctx);
                return false;
            }
        }
    }
    return true;
}

/* _fle2_collect_keys_for_compaction requests keys required to produce
 * compactionTokens or cleanupTokens.
 * compactionTokens and cleanupTokens are only applicable to FLE 2. */
static bool _fle2_collect_keys_for_compaction(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    /* compactionTokens are only appended for FLE 2. */
    if (!context_uses_fle2(ctx)) {
        return true;
    }

    const char *cmd_name = ectx->cmd_name;

    if (0 != strcmp(cmd_name, "compactStructuredEncryptionData")
        && 0 != strcmp(cmd_name, "cleanupStructuredEncryptionData")) {
        return true;
    }

    /* (compact/cleanup)StructuredEncryptionData must not be sent to mongocryptd. */
    ectx->bypass_query_analysis = true;

    mc_EncryptedField_t *field;

    for (field = ectx->efc.fields; field != NULL; field = field->next) {
        if (!_mongocrypt_key_broker_request_id(&ctx->kb, &field->keyId)) {
            _mongocrypt_key_broker_status(&ctx->kb, ctx->status);
            _mongocrypt_ctx_fail(ctx);
            return false;
        }
    }
    return true;
}

static bool _mongo_feed_collinfo(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in) {
    bson_t as_bson;

    _mongocrypt_ctx_encrypt_t *ectx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    if (!bson_init_static(&as_bson, in->data, in->len)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "BSON malformed");
    }

    /* Cache the received collinfo. */
    if (!_mongocrypt_cache_add_copy(&ctx->crypt->cache_collinfo, ectx->target_ns, &as_bson, ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    if (!_set_schema_from_collinfo(ctx, &as_bson)) {
        return false;
    }

    return true;
}

static bool _try_run_csfle_marking(mongocrypt_ctx_t *ctx);

static bool _mongo_done_collinfo(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx;

    BSON_ASSERT_PARAM(ctx);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    if (_mongocrypt_buffer_empty(&ectx->schema)) {
        bson_t empty_collinfo = BSON_INITIALIZER;

        /* If no collinfo was fed, apply and cache an empty collinfo. */
        if (!_set_schema_from_collinfo(ctx, &empty_collinfo)) {
            bson_destroy(&empty_collinfo);
            return false;
        }
        if (!_mongocrypt_cache_add_copy(&ctx->crypt->cache_collinfo, ectx->target_ns, &empty_collinfo, ctx->status)) {
            bson_destroy(&empty_collinfo);
            return _mongocrypt_ctx_fail(ctx);
        }
        bson_destroy(&empty_collinfo);
    }

    if (!_fle2_collect_keys_for_deleteTokens(ctx)) {
        return false;
    }

    if (!_fle2_collect_keys_for_compaction(ctx)) {
        return false;
    }

    if (ectx->bypass_query_analysis) {
        /* Keys may have been requested for deleteTokens or compactionTokens.
         * Finish key requests. */
        _mongocrypt_key_broker_requests_done(&ctx->kb);
        return _mongocrypt_ctx_state_from_key_broker(ctx);
    }
    ectx->parent.state = MONGOCRYPT_CTX_NEED_MONGO_MARKINGS;
    return _try_run_csfle_marking(ctx);
}

static const char *_mongo_db_collinfo(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx;

    BSON_ASSERT_PARAM(ctx);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    if (!ectx->target_db) {
        _mongocrypt_ctx_fail_w_msg(ctx, "Expected target database for `listCollections`, but none exists.");
        return NULL;
    }
    return ectx->target_db;
}

static bool _fle2_mongo_op_markings(mongocrypt_ctx_t *ctx, bson_t *out) {
    _mongocrypt_ctx_encrypt_t *ectx;
    bson_t cmd_bson = BSON_INITIALIZER, encrypted_field_config_bson = BSON_INITIALIZER;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT(ctx->state == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS);
    BSON_ASSERT(context_uses_fle2(ctx));

    if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &cmd_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "unable to convert original_cmd to BSON");
    }

    if (!_mongocrypt_buffer_to_bson(&ectx->encrypted_field_config, &encrypted_field_config_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "unable to convert encrypted_field_config to BSON");
    }

    const char *cmd_name = ectx->cmd_name;

    // If input command included $db, do not include it in the command to
    // mongocryptd. Drivers are expected to append $db in the RunCommand helper
    // used to send the command.
    bson_init(out);
    bson_copy_to_excluding_noinit(&cmd_bson, out, "$db", NULL);
    if (!_fle2_insert_encryptionInformation(ctx,
                                            cmd_name,
                                            out,
                                            ectx->target_ns,
                                            &encrypted_field_config_bson,
                                            NULL /* deleteTokens */,
                                            ectx->target_coll,
                                            ctx->crypt->csfle.okay ? MC_TO_CSFLE : MC_TO_MONGOCRYPTD,
                                            ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }
    return true;
}

/**
 * @brief Create the server-side command that contains information for
 * generating encryption markings via query analysis.
 *
 * @param ctx The encryption context.
 * @param out The destination of the generated BSON document
 * @return true On success
 * @return false Otherwise. Sets a failing status message in this case.
 */
static bool _create_markings_cmd_bson(mongocrypt_ctx_t *ctx, bson_t *out) {
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    if (context_uses_fle2(ctx)) {
        // Defer to FLE2 to generate the markings command
        return _fle2_mongo_op_markings(ctx, out);
    }

    // For FLE1:
    // Get the original command document
    bson_t bson_view = BSON_INITIALIZER;
    if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &bson_view)) {
        _mongocrypt_ctx_fail_w_msg(ctx, "invalid BSON cmd");
        return false;
    }

    // Copy the command to the output
    // If input command included $db, do not include it in the command to
    // mongocryptd. Drivers are expected to append $db in the RunCommand helper
    // used to send the command.
    bson_init(out);
    bson_copy_to_excluding_noinit(&bson_view, out, "$db", NULL);

    if (!_mongocrypt_buffer_empty(&ectx->schema)) {
        // We have a schema buffer. View it as BSON:
        if (!_mongocrypt_buffer_to_bson(&ectx->schema, &bson_view)) {
            _mongocrypt_ctx_fail_w_msg(ctx, "invalid BSON schema");
            return false;
        }
        // Append the jsonSchema to the output command
        BSON_APPEND_DOCUMENT(out, "jsonSchema", &bson_view);
    } else {
        bson_t empty = BSON_INITIALIZER;
        BSON_APPEND_DOCUMENT(out, "jsonSchema", &empty);
    }

    // if a local schema was not set, set isRemoteSchema=true
    BSON_APPEND_BOOL(out, "isRemoteSchema", !ectx->used_local_schema);
    return true;
}

static bool _mongo_op_markings(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    if (ectx->ismaster.needed) {
        if (_mongocrypt_buffer_empty(&ectx->ismaster.cmd)) {
            bson_t ismaster_cmd = BSON_INITIALIZER;
            // Store the generated command:
            BSON_APPEND_INT32(&ismaster_cmd, "isMaster", 1);
            _mongocrypt_buffer_steal_from_bson(&ectx->ismaster.cmd, &ismaster_cmd);
        }

        out->data = ectx->ismaster.cmd.data;
        out->len = ectx->ismaster.cmd.len;
        return true;
    }

    if (_mongocrypt_buffer_empty(&ectx->mongocryptd_cmd)) {
        // We need to generate the command document
        bson_t cmd_bson = BSON_INITIALIZER;
        if (!_create_markings_cmd_bson(ctx, &cmd_bson)) {
            // Failed
            bson_destroy(&cmd_bson);
            return false;
        }
        // Store the generated command:
        _mongocrypt_buffer_steal_from_bson(&ectx->mongocryptd_cmd, &cmd_bson);
    }

    // If we reach here, we have a valid mongocrypt_cmd
    out->data = ectx->mongocryptd_cmd.data;
    out->len = ectx->mongocryptd_cmd.len;
    return true;
}

static bool _collect_key_from_marking(void *ctx, _mongocrypt_buffer_t *in, mongocrypt_status_t *status) {
    _mongocrypt_marking_t marking;
    _mongocrypt_key_broker_t *kb;
    bool res;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);

    kb = (_mongocrypt_key_broker_t *)ctx;

    if (!_mongocrypt_marking_parse_unowned(in, &marking, status)) {
        _mongocrypt_marking_cleanup(&marking);
        return false;
    }

    if (marking.type == MONGOCRYPT_MARKING_FLE1_BY_ID) {
        res = _mongocrypt_key_broker_request_id(kb, &marking.key_id);
    } else if (marking.type == MONGOCRYPT_MARKING_FLE1_BY_ALTNAME) {
        res = _mongocrypt_key_broker_request_name(kb, &marking.key_alt_name);
    } else {
        BSON_ASSERT(marking.type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
        res = _mongocrypt_key_broker_request_id(kb, &marking.fle2.index_key_id)
           && _mongocrypt_key_broker_request_id(kb, &marking.fle2.user_key_id);
    }

    if (!res) {
        _mongocrypt_key_broker_status(kb, status);
        _mongocrypt_marking_cleanup(&marking);
        return false;
    }

    _mongocrypt_marking_cleanup(&marking);

    return true;
}

static bool _mongo_feed_markings(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in) {
    /* Find keys. */
    bson_t as_bson;
    bson_iter_t iter = {0};
    _mongocrypt_ctx_encrypt_t *ectx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    if (!_mongocrypt_binary_to_bson(in, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed BSON");
    }

    if (ectx->ismaster.needed) {
        /* This is a response to the 'isMaster' command. */
        if (!bson_iter_init_find(&iter, &as_bson, "maxWireVersion")) {
            return _mongocrypt_ctx_fail_w_msg(ctx,
                                              "expected to find 'maxWireVersion' in isMaster response, but did "
                                              "not.");
        }
        if (!BSON_ITER_HOLDS_INT32(&iter)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "expected 'maxWireVersion' to be int32.");
        }
        ectx->ismaster.maxwireversion = bson_iter_int32(&iter);
        return true;
    }

    if (bson_iter_init_find(&iter, &as_bson, "schemaRequiresEncryption") && !bson_iter_as_bool(&iter)) {
        /* TODO: update cache: this schema does not require encryption. */

        /* If using a local schema, warn if there are no encrypted fields. */
        if (ectx->used_local_schema) {
            _mongocrypt_log(&ctx->crypt->log,
                            MONGOCRYPT_LOG_LEVEL_WARNING,
                            "local schema used but does not have encryption specifiers");
        }
        return true;
    } else {
        /* if the schema requires encryption, but has sibling validators, error.
         */
        if (ectx->collinfo_has_siblings) {
            return _mongocrypt_ctx_fail_w_msg(ctx,
                                              "schema requires encryption, "
                                              "but collection JSON schema "
                                              "validator has siblings");
        }
    }

    if (bson_iter_init_find(&iter, &as_bson, "hasEncryptedPlaceholders") && !bson_iter_as_bool(&iter)) {
        return true;
    }

    if (!bson_iter_init_find(&iter, &as_bson, "result")) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed marking, no 'result'");
    }

    if (!_mongocrypt_buffer_copy_from_document_iter(&ectx->marked_cmd, &iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed marking, 'result' must be a document");
    }

    if (!bson_iter_recurse(&iter, &iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed marking, could not recurse into 'result'");
    }
    if (!_mongocrypt_traverse_binary_in_bson(_collect_key_from_marking,
                                             (void *)&ctx->kb,
                                             TRAVERSE_MATCH_MARKING,
                                             &iter,
                                             ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    return true;
}

static bool mongocrypt_ctx_encrypt_ismaster_done(mongocrypt_ctx_t *ctx);

static bool _mongo_done_markings(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    if (ectx->ismaster.needed) {
        return mongocrypt_ctx_encrypt_ismaster_done(ctx);
    }
    (void)_mongocrypt_key_broker_requests_done(&ctx->kb);
    return _mongocrypt_ctx_state_from_key_broker(ctx);
}

/**
 * @brief Append $db to a command being passed to csfle.
 */
static bool _add_dollar_db(const char *cmd_name, bson_t *cmd, const char *cmd_db, mongocrypt_status_t *status) {
    bson_t out = BSON_INITIALIZER;
    bson_t explain = BSON_INITIALIZER;
    bson_iter_t iter;
    bool ok = false;

    BSON_ASSERT_PARAM(cmd_name);
    BSON_ASSERT_PARAM(cmd);
    BSON_ASSERT_PARAM(cmd_db);

    if (!bson_iter_init_find(&iter, cmd, "$db")) {
        if (!BSON_APPEND_UTF8(cmd, "$db", cmd_db)) {
            CLIENT_ERR("failed to append '$db'");
            goto fail;
        }
    }

    if (0 != strcmp(cmd_name, "explain")) {
        goto success;
    }

    // The "explain" command for csfle is a special case.
    // csfle expects "$db" to be nested in the "explain" document and match the
    // top-level "$db". Example:
    // {
    //    "explain": {
    //       "find": "to-csfle"
    //       "$db": "db"
    //    }
    //    "$db": "db"
    // }
    BSON_ASSERT(bson_iter_init_find(&iter, cmd, "explain"));
    if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
        CLIENT_ERR("expected 'explain' to be document");
        goto fail;
    }

    {
        bson_t tmp;
        if (!mc_iter_document_as_bson(&iter, &tmp, status)) {
            goto fail;
        }
        bson_copy_to(&tmp, &explain);
    }

    if (!BSON_APPEND_UTF8(&explain, "$db", cmd_db)) {
        CLIENT_ERR("failed to append '$db'");
        goto fail;
    }

    if (!BSON_APPEND_DOCUMENT(&out, "explain", &explain)) {
        CLIENT_ERR("unable to append 'explain' document");
        goto fail;
    }

    bson_copy_to_excluding_noinit(cmd, &out, "explain", NULL);
    bson_destroy(cmd);
    if (!bson_steal(cmd, &out)) {
        CLIENT_ERR("failed to steal BSON without encryptionInformation");
        goto fail;
    }

success:
    ok = true;
fail:
    bson_destroy(&explain);
    if (!ok) {
        bson_destroy(&out);
    }
    return ok;
}

/**
 * @brief Attempt to generate csfle markings using a csfle dynamic library.
 *
 * @param ctx A context which has state NEED_MONGO_MARKINGS
 * @return true On success
 * @return false On error.
 *
 * This should be called only when we are ready for markings in the command
 * document. This function will only do anything if the csfle dynamic library
 * is loaded, otherwise it returns success immediately and leaves the state
 * as NEED_MONGO_MARKINGS.
 *
 * If csfle is loaded, this function will request the csfle library generate a
 * marked command document based on the caller's schema. If successful, the
 * state will be changed via @ref _mongo_done_markings().
 *
 * The purpose of this function is to short-circuit the phase of encryption
 * wherein we would normally return to the driver and give them the opportunity
 * to generate the markings by passing a special command to a mongocryptd daemon
 * process. Instead, we'll do it ourselves here, if possible.
 */
static bool _try_run_csfle_marking(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    BSON_ASSERT(ctx->state == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS
                && "_try_run_csfle_marking() should only be called when mongocrypt is "
                   "ready for markings");

    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT(ctx->crypt);

    // We have a valid schema and just need to mark the fields for encryption
    if (!ctx->crypt->csfle.okay) {
        // We don't have a csfle library to use to obtain the markings. It's up to
        // caller to resolve them.
        return true;
    }

    _mongo_crypt_v1_vtable csfle = ctx->crypt->csfle;
    mongo_crypt_v1_lib *csfle_lib = ctx->crypt->csfle_lib;
    BSON_ASSERT(csfle_lib);
    bool okay = false;

    // Obtain the command for markings
    bson_t cmd = BSON_INITIALIZER;
    if (!_create_markings_cmd_bson(ctx, &cmd)) {
        goto fail_create_cmd;
    }

    const char *cmd_name = ectx->cmd_name;

    if (!_add_dollar_db(cmd_name, &cmd, ectx->cmd_db, ctx->status)) {
        _mongocrypt_ctx_fail(ctx);
        goto fail_create_cmd;
    }

#define CHECK_CSFLE_ERROR(Func, FailLabel)                                                                             \
    if (1) {                                                                                                           \
        if (csfle.status_get_error(status)) {                                                                          \
            _mongocrypt_set_error(ctx->status,                                                                         \
                                  MONGOCRYPT_STATUS_ERROR_CRYPT_SHARED,                                                \
                                  MONGOCRYPT_GENERIC_ERROR_CODE,                                                       \
                                  "csfle " #Func " failed: %s [Error %d, code %d]",                                    \
                                  csfle.status_get_explanation(status),                                                \
                                  csfle.status_get_error(status),                                                      \
                                  csfle.status_get_code(status));                                                      \
            _mongocrypt_ctx_fail(ctx);                                                                                 \
            goto FailLabel;                                                                                            \
        }                                                                                                              \
    } else                                                                                                             \
        ((void)0)

    mongo_crypt_v1_status *status = csfle.status_create();
    BSON_ASSERT(status);

    mongo_crypt_v1_query_analyzer *qa = csfle.query_analyzer_create(csfle_lib, status);
    CHECK_CSFLE_ERROR("query_analyzer_create", fail_qa_create);

    uint32_t marked_bson_len = 0;
    uint8_t *marked_bson = csfle.analyze_query(qa,
                                               bson_get_data(&cmd),
                                               ectx->target_ns,
                                               (uint32_t)strlen(ectx->target_ns),
                                               &marked_bson_len,
                                               status);
    CHECK_CSFLE_ERROR("analyze_query", fail_analyze_query);

    // Copy out the marked document.
    mongocrypt_binary_t *marked = mongocrypt_binary_new_from_data(marked_bson, marked_bson_len);
    if (!_mongo_feed_markings(ctx, marked)) {
        // Wrap error with additional information.
        _mongocrypt_set_error(ctx->status,
                              MONGOCRYPT_STATUS_ERROR_CLIENT,
                              MONGOCRYPT_GENERIC_ERROR_CODE,
                              "Consuming the generated csfle markings failed: %s",
                              mongocrypt_status_message(ctx->status, NULL /* len */));
        goto fail_feed_markings;
    }

    okay = _mongo_done_markings(ctx);
    if (!okay) {
        // Wrap error with additional information.
        _mongocrypt_set_error(ctx->status,
                              MONGOCRYPT_STATUS_ERROR_CLIENT,
                              MONGOCRYPT_GENERIC_ERROR_CODE,
                              "Finalizing the generated csfle markings failed: %s",
                              mongocrypt_status_message(ctx->status, NULL /* len */));
    }

fail_feed_markings:
    mongocrypt_binary_destroy(marked);
    csfle.bson_free(marked_bson);
fail_analyze_query:
    csfle.query_analyzer_destroy(qa);
fail_qa_create:
    csfle.status_destroy(status);
fail_create_cmd:
    bson_destroy(&cmd);
    return okay;
}

static bool _mongocrypt_fle2_insert_update_find(mc_fle_blob_subtype_t subtype) {
    return (subtype == MC_SUBTYPE_FLE2InsertUpdatePayload) || (subtype == MC_SUBTYPE_FLE2InsertUpdatePayloadV2)
        || (subtype == MC_SUBTYPE_FLE2FindEqualityPayload) || (subtype == MC_SUBTYPE_FLE2FindEqualityPayloadV2)
        || (subtype == MC_SUBTYPE_FLE2FindRangePayload) || (subtype == MC_SUBTYPE_FLE2FindRangePayloadV2);
}

static bool
_marking_to_bson_value(void *ctx, _mongocrypt_marking_t *marking, bson_value_t *out, mongocrypt_status_t *status) {
    _mongocrypt_ciphertext_t ciphertext;
    _mongocrypt_buffer_t serialized_ciphertext = {0};
    bool ret = false;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(out);

    _mongocrypt_ciphertext_init(&ciphertext);

    if (!_mongocrypt_marking_to_ciphertext(ctx, marking, &ciphertext, status)) {
        goto fail;
    }

    if (_mongocrypt_fle2_insert_update_find(ciphertext.blob_subtype)) {
        /* ciphertext_data is already a BSON object, just need to prepend
         * blob_subtype */
        if (ciphertext.data.len > UINT32_MAX - 1u) {
            CLIENT_ERR("ciphertext too long");
            goto fail;
        }
        _mongocrypt_buffer_init_size(&serialized_ciphertext, ciphertext.data.len + 1);
        /* ciphertext->blob_subtype is an enum and easily fits in uint8_t */
        serialized_ciphertext.data[0] = (uint8_t)ciphertext.blob_subtype;
        memcpy(serialized_ciphertext.data + 1, ciphertext.data.data, ciphertext.data.len);

    } else if (!_mongocrypt_serialize_ciphertext(&ciphertext, &serialized_ciphertext)) {
        CLIENT_ERR("malformed ciphertext");
        goto fail;
    };

    /* ownership of serialized_ciphertext is transferred to caller. */
    out->value_type = BSON_TYPE_BINARY;
    out->value.v_binary.data = serialized_ciphertext.data;
    out->value.v_binary.data_len = serialized_ciphertext.len;
    out->value.v_binary.subtype = (bson_subtype_t)BSON_SUBTYPE_ENCRYPTED;

    ret = true;

fail:
    _mongocrypt_ciphertext_cleanup(&ciphertext);
    return ret;
}

static bool
_replace_marking_with_ciphertext(void *ctx, _mongocrypt_buffer_t *in, bson_value_t *out, mongocrypt_status_t *status) {
    _mongocrypt_marking_t marking = {0};
    bool ret;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);

    if (!_mongocrypt_marking_parse_unowned(in, &marking, status)) {
        _mongocrypt_marking_cleanup(&marking);
        return false;
    }

    ret = _marking_to_bson_value(ctx, &marking, out, status);
    _mongocrypt_marking_cleanup(&marking);
    return ret;
}

/* generate_delete_tokens generates the 'deleteTokens' document to be appended
 * to 'encryptionInformation'. */
static bson_t *generate_delete_tokens(_mongocrypt_crypto_t *crypto,
                                      _mongocrypt_key_broker_t *kb,
                                      mc_EncryptedFieldConfig_t *efc,
                                      mongocrypt_status_t *status) {
    bool ret = false;
    bson_t *out = bson_new();
    mc_EncryptedField_t *ef;

    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(efc);

    for (ef = efc->fields; ef != NULL; ef = ef->next) {
        _mongocrypt_buffer_t IndexKey = {0};
        _mongocrypt_buffer_t TokenKey = {0};
        mc_ServerDataEncryptionLevel1Token_t *sdel1t = NULL;
        mc_CollectionsLevel1Token_t *cl1t = NULL;
        mc_ECOCToken_t *ecoc = NULL;
        bool loop_ok = false;
        /* deleteTokens are only necessary for indexed fields. */
        if (!ef->supported_queries) {
            goto loop_continue;
        }

        if (!_mongocrypt_key_broker_decrypted_key_by_id(kb, &ef->keyId, &IndexKey)) {
            _mongocrypt_key_broker_status(kb, status);
            goto loop_fail;
        }

        /* Get the TokenKey from the last 32 bytes of IndexKey */
        if (IndexKey.len < MONGOCRYPT_TOKEN_KEY_LEN) {
            CLIENT_ERR("IndexKey too short");
            goto loop_fail;
        }
        if (!_mongocrypt_buffer_from_subrange(&TokenKey,
                                              &IndexKey,
                                              IndexKey.len - MONGOCRYPT_TOKEN_KEY_LEN,
                                              MONGOCRYPT_TOKEN_KEY_LEN)) {
            CLIENT_ERR("generate_delete_tokens unable to parse TokenKey from IndexKey");
            goto loop_fail;
        }

        sdel1t = mc_ServerDataEncryptionLevel1Token_new(crypto, &TokenKey, status);
        if (!sdel1t) {
            goto loop_fail;
        }

        cl1t = mc_CollectionsLevel1Token_new(crypto, &TokenKey, status);
        if (!cl1t) {
            goto loop_fail;
        }

        ecoc = mc_ECOCToken_new(crypto, cl1t, status);
        if (!ecoc) {
            goto loop_fail;
        }

        bson_t field_bson;
        if (!BSON_APPEND_DOCUMENT_BEGIN(out, ef->path, &field_bson)) {
            CLIENT_ERR("failed to begin document for 'deleteTokens.%s'", ef->path);
            goto loop_fail;
        }

        if (!BSON_APPEND_BINARY(&field_bson,
                                "e",
                                BSON_SUBTYPE_BINARY,
                                mc_ServerDataEncryptionLevel1Token_get(sdel1t)->data,
                                mc_ServerDataEncryptionLevel1Token_get(sdel1t)->len)) {
            CLIENT_ERR("failed to append ServerDataEncryptionLevel1Token for %s", ef->path);
            goto loop_fail;
        }

        if (!BSON_APPEND_BINARY(&field_bson,
                                "o",
                                BSON_SUBTYPE_BINARY,
                                mc_ECOCToken_get(ecoc)->data,
                                mc_ECOCToken_get(ecoc)->len)) {
            CLIENT_ERR("failed to append ECOCToken for %s", ef->path);
            goto loop_fail;
        }

        if (!bson_append_document_end(out, &field_bson)) {
            CLIENT_ERR("failed to end document for 'deleteTokens.%s'", ef->path);
            goto loop_fail;
        }

    loop_continue:
        loop_ok = true;
    loop_fail:
        _mongocrypt_buffer_cleanup(&IndexKey);
        _mongocrypt_buffer_cleanup(&TokenKey);
        mc_ServerDataEncryptionLevel1Token_destroy(sdel1t);
        mc_CollectionsLevel1Token_destroy(cl1t);
        mc_ECOCToken_destroy(ecoc);
        if (!loop_ok) {
            goto fail;
        }
    }

    ret = true;
fail:
    if (!ret) {
        bson_destroy(out);
        return NULL;
    }
    return out;
}

static bool
_check_for_payload_requiring_encryptionInformation(void *ctx, _mongocrypt_buffer_t *in, mongocrypt_status_t *status) {
    bool *out = (bool *)ctx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);

    if (in->len < 1) {
        CLIENT_ERR("unexpected empty FLE payload");
        return false;
    }

    mc_fle_blob_subtype_t subtype = (mc_fle_blob_subtype_t)in->data[0];
    if (_mongocrypt_fle2_insert_update_find(subtype)) {
        *out = true;
        return true;
    }

    return true;
}

typedef struct {
    bool must_omit;
    bool ok;
} moe_result;

// must_omit_encryptionInformation returns true if the command
// must omit the "encryptionInformation" field when sent to mongod / mongos.
static moe_result must_omit_encryptionInformation(const char *command_name,
                                                  const bson_t *command,
                                                  bool use_range_v2,
                                                  const mc_EncryptedFieldConfig_t *efc,
                                                  mongocrypt_status_t *status) {
    // eligible_commands may omit encryptionInformation if the command does not
    // contain payloads requiring encryption.
    const char *eligible_commands[] = {"find", "aggregate", "distinct", "count", "insert"};
    size_t i;
    bool found = false;

    // prohibited_commands prohibit encryptionInformation on mongod / mongos.
    const char *prohibited_commands[] = {"cleanupStructuredEncryptionData", "create", "collMod", "createIndexes"};

    BSON_ASSERT_PARAM(command_name);
    BSON_ASSERT_PARAM(command);
    BSON_ASSERT_PARAM(efc);

    if (0 == strcmp("compactStructuredEncryptionData", command_name)) {
        // `compactStructuredEncryptionData` is a special case:
        // - Server 7.0 prohibits `encryptionInformation`.
        // - Server 8.0 requires `encryptionInformation` if "range" fields are referenced. Otherwise ignores.
        // Only send `encryptionInformation` if "range" fields are present to support both server versions.
        bool uses_range_fields = false;
        if (use_range_v2) {
            for (const mc_EncryptedField_t *ef = efc->fields; ef != NULL; ef = ef->next) {
                if (ef->supported_queries & SUPPORTS_RANGE_QUERIES) {
                    uses_range_fields = true;
                    break;
                }
            }
        }
        return (moe_result){.ok = true, .must_omit = !uses_range_fields};
    }

    for (i = 0; i < sizeof(prohibited_commands) / sizeof(prohibited_commands[0]); i++) {
        if (0 == strcmp(prohibited_commands[i], command_name)) {
            return (moe_result){.ok = true, .must_omit = true};
        }
    }

    for (i = 0; i < sizeof(eligible_commands) / sizeof(eligible_commands[0]); i++) {
        if (0 == strcmp(eligible_commands[i], command_name)) {
            found = true;
            break;
        }
    }
    if (!found) {
        return (moe_result){.ok = true};
    }

    bool has_payload_requiring_encryptionInformation = false;
    bson_iter_t iter = {0};
    if (!bson_iter_init(&iter, command)) {
        CLIENT_ERR("unable to iterate command");
        return (moe_result){.ok = false};
    }
    if (!_mongocrypt_traverse_binary_in_bson(_check_for_payload_requiring_encryptionInformation,
                                             &has_payload_requiring_encryptionInformation,
                                             TRAVERSE_MATCH_SUBTYPE6,
                                             &iter,
                                             status)) {
        return (moe_result){.ok = false};
    }

    if (!has_payload_requiring_encryptionInformation) {
        return (moe_result){.ok = true, .must_omit = true};
    }
    return (moe_result){.ok = true, .must_omit = false};
}

/* _fle2_append_compactionTokens appends compactionTokens if command_name is
 * "compactStructuredEncryptionData" or cleanupTokens if command_name is
 * "cleanupStructuredEncryptionData"
 */
static bool _fle2_append_compactionTokens(mongocrypt_t *crypt,
                                          _mongocrypt_key_broker_t *kb,
                                          mc_EncryptedFieldConfig_t *efc,
                                          const char *command_name,
                                          bson_t *out,
                                          mongocrypt_status_t *status) {
    bson_t result_compactionTokens = BSON_INITIALIZER;
    bool ret = false;

    BSON_ASSERT_PARAM(crypt);
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(efc);
    BSON_ASSERT_PARAM(command_name);
    BSON_ASSERT_PARAM(out);
    _mongocrypt_crypto_t *crypto = crypt->crypto;

    bool cleanup = (0 == strcmp(command_name, "cleanupStructuredEncryptionData"));

    if (0 != strcmp(command_name, "compactStructuredEncryptionData") && !cleanup) {
        return true;
    }

    if (cleanup) {
        BSON_APPEND_DOCUMENT_BEGIN(out, "cleanupTokens", &result_compactionTokens);
    } else {
        BSON_APPEND_DOCUMENT_BEGIN(out, "compactionTokens", &result_compactionTokens);
    }

    mc_EncryptedField_t *ptr;
    for (ptr = efc->fields; ptr != NULL; ptr = ptr->next) {
        /* Append tokens. */
        _mongocrypt_buffer_t key = {0};
        _mongocrypt_buffer_t tokenkey = {0};
        mc_CollectionsLevel1Token_t *cl1t = NULL;
        mc_ECOCToken_t *ecoct = NULL;
        mc_ESCToken_t *esct = NULL;
        mc_AnchorPaddingTokenRoot_t *padt = NULL;
        bool ecoc_ok = false;

        if (!_mongocrypt_key_broker_decrypted_key_by_id(kb, &ptr->keyId, &key)) {
            _mongocrypt_key_broker_status(kb, status);
            goto ecoc_fail;
        }
        /* The last 32 bytes of the user key are the token key. */
        if (key.len < MONGOCRYPT_TOKEN_KEY_LEN) {
            CLIENT_ERR("key too short");
            goto ecoc_fail;
        }
        if (!_mongocrypt_buffer_from_subrange(&tokenkey,
                                              &key,
                                              key.len - MONGOCRYPT_TOKEN_KEY_LEN,
                                              MONGOCRYPT_TOKEN_KEY_LEN)) {
            CLIENT_ERR("unable to get TokenKey from Data Encryption Key");
            goto ecoc_fail;
        }
        cl1t = mc_CollectionsLevel1Token_new(crypto, &tokenkey, status);
        if (!cl1t) {
            goto ecoc_fail;
        }

        ecoct = mc_ECOCToken_new(crypto, cl1t, status);
        if (!ecoct) {
            goto ecoc_fail;
        }

        const _mongocrypt_buffer_t *ecoct_buf = mc_ECOCToken_get(ecoct);

        if (crypt->opts.use_range_v2 && (ptr->supported_queries & SUPPORTS_RANGE_QUERIES)) {
            // Append the document {ecoc: , anchorPaddingToken: }
            esct = mc_ESCToken_new(crypto, cl1t, status);
            if (!esct) {
                goto ecoc_fail;
            }
            padt = mc_AnchorPaddingTokenRoot_new(crypto, esct, status);
            if (!padt) {
                goto ecoc_fail;
            }
            const _mongocrypt_buffer_t *padt_buf = mc_AnchorPaddingTokenRoot_get(padt);
            bson_t tokenDoc;
            BSON_APPEND_DOCUMENT_BEGIN(&result_compactionTokens, ptr->path, &tokenDoc);
            BSON_APPEND_BINARY(&tokenDoc, "ecoc", BSON_SUBTYPE_BINARY, ecoct_buf->data, ecoct_buf->len);
            BSON_APPEND_BINARY(&tokenDoc, "anchorPaddingToken", BSON_SUBTYPE_BINARY, padt_buf->data, padt_buf->len);
            bson_append_document_end(&result_compactionTokens, &tokenDoc);
        } else {
            // Append just 
            BSON_APPEND_BINARY(&result_compactionTokens,
                               ptr->path,
                               BSON_SUBTYPE_BINARY,
                               ecoct_buf->data,
                               ecoct_buf->len);
        }

        ecoc_ok = true;
    ecoc_fail:
        mc_AnchorPaddingTokenRoot_destroy(padt);
        mc_ESCToken_destroy(esct);
        mc_ECOCToken_destroy(ecoct);
        mc_CollectionsLevel1Token_destroy(cl1t);
        _mongocrypt_buffer_cleanup(&key);
        if (!ecoc_ok) {
            goto fail;
        }
    }

    bson_append_document_end(out, &result_compactionTokens);

    ret = true;
fail:
    return ret;
}

/**
 * @brief Removes "encryptionInformation" from cmd.
 */
static bool
_fle2_strip_encryptionInformation(const char *cmd_name, bson_t *cmd /* in and out */, mongocrypt_status_t *status) {
    bson_t stripped = BSON_INITIALIZER;
    bool ok = false;

    BSON_ASSERT_PARAM(cmd_name);
    BSON_ASSERT_PARAM(cmd);

    if (0 != strcmp(cmd_name, "explain") && 0 != strcmp(cmd_name, "bulkWrite")) {
        bson_copy_to_excluding_noinit(cmd, &stripped, "encryptionInformation", NULL);
        goto success;
    }

    if (0 == strcmp(cmd_name, "bulkWrite")) {
        // Get the single `nsInfo` document from the input command.
        bson_t nsInfo; // Non-owning.
        {
            bson_iter_t nsInfo_iter;
            if (!bson_iter_init(&nsInfo_iter, cmd)) {
                CLIENT_ERR("failed to iterate command");
                goto fail;
            }
            if (!bson_iter_find_descendant(&nsInfo_iter, "nsInfo.0", &nsInfo_iter)) {
                CLIENT_ERR("expected one namespace in `bulkWrite`, but found zero.");
                goto fail;
            }
            if (bson_has_field(cmd, "nsInfo.1")) {
                CLIENT_ERR(
                    "expected one namespace in `bulkWrite`, but found more than one. Only one namespace is supported.");
                goto fail;
            }
            if (!mc_iter_document_as_bson(&nsInfo_iter, &nsInfo, status)) {
                goto fail;
            }
        }

        // Copy input and exclude `encryptionInformation` from `nsInfo`.
        {
            // Append everything from input except `nsInfo`.
            bson_copy_to_excluding_noinit(cmd, &stripped, "nsInfo", NULL);
            // Append `nsInfo` array.
            bson_t nsInfo_array;
            if (!BSON_APPEND_ARRAY_BEGIN(&stripped, "nsInfo", &nsInfo_array)) {
                CLIENT_ERR("unable to begin appending 'nsInfo' array");
                goto fail;
            }
            bson_t nsInfo_array_0;
            if (!BSON_APPEND_DOCUMENT_BEGIN(&nsInfo_array, "0", &nsInfo_array_0)) {
                CLIENT_ERR("unable to append 'nsInfo.0' document");
                goto fail;
            }
            // Copy everything from input `nsInfo` and exclude `encryptionInformation`.
            bson_copy_to_excluding_noinit(&nsInfo, &nsInfo_array_0, "encryptionInformation", NULL);
            if (!bson_append_document_end(&nsInfo_array, &nsInfo_array_0)) {
                CLIENT_ERR("unable to end appending 'nsInfo' document in array");
            }
            if (!bson_append_array_end(&stripped, &nsInfo_array)) {
                CLIENT_ERR("unable to end appending 'nsInfo' array");
                goto fail;
            }
        }

        goto success;
    }

    // The 'explain' command is a special case.
    // 'encryptionInformation' is returned from mongocryptd and csfle nested
    // inside 'explain'. Example:
    // {
    //    "explain": {
    //       "find": "coll"
    //       "encryptionInformation": {}
    //    }
    // }
    bson_iter_t iter;
    bson_t explain;

    BSON_ASSERT(bson_iter_init_find(&iter, cmd, "explain"));
    if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
        CLIENT_ERR("expected 'explain' to be document");
        goto fail;
    }

    {
        bson_t tmp;
        if (!mc_iter_document_as_bson(&iter, &tmp, status)) {
            goto fail;
        }
        bson_init(&explain);
        bson_copy_to_excluding_noinit(&tmp, &explain, "encryptionInformation", NULL);
    }

    if (!BSON_APPEND_DOCUMENT(&stripped, "explain", &explain)) {
        bson_destroy(&explain);
        CLIENT_ERR("unable to append 'explain'");
        goto fail;
    }
    bson_destroy(&explain);
    bson_copy_to_excluding_noinit(cmd, &stripped, "explain", NULL);

success:
    bson_destroy(cmd);
    if (!bson_steal(cmd, &stripped)) {
        CLIENT_ERR("failed to steal BSON without encryptionInformation");
        goto fail;
    }
    ok = true;
fail:
    if (!ok) {
        bson_destroy(&stripped);
    }
    return ok;
}

/* Process a call to mongocrypt_ctx_finalize when an encryptedFieldConfig is
 * associated with the command. */
static bool _fle2_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    bson_t converted;
    _mongocrypt_ctx_encrypt_t *ectx;
    bson_t encrypted_field_config_bson;
    bson_t original_cmd_bson;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT(context_uses_fle2(ctx));
    BSON_ASSERT(ctx->state == MONGOCRYPT_CTX_READY);

    if (ectx->explicit) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "explicit encryption is not yet supported. See MONGOCRYPT-409.");
    }

    if (!_mongocrypt_buffer_to_bson(&ectx->encrypted_field_config, &encrypted_field_config_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson in encrypted_field_config_bson");
    }

    if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &original_cmd_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson in original_cmd");
    }

    /* If marked_cmd buffer is empty, there are no markings to encrypt. */
    if (_mongocrypt_buffer_empty(&ectx->marked_cmd)) {
        /* Append 'encryptionInformation' to the original command. */
        bson_copy_to(&original_cmd_bson, &converted);
    } else {
        bson_t as_bson;
        bson_iter_t iter = {0};

        if (!_mongocrypt_buffer_to_bson(&ectx->marked_cmd, &as_bson)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson");
        }

        bson_iter_init(&iter, &as_bson);
        bson_init(&converted);
        if (!_mongocrypt_transform_binary_in_bson(_replace_marking_with_ciphertext,
                                                  &ctx->kb,
                                                  TRAVERSE_MATCH_MARKING,
                                                  &iter,
                                                  &converted,
                                                  ctx->status)) {
            bson_destroy(&converted);
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    const char *command_name = ectx->cmd_name;

    /* Remove the 'encryptionInformation' field. It is appended in the response
     * from mongocryptd or csfle. */
    if (!_fle2_strip_encryptionInformation(command_name, &converted, ctx->status)) {
        bson_destroy(&converted);
        return _mongocrypt_ctx_fail(ctx);
    }

    bson_t *deleteTokens = NULL;
    if (command_needs_deleteTokens(ctx, command_name)) {
        deleteTokens = generate_delete_tokens(ctx->crypt->crypto, &ctx->kb, &ectx->efc, ctx->status);
        if (!deleteTokens) {
            bson_destroy(&converted);
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    moe_result result = must_omit_encryptionInformation(command_name,
                                                        &converted,
                                                        ctx->crypt->opts.use_range_v2,
                                                        &ectx->efc,
                                                        ctx->status);
    if (!result.ok) {
        bson_destroy(&converted);
        bson_destroy(deleteTokens);
        return _mongocrypt_ctx_fail(ctx);
    }

    /* Append a new 'encryptionInformation'. */
    if (!result.must_omit && !ectx->used_empty_encryptedFields) {
        if (!_fle2_insert_encryptionInformation(ctx,
                                                command_name,
                                                &converted,
                                                ectx->target_ns,
                                                &encrypted_field_config_bson,
                                                deleteTokens,
                                                ectx->target_coll,
                                                MC_TO_MONGOD,
                                                ctx->status)) {
            bson_destroy(&converted);
            bson_destroy(deleteTokens);
            return _mongocrypt_ctx_fail(ctx);
        }
    }
    bson_destroy(deleteTokens);

    if (!_fle2_append_compactionTokens(ctx->crypt, &ctx->kb, &ectx->efc, command_name, &converted, ctx->status)) {
        bson_destroy(&converted);
        return _mongocrypt_ctx_fail(ctx);
    }

    // If input command has $db, ensure output command has $db.
    bson_iter_t iter;
    if (bson_iter_init_find(&iter, &original_cmd_bson, "$db")) {
        if (!bson_iter_init_find(&iter, &converted, "$db")) {
            BSON_APPEND_UTF8(&converted, "$db", ectx->cmd_db);
        }
    }

    _mongocrypt_buffer_steal_from_bson(&ectx->encrypted_cmd, &converted);
    _mongocrypt_buffer_to_binary(&ectx->encrypted_cmd, out);
    ctx->state = MONGOCRYPT_CTX_DONE;

    return true;
}

static bool FLE2RangeFindDriverSpec_to_ciphertexts(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    bool ok = false;
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    bson_t with_placholders = BSON_INITIALIZER;
    bson_t with_ciphertexts = BSON_INITIALIZER;

    if (!ctx->opts.rangeopts.set) {
        _mongocrypt_ctx_fail_w_msg(ctx, "Expected RangeOpts to be set for Range Find");
        goto fail;
    }
    if (!ctx->opts.contention_factor.set) {
        _mongocrypt_ctx_fail_w_msg(ctx, "Expected Contention Factor to be set for Range Find");
        goto fail;
    }

    bson_t in_bson;
    if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &in_bson)) {
        _mongocrypt_ctx_fail_w_msg(ctx, "unable to convert input to BSON");
        goto fail;
    }

    bson_t v_doc;
    // Parse 'v' document from input.
    {
        bson_iter_t v_iter;
        if (!bson_iter_init_find(&v_iter, &in_bson, "v")) {
            _mongocrypt_ctx_fail_w_msg(ctx, "invalid input BSON, must contain 'v'");
            goto fail;
        }
        if (!BSON_ITER_HOLDS_DOCUMENT(&v_iter)) {
            _mongocrypt_ctx_fail_w_msg(ctx, "invalid input BSON, expected 'v' to be document");
            goto fail;
        }
        if (!mc_iter_document_as_bson(&v_iter, &v_doc, ctx->status)) {
            _mongocrypt_ctx_fail(ctx);
            goto fail;
        }
    }

    // Parse FLE2RangeFindDriverSpec.
    {
        mc_FLE2RangeFindDriverSpec_t rfds;

        if (!mc_FLE2RangeFindDriverSpec_parse(&rfds, &v_doc, ctx->status)) {
            _mongocrypt_ctx_fail(ctx);
            goto fail;
        }

        // Convert FLE2RangeFindDriverSpec into a document with placeholders.
        if (!mc_FLE2RangeFindDriverSpec_to_placeholders(
                &rfds,
                &ctx->opts.rangeopts.value,
                ctx->opts.contention_factor.value,
                &ctx->opts.key_id,
                _mongocrypt_buffer_empty(&ctx->opts.index_key_id) ? &ctx->opts.key_id : &ctx->opts.index_key_id,
                mc_getNextPayloadId(),
                &with_placholders,
                ctx->status)) {
            _mongocrypt_ctx_fail(ctx);
            goto fail;
        }
    }

    // Convert document with placeholders into document with ciphertexts.
    {
        bson_iter_t iter;
        if (!bson_iter_init(&iter, &with_placholders)) {
            _mongocrypt_ctx_fail_w_msg(ctx, "unable to iterate into placeholder document");
            goto fail;
        }
        if (!_mongocrypt_transform_binary_in_bson(_replace_marking_with_ciphertext,
                                                  &ctx->kb,
                                                  TRAVERSE_MATCH_MARKING,
                                                  &iter,
                                                  &with_ciphertexts,
                                                  ctx->status)) {
            goto fail;
        }
    }

    // Wrap result in the document: { 'v':  }.
    {
        /* v_wrapped is the BSON document { 'v':  }. */
        bson_t v_wrapped = BSON_INITIALIZER;
        if (!bson_append_document(&v_wrapped, MONGOCRYPT_STR_AND_LEN("v"), &with_ciphertexts)) {
            _mongocrypt_ctx_fail_w_msg(ctx, "unable to append document to 'v'");
            goto fail;
        }
        _mongocrypt_buffer_steal_from_bson(&ectx->encrypted_cmd, &v_wrapped);
        _mongocrypt_buffer_to_binary(&ectx->encrypted_cmd, out);
        ctx->state = MONGOCRYPT_CTX_DONE;
    }

    ok = true;
fail:
    bson_destroy(&with_ciphertexts);
    bson_destroy(&with_placholders);
    return ok;
}

static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    bool ret = false;
    _mongocrypt_marking_t marking;
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    BSON_ASSERT(ctx->opts.index_type.set);

    if (ctx->opts.rangeopts.set && ctx->opts.query_type.set) {
        // RangeOpts with query type is a special case. The result contains two
        // ciphertext values.
        return FLE2RangeFindDriverSpec_to_ciphertexts(ctx, out);
    }

    bson_t new_v = BSON_INITIALIZER;

    _mongocrypt_marking_init(&marking);
    marking.type = MONGOCRYPT_MARKING_FLE2_ENCRYPTION;
    if (ctx->opts.query_type.set) {
        switch (ctx->opts.query_type.value) {
        case MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED:
            if (ctx->crypt->opts.use_range_v2) {
                _mongocrypt_ctx_fail_w_msg(ctx, "Cannot use rangePreview query type with Range V2");
                goto fail;
            }
        // fallthrough
        case MONGOCRYPT_QUERY_TYPE_RANGE:
        case MONGOCRYPT_QUERY_TYPE_EQUALITY: marking.fle2.type = MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND; break;
        default: _mongocrypt_ctx_fail_w_msg(ctx, "Invalid value for EncryptOpts.queryType"); goto fail;
        }
    } else {
        marking.fle2.type = MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT;
    }

    switch (ctx->opts.index_type.value) {
    case MONGOCRYPT_INDEX_TYPE_EQUALITY: marking.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_EQUALITY; break;
    case MONGOCRYPT_INDEX_TYPE_NONE: marking.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_UNINDEXED; break;
    case MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED:
        if (ctx->crypt->opts.use_range_v2) {
            _mongocrypt_ctx_fail_w_msg(ctx, "Cannot use rangePreview index type with Range V2");
            goto fail;
        }
        // fallthrough
    case MONGOCRYPT_INDEX_TYPE_RANGE: marking.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_RANGE; break;
    default:
        // This might be unreachable because of other validation. Better safe than
        // sorry.
        _mongocrypt_ctx_fail_w_msg(ctx, "Invalid value for EncryptOpts.indexType");
        goto fail;
    }

    if (ctx->opts.rangeopts.set) {
        // Process the RangeOpts and the input 'v' document into a new 'v'.
        // The new 'v' document will be a FLE2RangeFindSpec or
        // FLE2RangeInsertSpec.
        bson_t old_v;

        if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &old_v)) {
            _mongocrypt_ctx_fail_w_msg(ctx, "unable to convert input to BSON");
            goto fail;
        }

        // RangeOpts with query_type is handled above.
        BSON_ASSERT(!ctx->opts.query_type.set);
        if (!mc_RangeOpts_to_FLE2RangeInsertSpec(&ctx->opts.rangeopts.value,
                                                 &old_v,
                                                 &new_v,
                                                 ctx->crypt->opts.use_range_v2,
                                                 ctx->status)) {
            _mongocrypt_ctx_fail(ctx);
            goto fail;
        }

        if (!bson_iter_init_find(&marking.v_iter, &new_v, "v")) {
            _mongocrypt_ctx_fail_w_msg(ctx, "invalid input BSON, must contain 'v'");
            goto fail;
        }

        marking.fle2.sparsity = ctx->opts.rangeopts.value.sparsity;

    } else {
        bson_t as_bson;

        /* Get iterator to input 'v' BSON value. */
        if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &as_bson)) {
            _mongocrypt_ctx_fail_w_msg(ctx, "unable to convert input to BSON");
            goto fail;
        }

        if (!bson_iter_init_find(&marking.v_iter, &as_bson, "v")) {
            _mongocrypt_ctx_fail_w_msg(ctx, "invalid input BSON, must contain 'v'");
            goto fail;
        }
    }

    _mongocrypt_buffer_copy_to(&ctx->opts.key_id, &marking.fle2.user_key_id);
    if (!_mongocrypt_buffer_empty(&ctx->opts.index_key_id)) {
        _mongocrypt_buffer_copy_to(&ctx->opts.index_key_id, &marking.fle2.index_key_id);
    } else {
        _mongocrypt_buffer_copy_to(&ctx->opts.key_id, &marking.fle2.index_key_id);
    }

    if (ctx->opts.contention_factor.set) {
        marking.fle2.maxContentionFactor = ctx->opts.contention_factor.value;
    } else if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_EQUALITY) {
        _mongocrypt_ctx_fail_w_msg(ctx, "contention factor required for indexed algorithm");
        goto fail;
    }

    /* Convert marking to ciphertext. */
    {
        bson_value_t v_out;
        /* v_wrapped is the BSON document { 'v':  }. */
        bson_t v_wrapped = BSON_INITIALIZER;

        if (!_marking_to_bson_value(&ctx->kb, &marking, &v_out, ctx->status)) {
            bson_destroy(&v_wrapped);
            _mongocrypt_ctx_fail(ctx);
            goto fail;
        }

        bson_append_value(&v_wrapped, MONGOCRYPT_STR_AND_LEN("v"), &v_out);
        _mongocrypt_buffer_steal_from_bson(&ectx->encrypted_cmd, &v_wrapped);
        _mongocrypt_buffer_to_binary(&ectx->encrypted_cmd, out);
        ctx->state = MONGOCRYPT_CTX_DONE;
        bson_value_destroy(&v_out);
    }

    ret = true;
fail:
    bson_destroy(&new_v);
    _mongocrypt_marking_cleanup(&marking);
    return ret;
}

static bool _finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    bson_t as_bson, converted;
    bson_iter_t iter = {0};
    _mongocrypt_ctx_encrypt_t *ectx;
    bool res;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    if (context_uses_fle2(ctx)) {
        return _fle2_finalize(ctx, out);
    } else if (ctx->opts.index_type.set) {
        return _fle2_finalize_explicit(ctx, out);
    }

    if (!ectx->explicit) {
        if (ctx->nothing_to_do) {
            _mongocrypt_buffer_to_binary(&ectx->original_cmd, out);
            ctx->state = MONGOCRYPT_CTX_DONE;
            return true;
        }
        if (!_mongocrypt_buffer_to_bson(&ectx->marked_cmd, &as_bson)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson");
        }

        bson_iter_init(&iter, &as_bson);
        bson_init(&converted);
        if (!_mongocrypt_transform_binary_in_bson(_replace_marking_with_ciphertext,
                                                  &ctx->kb,
                                                  TRAVERSE_MATCH_MARKING,
                                                  &iter,
                                                  &converted,
                                                  ctx->status)) {
            bson_destroy(&converted);
            return _mongocrypt_ctx_fail(ctx);
        }

        bson_t original_cmd_bson;
        if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &original_cmd_bson)) {
            bson_destroy(&converted);
            return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson in original_cmd");
        }

        // If input command has $db, ensure output command has $db.
        bson_iter_t iter;
        if (bson_iter_init_find(&iter, &original_cmd_bson, "$db")) {
            if (!bson_iter_init_find(&iter, &converted, "$db")) {
                BSON_APPEND_UTF8(&converted, "$db", ectx->cmd_db);
            }
        }
    } else {
        /* For explicit encryption, we have no marking, but we can fake one */
        _mongocrypt_marking_t marking;
        bson_value_t value;

        memset(&value, 0, sizeof(value));

        _mongocrypt_marking_init(&marking);

        if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &as_bson)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson");
        }

        if (!bson_iter_init_find(&iter, &as_bson, "v")) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "invalid msg, must contain 'v'");
        }

        memcpy(&marking.v_iter, &iter, sizeof(bson_iter_t));
        marking.algorithm = ctx->opts.algorithm;
        _mongocrypt_buffer_set_to(&ctx->opts.key_id, &marking.key_id);
        if (ctx->opts.key_alt_names) {
            bson_value_copy(&ctx->opts.key_alt_names->value, &marking.key_alt_name);
            marking.type = MONGOCRYPT_MARKING_FLE1_BY_ALTNAME;
        }

        bson_init(&converted);
        res = _marking_to_bson_value(&ctx->kb, &marking, &value, ctx->status);
        if (res) {
            bson_append_value(&converted, MONGOCRYPT_STR_AND_LEN("v"), &value);
        }

        bson_value_destroy(&value);
        _mongocrypt_marking_cleanup(&marking);

        if (!res) {
            bson_destroy(&converted);
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    _mongocrypt_buffer_steal_from_bson(&ectx->encrypted_cmd, &converted);
    _mongocrypt_buffer_to_binary(&ectx->encrypted_cmd, out);
    ctx->state = MONGOCRYPT_CTX_DONE;

    return true;
}

static void _cleanup(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx;

    if (!ctx) {
        return;
    }

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    bson_free(ectx->target_ns);
    bson_free(ectx->cmd_db);
    bson_free(ectx->target_db);
    bson_free(ectx->target_coll);
    _mongocrypt_buffer_cleanup(&ectx->list_collections_filter);
    _mongocrypt_buffer_cleanup(&ectx->schema);
    _mongocrypt_buffer_cleanup(&ectx->encrypted_field_config);
    _mongocrypt_buffer_cleanup(&ectx->original_cmd);
    _mongocrypt_buffer_cleanup(&ectx->mongocryptd_cmd);
    _mongocrypt_buffer_cleanup(&ectx->marked_cmd);
    _mongocrypt_buffer_cleanup(&ectx->encrypted_cmd);
    _mongocrypt_buffer_cleanup(&ectx->ismaster.cmd);
    mc_EncryptedFieldConfig_cleanup(&ectx->efc);
}

static bool _try_schema_from_schema_map(mongocrypt_ctx_t *ctx) {
    mongocrypt_t *crypt;
    _mongocrypt_ctx_encrypt_t *ectx;
    bson_t schema_map;
    bson_iter_t iter;

    BSON_ASSERT_PARAM(ctx);

    crypt = ctx->crypt;
    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    if (_mongocrypt_buffer_empty(&crypt->opts.schema_map)) {
        /* No schema map set. */
        return true;
    }

    if (!_mongocrypt_buffer_to_bson(&crypt->opts.schema_map, &schema_map)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "malformed schema map");
    }

    if (bson_iter_init_find(&iter, &schema_map, ectx->target_ns)) {
        if (!_mongocrypt_buffer_copy_from_document_iter(&ectx->schema, &iter)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "malformed schema map");
        }
        ectx->used_local_schema = true;
        ctx->state = MONGOCRYPT_CTX_NEED_MONGO_MARKINGS;
    }

    /* No schema found in map. */
    return true;
}

/* Check if the local encrypted field config map has an entry for this
 * collection.
 * If an encrypted field config is found, the context transitions to
 * MONGOCRYPT_CTX_NEED_MONGO_MARKINGS. */
static bool _fle2_try_encrypted_field_config_from_map(mongocrypt_ctx_t *ctx) {
    mongocrypt_t *crypt;
    _mongocrypt_ctx_encrypt_t *ectx;
    bson_t encrypted_field_config_map;
    bson_iter_t iter;

    BSON_ASSERT_PARAM(ctx);

    crypt = ctx->crypt;
    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    if (_mongocrypt_buffer_empty(&crypt->opts.encrypted_field_config_map)) {
        /* No encrypted_field_config_map set. */
        return true;
    }

    if (!_mongocrypt_buffer_to_bson(&crypt->opts.encrypted_field_config_map, &encrypted_field_config_map)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "unable to convert encrypted_field_config_map to BSON");
    }

    if (bson_iter_init_find(&iter, &encrypted_field_config_map, ectx->target_ns)) {
        if (!_mongocrypt_buffer_copy_from_document_iter(&ectx->encrypted_field_config, &iter)) {
            return _mongocrypt_ctx_fail_w_msg(ctx,
                                              "unable to copy encrypted_field_config from "
                                              "encrypted_field_config_map");
        }
        bson_t efc_bson;
        if (!_mongocrypt_buffer_to_bson(&ectx->encrypted_field_config, &efc_bson)) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "unable to create BSON from encrypted_field_config");
        }
        if (!mc_EncryptedFieldConfig_parse(&ectx->efc, &efc_bson, ctx->status, ctx->crypt->opts.use_range_v2)) {
            _mongocrypt_ctx_fail(ctx);
            return false;
        }
        ctx->state = MONGOCRYPT_CTX_NEED_MONGO_MARKINGS;
    }

    /* No encrypted_field_config found in map. */
    return true;
}

static bool _try_schema_from_cache(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx;
    bson_t *collinfo = NULL;

    BSON_ASSERT_PARAM(ctx);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    /* Otherwise, we need a remote schema. Check if we have a response to
     * listCollections cached. */
    if (!_mongocrypt_cache_get(&ctx->crypt->cache_collinfo,
                               ectx->target_ns /* null terminated */,
                               (void **)&collinfo)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "failed to retrieve from cache");
    }

    if (collinfo) {
        if (!_set_schema_from_collinfo(ctx, collinfo)) {
            bson_destroy(collinfo);
            return _mongocrypt_ctx_fail(ctx);
        }
        ctx->state = MONGOCRYPT_CTX_NEED_MONGO_MARKINGS;
    } else {
        /* we need to get it. */
        ctx->state = MONGOCRYPT_CTX_NEED_MONGO_COLLINFO;
        if (ectx->target_db) {
            if (!ctx->crypt->opts.use_need_mongo_collinfo_with_db_state) {
                _mongocrypt_ctx_fail_w_msg(
                    ctx,
                    "Fetching remote collection information on separate databases is not supported. Try "
                    "upgrading driver, or specify a local schemaMap or encryptedFieldsMap.");
                return false;
            }
            // Target database may differ from command database. Request collection info from target database.
            ctx->state = MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB;
        }
    }

    bson_destroy(collinfo);
    return true;
}

/* _try_empty_schema_for_create uses an empty JSON schema for the create
 * command. This is to avoid an unnecessary 'listCollections' command for
 * create. */
static bool _try_empty_schema_for_create(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx;

    BSON_ASSERT_PARAM(ctx);

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    /* As a special case, use an empty schema for the 'create' command. */
    const char *cmd_name = ectx->cmd_name;

    if (0 != strcmp(cmd_name, "create")) {
        return true;
    }

    bson_t empty = BSON_INITIALIZER;
    _mongocrypt_buffer_steal_from_bson(&ectx->schema, &empty);
    ctx->state = MONGOCRYPT_CTX_NEED_MONGO_MARKINGS;
    return true;
}

/* _try_schema_from_create_or_collMod_cmd tries to find a JSON schema included
 * in a create or collMod command by checking for "validator.$jsonSchema".
 * Example:
 * {
 *     "create" : "coll",
 *     "validator" : {
 *         "$jsonSchema" : {
 *             "properties" : { "a" : { "bsonType" : "number" } }
 *          }
 *     }
 * }
 * If the "create" command does not include a JSON schema, an empty JSON schema
 * is returned. This is to avoid an unnecessary 'listCollections' command for
 * create.
 *
 * If the "collMod" command does not include a JSON schema, a schema is later
 * requested by entering the MONGOCRYPT_CTX_NEED_MONGO_COLLINFO state.
 * This is because a "collMod" command may have sensitive data in the
 * "validator" field.
 */
static bool _try_schema_from_create_or_collMod_cmd(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx;
    mongocrypt_status_t *status;

    BSON_ASSERT_PARAM(ctx);

    status = ctx->status;

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    const char *cmd_name = ectx->cmd_name;

    if (0 != strcmp(cmd_name, "create") && 0 != strcmp(cmd_name, "collMod")) {
        return true;
    }

    bson_t cmd_bson;
    bson_iter_t iter;

    if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &cmd_bson)) {
        CLIENT_ERR("unable to convert command buffer to BSON");
        _mongocrypt_ctx_fail(ctx);
        return false;
    }

    if (!bson_iter_init(&iter, &cmd_bson)) {
        CLIENT_ERR("unable to iterate over command BSON");
        _mongocrypt_ctx_fail(ctx);
        return false;
    }

    if (bson_iter_find_descendant(&iter, "validator.$jsonSchema", &iter)) {
        if (!_mongocrypt_buffer_copy_from_document_iter(&ectx->schema, &iter)) {
            CLIENT_ERR("failed to parse BSON document from create validator.$jsonSchema");
            _mongocrypt_ctx_fail(ctx);
            return false;
        }
        ctx->state = MONGOCRYPT_CTX_NEED_MONGO_MARKINGS;
        return true;
    }

    return true;
}

static bool
_permitted_for_encryption(bson_iter_t *iter, mongocrypt_encryption_algorithm_t algo, mongocrypt_status_t *status) {
    bson_type_t bson_type;
    const bson_value_t *bson_value;
    bool ret = false;

    BSON_ASSERT_PARAM(iter);

    bson_value = bson_iter_value(iter);
    if (!bson_value) {
        CLIENT_ERR("Unknown BSON type");
        goto fail;
    }
    bson_type = bson_value->value_type;
    switch (bson_type) {
    case BSON_TYPE_NULL:
    case BSON_TYPE_MINKEY:
    case BSON_TYPE_MAXKEY:
    case BSON_TYPE_UNDEFINED: CLIENT_ERR("BSON type invalid for encryption"); goto fail;
    case BSON_TYPE_BINARY:
        if (bson_value->value.v_binary.subtype == BSON_SUBTYPE_ENCRYPTED) {
            CLIENT_ERR("BSON binary subtype 6 is invalid for encryption");
            goto fail;
        }
        /* ok */
        break;
    case BSON_TYPE_DOUBLE:
    case BSON_TYPE_DOCUMENT:
    case BSON_TYPE_ARRAY:
    case BSON_TYPE_CODEWSCOPE:
    case BSON_TYPE_BOOL:
    case BSON_TYPE_DECIMAL128:
        if (algo == MONGOCRYPT_ENCRYPTION_ALGORITHM_DETERMINISTIC) {
            CLIENT_ERR("BSON type invalid for deterministic encryption");
            goto fail;
        }
        break;
    case BSON_TYPE_UTF8:
    case BSON_TYPE_OID:
    case BSON_TYPE_DATE_TIME:
    case BSON_TYPE_REGEX:
    case BSON_TYPE_DBPOINTER:
    case BSON_TYPE_CODE:
    case BSON_TYPE_SYMBOL:
    case BSON_TYPE_INT32:
    case BSON_TYPE_TIMESTAMP:
    case BSON_TYPE_INT64:
        /* ok */
        break;
    case BSON_TYPE_EOD:
    default: CLIENT_ERR("invalid BSON value type 00"); goto fail;
    }

    ret = true;
fail:
    return ret;
}

// explicit_encrypt_init is common code shared by
// mongocrypt_ctx_explicit_encrypt_init and
// mongocrypt_ctx_explicit_encrypt_expression_init.
static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg) {
    _mongocrypt_ctx_encrypt_t *ectx;
    bson_t as_bson;
    bson_iter_t iter;
    _mongocrypt_ctx_opts_spec_t opts_spec = {0};

    if (!ctx) {
        return false;
    }
    memset(&opts_spec, 0, sizeof(opts_spec));
    opts_spec.key_descriptor = OPT_REQUIRED;
    opts_spec.algorithm = OPT_OPTIONAL;
    opts_spec.rangeopts = OPT_OPTIONAL;

    if (!_mongocrypt_ctx_init(ctx, &opts_spec)) {
        return false;
    }

    /* Error if any mutually exclusive FLE 1 and FLE 2 options are set. */
    {
        /* key_alt_names is FLE 1 only. */
        if (ctx->opts.key_alt_names != NULL) {
            if (ctx->opts.index_type.set) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both key alt name and index type");
            }
            if (!_mongocrypt_buffer_empty(&ctx->opts.index_key_id)) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both key alt name and index key id");
            }
            if (ctx->opts.contention_factor.set) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both key alt name and contention factor");
            }
            if (ctx->opts.query_type.set) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both key alt name and query type");
            }
            if (ctx->opts.rangeopts.set) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both key alt name and range opts");
            }
        }
        /* algorithm is FLE 1 only. */
        if (ctx->opts.algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE) {
            if (!_mongocrypt_buffer_empty(&ctx->opts.index_key_id)) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both algorithm and index key id");
            }
            if (ctx->opts.contention_factor.set) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both algorithm and contention factor");
            }
            if (ctx->opts.query_type.set) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both algorithm and query type");
            }
            if (ctx->opts.rangeopts.set) {
                return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set both algorithm and range opts");
            }
        }
    }

    if (ctx->opts.algorithm == MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE && !ctx->opts.index_type.set) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "algorithm or index type required");
    }

    if (ctx->opts.contention_factor.set && ctx->opts.index_type.set
        && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_NONE) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set contention factor with no index type");
    }

    if (ctx->opts.query_type.set && ctx->opts.index_type.set
        && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_NONE) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set query type with no index type");
    }

    if (ctx->opts.rangeopts.set && ctx->opts.index_type.set) {
        if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_NONE) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set range opts with no index type");
        }

        if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_EQUALITY) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set range opts with equality index type");
        }
    }

    if (ctx->opts.contention_factor.set && !mc_validate_contention(ctx->opts.contention_factor.value, ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    if (ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_EQUALITY
        && !ctx->opts.contention_factor.set) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "contention factor is required for indexed algorithm");
    }

    if (ctx->opts.index_type.set
        && (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGE
            || ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED)) {
        if (!ctx->opts.contention_factor.set) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "contention factor is required for range indexed algorithm");
        }

        if (!ctx->opts.rangeopts.set) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "range opts are required for range indexed algorithm");
        }
    }

    if (ctx->opts.rangeopts.set && !mc_validate_sparsity(ctx->opts.rangeopts.value.sparsity, ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    // If query type is set, it must match the index type.
    if (ctx->opts.query_type.set && ctx->opts.index_type.set) {
        mongocrypt_status_t *const status = ctx->status;
        bool matches = false;

        switch (ctx->opts.query_type.value) {
        case MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED:
            // Don't allow deprecated query type if we are using new index type.
            matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED);
            break;
        case MONGOCRYPT_QUERY_TYPE_RANGE:
            // New query type is compatible with both new and old index types.
            matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED
                       || ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGE);
            break;
        case MONGOCRYPT_QUERY_TYPE_EQUALITY:
            matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_EQUALITY);
            break;
        default:
            CLIENT_ERR("unsupported value for query_type: %d", ctx->opts.query_type.value);
            return _mongocrypt_ctx_fail(ctx);
        }

        if (!matches) {
            CLIENT_ERR("query_type (%s) must match index_type (%s)",
                       _mongocrypt_query_type_to_string(ctx->opts.query_type.value),
                       _mongocrypt_index_type_to_string(ctx->opts.index_type.value));
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    ctx->type = _MONGOCRYPT_TYPE_ENCRYPT;
    ectx->explicit = true;
    ctx->vtable.finalize = _finalize;
    ctx->vtable.cleanup = _cleanup;

    if (!msg || !msg->data) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "msg required for explicit encryption");
    }

    if (ctx->opts.key_alt_names) {
        if (!_mongocrypt_key_broker_request_name(&ctx->kb, &ctx->opts.key_alt_names->value)) {
            return _mongocrypt_ctx_fail(ctx);
        }
    } else {
        if (!_mongocrypt_key_broker_request_id(&ctx->kb, &ctx->opts.key_id)) {
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    if (!_mongocrypt_buffer_empty(&ctx->opts.index_key_id)) {
        if (!_mongocrypt_key_broker_request_id(&ctx->kb, &ctx->opts.index_key_id)) {
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    _mongocrypt_buffer_init(&ectx->original_cmd);

    _mongocrypt_buffer_copy_from_binary(&ectx->original_cmd, msg);
    if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "msg must be bson");
    }

    if (ctx->crypt->log.trace_enabled) {
        char *cmd_val;
        cmd_val = _mongocrypt_new_json_string_from_binary(msg);
        _mongocrypt_log(&ctx->crypt->log, MONGOCRYPT_LOG_LEVEL_TRACE, "%s (%s=\"%s\")", BSON_FUNC, "msg", cmd_val);
        bson_free(cmd_val);
    }

    if (!bson_iter_init_find(&iter, &as_bson, "v")) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid msg, must contain 'v'");
    }

    if (!_permitted_for_encryption(&iter, ctx->opts.algorithm, ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    (void)_mongocrypt_key_broker_requests_done(&ctx->kb);
    return _mongocrypt_ctx_state_from_key_broker(ctx);
}

bool mongocrypt_ctx_explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg) {
    if (!explicit_encrypt_init(ctx, msg)) {
        return false;
    }
    if (ctx->opts.query_type.set
        && (ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGE
            || ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "Encrypt may not be used for range queries. Use EncryptExpression.");
    }
    return true;
}

bool mongocrypt_ctx_explicit_encrypt_expression_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg) {
    if (!explicit_encrypt_init(ctx, msg)) {
        return false;
    }
    if (!ctx->opts.query_type.set
        || !(ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGE
             || ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "EncryptExpression may only be used for range queries.");
    }
    return true;
}

static bool _check_cmd_for_auto_encrypt_bulkWrite(mongocrypt_binary_t *cmd,
                                                  char **target_db,
                                                  char **target_coll,
                                                  mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(cmd);
    BSON_ASSERT_PARAM(target_db);
    BSON_ASSERT_PARAM(target_coll);

    bson_t as_bson;
    bson_iter_t cmd_iter = {0};

    if (!_mongocrypt_binary_to_bson(cmd, &as_bson) || !bson_iter_init(&cmd_iter, &as_bson)) {
        CLIENT_ERR("invalid command BSON");
        return false;
    }

    bson_iter_t ns_iter = cmd_iter;
    if (!bson_iter_find_descendant(&ns_iter, "nsInfo.0.ns", &ns_iter)) {
        CLIENT_ERR("failed to find namespace in `bulkWrite` command");
        return false;
    }

    if (!BSON_ITER_HOLDS_UTF8(&ns_iter)) {
        CLIENT_ERR("expected namespace to be UTF8, got: %s", mc_bson_type_to_string(bson_iter_type(&ns_iter)));
        return false;
    }

    const char *target_ns = bson_iter_utf8(&ns_iter, NULL /* length */);
    // Parse `target_ns` into "."
    const char *dot = strstr(target_ns, ".");
    if (!dot) {
        CLIENT_ERR("expected namespace to contain dot, got: %s", target_ns);
        return false;
    }
    *target_coll = bson_strdup(dot + 1);
    // Get the database from the `ns` field (which may differ from `cmd_db`).
    ptrdiff_t db_len = dot - target_ns;
    if ((uint64_t)db_len > SIZE_MAX) {
        CLIENT_ERR("unexpected database length exceeds %zu", SIZE_MAX);
        return false;
    }
    *target_db = bson_strndup(target_ns, (size_t)db_len);

    // Ensure only one `nsInfo` element is present.
    // Query analysis (mongocryptd/crypt_shared) currently only supports one namespace.
    if (bson_has_field(&as_bson, "nsInfo.1")) {
        CLIENT_ERR("expected one namespace in `bulkWrite`, but found more than one. Only one namespace is supported.");
        return false;
    }

    return true;
}

static bool
_check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **target_coll, mongocrypt_status_t *status) {
    bson_t as_bson;
    bson_iter_t iter = {0}, target_coll_iter;
    const char *cmd_name;
    bool eligible = false;

    BSON_ASSERT_PARAM(cmd);
    BSON_ASSERT_PARAM(bypass);
    BSON_ASSERT_PARAM(target_coll);

    *bypass = false;

    if (!_mongocrypt_binary_to_bson(cmd, &as_bson) || !bson_iter_init(&iter, &as_bson)) {
        CLIENT_ERR("invalid BSON");
        return false;
    }

    /* The command name is the first key. */
    if (!bson_iter_next(&iter)) {
        CLIENT_ERR("invalid empty BSON");
        return false;
    }

    cmd_name = bson_iter_key(&iter);
    BSON_ASSERT(cmd_name);

    /* get the collection name (or NULL if database/client command). */
    if (0 == strcmp(cmd_name, "explain")) {
        if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
            CLIENT_ERR("explain value is not a document");
            return false;
        }
        if (!bson_iter_recurse(&iter, &target_coll_iter)) {
            CLIENT_ERR("malformed BSON for encrypt command");
            return false;
        }
        if (!bson_iter_next(&target_coll_iter)) {
            CLIENT_ERR("invalid empty BSON");
            return false;
        }
    } else {
        memcpy(&target_coll_iter, &iter, sizeof(iter));
    }

    if (BSON_ITER_HOLDS_UTF8(&target_coll_iter)) {
        *target_coll = bson_strdup(bson_iter_utf8(&target_coll_iter, NULL));
    } else {
        *target_coll = NULL;
    }

    /* check if command is eligible for auto encryption, bypassed, or ineligible.
     */
    if (0 == strcmp(cmd_name, "aggregate")) {
        /* collection level aggregate ok, database/client is not. */
        eligible = true;
    } else if (0 == strcmp(cmd_name, "count")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "distinct")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "delete")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "find")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "findAndModify")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "getMore")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "insert")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "update")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "authenticate")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "getnonce")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "logout")) {
        *bypass = true;
    } else if (0 == bson_strcasecmp(cmd_name, "isMaster")) {
        /* use case insensitive compare for ismaster, since some drivers send
         * "ismaster" and others send "isMaster" */
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "abortTransaction")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "commitTransaction")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "endSessions")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "startSession")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "create")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "createIndexes")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "drop")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "dropDatabase")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "dropIndexes")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "killCursors")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "listCollections")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "listDatabases")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "listIndexes")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "renameCollection")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "explain")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "ping")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "saslStart")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "saslContinue")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "killAllSessions")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "killSessions")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "killAllSessionsByPattern")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "refreshSessions")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "compactStructuredEncryptionData")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "cleanupStructuredEncryptionData")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "collMod")) {
        eligible = true;
    } else if (0 == strcmp(cmd_name, "hello")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "buildInfo")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "getCmdLineOpts")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "getLog")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "createSearchIndexes")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "listSearchIndexes")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "dropSearchIndex")) {
        *bypass = true;
    } else if (0 == strcmp(cmd_name, "updateSearchIndex")) {
        *bypass = true;
    }

    /* database/client commands are ineligible. */
    if (eligible) {
        if (!*target_coll) {
            CLIENT_ERR("non-collection command not supported for auto encryption: %s", cmd_name);
            return false;
        }
        if (0 == strlen(*target_coll)) {
            CLIENT_ERR("empty collection name on command: %s", cmd_name);
            return false;
        }
    }

    if (eligible || *bypass) {
        return true;
    }

    CLIENT_ERR("command not supported for auto encryption: %s", cmd_name);
    return false;
}

static bool needs_ismaster_check(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    bool using_mongocryptd = !ectx->bypass_query_analysis && !ctx->crypt->csfle.okay;
    // The "create" and "createIndexes" command require an isMaster check when
    // using mongocryptd. See MONGOCRYPT-429.
    return using_mongocryptd && (0 == strcmp(ectx->cmd_name, "create") || 0 == strcmp(ectx->cmd_name, "createIndexes"));
}

bool mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t *ctx, const char *db, int32_t db_len, mongocrypt_binary_t *cmd) {
    _mongocrypt_ctx_encrypt_t *ectx;
    _mongocrypt_ctx_opts_spec_t opts_spec;

    if (!ctx) {
        return false;
    }

    if (!db) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid db");
    }

    memset(&opts_spec, 0, sizeof(opts_spec));
    opts_spec.schema = OPT_OPTIONAL;
    if (!_mongocrypt_ctx_init(ctx, &opts_spec)) {
        return false;
    }

    ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
    ctx->type = _MONGOCRYPT_TYPE_ENCRYPT;
    ectx->explicit = false;
    ctx->vtable.mongo_op_collinfo = _mongo_op_collinfo;
    ctx->vtable.mongo_feed_collinfo = _mongo_feed_collinfo;
    ctx->vtable.mongo_done_collinfo = _mongo_done_collinfo;
    ctx->vtable.mongo_db_collinfo = _mongo_db_collinfo;
    ctx->vtable.mongo_op_collinfo = _mongo_op_collinfo;
    ctx->vtable.mongo_op_markings = _mongo_op_markings;
    ctx->vtable.mongo_feed_markings = _mongo_feed_markings;
    ctx->vtable.mongo_done_markings = _mongo_done_markings;
    ctx->vtable.finalize = _finalize;
    ctx->vtable.cleanup = _cleanup;
    ectx->bypass_query_analysis = ctx->crypt->opts.bypass_query_analysis;

    if (!cmd || !cmd->data) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid command");
    }

    _mongocrypt_buffer_copy_from_binary(&ectx->original_cmd, cmd);

    ectx->cmd_name = get_command_name(&ectx->original_cmd, ctx->status);
    if (!ectx->cmd_name) {
        return _mongocrypt_ctx_fail(ctx);
    }

    if (!_mongocrypt_validate_and_copy_string(db, db_len, &ectx->cmd_db) || 0 == strlen(ectx->cmd_db)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid db");
    }

    if (0 == strcmp(ectx->cmd_name, "bulkWrite")) {
        // Handle `bulkWrite` as a special case.
        // `bulkWrite` includes the target namespaces in an `nsInfo` field.
        // Only one target namespace is supported.
        if (!_check_cmd_for_auto_encrypt_bulkWrite(cmd, &ectx->target_db, &ectx->target_coll, ctx->status)) {
            return _mongocrypt_ctx_fail(ctx);
        }

        ectx->target_ns = bson_strdup_printf("%s.%s", ectx->target_db, ectx->target_coll);
    } else {
        bool bypass;
        if (!_check_cmd_for_auto_encrypt(cmd, &bypass, &ectx->target_coll, ctx->status)) {
            return _mongocrypt_ctx_fail(ctx);
        }

        if (bypass) {
            ctx->nothing_to_do = true;
            ctx->state = MONGOCRYPT_CTX_READY;
            return true;
        }

        /* if _check_cmd_for_auto_encrypt did not bypass or error, a collection name
         * must have been set. */
        if (!ectx->target_coll) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "unexpected error: did not bypass or error but no collection name");
        }
        ectx->target_ns = bson_strdup_printf("%s.%s", ectx->cmd_db, ectx->target_coll);
    }

    if (ctx->opts.kek.provider.aws.region || ctx->opts.kek.provider.aws.cmk) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "aws masterkey options must not be set");
    }

    if (!_mongocrypt_buffer_empty(&ctx->opts.key_id)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "key_id must not be set for auto encryption");
    }

    if (ctx->opts.algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "algorithm must not be set for auto encryption");
    }

    if (ctx->crypt->log.trace_enabled) {
        char *cmd_val;
        cmd_val = _mongocrypt_new_json_string_from_binary(cmd);
        _mongocrypt_log(&ctx->crypt->log,
                        MONGOCRYPT_LOG_LEVEL_TRACE,
                        "%s (%s=\"%s\", %s=%d, %s=\"%s\")",
                        BSON_FUNC,
                        "db",
                        ectx->cmd_db,
                        "db_len",
                        db_len,
                        "cmd",
                        cmd_val);
        bson_free(cmd_val);
    }

    /* The "create" and "createIndexes" command require sending an isMaster
     * request to mongocryptd. */
    if (needs_ismaster_check(ctx)) {
        /* We are using mongocryptd. We need to ensure that mongocryptd
         * maxWireVersion >= 17. */
        ectx->ismaster.needed = true;
        ctx->state = MONGOCRYPT_CTX_NEED_MONGO_MARKINGS;
        return true;
    }

    return mongocrypt_ctx_encrypt_ismaster_done(ctx);
}

#define WIRE_VERSION_SERVER_6 17

/* mongocrypt_ctx_encrypt_ismaster_done is called when:
 * 1. The max wire version of mongocryptd is known.
 * 2. The max wire version of mongocryptd is not required for the command.
 */
static bool mongocrypt_ctx_encrypt_ismaster_done(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    ectx->ismaster.needed = false;

    /* The "create" and "createIndexes" command require bypassing on mongocryptd
     * older than version 6.0. */
    if (needs_ismaster_check(ctx)) {
        if (ectx->ismaster.maxwireversion < WIRE_VERSION_SERVER_6) {
            /* Bypass. */
            ctx->nothing_to_do = true;
            ctx->state = MONGOCRYPT_CTX_READY;
            return true;
        }
    }

    /* Check if there is an encrypted field config in encrypted_field_config_map
     */
    if (!_fle2_try_encrypted_field_config_from_map(ctx)) {
        return false;
    }
    if (_mongocrypt_buffer_empty(&ectx->encrypted_field_config)) {
        if (!_try_schema_from_create_or_collMod_cmd(ctx)) {
            return false;
        }

        /* Check if we have a local schema from schema_map */
        if (_mongocrypt_buffer_empty(&ectx->schema)) {
            if (!_try_schema_from_schema_map(ctx)) {
                return false;
            }
        }

        /* If we didn't have a local schema, try the cache. */
        if (_mongocrypt_buffer_empty(&ectx->schema)) {
            if (!_try_schema_from_cache(ctx)) {
                return false;
            }
        }

        /* If we did not have a local or cached schema, check if this is a
         * "create" command. If it is a "create" command, do not run
         * "listCollections" to get a server-side schema. */
        if (_mongocrypt_buffer_empty(&ectx->schema) && !_try_empty_schema_for_create(ctx)) {
            return false;
        }

        /* Otherwise, we need the the driver to fetch the schema. */
        if (_mongocrypt_buffer_empty(&ectx->schema)) {
            ctx->state = MONGOCRYPT_CTX_NEED_MONGO_COLLINFO;
            if (ectx->target_db) {
                if (!ctx->crypt->opts.use_need_mongo_collinfo_with_db_state) {
                    _mongocrypt_ctx_fail_w_msg(
                        ctx,
                        "Fetching remote collection information on separate databases is not supported. Try "
                        "upgrading driver, or specify a local schemaMap or encryptedFieldsMap.");
                    return false;
                }
                // Target database may differ from command database. Request collection info from target database.
                ctx->state = MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB;
            }
        }
    }

    /* If an encrypted_field_config was set, check if keys are required for
     * delete tokens. */
    if (!_fle2_collect_keys_for_deleteTokens(ctx)) {
        return false;
    }

    if (!_fle2_collect_keys_for_compaction(ctx)) {
        return false;
    }

    if (ctx->state == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS) {
        if (ectx->bypass_query_analysis) {
            /* Keys may have been requested for deleteTokens or compactionTokens.
             * Finish key requests.
             */
            _mongocrypt_key_broker_requests_done(&ctx->kb);
            return _mongocrypt_ctx_state_from_key_broker(ctx);
        }
        // We're ready for markings. Try to generate them ourself.
        return _try_run_csfle_marking(ctx);
    } else {
        // Other state, return to caller.
        return true;
    }
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-ctx-private.h0000644000175100001660000003257114760300420021231 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_CTX_PRIVATE_H
#define MONGOCRYPT_CTX_PRIVATE_H

#include "mc-efc-private.h"
#include "mc-optional-private.h"
#include "mc-rangeopts-private.h"
#include "mongocrypt-buffer-private.h"
#include "mongocrypt-endpoint-private.h"
#include "mongocrypt-key-broker-private.h"
#include "mongocrypt-key-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt.h"

typedef enum {
    _MONGOCRYPT_TYPE_NONE,
    _MONGOCRYPT_TYPE_ENCRYPT,
    _MONGOCRYPT_TYPE_DECRYPT,
    _MONGOCRYPT_TYPE_CREATE_DATA_KEY,
    _MONGOCRYPT_TYPE_REWRAP_MANY_DATAKEY,
    _MONGOCRYPT_TYPE_COMPACT,
} _mongocrypt_ctx_type_t;

typedef enum {
    MONGOCRYPT_INDEX_TYPE_NONE = 1,
    MONGOCRYPT_INDEX_TYPE_EQUALITY = 2,
    MONGOCRYPT_INDEX_TYPE_RANGE = 3,
    MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED = 4
} mongocrypt_index_type_t;

const char *_mongocrypt_index_type_to_string(mongocrypt_index_type_t val);

typedef enum {
    MONGOCRYPT_QUERY_TYPE_EQUALITY = 1,
    MONGOCRYPT_QUERY_TYPE_RANGE = 2,
    MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED = 3
} mongocrypt_query_type_t;

const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val);

/* Option values are validated when set.
 * Different contexts accept/require different options,
 * validated when a context is initialized.
 */
typedef struct __mongocrypt_ctx_opts_t {
    _mongocrypt_buffer_t key_id;
    _mongocrypt_key_alt_name_t *key_alt_names;
    _mongocrypt_buffer_t key_material;
    mongocrypt_encryption_algorithm_t algorithm;
    _mongocrypt_kek_t kek;
    bool retry_enabled;

    struct {
        mongocrypt_index_type_t value;
        bool set;
    } index_type;

    _mongocrypt_buffer_t index_key_id;

    struct {
        int64_t value;
        bool set;
    } contention_factor;

    struct {
        mongocrypt_query_type_t value;
        bool set;
    } query_type;

    struct {
        mc_RangeOpts_t value;
        bool set;
    } rangeopts;
} _mongocrypt_ctx_opts_t;

// `_mongocrypt_ctx_opts_t` inherits extended alignment from libbson. To dynamically allocate, use
// aligned allocation (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_ctx_opts_t,
                    BSON_ALIGNOF(_mongocrypt_ctx_opts_t)
                        >= BSON_MAX(BSON_ALIGNOF(_mongocrypt_key_alt_name_t), BSON_ALIGNOF(mc_RangeOpts_t)));

/* All derived contexts may override these methods. */
typedef struct {
    const char *(*mongo_db_collinfo)(mongocrypt_ctx_t *ctx);
    bool (*mongo_op_collinfo)(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out);
    bool (*mongo_feed_collinfo)(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in);
    bool (*mongo_done_collinfo)(mongocrypt_ctx_t *ctx);
    bool (*mongo_op_markings)(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out);
    bool (*mongo_feed_markings)(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in);
    bool (*mongo_done_markings)(mongocrypt_ctx_t *ctx);
    bool (*mongo_op_keys)(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out);
    bool (*mongo_feed_keys)(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in);
    bool (*mongo_done_keys)(mongocrypt_ctx_t *ctx);
    bool (*after_kms_credentials_provided)(mongocrypt_ctx_t *ctx);
    mongocrypt_kms_ctx_t *(*next_kms_ctx)(mongocrypt_ctx_t *ctx);
    bool (*kms_done)(mongocrypt_ctx_t *ctx);
    bool (*finalize)(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out);
    void (*cleanup)(mongocrypt_ctx_t *ctx);
} _mongocrypt_vtable_t;

struct _mongocrypt_ctx_t {
    mongocrypt_t *crypt;
    mongocrypt_ctx_state_t state;
    _mongocrypt_ctx_type_t type;
    mongocrypt_status_t *status;
    _mongocrypt_key_broker_t kb;
    _mongocrypt_vtable_t vtable;
    _mongocrypt_ctx_opts_t opts;
    _mongocrypt_opts_kms_providers_t per_ctx_kms_providers; /* owned */
    _mongocrypt_opts_kms_providers_t kms_providers;         /* not owned, is merged from per-ctx / per-mongocrypt_t */
    bool initialized;
    /* nothing_to_do is set to true under these conditions:
     * 1. No keys are requested
     * 2. The command is bypassed for automatic encryption (e.g. ping).
     * 3. bypass_query_analysis is true.
     * TODO (MONGOCRYPT-422) replace nothing_to_do.
     */
    bool nothing_to_do;
};

/* Transition to the error state. An error status must have been set. */
bool _mongocrypt_ctx_fail(mongocrypt_ctx_t *ctx);

/* Set an error status and transition to the error state. */
bool _mongocrypt_ctx_fail_w_msg(mongocrypt_ctx_t *ctx, const char *msg);

typedef struct {
    mongocrypt_ctx_t parent;
    bool explicit;

    // `cmd_db` is the command database (appended as `$db`).
    char *cmd_db;

    // `target_ns` is the target namespace "." for the operation. May be associated with
    // jsonSchema (CSFLE) or encryptedFields (QE). For `bulkWrite`, the target namespace database may differ from
    // `cmd_db`.
    char *target_ns;

    // `target_db` is the target database for the operation. For `bulkWrite`, the target namespace database may differ
    // from `cmd_db`. If `target_db` is NULL, the target namespace database is the same as `cmd_db`.
    char *target_db;

    // `target_coll` is the target namespace collection name.
    char *target_coll;

    _mongocrypt_buffer_t list_collections_filter;
    _mongocrypt_buffer_t schema;
    /* TODO CDRIVER-3150: audit + rename these buffers.
     * original_cmd for explicit is {v: }, for auto is the command to
     * be encrypted.
     *
     * mongocryptd_cmd is only applicable for auto encryption. It is the original
     * command with JSONSchema appended.
     *
     * marked_cmd is the value of the 'result' field in mongocryptd response
     *
     * encrypted_cmd is the final output, the original command encrypted, or for
     * explicit, the {v: } doc.
     */
    _mongocrypt_buffer_t original_cmd;
    _mongocrypt_buffer_t mongocryptd_cmd;
    _mongocrypt_buffer_t marked_cmd;
    _mongocrypt_buffer_t encrypted_cmd;
    _mongocrypt_buffer_t key_id;
    bool used_local_schema;
    /* collinfo_has_siblings is true if the schema came from a remote JSON
     * schema, and there were siblings. */
    bool collinfo_has_siblings;
    /* encrypted_field_config is set when:
     * 1. `target_ns` is present in an encrypted_field_config_map.
     * 2. (TODO MONGOCRYPT-414) The collection has encryptedFields in the
     * response to listCollections. encrypted_field_config is true if and only if
     * encryption is using FLE 2.0.
     * 3. The `bulkWrite` command is processed and needs an empty encryptedFields to be processed by query analysis.
     * (`bulkWrite` does not support empty JSON schema).
     */
    _mongocrypt_buffer_t encrypted_field_config;
    mc_EncryptedFieldConfig_t efc;
    // `used_empty_encryptedFields` is true if the collection has no JSON schema or encryptedFields,
    // yet an empty encryptedFields was constructed to support query analysis.
    // When true, an empty encryptedFields is sent to query analysis, but not appended to the final command.
    bool used_empty_encryptedFields;
    /* bypass_query_analysis is set to true to skip the
     * MONGOCRYPT_CTX_NEED_MONGO_MARKINGS state. */
    bool bypass_query_analysis;

    struct {
        bool needed;
        _mongocrypt_buffer_t cmd;
        int32_t maxwireversion;
    } ismaster;

    // cmd_name is the first BSON field in original_cmd for auto encryption.
    const char *cmd_name;
} _mongocrypt_ctx_encrypt_t;

// `_mongocrypt_ctx_encrypt_t` inherits extended alignment from libbson. To dynamically allocate, use
// aligned allocation (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_ctx_encrypt_t,
                    BSON_ALIGNOF(_mongocrypt_ctx_encrypt_t) >= BSON_ALIGNOF(mongocrypt_ctx_t));

typedef struct {
    mongocrypt_ctx_t parent;
    /* TODO CDRIVER-3150: audit + rename these buffers.
     * Unlike ctx_encrypt, unwrapped_doc holds the binary value of the {v:
     * } doc.
     * */
    _mongocrypt_buffer_t original_doc;
    _mongocrypt_buffer_t decrypted_doc;
} _mongocrypt_ctx_decrypt_t;

// `_mongocrypt_ctx_datakey_t` inherits extended alignment from libbson. To dynamically allocate, use
// aligned allocation (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_ctx_decrypt_t,
                    BSON_ALIGNOF(_mongocrypt_ctx_decrypt_t) >= BSON_ALIGNOF(mongocrypt_ctx_t));

typedef struct {
    mongocrypt_ctx_t parent;
    mongocrypt_kms_ctx_t kms;
    bool kms_returned;
    _mongocrypt_buffer_t key_doc;
    _mongocrypt_buffer_t plaintext_key_material;
    _mongocrypt_buffer_t encrypted_key_material;

    const char *kmip_unique_identifier;
    bool kmip_activated;
    _mongocrypt_buffer_t kmip_secretdata;
} _mongocrypt_ctx_datakey_t;

// `_mongocrypt_ctx_datakey_t` inherits extended alignment from libbson. To dynamically allocate, use
// aligned allocation (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_ctx_datakey_t,
                    BSON_ALIGNOF(_mongocrypt_ctx_datakey_t) >= BSON_ALIGNOF(mongocrypt_ctx_t));

typedef struct _mongocrypt_ctx_rmd_datakey_t _mongocrypt_ctx_rmd_datakey_t;

struct _mongocrypt_ctx_rmd_datakey_t {
    _mongocrypt_ctx_rmd_datakey_t *next;
    mongocrypt_ctx_t *dkctx;
    _mongocrypt_key_doc_t *doc;
};

typedef struct {
    mongocrypt_ctx_t parent;
    _mongocrypt_buffer_t filter;
    mongocrypt_kms_ctx_t kms;
    _mongocrypt_ctx_rmd_datakey_t *datakeys;
    _mongocrypt_ctx_rmd_datakey_t *datakeys_iter;
    _mongocrypt_buffer_t results;
} _mongocrypt_ctx_rewrap_many_datakey_t;

// `_mongocrypt_ctx_rewrap_many_datakey_t` inherits extended alignment from libbson. To dynamically allocate, use
// aligned allocation (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_ctx_rewrap_many_datakey_t,
                    BSON_ALIGNOF(_mongocrypt_ctx_rewrap_many_datakey_t) >= BSON_ALIGNOF(mongocrypt_ctx_t));

typedef struct {
    mongocrypt_ctx_t parent;
    _mongocrypt_buffer_t result;
    mc_EncryptedFieldConfig_t efc;
} _mongocrypt_ctx_compact_t;

// `_mongocrypt_ctx_compact_t` inherits extended alignment from libbson. To dynamically allocate, use aligned
// allocation (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_ctx_compact_t,
                    BSON_ALIGNOF(_mongocrypt_ctx_compact_t) >= BSON_ALIGNOF(mongocrypt_ctx_t));

#define MONGOCRYPT_CTX_ALLOC_SIZE                                                                                      \
    BSON_MAX(sizeof(_mongocrypt_ctx_encrypt_t),                                                                        \
             BSON_MAX(sizeof(_mongocrypt_ctx_decrypt_t),                                                               \
                      BSON_MAX(sizeof(_mongocrypt_ctx_datakey_t),                                                      \
                               BSON_MAX(sizeof(_mongocrypt_ctx_rewrap_many_datakey_t),                                 \
                                        sizeof(_mongocrypt_ctx_compact_t)))))

#define MONGOCRYPT_CTX_ALLOC_ALIGNMENT                                                                                 \
    BSON_MAX(BSON_ALIGNOF(_mongocrypt_ctx_encrypt_t),                                                                  \
             BSON_MAX(BSON_ALIGNOF(_mongocrypt_ctx_decrypt_t),                                                         \
                      BSON_MAX(BSON_ALIGNOF(_mongocrypt_ctx_datakey_t),                                                \
                               BSON_MAX(BSON_ALIGNOF(_mongocrypt_ctx_rewrap_many_datakey_t),                           \
                                        BSON_ALIGNOF(_mongocrypt_ctx_compact_t)))))

// `_mongocrypt_ctx_t` inherits extended alignment from libbson. To dynamically allocate, use
// aligned allocation (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof_mongocrypt_ctx_t, BSON_ALIGNOF(mongocrypt_ctx_t) >= MONGOCRYPT_CTX_ALLOC_ALIGNMENT);

/* Used for option validation. True means required. False means prohibited. */
typedef enum { OPT_PROHIBITED = 0, OPT_REQUIRED, OPT_OPTIONAL } _mongocrypt_ctx_opt_spec_t;

typedef struct {
    _mongocrypt_ctx_opt_spec_t kek;
    _mongocrypt_ctx_opt_spec_t schema;
    _mongocrypt_ctx_opt_spec_t key_descriptor; /* a key_id or key_alt_name */
    _mongocrypt_ctx_opt_spec_t key_alt_names;
    _mongocrypt_ctx_opt_spec_t key_material;
    _mongocrypt_ctx_opt_spec_t algorithm;
    _mongocrypt_ctx_opt_spec_t rangeopts;
} _mongocrypt_ctx_opts_spec_t;

/* Common initialization. */
bool _mongocrypt_ctx_init(mongocrypt_ctx_t *ctx, _mongocrypt_ctx_opts_spec_t *opt_spec) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Set the state of the context from the state of keys in the key broker. */
bool _mongocrypt_ctx_state_from_key_broker(mongocrypt_ctx_t *ctx) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Get the KMS providers for the current context, fall back to the ones
 * from mongocrypt_t if none are provided for the context specifically. */
_mongocrypt_opts_kms_providers_t *_mongocrypt_ctx_kms_providers(mongocrypt_ctx_t *ctx);

#endif /* MONGOCRYPT_CTX_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-ctx-rewrap-many-datakey.c0000644000175100001660000003116314760300420023430 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#include "mongocrypt-ctx-private.h"

static bool _finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    _mongocrypt_ctx_rewrap_many_datakey_t *const rmdctx = (_mongocrypt_ctx_rewrap_many_datakey_t *)ctx;

    bson_t doc = BSON_INITIALIZER;
    bson_t array = BSON_INITIALIZER;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    BSON_ASSERT(BSON_APPEND_ARRAY_BEGIN(&doc, "v", &array));
    {
        _mongocrypt_ctx_rmd_datakey_t *iter = NULL;
        size_t idx = 0u;

        for (iter = rmdctx->datakeys; iter; (iter = iter->next), (++idx)) {
            mongocrypt_binary_t bin;
            bson_t bson;
            bson_t elem = BSON_INITIALIZER;

            if (!mongocrypt_ctx_finalize(iter->dkctx, &bin)) {
                BSON_ASSERT(bson_append_array_end(&doc, &array));
                bson_destroy(&doc);
                bson_destroy(&elem);
                return _mongocrypt_ctx_fail_w_msg(ctx, "failed to encrypt datakey with new provider");
            }

            BSON_ASSERT(bson_init_static(&bson, bin.data, bin.len));

            /* Among all (possible) fields in key document, the only fields
             * required by caller to construct the corresponding bulk write
             * operations to update the key document with rewrapped key material
             * are:
             *   - _id (same as original key)
             *   - keyMaterial (updated)
             *   - masterKey (updated)
             * Which means the following fields can be excluded:
             *   - _id (discard new ID generated during rewrapping)
             *   - creationDate
             *   - updateDate (updated via the $currentDate operator)
             *   - status
             *   - keyAltNames
             */
            bson_copy_to_excluding_noinit(&bson,
                                          &elem,
                                          "_id",
                                          "creationDate",
                                          "updateDate",
                                          "status",
                                          "keyAltNames",
                                          NULL);

            /* Preserve key ID of original document. */
            BSON_ASSERT(iter->doc);
            BSON_ASSERT(BSON_APPEND_BINARY(&elem, "_id", BSON_SUBTYPE_UUID, iter->doc->id.data, iter->doc->id.len));

            /* Array indicies must be specified manually. */
            {
                char *idx_str = bson_strdup_printf("%zu", idx);
                BSON_ASSERT(BSON_APPEND_DOCUMENT(&array, idx_str, &elem));
                bson_free(idx_str);
            }

            bson_destroy(&elem);
        }
    }
    BSON_ASSERT(bson_append_array_end(&doc, &array));

    /* Extend lifetime of bson so it can be referenced by out parameter. */
    _mongocrypt_buffer_steal_from_bson(&rmdctx->results, &doc);

    out->data = rmdctx->results.data;
    out->len = rmdctx->results.len;

    ctx->state = MONGOCRYPT_CTX_DONE;

    return true;
}

static bool _kms_done_encrypt(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_rewrap_many_datakey_t *const rmdctx = (_mongocrypt_ctx_rewrap_many_datakey_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    {
        _mongocrypt_ctx_rmd_datakey_t *iter;

        for (iter = rmdctx->datakeys; iter; iter = iter->next) {
            if (iter->dkctx->state == MONGOCRYPT_CTX_NEED_KMS && !mongocrypt_ctx_kms_done(iter->dkctx)) {
                _mongocrypt_status_copy_to(iter->dkctx->status, ctx->status);
                return _mongocrypt_ctx_fail(ctx);
            }
        }
    }

    /* Some providers may require multiple rounds of KMS requests. Reiterate
     * through datakey contexts to verify if more work needs to be done. */
    rmdctx->datakeys_iter = rmdctx->datakeys;

    while (rmdctx->datakeys_iter && rmdctx->datakeys_iter->dkctx->state != MONGOCRYPT_CTX_NEED_KMS) {
        rmdctx->datakeys_iter = rmdctx->datakeys_iter->next;
    }

    if (rmdctx->datakeys_iter) {
        /* More work to be done, remain in MONGOCRYPT_CTX_NEED_KMS state. */
        return true;
    }

    /* All datakeys have been encrypted and are ready to be finalized. */
    ctx->state = MONGOCRYPT_CTX_READY;
    ctx->vtable.finalize = _finalize;

    return true;
}

static mongocrypt_kms_ctx_t *_next_kms_ctx_encrypt(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_rewrap_many_datakey_t *const rmdctx = (_mongocrypt_ctx_rewrap_many_datakey_t *)ctx;

    mongocrypt_ctx_t *dkctx = NULL;

    BSON_ASSERT_PARAM(ctx);

    /* No more datakey contexts requiring KMS. */
    if (!rmdctx->datakeys_iter) {
        return NULL;
    }

    dkctx = rmdctx->datakeys_iter->dkctx;

    /* Skip next iterator ahead to next datakey context that needs KMS. */
    do {
        rmdctx->datakeys_iter = rmdctx->datakeys_iter->next;
    } while (rmdctx->datakeys_iter && rmdctx->datakeys_iter->dkctx->state != MONGOCRYPT_CTX_NEED_KMS);

    return mongocrypt_ctx_next_kms_ctx(dkctx);
}

static bool _add_new_datakey(mongocrypt_ctx_t *ctx, key_returned_t *key) {
    _mongocrypt_ctx_rewrap_many_datakey_t *const rmdctx = (_mongocrypt_ctx_rewrap_many_datakey_t *)ctx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(key);

    /* Datakey should be fully decrypted at this stage. */
    BSON_ASSERT(key->decrypted);

    _mongocrypt_ctx_rmd_datakey_t *const datakey = bson_malloc0(sizeof(_mongocrypt_ctx_rmd_datakey_t));

    datakey->dkctx = mongocrypt_ctx_new(ctx->crypt);
    datakey->next = rmdctx->datakeys;
    datakey->doc = key->doc;
    rmdctx->datakeys = datakey; /* Ownership transfer. */

    /* Set new provider and master key (rewrapManyDataKeyOpts). */
    if (ctx->opts.kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_NONE) {
        /* Reuse current KMS provider if option not set. */
        _mongocrypt_kek_copy_to(&key->doc->kek, &datakey->dkctx->opts.kek);
    } else {
        /* Apply new KMS provider as given by options. */
        _mongocrypt_kek_copy_to(&ctx->opts.kek, &datakey->dkctx->opts.kek);
    }

    /* Preserve alt names. */
    datakey->dkctx->opts.key_alt_names = _mongocrypt_key_alt_name_copy_all(key->doc->key_alt_names);

    /* Preserve key material. */
    _mongocrypt_buffer_copy_to(&key->decrypted_key_material, &datakey->dkctx->opts.key_material);

    if (!mongocrypt_ctx_datakey_init(datakey->dkctx)) {
        _mongocrypt_status_copy_to(datakey->dkctx->status, ctx->status);
        return _mongocrypt_ctx_fail(ctx);
    }

    /* Reuse KMS credentials provided during decryption. */
    if (datakey->dkctx->state == MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS) {
        memcpy(&datakey->dkctx->kms_providers,
               _mongocrypt_ctx_kms_providers(ctx),
               sizeof(_mongocrypt_opts_kms_providers_t));
        if (!datakey->dkctx->vtable.after_kms_credentials_provided(datakey->dkctx)) {
            _mongocrypt_status_copy_to(datakey->dkctx->status, ctx->status);
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    return true;
}

static bool _start_kms_encrypt(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_rewrap_many_datakey_t *const rmdctx = (_mongocrypt_ctx_rewrap_many_datakey_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    /* Finish KMS requests for decryption if there were any. */
    if (ctx->state == MONGOCRYPT_CTX_NEED_KMS) {
        _mongocrypt_opts_kms_providers_t *const providers = _mongocrypt_ctx_kms_providers(ctx);

        if (!_mongocrypt_key_broker_kms_done(&ctx->kb, providers)) {
            _mongocrypt_status_copy_to(ctx->kb.status, ctx->status);
            return _mongocrypt_ctx_fail(ctx);
        }

        if (!_mongocrypt_ctx_state_from_key_broker(ctx)) {
            return _mongocrypt_ctx_fail(ctx);
        }

        /* Some providers may require multiple rounds of KMS requests. */
        if (ctx->state == MONGOCRYPT_CTX_NEED_KMS) {
            return true;
        }
    }

    /* All datakeys should be decrypted at this point. */
    BSON_ASSERT(ctx->state == MONGOCRYPT_CTX_READY);

    /* For all decrypted datakeys, initialize a corresponding datakey context. */
    {
        key_returned_t *key;

        /* Some decrypted keys may have been cached. */
        for (key = ctx->kb.keys_cached; key; key = key->next) {
            if (!_add_new_datakey(ctx, key)) {
                return _mongocrypt_ctx_fail(ctx);
            }
        }

        /* Remaining keys were decrypted via KMS requests. */
        for (key = ctx->kb.keys_returned; key; key = key->next) {
            if (!_add_new_datakey(ctx, key)) {
                return _mongocrypt_ctx_fail(ctx);
            }
        }
    }

    /* Prepare iterator used by _next_kms_ctx_encrypt. */
    rmdctx->datakeys_iter = rmdctx->datakeys;

    /* Skip datakeys that do not require a KMS request. */
    while (rmdctx->datakeys_iter && rmdctx->datakeys_iter->dkctx->state == MONGOCRYPT_CTX_READY) {
        rmdctx->datakeys_iter = rmdctx->datakeys_iter->next;
    }

    /* Skip to READY state if no KMS requests are required. */
    if (!rmdctx->datakeys_iter) {
        ctx->state = MONGOCRYPT_CTX_READY;
        ctx->vtable.finalize = _finalize;
        return true;
    }

    ctx->state = MONGOCRYPT_CTX_NEED_KMS;
    ctx->vtable.next_kms_ctx = _next_kms_ctx_encrypt;
    ctx->vtable.kms_done = _kms_done_encrypt;

    return true;
}

static bool _mongo_done_keys(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    if (!_mongocrypt_key_broker_docs_done(&ctx->kb) || !_mongocrypt_ctx_state_from_key_broker(ctx)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    /* No keys to rewrap, no work to be done. */
    if (!ctx->kb.key_requests) {
        ctx->state = MONGOCRYPT_CTX_DONE;
        return true;
    }

    /* No KMS required, skip straight to encryption. */
    if (ctx->state == MONGOCRYPT_CTX_READY) {
        return _start_kms_encrypt(ctx);
    }

    /* KMS requests needed to decrypt keys. */
    BSON_ASSERT(ctx->state == MONGOCRYPT_CTX_NEED_KMS);

    return true;
}

static bool _mongo_op_keys(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    _mongocrypt_ctx_rewrap_many_datakey_t *const rmdctx = (_mongocrypt_ctx_rewrap_many_datakey_t *)ctx;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    _mongocrypt_buffer_to_binary(&rmdctx->filter, out);

    return true;
}

static bool _kms_start_decrypt(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    return _mongocrypt_key_broker_request_any(&ctx->kb) && _mongocrypt_ctx_state_from_key_broker(ctx);
}

static void _cleanup(mongocrypt_ctx_t *ctx) {
    _mongocrypt_ctx_rewrap_many_datakey_t *const rmdctx = (_mongocrypt_ctx_rewrap_many_datakey_t *)ctx;

    BSON_ASSERT_PARAM(ctx);

    _mongocrypt_buffer_cleanup(&rmdctx->results);

    while (rmdctx->datakeys) {
        _mongocrypt_ctx_rmd_datakey_t *result = rmdctx->datakeys;
        rmdctx->datakeys = result->next;

        mongocrypt_ctx_destroy(result->dkctx);
        bson_free(result);
    }

    _mongocrypt_kms_ctx_cleanup(&rmdctx->kms);
    _mongocrypt_buffer_cleanup(&rmdctx->filter);
}

bool mongocrypt_ctx_rewrap_many_datakey_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *filter) {
    _mongocrypt_ctx_rewrap_many_datakey_t *const rmdctx = (_mongocrypt_ctx_rewrap_many_datakey_t *)ctx;

    if (!ctx) {
        return false;
    }

    if (!filter) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "filter must not be null");
    }

    {
        _mongocrypt_ctx_opts_spec_t opts_spec;
        memset(&opts_spec, 0, sizeof(opts_spec));

        opts_spec.kek = OPT_OPTIONAL;

        if (!_mongocrypt_ctx_init(ctx, &opts_spec)) {
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    ctx->type = _MONGOCRYPT_TYPE_REWRAP_MANY_DATAKEY;
    ctx->state = MONGOCRYPT_CTX_NEED_MONGO_KEYS;
    ctx->vtable.cleanup = _cleanup;
    ctx->vtable.kms_done = _start_kms_encrypt;
    ctx->vtable.mongo_op_keys = _mongo_op_keys;
    ctx->vtable.mongo_done_keys = _mongo_done_keys;

    _mongocrypt_buffer_copy_from_binary(&rmdctx->filter, filter);

    /* Obtain KMS credentials for use during decryption and encryption. */
    if (_mongocrypt_needs_credentials(ctx->crypt)) {
        ctx->state = MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS;
        ctx->vtable.after_kms_credentials_provided = _kms_start_decrypt;
        return true;
    }

    return _kms_start_decrypt(ctx);
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-ctx.c0000644000175100001660000011454314760300420017554 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include 

#include "mongocrypt-ctx-private.h"
#include "mongocrypt-key-broker-private.h"

bool _mongocrypt_ctx_fail_w_msg(mongocrypt_ctx_t *ctx, const char *msg) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(msg);

    _mongocrypt_set_error(ctx->status, MONGOCRYPT_STATUS_ERROR_CLIENT, MONGOCRYPT_GENERIC_ERROR_CODE, "%s", msg);
    return _mongocrypt_ctx_fail(ctx);
}

/* A failure status has already been set. */
bool _mongocrypt_ctx_fail(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    if (mongocrypt_status_ok(ctx->status)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "unexpected, failing but no error status set");
    }
    ctx->state = MONGOCRYPT_CTX_ERROR;
    return false;
}

static bool
_set_binary_opt(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *binary, _mongocrypt_buffer_t *buf, bson_subtype_t subtype) {
    BSON_ASSERT_PARAM(ctx);

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (!binary || !binary->data) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "option must be non-NULL");
    }

    if (!_mongocrypt_buffer_empty(buf)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "option already set");
    }

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (subtype == BSON_SUBTYPE_UUID && binary->len != 16) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "expected 16 byte UUID");
    }

    _mongocrypt_buffer_copy_from_binary(buf, binary);
    buf->subtype = subtype;

    return true;
}

bool mongocrypt_ctx_setopt_key_id(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_id) {
    if (!ctx) {
        return false;
    }

    if (ctx->crypt->log.trace_enabled && key_id && key_id->data) {
        char *key_id_val;
        /* this should never happen, so assert rather than return false */
        BSON_ASSERT(key_id->len <= INT_MAX);
        key_id_val = _mongocrypt_new_string_from_bytes(key_id->data, (int)key_id->len);
        _mongocrypt_log(&ctx->crypt->log,
                        MONGOCRYPT_LOG_LEVEL_TRACE,
                        "%s (%s=\"%s\")",
                        BSON_FUNC,
                        "key_id",
                        key_id_val);
        bson_free(key_id_val);
    }

    return _set_binary_opt(ctx, key_id, &ctx->opts.key_id, BSON_SUBTYPE_UUID);
}

bool mongocrypt_ctx_setopt_key_alt_name(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_alt_name) {
    bson_t as_bson;
    bson_iter_t iter;
    _mongocrypt_key_alt_name_t *new_key_alt_name;
    const char *key;

    if (!ctx) {
        return false;
    }

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (!key_alt_name || !key_alt_name->data) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "option must be non-NULL");
    }

    if (!_mongocrypt_binary_to_bson(key_alt_name, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid keyAltName bson object");
    }

    if (!bson_iter_init(&iter, &as_bson) || !bson_iter_next(&iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid bson");
    }

    key = bson_iter_key(&iter);
    BSON_ASSERT(key);
    if (0 != strcmp(key, "keyAltName")) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "keyAltName must have field 'keyAltName'");
    }

    if (!BSON_ITER_HOLDS_UTF8(&iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "keyAltName expected to be UTF8");
    }

    new_key_alt_name = _mongocrypt_key_alt_name_new(bson_iter_value(&iter));

    if (ctx->opts.key_alt_names && _mongocrypt_key_alt_name_intersects(ctx->opts.key_alt_names, new_key_alt_name)) {
        _mongocrypt_key_alt_name_destroy_all(new_key_alt_name);
        return _mongocrypt_ctx_fail_w_msg(ctx, "duplicate keyAltNames found");
    }
    new_key_alt_name->next = ctx->opts.key_alt_names;
    ctx->opts.key_alt_names = new_key_alt_name;

    if (bson_iter_next(&iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "unrecognized field, only keyAltName expected");
    }

    return true;
}

bool mongocrypt_ctx_setopt_key_material(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_material) {
    bson_t as_bson;
    bson_iter_t iter;
    const char *key;
    _mongocrypt_buffer_t buffer;

    if (!ctx) {
        return false;
    }

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (ctx->opts.key_material.owned) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "keyMaterial already set");
    }

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (!key_material || !key_material->data) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "option must be non-NULL");
    }

    if (!_mongocrypt_binary_to_bson(key_material, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid keyMaterial bson object");
    }

    /* TODO: use _mongocrypt_parse_required_binary once MONGOCRYPT-380 is
     * resolved.*/
    if (!bson_iter_init(&iter, &as_bson) || !bson_iter_next(&iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid bson");
    }

    key = bson_iter_key(&iter);
    BSON_ASSERT(key);
    if (0 != strcmp(key, "keyMaterial")) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "keyMaterial must have field 'keyMaterial'");
    }

    if (!_mongocrypt_buffer_from_binary_iter(&buffer, &iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "keyMaterial must be binary data");
    }

    if (buffer.len != MONGOCRYPT_KEY_LEN) {
        _mongocrypt_set_error(ctx->status,
                              MONGOCRYPT_STATUS_ERROR_CLIENT,
                              MONGOCRYPT_GENERIC_ERROR_CODE,
                              "keyMaterial should have length %d, but has length %" PRIu32,
                              MONGOCRYPT_KEY_LEN,
                              buffer.len);
        return _mongocrypt_ctx_fail(ctx);
    }

    _mongocrypt_buffer_steal(&ctx->opts.key_material, &buffer);

    if (bson_iter_next(&iter)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "unrecognized field, only keyMaterial expected");
    }

    return true;
}

bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t *ctx, const char *algorithm, int len) {
    if (!ctx) {
        return false;
    }

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (ctx->opts.algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE || ctx->opts.index_type.set) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "already set algorithm");
    }

    if (len < -1) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid algorithm length");
    }

    if (!algorithm) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "passed null algorithm");
    }

    const size_t calculated_len = len == -1 ? strlen(algorithm) : (size_t)len;
    if (ctx->crypt->log.trace_enabled) {
        _mongocrypt_log(&ctx->crypt->log,
                        MONGOCRYPT_LOG_LEVEL_TRACE,
                        "%s (%s=\"%.*s\")",
                        BSON_FUNC,
                        "algorithm",
                        calculated_len <= (size_t)INT_MAX ? (int)calculated_len : INT_MAX,
                        algorithm);
    }

    mstr_view algo_str = mstrv_view_data(algorithm, calculated_len);
    if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_DETERMINISTIC_STR))) {
        ctx->opts.algorithm = MONGOCRYPT_ENCRYPTION_ALGORITHM_DETERMINISTIC;
    } else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_RANDOM_STR))) {
        ctx->opts.algorithm = MONGOCRYPT_ENCRYPTION_ALGORITHM_RANDOM;
    } else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_INDEXED_STR))) {
        ctx->opts.index_type.value = MONGOCRYPT_INDEX_TYPE_EQUALITY;
        ctx->opts.index_type.set = true;
    } else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_UNINDEXED_STR))) {
        ctx->opts.index_type.value = MONGOCRYPT_INDEX_TYPE_NONE;
        ctx->opts.index_type.set = true;
    } else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_RANGE_STR))) {
        ctx->opts.index_type.value = MONGOCRYPT_INDEX_TYPE_RANGE;
        ctx->opts.index_type.set = true;
    } else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_RANGEPREVIEW_DEPRECATED_STR))) {
        if (ctx->crypt->opts.use_range_v2) {
            _mongocrypt_ctx_fail_w_msg(ctx, "Algorithm 'rangePreview' is deprecated, please use 'range'");
            return false;
        }
        ctx->opts.index_type.value = MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED;
        ctx->opts.index_type.set = true;
    } else {
        char *error = bson_strdup_printf("unsupported algorithm string \"%.*s\"",
                                         algo_str.len <= (size_t)INT_MAX ? (int)algo_str.len : INT_MAX,
                                         algo_str.data);
        _mongocrypt_ctx_fail_w_msg(ctx, error);
        bson_free(error);
        return false;
    }

    return true;
}

mongocrypt_ctx_t *mongocrypt_ctx_new(mongocrypt_t *crypt) {
    mongocrypt_ctx_t *ctx;

    if (!crypt) {
        return NULL;
    }
    if (!crypt->initialized) {
        mongocrypt_status_t *status;

        status = crypt->status;
        CLIENT_ERR("cannot create context from uninitialized crypt");
        return NULL;
    }

    // Allocate with memory and alignment large enough for any possible context type.
    static const size_t ctx_alignment = MONGOCRYPT_CTX_ALLOC_ALIGNMENT;
    static const size_t ctx_size = MONGOCRYPT_CTX_ALLOC_SIZE;
    ctx = bson_aligned_alloc0(ctx_alignment, ctx_size);
    BSON_ASSERT(ctx);

    ctx->crypt = crypt;
    ctx->status = mongocrypt_status_new();
    ctx->opts.algorithm = MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE;
    ctx->opts.retry_enabled = crypt->retry_enabled;
    ctx->state = MONGOCRYPT_CTX_DONE;
    return ctx;
}

#define CHECK_AND_CALL(fn, ...)                                                                                        \
    do {                                                                                                               \
        if (!ctx->vtable.fn) {                                                                                         \
            return _mongocrypt_ctx_fail_w_msg(ctx, "not applicable to context");                                       \
        }                                                                                                              \
        return ctx->vtable.fn(__VA_ARGS__);                                                                            \
    } while (0)

/* Common to both encrypt and decrypt context. */
static bool _mongo_op_keys(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(out);

    /* Construct the find filter to fetch keys. */
    if (!_mongocrypt_key_broker_filter(&ctx->kb, out)) {
        BSON_ASSERT(!_mongocrypt_key_broker_status(&ctx->kb, ctx->status));
        return _mongocrypt_ctx_fail(ctx);
    }
    return true;
}

static bool _mongo_feed_keys(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in) {
    _mongocrypt_buffer_t buf;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(in);

    _mongocrypt_buffer_from_binary(&buf, in);
    if (!_mongocrypt_key_broker_add_doc(&ctx->kb, _mongocrypt_ctx_kms_providers(ctx), &buf)) {
        BSON_ASSERT(!_mongocrypt_key_broker_status(&ctx->kb, ctx->status));
        return _mongocrypt_ctx_fail(ctx);
    }
    return true;
}

static bool _mongo_done_keys(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    (void)_mongocrypt_key_broker_docs_done(&ctx->kb);
    return _mongocrypt_ctx_state_from_key_broker(ctx);
}

static mongocrypt_kms_ctx_t *_next_kms_ctx(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    return _mongocrypt_key_broker_next_kms(&ctx->kb);
}

static bool _kms_done(mongocrypt_ctx_t *ctx) {
    _mongocrypt_opts_kms_providers_t *kms_providers;

    BSON_ASSERT_PARAM(ctx);

    kms_providers = _mongocrypt_ctx_kms_providers(ctx);

    if (!_mongocrypt_key_broker_kms_done(&ctx->kb, kms_providers)) {
        BSON_ASSERT(!_mongocrypt_key_broker_status(&ctx->kb, ctx->status));
        return _mongocrypt_ctx_fail(ctx);
    }
    return _mongocrypt_ctx_state_from_key_broker(ctx);
}

bool mongocrypt_ctx_mongo_op(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    if (!ctx) {
        return false;
    }
    if (!ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
    }

    if (!out) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid NULL output");
    }

    switch (ctx->state) {
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: CHECK_AND_CALL(mongo_op_collinfo, ctx, out);
    case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: CHECK_AND_CALL(mongo_op_markings, ctx, out);
    case MONGOCRYPT_CTX_NEED_MONGO_KEYS: CHECK_AND_CALL(mongo_op_keys, ctx, out);
    case MONGOCRYPT_CTX_ERROR: return false;
    case MONGOCRYPT_CTX_DONE:
    case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS:
    case MONGOCRYPT_CTX_NEED_KMS:
    case MONGOCRYPT_CTX_READY:
    default: return _mongocrypt_ctx_fail_w_msg(ctx, "wrong state");
    }
}

const char *mongocrypt_ctx_mongo_db(mongocrypt_ctx_t *ctx) {
    if (!ctx) {
        return NULL;
    }
    if (!ctx->initialized) {
        _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
        return NULL;
    }

    switch (ctx->state) {
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB: {
        if (!ctx->vtable.mongo_db_collinfo) {
            _mongocrypt_ctx_fail_w_msg(ctx, "not applicable to context");
            return NULL;
        }
        return ctx->vtable.mongo_db_collinfo(ctx);
    }
    case MONGOCRYPT_CTX_ERROR: return false;
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO:
    case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS:
    case MONGOCRYPT_CTX_NEED_MONGO_KEYS:
    case MONGOCRYPT_CTX_DONE:
    case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS:
    case MONGOCRYPT_CTX_NEED_KMS:
    case MONGOCRYPT_CTX_READY:
    default: {
        _mongocrypt_ctx_fail_w_msg(ctx, "wrong state");
        return NULL;
    }
    }
}

bool mongocrypt_ctx_mongo_feed(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in) {
    if (!ctx) {
        return false;
    }
    if (!ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
    }

    if (!in) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid NULL input");
    }

    if (ctx->crypt->log.trace_enabled) {
        char *in_val;

        in_val = _mongocrypt_new_json_string_from_binary(in);
        _mongocrypt_log(&ctx->crypt->log, MONGOCRYPT_LOG_LEVEL_TRACE, "%s (%s=\"%s\")", BSON_FUNC, "in", in_val);
        bson_free(in_val);
    }

    switch (ctx->state) {
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: CHECK_AND_CALL(mongo_feed_collinfo, ctx, in);
    case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: CHECK_AND_CALL(mongo_feed_markings, ctx, in);
    case MONGOCRYPT_CTX_NEED_MONGO_KEYS: CHECK_AND_CALL(mongo_feed_keys, ctx, in);
    case MONGOCRYPT_CTX_ERROR: return false;
    case MONGOCRYPT_CTX_DONE:
    case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS:
    case MONGOCRYPT_CTX_NEED_KMS:
    case MONGOCRYPT_CTX_READY:
    default: return _mongocrypt_ctx_fail_w_msg(ctx, "wrong state");
    }
}

bool mongocrypt_ctx_mongo_done(mongocrypt_ctx_t *ctx) {
    if (!ctx) {
        return false;
    }
    if (!ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
    }

    switch (ctx->state) {
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: CHECK_AND_CALL(mongo_done_collinfo, ctx);
    case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS: CHECK_AND_CALL(mongo_done_markings, ctx);
    case MONGOCRYPT_CTX_NEED_MONGO_KEYS: CHECK_AND_CALL(mongo_done_keys, ctx);
    case MONGOCRYPT_CTX_ERROR: return false;
    case MONGOCRYPT_CTX_DONE:
    case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS:
    case MONGOCRYPT_CTX_NEED_KMS:
    case MONGOCRYPT_CTX_READY:
    default: return _mongocrypt_ctx_fail_w_msg(ctx, "wrong state");
    }
}

mongocrypt_ctx_state_t mongocrypt_ctx_state(mongocrypt_ctx_t *ctx) {
    if (!ctx) {
        return MONGOCRYPT_CTX_ERROR;
    }
    if (!ctx->initialized) {
        _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
        return MONGOCRYPT_CTX_ERROR;
    }

    return ctx->state;
}

mongocrypt_kms_ctx_t *mongocrypt_ctx_next_kms_ctx(mongocrypt_ctx_t *ctx) {
    if (!ctx) {
        return NULL;
    }
    if (!ctx->initialized) {
        _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
        return NULL;
    }

    if (!ctx->vtable.next_kms_ctx) {
        _mongocrypt_ctx_fail_w_msg(ctx, "not applicable to context");
        return NULL;
    }

    mongocrypt_kms_ctx_t *ret;
    switch (ctx->state) {
    case MONGOCRYPT_CTX_NEED_KMS: ret = ctx->vtable.next_kms_ctx(ctx); break;
    case MONGOCRYPT_CTX_ERROR: return NULL;
    case MONGOCRYPT_CTX_DONE:
    case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO:
    case MONGOCRYPT_CTX_NEED_MONGO_KEYS:
    case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS:
    case MONGOCRYPT_CTX_READY:
    default: _mongocrypt_ctx_fail_w_msg(ctx, "wrong state"); return NULL;
    }

    if (ret) {
        ret->retry_enabled = ctx->opts.retry_enabled;
    }
    return ret;
}

bool mongocrypt_ctx_provide_kms_providers(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *kms_providers_definition) {
    if (!ctx) {
        return false;
    }

    if (!ctx->initialized) {
        _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
        return false;
    }

    if (ctx->state != MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS) {
        _mongocrypt_ctx_fail_w_msg(ctx, "wrong state");
        return false;
    }

    if (!kms_providers_definition) {
        _mongocrypt_ctx_fail_w_msg(ctx, "KMS provider credential mapping not provided");
        return false;
    }

    _mongocrypt_opts_kms_providers_init(&ctx->per_ctx_kms_providers);

    if (!_mongocrypt_parse_kms_providers(kms_providers_definition,
                                         &ctx->per_ctx_kms_providers,
                                         ctx->status,
                                         &ctx->crypt->log)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    if (!_mongocrypt_opts_kms_providers_validate(&ctx->crypt->opts, &ctx->per_ctx_kms_providers, ctx->status)) {
        /* Remove the parsed KMS providers if they are invalid */
        _mongocrypt_opts_kms_providers_cleanup(&ctx->per_ctx_kms_providers);
        memset(&ctx->per_ctx_kms_providers, 0, sizeof(ctx->per_ctx_kms_providers));
        return _mongocrypt_ctx_fail(ctx);
    }

    memcpy(&ctx->kms_providers, &ctx->crypt->opts.kms_providers, sizeof(_mongocrypt_opts_kms_providers_t));
    _mongocrypt_opts_merge_kms_providers(&ctx->kms_providers, &ctx->per_ctx_kms_providers);

    ctx->state = ctx->kb.state == KB_ADDING_DOCS ? MONGOCRYPT_CTX_NEED_MONGO_KEYS : MONGOCRYPT_CTX_NEED_KMS;
    if (ctx->vtable.after_kms_credentials_provided) {
        return ctx->vtable.after_kms_credentials_provided(ctx);
    }
    return true;
}

bool mongocrypt_ctx_kms_done(mongocrypt_ctx_t *ctx) {
    if (!ctx) {
        return false;
    }
    if (!ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
    }

    if (!ctx->vtable.kms_done) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "not applicable to context");
    }

    switch (ctx->state) {
    case MONGOCRYPT_CTX_NEED_KMS: return ctx->vtable.kms_done(ctx);
    case MONGOCRYPT_CTX_ERROR: return false;
    case MONGOCRYPT_CTX_DONE:
    case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO:
    case MONGOCRYPT_CTX_NEED_MONGO_KEYS:
    case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS:
    case MONGOCRYPT_CTX_READY:
    default: return _mongocrypt_ctx_fail_w_msg(ctx, "wrong state");
    }
}

bool mongocrypt_ctx_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
    if (!ctx) {
        return false;
    }
    if (!ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "ctx NULL or uninitialized");
    }

    if (!out) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid NULL output");
    }

    if (!ctx->vtable.finalize) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "not applicable to context");
    }

    switch (ctx->state) {
    case MONGOCRYPT_CTX_READY: return ctx->vtable.finalize(ctx, out);
    case MONGOCRYPT_CTX_ERROR: return false;
    case MONGOCRYPT_CTX_DONE:
    case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS:
    case MONGOCRYPT_CTX_NEED_KMS:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB:
    case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO:
    case MONGOCRYPT_CTX_NEED_MONGO_KEYS:
    case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS:
    default: return _mongocrypt_ctx_fail_w_msg(ctx, "wrong state");
    }
}

bool mongocrypt_ctx_status(mongocrypt_ctx_t *ctx, mongocrypt_status_t *out) {
    if (!ctx) {
        return false;
    }

    if (!out) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid NULL output");
    }

    if (!mongocrypt_status_ok(ctx->status)) {
        _mongocrypt_status_copy_to(ctx->status, out);
        return false;
    }
    _mongocrypt_status_reset(out);
    return true;
}

void mongocrypt_ctx_destroy(mongocrypt_ctx_t *ctx) {
    if (!ctx) {
        return;
    }

    if (ctx->vtable.cleanup) {
        ctx->vtable.cleanup(ctx);
    }

    mc_RangeOpts_cleanup(&ctx->opts.rangeopts.value);
    _mongocrypt_opts_kms_providers_cleanup(&ctx->per_ctx_kms_providers);
    _mongocrypt_kek_cleanup(&ctx->opts.kek);
    mongocrypt_status_destroy(ctx->status);
    _mongocrypt_key_broker_cleanup(&ctx->kb);
    _mongocrypt_buffer_cleanup(&ctx->opts.key_material);
    _mongocrypt_key_alt_name_destroy_all(ctx->opts.key_alt_names);
    _mongocrypt_buffer_cleanup(&ctx->opts.key_id);
    _mongocrypt_buffer_cleanup(&ctx->opts.index_key_id);
    bson_free(ctx);
    return;
}

bool mongocrypt_ctx_setopt_masterkey_aws(mongocrypt_ctx_t *ctx,
                                         const char *region,
                                         int32_t region_len,
                                         const char *cmk,
                                         int32_t cmk_len) {
    mongocrypt_binary_t *bin;
    bson_t as_bson;
    bool ret;
    char *temp = NULL;

    if (!ctx) {
        return false;
    }
    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (ctx->opts.kek.kms_provider != MONGOCRYPT_KMS_PROVIDER_AWS
        && ctx->opts.kek.kms_provider != MONGOCRYPT_KMS_PROVIDER_NONE) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "master key already set");
    }

    if (ctx->opts.kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_AWS && ctx->opts.kek.provider.aws.region) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "master key already set");
    }

    if (!_mongocrypt_validate_and_copy_string(region, region_len, &temp) || region_len == 0) {
        bson_free(temp);
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid region");
    }
    bson_free(temp);

    temp = NULL;
    if (!_mongocrypt_validate_and_copy_string(cmk, cmk_len, &temp) || cmk_len == 0) {
        bson_free(temp);
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid cmk");
    }
    bson_free(temp);

    bson_init(&as_bson);
    bson_append_utf8(&as_bson, MONGOCRYPT_STR_AND_LEN("provider"), MONGOCRYPT_STR_AND_LEN("aws"));
    BSON_ASSERT(region_len <= INT_MAX);
    bson_append_utf8(&as_bson, MONGOCRYPT_STR_AND_LEN("region"), region, region_len);
    BSON_ASSERT(cmk_len <= INT_MAX);
    bson_append_utf8(&as_bson, MONGOCRYPT_STR_AND_LEN("key"), cmk, cmk_len);
    bin = mongocrypt_binary_new_from_data((uint8_t *)bson_get_data(&as_bson), as_bson.len);

    ret = mongocrypt_ctx_setopt_key_encryption_key(ctx, bin);
    mongocrypt_binary_destroy(bin);
    bson_destroy(&as_bson);

    if (ctx->crypt->log.trace_enabled) {
        _mongocrypt_log(&ctx->crypt->log,
                        MONGOCRYPT_LOG_LEVEL_TRACE,
                        "%s (%s=\"%s\", %s=%d, %s=\"%s\", %s=%d)",
                        BSON_FUNC,
                        "region",
                        ctx->opts.kek.provider.aws.region,
                        "region_len",
                        region_len,
                        "cmk",
                        ctx->opts.kek.provider.aws.cmk,
                        "cmk_len",
                        cmk_len);
    }

    return ret;
}

bool mongocrypt_ctx_setopt_masterkey_local(mongocrypt_ctx_t *ctx) {
    if (!ctx) {
        return false;
    }
    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (ctx->opts.kek.kms_provider) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "master key already set");
    }

    ctx->opts.kek.kms_provider = MONGOCRYPT_KMS_PROVIDER_LOCAL;
    ctx->opts.kek.kmsid = bson_strdup("local");
    return true;
}

bool _mongocrypt_ctx_init(mongocrypt_ctx_t *ctx, _mongocrypt_ctx_opts_spec_t *opts_spec) {
    bool has_id = false, has_alt_name = false, has_multiple_alt_names = false;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(opts_spec);

    // This condition is guarded in setopt_algorithm:
    BSON_ASSERT(!(ctx->opts.index_type.set && ctx->opts.algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE)
                && "Both an encryption algorithm and an index_type were set.");

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot double initialize");
    }
    ctx->initialized = true;

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }
    /* Set some default functions */
    ctx->vtable.mongo_op_keys = _mongo_op_keys;
    ctx->vtable.mongo_feed_keys = _mongo_feed_keys;
    ctx->vtable.mongo_done_keys = _mongo_done_keys;
    ctx->vtable.next_kms_ctx = _next_kms_ctx;
    ctx->vtable.kms_done = _kms_done;

    /* Check that required options are included and prohibited options are
     * not.
     */

    if (opts_spec->kek == OPT_REQUIRED) {
        if (!ctx->opts.kek.kms_provider) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "master key required");
        }
        mc_kms_creds_t unused;
        bool is_configured =
            _mongocrypt_opts_kms_providers_lookup(_mongocrypt_ctx_kms_providers(ctx), ctx->opts.kek.kmsid, &unused);
        if (!ctx->crypt->opts.use_need_kms_credentials_state && !is_configured) {
            mongocrypt_status_t *status = ctx->status;
            CLIENT_ERR("requested kms provider not configured: `%s`", ctx->opts.kek.kmsid);
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    if (opts_spec->kek == OPT_PROHIBITED && ctx->opts.kek.kms_provider) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "master key prohibited");
    }

    /* Check that the kms provider required by the datakey is configured.  */
    if (ctx->opts.kek.kms_provider) {
        mc_kms_creds_t unused;
        bool is_configured =
            _mongocrypt_opts_kms_providers_lookup(_mongocrypt_ctx_kms_providers(ctx), ctx->opts.kek.kmsid, &unused);
        bool needs = _mongocrypt_needs_credentials_for_provider(ctx->crypt,
                                                                ctx->opts.kek.kms_provider,
                                                                ctx->opts.kek.kmsid_name);
        if (!is_configured && !needs) {
            mongocrypt_status_t *status = ctx->status;
            CLIENT_ERR("requested kms provider required by datakey is not configured: `%s`", ctx->opts.kek.kmsid);
            return _mongocrypt_ctx_fail(ctx);
        }
    }

    /* Special case. key_descriptor applies to explicit encryption. It must be
     * either a key id or *one* key alt name, but not both.
     * key_alt_names applies to creating a data key. It may be one or multiple
     * key alt names.
     */
    has_id = !_mongocrypt_buffer_empty(&ctx->opts.key_id);
    has_alt_name = !!(ctx->opts.key_alt_names);
    has_multiple_alt_names = has_alt_name && !!(ctx->opts.key_alt_names->next);

    if (opts_spec->key_descriptor == OPT_REQUIRED) {
        if (!has_id && !has_alt_name) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "either key id or key alt name required");
        }

        if (has_id && has_alt_name) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "cannot have both key id and key alt name");
        }

        if (has_multiple_alt_names) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "must not specify multiple key alt names");
        }
    }

    if (opts_spec->key_descriptor == OPT_PROHIBITED) {
        /* still okay if key_alt_names are allowed and only alt names were
         * specified. */
        if ((opts_spec->key_alt_names == OPT_PROHIBITED && has_alt_name) || has_id) {
            return _mongocrypt_ctx_fail_w_msg(ctx, "key id and alt name prohibited");
        }
    }

    if (opts_spec->key_material == OPT_PROHIBITED && ctx->opts.key_material.owned) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "key material prohibited");
    }

    if (opts_spec->algorithm == OPT_REQUIRED && ctx->opts.algorithm == MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "algorithm required");
    }

    if (opts_spec->algorithm == OPT_PROHIBITED && ctx->opts.algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "algorithm prohibited");
    }

    if (opts_spec->rangeopts == OPT_PROHIBITED && ctx->opts.rangeopts.set) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "range opts are prohibited on this context");
    }

    _mongocrypt_key_broker_init(&ctx->kb, ctx->crypt);
    return true;
}

bool _mongocrypt_ctx_state_from_key_broker(mongocrypt_ctx_t *ctx) {
    _mongocrypt_key_broker_t *kb;
    mongocrypt_status_t *status;
    mongocrypt_ctx_state_t new_state = MONGOCRYPT_CTX_ERROR;
    bool ret = false;

    BSON_ASSERT_PARAM(ctx);

    status = ctx->status;
    kb = &ctx->kb;

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    switch (kb->state) {
    case KB_ERROR:
        _mongocrypt_status_copy_to(kb->status, status);
        new_state = MONGOCRYPT_CTX_ERROR;
        ret = false;
        break;
    case KB_ADDING_DOCS:
        /* Encrypted keys need KMS, which need to be provided before
         * adding docs. */
        if (_mongocrypt_needs_credentials(ctx->crypt)) {
            new_state = MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS;
        } else {
            /* Require key documents from driver. */
            new_state = MONGOCRYPT_CTX_NEED_MONGO_KEYS;
        }
        ret = true;
        break;
    case KB_ADDING_DOCS_ANY:
        /* Assume KMS credentials have been provided. */
        new_state = MONGOCRYPT_CTX_NEED_MONGO_KEYS;
        ret = true;
        break;
    case KB_AUTHENTICATING:
    case KB_DECRYPTING_KEY_MATERIAL:
        new_state = MONGOCRYPT_CTX_NEED_KMS;
        ret = true;
        break;
    case KB_DONE:
        new_state = MONGOCRYPT_CTX_READY;
        if (kb->key_requests == NULL) {
            /* No key requests were ever added. */
            ctx->nothing_to_do = true; /* nothing to encrypt/decrypt */
        }
        ret = true;
        break;
    /* As currently implemented, we do not expect to ever be in KB_REQUESTING
     * or KB_REQUESTING_ANY state when calling this function. */
    case KB_REQUESTING:
    default:
        CLIENT_ERR("key broker in unexpected state");
        new_state = MONGOCRYPT_CTX_ERROR;
        ret = false;
        break;
    }

    if (new_state != ctx->state) {
        ctx->state = new_state;
    }

    return ret;
}

bool mongocrypt_ctx_setopt_masterkey_aws_endpoint(mongocrypt_ctx_t *ctx, const char *endpoint, int32_t endpoint_len) {
    if (!ctx) {
        return false;
    }

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (ctx->opts.kek.kms_provider != MONGOCRYPT_KMS_PROVIDER_AWS
        && ctx->opts.kek.kms_provider != MONGOCRYPT_KMS_PROVIDER_NONE) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "endpoint prohibited");
    }

    ctx->opts.kek.kms_provider = MONGOCRYPT_KMS_PROVIDER_AWS;

    if (ctx->opts.kek.provider.aws.endpoint) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "already set masterkey endpoint");
    }

    ctx->opts.kek.provider.aws.endpoint =
        _mongocrypt_endpoint_new(endpoint, endpoint_len, NULL /* opts */, ctx->status);
    if (!ctx->opts.kek.provider.aws.endpoint) {
        return _mongocrypt_ctx_fail(ctx);
    }

    return true;
}

bool mongocrypt_ctx_setopt_key_encryption_key(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *bin) {
    bson_t as_bson;

    if (!ctx) {
        return false;
    }

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (ctx->opts.kek.kms_provider) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "key encryption key already set");
    }

    if (!bin) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid NULL key encryption key document");
    }

    if (!_mongocrypt_binary_to_bson(bin, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid BSON");
    }

    if (!_mongocrypt_kek_parse_owned(&as_bson, &ctx->opts.kek, ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    if (ctx->crypt->log.trace_enabled) {
        char *bin_str = bson_as_canonical_extended_json(&as_bson, NULL);
        _mongocrypt_log(&ctx->crypt->log, MONGOCRYPT_LOG_LEVEL_TRACE, "%s (%s=\"%s\")", BSON_FUNC, "bin", bin_str);
        bson_free(bin_str);
    }

    return true;
}

_mongocrypt_opts_kms_providers_t *_mongocrypt_ctx_kms_providers(mongocrypt_ctx_t *ctx) {
    BSON_ASSERT_PARAM(ctx);

    return ctx->kms_providers.configured_providers ? &ctx->kms_providers : &ctx->crypt->opts.kms_providers;
}

bool mongocrypt_ctx_setopt_contention_factor(mongocrypt_ctx_t *ctx, int64_t contention_factor) {
    if (!ctx) {
        return false;
    }
    ctx->opts.contention_factor.value = contention_factor;
    ctx->opts.contention_factor.set = true;
    return true;
}

bool mongocrypt_ctx_setopt_index_key_id(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_id) {
    if (!ctx) {
        return false;
    }

    return _set_binary_opt(ctx, key_id, &ctx->opts.index_key_id, BSON_SUBTYPE_UUID);
}

bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t *ctx, const char *query_type, int len) {
    if (!ctx) {
        return false;
    }

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "Cannot set options after init");
    }
    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }
    if (len < -1) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "Invalid query_type string length");
    }
    if (!query_type) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "Invalid null query_type string");
    }

    const size_t calc_len = len == -1 ? strlen(query_type) : (size_t)len;
    mstr_view qt_str = mstrv_view_data(query_type, calc_len);
    if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_EQUALITY_STR))) {
        ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_EQUALITY;
        ctx->opts.query_type.set = true;
    } else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_RANGE_STR))) {
        ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_RANGE;
        ctx->opts.query_type.set = true;
    } else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED_STR))) {
        if (ctx->crypt->opts.use_range_v2) {
            _mongocrypt_ctx_fail_w_msg(ctx, "Query type 'rangePreview' is deprecated, please use 'range'");
            return false;
        }
        ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED;
        ctx->opts.query_type.set = true;
    } else {
        /* don't check if qt_str.len fits in int; we want the diagnostic output */
        char *error = bson_strdup_printf("Unsupported query_type \"%.*s\"",
                                         qt_str.len <= (size_t)INT_MAX ? (int)qt_str.len : INT_MAX,
                                         qt_str.data);
        _mongocrypt_ctx_fail_w_msg(ctx, error);
        bson_free(error);
        return false;
    }
    return true;
}

const char *_mongocrypt_index_type_to_string(mongocrypt_index_type_t val) {
    switch (val) {
    case MONGOCRYPT_INDEX_TYPE_NONE: return "None";
    case MONGOCRYPT_INDEX_TYPE_EQUALITY: return "Equality";
    case MONGOCRYPT_INDEX_TYPE_RANGE: return "Range";
    case MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED: return "RangePreview";
    default: return "Unknown";
    }
}

const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val) {
    switch (val) {
    case MONGOCRYPT_QUERY_TYPE_EQUALITY: return "Equality";
    case MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED: return "RangePreview";
    case MONGOCRYPT_QUERY_TYPE_RANGE: return "Range";
    default: return "Unknown";
    }
}

bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts) {
    bson_t as_bson;

    if (!ctx) {
        return false;
    }

    if (ctx->initialized) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
    }

    if (ctx->state == MONGOCRYPT_CTX_ERROR) {
        return false;
    }

    if (ctx->opts.rangeopts.set) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "RangeOpts already set");
    }

    if (!_mongocrypt_binary_to_bson(opts, &as_bson)) {
        return _mongocrypt_ctx_fail_w_msg(ctx, "invalid BSON");
    }

    if (!mc_RangeOpts_parse(&ctx->opts.rangeopts.value, &as_bson, ctx->crypt->opts.use_range_v2, ctx->status)) {
        return _mongocrypt_ctx_fail(ctx);
    }

    ctx->opts.rangeopts.set = true;
    return true;
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-dll-private.h0000644000175100001660000000521214760300420021176 0ustar  #ifndef MONGOCRYPT_DLL_PRIVATE_H
#define MONGOCRYPT_DLL_PRIVATE_H

#include 
#include 

#include 

#if _WIN32
#define MCR_DLL_SUFFIX ".dll"
#elif __APPLE__
#define MCR_DLL_SUFFIX ".dylib"
#else
#define MCR_DLL_SUFFIX ".so"
#endif

#define MCR_DLL_NULL ((mcr_dll){._native_handle = NULL, .error_string = MSTR_NULL})

/**
 * @brief A dynamically-loaded library i.e. returned by LoadLibrary() or
 * dlopen()
 */
typedef struct mcr_dll {
    // (All supported platforms use a void* as the library handle type)
    void *_native_handle;
    mstr error_string;
} mcr_dll;

/**
 * @brief Open and load a dynamic library
 *
 * @param lib A path or name of a library, suitable for encoding as a
 * filepath on the host system.
 *
 * @return mcr_dll A newly opened dynamic library, which must be
 * released using @ref mcr_dll_close()
 *
 * If the given `lib` is a qualified path (either relative or absolute) and not
 * just a filename, then the system will search for the library on the system's
 * default library search paths. If `lib` is a qualified relative path (not just
 * a filename), it will be resolved relative to the application's working
 * directory.
 */
mcr_dll mcr_dll_open(const char *lib);

/**
 * @brief Close a dynamic library opened with @ref mcr_dll_open
 *
 * @param dll A dynamic library handle
 */
static inline void mcr_dll_close(mcr_dll dll) {
    extern void mcr_dll_close_handle(mcr_dll);
    mcr_dll_close_handle(dll);
    mstr_free(dll.error_string);
}

/**
 * @brief Obtain a pointer to an exported entity from the given dynamic library.
 *
 * @param dll A library opened with @ref mcr_dll_open
 * @param symbol The name of a symbol to open
 * @return void* A pointer to that symbol, or NULL if not found
 */
void *mcr_dll_sym(mcr_dll dll, const char *symbol);

/**
 * @brief Determine whether the given DLL is a handle to an open library
 */
static inline bool mcr_dll_is_open(mcr_dll dll) {
    return dll._native_handle != NULL;
}

typedef struct mcr_dll_path_result {
    mstr path;
    mstr error_string;
} mcr_dll_path_result;

/**
 * @brief Obtain a filepath to the given loaded DLL
 *
 * @param dll The library loaded to inspect
 * @return mcr_dll_path_result A result containing the absolute path to a
 * library, or an error string.
 *
 * @note Caller must free both `retval.path` and `retval.error_string`.
 * @note Returns an error if not supported on this platform. Use
 * `mcr_dll_path_supported` to check before calling.
 */
mcr_dll_path_result mcr_dll_path(mcr_dll dll);

/**
 * @brief Return true if `mcr_dll_path` is supported on this platform.
 */
bool mcr_dll_path_supported(void);

#endif // MONGOCRYPT_DLL_PRIVATE_H
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-endian-private.h0000644000175100001660000001261714760300420021670 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

/* This file is copied and modified from kms_message kms_endian.h. */

#ifndef MONGOCRYPT_ENDIAN_PRIVATE_H
#define MONGOCRYPT_ENDIAN_PRIVATE_H

#include 
#include 

/* Define a fallback for __has_builtin for compatibility with non-clang
 * compilers. */
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif

#if defined(__clang__) && __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32)                         \
    && __has_builtin(__builtin_bswap64)
#define MONGOCRYPT_UINT16_SWAP_LE_BE(v) __builtin_bswap16(v)
#define MONGOCRYPT_UINT32_SWAP_LE_BE(v) __builtin_bswap32(v)
#define MONGOCRYPT_UINT64_SWAP_LE_BE(v) __builtin_bswap64(v)
#elif defined(__GNUC__) && (__GNUC__ >= 4)
#if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3)
#define MONGOCRYPT_UINT32_SWAP_LE_BE(v) __builtin_bswap32((uint32_t)v)
#define MONGOCRYPT_UINT64_SWAP_LE_BE(v) __builtin_bswap64((uint64_t)v)
#endif
#if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8)
#define MONGOCRYPT_UINT16_SWAP_LE_BE(v) __builtin_bswap16((uint32_t)v)
#endif
#endif

#ifndef MONGOCRYPT_UINT16_SWAP_LE_BE
#define MONGOCRYPT_UINT16_SWAP_LE_BE(v) __mongocrypt_uint16_swap_slow((uint16_t)v)
#endif

#ifndef MONGOCRYPT_UINT32_SWAP_LE_BE
#define MONGOCRYPT_UINT32_SWAP_LE_BE(v) __mongocrypt_uint32_swap_slow((uint32_t)v)
#endif

#ifndef MONGOCRYPT_UINT64_SWAP_LE_BE
#define MONGOCRYPT_UINT64_SWAP_LE_BE(v) __mongocrypt_uint64_swap_slow((uint64_t)v)
#endif

#if defined(MONGOCRYPT_LITTLE_ENDIAN)
#define MONGOCRYPT_UINT16_FROM_LE(v) ((uint16_t)v)
#define MONGOCRYPT_UINT16_TO_LE(v) ((uint16_t)v)
#define MONGOCRYPT_UINT16_FROM_BE(v) MONGOCRYPT_UINT16_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT16_TO_BE(v) MONGOCRYPT_UINT16_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT32_FROM_LE(v) ((uint32_t)v)
#define MONGOCRYPT_UINT32_TO_LE(v) ((uint32_t)v)
#define MONGOCRYPT_UINT32_FROM_BE(v) MONGOCRYPT_UINT32_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT32_TO_BE(v) MONGOCRYPT_UINT32_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT64_FROM_LE(v) ((uint64_t)v)
#define MONGOCRYPT_UINT64_TO_LE(v) ((uint64_t)v)
#define MONGOCRYPT_UINT64_FROM_BE(v) MONGOCRYPT_UINT64_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT64_TO_BE(v) MONGOCRYPT_UINT64_SWAP_LE_BE(v)
#elif defined(MONGOCRYPT_BIG_ENDIAN)
#define MONGOCRYPT_UINT16_FROM_LE(v) MONGOCRYPT_UINT16_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT16_TO_LE(v) MONGOCRYPT_UINT16_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT16_FROM_BE(v) ((uint16_t)v)
#define MONGOCRYPT_UINT16_TO_BE(v) ((uint16_t)v)
#define MONGOCRYPT_UINT32_FROM_LE(v) MONGOCRYPT_UINT32_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT32_TO_LE(v) MONGOCRYPT_UINT32_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT32_FROM_BE(v) ((uint32_t)v)
#define MONGOCRYPT_UINT32_TO_BE(v) ((uint32_t)v)
#define MONGOCRYPT_UINT64_FROM_LE(v) MONGOCRYPT_UINT64_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT64_TO_LE(v) MONGOCRYPT_UINT64_SWAP_LE_BE(v)
#define MONGOCRYPT_UINT64_FROM_BE(v) ((uint64_t)v)
#define MONGOCRYPT_UINT64_TO_BE(v) ((uint64_t)v)
#else
#error "The endianness of target architecture is unknown."
#endif

/*
 *--------------------------------------------------------------------------
 *
 * __mongocrypt_uint16_swap_slow --
 *
 *       Fallback endianness conversion for 16-bit integers.
 *
 * Returns:
 *       The endian swapped version.
 *
 * Side effects:
 *       None.
 *
 *--------------------------------------------------------------------------
 */

static inline uint16_t __mongocrypt_uint16_swap_slow(uint16_t v) /* IN */
{
    return (uint16_t)((v & 0x00FF) << 8) | (uint16_t)((v & 0xFF00) >> 8);
}

/*
 *--------------------------------------------------------------------------
 *
 * __mongocrypt_uint32_swap_slow --
 *
 *       Fallback endianness conversion for 32-bit integers.
 *
 * Returns:
 *       The endian swapped version.
 *
 * Side effects:
 *       None.
 *
 *--------------------------------------------------------------------------
 */

static inline uint32_t __mongocrypt_uint32_swap_slow(uint32_t v) /* IN */
{
    return ((v & 0x000000FFU) << 24) | ((v & 0x0000FF00U) << 8) | ((v & 0x00FF0000U) >> 8) | ((v & 0xFF000000U) >> 24);
}

/*
 *--------------------------------------------------------------------------
 *
 * __mongocrypt_uint64_swap_slow --
 *
 *       Fallback endianness conversion for 64-bit integers.
 *
 * Returns:
 *       The endian swapped version.
 *
 * Side effects:
 *       None.
 *
 *--------------------------------------------------------------------------
 */

static inline uint64_t __mongocrypt_uint64_swap_slow(uint64_t v) /* IN */
{
    return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40)
         | ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) | ((v & 0x000000FF00000000ULL) >> 8)
         | ((v & 0x0000FF0000000000ULL) >> 24) | ((v & 0x00FF000000000000ULL) >> 40)
         | ((v & 0xFF00000000000000ULL) >> 56);
}

#endif /* MONGOCRYPT_ENDIAN_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-endpoint-private.h0000644000175100001660000000462214760300420022247 0ustar  /*
 * Copyright 2020-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_ENDPOINT_PRIVATE_H
#define MONGOCRYPT_ENDPOINT_PRIVATE_H

#include "mongocrypt-status-private.h"

typedef struct {
    /* e.g. https://kevin.keyvault.azure.net:443/path/path/?query=value */
    char *original;
    char *protocol;  /* e.g. https */
    char *host;      /* e.g. kevin.keyvault.azure.net */
    char *port;      /* e.g. 443 */
    char *domain;    /* e.g. keyvault.azure.net */
    char *subdomain; /* e.g. kevin */
    char *path;      /* e.g. path/path */
    char *query;     /* e.g. query=value */
    /* host_and_port is the form that should be returned to drivers. */
    char *host_and_port; /* e.g. kevin.keyvault.azure.net:443 */
} _mongocrypt_endpoint_t;

_mongocrypt_endpoint_t *_mongocrypt_endpoint_copy(_mongocrypt_endpoint_t *src);

void _mongocrypt_endpoint_destroy(_mongocrypt_endpoint_t *endpoint);

typedef struct {
    /* allow_empty_subdomain does not require "host" to contain dot separators.
     * If allow_empty_subdomain is true, then "localhost" is a valid endpoint. */
    bool allow_empty_subdomain;
} _mongocrypt_endpoint_parse_opts_t;

/* Parses a subset of URIs of the form:
 * [protocol://][host[:port]][path][?query]
 */
_mongocrypt_endpoint_t *_mongocrypt_endpoint_new(const char *endpoint_raw,
                                                 int32_t len,
                                                 _mongocrypt_endpoint_parse_opts_t *opts,
                                                 mongocrypt_status_t *status);

/* _mongocrypt_apply_default_port checks if the endpoint string *endpoint_raw
 * contains a port. If *endpoint_raw does not contain a port, *endpoint_raw is
 * freed and overwritten to a copy of *endpoint_raw with ":" appended.
 */
void _mongocrypt_apply_default_port(char **endpoint_raw, char *port);

#endif /* MONGOCRYPT_ENDPOINT_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-endpoint.c0000644000175100001660000001363114760300420020572 0ustar  /*
 * Copyright 2020-present MongoDB, 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.
 */

#include "mongocrypt-endpoint-private.h"

#include "mongocrypt-private.h"

void _mongocrypt_endpoint_destroy(_mongocrypt_endpoint_t *endpoint) {
    if (!endpoint) {
        return;
    }
    bson_free(endpoint->original);
    bson_free(endpoint->protocol);
    bson_free(endpoint->host);
    bson_free(endpoint->port);
    bson_free(endpoint->domain);
    bson_free(endpoint->subdomain);
    bson_free(endpoint->path);
    bson_free(endpoint->query);
    bson_free(endpoint->host_and_port);
    bson_free(endpoint);
}

/* Parses a subset of URIs of the form:
 * [protocol://][host[:port]][path][?query]
 */
_mongocrypt_endpoint_t *_mongocrypt_endpoint_new(const char *endpoint_raw,
                                                 int32_t len,
                                                 _mongocrypt_endpoint_parse_opts_t *opts,
                                                 mongocrypt_status_t *status) {
    _mongocrypt_endpoint_t *endpoint;
    bool ok = false;
    char *pos;
    char *prev;
    char *colon;
    char *qmark;
    char *slash;
    char *host_start;
    char *host_end;

    /* opts is checked where it is used below, to allow a more precise error */

    endpoint = bson_malloc0(sizeof(_mongocrypt_endpoint_t));
    _mongocrypt_status_reset(status);
    BSON_ASSERT(endpoint);
    if (!_mongocrypt_validate_and_copy_string(endpoint_raw, len, &endpoint->original)) {
        CLIENT_ERR("Invalid endpoint");
        goto fail;
    }

    /* Parse optional protocol. */
    pos = strstr(endpoint->original, "://");
    if (pos) {
        endpoint->protocol = bson_strndup(endpoint->original, (size_t)(pos - endpoint->original));
        pos += 3;
    } else {
        pos = endpoint->original;
    }
    host_start = pos;

    /* Parse subdomain. */
    prev = pos;
    pos = strstr(pos, ".");
    if (pos) {
        BSON_ASSERT(pos >= prev);
        endpoint->subdomain = bson_strndup(prev, (size_t)(pos - prev));
        pos += 1;
    } else {
        if (!opts || !opts->allow_empty_subdomain) {
            CLIENT_ERR("Invalid endpoint, expected dot separator in host, but got: %s", endpoint->original);
            goto fail;
        }
        /* OK, reset pos to the start of the host. */
        pos = prev;
    }

    /* Parse domain. */
    prev = pos;
    colon = strstr(pos, ":");
    qmark = strstr(pos, "?");
    slash = strstr(pos, "/");
    if (colon) {
        host_end = colon;
    } else if (slash) {
        host_end = slash;
    } else if (qmark) {
        host_end = qmark;
    } else {
        host_end = NULL;
    }

    if (host_end) {
        BSON_ASSERT(host_end >= prev);
        endpoint->domain = bson_strndup(prev, (size_t)(host_end - prev));
        BSON_ASSERT(host_end >= host_start);
        endpoint->host = bson_strndup(host_start, (size_t)(host_end - host_start));
    } else {
        endpoint->domain = bson_strdup(prev);
        endpoint->host = bson_strdup(host_start);
    }

    /* Parse optional port */
    if (colon) {
        prev = colon + 1;
        qmark = strstr(pos, "?");
        slash = strstr(pos, "/");
        if (slash) {
            endpoint->port = bson_strndup(prev, (size_t)(slash - prev));
        } else if (qmark) {
            BSON_ASSERT(qmark >= prev);
            endpoint->port = bson_strndup(prev, (size_t)(qmark - prev));
        } else {
            endpoint->port = bson_strdup(prev);
        }
    }

    /* Parse optional path */
    if (slash) {
        size_t path_len;

        prev = slash + 1;
        qmark = strstr(prev, "?");
        if (qmark) {
            endpoint->path = bson_strndup(prev, (size_t)(qmark - prev));
        } else {
            endpoint->path = bson_strdup(prev);
        }

        path_len = strlen(endpoint->path);
        /* Clear a trailing slash if it exists. */
        if (path_len > 0 && endpoint->path[path_len - 1] == '/') {
            endpoint->path[path_len - 1] = '\0';
        }
    }

    /* Parse optional query */
    if (qmark) {
        endpoint->query = bson_strdup(qmark + 1);
    }

    if (endpoint->port) {
        endpoint->host_and_port = bson_strdup_printf("%s:%s", endpoint->host, endpoint->port);
    } else {
        endpoint->host_and_port = bson_strdup(endpoint->host);
    }

    ok = true;
fail:
    if (!ok) {
        _mongocrypt_endpoint_destroy(endpoint);
        return NULL;
    }
    return endpoint;
}

_mongocrypt_endpoint_t *_mongocrypt_endpoint_copy(_mongocrypt_endpoint_t *src) {
    _mongocrypt_endpoint_t *endpoint;

    if (!src) {
        return NULL;
    }
    endpoint = bson_malloc0(sizeof(_mongocrypt_endpoint_t));
    endpoint->original = bson_strdup(src->original);
    endpoint->protocol = bson_strdup(src->protocol);
    endpoint->host = bson_strdup(src->host);
    endpoint->port = bson_strdup(src->port);
    endpoint->domain = bson_strdup(src->domain);
    endpoint->subdomain = bson_strdup(src->subdomain);
    endpoint->path = bson_strdup(src->path);
    endpoint->query = bson_strdup(src->query);
    endpoint->host_and_port = bson_strdup(src->host_and_port);
    return endpoint;
}

void _mongocrypt_apply_default_port(char **endpoint_raw, char *port) {
    BSON_ASSERT_PARAM(endpoint_raw);
    BSON_ASSERT_PARAM(port);
    BSON_ASSERT(*endpoint_raw);

    if (strstr(*endpoint_raw, ":") == NULL) {
        char *tmp = *endpoint_raw;
        *endpoint_raw = bson_strdup_printf("%s:%s", *endpoint_raw, port);
        bson_free(tmp);
    }
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-kek-private.h0000644000175100001660000000652014760300420021200 0ustar  /*
 * Copyright 2020-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_KEK_PRIVATE_H
#define MONGOCRYPT_KEK_PRIVATE_H

#include 

#include "mongocrypt-endpoint-private.h"
#include "mongocrypt.h"

/* Defines structs for Key Encryption Keys (KEKs)
 * The KEK is used as part of envelope encryption. It encrypts a Data Encryption
 * Key (DEK). A KEK is specified when creating a new data encryption key, or
 * when parsing a key document from the key vault.
 */

/* KMS providers are used in a bit set.
 *
 * Check for set membership using bitwise and:
 *   int kms_set = fn();
 *   if (kms_set & MONGOCRYPT_KMS_PROVIDER_AWS)
 * Add to a set using bitwise or:
 *   kms_set |= MONGOCRYPT_KMS_PROVIDER_LOCAL
 */
typedef enum {
    MONGOCRYPT_KMS_PROVIDER_NONE = 0,
    MONGOCRYPT_KMS_PROVIDER_AWS = 1 << 0,
    MONGOCRYPT_KMS_PROVIDER_LOCAL = 1 << 1,
    MONGOCRYPT_KMS_PROVIDER_AZURE = 1 << 2,
    MONGOCRYPT_KMS_PROVIDER_GCP = 1 << 3,
    MONGOCRYPT_KMS_PROVIDER_KMIP = 1 << 4
} _mongocrypt_kms_provider_t;

typedef struct {
    _mongocrypt_endpoint_t *key_vault_endpoint;
    char *key_name;
    char *key_version;
} _mongocrypt_azure_kek_t;

typedef struct {
    char *project_id;
    char *location;
    char *key_ring;
    char *key_name;
    char *key_version;                /* optional */
    _mongocrypt_endpoint_t *endpoint; /* optional. */
} _mongocrypt_gcp_kek_t;

typedef struct {
    char *region;
    char *cmk;
    _mongocrypt_endpoint_t *endpoint; /* optional. */
} _mongocrypt_aws_kek_t;

typedef struct {
    char *key_id;                     /* optional on parsing, required on appending. */
    _mongocrypt_endpoint_t *endpoint; /* optional. */
    bool delegated;
} _mongocrypt_kmip_kek_t;

typedef struct {
    _mongocrypt_kms_provider_t kms_provider;

    union {
        _mongocrypt_azure_kek_t azure;
        _mongocrypt_gcp_kek_t gcp;
        _mongocrypt_aws_kek_t aws;
        _mongocrypt_kmip_kek_t kmip;
    } provider;

    char *kmsid;
    const char *kmsid_name;
} _mongocrypt_kek_t;

/* Parse a document describing a key encryption key.
 * This may can come from two places:
 * 1. The option passed for creating a data key via
 * mongocrypt_ctx_setopt_key_encryption_key
 * 2. The "masterKey" document from a data encryption key document.
 */
bool _mongocrypt_kek_parse_owned(const bson_t *bson,
                                 _mongocrypt_kek_t *out,
                                 mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kek_append(const _mongocrypt_kek_t *kek,
                            bson_t *out,
                            mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

void _mongocrypt_kek_copy_to(const _mongocrypt_kek_t *src, _mongocrypt_kek_t *dst);

void _mongocrypt_kek_cleanup(_mongocrypt_kek_t *kek);

#endif /* MONGOCRYPT_KEK_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-kek.c0000644000175100001660000003174014760300420017525 0ustar  /*
 * Copyright 2020-present MongoDB, 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.
 */

#include "mongocrypt-kek-private.h"
#include "mongocrypt-opts-private.h"
#include "mongocrypt-private.h"

static bool _mongocrypt_azure_kek_parse(_mongocrypt_azure_kek_t *azure,
                                        const char *kmsid,
                                        const bson_t *def,
                                        mongocrypt_status_t *status) {
    if (!_mongocrypt_parse_required_endpoint(def,
                                             "keyVaultEndpoint",
                                             &azure->key_vault_endpoint,
                                             NULL /* opts */,
                                             status)) {
        return false;
    }

    if (!_mongocrypt_parse_required_utf8(def, "keyName", &azure->key_name, status)) {
        return false;
    }

    if (!_mongocrypt_parse_optional_utf8(def, "keyVersion", &azure->key_version, status)) {
        return false;
    }

    if (!_mongocrypt_check_allowed_fields(def,
                                          NULL /* root */,
                                          status,
                                          "provider",
                                          "keyVaultEndpoint",
                                          "keyName",
                                          "keyVersion")) {
        return false;
    }
    return true;
}

static bool _mongocrypt_gcp_kek_parse(_mongocrypt_gcp_kek_t *gcp,
                                      const char *kmsid,
                                      const bson_t *def,
                                      mongocrypt_status_t *status) {
    if (!_mongocrypt_parse_optional_endpoint(def, "endpoint", &gcp->endpoint, NULL /* opts */, status)) {
        return false;
    }

    if (!_mongocrypt_parse_required_utf8(def, "projectId", &gcp->project_id, status)) {
        return false;
    }

    if (!_mongocrypt_parse_required_utf8(def, "location", &gcp->location, status)) {
        return false;
    }

    if (!_mongocrypt_parse_required_utf8(def, "keyRing", &gcp->key_ring, status)) {
        return false;
    }

    if (!_mongocrypt_parse_required_utf8(def, "keyName", &gcp->key_name, status)) {
        return false;
    }

    if (!_mongocrypt_parse_optional_utf8(def, "keyVersion", &gcp->key_version, status)) {
        return false;
    }
    if (!_mongocrypt_check_allowed_fields(def,
                                          NULL,
                                          status,
                                          "provider",
                                          "endpoint",
                                          "projectId",
                                          "location",
                                          "keyRing",
                                          "keyName",
                                          "keyVersion")) {
        return false;
    }
    return true;
}

static bool _mongocrypt_aws_kek_parse(_mongocrypt_aws_kek_t *aws,
                                      const char *kmsid,
                                      const bson_t *def,
                                      mongocrypt_status_t *status) {
    if (!_mongocrypt_parse_required_utf8(def, "key", &aws->cmk, status)) {
        return false;
    }
    if (!_mongocrypt_parse_required_utf8(def, "region", &aws->region, status)) {
        return false;
    }
    if (!_mongocrypt_parse_optional_endpoint(def, "endpoint", &aws->endpoint, NULL /* opts */, status)) {
        return false;
    }
    if (!_mongocrypt_check_allowed_fields(def, NULL, status, "provider", "key", "region", "endpoint")) {
        return false;
    }

    return true;
}

static bool _mongocrypt_kmip_kek_parse(_mongocrypt_kmip_kek_t *kmip,
                                       const char *kmsid,
                                       const bson_t *def,
                                       mongocrypt_status_t *status) {
    _mongocrypt_endpoint_parse_opts_t opts = {0};

    opts.allow_empty_subdomain = true;
    if (!_mongocrypt_parse_optional_endpoint(def, "endpoint", &kmip->endpoint, &opts, status)) {
        return false;
    }

    if (!_mongocrypt_parse_optional_utf8(def, "keyId", &kmip->key_id, status)) {
        return false;
    }

    kmip->delegated = false;
    if (!_mongocrypt_parse_optional_bool(def, "delegated", &kmip->delegated, status)) {
        return false;
    }

    if (!_mongocrypt_check_allowed_fields(def, NULL, status, "provider", "endpoint", "keyId", "delegated")) {
        return false;
    }
    return true;
}

/* Possible documents to parse:
 * AWS
 *    provider: "aws"
 *    region: 
 *    key: 
 *    endpoint: 
 * Azure
 *    provider: "azure"
 *    keyVaultEndpoint: 
 *    keyName: 
 *    keyVersion: 
 * GCP
 *    provider: "gcp"
 *    projectId: 
 *    location: 
 *    keyRing: 
 *    keyName: 
 *    keyVersion: 
 *    endpoint: 
 * Local
 *    provider: "local"
 * KMIP
 *    provider: "kmip"
 *    keyId: 
 *    endpoint: 
 */
bool _mongocrypt_kek_parse_owned(const bson_t *bson, _mongocrypt_kek_t *kek, mongocrypt_status_t *status) {
    char *kms_provider = NULL;
    bool ret = false;

    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(kek);

    if (!_mongocrypt_parse_required_utf8(bson, "provider", &kms_provider, status)) {
        goto done;
    }

    kek->kmsid = bson_strdup(kms_provider);

    _mongocrypt_kms_provider_t type;
    if (!mc_kmsid_parse(kek->kmsid, &type, &kek->kmsid_name, status)) {
        goto done;
    }

    kek->kms_provider = type;
    switch (type) {
    default:
    case MONGOCRYPT_KMS_PROVIDER_NONE: {
        CLIENT_ERR("Unexpected parsing KMS type: none");
        goto done;
    }
    case MONGOCRYPT_KMS_PROVIDER_AWS: {
        if (!_mongocrypt_aws_kek_parse(&kek->provider.aws, kek->kmsid, bson, status)) {
            goto done;
        }
        break;
    }
    case MONGOCRYPT_KMS_PROVIDER_LOCAL: {
        if (!_mongocrypt_check_allowed_fields(bson, NULL, status, "provider")) {
            goto done;
        }
        break;
    }
    case MONGOCRYPT_KMS_PROVIDER_AZURE: {
        if (!_mongocrypt_azure_kek_parse(&kek->provider.azure, kek->kmsid, bson, status)) {
            goto done;
        }
        break;
    }
    case MONGOCRYPT_KMS_PROVIDER_GCP: {
        if (!_mongocrypt_gcp_kek_parse(&kek->provider.gcp, kek->kmsid, bson, status)) {
            goto done;
        }
        break;
    }
    case MONGOCRYPT_KMS_PROVIDER_KMIP: {
        if (!_mongocrypt_kmip_kek_parse(&kek->provider.kmip, kek->kmsid, bson, status)) {
            goto done;
        }
        break;
    }
    }

    ret = true;
done:
    bson_free(kms_provider);
    return ret;
}

bool _mongocrypt_kek_append(const _mongocrypt_kek_t *kek, bson_t *bson, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kek);
    BSON_ASSERT_PARAM(bson);

    BSON_APPEND_UTF8(bson, "provider", kek->kmsid);
    if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_AWS) {
        BSON_APPEND_UTF8(bson, "region", kek->provider.aws.region);
        BSON_APPEND_UTF8(bson, "key", kek->provider.aws.cmk);
        if (kek->provider.aws.endpoint) {
            BSON_APPEND_UTF8(bson, "endpoint", kek->provider.aws.endpoint->host_and_port);
        }
    } else if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_LOCAL) {
        // Only `provider` is needed.
    } else if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_AZURE) {
        BSON_APPEND_UTF8(bson, "keyVaultEndpoint", kek->provider.azure.key_vault_endpoint->host_and_port);
        BSON_APPEND_UTF8(bson, "keyName", kek->provider.azure.key_name);
        if (kek->provider.azure.key_version) {
            BSON_APPEND_UTF8(bson, "keyVersion", kek->provider.azure.key_version);
        }
    } else if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_GCP) {
        BSON_APPEND_UTF8(bson, "projectId", kek->provider.gcp.project_id);
        BSON_APPEND_UTF8(bson, "location", kek->provider.gcp.location);
        BSON_APPEND_UTF8(bson, "keyRing", kek->provider.gcp.key_ring);
        BSON_APPEND_UTF8(bson, "keyName", kek->provider.gcp.key_name);
        if (kek->provider.gcp.key_version) {
            BSON_APPEND_UTF8(bson, "keyVersion", kek->provider.gcp.key_version);
        }
        if (kek->provider.gcp.endpoint) {
            BSON_APPEND_UTF8(bson, "endpoint", kek->provider.gcp.endpoint->host_and_port);
        }
    } else if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_KMIP) {
        if (kek->provider.kmip.endpoint) {
            BSON_APPEND_UTF8(bson, "endpoint", kek->provider.kmip.endpoint->host_and_port);
        }

        if (kek->provider.kmip.delegated) {
            BSON_APPEND_BOOL(bson, "delegated", kek->provider.kmip.delegated);
        }

        /* "keyId" is required in the final data key document for the "kmip" KMS
         * provider. It may be set from the "kmip.keyId" in the BSON document set
         * in mongocrypt_ctx_setopt_key_encryption_key, Otherwise, libmongocrypt
         * is expected to set "keyId". */
        if (kek->provider.kmip.key_id) {
            BSON_APPEND_UTF8(bson, "keyId", kek->provider.kmip.key_id);
        } else {
            CLIENT_ERR("keyId required for KMIP");
            return false;
        }
    } else {
        BSON_ASSERT(kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_NONE);
    }
    return true;
}

void _mongocrypt_kek_copy_to(const _mongocrypt_kek_t *src, _mongocrypt_kek_t *dst) {
    BSON_ASSERT_PARAM(src);
    BSON_ASSERT_PARAM(dst);

    if (src->kms_provider == MONGOCRYPT_KMS_PROVIDER_AWS) {
        dst->provider.aws.cmk = bson_strdup(src->provider.aws.cmk);
        dst->provider.aws.region = bson_strdup(src->provider.aws.region);
        dst->provider.aws.endpoint = _mongocrypt_endpoint_copy(src->provider.aws.endpoint);
    } else if (src->kms_provider == MONGOCRYPT_KMS_PROVIDER_AZURE) {
        dst->provider.azure.key_vault_endpoint = _mongocrypt_endpoint_copy(src->provider.azure.key_vault_endpoint);
        dst->provider.azure.key_name = bson_strdup(src->provider.azure.key_name);
        dst->provider.azure.key_version = bson_strdup(src->provider.azure.key_version);
    } else if (src->kms_provider == MONGOCRYPT_KMS_PROVIDER_GCP) {
        dst->provider.gcp.project_id = bson_strdup(src->provider.gcp.project_id);
        dst->provider.gcp.location = bson_strdup(src->provider.gcp.location);
        dst->provider.gcp.key_ring = bson_strdup(src->provider.gcp.key_ring);
        dst->provider.gcp.key_name = bson_strdup(src->provider.gcp.key_name);
        dst->provider.gcp.key_version = bson_strdup(src->provider.gcp.key_version);
        dst->provider.gcp.endpoint = _mongocrypt_endpoint_copy(src->provider.gcp.endpoint);
    } else if (src->kms_provider == MONGOCRYPT_KMS_PROVIDER_KMIP) {
        dst->provider.kmip.endpoint = _mongocrypt_endpoint_copy(src->provider.kmip.endpoint);
        dst->provider.kmip.key_id = bson_strdup(src->provider.kmip.key_id);
        dst->provider.kmip.delegated = src->provider.kmip.delegated;
    } else {
        BSON_ASSERT(src->kms_provider == MONGOCRYPT_KMS_PROVIDER_NONE
                    || src->kms_provider == MONGOCRYPT_KMS_PROVIDER_LOCAL);
    }
    dst->kms_provider = src->kms_provider;
    dst->kmsid = bson_strdup(src->kmsid);
}

void _mongocrypt_kek_cleanup(_mongocrypt_kek_t *kek) {
    if (!kek) {
        return;
    }

    if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_AWS) {
        bson_free(kek->provider.aws.cmk);
        bson_free(kek->provider.aws.region);
        _mongocrypt_endpoint_destroy(kek->provider.aws.endpoint);
    } else if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_AZURE) {
        _mongocrypt_endpoint_destroy(kek->provider.azure.key_vault_endpoint);
        bson_free(kek->provider.azure.key_name);
        bson_free(kek->provider.azure.key_version);
    } else if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_GCP) {
        bson_free(kek->provider.gcp.project_id);
        bson_free(kek->provider.gcp.location);
        bson_free(kek->provider.gcp.key_ring);
        bson_free(kek->provider.gcp.key_name);
        bson_free(kek->provider.gcp.key_version);
        _mongocrypt_endpoint_destroy(kek->provider.gcp.endpoint);
    } else if (kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_KMIP) {
        bson_free(kek->provider.kmip.key_id);
        _mongocrypt_endpoint_destroy(kek->provider.kmip.endpoint);
    } else {
        BSON_ASSERT(kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_NONE
                    || kek->kms_provider == MONGOCRYPT_KMS_PROVIDER_LOCAL);
    }
    bson_free(kek->kmsid);
    return;
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-key-broker-private.h0000644000175100001660000001567014760300420022506 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_KEY_BROKER_PRIVATE_H
#define MONGOCRYPT_KEY_BROKER_PRIVATE_H

#include 

#include "kms_message/kms_message.h"
#include "mongocrypt-binary-private.h"
#include "mongocrypt-cache-key-private.h"
#include "mongocrypt-cache-private.h"
#include "mongocrypt-kms-ctx-private.h"
#include "mongocrypt-opts-private.h"
#include "mongocrypt.h"

/* The key broker acts as a middle-man between an encrypt/decrypt request and
 * the key cache.
 * Each encrypt/decrypt request has one key broker. Key brokers are not shared.
 * It is responsible for:
 * - keeping track of requested keys (either by id or keyAltName)
 * - copying keys from the cache to satisfy those requests
 * - generating find cmd filters to fetch keys that aren't cached or are expired
 * - generating KMS decrypt requests on newly fetched keys
 * - adding newly fetched keys back to the cache
 *
 * Notes:
 * - any key request that is satisfied stays satisfied.
 * - keys returned from the driver are validated to not have intersecting key
 * alt names (or duplicate ids).
 * - keys fetched from the cache are not validated, because the cache is shared
 * and locking only occurs on a single fetch (so it is possible to have two keys
 * fetched from the cache that have intersecting keyAltNames but a different
 * _id, and that is not an error)
 */

/* The state of the key broker. */
typedef enum {
    /* Starting state. Accept requests for keys to be added (either by id or
       name) */
    KB_REQUESTING,
    /* Accept key documents fetched from the key vault collection. */
    KB_ADDING_DOCS,
    /* Accept any key document fetched from the key vault collection. */
    KB_ADDING_DOCS_ANY,
    /* Getting oauth token(s) from KMS providers. */
    KB_AUTHENTICATING,
    /* Accept KMS replies to decrypt key material in each key document. */
    KB_DECRYPTING_KEY_MATERIAL,
    KB_DONE,
    KB_ERROR
} key_broker_state_t;

/* Represents a single request for a key, as indicated from a response
 * from mongocryptd. */
typedef struct _key_request_t {
    /* only one of id or alt_name are set. */
    _mongocrypt_buffer_t id;
    _mongocrypt_key_alt_name_t *alt_name;
    bool satisfied; /* true if satisfied by a cache entry or a key returned. */
    struct _key_request_t *next;
} key_request_t;

/* Represents a single key supplied from the driver or cache. */
typedef struct _key_returned_t {
    _mongocrypt_key_doc_t *doc;
    _mongocrypt_buffer_t decrypted_key_material;

    mongocrypt_kms_ctx_t kms;
    bool decrypted;

    bool needs_auth;

    struct _key_returned_t *next;
} key_returned_t;

typedef struct _mc_mapof_kmsid_to_authrequest_t mc_mapof_kmsid_to_authrequest_t;

typedef struct {
    key_broker_state_t state;
    mongocrypt_status_t *status;
    key_request_t *key_requests;
    /* Keep keys returned from driver separate from keys returned from cache.
     * Keys returned from driver MUST not have conflicts (e.g. intersecting key
     * alt names)
     * But keys from cache MAY have conflicts since the cache is only locked for
     * a single get operation.
     */
    key_returned_t *keys_returned;
    key_returned_t *keys_cached;
    _mongocrypt_buffer_t filter;
    mongocrypt_t *crypt;

    key_returned_t *decryptor_iter;
    mc_mapof_kmsid_to_authrequest_t *auth_requests;
} _mongocrypt_key_broker_t;

void _mongocrypt_key_broker_init(_mongocrypt_key_broker_t *kb, mongocrypt_t *crypt);

/* Add a request for a key by UUID. */
bool _mongocrypt_key_broker_request_id(_mongocrypt_key_broker_t *kb,
                                       const _mongocrypt_buffer_t *key_id) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Add keyAltName into the key broker.
   Key is added as KEY_EMPTY. */
bool _mongocrypt_key_broker_request_name(_mongocrypt_key_broker_t *kb,
                                         const bson_value_t *key_alt_name) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Switch mode to permit adding documents without prior requests. */
bool _mongocrypt_key_broker_request_any(_mongocrypt_key_broker_t *kb) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_key_broker_requests_done(_mongocrypt_key_broker_t *kb);

/* Get the find command filter. */
bool _mongocrypt_key_broker_filter(_mongocrypt_key_broker_t *kb,
                                   mongocrypt_binary_t *out) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Add a key document. */
bool _mongocrypt_key_broker_add_doc(_mongocrypt_key_broker_t *kb,
                                    _mongocrypt_opts_kms_providers_t *kms_providers,
                                    const _mongocrypt_buffer_t *doc) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_key_broker_docs_done(_mongocrypt_key_broker_t *kb);

/* Iterate the keys needing KMS decryption. */
mongocrypt_kms_ctx_t *_mongocrypt_key_broker_next_kms(_mongocrypt_key_broker_t *kb) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Indicate that all KMS requests are complete. */
bool _mongocrypt_key_broker_kms_done(_mongocrypt_key_broker_t *kb, _mongocrypt_opts_kms_providers_t *kms_providers);

/* Get the final decrypted key material from a key by looking up with a key_id.
 * @out is always initialized, even on error. */
bool _mongocrypt_key_broker_decrypted_key_by_id(_mongocrypt_key_broker_t *kb,
                                                const _mongocrypt_buffer_t *key_id,
                                                _mongocrypt_buffer_t *out) MONGOCRYPT_WARN_UNUSED_RESULT;

/* Get the final decrypted key material from a key, and optionally its key_id.
 * @key_id_out may be NULL. @out and @key_id_out (if not NULL) are always
 * initialized, even on error. */
bool _mongocrypt_key_broker_decrypted_key_by_name(_mongocrypt_key_broker_t *kb,
                                                  const bson_value_t *key_alt_name,
                                                  _mongocrypt_buffer_t *out,
                                                  _mongocrypt_buffer_t *key_id_out) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_key_broker_status(_mongocrypt_key_broker_t *kb, mongocrypt_status_t *out);

void _mongocrypt_key_broker_cleanup(_mongocrypt_key_broker_t *kb);

/* For testing only, add a decrypted key */
void _mongocrypt_key_broker_add_test_key(_mongocrypt_key_broker_t *kb, const _mongocrypt_buffer_t *key_id);

/* _mongocrypt_key_broker_restart is used to request additional keys. It must
 * only be called in the KB_DONE state. */
bool _mongocrypt_key_broker_restart(_mongocrypt_key_broker_t *kb);

#endif /* MONGOCRYPT_KEY_BROKER_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-key-broker.c0000644000175100001660000012531114760300420021023 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include "mc-array-private.h"
#include "mongocrypt-key-broker-private.h"
#include "mongocrypt-private.h"

typedef struct _auth_request_t {
    mongocrypt_kms_ctx_t kms;
    bool returned;
    char *kmsid;
} auth_request_t;

auth_request_t *auth_request_new() {
    return bson_malloc0(sizeof(auth_request_t));
}

void auth_request_destroy(auth_request_t *ar) {
    if (!ar) {
        return;
    }
    _mongocrypt_kms_ctx_cleanup(&ar->kms);
    bson_free(ar->kmsid);
    bson_free(ar);
}

struct _mc_mapof_kmsid_to_authrequest_t {
    mc_array_t entries;
};

mc_mapof_kmsid_to_authrequest_t *mc_mapof_kmsid_to_authrequest_new(void) {
    mc_mapof_kmsid_to_authrequest_t *k2a = bson_malloc0(sizeof(mc_mapof_kmsid_to_authrequest_t));
    _mc_array_init(&k2a->entries, sizeof(auth_request_t *));
    return k2a;
}

void mc_mapof_kmsid_to_authrequest_destroy(mc_mapof_kmsid_to_authrequest_t *k2a) {
    if (!k2a) {
        return;
    }
    for (size_t i = 0; i < k2a->entries.len; i++) {
        auth_request_t *ar = _mc_array_index(&k2a->entries, auth_request_t *, i);
        auth_request_destroy(ar);
    }
    _mc_array_destroy(&k2a->entries);
    bson_free(k2a);
}

bool mc_mapof_kmsid_to_authrequest_has(const mc_mapof_kmsid_to_authrequest_t *k2a, const char *kmsid) {
    BSON_ASSERT_PARAM(k2a);
    BSON_ASSERT_PARAM(kmsid);
    for (size_t i = 0; i < k2a->entries.len; i++) {
        auth_request_t *ar = _mc_array_index(&k2a->entries, auth_request_t *, i);
        if (0 == strcmp(ar->kmsid, kmsid)) {
            return true;
        }
    }
    return false;
}

size_t mc_mapof_kmsid_to_authrequest_len(const mc_mapof_kmsid_to_authrequest_t *k2a) {
    BSON_ASSERT_PARAM(k2a);
    return k2a->entries.len;
}

bool mc_mapof_kmsid_to_authrequest_empty(const mc_mapof_kmsid_to_authrequest_t *k2a) {
    BSON_ASSERT_PARAM(k2a);
    return k2a->entries.len == 0;
}

// `mc_mapof_kmsid_to_authrequest_put` moves `to_put` into the map and takes ownership of `to_put`.
// No checking is done to prohibit duplicate entries.
void mc_mapof_kmsid_to_authrequest_put(mc_mapof_kmsid_to_authrequest_t *k2a, auth_request_t *to_put) {
    BSON_ASSERT_PARAM(k2a);

    _mc_array_append_val(&k2a->entries, to_put);
}

auth_request_t *mc_mapof_kmsid_to_authrequest_at(mc_mapof_kmsid_to_authrequest_t *k2a, size_t i) {
    BSON_ASSERT_PARAM(k2a);

    return _mc_array_index(&k2a->entries, auth_request_t *, i);
}

void _mongocrypt_key_broker_init(_mongocrypt_key_broker_t *kb, mongocrypt_t *crypt) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(crypt);

    memset(kb, 0, sizeof(*kb));
    kb->crypt = crypt;
    kb->state = KB_REQUESTING;
    kb->status = mongocrypt_status_new();
    kb->auth_requests = mc_mapof_kmsid_to_authrequest_new();
}

/*
 * Creates a new key_returned_t and prepends it to a list.
 *
 * Side effects:
 * - updates *list to point to a new head.
 */
static key_returned_t *
_key_returned_prepend(_mongocrypt_key_broker_t *kb, key_returned_t **list, _mongocrypt_key_doc_t *key_doc) {
    key_returned_t *key_returned;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(list);
    BSON_ASSERT_PARAM(key_doc);

    key_returned = bson_malloc0(sizeof(*key_returned));
    BSON_ASSERT(key_returned);

    key_returned->doc = _mongocrypt_key_new();
    _mongocrypt_key_doc_copy_to(key_doc, key_returned->doc);

    /* Prepend and update the head of the list. */
    key_returned->next = *list;
    *list = key_returned;

    /* Update the head of the decrypting iter. */
    kb->decryptor_iter = kb->keys_returned;
    return key_returned;
}

/* Find the first (if any) key_returned_t matching either a key_id or a list of
 * key_alt_names (both are NULLable) */
static key_returned_t *
_key_returned_find_one(key_returned_t *list, _mongocrypt_buffer_t *key_id, _mongocrypt_key_alt_name_t *key_alt_names) {
    key_returned_t *key_returned;

    /* list can be NULL. */
    /* key_id and key_alt_names are not dereferenced in this function and they
     * are checked just before being passed on as parameters. */

    for (key_returned = list; NULL != key_returned; key_returned = key_returned->next) {
        if (key_id) {
            BSON_ASSERT(key_returned->doc);
            if (0 == _mongocrypt_buffer_cmp(key_id, &key_returned->doc->id)) {
                return key_returned;
            }
        }
        if (key_alt_names) {
            BSON_ASSERT(key_returned->doc);
            if (_mongocrypt_key_alt_name_intersects(key_alt_names, key_returned->doc->key_alt_names)) {
                return key_returned;
            }
        }
    }

    return NULL;
}

/* Find the first (if any) key_request_t in the key broker matching either a
 * key_id or a list of key_alt_names (both are NULLable) */
static key_request_t *_key_request_find_one(_mongocrypt_key_broker_t *kb,
                                            const _mongocrypt_buffer_t *key_id,
                                            _mongocrypt_key_alt_name_t *key_alt_names) {
    key_request_t *key_request;

    BSON_ASSERT_PARAM(kb);
    /* key_id and key_alt_names are not dereferenced in this function and they
     * are checked just before being passed on as parameters. */

    for (key_request = kb->key_requests; NULL != key_request; key_request = key_request->next) {
        if (key_id) {
            if (0 == _mongocrypt_buffer_cmp(key_id, &key_request->id)) {
                return key_request;
            }
        }
        if (key_alt_names) {
            if (_mongocrypt_key_alt_name_intersects(key_alt_names, key_request->alt_name)) {
                return key_request;
            }
        }
    }

    return NULL;
}

static bool _all_key_requests_satisfied(_mongocrypt_key_broker_t *kb) {
    key_request_t *key_request;

    BSON_ASSERT_PARAM(kb);

    for (key_request = kb->key_requests; NULL != key_request; key_request = key_request->next) {
        if (!key_request->satisfied) {
            return false;
        }
    }
    return true;
}

static bool _key_broker_fail_w_msg(_mongocrypt_key_broker_t *kb, const char *msg) {
    mongocrypt_status_t *status;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(msg);

    kb->state = KB_ERROR;
    status = kb->status;
    CLIENT_ERR("%s", msg);
    return false;
}

static bool _key_broker_fail(_mongocrypt_key_broker_t *kb) {
    BSON_ASSERT_PARAM(kb);

    if (mongocrypt_status_ok(kb->status)) {
        return _key_broker_fail_w_msg(kb, "unexpected, failing but no error status set");
    }
    kb->state = KB_ERROR;
    return false;
}

static bool _try_satisfying_from_cache(_mongocrypt_key_broker_t *kb, key_request_t *req) {
    _mongocrypt_cache_key_attr_t *attr = NULL;
    _mongocrypt_cache_key_value_t *value = NULL;
    bool ret = false;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(req);

    if (kb->state != KB_REQUESTING && kb->state != KB_ADDING_DOCS_ANY) {
        _key_broker_fail_w_msg(kb, "trying to retrieve key from cache in invalid state");
        goto cleanup;
    }

    attr = _mongocrypt_cache_key_attr_new(&req->id, req->alt_name);
    if (!_mongocrypt_cache_get(&kb->crypt->cache_key, attr, (void **)&value)) {
        _key_broker_fail_w_msg(kb, "failed to retrieve from cache");
        goto cleanup;
    }

    if (value) {
        key_returned_t *key_returned;

        req->satisfied = true;
        if (_mongocrypt_buffer_empty(&value->decrypted_key_material)) {
            _key_broker_fail_w_msg(kb, "cache entry does not have decrypted key material");
            goto cleanup;
        }

        /* Add the cached key to our locally copied list.
         * Note, we deduplicate requests, but *not* keys from the cache,
         * because the state of the cache may change between each call to
         * _mongocrypt_cache_get.
         */
        key_returned = _key_returned_prepend(kb, &kb->keys_cached, value->key_doc);
        _mongocrypt_buffer_init(&key_returned->decrypted_key_material);
        _mongocrypt_buffer_copy_to(&value->decrypted_key_material, &key_returned->decrypted_key_material);
        key_returned->decrypted = true;
    }

    ret = true;
cleanup:
    _mongocrypt_cache_key_value_destroy(value);
    _mongocrypt_cache_key_attr_destroy(attr);
    return ret;
}

static bool _store_to_cache(_mongocrypt_key_broker_t *kb, key_returned_t *key_returned) {
    _mongocrypt_cache_key_value_t *value;
    _mongocrypt_cache_key_attr_t *attr;
    bool ret;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(key_returned);

    if (!key_returned->decrypted) {
        return _key_broker_fail_w_msg(kb, "cannot cache non-decrypted key");
    }

    attr = _mongocrypt_cache_key_attr_new(&key_returned->doc->id, key_returned->doc->key_alt_names);
    if (!attr) {
        return _key_broker_fail_w_msg(kb, "could not create key cache attribute");
    }
    value = _mongocrypt_cache_key_value_new(key_returned->doc, &key_returned->decrypted_key_material);
    ret = _mongocrypt_cache_add_stolen(&kb->crypt->cache_key, attr, value, kb->status);
    _mongocrypt_cache_key_attr_destroy(attr);
    if (!ret) {
        return _key_broker_fail(kb);
    }
    return true;
}

bool _mongocrypt_key_broker_request_id(_mongocrypt_key_broker_t *kb, const _mongocrypt_buffer_t *key_id) {
    key_request_t *req;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(key_id);

    if (kb->state != KB_REQUESTING) {
        return _key_broker_fail_w_msg(kb, "attempting to request a key id, but in wrong state");
    }

    if (!_mongocrypt_buffer_is_uuid((_mongocrypt_buffer_t *)key_id)) {
        return _key_broker_fail_w_msg(kb, "expected UUID for key id");
    }

    if (_key_request_find_one(kb, key_id, NULL)) {
        return true;
    }

    req = bson_malloc0(sizeof *req);
    BSON_ASSERT(req);

    _mongocrypt_buffer_copy_to(key_id, &req->id);
    req->next = kb->key_requests;
    kb->key_requests = req;
    if (!_try_satisfying_from_cache(kb, req)) {
        return false;
    }
    return true;
}

bool _mongocrypt_key_broker_request_name(_mongocrypt_key_broker_t *kb, const bson_value_t *key_alt_name_value) {
    key_request_t *req;
    _mongocrypt_key_alt_name_t *key_alt_name;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(key_alt_name_value);

    if (kb->state != KB_REQUESTING) {
        return _key_broker_fail_w_msg(kb, "attempting to request a key name, but in wrong state");
    }

    key_alt_name = _mongocrypt_key_alt_name_new(key_alt_name_value);

    /* Check if we already have a request for this key alt name. */
    if (_key_request_find_one(kb, NULL /* key id */, key_alt_name)) {
        _mongocrypt_key_alt_name_destroy_all(key_alt_name);
        return true;
    }

    req = bson_malloc0(sizeof *req);
    BSON_ASSERT(req);

    req->alt_name = key_alt_name /* takes ownership */;
    req->next = kb->key_requests;
    kb->key_requests = req;
    if (!_try_satisfying_from_cache(kb, req)) {
        return false;
    }
    return true;
}

bool _mongocrypt_key_broker_request_any(_mongocrypt_key_broker_t *kb) {
    BSON_ASSERT_PARAM(kb);

    if (kb->state != KB_REQUESTING) {
        return _key_broker_fail_w_msg(kb, "attempting to request any keys, but in wrong state");
    }

    if (kb->key_requests) {
        return _key_broker_fail_w_msg(kb, "attempting to request any keys, but requests already made");
    }

    kb->state = KB_ADDING_DOCS_ANY;

    return true;
}

bool _mongocrypt_key_broker_requests_done(_mongocrypt_key_broker_t *kb) {
    BSON_ASSERT_PARAM(kb);

    if (kb->state != KB_REQUESTING) {
        return _key_broker_fail_w_msg(kb, "attempting to finish adding requests, but in wrong state");
    }

    if (kb->key_requests) {
        if (_all_key_requests_satisfied(kb)) {
            kb->state = KB_DONE;
        } else {
            kb->state = KB_ADDING_DOCS;
        }
    } else {
        kb->state = KB_DONE;
    }
    return true;
}

bool _mongocrypt_key_broker_filter(_mongocrypt_key_broker_t *kb, mongocrypt_binary_t *out) {
    key_request_t *req;
    _mongocrypt_key_alt_name_t *key_alt_name;
    int name_index = 0;
    int id_index = 0;
    bson_t ids, names;
    bson_t *filter;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(out);

    if (kb->state != KB_ADDING_DOCS) {
        return _key_broker_fail_w_msg(kb, "attempting to retrieve filter, but in wrong state");
    }

    if (!_mongocrypt_buffer_empty(&kb->filter)) {
        _mongocrypt_buffer_to_binary(&kb->filter, out);
        return true;
    }

    bson_init(&names);
    bson_init(&ids);

    for (req = kb->key_requests; NULL != req; req = req->next) {
        if (req->satisfied) {
            continue;
        }

        if (!_mongocrypt_buffer_empty(&req->id)) {
            /* Collect key_ids in "ids" */
            char *key_str;

            key_str = bson_strdup_printf("%d", id_index++);
            if (!key_str || !_mongocrypt_buffer_append(&req->id, &ids, key_str, -1)) {
                bson_destroy(&ids);
                bson_destroy(&names);
                bson_free(key_str);
                return _key_broker_fail_w_msg(kb, "could not construct id list");
            }

            bson_free(key_str);
        }

        /* Collect key alt names in "names" */
        for (key_alt_name = req->alt_name; NULL != key_alt_name; key_alt_name = key_alt_name->next) {
            char *key_str;

            key_str = bson_strdup_printf("%d", name_index++);
            BSON_ASSERT(key_str);
            if (!bson_append_value(&names, key_str, (int)strlen(key_str), &key_alt_name->value)) {
                bson_destroy(&ids);
                bson_destroy(&names);
                bson_free(key_str);
                return _key_broker_fail_w_msg(kb, "could not construct keyAltName list");
            }

            bson_free(key_str);
        }
    }

    /*
     * This is our final query:
     * { $or: [ { _id: { $in : [ids] }},
     *          { keyAltName : { $in : [names] }} ] }
     */
    filter = BCON_NEW("$or",
                      "[",
                      "{",
                      "_id",
                      "{",
                      "$in",
                      BCON_ARRAY(&ids),
                      "}",
                      "}",
                      "{",
                      "keyAltNames",
                      "{",
                      "$in",
                      BCON_ARRAY(&names),
                      "}",
                      "}",
                      "]");

    _mongocrypt_buffer_steal_from_bson(&kb->filter, filter);
    _mongocrypt_buffer_to_binary(&kb->filter, out);
    bson_destroy(&ids);
    bson_destroy(&names);

    return true;
}

bool _mongocrypt_key_broker_add_doc(_mongocrypt_key_broker_t *kb,
                                    _mongocrypt_opts_kms_providers_t *kms_providers,
                                    const _mongocrypt_buffer_t *doc) {
    bool ret = false;
    bson_t doc_bson;
    _mongocrypt_key_doc_t *key_doc = NULL;
    key_request_t *key_request;
    key_returned_t *key_returned;
    _mongocrypt_kms_provider_t kek_provider;
    char *access_token = NULL;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(kms_providers);

    if (kb->state != KB_ADDING_DOCS && kb->state != KB_ADDING_DOCS_ANY) {
        _key_broker_fail_w_msg(kb, "attempting to add a key doc, but in wrong state");
        goto done;
    }

    if (!doc) {
        _key_broker_fail_w_msg(kb, "invalid key");
        goto done;
    }

    /* First, parse the key document. */
    key_doc = _mongocrypt_key_new();
    if (!_mongocrypt_buffer_to_bson(doc, &doc_bson)) {
        _key_broker_fail_w_msg(kb, "malformed BSON for key document");
        goto done;
    }

    if (!_mongocrypt_key_parse_owned(&doc_bson, key_doc, kb->status)) {
        goto done;
    }

    if (!_key_request_find_one(kb, &key_doc->id, key_doc->key_alt_names)) {
        /* If in normal mode, ensure that this document matches at least one
         * existing request. */
        if (kb->state == KB_ADDING_DOCS) {
            _key_broker_fail_w_msg(kb, "unexpected key returned, does not match any requests");
            goto done;
        }

        /* If in any mode, add request for provided document now. */
        if (kb->state == KB_ADDING_DOCS_ANY) {
            key_request_t *const req = bson_malloc0(sizeof(key_request_t));

            BSON_ASSERT(req);

            _mongocrypt_buffer_copy_to(&key_doc->id, &req->id);
            req->alt_name = _mongocrypt_key_alt_name_copy_all(key_doc->key_alt_names);
            req->next = kb->key_requests;
            kb->key_requests = req;

            if (!_try_satisfying_from_cache(kb, req)) {
                goto done;
            }

            /* Key is already cached; no work to be done. */
            if (req->satisfied) {
                ret = true;
                goto done;
            }
        }
    }

    /* Check if there are other keys_returned with intersecting altnames or
     * equal id. This is an error. Do *not* check cached keys. */
    if (_key_returned_find_one(kb->keys_returned, &key_doc->id, key_doc->key_alt_names)) {
        _key_broker_fail_w_msg(kb, "keys returned have duplicate keyAltNames or _id");
        goto done;
    }

    key_returned = _key_returned_prepend(kb, &kb->keys_returned, key_doc);

    /* Check that the returned key doc's provider matches. */
    kek_provider = key_doc->kek.kms_provider;

    mc_kms_creds_t kc;
    if (!_mongocrypt_opts_kms_providers_lookup(kms_providers, key_doc->kek.kmsid, &kc)) {
        mongocrypt_status_t *status = kb->status;
        CLIENT_ERR("KMS provider `%s` is not configured", key_doc->kek.kmsid);
        _key_broker_fail(kb);
        goto done;
    }

    /* If the KMS provider is local, decrypt immediately. Otherwise, create the
     * HTTP KMS request. */
    BSON_ASSERT(kb->crypt);
    if (kek_provider == MONGOCRYPT_KMS_PROVIDER_LOCAL) {
        BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_LOCAL);
        if (!_mongocrypt_unwrap_key(kb->crypt->crypto,
                                    &kc.value.local.key,
                                    &key_returned->doc->key_material,
                                    &key_returned->decrypted_key_material,
                                    kb->status)) {
            _key_broker_fail(kb);
            goto done;
        }
        key_returned->decrypted = true;
        if (!_store_to_cache(kb, key_returned)) {
            goto done;
        }
    } else if (kek_provider == MONGOCRYPT_KMS_PROVIDER_AWS) {
        if (!_mongocrypt_kms_ctx_init_aws_decrypt(&key_returned->kms,
                                                  kms_providers,
                                                  key_doc,
                                                  kb->crypt->crypto,
                                                  key_doc->kek.kmsid,
                                                  &kb->crypt->log)) {
            mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
            _key_broker_fail(kb);
            goto done;
        }
    } else if (kek_provider == MONGOCRYPT_KMS_PROVIDER_AZURE) {
        BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_AZURE);
        if (kc.value.azure.access_token) {
            access_token = bson_strdup(kc.value.azure.access_token);
        } else {
            access_token = mc_mapof_kmsid_to_token_get_token(kb->crypt->cache_oauth, key_doc->kek.kmsid);
        }
        if (!access_token) {
            key_returned->needs_auth = true;
            /* Create an oauth request if one does not exist. */
            if (!mc_mapof_kmsid_to_authrequest_has(kb->auth_requests, key_doc->kek.kmsid)) {
                auth_request_t *ar = auth_request_new();
                if (!_mongocrypt_kms_ctx_init_azure_auth(&ar->kms,
                                                         &kc,
                                                         /* The key vault endpoint is used to determine the scope. */
                                                         key_doc->kek.provider.azure.key_vault_endpoint,
                                                         key_doc->kek.kmsid,
                                                         &kb->crypt->log)) {
                    mongocrypt_kms_ctx_status(&ar->kms, kb->status);
                    _key_broker_fail(kb);
                    auth_request_destroy(ar);
                    goto done;
                }
                ar->kmsid = bson_strdup(key_doc->kek.kmsid);
                mc_mapof_kmsid_to_authrequest_put(kb->auth_requests, ar);
            }
        } else {
            if (!_mongocrypt_kms_ctx_init_azure_unwrapkey(&key_returned->kms,
                                                          kms_providers,
                                                          access_token,
                                                          key_doc,
                                                          key_returned->doc->kek.kmsid,
                                                          &kb->crypt->log)) {
                mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                _key_broker_fail(kb);
                goto done;
            }
        }
    } else if (kek_provider == MONGOCRYPT_KMS_PROVIDER_GCP) {
        BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_GCP);
        if (NULL != kc.value.gcp.access_token) {
            access_token = bson_strdup(kc.value.gcp.access_token);
        } else {
            access_token = mc_mapof_kmsid_to_token_get_token(kb->crypt->cache_oauth, key_doc->kek.kmsid);
        }
        if (!access_token) {
            key_returned->needs_auth = true;
            /* Create an oauth request if one does not exist. */
            if (!mc_mapof_kmsid_to_authrequest_has(kb->auth_requests, key_doc->kek.kmsid)) {
                auth_request_t *ar = auth_request_new();
                if (!_mongocrypt_kms_ctx_init_gcp_auth(&ar->kms,
                                                       &kb->crypt->opts,
                                                       &kc,
                                                       key_doc->kek.provider.gcp.endpoint,
                                                       key_doc->kek.kmsid,
                                                       &kb->crypt->log)) {
                    mongocrypt_kms_ctx_status(&ar->kms, kb->status);
                    _key_broker_fail(kb);
                    auth_request_destroy(ar);
                    goto done;
                }
                ar->kmsid = bson_strdup(key_doc->kek.kmsid);
                mc_mapof_kmsid_to_authrequest_put(kb->auth_requests, ar);
            }
        } else {
            if (!_mongocrypt_kms_ctx_init_gcp_decrypt(&key_returned->kms,
                                                      kms_providers,
                                                      access_token,
                                                      key_doc,
                                                      key_returned->doc->kek.kmsid,
                                                      &kb->crypt->log)) {
                mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                _key_broker_fail(kb);
                goto done;
            }
        }
    } else if (kek_provider == MONGOCRYPT_KMS_PROVIDER_KMIP) {
        BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_KMIP);
        char *unique_identifier;
        _mongocrypt_endpoint_t *endpoint;

        if (!key_returned->doc->kek.provider.kmip.key_id) {
            _key_broker_fail_w_msg(kb, "KMIP key malformed, no keyId present");
            goto done;
        }

        unique_identifier = key_returned->doc->kek.provider.kmip.key_id;

        if (key_returned->doc->kek.provider.kmip.endpoint) {
            endpoint = key_returned->doc->kek.provider.kmip.endpoint;
        } else if (kc.value.kmip.endpoint) {
            endpoint = kc.value.kmip.endpoint;
        } else {
            _key_broker_fail_w_msg(kb, "endpoint not set for KMIP request");
            goto done;
        }

        if (key_returned->doc->kek.provider.kmip.delegated) {
            if (!_mongocrypt_kms_ctx_init_kmip_decrypt(&key_returned->kms,
                                                       endpoint,
                                                       key_doc->kek.kmsid,
                                                       key_doc,
                                                       &kb->crypt->log)) {
                mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                _key_broker_fail(kb);
                goto done;
            }
        } else {
            if (!_mongocrypt_kms_ctx_init_kmip_get(&key_returned->kms,
                                                   endpoint,
                                                   unique_identifier,
                                                   key_doc->kek.kmsid,
                                                   &kb->crypt->log)) {
                mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                _key_broker_fail(kb);
                goto done;
            }
        }
    } else {
        _key_broker_fail_w_msg(kb, "unrecognized kms provider");
        goto done;
    }

    /* Mark all matching key requests as satisfied. */
    for (key_request = kb->key_requests; NULL != key_request; key_request = key_request->next) {
        if (0 == _mongocrypt_buffer_cmp(&key_doc->id, &key_request->id)) {
            key_request->satisfied = true;
        }
        if (_mongocrypt_key_alt_name_intersects(key_doc->key_alt_names, key_request->alt_name)) {
            key_request->satisfied = true;
        }
    }

    ret = true;
done:
    bson_free(access_token);
    _mongocrypt_key_destroy(key_doc);
    return ret;
}

bool _mongocrypt_key_broker_docs_done(_mongocrypt_key_broker_t *kb) {
    key_returned_t *key_returned;
    bool needs_decryption;
    bool needs_auth;

    BSON_ASSERT_PARAM(kb);

    if (kb->state != KB_ADDING_DOCS && kb->state != KB_ADDING_DOCS_ANY) {
        return _key_broker_fail_w_msg(kb, "attempting to finish adding docs, but in wrong state");
    }

    /* If there are any requests left unsatisfied, error. */
    if (!_all_key_requests_satisfied(kb)) {
        return _key_broker_fail_w_msg(
            kb,
            "not all keys requested were satisfied. Verify that key vault DB/collection name was correctly specified.");
    }

    /* Transition to the next state.
     *  - If there are any Azure or GCP backed keys, and no oauth token is
     * cached, transition to KB_AUTHENTICATING.
     *  - Otherwise, if there are keys that need to be decrypted, transition to
     * KB_DECRYPTING_KEY_MATERIAL.
     *  - Otherwise, all keys were retrieved from the cache or decrypted locally,
     * skip the decrypting state and go right to KB_DONE.
     */
    needs_decryption = false;
    needs_auth = false;
    for (key_returned = kb->keys_returned; NULL != key_returned; key_returned = key_returned->next) {
        if (key_returned->needs_auth) {
            needs_auth = true;
            break;
        }
        if (!key_returned->decrypted) {
            needs_decryption = true;
        }
    }

    if (needs_auth) {
        kb->state = KB_AUTHENTICATING;
    } else if (needs_decryption) {
        kb->state = KB_DECRYPTING_KEY_MATERIAL;
    } else {
        kb->state = KB_DONE;
    }
    return true;
}

mongocrypt_kms_ctx_t *_mongocrypt_key_broker_next_kms(_mongocrypt_key_broker_t *kb) {
    BSON_ASSERT_PARAM(kb);

    if (kb->state != KB_DECRYPTING_KEY_MATERIAL && kb->state != KB_AUTHENTICATING) {
        _key_broker_fail_w_msg(kb, "attempting to get KMS request, but in wrong state");
        /* TODO (CDRIVER-3327) this breaks other expectations. If the caller only
         * checks the return value they may mistake this NULL as indicating all
         * KMS requests have been iterated. */
        return NULL;
    }

    if (kb->state == KB_AUTHENTICATING) {
        if (mc_mapof_kmsid_to_authrequest_empty(kb->auth_requests)) {
            _key_broker_fail_w_msg(kb,
                                   "unexpected, attempting to authenticate but "
                                   "KMS request not initialized");
            return NULL;
        }

        // Return the first not-yet-returned auth request.
        for (size_t i = 0; i < mc_mapof_kmsid_to_authrequest_len(kb->auth_requests); i++) {
            auth_request_t *ar = mc_mapof_kmsid_to_authrequest_at(kb->auth_requests, i);

            if (ar->kms.should_retry) {
                ar->kms.should_retry = false;
                ar->returned = true;
                return &ar->kms;
            }

            if (ar->returned) {
                continue;
            }
            ar->returned = true;
            return &ar->kms;
        }

        return NULL;
    }

    // Check if any requests need retry
    for (key_returned_t *ptr = kb->keys_returned; ptr != NULL; ptr = ptr->next) {
        if (ptr->kms.should_retry) {
            ptr->kms.should_retry = false;
            return &ptr->kms;
        }
    }
    while (kb->decryptor_iter) {
        if (!kb->decryptor_iter->decrypted) {
            key_returned_t *key_returned;

            key_returned = kb->decryptor_iter;
            /* iterate before returning, so next call starts at next entry */
            kb->decryptor_iter = kb->decryptor_iter->next;
            return &key_returned->kms;
        }
        kb->decryptor_iter = kb->decryptor_iter->next;
    }

    return NULL;
}

bool _mongocrypt_key_broker_kms_done(_mongocrypt_key_broker_t *kb, _mongocrypt_opts_kms_providers_t *kms_providers) {
    key_returned_t *key_returned;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(kms_providers);

    if (kb->state != KB_DECRYPTING_KEY_MATERIAL && kb->state != KB_AUTHENTICATING) {
        return _key_broker_fail_w_msg(kb, "attempting to complete KMS requests, but in wrong state");
    }

    if (kb->state == KB_AUTHENTICATING) {
        bson_t oauth_response;
        _mongocrypt_buffer_t oauth_response_buf;

        // Apply tokens from oauth responses to oauth token cache.
        for (size_t i = 0; i < mc_mapof_kmsid_to_authrequest_len(kb->auth_requests); i++) {
            auth_request_t *ar = mc_mapof_kmsid_to_authrequest_at(kb->auth_requests, i);

            if (!_mongocrypt_kms_ctx_result(&ar->kms, &oauth_response_buf)) {
                mongocrypt_kms_ctx_status(&ar->kms, kb->status);
                return _key_broker_fail(kb);
            }

            /* Cache returned tokens. */
            BSON_ASSERT(_mongocrypt_buffer_to_bson(&oauth_response_buf, &oauth_response));
            if (!mc_mapof_kmsid_to_token_add_response(kb->crypt->cache_oauth, ar->kmsid, &oauth_response, kb->status)) {
                return _key_broker_fail(kb);
            }
        }

        /* Auth should be finished, create any remaining KMS requests. */
        for (key_returned = kb->keys_returned; NULL != key_returned; key_returned = key_returned->next) {
            char *access_token;

            if (!key_returned->needs_auth) {
                continue;
            }

            mc_kms_creds_t kc;
            if (!_mongocrypt_opts_kms_providers_lookup(kms_providers, key_returned->doc->kek.kmsid, &kc)) {
                mongocrypt_status_t *status = kb->status;
                CLIENT_ERR("KMS provider `%s` is not configured", key_returned->doc->kek.kmsid);
                return _key_broker_fail(kb);
            }

            if (key_returned->doc->kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_AZURE) {
                BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_AZURE);
                if (kc.value.azure.access_token) {
                    access_token = bson_strdup(kc.value.azure.access_token);
                } else {
                    access_token =
                        mc_mapof_kmsid_to_token_get_token(kb->crypt->cache_oauth, key_returned->doc->kek.kmsid);
                }

                if (!access_token) {
                    return _key_broker_fail_w_msg(kb, "authentication failed, no oauth token");
                }

                if (!_mongocrypt_kms_ctx_init_azure_unwrapkey(&key_returned->kms,
                                                              kms_providers,
                                                              access_token,
                                                              key_returned->doc,
                                                              key_returned->doc->kek.kmsid,
                                                              &kb->crypt->log)) {
                    mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                    bson_free(access_token);
                    return _key_broker_fail(kb);
                }

                key_returned->needs_auth = false;
                bson_free(access_token);
            } else if (key_returned->doc->kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_GCP) {
                BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_GCP);
                if (kc.value.gcp.access_token) {
                    access_token = bson_strdup(kc.value.gcp.access_token);
                } else {
                    access_token =
                        mc_mapof_kmsid_to_token_get_token(kb->crypt->cache_oauth, key_returned->doc->kek.kmsid);
                }

                if (!access_token) {
                    return _key_broker_fail_w_msg(kb, "authentication failed, no oauth token");
                }

                if (!_mongocrypt_kms_ctx_init_gcp_decrypt(&key_returned->kms,
                                                          kms_providers,
                                                          access_token,
                                                          key_returned->doc,
                                                          key_returned->doc->kek.kmsid,
                                                          &kb->crypt->log)) {
                    mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                    bson_free(access_token);
                    return _key_broker_fail(kb);
                }

                key_returned->needs_auth = false;
                bson_free(access_token);
            } else {
                return _key_broker_fail_w_msg(kb,
                                              "unexpected, authenticating but "
                                              "no requests require "
                                              "authentication");
            }
        }

        kb->state = KB_DECRYPTING_KEY_MATERIAL;
        return true;
    }

    for (key_returned = kb->keys_returned; NULL != key_returned; key_returned = key_returned->next) {
        /* Local keys were already decrypted. */
        if (key_returned->doc->kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_AWS
            || key_returned->doc->kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_AZURE
            || key_returned->doc->kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_GCP) {
            if (key_returned->decrypted) {
                /* Non-local keys may have been decrypted previously if the key
                 * broker has been restarted. */
                continue;
            }

            if (!key_returned->kms.req) {
                return _key_broker_fail_w_msg(kb, "unexpected, KMS not set on key returned");
            }

            if (!_mongocrypt_kms_ctx_result(&key_returned->kms, &key_returned->decrypted_key_material)) {
                /* Always fatal. Key attempted to decrypt but failed. */
                mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                return _key_broker_fail(kb);
            }
        } else if (key_returned->doc->kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_KMIP) {
            _mongocrypt_buffer_t kek;
            if (!_mongocrypt_kms_ctx_result(&key_returned->kms, &kek)) {
                mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                return _key_broker_fail(kb);
            }

            if (key_returned->doc->kek.provider.kmip.delegated) {
                if (!_mongocrypt_kms_ctx_result(&key_returned->kms, &key_returned->decrypted_key_material)) {
                    mongocrypt_kms_ctx_status(&key_returned->kms, kb->status);
                    return _key_broker_fail(kb);
                }
            } else if (!_mongocrypt_unwrap_key(kb->crypt->crypto,
                                               &kek,
                                               &key_returned->doc->key_material,
                                               &key_returned->decrypted_key_material,
                                               kb->status)) {
                _key_broker_fail(kb);
                _mongocrypt_buffer_cleanup(&kek);
                return false;
            }
            _mongocrypt_buffer_cleanup(&kek);
        } else if (key_returned->doc->kek.kms_provider != MONGOCRYPT_KMS_PROVIDER_LOCAL) {
            return _key_broker_fail_w_msg(kb, "unrecognized kms provider");
        }

        if (key_returned->decrypted_key_material.len != MONGOCRYPT_KEY_LEN) {
            return _key_broker_fail_w_msg(kb, "decrypted key is incorrect length");
        }

        key_returned->decrypted = true;
        if (!_store_to_cache(kb, key_returned)) {
            return false;
        }
    }

    kb->state = KB_DONE;
    return true;
}

static bool _get_decrypted_key_material(_mongocrypt_key_broker_t *kb,
                                        _mongocrypt_buffer_t *key_id,
                                        _mongocrypt_key_alt_name_t *key_alt_name,
                                        _mongocrypt_buffer_t *out,
                                        _mongocrypt_buffer_t *key_id_out) {
    key_returned_t *key_returned;

    BSON_ASSERT_PARAM(kb);
    /* key_id can be NULL */
    /* key_alt_name can be NULL */
    BSON_ASSERT_PARAM(out);
    /* key_id_out is checked before each use, so it can be NULL */

    _mongocrypt_buffer_init(out);
    if (key_id_out) {
        _mongocrypt_buffer_init(key_id_out);
    }
    /* Search both keys_returned and keys_cached. */

    key_returned = _key_returned_find_one(kb->keys_returned, key_id, key_alt_name);
    if (!key_returned) {
        /* Try the keys retrieved from the cache. */
        key_returned = _key_returned_find_one(kb->keys_cached, key_id, key_alt_name);
    }

    if (!key_returned) {
        return _key_broker_fail_w_msg(kb, "could not find key");
    }

    if (!key_returned->decrypted) {
        return _key_broker_fail_w_msg(kb, "unexpected, key not decrypted");
    }

    _mongocrypt_buffer_copy_to(&key_returned->decrypted_key_material, out);
    if (key_id_out) {
        _mongocrypt_buffer_copy_to(&key_returned->doc->id, key_id_out);
    }
    return true;
}

bool _mongocrypt_key_broker_decrypted_key_by_id(_mongocrypt_key_broker_t *kb,
                                                const _mongocrypt_buffer_t *key_id,
                                                _mongocrypt_buffer_t *out) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(key_id);
    BSON_ASSERT_PARAM(out);

    if (kb->state != KB_DONE && kb->state != KB_REQUESTING) {
        return _key_broker_fail_w_msg(kb, "attempting retrieve decrypted key material, but in wrong state");
    }
    return _get_decrypted_key_material(kb,
                                       (_mongocrypt_buffer_t *)key_id,
                                       NULL /* key alt name */,
                                       out,
                                       NULL /* key id out */);
}

bool _mongocrypt_key_broker_decrypted_key_by_name(_mongocrypt_key_broker_t *kb,
                                                  const bson_value_t *key_alt_name_value,
                                                  _mongocrypt_buffer_t *out,
                                                  _mongocrypt_buffer_t *key_id_out) {
    bool ret;
    _mongocrypt_key_alt_name_t *key_alt_name;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(key_alt_name_value);
    BSON_ASSERT_PARAM(out);
    BSON_ASSERT_PARAM(key_id_out);

    if (kb->state != KB_DONE) {
        return _key_broker_fail_w_msg(kb, "attempting retrieve decrypted key material, but in wrong state");
    }

    key_alt_name = _mongocrypt_key_alt_name_new(key_alt_name_value);
    ret = _get_decrypted_key_material(kb, NULL, key_alt_name, out, key_id_out);
    _mongocrypt_key_alt_name_destroy_all(key_alt_name);
    return ret;
}

bool _mongocrypt_key_broker_status(_mongocrypt_key_broker_t *kb, mongocrypt_status_t *out) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(out);

    if (!mongocrypt_status_ok(kb->status)) {
        _mongocrypt_status_copy_to(kb->status, out);
        return false;
    }

    return true;
}

static void _destroy_key_requests(key_request_t *head) {
    key_request_t *tmp;

    while (head) {
        tmp = head->next;

        _mongocrypt_buffer_cleanup(&head->id);
        _mongocrypt_key_alt_name_destroy_all(head->alt_name);

        bson_free(head);
        head = tmp;
    }
}

static void _destroy_keys_returned(key_returned_t *head) {
    key_returned_t *tmp;

    while (head) {
        tmp = head->next;

        _mongocrypt_key_destroy(head->doc);
        _mongocrypt_buffer_cleanup(&head->decrypted_key_material);
        _mongocrypt_kms_ctx_cleanup(&head->kms);

        bson_free(head);
        head = tmp;
    }
}

void _mongocrypt_key_broker_cleanup(_mongocrypt_key_broker_t *kb) {
    if (!kb) {
        return;
    }
    mongocrypt_status_destroy(kb->status);
    _mongocrypt_buffer_cleanup(&kb->filter);
    /* Delete all linked lists */
    _destroy_keys_returned(kb->keys_returned);
    _destroy_keys_returned(kb->keys_cached);
    _destroy_key_requests(kb->key_requests);
    mc_mapof_kmsid_to_authrequest_destroy(kb->auth_requests);
}

void _mongocrypt_key_broker_add_test_key(_mongocrypt_key_broker_t *kb, const _mongocrypt_buffer_t *key_id) {
    key_returned_t *key_returned;
    _mongocrypt_key_doc_t *key_doc;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(key_id);

    key_doc = _mongocrypt_key_new();
    _mongocrypt_buffer_copy_to(key_id, &key_doc->id);

    key_returned = _key_returned_prepend(kb, &kb->keys_returned, key_doc);
    key_returned->decrypted = true;
    _mongocrypt_buffer_init(&key_returned->decrypted_key_material);
    _mongocrypt_buffer_resize(&key_returned->decrypted_key_material, MONGOCRYPT_KEY_LEN);
    // Initialize test key material with all zeros.
    memset(key_returned->decrypted_key_material.data, 0, MONGOCRYPT_KEY_LEN);
    _mongocrypt_key_destroy(key_doc);
    /* Hijack state and move directly to DONE. */
    kb->state = KB_DONE;
}

bool _mongocrypt_key_broker_restart(_mongocrypt_key_broker_t *kb) {
    BSON_ASSERT_PARAM(kb);
    if (kb->state != KB_DONE) {
        return _key_broker_fail_w_msg(kb, "_mongocrypt_key_broker_restart called in wrong state");
    }
    kb->state = KB_REQUESTING;
    _mongocrypt_buffer_cleanup(&kb->filter);
    _mongocrypt_buffer_init(&kb->filter);
    return true;
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-key-private.h0000644000175100001660000000654514760300420021225 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_KEY_PRIVATE_H
#define MONGOCRYPT_KEY_PRIVATE_H

#include "mongocrypt-buffer-private.h"
#include "mongocrypt-kek-private.h"
#include "mongocrypt-opts-private.h"

/* A linked list of key alt names */
typedef struct __mongocrypt_key_alt_name_t {
    struct __mongocrypt_key_alt_name_t *next;
    bson_value_t value;
} _mongocrypt_key_alt_name_t;

// `_mongocrypt_key_alt_name_t` inherits extended alignment from libbson. To dynamically allocate, use aligned
// allocation (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_key_alt_name_t,
                    BSON_ALIGNOF(_mongocrypt_key_alt_name_t) >= BSON_ALIGNOF(bson_value_t));

typedef struct {
    bson_t bson; /* original BSON for this key. */
    _mongocrypt_buffer_t id;
    _mongocrypt_key_alt_name_t *key_alt_names;
    _mongocrypt_buffer_t key_material;
    int64_t creation_date;
    int64_t update_date;
    _mongocrypt_kek_t kek;
} _mongocrypt_key_doc_t;

// `_mongocrypt_key_doc_t` inherits extended alignment from libbson. To dynamically allocate, use aligned allocation
// (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_key_doc_t, BSON_ALIGNOF(_mongocrypt_key_doc_t) >= BSON_ALIGNOF(bson_t));

_mongocrypt_key_alt_name_t *_mongocrypt_key_alt_name_new(const bson_value_t *value);

bool _mongocrypt_key_alt_name_from_iter(const bson_iter_t *iter,
                                        _mongocrypt_key_alt_name_t **out,
                                        mongocrypt_status_t *status);

_mongocrypt_key_alt_name_t *_mongocrypt_key_alt_name_copy_all(_mongocrypt_key_alt_name_t *list);
void _mongocrypt_key_alt_name_destroy_all(_mongocrypt_key_alt_name_t *list);
bool _mongocrypt_key_alt_name_intersects(_mongocrypt_key_alt_name_t *list_a, _mongocrypt_key_alt_name_t *list_b);
bool _mongocrypt_key_parse_owned(const bson_t *bson,
                                 _mongocrypt_key_doc_t *out,
                                 mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

_mongocrypt_key_doc_t *_mongocrypt_key_new(void);

void _mongocrypt_key_doc_copy_to(_mongocrypt_key_doc_t *src, _mongocrypt_key_doc_t *dst);

void _mongocrypt_key_destroy(_mongocrypt_key_doc_t *key);

const char *_mongocrypt_key_alt_name_get_string(_mongocrypt_key_alt_name_t *key_alt_name);

/* Begin: Functions for tests. */
/* Are the two lists equal without ordering.  */
bool _mongocrypt_key_alt_name_unique_list_equal(_mongocrypt_key_alt_name_t *list_a, _mongocrypt_key_alt_name_t *list_b);

/* For testing, construct a list of key alt names from variadic args */
_mongocrypt_key_alt_name_t *_mongocrypt_key_alt_name_create(const char *name, ...);
#define _MONGOCRYPT_KEY_ALT_NAME_CREATE(...) _mongocrypt_key_alt_name_create(__VA_ARGS__, NULL)
/* End: Functions for tests. */

#endif /* MONGOCRYPT_KEY_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-key.c0000644000175100001660000003036714760300420017547 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include "mongocrypt-key-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt-util-private.h" // mc_iter_document_as_bson

/* Check if two single entries are equal (i.e. ignore the 'next' pointer). */
static bool _one_key_alt_name_equal(_mongocrypt_key_alt_name_t *ptr_a, _mongocrypt_key_alt_name_t *ptr_b) {
    BSON_ASSERT_PARAM(ptr_a);
    BSON_ASSERT_PARAM(ptr_b);
    BSON_ASSERT(ptr_a->value.value_type == BSON_TYPE_UTF8);
    BSON_ASSERT(ptr_b->value.value_type == BSON_TYPE_UTF8);
    return 0 == strcmp(_mongocrypt_key_alt_name_get_string(ptr_a), _mongocrypt_key_alt_name_get_string(ptr_b));
}

static bool _find(_mongocrypt_key_alt_name_t *list, _mongocrypt_key_alt_name_t *entry) {
    BSON_ASSERT_PARAM(entry);

    for (; NULL != list; list = list->next) {
        if (_one_key_alt_name_equal(list, entry)) {
            return true;
        }
    }
    return false;
}

static uint32_t _list_len(_mongocrypt_key_alt_name_t *list) {
    uint32_t count = 0;

    while (NULL != list && count < UINT32_MAX) {
        count++;
        list = list->next;
    }
    return count;
}

static bool _check_unique(_mongocrypt_key_alt_name_t *list) {
    for (; NULL != list; list = list->next) {
        /* Check if we can find the current entry in the remaining. */
        if (_find(list->next, list)) {
            return false;
        }
    }
    return true;
}

static bool _parse_masterkey(bson_iter_t *iter, _mongocrypt_key_doc_t *out, mongocrypt_status_t *status) {
    bson_t kek_doc;

    BSON_ASSERT_PARAM(iter);
    BSON_ASSERT_PARAM(out);

    if (!BSON_ITER_HOLDS_DOCUMENT(iter)) {
        CLIENT_ERR("invalid 'masterKey', expected document");
        return false;
    }

    if (!mc_iter_document_as_bson(iter, &kek_doc, status)) {
        return false;
    }

    if (!_mongocrypt_kek_parse_owned(&kek_doc, &out->kek, status)) {
        return false;
    }
    return true;
}

bool _mongocrypt_key_alt_name_from_iter(const bson_iter_t *iter_in,
                                        _mongocrypt_key_alt_name_t **out,
                                        mongocrypt_status_t *status) {
    _mongocrypt_key_alt_name_t *key_alt_names = NULL, *tmp;
    bson_iter_t iter;

    BSON_ASSERT_PARAM(iter_in);
    BSON_ASSERT_PARAM(out);

    memcpy(&iter, iter_in, sizeof(iter));
    *out = NULL;

    /* A key parsed with no keyAltNames will have a zero'ed out bson value. Not
     * an error. */
    if (!BSON_ITER_HOLDS_ARRAY(&iter)) {
        CLIENT_ERR("malformed keyAltNames, expected array");
        return false;
    }

    if (!bson_iter_recurse(&iter, &iter)) {
        CLIENT_ERR("malformed keyAltNames, could not recurse into array");
        return false;
    }

    while (bson_iter_next(&iter)) {
        if (!BSON_ITER_HOLDS_UTF8(&iter)) {
            _mongocrypt_key_alt_name_destroy_all(key_alt_names);
            CLIENT_ERR("unexpected non-UTF8 keyAltName");
            return false;
        }

        tmp = _mongocrypt_key_alt_name_new(bson_iter_value(&iter));
        tmp->next = key_alt_names;
        key_alt_names = tmp;
    }

    if (!_check_unique(key_alt_names)) {
        _mongocrypt_key_alt_name_destroy_all(key_alt_names);
        CLIENT_ERR("unexpected duplicate keyAltNames");
        return false;
    }

    *out = key_alt_names;
    return true;
}

/* Takes ownership of all fields. */
bool _mongocrypt_key_parse_owned(const bson_t *bson, _mongocrypt_key_doc_t *out, mongocrypt_status_t *status) {
    bson_iter_t iter = {0};
    bool has_id = false, has_key_material = false, has_status = false, has_creation_date = false,
         has_update_date = false, has_master_key = false;

    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(out);

    if (!bson_validate(bson, BSON_VALIDATE_NONE, NULL) || !bson_iter_init(&iter, bson)) {
        CLIENT_ERR("invalid BSON");
        return false;
    }

    bson_destroy(&out->bson);
    bson_copy_to(bson, &out->bson);

    while (bson_iter_next(&iter)) {
        const char *field;

        field = bson_iter_key(&iter);
        if (!field) {
            CLIENT_ERR("invalid BSON, could not retrieve field name");
            return false;
        }
        if (0 == strcmp("_id", field)) {
            has_id = true;
            if (!_mongocrypt_buffer_copy_from_uuid_iter(&out->id, &iter)) {
                CLIENT_ERR("invalid key, '_id' is not a UUID");
                return false;
            }
            continue;
        }

        /* keyAltNames (optional) */
        if (0 == strcmp("keyAltNames", field)) {
            if (!_mongocrypt_key_alt_name_from_iter(&iter, &out->key_alt_names, status)) {
                return false;
            }
            continue;
        }

        if (0 == strcmp("keyMaterial", field)) {
            has_key_material = true;
            if (!_mongocrypt_buffer_copy_from_binary_iter(&out->key_material, &iter)) {
                CLIENT_ERR("invalid 'keyMaterial', expected binary");
                return false;
            }
            if (out->key_material.subtype != BSON_SUBTYPE_BINARY) {
                CLIENT_ERR("invalid 'keyMaterial', expected subtype 0");
                return false;
            }
            continue;
        }

        if (0 == strcmp("masterKey", field)) {
            has_master_key = true;
            if (!_parse_masterkey(&iter, out, status)) {
                return false;
            }
            continue;
        }

        if (0 == strcmp("version", field)) {
            if (!BSON_ITER_HOLDS_INT(&iter)) {
                CLIENT_ERR("invalid 'version', expect int");
                return false;
            }
            if (bson_iter_as_int64(&iter) != 0) {
                CLIENT_ERR("unsupported key document version, only supports version=0");
                return false;
            }
            continue;
        }

        if (0 == strcmp("status", field)) {
            /* Don't need status. Check that it's present and ignore it. */
            has_status = true;
            continue;
        }

        if (0 == strcmp("creationDate", field)) {
            has_creation_date = true;

            if (!BSON_ITER_HOLDS_DATE_TIME(&iter)) {
                CLIENT_ERR("invalid 'creationDate', expect datetime");
                return false;
            }

            out->creation_date = bson_iter_date_time(&iter);
            continue;
        }

        if (0 == strcmp("updateDate", field)) {
            has_update_date = true;

            if (!BSON_ITER_HOLDS_DATE_TIME(&iter)) {
                CLIENT_ERR("invalid 'updateDate', expect datetime");
                return false;
            }

            out->update_date = bson_iter_date_time(&iter);
            continue;
        }

        CLIENT_ERR("unrecognized field '%s'", field);
        return false;
    }

    /* Check that required fields were set. */
    if (!has_id) {
        CLIENT_ERR("invalid key, no '_id'");
        return false;
    }

    if (!has_master_key) {
        CLIENT_ERR("invalid key, no 'masterKey'");
        return false;
    }

    if (!has_key_material) {
        CLIENT_ERR("invalid key, no 'keyMaterial'");
        return false;
    }

    if (!has_status) {
        CLIENT_ERR("invalid key, no 'status'");
        return false;
    }

    if (!has_creation_date) {
        CLIENT_ERR("invalid key, no 'creationDate'");
        return false;
    }

    if (!has_update_date) {
        CLIENT_ERR("invalid key, no 'updateDate'");
        return false;
    }

    return true;
}

_mongocrypt_key_doc_t *_mongocrypt_key_new(void) {
    _mongocrypt_key_doc_t *key_doc;

    key_doc = BSON_ALIGNED_ALLOC(_mongocrypt_key_doc_t);
    // Use two sets of braces to avoid erroneous missing-braces warning in GCC. Refer:
    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
    *key_doc = (_mongocrypt_key_doc_t){{0}};
    bson_init(&key_doc->bson);

    return key_doc;
}

void _mongocrypt_key_destroy(_mongocrypt_key_doc_t *key) {
    if (!key) {
        return;
    }

    _mongocrypt_buffer_cleanup(&key->id);
    _mongocrypt_key_alt_name_destroy_all(key->key_alt_names);
    _mongocrypt_buffer_cleanup(&key->key_material);
    _mongocrypt_kek_cleanup(&key->kek);

    bson_destroy(&key->bson);
    bson_free(key);
}

void _mongocrypt_key_doc_copy_to(_mongocrypt_key_doc_t *src, _mongocrypt_key_doc_t *dst) {
    BSON_ASSERT_PARAM(src);
    BSON_ASSERT_PARAM(dst);

    _mongocrypt_buffer_copy_to(&src->id, &dst->id);
    _mongocrypt_buffer_copy_to(&src->key_material, &dst->key_material);
    dst->key_alt_names = _mongocrypt_key_alt_name_copy_all(src->key_alt_names);
    bson_destroy(&dst->bson);
    bson_copy_to(&src->bson, &dst->bson);
    _mongocrypt_kek_copy_to(&src->kek, &dst->kek);
    dst->creation_date = src->creation_date;
    dst->update_date = src->update_date;
}

_mongocrypt_key_alt_name_t *_mongocrypt_key_alt_name_copy_all(_mongocrypt_key_alt_name_t *ptr) {
    _mongocrypt_key_alt_name_t *ptr_copy = NULL, *head = NULL;

    while (ptr) {
        _mongocrypt_key_alt_name_t *copied;
        copied = bson_malloc0(sizeof(*copied));
        BSON_ASSERT(copied);

        bson_value_copy(&ptr->value, &copied->value);

        if (!ptr_copy) {
            ptr_copy = copied;
            head = ptr_copy;
        } else {
            ptr_copy->next = copied;
            ptr_copy = ptr_copy->next;
        }
        ptr = ptr->next;
    }
    return head;
}

void _mongocrypt_key_alt_name_destroy_all(_mongocrypt_key_alt_name_t *ptr) {
    _mongocrypt_key_alt_name_t *next;
    while (ptr) {
        next = ptr->next;
        bson_value_destroy(&ptr->value);
        bson_free(ptr);
        ptr = next;
    }
}

bool _mongocrypt_key_alt_name_intersects(_mongocrypt_key_alt_name_t *ptr_a, _mongocrypt_key_alt_name_t *ptr_b) {
    _mongocrypt_key_alt_name_t *orig_ptr_b = ptr_b;

    if (!ptr_a || !ptr_b) {
        return false;
    }

    for (; ptr_a; ptr_a = ptr_a->next) {
        for (ptr_b = orig_ptr_b; ptr_b; ptr_b = ptr_b->next) {
            if (_one_key_alt_name_equal(ptr_a, ptr_b)) {
                return true;
            }
        }
    }
    return false;
}

_mongocrypt_key_alt_name_t *_mongocrypt_key_alt_name_create(const char *name, ...) {
    va_list args;
    const char *arg_ptr;
    _mongocrypt_key_alt_name_t *head, *prev;

    head = NULL;
    prev = NULL;
    va_start(args, name);
    arg_ptr = name;
    while (arg_ptr) {
        _mongocrypt_key_alt_name_t *curr;

        curr = bson_malloc0(sizeof(*curr));
        BSON_ASSERT(curr);

        curr->value.value_type = BSON_TYPE_UTF8;
        curr->value.value.v_utf8.str = bson_strdup(arg_ptr);
        curr->value.value.v_utf8.len = (uint32_t)strlen(arg_ptr);
        if (!prev) {
            head = curr;
        } else {
            prev->next = curr;
        }

        arg_ptr = va_arg(args, const char *);
        prev = curr;
    }
    va_end(args);

    return head;
}

_mongocrypt_key_alt_name_t *_mongocrypt_key_alt_name_new(const bson_value_t *value) {
    BSON_ASSERT_PARAM(value);

    _mongocrypt_key_alt_name_t *name = BSON_ALIGNED_ALLOC(_mongocrypt_key_alt_name_t);
    *name = (_mongocrypt_key_alt_name_t){0};
    BSON_ASSERT(name);

    bson_value_copy(value, &name->value);
    return name;
}

bool _mongocrypt_key_alt_name_unique_list_equal(_mongocrypt_key_alt_name_t *list_a,
                                                _mongocrypt_key_alt_name_t *list_b) {
    _mongocrypt_key_alt_name_t *ptr;

    BSON_ASSERT(_check_unique(list_a));
    BSON_ASSERT(_check_unique(list_b));
    if (_list_len(list_a) != _list_len(list_b)) {
        return false;
    }
    for (ptr = list_a; NULL != ptr; ptr = ptr->next) {
        if (!_find(list_b, ptr)) {
            return false;
        }
    }
    return true;
}

const char *_mongocrypt_key_alt_name_get_string(_mongocrypt_key_alt_name_t *key_alt_name) {
    BSON_ASSERT_PARAM(key_alt_name);

    return key_alt_name->value.value.v_utf8.str;
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-kms-ctx-private.h0000644000175100001660000002025514760300420022015 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_KMX_CTX_PRIVATE_H
#define MONGOCRYPT_KMX_CTX_PRIVATE_H

#include "kms_message/kms_message.h"
#include "mongocrypt-buffer-private.h"
#include "mongocrypt-cache-key-private.h"
#include "mongocrypt-compat.h"
#include "mongocrypt-crypto-private.h"
#include "mongocrypt-endpoint-private.h"
#include "mongocrypt-key-private.h"
#include "mongocrypt-opts-private.h"
#include "mongocrypt.h"

struct __mongocrypt_ctx_opts_t;

typedef enum {
    MONGOCRYPT_KMS_AWS_ENCRYPT,
    MONGOCRYPT_KMS_AWS_DECRYPT,
    MONGOCRYPT_KMS_AZURE_OAUTH,
    MONGOCRYPT_KMS_AZURE_WRAPKEY,
    MONGOCRYPT_KMS_AZURE_UNWRAPKEY,
    MONGOCRYPT_KMS_GCP_OAUTH,
    MONGOCRYPT_KMS_GCP_ENCRYPT,
    MONGOCRYPT_KMS_GCP_DECRYPT,
    MONGOCRYPT_KMS_KMIP_REGISTER,
    MONGOCRYPT_KMS_KMIP_ACTIVATE,
    MONGOCRYPT_KMS_KMIP_GET,
    MONGOCRYPT_KMS_KMIP_CREATE,
    MONGOCRYPT_KMS_KMIP_ENCRYPT,
    MONGOCRYPT_KMS_KMIP_DECRYPT,
} _kms_request_type_t;

struct _mongocrypt_kms_ctx_t {
    kms_request_t *req;
    _kms_request_type_t req_type;
    kms_response_parser_t *parser;
    mongocrypt_status_t *status;
    _mongocrypt_buffer_t msg;
    _mongocrypt_buffer_t result;
    char *endpoint;
    _mongocrypt_log_t *log;
    char *kmsid;
    int64_t sleep_usec;
    int attempts;
    bool retry_enabled;
    bool should_retry;
};

static const int kms_max_attempts = 3;

bool _mongocrypt_kms_ctx_init_aws_decrypt(mongocrypt_kms_ctx_t *kms,
                                          _mongocrypt_opts_kms_providers_t *kms_providers,
                                          _mongocrypt_key_doc_t *key,
                                          _mongocrypt_crypto_t *crypto,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_aws_encrypt(mongocrypt_kms_ctx_t *kms,
                                          _mongocrypt_opts_kms_providers_t *kms_providers,
                                          struct __mongocrypt_ctx_opts_t *ctx_opts,
                                          _mongocrypt_buffer_t *decrypted_key_material,
                                          _mongocrypt_crypto_t *crypto,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_result(mongocrypt_kms_ctx_t *kms, _mongocrypt_buffer_t *out) MONGOCRYPT_WARN_UNUSED_RESULT;

void _mongocrypt_kms_ctx_cleanup(mongocrypt_kms_ctx_t *kms);

bool _mongocrypt_kms_ctx_init_azure_auth(mongocrypt_kms_ctx_t *kms,
                                         const mc_kms_creds_t *kc,
                                         _mongocrypt_endpoint_t *key_vault_endpoint,
                                         const char *kmsid,
                                         _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_azure_wrapkey(mongocrypt_kms_ctx_t *kms,
                                            _mongocrypt_opts_kms_providers_t *kms_providers,
                                            struct __mongocrypt_ctx_opts_t *ctx_opts,
                                            const char *access_token,
                                            _mongocrypt_buffer_t *plaintext_key_material,
                                            const char *kmsid,
                                            _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_azure_unwrapkey(mongocrypt_kms_ctx_t *kms,
                                              _mongocrypt_opts_kms_providers_t *kms_providers,
                                              const char *access_token,
                                              _mongocrypt_key_doc_t *key,
                                              const char *kmsid,
                                              _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_gcp_auth(mongocrypt_kms_ctx_t *kms,
                                       _mongocrypt_opts_t *crypt_opts,
                                       const mc_kms_creds_t *kc,
                                       _mongocrypt_endpoint_t *kms_endpoint,
                                       const char *kmsid,
                                       _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_gcp_encrypt(mongocrypt_kms_ctx_t *kms,
                                          _mongocrypt_opts_kms_providers_t *kms_providers,
                                          struct __mongocrypt_ctx_opts_t *ctx_opts,
                                          const char *access_token,
                                          _mongocrypt_buffer_t *plaintext_key_material,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_gcp_decrypt(mongocrypt_kms_ctx_t *kms,
                                          _mongocrypt_opts_kms_providers_t *kms_providers,
                                          const char *access_token,
                                          _mongocrypt_key_doc_t *key,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_kmip_register(mongocrypt_kms_ctx_t *kms,
                                            const _mongocrypt_endpoint_t *endpoint,
                                            const uint8_t *secretdata,
                                            uint32_t secretdata_len,

                                            const char *kmsid,
                                            _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_kmip_activate(mongocrypt_kms_ctx_t *kms,
                                            const _mongocrypt_endpoint_t *endpoint,
                                            const char *unique_identifier,
                                            const char *kmsid,
                                            _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_kmip_get(mongocrypt_kms_ctx_t *kms,
                                       const _mongocrypt_endpoint_t *endpoint,
                                       const char *unique_identifier,
                                       const char *kmsid,
                                       _mongocrypt_log_t *log) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_kms_ctx_init_kmip_create(mongocrypt_kms_ctx_t *kms,
                                          const _mongocrypt_endpoint_t *endpoint,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log);

bool _mongocrypt_kms_ctx_init_kmip_encrypt(mongocrypt_kms_ctx_t *kms,
                                           const _mongocrypt_endpoint_t *endpoint,
                                           const char *unique_identifier,
                                           const char *kmsid,
                                           _mongocrypt_buffer_t *plaintext,
                                           _mongocrypt_log_t *log);

bool _mongocrypt_kms_ctx_init_kmip_decrypt(mongocrypt_kms_ctx_t *kms,
                                           const _mongocrypt_endpoint_t *endpoint,
                                           const char *kmsid,
                                           _mongocrypt_key_doc_t *key,
                                           _mongocrypt_log_t *log);

#endif /* MONGOCRYPT_KMX_CTX_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-kms-ctx.c0000644000175100001660000021541614760300420020345 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include "kms_message/kms_kmip_request.h"
#include "mongocrypt-binary-private.h"
#include "mongocrypt-buffer-private.h"
#include "mongocrypt-crypto-private.h"
#include "mongocrypt-ctx-private.h"
#include "mongocrypt-endpoint-private.h"
#include "mongocrypt-kek-private.h"
#include "mongocrypt-kms-ctx-private.h"
#include "mongocrypt-log-private.h"
#include "mongocrypt-opts-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt-status-private.h"
#include "mongocrypt-util-private.h"
#include "mongocrypt.h"
#include 
#include 
#include 
#include 

/* Sadly, Windows does not define SSIZE_MAX. It is defined in bson-compat.h,
 * but only since 1.22.x, so copy this from bson-compat.h for now. */
#ifndef SSIZE_MAX
#define SSIZE_MAX (ssize_t)((((size_t)0x01u) << (sizeof(ssize_t) * (size_t)CHAR_BIT - 1u)) - 1u)
#endif

typedef struct {
    mongocrypt_status_t *status;
    void *ctx;
} ctx_with_status_t;

/* Before we've read the Content-Length header in an HTTP response,
 * we don't know how many bytes we'll need. So return this value
 * in kms_ctx_bytes_needed until we are fed the Content-Length.
 */
#define DEFAULT_MAX_KMS_BYTE_REQUEST 1024
#define SHA256_LEN 32
#define DEFAULT_HTTPS_PORT "443"
#define DEFAULT_KMIP_PORT "5696"

static bool _sha256(void *ctx, const char *input, size_t len, unsigned char *hash_out) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(input);
    BSON_ASSERT_PARAM(hash_out);

    bool ret;
    ctx_with_status_t *ctx_with_status = (ctx_with_status_t *)ctx;
    _mongocrypt_crypto_t *crypto;
    mongocrypt_binary_t *plaintext, *out;

    crypto = (_mongocrypt_crypto_t *)ctx_with_status->ctx;
    BSON_ASSERT(crypto);
    BSON_ASSERT(len <= UINT32_MAX);
    plaintext = mongocrypt_binary_new_from_data((uint8_t *)input, (uint32_t)len);
    out = mongocrypt_binary_new();

    out->data = hash_out;
    out->len = SHA256_LEN;

    ret = crypto->sha_256(crypto->ctx, plaintext, out, ctx_with_status->status);

    mongocrypt_binary_destroy(plaintext);
    mongocrypt_binary_destroy(out);
    return ret;
}

static bool
_sha256_hmac(void *ctx, const char *key_input, size_t key_len, const char *input, size_t len, unsigned char *hash_out) {
    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(key_input);
    BSON_ASSERT_PARAM(input);
    BSON_ASSERT_PARAM(hash_out);

    ctx_with_status_t *ctx_with_status = (ctx_with_status_t *)ctx;
    _mongocrypt_crypto_t *crypto;
    mongocrypt_binary_t *key, *plaintext, *out;
    bool ret;

    crypto = (_mongocrypt_crypto_t *)ctx_with_status->ctx;
    BSON_ASSERT(crypto);

    BSON_ASSERT(key_len <= UINT32_MAX);
    key = mongocrypt_binary_new_from_data((uint8_t *)key_input, (uint32_t)key_len);
    BSON_ASSERT(len <= UINT32_MAX);
    plaintext = mongocrypt_binary_new_from_data((uint8_t *)input, (uint32_t)len);
    out = mongocrypt_binary_new();

    out->data = hash_out;
    out->len = SHA256_LEN;

    ret = crypto->hmac_sha_256(crypto->ctx, key, plaintext, out, ctx_with_status->status);

    mongocrypt_binary_destroy(key);
    mongocrypt_binary_destroy(plaintext);
    mongocrypt_binary_destroy(out);
    return ret;
}

static void
_set_kms_crypto_hooks(_mongocrypt_crypto_t *crypto, ctx_with_status_t *ctx_with_status, kms_request_opt_t *opts) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(ctx_with_status);
    BSON_ASSERT_PARAM(opts);

    if (crypto->hooks_enabled) {
        kms_request_opt_set_crypto_hooks(opts, _sha256, _sha256_hmac, ctx_with_status);
    }
}

static bool is_kms(_kms_request_type_t kms_type) {
    return kms_type == MONGOCRYPT_KMS_KMIP_REGISTER || kms_type == MONGOCRYPT_KMS_KMIP_ACTIVATE
        || kms_type == MONGOCRYPT_KMS_KMIP_GET || kms_type == MONGOCRYPT_KMS_KMIP_ENCRYPT
        || kms_type == MONGOCRYPT_KMS_KMIP_DECRYPT || kms_type == MONGOCRYPT_KMS_KMIP_CREATE;
}

static void
_init_common(mongocrypt_kms_ctx_t *kms, _mongocrypt_log_t *log, _kms_request_type_t kms_type, const char *kmsid) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(kmsid);

    kms->kmsid = bson_strdup(kmsid);

    if (is_kms(kms_type)) {
        kms->parser = kms_kmip_response_parser_new(NULL /* reserved */);
    } else {
        kms->parser = kms_response_parser_new();
    }
    kms->log = log;
    kms->status = mongocrypt_status_new();
    kms->req_type = kms_type;
    _mongocrypt_buffer_init(&kms->result);
    kms->sleep_usec = 0;
    kms->attempts = 0;
    kms->should_retry = false;
}

bool _mongocrypt_kms_ctx_init_aws_decrypt(mongocrypt_kms_ctx_t *kms,
                                          _mongocrypt_opts_kms_providers_t *kms_providers,
                                          _mongocrypt_key_doc_t *key,
                                          _mongocrypt_crypto_t *crypto,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(key);
    BSON_ASSERT_PARAM(kms_providers);
    BSON_ASSERT_PARAM(crypto);

    kms_request_opt_t *opt;
    mongocrypt_status_t *status;
    ctx_with_status_t ctx_with_status;
    bool ret = false;

    _init_common(kms, log, MONGOCRYPT_KMS_AWS_DECRYPT, kmsid);
    status = kms->status;
    ctx_with_status.ctx = crypto;
    ctx_with_status.status = mongocrypt_status_new();

    if (!key->kek.kms_provider) {
        CLIENT_ERR("no kms provider specified on key");
        goto done;
    }

    if (MONGOCRYPT_KMS_PROVIDER_AWS != key->kek.kms_provider) {
        CLIENT_ERR("expected aws kms provider");
        goto done;
    }

    if (!key->kek.provider.aws.region) {
        CLIENT_ERR("no key region provided");
        goto done;
    }

    mc_kms_creds_t kc;
    if (!_mongocrypt_opts_kms_providers_lookup(kms_providers, key->kek.kmsid, &kc)) {
        CLIENT_ERR("KMS provider `%s` is not configured", key->kek.kmsid);
        goto done;
    }
    BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_AWS);

    if (!kc.value.aws.access_key_id) {
        CLIENT_ERR("aws access key id not provided");
        goto done;
    }

    if (!kc.value.aws.secret_access_key) {
        CLIENT_ERR("aws secret access key not provided");
        goto done;
    }

    /* create the KMS request. */
    opt = kms_request_opt_new();
    BSON_ASSERT(opt);

    _set_kms_crypto_hooks(crypto, &ctx_with_status, opt);
    kms_request_opt_set_connection_close(opt, true);

    kms->req = kms_decrypt_request_new(key->key_material.data, key->key_material.len, opt);

    kms_request_opt_destroy(opt);
    if (!kms_request_set_service(kms->req, "kms")) {
        CLIENT_ERR("failed to set service: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }

    if (kc.value.aws.session_token) {
        if (!kms_request_add_header_field(kms->req, "X-Amz-Security-Token", kc.value.aws.session_token)) {
            CLIENT_ERR("failed to set session token: %s", kms_request_get_error(kms->req));
            _mongocrypt_status_append(status, ctx_with_status.status);
            goto done;
        }
    }

    if (kms_request_get_error(kms->req)) {
        CLIENT_ERR("error constructing KMS message: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }

    /* If an endpoint was set, override the default Host header. */
    if (key->kek.provider.aws.endpoint) {
        if (!kms_request_add_header_field(kms->req, "Host", key->kek.provider.aws.endpoint->host_and_port)) {
            CLIENT_ERR("error constructing KMS message: %s", kms_request_get_error(kms->req));
            _mongocrypt_status_append(status, ctx_with_status.status);
            goto done;
        }
    }

    if (!kms_request_set_region(kms->req, key->kek.provider.aws.region)) {
        CLIENT_ERR("failed to set region: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }

    if (!kms_request_set_access_key_id(kms->req, kc.value.aws.access_key_id)) {
        CLIENT_ERR("failed to set aws access key id: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }
    if (!kms_request_set_secret_key(kms->req, kc.value.aws.secret_access_key)) {
        CLIENT_ERR("failed to set aws secret access key: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }

    _mongocrypt_buffer_init(&kms->msg);
    kms->msg.data = (uint8_t *)kms_request_get_signed(kms->req);
    if (!kms->msg.data) {
        CLIENT_ERR("failed to create KMS message: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }
    kms->msg.len = (uint32_t)strlen((char *)kms->msg.data);
    kms->msg.owned = true;

    if (key->kek.provider.aws.endpoint) {
        kms->endpoint = bson_strdup(key->kek.provider.aws.endpoint->host_and_port);
    } else {
        /* construct the endpoint from AWS region. */
        kms->endpoint = bson_strdup_printf("kms.%s.amazonaws.com", key->kek.provider.aws.region);
    }
    _mongocrypt_apply_default_port(&kms->endpoint, DEFAULT_HTTPS_PORT);

    ret = true;
done:
    mongocrypt_status_destroy(ctx_with_status.status);

    return ret;
}

bool _mongocrypt_kms_ctx_init_aws_encrypt(mongocrypt_kms_ctx_t *kms,
                                          _mongocrypt_opts_kms_providers_t *kms_providers,
                                          _mongocrypt_ctx_opts_t *ctx_opts,
                                          _mongocrypt_buffer_t *plaintext_key_material,
                                          _mongocrypt_crypto_t *crypto,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(ctx_opts);
    BSON_ASSERT_PARAM(kms_providers);
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(plaintext_key_material);

    kms_request_opt_t *opt;
    mongocrypt_status_t *status;
    ctx_with_status_t ctx_with_status;
    bool ret = false;

    _init_common(kms, log, MONGOCRYPT_KMS_AWS_ENCRYPT, kmsid);
    status = kms->status;
    ctx_with_status.ctx = crypto;
    ctx_with_status.status = mongocrypt_status_new();

    if (MONGOCRYPT_KMS_PROVIDER_AWS != ctx_opts->kek.kms_provider) {
        CLIENT_ERR("expected aws kms provider");
        goto done;
    }

    if (!ctx_opts->kek.provider.aws.region) {
        CLIENT_ERR("no key region provided");
        goto done;
    }

    if (!ctx_opts->kek.provider.aws.cmk) {
        CLIENT_ERR("no aws cmk provided");
        goto done;
    }

    mc_kms_creds_t kc;
    if (!_mongocrypt_opts_kms_providers_lookup(kms_providers, ctx_opts->kek.kmsid, &kc)) {
        CLIENT_ERR("KMS provider `%s` is not configured", ctx_opts->kek.kmsid);
        goto done;
    }
    BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_AWS);

    if (!kc.value.aws.access_key_id) {
        CLIENT_ERR("aws access key id not provided");
        goto done;
    }

    if (!kc.value.aws.secret_access_key) {
        CLIENT_ERR("aws secret access key not provided");
        goto done;
    }

    /* create the KMS request. */
    opt = kms_request_opt_new();
    BSON_ASSERT(opt);

    _set_kms_crypto_hooks(crypto, &ctx_with_status, opt);
    kms_request_opt_set_connection_close(opt, true);

    kms->req = kms_encrypt_request_new(plaintext_key_material->data,
                                       plaintext_key_material->len,
                                       ctx_opts->kek.provider.aws.cmk,
                                       opt);

    kms_request_opt_destroy(opt);
    if (!kms_request_set_service(kms->req, "kms")) {
        CLIENT_ERR("failed to set service: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }

    if (kc.value.aws.session_token) {
        if (!kms_request_add_header_field(kms->req, "X-Amz-Security-Token", kc.value.aws.session_token)) {
            CLIENT_ERR("failed to set session token: %s", kms_request_get_error(kms->req));
            _mongocrypt_status_append(status, ctx_with_status.status);
            goto done;
        }
    }

    if (kms_request_get_error(kms->req)) {
        CLIENT_ERR("error constructing KMS message: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }

    /* If an endpoint was set, override the default Host header. */
    if (ctx_opts->kek.provider.aws.endpoint) {
        if (!kms_request_add_header_field(kms->req, "Host", ctx_opts->kek.provider.aws.endpoint->host)) {
            CLIENT_ERR("error constructing KMS message: %s", kms_request_get_error(kms->req));
            _mongocrypt_status_append(status, ctx_with_status.status);
            goto done;
        }
    }

    if (!kms_request_set_region(kms->req, ctx_opts->kek.provider.aws.region)) {
        CLIENT_ERR("failed to set region: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }

    if (!kms_request_set_access_key_id(kms->req, kc.value.aws.access_key_id)) {
        CLIENT_ERR("failed to set aws access key id: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }
    if (!kms_request_set_secret_key(kms->req, kc.value.aws.secret_access_key)) {
        CLIENT_ERR("failed to set aws secret access key: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }

    _mongocrypt_buffer_init(&kms->msg);
    kms->msg.data = (uint8_t *)kms_request_get_signed(kms->req);
    if (!kms->msg.data) {
        CLIENT_ERR("failed to create KMS message: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto done;
    }
    kms->msg.len = (uint32_t)strlen((char *)kms->msg.data);
    kms->msg.owned = true;

    /* construct the endpoint */
    if (ctx_opts->kek.provider.aws.endpoint) {
        kms->endpoint = bson_strdup(ctx_opts->kek.provider.aws.endpoint->host_and_port);
    } else {
        kms->endpoint = bson_strdup_printf("kms.%s.amazonaws.com", ctx_opts->kek.provider.aws.region);
    }
    _mongocrypt_apply_default_port(&kms->endpoint, DEFAULT_HTTPS_PORT);

    ret = true;
done:
    mongocrypt_status_destroy(ctx_with_status.status);
    return ret;
}

uint32_t mongocrypt_kms_ctx_bytes_needed(mongocrypt_kms_ctx_t *kms) {
    int want_bytes;

    if (!kms) {
        return 0;
    }
    /* TODO: an oddity of kms-message. After retrieving the result, it
     * resets the parser. */
    if (!mongocrypt_status_ok(kms->status) || !_mongocrypt_buffer_empty(&kms->result)) {
        return 0;
    }
    if (kms->should_retry) {
        return 0;
    }
    want_bytes = kms_response_parser_wants_bytes(kms->parser, DEFAULT_MAX_KMS_BYTE_REQUEST);
    BSON_ASSERT(want_bytes >= 0);
    return (uint32_t)want_bytes;
}

int64_t mongocrypt_kms_ctx_usleep(mongocrypt_kms_ctx_t *kms) {
    if (!kms) {
        return 0;
    }
    return kms->sleep_usec;
}

static void
_handle_non200_http_status(int http_status, const char *body, size_t body_len, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(body);

    /* 1xx, 2xx, and 3xx HTTP status codes are not errors, but we only
     * support handling 200 response. */
    if (http_status < 400) {
        CLIENT_ERR("Unsupported HTTP code in KMS response. HTTP status=%d. "
                   "Response body=\n%s",
                   http_status,
                   body);
        return;
    }

    /* Either empty body or body containing JSON with error message. */
    if (body_len == 0) {
        CLIENT_ERR("Error in KMS response. HTTP status=%d. Empty body.", http_status);
        return;
    }

    CLIENT_ERR("Error in KMS response. HTTP status=%d. Response body=\n%s", http_status, body);
}

static int64_t backoff_time_usec(int64_t attempts) {
    static bool seeded = false;
    if (!seeded) {
        srand((uint32_t)time(NULL));
        seeded = true;
    }

    /* Exponential backoff with jitter. */
    const int64_t base = 200000;  /* 0.2 seconds */
    const int64_t max = 20000000; /* 20 seconds */
    BSON_ASSERT(attempts > 0);
    int64_t backoff = base * ((int64_t)1 << (attempts - 1));
    if (backoff > max) {
        backoff = max;
    }

    /* Full jitter: between 1 and current max */
    return (int64_t)((double)rand() / (double)RAND_MAX * (double)backoff) + 1;
}

static bool should_retry_http(int http_status, _kms_request_type_t t) {
    static const int retryable_aws[] = {408, 429, 500, 502, 503, 509};
    static const int retryable_azure[] = {408, 429, 500, 502, 503, 504};
    if (t == MONGOCRYPT_KMS_AWS_ENCRYPT || t == MONGOCRYPT_KMS_AWS_DECRYPT) {
        for (size_t i = 0; i < sizeof(retryable_aws) / sizeof(retryable_aws[0]); i++) {
            if (http_status == retryable_aws[i]) {
                return true;
            }
        }
    } else if (t == MONGOCRYPT_KMS_AZURE_WRAPKEY || t == MONGOCRYPT_KMS_AZURE_UNWRAPKEY
               || t == MONGOCRYPT_KMS_AZURE_OAUTH) {
        for (size_t i = 0; i < sizeof(retryable_azure) / sizeof(retryable_azure[0]); i++) {
            if (http_status == retryable_azure[i]) {
                return true;
            }
        }
    } else if (t == MONGOCRYPT_KMS_GCP_ENCRYPT || t == MONGOCRYPT_KMS_GCP_DECRYPT || t == MONGOCRYPT_KMS_GCP_OAUTH) {
        if (http_status == 408 || http_status == 429 || http_status / 500 == 1) {
            return true;
        }
    }
    return false;
}

static void set_retry(mongocrypt_kms_ctx_t *kms) {
    kms->should_retry = true;
    kms->attempts++;
    kms->sleep_usec = backoff_time_usec(kms->attempts);
}

/* An AWS KMS context has received full response. Parse out the result or error.
 */
static bool _ctx_done_aws(mongocrypt_kms_ctx_t *kms, const char *json_field) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(json_field);

    kms_response_t *response = NULL;
    const char *body;
    bson_t body_bson = BSON_INITIALIZER;
    bool ret;
    bson_error_t bson_error;
    bson_iter_t iter;
    uint32_t b64_strlen;
    char *b64_str;
    int http_status;
    size_t body_len;
    int result_len;
    mongocrypt_status_t *status;

    status = kms->status;
    ret = false;
    /* Parse out the {en|de}crypted result. */
    http_status = kms_response_parser_status(kms->parser);
    response = kms_response_parser_get_response(kms->parser);
    if (!response) {
        CLIENT_ERR("Failed to get response from parser: %s", kms_response_parser_error(kms->parser));
        goto fail;
    }
    body = kms_response_get_body(response, &body_len);

    if (kms->retry_enabled && should_retry_http(http_status, kms->req_type)) {
        if (kms->attempts >= kms_max_attempts) {
            // Wrap error to indicate maximum retries occurred.
            _handle_non200_http_status(http_status, body, body_len, status);
            CLIENT_ERR("KMS request failed after maximum of %d retries: %s",
                       kms_max_attempts,
                       mongocrypt_status_message(status, NULL));
            goto fail;
        } else {
            ret = true;
            set_retry(kms);
            goto fail;
        }
    }

    if (http_status != 200) {
        _handle_non200_http_status(http_status, body, body_len, status);
        goto fail;
    }

    /* If HTTP response succeeded (status 200) then body should contain JSON.
     */
    bson_destroy(&body_bson);
    if (body_len > (size_t)SSIZE_MAX) {
        CLIENT_ERR("Error parsing JSON in KMS response '%s'. "
                   "Response body exceeds maximum supported length",
                   bson_error.message);
        bson_init(&body_bson);
        goto fail;
    }
    if (!bson_init_from_json(&body_bson, body, (ssize_t)body_len, &bson_error)) {
        CLIENT_ERR("Error parsing JSON in KMS response '%s'. "
                   "HTTP status=%d. Response body=\n%s",
                   bson_error.message,
                   http_status,
                   body);
        bson_init(&body_bson);
        goto fail;
    }

    if (!bson_iter_init_find(&iter, &body_bson, json_field) || !BSON_ITER_HOLDS_UTF8(&iter)) {
        CLIENT_ERR("KMS JSON response does not include field '%s'. HTTP status=%d. "
                   "Response body=\n%s",
                   json_field,
                   http_status,
                   body);
        goto fail;
    }

    b64_str = (char *)bson_iter_utf8(&iter, &b64_strlen);
    BSON_ASSERT(b64_str);
    uint8_t *result_data = bson_malloc((size_t)b64_strlen + 1u);
    BSON_ASSERT(result_data);

    result_len = kms_message_b64_pton(b64_str, result_data, b64_strlen);
    if (result_len < 0) {
        CLIENT_ERR("Failed to base64 decode response. HTTP status=%d. Response body=\n%s", http_status, body);
        bson_free(result_data);
        goto fail;
    }
    kms->result.data = result_data;
    kms->result.len = (uint32_t)result_len;
    kms->result.owned = true;
    ret = true;
fail:
    bson_destroy(&body_bson);
    kms_response_destroy(response);
    return ret;
}

/* A Azure/GCP oauth KMS context has received full response. Parse out the
 * bearer token or error. */
static bool _ctx_done_oauth(mongocrypt_kms_ctx_t *kms) {
    BSON_ASSERT_PARAM(kms);

    kms_response_t *response = NULL;
    const char *body;
    bson_t *bson_body = NULL;
    bool ret;
    bson_error_t bson_error;
    bson_iter_t iter;
    int http_status;
    size_t body_len;
    mongocrypt_status_t *status;

    status = kms->status;
    ret = false;
    /* Parse out the oauth token result (or error). */
    http_status = kms_response_parser_status(kms->parser);
    response = kms_response_parser_get_response(kms->parser);
    if (!response) {
        CLIENT_ERR("Failed to get response from parser: %s", kms_response_parser_error(kms->parser));
        goto fail;
    }
    body = kms_response_get_body(response, &body_len);

    if (kms->retry_enabled && should_retry_http(http_status, kms->req_type)) {
        if (kms->attempts >= kms_max_attempts) {
            // Wrap error to indicate maximum retries occurred.
            _handle_non200_http_status(http_status, body, body_len, status);
            CLIENT_ERR("KMS request failed after maximum of %d retries: %s",
                       kms_max_attempts,
                       mongocrypt_status_message(status, NULL));
            goto fail;
        } else {
            ret = true;
            set_retry(kms);
            goto fail;
        }
    }

    if (body_len == 0) {
        CLIENT_ERR("Empty KMS response. HTTP status=%d", http_status);
        goto fail;
    }

    if (body_len > (size_t)SSIZE_MAX) {
        CLIENT_ERR("Error parsing JSON in KMS response '%s'. "
                   "Response body exceeds maximum supported length",
                   bson_error.message);
        goto fail;
    }
    bson_body = bson_new_from_json((const uint8_t *)body, (ssize_t)body_len, &bson_error);
    if (!bson_body) {
        CLIENT_ERR("Error parsing JSON in KMS response '%s'. "
                   "HTTP status=%d. Response body=\n%s",
                   bson_error.message,
                   http_status,
                   body);
        goto fail;
    }

    if (http_status != 200) {
        _handle_non200_http_status(http_status, body, body_len, status);
        goto fail;
    }

    if (!bson_iter_init_find(&iter, bson_body, "access_token") || !BSON_ITER_HOLDS_UTF8(&iter)) {
        CLIENT_ERR("Invalid KMS response. KMS JSON response does not include "
                   "field 'access_token'. "
                   "HTTP status=%d. Response body=\n%s",
                   http_status,
                   body);
        goto fail;
    }

    /* Store the full response, to include the expiration time. */
    _mongocrypt_buffer_steal_from_bson(&kms->result, bson_body);
    bson_body = NULL;

    ret = true;
fail:
    bson_destroy(bson_body);
    kms_response_destroy(response);
    return ret;
}

/* An Azure oauth KMS context has received full response. Parse out the bearer
 * token or error. */
static bool _ctx_done_azure_wrapkey_unwrapkey(mongocrypt_kms_ctx_t *kms) {
    BSON_ASSERT_PARAM(kms);

    kms_response_t *response = NULL;
    const char *body;
    bson_t *bson_body = NULL;
    bool ret;
    bson_error_t bson_error;
    bson_iter_t iter;
    int http_status;
    size_t body_len;
    mongocrypt_status_t *status;
    const char *b64url_data = NULL;
    uint32_t b64url_len;
    char *b64_data = NULL;
    uint32_t b64_len;
    int result_len;

    status = kms->status;
    ret = false;
    /* Parse out the oauth token result (or error). */
    http_status = kms_response_parser_status(kms->parser);
    response = kms_response_parser_get_response(kms->parser);
    if (!response) {
        CLIENT_ERR("Failed to get response from parser: %s", kms_response_parser_error(kms->parser));
        goto fail;
    }
    body = kms_response_get_body(response, &body_len);

    if (kms->retry_enabled && should_retry_http(http_status, kms->req_type)) {
        if (kms->attempts >= kms_max_attempts) {
            // Wrap error to indicate maximum retries occurred.
            _handle_non200_http_status(http_status, body, body_len, status);
            CLIENT_ERR("KMS request failed after maximum of %d retries: %s",
                       kms_max_attempts,
                       mongocrypt_status_message(status, NULL));
            goto fail;
        } else {
            ret = true;
            set_retry(kms);
            goto fail;
        }
    }

    if (body_len == 0) {
        CLIENT_ERR("Empty KMS response. HTTP status=%d", http_status);
        goto fail;
    }

    if (body_len > (size_t)SSIZE_MAX) {
        CLIENT_ERR("Error parsing JSON in KMS response '%s'. "
                   "Response body exceeds maximum supported length",
                   bson_error.message);
        goto fail;
    }
    bson_body = bson_new_from_json((const uint8_t *)body, (ssize_t)body_len, &bson_error);
    if (!bson_body) {
        CLIENT_ERR("Error parsing JSON in KMS response '%s'. "
                   "HTTP status=%d. Response body=\n%s",
                   bson_error.message,
                   http_status,
                   body);
        goto fail;
    }

    if (http_status != 200) {
        _handle_non200_http_status(http_status, body, body_len, status);
        goto fail;
    }

    if (!bson_iter_init_find(&iter, bson_body, "value") || !BSON_ITER_HOLDS_UTF8(&iter)) {
        CLIENT_ERR("KMS JSON response does not include field 'value'. HTTP status=%d. "
                   "Response body=\n%s",
                   http_status,
                   body);
        goto fail;
    }

    b64url_data = bson_iter_utf8(&iter, &b64url_len);
    BSON_ASSERT(b64url_len <= UINT32_MAX - 4u);
    /* add four for padding. */
    b64_len = b64url_len + 4;
    b64_data = bson_malloc0(b64_len);
    if (kms_message_b64url_to_b64(b64url_data, b64url_len, b64_data, b64_len) == -1) {
        CLIENT_ERR("Error converting base64url to base64");
        goto fail;
    }

    uint8_t *result_data = bson_malloc(b64_len);
    BSON_ASSERT(result_data);
    result_len = kms_message_b64_pton(b64_data, result_data, b64_len);
    if (result_len < 0) {
        CLIENT_ERR("Failed to base64 decode response. HTTP status=%d. Response body=\n%s", http_status, body);
        bson_free(result_data);
        goto fail;
    }

    kms->result.data = result_data;
    kms->result.len = (uint32_t)result_len;
    kms->result.owned = true;

    ret = true;
fail:
    bson_destroy(bson_body);
    kms_response_destroy(response);
    bson_free(b64_data);
    return ret;
}

/* A GCP KMS context has received full response. Parse out the result or error.
 */
static bool _ctx_done_gcp(mongocrypt_kms_ctx_t *kms, const char *json_field) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(json_field);

    kms_response_t *response = NULL;
    const char *body;
    bson_t body_bson = BSON_INITIALIZER;
    bool ret;
    bson_error_t bson_error;
    bson_iter_t iter;
    size_t outlen;
    char *b64_str;
    int http_status;
    size_t body_len;
    mongocrypt_status_t *status;

    status = kms->status;
    ret = false;
    /* Parse out the {en|de}crypted result. */
    http_status = kms_response_parser_status(kms->parser);
    response = kms_response_parser_get_response(kms->parser);
    if (!response) {
        CLIENT_ERR("Failed to get response from parser: %s", kms_response_parser_error(kms->parser));
        goto fail;
    }
    body = kms_response_get_body(response, &body_len);

    if (kms->retry_enabled && should_retry_http(http_status, kms->req_type)) {
        if (kms->attempts >= kms_max_attempts) {
            // Wrap error to indicate maximum retries occurred.
            _handle_non200_http_status(http_status, body, body_len, status);
            CLIENT_ERR("KMS request failed after maximum of %d retries: %s",
                       kms_max_attempts,
                       mongocrypt_status_message(status, NULL));
            goto fail;
        } else {
            ret = true;
            set_retry(kms);
            goto fail;
        }
    }

    if (http_status != 200) {
        _handle_non200_http_status(http_status, body, body_len, status);
        goto fail;
    }

    /* If HTTP response succeeded (status 200) then body should contain JSON.
     */
    bson_destroy(&body_bson);
    if (body_len > (size_t)SSIZE_MAX) {
        CLIENT_ERR("Error parsing JSON in KMS response '%s'. "
                   "Response body exceeds maximum supported length",
                   bson_error.message);
        bson_init(&body_bson);
        goto fail;
    }
    if (!bson_init_from_json(&body_bson, body, (ssize_t)body_len, &bson_error)) {
        CLIENT_ERR("Error parsing JSON in KMS response '%s'. "
                   "HTTP status=%d. Response body=\n%s",
                   bson_error.message,
                   http_status,
                   body);
        bson_init(&body_bson);
        goto fail;
    }

    if (!bson_iter_init_find(&iter, &body_bson, json_field) || !BSON_ITER_HOLDS_UTF8(&iter)) {
        CLIENT_ERR("KMS JSON response does not include field '%s'. HTTP status=%d. "
                   "Response body=\n%s",
                   json_field,
                   http_status,
                   body);
        goto fail;
    }

    b64_str = (char *)bson_iter_utf8(&iter, NULL);
    BSON_ASSERT(b64_str);
    kms->result.data = kms_message_b64_to_raw(b64_str, &outlen);
    BSON_ASSERT(outlen <= UINT32_MAX);
    kms->result.len = (uint32_t)outlen;
    kms->result.owned = true;
    ret = true;
fail:
    bson_destroy(&body_bson);
    kms_response_destroy(response);
    return ret;
}

static bool _ctx_done_kmip_register(mongocrypt_kms_ctx_t *kms_ctx) {
    BSON_ASSERT_PARAM(kms_ctx);

    kms_response_t *res = NULL;

    mongocrypt_status_t *status = kms_ctx->status;
    bool ret = false;
    char *uid;

    res = kms_response_parser_get_response(kms_ctx->parser);
    if (!res) {
        CLIENT_ERR("Error getting KMIP response: %s", kms_response_parser_error(kms_ctx->parser));
        goto done;
    }

    uid = kms_kmip_response_get_unique_identifier(res);
    if (!uid) {
        CLIENT_ERR("Error getting UniqueIdentifer from KMIP Register response: %s", kms_response_get_error(res));
        goto done;
    }

    if (!_mongocrypt_buffer_steal_from_string(&kms_ctx->result, uid)) {
        CLIENT_ERR("Error storing KMS UniqueIdentifer result");
        bson_free(uid);
        goto done;
    }
    ret = true;

done:
    kms_response_destroy(res);
    return ret;
}

static bool _ctx_done_kmip_activate(mongocrypt_kms_ctx_t *kms_ctx) {
    BSON_ASSERT_PARAM(kms_ctx);
    return _ctx_done_kmip_register(kms_ctx);
}

static bool _ctx_done_kmip_get(mongocrypt_kms_ctx_t *kms_ctx) {
    BSON_ASSERT_PARAM(kms_ctx);

    kms_response_t *res = NULL;

    mongocrypt_status_t *status = kms_ctx->status;
    bool ret = false;
    uint8_t *secretdata;
    size_t secretdata_len;

    res = kms_response_parser_get_response(kms_ctx->parser);
    if (!res) {
        CLIENT_ERR("Error getting KMIP response: %s", kms_response_parser_error(kms_ctx->parser));
        goto done;
    }

    secretdata = kms_kmip_response_get_secretdata(res, &secretdata_len);
    if (!secretdata) {
        CLIENT_ERR("Error getting SecretData from KMIP Get response: %s", kms_response_get_error(res));
        goto done;
    }

    if (!_mongocrypt_buffer_steal_from_data_and_size(&kms_ctx->result, secretdata, secretdata_len)) {
        CLIENT_ERR("Error storing KMS SecretData result");
        bson_free(secretdata);
        goto done;
    }

    ret = true;

done:
    kms_response_destroy(res);
    return ret;
}

static bool _ctx_done_kmip_create(mongocrypt_kms_ctx_t *kms_ctx) {
    BSON_ASSERT_PARAM(kms_ctx);

    kms_response_t *res = NULL;

    mongocrypt_status_t *status = kms_ctx->status;
    bool ret = false;
    char *uid;

    res = kms_response_parser_get_response(kms_ctx->parser);
    if (!res) {
        CLIENT_ERR("Error getting KMIP response: %s", kms_response_parser_error(kms_ctx->parser));
        goto done;
    }

    uid = kms_kmip_response_get_unique_identifier(res);
    if (!uid) {
        CLIENT_ERR("Error getting UniqueIdentifer from KMIP Create response: %s", kms_response_get_error(res));
        goto done;
    }

    if (!_mongocrypt_buffer_steal_from_string(&kms_ctx->result, uid)) {
        CLIENT_ERR("Error storing KMS UniqueIdentifer result");
        bson_free(uid);
        goto done;
    }
    ret = true;

done:
    kms_response_destroy(res);
    return ret;
}

static bool _ctx_done_kmip_encrypt(mongocrypt_kms_ctx_t *kms_ctx) {
    BSON_ASSERT_PARAM(kms_ctx);

    kms_response_t *res = NULL;

    mongocrypt_status_t *status = kms_ctx->status;
    bool ret = false;
    uint8_t *ciphertext;
    size_t ciphertext_len;
    uint8_t *iv;
    size_t iv_len;
    _mongocrypt_buffer_t data_buf, iv_buf;
    _mongocrypt_buffer_init(&data_buf);
    _mongocrypt_buffer_init(&iv_buf);

    res = kms_response_parser_get_response(kms_ctx->parser);
    if (!res) {
        CLIENT_ERR("Error getting KMIP response: %s", kms_response_parser_error(kms_ctx->parser));
        goto done;
    }

    ciphertext = kms_kmip_response_get_data(res, &ciphertext_len);
    if (!ciphertext) {
        CLIENT_ERR("Error getting data from KMIP Encrypt response: %s", kms_response_get_error(res));
        goto done;
    }

    iv = kms_kmip_response_get_iv(res, &iv_len);
    if (!iv) {
        CLIENT_ERR("Error getting IV from KMIP Encrypt response: %s", kms_response_get_error(res));
        bson_free(ciphertext);
        goto done;
    }

    if (iv_len != MONGOCRYPT_IV_LEN) {
        CLIENT_ERR("KMIP IV response has unexpected length: %zu", iv_len);
        bson_free(ciphertext);
        bson_free(iv);
        goto done;
    }

    if (!_mongocrypt_buffer_steal_from_data_and_size(&data_buf, ciphertext, ciphertext_len)) {
        CLIENT_ERR("Error storing KMS Encrypt result");
        bson_free(ciphertext);
        bson_free(iv);
        goto done;
    }

    if (!_mongocrypt_buffer_steal_from_data_and_size(&iv_buf, iv, iv_len)) {
        CLIENT_ERR("Error storing KMS Encrypt IV");
        bson_free(ciphertext);
        bson_free(iv);
        goto done;
    }

    const _mongocrypt_buffer_t results_buf[2] = {iv_buf, data_buf};
    if (!_mongocrypt_buffer_concat(&kms_ctx->result, results_buf, 2)) {
        CLIENT_ERR("Error concatenating IV and ciphertext");
        goto done;
    }

    ret = true;

done:
    kms_response_destroy(res);
    _mongocrypt_buffer_cleanup(&iv_buf);
    _mongocrypt_buffer_cleanup(&data_buf);
    return ret;
}

static bool _ctx_done_kmip_decrypt(mongocrypt_kms_ctx_t *kms_ctx) {
    BSON_ASSERT_PARAM(kms_ctx);

    kms_response_t *res = NULL;

    mongocrypt_status_t *status = kms_ctx->status;
    bool ret = false;
    uint8_t *ciphertext;
    size_t ciphertext_len;

    res = kms_response_parser_get_response(kms_ctx->parser);
    if (!res) {
        CLIENT_ERR("Error getting KMIP response: %s", kms_response_parser_error(kms_ctx->parser));
        goto done;
    }

    ciphertext = kms_kmip_response_get_data(res, &ciphertext_len);
    if (!ciphertext) {
        CLIENT_ERR("Error getting data from KMIP Decrypt response: %s", kms_response_get_error(res));
        goto done;
    }

    if (!_mongocrypt_buffer_steal_from_data_and_size(&kms_ctx->result, ciphertext, ciphertext_len)) {
        CLIENT_ERR("Error storing KMS Decrypt result");
        bson_free(ciphertext);
        goto done;
    }

    ret = true;

done:
    kms_response_destroy(res);
    return ret;
}

bool mongocrypt_kms_ctx_fail(mongocrypt_kms_ctx_t *kms) {
    if (!kms || !kms->retry_enabled) {
        return false;
    }

    kms->should_retry = false;
    mongocrypt_status_t *status = kms->status;

    if (!kms->retry_enabled) {
        CLIENT_ERR("KMS request failed due to network error");
        return false;
    }

    if (kms->attempts >= kms_max_attempts) {
        CLIENT_ERR("KMS request failed after %d retries due to a network error", kms_max_attempts);
        return false;
    }

    // Check if request type is retryable. Some requests are non-idempotent and cannot be safely retried.
    _kms_request_type_t retryable_types[] = {MONGOCRYPT_KMS_AZURE_OAUTH,
                                             MONGOCRYPT_KMS_GCP_OAUTH,
                                             MONGOCRYPT_KMS_AWS_ENCRYPT,
                                             MONGOCRYPT_KMS_AWS_DECRYPT,
                                             MONGOCRYPT_KMS_AZURE_WRAPKEY,
                                             MONGOCRYPT_KMS_AZURE_UNWRAPKEY,
                                             MONGOCRYPT_KMS_GCP_ENCRYPT,
                                             MONGOCRYPT_KMS_GCP_DECRYPT};
    bool is_retryable = false;
    for (size_t i = 0; i < sizeof(retryable_types) / sizeof(retryable_types[0]); i++) {
        if (retryable_types[i] == kms->req_type) {
            is_retryable = true;
            break;
        }
    }
    if (!is_retryable) {
        CLIENT_ERR("KMS request failed due to network error");
        return false;
    }

    // Mark KMS context as retryable. Return again in `mongocrypt_ctx_next_kms_ctx`.
    set_retry(kms);

    // Reset intermediate state of parser.
    if (kms->parser) {
        kms_response_parser_reset(kms->parser);
    }
    return true;
}

bool mongocrypt_kms_ctx_feed(mongocrypt_kms_ctx_t *kms, mongocrypt_binary_t *bytes) {
    if (!kms) {
        return false;
    }

    mongocrypt_status_t *status = kms->status;
    if (!mongocrypt_status_ok(status)) {
        return false;
    }

    if (!bytes) {
        CLIENT_ERR("argument 'bytes' is required");
        return false;
    }

    if (0 == bytes->len) {
        CLIENT_ERR("argument 'bytes' cannot be empty");
        return false;
    }

    if (bytes->len > mongocrypt_kms_ctx_bytes_needed(kms)) {
        CLIENT_ERR("KMS response fed too much data");
        return false;
    }

    if (kms->log && kms->log->trace_enabled) {
        _mongocrypt_log(kms->log,
                        MONGOCRYPT_LOG_LEVEL_TRACE,
                        "%s (%s=\"%.*s\")",
                        BSON_FUNC,
                        "bytes",
                        mongocrypt_binary_len(bytes),
                        mongocrypt_binary_data(bytes));
    }

    if (!kms_response_parser_feed(kms->parser, bytes->data, bytes->len)) {
        if (is_kms(kms->req_type)) {
            /* The KMIP response parser does not suport kms_response_parser_status.
             * Only report the error string. */
            CLIENT_ERR("KMS response parser error with error: '%s'", kms_response_parser_error(kms->parser));
        } else {
            CLIENT_ERR("KMS response parser error with status %d, error: '%s'",
                       kms_response_parser_status(kms->parser),
                       kms_response_parser_error(kms->parser));
        }

        return false;
    }

    if (0 == mongocrypt_kms_ctx_bytes_needed(kms)) {
        switch (kms->req_type) {
        default: CLIENT_ERR("Unknown request type"); return false;
        case MONGOCRYPT_KMS_AWS_ENCRYPT: return _ctx_done_aws(kms, "CiphertextBlob");
        case MONGOCRYPT_KMS_AWS_DECRYPT: return _ctx_done_aws(kms, "Plaintext");
        case MONGOCRYPT_KMS_AZURE_OAUTH: return _ctx_done_oauth(kms);
        case MONGOCRYPT_KMS_AZURE_WRAPKEY: return _ctx_done_azure_wrapkey_unwrapkey(kms);
        case MONGOCRYPT_KMS_AZURE_UNWRAPKEY: return _ctx_done_azure_wrapkey_unwrapkey(kms);
        case MONGOCRYPT_KMS_GCP_OAUTH: return _ctx_done_oauth(kms);
        case MONGOCRYPT_KMS_GCP_ENCRYPT: return _ctx_done_gcp(kms, "ciphertext");
        case MONGOCRYPT_KMS_GCP_DECRYPT: return _ctx_done_gcp(kms, "plaintext");
        case MONGOCRYPT_KMS_KMIP_REGISTER: return _ctx_done_kmip_register(kms);
        case MONGOCRYPT_KMS_KMIP_ACTIVATE: return _ctx_done_kmip_activate(kms);
        case MONGOCRYPT_KMS_KMIP_GET: return _ctx_done_kmip_get(kms);
        case MONGOCRYPT_KMS_KMIP_ENCRYPT: return _ctx_done_kmip_encrypt(kms);
        case MONGOCRYPT_KMS_KMIP_DECRYPT: return _ctx_done_kmip_decrypt(kms);
        case MONGOCRYPT_KMS_KMIP_CREATE: return _ctx_done_kmip_create(kms);
        }
    }
    return true;
}

bool _mongocrypt_kms_ctx_result(mongocrypt_kms_ctx_t *kms, _mongocrypt_buffer_t *out) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(out);

    mongocrypt_status_t *status = kms->status;

    /* If we have no status, we were never initialized */
    if (!status) {
        return false;
    }

    if (!mongocrypt_status_ok(status)) {
        return false;
    }

    if (mongocrypt_kms_ctx_bytes_needed(kms) > 0) {
        CLIENT_ERR("KMS response unfinished");
        return false;
    }

    _mongocrypt_buffer_init(out);
    out->data = kms->result.data;
    out->len = kms->result.len;
    return true;
}

bool mongocrypt_kms_ctx_status(mongocrypt_kms_ctx_t *kms, mongocrypt_status_t *status_out) {
    if (!kms) {
        return false;
    }

    if (!status_out) {
        mongocrypt_status_t *status = kms->status;
        CLIENT_ERR("argument 'status' is required");
        return false;
    }
    _mongocrypt_status_copy_to(kms->status, status_out);
    return mongocrypt_status_ok(status_out);
}

void _mongocrypt_kms_ctx_cleanup(mongocrypt_kms_ctx_t *kms) {
    if (!kms) {
        return;
    }
    if (kms->req) {
        kms_request_destroy(kms->req);
    }
    if (kms->parser) {
        kms_response_parser_destroy(kms->parser);
    }
    mongocrypt_status_destroy(kms->status);
    _mongocrypt_buffer_cleanup(&kms->msg);
    _mongocrypt_buffer_cleanup(&kms->result);
    bson_free(kms->endpoint);
    bson_free(kms->kmsid);
}

bool mongocrypt_kms_ctx_message(mongocrypt_kms_ctx_t *kms, mongocrypt_binary_t *msg) {
    if (!kms) {
        return false;
    }

    if (!msg) {
        mongocrypt_status_t *status = kms->status;
        CLIENT_ERR("argument 'msg' is required");
        return false;
    }
    msg->data = kms->msg.data;
    msg->len = kms->msg.len;
    return true;
}

bool mongocrypt_kms_ctx_endpoint(mongocrypt_kms_ctx_t *kms, const char **endpoint) {
    if (!kms) {
        return false;
    }
    if (!endpoint) {
        mongocrypt_status_t *status = kms->status;
        CLIENT_ERR("argument 'endpoint' is required");
        return false;
    }
    *endpoint = kms->endpoint;
    return true;
}

bool _mongocrypt_kms_ctx_init_azure_auth(mongocrypt_kms_ctx_t *kms,
                                         const mc_kms_creds_t *kc,
                                         _mongocrypt_endpoint_t *key_vault_endpoint,
                                         const char *kmsid,
                                         _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(kc);

    kms_request_opt_t *opt = NULL;
    mongocrypt_status_t *status;
    const _mongocrypt_endpoint_t *identity_platform_endpoint;
    char *scope = NULL;
    const char *hostname;
    char *request_string;
    bool ret = false;

    _init_common(kms, log, MONGOCRYPT_KMS_AZURE_OAUTH, kmsid);
    status = kms->status;

    BSON_ASSERT(kc->type == MONGOCRYPT_KMS_PROVIDER_AZURE);

    identity_platform_endpoint = kc->value.azure.identity_platform_endpoint;

    if (identity_platform_endpoint) {
        kms->endpoint = bson_strdup(identity_platform_endpoint->host_and_port);
        hostname = identity_platform_endpoint->host;
    } else {
        kms->endpoint = bson_strdup("login.microsoftonline.com");
        hostname = "login.microsoftonline.com";
    }
    _mongocrypt_apply_default_port(&kms->endpoint, DEFAULT_HTTPS_PORT);

    if (key_vault_endpoint) {
        /* Request a custom scope. It is URL encoded, like
         * https%3A%2F%2Fvault.azure.net%2F.default */
        scope = bson_strdup_printf("%s%s%s", "https%3A%2F%2F", key_vault_endpoint->domain, "%2F.default");
    } else {
        /* Default to commercial Azure endpoint. */
        scope = bson_strdup("https%3A%2F%2Fvault.azure.net%2F.default");
    }

    opt = kms_request_opt_new();
    BSON_ASSERT(opt);
    kms_request_opt_set_connection_close(opt, true);
    kms_request_opt_set_provider(opt, KMS_REQUEST_PROVIDER_AZURE);
    kms->req = kms_azure_request_oauth_new(hostname,
                                           scope,
                                           kc->value.azure.tenant_id,
                                           kc->value.azure.client_id,
                                           kc->value.azure.client_secret,
                                           opt);
    if (kms_request_get_error(kms->req)) {
        CLIENT_ERR("error constructing KMS message: %s", kms_request_get_error(kms->req));
        goto fail;
    }

    request_string = kms_request_to_string(kms->req);
    if (!request_string) {
        CLIENT_ERR("error getting Azure OAuth KMS message: %s", kms_request_get_error(kms->req));
        goto fail;
    }
    _mongocrypt_buffer_init(&kms->msg);
    kms->msg.data = (uint8_t *)request_string;
    kms->msg.len = (uint32_t)strlen(request_string);
    kms->msg.owned = true;

    ret = true;
fail:
    bson_free(scope);
    kms_request_opt_destroy(opt);
    return ret;
}

bool _mongocrypt_kms_ctx_init_azure_wrapkey(mongocrypt_kms_ctx_t *kms,
                                            _mongocrypt_opts_kms_providers_t *kms_providers,
                                            struct __mongocrypt_ctx_opts_t *ctx_opts,
                                            const char *access_token,
                                            _mongocrypt_buffer_t *plaintext_key_material,
                                            const char *kmsid,
                                            _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(ctx_opts);
    BSON_ASSERT_PARAM(plaintext_key_material);

    kms_request_opt_t *opt = NULL;
    mongocrypt_status_t *status;
    char *path_and_query = NULL;
    char *payload = NULL;
    const char *host;
    char *request_string;
    bool ret = false;

    _init_common(kms, log, MONGOCRYPT_KMS_AZURE_WRAPKEY, kmsid);
    status = kms->status;

    BSON_ASSERT(ctx_opts->kek.provider.azure.key_vault_endpoint);

    kms->endpoint = bson_strdup(ctx_opts->kek.provider.azure.key_vault_endpoint->host_and_port);
    _mongocrypt_apply_default_port(&kms->endpoint, DEFAULT_HTTPS_PORT);
    host = ctx_opts->kek.provider.azure.key_vault_endpoint->host;

    opt = kms_request_opt_new();
    BSON_ASSERT(opt);
    kms_request_opt_set_connection_close(opt, true);
    kms_request_opt_set_provider(opt, KMS_REQUEST_PROVIDER_AZURE);
    kms->req = kms_azure_request_wrapkey_new(host,
                                             access_token,
                                             ctx_opts->kek.provider.azure.key_name,
                                             ctx_opts->kek.provider.azure.key_version,
                                             plaintext_key_material->data,
                                             plaintext_key_material->len,
                                             opt);

    if (kms_request_get_error(kms->req)) {
        CLIENT_ERR("error constructing KMS wrapkey message: %s", kms_request_get_error(kms->req));
        goto fail;
    }

    request_string = kms_request_to_string(kms->req);
    if (!request_string) {
        CLIENT_ERR("error getting Azure wrapkey KMS message: %s", kms_request_get_error(kms->req));
        goto fail;
    }
    _mongocrypt_buffer_init(&kms->msg);
    kms->msg.data = (uint8_t *)request_string;
    kms->msg.len = (uint32_t)strlen(request_string);
    kms->msg.owned = true;

    ret = true;
fail:
    kms_request_opt_destroy(opt);
    bson_free(path_and_query);
    bson_free(payload);
    return ret;
}

bool _mongocrypt_kms_ctx_init_azure_unwrapkey(mongocrypt_kms_ctx_t *kms,
                                              _mongocrypt_opts_kms_providers_t *kms_providers,
                                              const char *access_token,
                                              _mongocrypt_key_doc_t *key,
                                              const char *kmsid,
                                              _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(key);

    kms_request_opt_t *opt = NULL;
    mongocrypt_status_t *status;
    char *path_and_query = NULL;
    char *payload = NULL;
    const char *host;
    char *request_string;
    bool ret = false;

    _init_common(kms, log, MONGOCRYPT_KMS_AZURE_UNWRAPKEY, kmsid);
    status = kms->status;

    BSON_ASSERT(key->kek.provider.azure.key_vault_endpoint);

    kms->endpoint = bson_strdup(key->kek.provider.azure.key_vault_endpoint->host_and_port);
    _mongocrypt_apply_default_port(&kms->endpoint, DEFAULT_HTTPS_PORT);
    host = key->kek.provider.azure.key_vault_endpoint->host;

    opt = kms_request_opt_new();
    BSON_ASSERT(opt);
    kms_request_opt_set_connection_close(opt, true);
    kms_request_opt_set_provider(opt, KMS_REQUEST_PROVIDER_AZURE);
    kms->req = kms_azure_request_unwrapkey_new(host,
                                               access_token,
                                               key->kek.provider.azure.key_name,
                                               key->kek.provider.azure.key_version,
                                               key->key_material.data,
                                               key->key_material.len,
                                               opt);

    if (kms_request_get_error(kms->req)) {
        CLIENT_ERR("error constructing KMS unwrapkey message: %s", kms_request_get_error(kms->req));
        goto fail;
    }

    request_string = kms_request_to_string(kms->req);
    if (!request_string) {
        CLIENT_ERR("error getting Azure unwrapkey KMS message: %s", kms_request_get_error(kms->req));
        goto fail;
    }
    _mongocrypt_buffer_init(&kms->msg);
    kms->msg.data = (uint8_t *)request_string;
    kms->msg.len = (uint32_t)strlen(request_string);
    kms->msg.owned = true;

    ret = true;
fail:
    kms_request_opt_destroy(opt);
    bson_free(path_and_query);
    bson_free(payload);
    return ret;
}

#define RSAES_PKCS1_V1_5_SIGNATURE_LEN 256

/* This is the form of the callback that KMS message calls. */
static bool _sign_rsaes_pkcs1_v1_5_trampoline(void *ctx,
                                              const char *private_key,
                                              size_t private_key_len,
                                              const char *input,
                                              size_t input_len,
                                              unsigned char *signature_out) {
    ctx_with_status_t *ctx_with_status;
    _mongocrypt_opts_t *crypt_opts;
    mongocrypt_binary_t private_key_bin;
    mongocrypt_binary_t input_bin;
    mongocrypt_binary_t output_bin;
    bool ret;

    BSON_ASSERT_PARAM(ctx);
    BSON_ASSERT_PARAM(input);
    BSON_ASSERT_PARAM(private_key);
    BSON_ASSERT_PARAM(signature_out);

    ctx_with_status = (ctx_with_status_t *)ctx;
    crypt_opts = (_mongocrypt_opts_t *)ctx_with_status->ctx;
    BSON_ASSERT(crypt_opts);
    private_key_bin.data = (uint8_t *)private_key;
    BSON_ASSERT(private_key_len <= UINT32_MAX);
    private_key_bin.len = (uint32_t)private_key_len;
    input_bin.data = (uint8_t *)input;
    BSON_ASSERT(input_len <= UINT32_MAX);
    input_bin.len = (uint32_t)input_len;
    output_bin.data = (uint8_t *)signature_out;
    output_bin.len = RSAES_PKCS1_V1_5_SIGNATURE_LEN;

    ret = crypt_opts->sign_rsaes_pkcs1_v1_5(crypt_opts->sign_ctx,
                                            &private_key_bin,
                                            &input_bin,
                                            &output_bin,
                                            ctx_with_status->status);
    return ret;
}

bool _mongocrypt_kms_ctx_init_gcp_auth(mongocrypt_kms_ctx_t *kms,
                                       _mongocrypt_opts_t *crypt_opts,
                                       const mc_kms_creds_t *kc,
                                       _mongocrypt_endpoint_t *kms_endpoint,
                                       const char *kmsid,
                                       _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(kc);
    BSON_ASSERT_PARAM(crypt_opts);

    kms_request_opt_t *opt = NULL;
    mongocrypt_status_t *status;
    const _mongocrypt_endpoint_t *auth_endpoint;
    char *scope = NULL;
    char *audience = NULL;
    const char *hostname;
    char *request_string;
    bool ret = false;
    ctx_with_status_t ctx_with_status;

    _init_common(kms, log, MONGOCRYPT_KMS_GCP_OAUTH, kmsid);
    status = kms->status;
    ctx_with_status.ctx = crypt_opts;
    ctx_with_status.status = mongocrypt_status_new();

    BSON_ASSERT(kc->type == MONGOCRYPT_KMS_PROVIDER_GCP);

    auth_endpoint = kc->value.gcp.endpoint;
    if (auth_endpoint) {
        kms->endpoint = bson_strdup(auth_endpoint->host_and_port);
        hostname = auth_endpoint->host;
        audience = bson_strdup_printf("https://%s/token", auth_endpoint->host);
    } else {
        kms->endpoint = bson_strdup("oauth2.googleapis.com");
        hostname = "oauth2.googleapis.com";
        audience = bson_strdup_printf("https://oauth2.googleapis.com/token");
    }
    _mongocrypt_apply_default_port(&kms->endpoint, DEFAULT_HTTPS_PORT);

    if (kms_endpoint) {
        /* Request a custom scope. */
        scope = bson_strdup_printf("https://www.%s/auth/cloudkms", kms_endpoint->domain);
    } else {
        scope = bson_strdup("https://www.googleapis.com/auth/cloudkms");
    }

    opt = kms_request_opt_new();
    BSON_ASSERT(opt);
    kms_request_opt_set_connection_close(opt, true);
    kms_request_opt_set_provider(opt, KMS_REQUEST_PROVIDER_GCP);
    if (crypt_opts->sign_rsaes_pkcs1_v1_5) {
        kms_request_opt_set_crypto_hook_sign_rsaes_pkcs1_v1_5(opt, _sign_rsaes_pkcs1_v1_5_trampoline, &ctx_with_status);
    }
    kms->req = kms_gcp_request_oauth_new(hostname,
                                         kc->value.gcp.email,
                                         audience,
                                         scope,
                                         (const char *)kc->value.gcp.private_key.data,
                                         kc->value.gcp.private_key.len,
                                         opt);
    if (kms_request_get_error(kms->req)) {
        CLIENT_ERR("error constructing KMS message: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto fail;
    }

    request_string = kms_request_to_string(kms->req);
    if (!request_string) {
        CLIENT_ERR("error getting GCP OAuth KMS message: %s", kms_request_get_error(kms->req));
        _mongocrypt_status_append(status, ctx_with_status.status);
        goto fail;
    }
    _mongocrypt_buffer_init(&kms->msg);
    kms->msg.data = (uint8_t *)request_string;
    kms->msg.len = (uint32_t)strlen(request_string);
    kms->msg.owned = true;

    ret = true;
fail:
    bson_free(scope);
    bson_free(audience);
    kms_request_opt_destroy(opt);
    mongocrypt_status_destroy(ctx_with_status.status);
    return ret;
}

bool _mongocrypt_kms_ctx_init_gcp_encrypt(mongocrypt_kms_ctx_t *kms,
                                          _mongocrypt_opts_kms_providers_t *kms_providers,
                                          struct __mongocrypt_ctx_opts_t *ctx_opts,
                                          const char *access_token,
                                          _mongocrypt_buffer_t *plaintext_key_material,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(ctx_opts);
    BSON_ASSERT_PARAM(kms_providers);
    BSON_ASSERT_PARAM(access_token);
    BSON_ASSERT_PARAM(plaintext_key_material);

    kms_request_opt_t *opt = NULL;
    mongocrypt_status_t *status;
    char *path_and_query = NULL;
    char *payload = NULL;
    const char *hostname;
    char *request_string;
    bool ret = false;

    _init_common(kms, log, MONGOCRYPT_KMS_GCP_ENCRYPT, kmsid);
    status = kms->status;

    if (ctx_opts->kek.provider.gcp.endpoint) {
        kms->endpoint = bson_strdup(ctx_opts->kek.provider.gcp.endpoint->host_and_port);
        hostname = ctx_opts->kek.provider.gcp.endpoint->host;
    } else {
        kms->endpoint = bson_strdup("cloudkms.googleapis.com");
        hostname = "cloudkms.googleapis.com";
    }
    _mongocrypt_apply_default_port(&kms->endpoint, DEFAULT_HTTPS_PORT);

    opt = kms_request_opt_new();
    BSON_ASSERT(opt);
    kms_request_opt_set_connection_close(opt, true);
    kms_request_opt_set_provider(opt, KMS_REQUEST_PROVIDER_GCP);
    kms->req = kms_gcp_request_encrypt_new(hostname,
                                           access_token,
                                           ctx_opts->kek.provider.gcp.project_id,
                                           ctx_opts->kek.provider.gcp.location,
                                           ctx_opts->kek.provider.gcp.key_ring,
                                           ctx_opts->kek.provider.gcp.key_name,
                                           ctx_opts->kek.provider.gcp.key_version,
                                           plaintext_key_material->data,
                                           plaintext_key_material->len,
                                           opt);

    if (kms_request_get_error(kms->req)) {
        CLIENT_ERR("error constructing GCP KMS encrypt message: %s", kms_request_get_error(kms->req));
        goto fail;
    }

    request_string = kms_request_to_string(kms->req);
    if (!request_string) {
        CLIENT_ERR("error getting GCP KMS encrypt KMS message: %s", kms_request_get_error(kms->req));
        goto fail;
    }
    _mongocrypt_buffer_init(&kms->msg);
    kms->msg.data = (uint8_t *)request_string;
    kms->msg.len = (uint32_t)strlen(request_string);
    kms->msg.owned = true;

    ret = true;
fail:
    kms_request_opt_destroy(opt);
    bson_free(path_and_query);
    bson_free(payload);
    return ret;
}

bool _mongocrypt_kms_ctx_init_gcp_decrypt(mongocrypt_kms_ctx_t *kms,
                                          _mongocrypt_opts_kms_providers_t *kms_providers,
                                          const char *access_token,
                                          _mongocrypt_key_doc_t *key,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms);
    BSON_ASSERT_PARAM(kms_providers);
    BSON_ASSERT_PARAM(access_token);
    BSON_ASSERT_PARAM(key);

    kms_request_opt_t *opt = NULL;
    mongocrypt_status_t *status;
    char *path_and_query = NULL;
    char *payload = NULL;
    const char *hostname;
    char *request_string;
    bool ret = false;

    _init_common(kms, log, MONGOCRYPT_KMS_GCP_DECRYPT, kmsid);
    status = kms->status;

    if (key->kek.provider.gcp.endpoint) {
        kms->endpoint = bson_strdup(key->kek.provider.gcp.endpoint->host_and_port);
        hostname = key->kek.provider.gcp.endpoint->host;
    } else {
        kms->endpoint = bson_strdup("cloudkms.googleapis.com");
        hostname = "cloudkms.googleapis.com";
    }
    _mongocrypt_apply_default_port(&kms->endpoint, DEFAULT_HTTPS_PORT);

    opt = kms_request_opt_new();
    BSON_ASSERT(opt);
    kms_request_opt_set_connection_close(opt, true);
    kms_request_opt_set_provider(opt, KMS_REQUEST_PROVIDER_GCP);
    kms->req = kms_gcp_request_decrypt_new(hostname,
                                           access_token,
                                           key->kek.provider.gcp.project_id,
                                           key->kek.provider.gcp.location,
                                           key->kek.provider.gcp.key_ring,
                                           key->kek.provider.gcp.key_name,
                                           key->key_material.data,
                                           key->key_material.len,
                                           opt);

    if (kms_request_get_error(kms->req)) {
        CLIENT_ERR("error constructing GCP KMS decrypt message: %s", kms_request_get_error(kms->req));
        goto fail;
    }

    request_string = kms_request_to_string(kms->req);
    if (!request_string) {
        CLIENT_ERR("error getting GCP KMS decrypt KMS message: %s", kms_request_get_error(kms->req));
        goto fail;
    }
    _mongocrypt_buffer_init(&kms->msg);
    kms->msg.data = (uint8_t *)request_string;
    kms->msg.len = (uint32_t)strlen(request_string);
    kms->msg.owned = true;

    ret = true;
fail:
    kms_request_opt_destroy(opt);
    bson_free(path_and_query);
    bson_free(payload);
    return ret;
}

bool _mongocrypt_kms_ctx_init_kmip_register(mongocrypt_kms_ctx_t *kms_ctx,
                                            const _mongocrypt_endpoint_t *endpoint,
                                            const uint8_t *secretdata,
                                            uint32_t secretdata_len,
                                            const char *kmsid,
                                            _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms_ctx);
    BSON_ASSERT_PARAM(endpoint);
    BSON_ASSERT_PARAM(secretdata);

    mongocrypt_status_t *status;
    bool ret = false;
    const uint8_t *reqdata;
    size_t reqlen;

    _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_REGISTER, kmsid);
    status = kms_ctx->status;

    kms_ctx->endpoint = bson_strdup(endpoint->host_and_port);
    _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT);
    kms_ctx->req = kms_kmip_request_register_secretdata_new(NULL /* reserved */, secretdata, secretdata_len);

    if (kms_request_get_error(kms_ctx->req)) {
        CLIENT_ERR("Error creating KMIP register request: %s", kms_request_get_error(kms_ctx->req));
        goto done;
    }

    reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen);
    if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) {
        CLIENT_ERR("Error storing KMS request payload");
        goto done;
    }

    ret = true;
done:
    return ret;
}

bool _mongocrypt_kms_ctx_init_kmip_activate(mongocrypt_kms_ctx_t *kms_ctx,
                                            const _mongocrypt_endpoint_t *endpoint,
                                            const char *unique_identifier,
                                            const char *kmsid,
                                            _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms_ctx);
    BSON_ASSERT_PARAM(endpoint);
    BSON_ASSERT_PARAM(unique_identifier);

    mongocrypt_status_t *status;
    bool ret = false;
    size_t reqlen;
    const uint8_t *reqdata;

    _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_ACTIVATE, kmsid);
    status = kms_ctx->status;

    kms_ctx->endpoint = bson_strdup(endpoint->host_and_port);
    _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT);
    kms_ctx->req = kms_kmip_request_activate_new(NULL /* reserved */, unique_identifier);

    if (kms_request_get_error(kms_ctx->req)) {
        CLIENT_ERR("Error creating KMIP activate request: %s", kms_request_get_error(kms_ctx->req));
        goto done;
    }

    reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen);
    if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) {
        CLIENT_ERR("Error storing KMS request payload");
        goto done;
    }

    ret = true;
done:
    return ret;
}

bool _mongocrypt_kms_ctx_init_kmip_get(mongocrypt_kms_ctx_t *kms_ctx,
                                       const _mongocrypt_endpoint_t *endpoint,
                                       const char *unique_identifier,
                                       const char *kmsid,
                                       _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms_ctx);
    BSON_ASSERT_PARAM(endpoint);
    BSON_ASSERT_PARAM(unique_identifier);

    mongocrypt_status_t *status;
    bool ret = false;
    size_t reqlen;
    const uint8_t *reqdata;

    _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_GET, kmsid);
    status = kms_ctx->status;

    kms_ctx->endpoint = bson_strdup(endpoint->host_and_port);
    _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT);
    kms_ctx->req = kms_kmip_request_get_new(NULL /* reserved */, unique_identifier);

    if (kms_request_get_error(kms_ctx->req)) {
        CLIENT_ERR("Error creating KMIP get request: %s", kms_request_get_error(kms_ctx->req));
        goto done;
    }

    reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen);
    if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) {
        CLIENT_ERR("Error storing KMS request payload");
        goto done;
    }

    ret = true;
done:
    return ret;
}

bool _mongocrypt_kms_ctx_init_kmip_create(mongocrypt_kms_ctx_t *kms_ctx,
                                          const _mongocrypt_endpoint_t *endpoint,
                                          const char *kmsid,
                                          _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms_ctx);
    BSON_ASSERT_PARAM(endpoint);
    bool ret = false;

    _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_CREATE, kmsid);
    mongocrypt_status_t *status = kms_ctx->status;
    kms_ctx->endpoint = bson_strdup(endpoint->host_and_port);
    _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT);

    kms_ctx->req = kms_kmip_request_create_new(NULL /* reserved */);

    if (kms_request_get_error(kms_ctx->req)) {
        CLIENT_ERR("Error creating KMIP create request: %s", kms_request_get_error(kms_ctx->req));
        goto done;
    }

    size_t reqlen;
    const uint8_t *reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen);
    if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) {
        CLIENT_ERR("Error storing KMS request payload");
        goto done;
    }

    ret = true;
done:
    return ret;
}

bool _mongocrypt_kms_ctx_init_kmip_encrypt(mongocrypt_kms_ctx_t *kms_ctx,
                                           const _mongocrypt_endpoint_t *endpoint,
                                           const char *unique_identifier,
                                           const char *kmsid,
                                           _mongocrypt_buffer_t *plaintext,
                                           _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms_ctx);
    BSON_ASSERT_PARAM(endpoint);
    BSON_ASSERT_PARAM(plaintext);
    bool ret = false;

    _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_ENCRYPT, kmsid);
    mongocrypt_status_t *status = kms_ctx->status;
    kms_ctx->endpoint = bson_strdup(endpoint->host_and_port);
    _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT);

    kms_ctx->req =
        kms_kmip_request_encrypt_new(NULL /* reserved */, unique_identifier, plaintext->data, plaintext->len);

    if (kms_request_get_error(kms_ctx->req)) {
        CLIENT_ERR("Error creating KMIP encrypt request: %s", kms_request_get_error(kms_ctx->req));
        goto done;
    }

    size_t reqlen;
    const uint8_t *reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen);
    if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) {
        CLIENT_ERR("Error storing KMS request payload");
        goto done;
    }

    ret = true;
done:
    return ret;
}

bool _mongocrypt_kms_ctx_init_kmip_decrypt(mongocrypt_kms_ctx_t *kms_ctx,
                                           const _mongocrypt_endpoint_t *endpoint,
                                           const char *kmsid,
                                           _mongocrypt_key_doc_t *key,
                                           _mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(kms_ctx);
    BSON_ASSERT_PARAM(endpoint);
    BSON_ASSERT_PARAM(key);
    bool ret = false;

    _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_DECRYPT, kmsid);
    mongocrypt_status_t *status = kms_ctx->status;
    kms_ctx->endpoint = bson_strdup(endpoint->host_and_port);
    _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT);

    _mongocrypt_buffer_t iv;
    if (!_mongocrypt_buffer_from_subrange(&iv, &key->key_material, 0, MONGOCRYPT_IV_LEN)) {
        CLIENT_ERR("Error getting IV from key material");
        goto done;
    }
    _mongocrypt_buffer_t ciphertext;
    if (!_mongocrypt_buffer_from_subrange(&ciphertext,
                                          &key->key_material,
                                          MONGOCRYPT_IV_LEN,
                                          key->key_material.len - MONGOCRYPT_IV_LEN)) {
        CLIENT_ERR("Error getting ciphertext from key material");
        goto done;
    }

    BSON_ASSERT(key->kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_KMIP);
    BSON_ASSERT(key->kek.provider.kmip.delegated);
    kms_ctx->req = kms_kmip_request_decrypt_new(NULL /* reserved */,
                                                key->kek.provider.kmip.key_id,
                                                ciphertext.data,
                                                ciphertext.len,
                                                iv.data,
                                                iv.len);

    if (kms_request_get_error(kms_ctx->req)) {
        CLIENT_ERR("Error creating KMIP decrypt request: %s", kms_request_get_error(kms_ctx->req));
        goto done;
    }

    size_t reqlen;
    const uint8_t *reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen);
    if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) {
        CLIENT_ERR("Error storing KMS request payload");
        goto done;
    }

    ret = true;
done:
    return ret;
}

static const char *set_and_ret(const char *what, uint32_t *len) {
    BSON_ASSERT_PARAM(what);

    if (len) {
        BSON_ASSERT(size_to_uint32(strlen(what), len));
    }
    return what;
}

const char *mongocrypt_kms_ctx_get_kms_provider(mongocrypt_kms_ctx_t *kms, uint32_t *len) {
    BSON_ASSERT_PARAM(kms);
    /* len is checked in set_and_ret () before it is used */

    return set_and_ret(kms->kmsid, len);
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-log-private.h0000644000175100001660000000674014760300420021213 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_LOG_PRIVATE_H
#define MONGOCRYPT_LOG_PRIVATE_H

#include "mongocrypt-mutex-private.h"
#include "mongocrypt.h"

typedef struct {
    mongocrypt_mutex_t mutex; /* protects fn and ctx. */
    mongocrypt_log_fn_t fn;
    void *ctx;
    bool trace_enabled;
} _mongocrypt_log_t;

void _mongocrypt_stdout_log_fn(mongocrypt_log_level_t level, const char *message, uint32_t message_len, void *ctx);

void _mongocrypt_log(_mongocrypt_log_t *log, mongocrypt_log_level_t level, const char *message, ...)
    BSON_GNUC_PRINTF(3, 4);

void _mongocrypt_log_init(_mongocrypt_log_t *log);

void _mongocrypt_log_cleanup(_mongocrypt_log_t *log);

void _mongocrypt_log_set_fn(_mongocrypt_log_t *log, mongocrypt_log_fn_t fn, void *ctx);

#ifdef MONGOCRYPT_ENABLE_TRACE

#define CRYPT_TRACEF(log, fmt, ...)                                                                                    \
    _mongocrypt_log(log, MONGOCRYPT_LOG_LEVEL_TRACE, "(%s:%d) " fmt, BSON_FUNC, __LINE__, __VA_ARGS__)

#define CRYPT_TRACE(log, msg) CRYPT_TRACEF(crypt, "%s", msg)

#define CRYPT_ENTRY(log) _mongocrypt_log(crypt, MONGOCRYPT_LOG_LEVEL_TRACE, "entry (%s:%d)", BSON_FUNC, __LINE__)

#define CRYPT_EXIT(log)                                                                                                \
    do {                                                                                                               \
        _mongocrypt_log(crypt, MONGOCRYPT_LOG_LEVEL_TRACE, "exit (%s:%d)", BSON_FUNC, __LINE__);                       \
        return;                                                                                                        \
    } while (0)

#define CRYPT_RETURN(log, x)                                                                                           \
    do {                                                                                                               \
        _mongocrypt_log(log, MONGOCRYPT_LOG_LEVEL_TRACE, "return (%s:%d)", BSON_FUNC, __LINE__);                       \
        return (x);                                                                                                    \
    } while (0)

#define CRYPT_GOTO(log, x)                                                                                             \
    do {                                                                                                               \
        _mongocrypt_log(log, MONGOCRYPT_LOG_LEVEL_TRACE, "goto (%s:%d)", BSON_FUNC, __LINE__);                         \
        goto x;                                                                                                        \
    } while (0)

#else

#define CRYPT_TRACEF(log, fmt, ...)
#define CRYPT_TRACE(log, msg)
#define CRYPT_ENTRY(log)
#define CRYPT_EXIT(log)
#define CRYPT_RETURN(log, x) return (x);
#define CRYPT_GOTO(log, x) goto x;

#endif /* MONGOCRYPT_ENABLE_TRACE */

#endif /* MONGOCRYPT_LOG_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-log.c0000644000175100001660000000506214760300420017532 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include "mongocrypt-config.h"
#include "mongocrypt-log-private.h"
#include "mongocrypt-opts-private.h"

#include 

void _mongocrypt_log_init(_mongocrypt_log_t *log) {
    BSON_ASSERT_PARAM(log);

    _mongocrypt_mutex_init(&log->mutex);
    /* Initially, no log function is set. */
    _mongocrypt_log_set_fn(log, NULL, NULL);
#ifdef MONGOCRYPT_ENABLE_TRACE
    log->trace_enabled = (getenv("MONGOCRYPT_TRACE") != NULL);
#endif
}

void _mongocrypt_log_cleanup(_mongocrypt_log_t *log) {
    if (!log) {
        return;
    }

    _mongocrypt_mutex_cleanup(&log->mutex);
}

void _mongocrypt_stdout_log_fn(mongocrypt_log_level_t level, const char *message, uint32_t message_len, void *ctx) {
    BSON_ASSERT_PARAM(message);

    switch (level) {
    case MONGOCRYPT_LOG_LEVEL_FATAL: printf("FATAL"); break;
    case MONGOCRYPT_LOG_LEVEL_ERROR: printf("ERROR"); break;
    case MONGOCRYPT_LOG_LEVEL_WARNING: printf("WARNING"); break;
    case MONGOCRYPT_LOG_LEVEL_INFO: printf("INFO"); break;
    case MONGOCRYPT_LOG_LEVEL_TRACE: printf("TRACE"); break;
    default: printf("UNKNOWN"); break;
    }
    printf(" %s\n", message);
}

void _mongocrypt_log_set_fn(_mongocrypt_log_t *log, mongocrypt_log_fn_t fn, void *ctx) {
    BSON_ASSERT_PARAM(log);

    _mongocrypt_mutex_lock(&log->mutex);
    log->fn = fn;
    log->ctx = ctx;
    _mongocrypt_mutex_unlock(&log->mutex);
}

void _mongocrypt_log(_mongocrypt_log_t *log, mongocrypt_log_level_t level, const char *format, ...) {
    va_list args;
    char *message;

    BSON_ASSERT_PARAM(log);
    BSON_ASSERT_PARAM(format);

    if (level == MONGOCRYPT_LOG_LEVEL_TRACE && !log->trace_enabled) {
        return;
    }

    va_start(args, format);
    message = bson_strdupv_printf(format, args);
    va_end(args);

    BSON_ASSERT(message);

    _mongocrypt_mutex_lock(&log->mutex);
    if (log->fn) {
        log->fn(level, message, (uint32_t)strlen(message), log->ctx);
    }
    _mongocrypt_mutex_unlock(&log->mutex);
    bson_free(message);
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-marking-private.h0000644000175100001660000000547514760300420022066 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_MARKING_PRIVATE_H
#define MONGOCRYPT_MARKING_PRIVATE_H

#include "mc-fle2-encryption-placeholder-private.h"
#include "mc-range-mincover-private.h"
#include "mongocrypt-ciphertext-private.h"
#include "mongocrypt-private.h"

typedef enum {
    MONGOCRYPT_MARKING_FLE1_BY_ID,
    MONGOCRYPT_MARKING_FLE1_BY_ALTNAME,
    MONGOCRYPT_MARKING_FLE2_ENCRYPTION,
} mongocrypt_marking_type_t;

typedef struct {
    mongocrypt_marking_type_t type;

    union {
        struct {
            // Markings used by FLE1
            mongocrypt_encryption_algorithm_t algorithm;
            bson_iter_t v_iter;

            _mongocrypt_buffer_t key_id;
            bson_value_t key_alt_name;
        };

        mc_FLE2EncryptionPlaceholder_t fle2;
    };
} _mongocrypt_marking_t;

// `_mongocrypt_marking_t` inherits extended alignment from libbson. To dynamically allocate, use aligned allocation
// (e.g. BSON_ALIGNED_ALLOC)
BSON_STATIC_ASSERT2(alignof__mongocrypt_marking_t, BSON_ALIGNOF(_mongocrypt_marking_t) >= BSON_ALIGNOF(bson_iter_t));

void _mongocrypt_marking_init(_mongocrypt_marking_t *marking);

void _mongocrypt_marking_cleanup(_mongocrypt_marking_t *marking);

bool _mongocrypt_marking_parse_unowned(const _mongocrypt_buffer_t *in,
                                       _mongocrypt_marking_t *out,
                                       mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

// Callers are expected to initialize `ciphertext` with
// `_mongocrypt_ciphertext_init before calling,
// and eventually free it using `_mongocrypt_ciphertext_cleanup`.
bool _mongocrypt_marking_to_ciphertext(void *ctx,
                                       _mongocrypt_marking_t *marking,
                                       _mongocrypt_ciphertext_t *ciphertext,
                                       mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

mc_mincover_t *mc_get_mincover_from_FLE2RangeFindSpec(mc_FLE2RangeFindSpec_t *findSpec,
                                                      size_t sparsity,
                                                      mongocrypt_status_t *status,
                                                      bool use_range_v2) MONGOCRYPT_WARN_UNUSED_RESULT;

#endif /* MONGOCRYPT_MARKING_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-marking.c0000644000175100001660000026522414760300420020411 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#include "mc-fle-blob-subtype-private.h"
#include "mc-fle2-encryption-placeholder-private.h"
#include "mc-fle2-find-equality-payload-private-v2.h"
#include "mc-fle2-find-equality-payload-private.h"
#include "mc-fle2-find-range-payload-private-v2.h"
#include "mc-fle2-find-range-payload-private.h"
#include "mc-fle2-insert-update-payload-private-v2.h"
#include "mc-fle2-insert-update-payload-private.h"
#include "mc-fle2-payload-uev-private.h"
#include "mc-fle2-payload-uev-v2-private.h"
#include "mc-optional-private.h"
#include "mc-range-edge-generation-private.h"
#include "mc-range-encoding-private.h"
#include "mc-range-mincover-private.h"
#include "mc-tokens-private.h"
#include "mongocrypt-buffer-private.h"
#include "mongocrypt-ciphertext-private.h"
#include "mongocrypt-crypto-private.h"
#include "mongocrypt-key-broker-private.h"
#include "mongocrypt-marking-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt-util-private.h" // mc_bson_type_to_string
#include "mongocrypt.h"

#include  // isinf

static bool
_mongocrypt_marking_parse_fle1_placeholder(const bson_t *in, _mongocrypt_marking_t *out, mongocrypt_status_t *status) {
    bson_iter_t iter = {0};
    bool has_ki = false, has_ka = false, has_a = false, has_v = false;

    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    out->type = MONGOCRYPT_MARKING_FLE1_BY_ID;

    if (!bson_iter_init(&iter, in)) {
        CLIENT_ERR("invalid BSON");
        return false;
    }

    while (bson_iter_next(&iter)) {
        const char *field;

        field = bson_iter_key(&iter);
        BSON_ASSERT(field);
        if (0 == strcmp("ki", field)) {
            has_ki = true;
            if (!_mongocrypt_buffer_from_uuid_iter(&out->key_id, &iter)) {
                CLIENT_ERR("key id must be a UUID");
                return false;
            }
            continue;
        }

        if (0 == strcmp("ka", field)) {
            has_ka = true;
            /* Some bson_value types are not allowed to be key alt names */
            const bson_value_t *value;

            value = bson_iter_value(&iter);

            if (!BSON_ITER_HOLDS_UTF8(&iter)) {
                CLIENT_ERR("key alt name must be a UTF8");
                return false;
            }
            /* CDRIVER-3100 We must make a copy of this value; the result of
             * bson_iter_value is ephemeral. */
            bson_value_copy(value, &out->key_alt_name);
            out->type = MONGOCRYPT_MARKING_FLE1_BY_ALTNAME;
            continue;
        }

        if (0 == strcmp("v", field)) {
            has_v = true;
            memcpy(&out->v_iter, &iter, sizeof(bson_iter_t));
            continue;
        }

        if (0 == strcmp("a", field)) {
            int32_t algorithm;

            has_a = true;
            if (!BSON_ITER_HOLDS_INT32(&iter)) {
                CLIENT_ERR("invalid marking, 'a' must be an int32");
                return false;
            }
            algorithm = bson_iter_int32(&iter);
            if (algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_DETERMINISTIC
                && algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_RANDOM) {
                CLIENT_ERR("invalid algorithm value: %d", algorithm);
                return false;
            }
            out->algorithm = (mongocrypt_encryption_algorithm_t)algorithm;
            continue;
        }

        CLIENT_ERR("unrecognized field '%s'", field);
        return false;
    }

    if (!has_v) {
        CLIENT_ERR("no 'v' specified");
        return false;
    }

    if (!has_ki && !has_ka) {
        CLIENT_ERR("neither 'ki' nor 'ka' specified");
        return false;
    }

    if (has_ki && has_ka) {
        CLIENT_ERR("both 'ki' and 'ka' specified");
        return false;
    }

    if (!has_a) {
        CLIENT_ERR("no 'a' specified");
        return false;
    }

    return true;
}

static bool
_mongocrypt_marking_parse_fle2_placeholder(const bson_t *in, _mongocrypt_marking_t *out, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    out->type = MONGOCRYPT_MARKING_FLE2_ENCRYPTION;
    return mc_FLE2EncryptionPlaceholder_parse(&out->fle2, in, status);
}

bool _mongocrypt_marking_parse_unowned(const _mongocrypt_buffer_t *in,
                                       _mongocrypt_marking_t *out,
                                       mongocrypt_status_t *status) {
    bson_t bson;

    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    _mongocrypt_marking_init(out);
    /* 5 for minimal BSON object, plus one for blob subtype */
    if (in->len < 6) {
        CLIENT_ERR("invalid marking, length < 6");
        return false;
    }

    if (!bson_init_static(&bson, in->data + 1, in->len - 1) || !bson_validate(&bson, BSON_VALIDATE_NONE, NULL)) {
        CLIENT_ERR("invalid BSON");
        return false;
    }

    if (in->data[0] == MC_SUBTYPE_FLE1EncryptionPlaceholder) {
        return _mongocrypt_marking_parse_fle1_placeholder(&bson, out, status);
    } else if (in->data[0] == MC_SUBTYPE_FLE2EncryptionPlaceholder) {
        return _mongocrypt_marking_parse_fle2_placeholder(&bson, out, status);
    } else {
        CLIENT_ERR("invalid marking, first byte must be 0 or 3");
        return false;
    }
}

void _mongocrypt_marking_init(_mongocrypt_marking_t *marking) {
    BSON_ASSERT_PARAM(marking);

    memset(marking, 0, sizeof(*marking));
}

void _mongocrypt_marking_cleanup(_mongocrypt_marking_t *marking) {
    if (!marking) {
        return;
    }
    if (marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION) {
        mc_FLE2EncryptionPlaceholder_cleanup(&marking->fle2);
        return;
    }

    // else FLE1
    _mongocrypt_buffer_cleanup(&marking->key_id);
    bson_value_destroy(&marking->key_alt_name);
}

/**
 * Calculates:
 * E?CToken = HMAC(collectionLevel1Token, n)
 * E?CDerivedFromDataToken = HMAC(E?CToken, value)
 * E?CDerivedFromDataTokenAndContentionFactor = HMAC(E?CDerivedFromDataToken, cf)
 *
 * E?C = EDC|ESC|ECC
 * n = 1 for EDC, 2 for ESC, 3 for ECC
 * cf = contentionFactor
 *
 * If {useContentionFactor} is False, E?CDerivedFromDataToken is saved to out, and {contentionFactor} is ignored.
 * Otherwise, E?CDerivedFromDataTokenAndContentionFactor is saved to out using {contentionFactor}.
 *
 * Note that {out} is initialized even on failure.
 */
#define DERIVE_TOKEN_IMPL(Name)                                                                                        \
    static bool _fle2_derive_##Name##_token(_mongocrypt_crypto_t *crypto,                                              \
                                            _mongocrypt_buffer_t *out,                                                 \
                                            const mc_CollectionsLevel1Token_t *level1Token,                            \
                                            const _mongocrypt_buffer_t *value,                                         \
                                            bool useContentionFactor,                                                  \
                                            int64_t contentionFactor,                                                  \
                                            mongocrypt_status_t *status) {                                             \
        BSON_ASSERT_PARAM(crypto);                                                                                     \
        BSON_ASSERT_PARAM(out);                                                                                        \
        BSON_ASSERT_PARAM(level1Token);                                                                                \
        BSON_ASSERT_PARAM(value);                                                                                      \
                                                                                                                       \
        _mongocrypt_buffer_init(out);                                                                                  \
                                                                                                                       \
        mc_##Name##Token_t *token = mc_##Name##Token_new(crypto, level1Token, status);                                 \
        if (!token) {                                                                                                  \
            return false;                                                                                              \
        }                                                                                                              \
                                                                                                                       \
        mc_##Name##DerivedFromDataToken_t *fromDataToken =                                                             \
            mc_##Name##DerivedFromDataToken_new(crypto, token, value, status);                                         \
        mc_##Name##Token_destroy(token);                                                                               \
        if (!fromDataToken) {                                                                                          \
            return false;                                                                                              \
        }                                                                                                              \
                                                                                                                       \
        if (!useContentionFactor) {                                                                                    \
            /* FindEqualityPayload uses *fromDataToken */                                                              \
            _mongocrypt_buffer_copy_to(mc_##Name##DerivedFromDataToken_get(fromDataToken), out);                       \
            mc_##Name##DerivedFromDataToken_destroy(fromDataToken);                                                    \
            return true;                                                                                               \
        }                                                                                                              \
                                                                                                                       \
        BSON_ASSERT(contentionFactor >= 0);                                                                            \
        /* InsertUpdatePayload continues through *fromDataTokenAndContentionFactor */                                  \
        mc_##Name##DerivedFromDataTokenAndContentionFactor_t *fromTokenAndContentionFactor =                           \
            mc_##Name##DerivedFromDataTokenAndContentionFactor_new(crypto,                                             \
                                                                   fromDataToken,                                      \
                                                                   (uint64_t)contentionFactor,                         \
                                                                   status);                                            \
        mc_##Name##DerivedFromDataToken_destroy(fromDataToken);                                                        \
        if (!fromTokenAndContentionFactor) {                                                                           \
            return false;                                                                                              \
        }                                                                                                              \
                                                                                                                       \
        _mongocrypt_buffer_copy_to(                                                                                    \
            mc_##Name##DerivedFromDataTokenAndContentionFactor_get(fromTokenAndContentionFactor),                      \
            out);                                                                                                      \
        mc_##Name##DerivedFromDataTokenAndContentionFactor_destroy(fromTokenAndContentionFactor);                      \
                                                                                                                       \
        return true;                                                                                                   \
    }

DERIVE_TOKEN_IMPL(EDC)
DERIVE_TOKEN_IMPL(ESC)
DERIVE_TOKEN_IMPL(ECC)

#undef DERIVE_TOKEN_IMPL

static bool _fle2_derive_serverDerivedFromDataToken(_mongocrypt_crypto_t *crypto,
                                                    _mongocrypt_buffer_t *out,
                                                    const mc_ServerTokenDerivationLevel1Token_t *level1Token,
                                                    const _mongocrypt_buffer_t *value,
                                                    mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(out);
    BSON_ASSERT_PARAM(level1Token);
    BSON_ASSERT_PARAM(value);
    BSON_ASSERT_PARAM(status);

    _mongocrypt_buffer_init(out);

    mc_ServerDerivedFromDataToken_t *token = mc_ServerDerivedFromDataToken_new(crypto, level1Token, value, status);
    if (!token) {
        return false;
    }

    _mongocrypt_buffer_copy_to(mc_ServerDerivedFromDataToken_get(token), out);
    mc_ServerDerivedFromDataToken_destroy(token);
    return true;
}

static bool _fle2_placeholder_aes_ctr_encrypt(_mongocrypt_crypto_t *crypto,
                                              const _mongocrypt_buffer_t *key,
                                              const _mongocrypt_buffer_t *in,
                                              _mongocrypt_buffer_t *out,
                                              mongocrypt_status_t *status) {
    const _mongocrypt_value_encryption_algorithm_t *fle2alg = _mcFLE2Algorithm();
    BSON_ASSERT_PARAM(crypto);
    BSON_ASSERT_PARAM(key);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);

    _mongocrypt_buffer_t iv;
    const uint32_t cipherlen = fle2alg->get_ciphertext_len(in->len, status);
    if (cipherlen == 0) {
        return false;
    }
    uint32_t written = 0;

    _mongocrypt_buffer_init_size(out, cipherlen);

    BSON_ASSERT(_mongocrypt_buffer_from_subrange(&iv, out, 0, MONGOCRYPT_IV_LEN));
    if (!_mongocrypt_random(crypto, &iv, MONGOCRYPT_IV_LEN, status)) {
        return false;
    }

    if (!fle2alg->do_encrypt(crypto, &iv, NULL /* aad */, key, in, out, &written, status)) {
        _mongocrypt_buffer_cleanup(out);
        _mongocrypt_buffer_init(out);
        return false;
    }

    return true;
}

static bool _fle2_placeholder_aes_aead_encrypt(_mongocrypt_key_broker_t *kb,
                                               const _mongocrypt_value_encryption_algorithm_t *algorithm,
                                               _mongocrypt_buffer_t *out,
                                               const _mongocrypt_buffer_t *keyId,
                                               const _mongocrypt_buffer_t *in,
                                               mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(keyId);
    BSON_ASSERT_PARAM(in);
    BSON_ASSERT_PARAM(out);
    BSON_ASSERT(kb->crypt);

    _mongocrypt_crypto_t *crypto = kb->crypt->crypto;
    _mongocrypt_buffer_t iv, key;
    const uint32_t cipherlen = algorithm->get_ciphertext_len(in->len, status);
    if (cipherlen == 0) {
        return false;
    }
    uint32_t written = 0;
    bool res;

    if (!_mongocrypt_key_broker_decrypted_key_by_id(kb, keyId, &key)) {
        CLIENT_ERR("unable to retrieve key");
        return false;
    }

    _mongocrypt_buffer_init_size(&iv, MONGOCRYPT_IV_LEN);
    if (!_mongocrypt_random(crypto, &iv, iv.len, status)) {
        _mongocrypt_buffer_cleanup(&key);
        return false;
    }

    _mongocrypt_buffer_init_size(out, cipherlen);
    res = algorithm->do_encrypt(crypto, &iv, keyId, &key, in, out, &written, status);
    _mongocrypt_buffer_cleanup(&key);
    _mongocrypt_buffer_cleanup(&iv);

    if (!res) {
        _mongocrypt_buffer_cleanup(out);
        _mongocrypt_buffer_init(out);
        return false;
    }

    return true;
}

// FLE V1: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor ||
//                            ECCDerivedFromDataTokenAndContentionFactor)
// FLE V2: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor)
// Range V2: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor || isLeaf)
static bool _fle2_derive_encrypted_token(_mongocrypt_crypto_t *crypto,
                                         _mongocrypt_buffer_t *out,
                                         bool use_range_v2,
                                         const mc_CollectionsLevel1Token_t *collectionsLevel1Token,
                                         const _mongocrypt_buffer_t *escDerivedToken,
                                         const _mongocrypt_buffer_t *eccDerivedToken,
                                         mc_optional_bool_t is_leaf,
                                         mongocrypt_status_t *status) {
    mc_ECOCToken_t *ecocToken = mc_ECOCToken_new(crypto, collectionsLevel1Token, status);
    if (!ecocToken) {
        return false;
    }
    bool ok = false;

    _mongocrypt_buffer_t tmp;
    _mongocrypt_buffer_init(&tmp);
    const _mongocrypt_buffer_t *p = &tmp;
    if (!eccDerivedToken) {
        // FLE2v2
        if (use_range_v2 && is_leaf.set) {
            // Range V2; concat isLeaf
            _mongocrypt_buffer_t isLeafBuf;
            if (!_mongocrypt_buffer_copy_from_data_and_size(&isLeafBuf, (uint8_t[]){is_leaf.value}, 1)) {
                CLIENT_ERR("failed to create is_leaf buffer");
                goto fail;
            }
            if (!_mongocrypt_buffer_concat(&tmp, (_mongocrypt_buffer_t[]){*escDerivedToken, isLeafBuf}, 2)) {
                CLIENT_ERR("failed to allocate buffer");
                _mongocrypt_buffer_cleanup(&isLeafBuf);
                goto fail;
            }
            _mongocrypt_buffer_cleanup(&isLeafBuf);
        } else {
            p = escDerivedToken;
        }

    } else {
        // FLE2v1
        const _mongocrypt_buffer_t tokens[] = {*escDerivedToken, *eccDerivedToken};
        if (!_mongocrypt_buffer_concat(&tmp, tokens, 2)) {
            CLIENT_ERR("failed to allocate buffer");
            goto fail;
        }
    }

    if (!_fle2_placeholder_aes_ctr_encrypt(crypto, mc_ECOCToken_get(ecocToken), p, out, status)) {
        goto fail;
    }

    ok = true;
fail:
    _mongocrypt_buffer_cleanup(&tmp);
    mc_ECOCToken_destroy(ecocToken);
    return ok;
}

// Field derivations shared by both INSERT and FIND payloads.
typedef struct {
    _mongocrypt_buffer_t tokenKey;
    mc_CollectionsLevel1Token_t *collectionsLevel1Token;
    mc_ServerDataEncryptionLevel1Token_t *serverDataEncryptionLevel1Token;
    mc_ServerTokenDerivationLevel1Token_t *serverTokenDerivationLevel1Token; // v2
    _mongocrypt_buffer_t edcDerivedToken;
    _mongocrypt_buffer_t escDerivedToken;
    _mongocrypt_buffer_t eccDerivedToken;            // v1
    _mongocrypt_buffer_t serverDerivedFromDataToken; // v2
} _FLE2EncryptedPayloadCommon_t;

static void _FLE2EncryptedPayloadCommon_cleanup(_FLE2EncryptedPayloadCommon_t *common) {
    if (!common) {
        return;
    }

    _mongocrypt_buffer_cleanup(&common->tokenKey);
    mc_CollectionsLevel1Token_destroy(common->collectionsLevel1Token);
    mc_ServerDataEncryptionLevel1Token_destroy(common->serverDataEncryptionLevel1Token);
    mc_ServerTokenDerivationLevel1Token_destroy(common->serverTokenDerivationLevel1Token);
    _mongocrypt_buffer_cleanup(&common->edcDerivedToken);
    _mongocrypt_buffer_cleanup(&common->escDerivedToken);
    _mongocrypt_buffer_cleanup(&common->eccDerivedToken);
    _mongocrypt_buffer_cleanup(&common->serverDerivedFromDataToken);
    // Zero out memory so `_FLE2EncryptedPayloadCommon_cleanup` is safe to call twice.
    *common = (_FLE2EncryptedPayloadCommon_t){{0}};
}

// _get_tokenKey returns the tokenKey identified by indexKeyId.
// Returns false on error.
static bool _get_tokenKey(_mongocrypt_key_broker_t *kb,
                          const _mongocrypt_buffer_t *indexKeyId,
                          _mongocrypt_buffer_t *tokenKey,
                          mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(indexKeyId);
    BSON_ASSERT_PARAM(tokenKey);

    _mongocrypt_buffer_t indexKey = {0};
    _mongocrypt_buffer_init(tokenKey);

    if (!_mongocrypt_key_broker_decrypted_key_by_id(kb, indexKeyId, &indexKey)) {
        CLIENT_ERR("unable to retrieve key");
        return false;
    }

    if (indexKey.len != MONGOCRYPT_KEY_LEN) {
        CLIENT_ERR("invalid indexKey, expected len=%" PRIu32 ", got len=%" PRIu32, MONGOCRYPT_KEY_LEN, indexKey.len);
        _mongocrypt_buffer_cleanup(&indexKey);
        return false;
    }

    // indexKey is 3 equal sized keys: [Ke][Km][TokenKey]
    BSON_ASSERT(MONGOCRYPT_KEY_LEN == (3 * MONGOCRYPT_TOKEN_KEY_LEN));
    if (!_mongocrypt_buffer_copy_from_data_and_size(tokenKey,
                                                    indexKey.data + (2 * MONGOCRYPT_TOKEN_KEY_LEN),
                                                    MONGOCRYPT_TOKEN_KEY_LEN)) {
        CLIENT_ERR("failed allocating memory for token key");
        _mongocrypt_buffer_cleanup(&indexKey);
        return false;
    }
    _mongocrypt_buffer_cleanup(&indexKey);
    return true;
}

static bool _mongocrypt_fle2_placeholder_common(_mongocrypt_key_broker_t *kb,
                                                _FLE2EncryptedPayloadCommon_t *ret,
                                                const _mongocrypt_buffer_t *indexKeyId,
                                                const _mongocrypt_buffer_t *value,
                                                bool useContentionFactor,
                                                int64_t contentionFactor,
                                                mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(ret);
    BSON_ASSERT_PARAM(indexKeyId);
    BSON_ASSERT_PARAM(value);

    _mongocrypt_crypto_t *crypto = kb->crypt->crypto;
    _mongocrypt_buffer_t indexKey = {0};
    *ret = (_FLE2EncryptedPayloadCommon_t){{0}};

    if (!_get_tokenKey(kb, indexKeyId, &ret->tokenKey, status)) {
        goto fail;
    }

    ret->collectionsLevel1Token = mc_CollectionsLevel1Token_new(crypto, &ret->tokenKey, status);
    if (!ret->collectionsLevel1Token) {
        CLIENT_ERR("unable to derive collectionLevel1Token");
        goto fail;
    }

    ret->serverDataEncryptionLevel1Token = mc_ServerDataEncryptionLevel1Token_new(crypto, &ret->tokenKey, status);
    if (!ret->serverDataEncryptionLevel1Token) {
        CLIENT_ERR("unable to derive serverDataEncryptionLevel1Token");
        goto fail;
    }

    if (!_fle2_derive_EDC_token(crypto,
                                &ret->edcDerivedToken,
                                ret->collectionsLevel1Token,
                                value,
                                useContentionFactor,
                                contentionFactor,
                                status)) {
        goto fail;
    }

    if (!_fle2_derive_ESC_token(crypto,
                                &ret->escDerivedToken,
                                ret->collectionsLevel1Token,
                                value,
                                useContentionFactor,
                                contentionFactor,
                                status)) {
        goto fail;
    }

    if (kb->crypt->opts.use_fle2_v2) {
        /* FLE2v2 */
        ret->serverTokenDerivationLevel1Token = mc_ServerTokenDerivationLevel1Token_new(crypto, &ret->tokenKey, status);
        if (!ret->serverTokenDerivationLevel1Token) {
            CLIENT_ERR("unable to derive serverTokenDerivationLevel1Token");
            goto fail;
        }

        if (!_fle2_derive_serverDerivedFromDataToken(crypto,
                                                     &ret->serverDerivedFromDataToken,
                                                     ret->serverTokenDerivationLevel1Token,
                                                     value,
                                                     status)) {
            goto fail;
        }
    } else {
        /* FLE2v1 */
        if (!_fle2_derive_ECC_token(crypto,
                                    &ret->eccDerivedToken,
                                    ret->collectionsLevel1Token,
                                    value,
                                    useContentionFactor,
                                    contentionFactor,
                                    status)) {
            goto fail;
        }
    }

    _mongocrypt_buffer_cleanup(&indexKey);
    return true;

fail:
    _FLE2EncryptedPayloadCommon_cleanup(ret);
    _mongocrypt_buffer_cleanup(&indexKey);
    return false;
}

// Shared implementation for insert/update and insert/update ForRange (v1)
static bool _mongocrypt_fle2_placeholder_to_insert_update_common_v1(_mongocrypt_key_broker_t *kb,
                                                                    mc_FLE2InsertUpdatePayload_t *out,
                                                                    int64_t *contentionFactor,
                                                                    _FLE2EncryptedPayloadCommon_t *common,
                                                                    const mc_FLE2EncryptionPlaceholder_t *placeholder,
                                                                    bson_iter_t *value_iter,
                                                                    mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(out);
    BSON_ASSERT_PARAM(common);
    BSON_ASSERT_PARAM(placeholder);
    BSON_ASSERT_PARAM(value_iter);
    BSON_ASSERT(kb->crypt);
    BSON_ASSERT(kb->crypt->opts.use_fle2_v2 == false);
    BSON_ASSERT(kb->crypt->opts.use_range_v2 == false);
    BSON_ASSERT(placeholder->type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT);

    _mongocrypt_crypto_t *crypto = kb->crypt->crypto;
    _mongocrypt_buffer_t value = {0};
    bool res = false;

    *contentionFactor = 0;
    if (placeholder->maxContentionFactor > 0) {
        /* Choose a random contentionFactor in the inclusive range [0,
         * placeholder->maxContentionFactor] */
        if (!_mongocrypt_random_int64(crypto, placeholder->maxContentionFactor + 1, contentionFactor, status)) {
            goto fail;
        }
    }

    _mongocrypt_buffer_from_iter(&value, value_iter);
    if (!_mongocrypt_fle2_placeholder_common(kb,
                                             common,
                                             &placeholder->index_key_id,
                                             &value,
                                             true, /* derive tokens using contentionFactor */
                                             *contentionFactor,
                                             status)) {
        goto fail;
    }

    // d := EDCDerivedToken
    _mongocrypt_buffer_steal(&out->edcDerivedToken, &common->edcDerivedToken);
    // s := ESCDerivedToken
    _mongocrypt_buffer_steal(&out->escDerivedToken, &common->escDerivedToken);
    // c := ECCDerivedToken
    _mongocrypt_buffer_steal(&out->eccDerivedToken, &common->eccDerivedToken);

    // p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor ||
    // ECCDerivedFromDataTokenAndContentionFactor)
    if (!_fle2_derive_encrypted_token(crypto,
                                      &out->encryptedTokens,
                                      false, // Can't use range V2 with FLE V1
                                      common->collectionsLevel1Token,
                                      &out->escDerivedToken,
                                      &out->eccDerivedToken,
                                      (mc_optional_bool_t){0}, // Unset is_leaf as it's not used in V1
                                      status)) {
        goto fail;
    }

    _mongocrypt_buffer_copy_to(&placeholder->index_key_id,
                               &out->indexKeyId); // u
    out->valueType = bson_iter_type(value_iter);  // t

    // v := UserKeyId + EncryptCTRAEAD(UserKey, value)
    {
        _mongocrypt_buffer_t ciphertext = {0};
        if (!_fle2_placeholder_aes_aead_encrypt(kb,
                                                _mcFLE2AEADAlgorithm(),
                                                &ciphertext,
                                                &placeholder->user_key_id,
                                                &value,
                                                status)) {
            goto fail;
        }
        const _mongocrypt_buffer_t v[2] = {placeholder->user_key_id, ciphertext};
        const bool ok = _mongocrypt_buffer_concat(&out->value, v, 2);
        _mongocrypt_buffer_cleanup(&ciphertext);
        if (!ok) {
            goto fail;
        }
    }

    // e := ServerDataEncryptionLevel1Token
    _mongocrypt_buffer_copy_to(mc_ServerDataEncryptionLevel1Token_get(common->serverDataEncryptionLevel1Token),
                               &out->serverEncryptionToken);

    res = true;
fail:
    _mongocrypt_buffer_cleanup(&value);
    return res;
}

/**
 * Payload subtype 4: FLE2InsertUpdatePayload
 *
 * {d: EDC, s: ESC, c: ECC,
 *  p: encToken, u: indexKeyId, t: type,
 *  v: value, e: serverToken}
 */
static bool _mongocrypt_fle2_placeholder_to_insert_update_ciphertext_v1(_mongocrypt_key_broker_t *kb,
                                                                        _mongocrypt_marking_t *marking,
                                                                        _mongocrypt_ciphertext_t *ciphertext,
                                                                        mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);
    BSON_ASSERT_PARAM(status);
    BSON_ASSERT(kb->crypt);
    BSON_ASSERT(kb->crypt->opts.use_fle2_v2 == false);
    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
    BSON_ASSERT(marking->fle2.algorithm == MONGOCRYPT_FLE2_ALGORITHM_EQUALITY);

    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    _FLE2EncryptedPayloadCommon_t common = {{0}};
    mc_FLE2InsertUpdatePayload_t payload;
    mc_FLE2InsertUpdatePayload_init(&payload);
    bool res = false;

    int64_t contentionFactor = 0; /* ignored */
    if (!_mongocrypt_fle2_placeholder_to_insert_update_common_v1(kb,
                                                                 &payload,
                                                                 &contentionFactor,
                                                                 &common,
                                                                 placeholder,
                                                                 &placeholder->v_iter,
                                                                 status)) {
        goto fail;
    }

    {
        bson_t out;
        bson_init(&out);
        mc_FLE2InsertUpdatePayload_serialize(&payload, &out);
        _mongocrypt_buffer_steal_from_bson(&ciphertext->data, &out);
    }
    // Do not set ciphertext->original_bson_type and ciphertext->key_id. They are
    // not used for FLE2InsertUpdatePayload.
    ciphertext->blob_subtype = MC_SUBTYPE_FLE2InsertUpdatePayload;

    res = true;
fail:
    mc_FLE2InsertUpdatePayload_cleanup(&payload);
    _FLE2EncryptedPayloadCommon_cleanup(&common);

    return res;
}

// Shared implementation for insert/update and insert/update ForRange (v2)
static bool _mongocrypt_fle2_placeholder_to_insert_update_common(_mongocrypt_key_broker_t *kb,
                                                                 mc_FLE2InsertUpdatePayloadV2_t *out,
                                                                 _FLE2EncryptedPayloadCommon_t *common,
                                                                 const mc_FLE2EncryptionPlaceholder_t *placeholder,
                                                                 bson_iter_t *value_iter,
                                                                 mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(out);
    BSON_ASSERT_PARAM(common);
    BSON_ASSERT_PARAM(placeholder);
    BSON_ASSERT_PARAM(value_iter);
    BSON_ASSERT(kb->crypt);
    BSON_ASSERT(kb->crypt->opts.use_fle2_v2 == true);
    BSON_ASSERT(placeholder->type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT);

    _mongocrypt_crypto_t *crypto = kb->crypt->crypto;
    _mongocrypt_buffer_t value = {0};
    bool res = false;

    out->contentionFactor = 0; // k
    if (placeholder->maxContentionFactor > 0) {
        /* Choose a random contentionFactor in the inclusive range [0,
         * placeholder->maxContentionFactor] */
        if (!_mongocrypt_random_int64(crypto, placeholder->maxContentionFactor + 1, &out->contentionFactor, status)) {
            goto fail;
        }
    }

    _mongocrypt_buffer_from_iter(&value, value_iter);
    if (!_mongocrypt_fle2_placeholder_common(kb,
                                             common,
                                             &placeholder->index_key_id,
                                             &value,
                                             true, /* derive tokens using contentionFactor */
                                             out->contentionFactor,
                                             status)) {
        goto fail;
    }

    // d := EDCDerivedToken
    _mongocrypt_buffer_steal(&out->edcDerivedToken, &common->edcDerivedToken);
    // s := ESCDerivedToken
    _mongocrypt_buffer_steal(&out->escDerivedToken, &common->escDerivedToken);
    BSON_ASSERT(common->eccDerivedToken.data == NULL);

    // p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor)
    // Or in Range V2, when using range: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor || 0x00)
    if (!_fle2_derive_encrypted_token(
            crypto,
            &out->encryptedTokens,
            kb->crypt->opts.use_range_v2,
            common->collectionsLevel1Token,
            &out->escDerivedToken,
            NULL, // unused in v2
            // If this is a range insert, we append isLeaf to the encryptedTokens. Otherwise, we don't.
            placeholder->algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE ? OPT_BOOL(false) : (mc_optional_bool_t){0},
            status)) {
        goto fail;
    }

    _mongocrypt_buffer_copy_to(&placeholder->index_key_id,
                               &out->indexKeyId); // u
    out->valueType = bson_iter_type(value_iter);  // t

    // v := UserKeyId + EncryptCBCAEAD(UserKey, value)
    {
        _mongocrypt_buffer_t ciphertext = {0};
        if (!_fle2_placeholder_aes_aead_encrypt(kb,
                                                _mcFLE2v2AEADAlgorithm(),
                                                &ciphertext,
                                                &placeholder->user_key_id,
                                                &value,
                                                status)) {
            goto fail;
        }
        const _mongocrypt_buffer_t v[2] = {placeholder->user_key_id, ciphertext};
        const bool ok = _mongocrypt_buffer_concat(&out->value, v, 2);
        _mongocrypt_buffer_cleanup(&ciphertext);
        if (!ok) {
            goto fail;
        }
    }

    // e := ServerDataEncryptionLevel1Token
    _mongocrypt_buffer_copy_to(mc_ServerDataEncryptionLevel1Token_get(common->serverDataEncryptionLevel1Token),
                               &out->serverEncryptionToken);

    // l := ServerDerivedFromDataToken
    _mongocrypt_buffer_steal(&out->serverDerivedFromDataToken, &common->serverDerivedFromDataToken);

    res = true;
fail:
    _mongocrypt_buffer_cleanup(&value);
    return res;
}

/**
 * Payload subtype 11: FLE2InsertUpdatePayloadV2
 * Delegates to ..._insert_update_ciphertext_v1 for subtype 4
 *   when crypt.opts.use_fle2_v2 == false
 *
 * {d: EDC, s: ESC, p: encToken,
 *  u: indexKeyId, t: valueType, v: value,
 *  e: serverToken, l: serverDerivedFromDataToken,
 *  k: contentionFactor}
 */
static bool _mongocrypt_fle2_placeholder_to_insert_update_ciphertext(_mongocrypt_key_broker_t *kb,
                                                                     _mongocrypt_marking_t *marking,
                                                                     _mongocrypt_ciphertext_t *ciphertext,
                                                                     mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);
    BSON_ASSERT(kb->crypt);
    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);

    if (!kb->crypt->opts.use_fle2_v2) {
        return _mongocrypt_fle2_placeholder_to_insert_update_ciphertext_v1(kb, marking, ciphertext, status);
    }

    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    _FLE2EncryptedPayloadCommon_t common = {{0}};
    mc_FLE2InsertUpdatePayloadV2_t payload;
    mc_FLE2InsertUpdatePayloadV2_init(&payload);
    bool res = false;

    if (!_mongocrypt_fle2_placeholder_to_insert_update_common(kb,
                                                              &payload,
                                                              &common,
                                                              placeholder,
                                                              &placeholder->v_iter,
                                                              status)) {
        goto fail;
    }

    {
        bson_t out;
        bson_init(&out);
        mc_FLE2InsertUpdatePayloadV2_serialize(&payload, &out);
        _mongocrypt_buffer_steal_from_bson(&ciphertext->data, &out);
    }

    // Do not set ciphertext->original_bson_type and ciphertext->key_id. They are
    // not used for FLE2InsertUpdatePayloadV2.
    ciphertext->blob_subtype = MC_SUBTYPE_FLE2InsertUpdatePayloadV2;

    res = true;
fail:
    mc_FLE2InsertUpdatePayloadV2_cleanup(&payload);
    _FLE2EncryptedPayloadCommon_cleanup(&common);

    return res;
}

// get_edges creates and returns edges from an FLE2RangeInsertSpec. Returns NULL
// on error.
static mc_edges_t *
get_edges(mc_FLE2RangeInsertSpec_t *insertSpec, size_t sparsity, mongocrypt_status_t *status, bool use_range_v2) {
    BSON_ASSERT_PARAM(insertSpec);

    bson_type_t value_type = bson_iter_type(&insertSpec->v);

    if (value_type == BSON_TYPE_INT32) {
        return mc_getEdgesInt32((mc_getEdgesInt32_args_t){.value = bson_iter_int32(&insertSpec->v),
                                                          .min = OPT_I32(bson_iter_int32(&insertSpec->min)),
                                                          .max = OPT_I32(bson_iter_int32(&insertSpec->max)),
                                                          .sparsity = sparsity,
                                                          .trimFactor = insertSpec->trimFactor},
                                status,
                                use_range_v2);
    }

    else if (value_type == BSON_TYPE_INT64) {
        return mc_getEdgesInt64((mc_getEdgesInt64_args_t){.value = bson_iter_int64(&insertSpec->v),
                                                          .min = OPT_I64(bson_iter_int64(&insertSpec->min)),
                                                          .max = OPT_I64(bson_iter_int64(&insertSpec->max)),
                                                          .sparsity = sparsity,
                                                          .trimFactor = insertSpec->trimFactor},
                                status,
                                use_range_v2);
    }

    else if (value_type == BSON_TYPE_DATE_TIME) {
        return mc_getEdgesInt64((mc_getEdgesInt64_args_t){.value = bson_iter_date_time(&insertSpec->v),
                                                          .min = OPT_I64(bson_iter_date_time(&insertSpec->min)),
                                                          .max = OPT_I64(bson_iter_date_time(&insertSpec->max)),
                                                          .sparsity = sparsity,
                                                          .trimFactor = insertSpec->trimFactor},
                                status,
                                use_range_v2);
    }

    else if (value_type == BSON_TYPE_DOUBLE) {
        mc_getEdgesDouble_args_t args = {.value = bson_iter_double(&insertSpec->v),
                                         .sparsity = sparsity,
                                         .trimFactor = insertSpec->trimFactor};
        if (insertSpec->precision.set) {
            // If precision is set, pass min/max/precision to mc_getEdgesDouble.
            // Do not pass min/max if precision is not set. All three must be set
            // or all three must be unset in mc_getTypeInfoDouble.
            args.min = OPT_DOUBLE(bson_iter_double(&insertSpec->min));
            args.max = OPT_DOUBLE(bson_iter_double(&insertSpec->max));
            args.precision = insertSpec->precision;
        }

        return mc_getEdgesDouble(args, status, use_range_v2);
    }

    else if (value_type == BSON_TYPE_DECIMAL128) {
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
        const mc_dec128 value = mc_dec128_from_bson_iter(&insertSpec->v);
        mc_getEdgesDecimal128_args_t args = {
            .value = value,
            .sparsity = sparsity,
            .trimFactor = insertSpec->trimFactor,
        };
        if (insertSpec->precision.set) {
            const mc_dec128 min = mc_dec128_from_bson_iter(&insertSpec->min);
            const mc_dec128 max = mc_dec128_from_bson_iter(&insertSpec->max);
            args.min = OPT_MC_DEC128(min);
            args.max = OPT_MC_DEC128(max);
            args.precision = insertSpec->precision;
        }
        return mc_getEdgesDecimal128(args, status, use_range_v2);
#else // ↑↑↑↑↑↑↑↑ With Decimal128 / Without ↓↓↓↓↓↓↓↓↓↓
        CLIENT_ERR("unsupported BSON type (Decimal128) for range: libmongocrypt "
                   "was built without extended Decimal128 support");
        return NULL;
#endif
    }

    CLIENT_ERR("unsupported BSON type: %s for range", mc_bson_type_to_string(value_type));
    return NULL;
}

/**
 * Payload subtype 4: FLE2InsertUpdatePayload for range updates
 *
 * {d: EDC, s: ESC, c: ECC,
 *  p: encToken, u: indexKeyId, t: type,
 *  v: value, e: serverToken,
 *  g: [{d: EDC, s: ESC, c: ECC, p: encToken},
 *      {d: EDC, s: ESC, c: ECC, p: encToken},
 *      ...]}
 */
static bool _mongocrypt_fle2_placeholder_to_insert_update_ciphertextForRange_v1(_mongocrypt_key_broker_t *kb,
                                                                                _mongocrypt_marking_t *marking,
                                                                                _mongocrypt_ciphertext_t *ciphertext,
                                                                                mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);
    BSON_ASSERT_PARAM(status);
    BSON_ASSERT(kb->crypt);
    BSON_ASSERT(kb->crypt->opts.use_fle2_v2 == false);
    BSON_ASSERT(kb->crypt->opts.use_range_v2 == false);
    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
    BSON_ASSERT(marking->fle2.algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE);

    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    _FLE2EncryptedPayloadCommon_t common = {{0}};
    mc_FLE2InsertUpdatePayload_t payload;
    mc_FLE2InsertUpdatePayload_init(&payload);
    bool res = false;
    mc_edges_t *edges = NULL;

    // Parse the value ("v"), min ("min"), and max ("max") from
    // FLE2EncryptionPlaceholder for range insert.
    mc_FLE2RangeInsertSpec_t insertSpec;
    if (!mc_FLE2RangeInsertSpec_parse(&insertSpec, &placeholder->v_iter, kb->crypt->opts.use_range_v2, status)) {
        goto fail;
    }

    int64_t contentionFactor = 0;
    if (!_mongocrypt_fle2_placeholder_to_insert_update_common_v1(kb,
                                                                 &payload,
                                                                 &contentionFactor,
                                                                 &common,
                                                                 &marking->fle2,
                                                                 &insertSpec.v,
                                                                 status)) {
        goto fail;
    }

    // g:= array
    {
        BSON_ASSERT(placeholder->sparsity >= 0 && (uint64_t)placeholder->sparsity <= (uint64_t)SIZE_MAX);
        edges = get_edges(&insertSpec, (size_t)placeholder->sparsity, status, kb->crypt->opts.use_range_v2);
        if (!edges) {
            goto fail;
        }

        for (size_t i = 0; i < mc_edges_len(edges); ++i) {
            // Create an EdgeTokenSet from each edge.
            bool loop_ok = false;
            const char *edge = mc_edges_get(edges, i);
            _mongocrypt_buffer_t edge_buf = {0};
            _FLE2EncryptedPayloadCommon_t edge_tokens = {{0}};
            _mongocrypt_buffer_t encryptedTokens = {0};
            mc_EdgeTokenSet_t etc = {{0}};

            if (!_mongocrypt_buffer_from_string(&edge_buf, edge)) {
                CLIENT_ERR("failed to copy edge to buffer");
                goto fail_loop;
            }

            if (!_mongocrypt_fle2_placeholder_common(kb,
                                                     &edge_tokens,
                                                     &placeholder->index_key_id,
                                                     &edge_buf,
                                                     true, /* derive tokens using contentionFactor */
                                                     contentionFactor,
                                                     status)) {
                goto fail_loop;
            }

            // d := EDCDerivedToken
            _mongocrypt_buffer_steal(&etc.edcDerivedToken, &edge_tokens.edcDerivedToken);
            // s := ESCDerivedToken
            _mongocrypt_buffer_steal(&etc.escDerivedToken, &edge_tokens.escDerivedToken);
            // c := ECCDerivedToken
            _mongocrypt_buffer_steal(&etc.eccDerivedToken, &edge_tokens.eccDerivedToken);

            // p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor ||
            // ECCDerivedFromDataTokenAndContentionFactor)
            if (!_fle2_derive_encrypted_token(kb->crypt->crypto,
                                              &etc.encryptedTokens,
                                              false, // Range V2 is incompatible with FLE V1
                                              edge_tokens.collectionsLevel1Token,
                                              &etc.escDerivedToken,
                                              &etc.eccDerivedToken,
                                              (mc_optional_bool_t){0}, // Dummy value for isLeaf, unused in FLE V1
                                              status)) {
                goto fail_loop;
            }

            _mc_array_append_val(&payload.edgeTokenSetArray, etc);

            loop_ok = true;
        fail_loop:
            _mongocrypt_buffer_cleanup(&encryptedTokens);
            _FLE2EncryptedPayloadCommon_cleanup(&edge_tokens);
            _mongocrypt_buffer_cleanup(&edge_buf);
            if (!loop_ok) {
                goto fail;
            }
        }
    }

    {
        bson_t out;
        bson_init(&out);
        mc_FLE2InsertUpdatePayload_serializeForRange(&payload, &out);
        _mongocrypt_buffer_steal_from_bson(&ciphertext->data, &out);
    }
    // Do not set ciphertext->original_bson_type and ciphertext->key_id. They are
    // not used for FLE2InsertUpdatePayload.
    ciphertext->blob_subtype = MC_SUBTYPE_FLE2InsertUpdatePayload;

    res = true;
fail:
    mc_edges_destroy(edges);
    mc_FLE2InsertUpdatePayload_cleanup(&payload);
    _FLE2EncryptedPayloadCommon_cleanup(&common);

    return res;
}

/**
 * Payload subtype 11: FLE2InsertUpdatePayloadV2 for range updates
 * Delegates to ..._insert_update_ciphertextForRange_v1 for subtype 4
 *   when crypt.opts.use_fle2_v2 == false
 *
 * {d: EDC, s: ESC, p: encToken,
 *  u: indexKeyId, t: valueType, v: value,
 *  e: serverToken, l: serverDerivedFromDataToken,
 *  k: contentionFactor,
 *  g: [{d: EDC, s: ESC, l: serverDerivedFromDataToken, p: encToken},
 *      {d: EDC, s: ESC, l: serverDerivedFromDataToken, p: encToken},
 *      ...]}
 */
static bool _mongocrypt_fle2_placeholder_to_insert_update_ciphertextForRange(_mongocrypt_key_broker_t *kb,
                                                                             _mongocrypt_marking_t *marking,
                                                                             _mongocrypt_ciphertext_t *ciphertext,
                                                                             mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);
    BSON_ASSERT(kb->crypt);
    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
    const bool use_range_v2 = kb->crypt->opts.use_range_v2;

    if (!kb->crypt->opts.use_fle2_v2) {
        return _mongocrypt_fle2_placeholder_to_insert_update_ciphertextForRange_v1(kb, marking, ciphertext, status);
    }

    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    _FLE2EncryptedPayloadCommon_t common = {{0}};
    mc_FLE2InsertUpdatePayloadV2_t payload;
    mc_FLE2InsertUpdatePayloadV2_init(&payload);
    bool res = false;
    mc_edges_t *edges = NULL;

    // Parse the value ("v"), min ("min"), and max ("max") from
    // FLE2EncryptionPlaceholder for range insert.
    mc_FLE2RangeInsertSpec_t insertSpec;
    if (!mc_FLE2RangeInsertSpec_parse(&insertSpec, &placeholder->v_iter, use_range_v2, status)) {
        goto fail;
    }

    if (!_mongocrypt_fle2_placeholder_to_insert_update_common(kb,
                                                              &payload,
                                                              &common,
                                                              &marking->fle2,
                                                              &insertSpec.v,
                                                              status)) {
        goto fail;
    }

    // g:= array
    {
        BSON_ASSERT(placeholder->sparsity >= 0 && (uint64_t)placeholder->sparsity <= (uint64_t)SIZE_MAX);
        edges = get_edges(&insertSpec, (size_t)placeholder->sparsity, status, kb->crypt->opts.use_range_v2);
        if (!edges) {
            goto fail;
        }

        for (size_t i = 0; i < mc_edges_len(edges); ++i) {
            // Create an EdgeTokenSet from each edge.
            bool loop_ok = false;
            const char *edge = mc_edges_get(edges, i);
            bool is_leaf = mc_edges_is_leaf(edges, edge);
            _mongocrypt_buffer_t edge_buf = {0};
            _FLE2EncryptedPayloadCommon_t edge_tokens = {{0}};
            _mongocrypt_buffer_t encryptedTokens = {0};
            mc_EdgeTokenSetV2_t etc = {{0}};

            if (!_mongocrypt_buffer_from_string(&edge_buf, edge)) {
                CLIENT_ERR("failed to copy edge to buffer");
                goto fail_loop;
            }

            if (!_mongocrypt_fle2_placeholder_common(kb,
                                                     &edge_tokens,
                                                     &placeholder->index_key_id,
                                                     &edge_buf,
                                                     true, /* derive tokens using contentionFactor */
                                                     payload.contentionFactor,
                                                     status)) {
                goto fail_loop;
            }
            BSON_ASSERT(edge_tokens.eccDerivedToken.data == NULL);

            // d := EDCDerivedToken
            _mongocrypt_buffer_steal(&etc.edcDerivedToken, &edge_tokens.edcDerivedToken);
            // s := ESCDerivedToken
            _mongocrypt_buffer_steal(&etc.escDerivedToken, &edge_tokens.escDerivedToken);

            // l := serverDerivedFromDataToken
            _mongocrypt_buffer_steal(&etc.serverDerivedFromDataToken, &edge_tokens.serverDerivedFromDataToken);

            // p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor)
            // Or in Range V2: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor || isLeaf)
            if (!_fle2_derive_encrypted_token(kb->crypt->crypto,
                                              &etc.encryptedTokens,
                                              kb->crypt->opts.use_range_v2,
                                              edge_tokens.collectionsLevel1Token,
                                              &etc.escDerivedToken,
                                              NULL, // ecc unsed in FLE2v2
                                              OPT_BOOL(is_leaf),
                                              status)) {
                goto fail_loop;
            }

            _mc_array_append_val(&payload.edgeTokenSetArray, etc);

            loop_ok = true;
        fail_loop:
            _mongocrypt_buffer_cleanup(&encryptedTokens);
            _FLE2EncryptedPayloadCommon_cleanup(&edge_tokens);
            _mongocrypt_buffer_cleanup(&edge_buf);
            if (!loop_ok) {
                goto fail;
            }
        }
    }

    // Include "range" payload fields introduced in SERVER-91889.
    payload.sparsity = OPT_I64(placeholder->sparsity);
    payload.precision = insertSpec.precision;
    payload.trimFactor = OPT_I32(mc_edges_get_used_trimFactor(edges));
    bson_value_copy(bson_iter_value(&insertSpec.min), &payload.indexMin);
    bson_value_copy(bson_iter_value(&insertSpec.max), &payload.indexMax);

    {
        bson_t out;
        bson_init(&out);
        mc_FLE2InsertUpdatePayloadV2_serializeForRange(&payload, &out, use_range_v2);
        _mongocrypt_buffer_steal_from_bson(&ciphertext->data, &out);
    }
    // Do not set ciphertext->original_bson_type and ciphertext->key_id. They are
    // not used for FLE2InsertUpdatePayloadV2.
    ciphertext->blob_subtype = MC_SUBTYPE_FLE2InsertUpdatePayloadV2;

    res = true;
fail:
    mc_edges_destroy(edges);
    mc_FLE2InsertUpdatePayloadV2_cleanup(&payload);
    _FLE2EncryptedPayloadCommon_cleanup(&common);

    return res;
}

/**
 * Payload subtype 5: FLE2FindEqualityPayload
 *
 * {d: EDC, s: ESC, c: ECC, e: serverToken, cm: maxContentionFactor}
 */
static bool _mongocrypt_fle2_placeholder_to_find_ciphertext_v1(_mongocrypt_key_broker_t *kb,
                                                               _mongocrypt_marking_t *marking,
                                                               _mongocrypt_ciphertext_t *ciphertext,
                                                               mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);

    _FLE2EncryptedPayloadCommon_t common = {{0}};
    _mongocrypt_buffer_t value = {0};
    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    mc_FLE2FindEqualityPayload_t payload;
    bool res = false;

    BSON_ASSERT(kb->crypt->opts.use_fle2_v2 == false);
    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
    BSON_ASSERT(placeholder->type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND);
    _mongocrypt_buffer_init(&value);
    mc_FLE2FindEqualityPayload_init(&payload);

    _mongocrypt_buffer_from_iter(&value, &placeholder->v_iter);

    if (!_mongocrypt_fle2_placeholder_common(kb,
                                             &common,
                                             &placeholder->index_key_id,
                                             &value,
                                             false, /* derive tokens without contentionFactor */
                                             placeholder->maxContentionFactor, /* ignored */
                                             status)) {
        goto fail;
    }

    // d := EDCDerivedToken
    _mongocrypt_buffer_steal(&payload.edcDerivedToken, &common.edcDerivedToken);
    // s := ESCDerivedToken
    _mongocrypt_buffer_steal(&payload.escDerivedToken, &common.escDerivedToken);
    // c := ECCDerivedToken
    _mongocrypt_buffer_steal(&payload.eccDerivedToken, &common.eccDerivedToken);

    // e := ServerDataEncryptionLevel1Token
    _mongocrypt_buffer_copy_to(mc_ServerDataEncryptionLevel1Token_get(common.serverDataEncryptionLevel1Token),
                               &payload.serverEncryptionToken);

    payload.maxContentionFactor = placeholder->maxContentionFactor;

    {
        bson_t out;
        bson_init(&out);
        mc_FLE2FindEqualityPayload_serialize(&payload, &out);
        _mongocrypt_buffer_steal_from_bson(&ciphertext->data, &out);
    }
    // Do not set ciphertext->original_bson_type and ciphertext->key_id. They are
    // not used for FLE2FindEqualityPayload.
    ciphertext->blob_subtype = MC_SUBTYPE_FLE2FindEqualityPayload;

    res = true;
fail:
    mc_FLE2FindEqualityPayload_cleanup(&payload);
    _mongocrypt_buffer_cleanup(&value);
    _FLE2EncryptedPayloadCommon_cleanup(&common);

    return res;
}

/**
 * Payload subtype 12: FLE2FindEqualityPayloadV2
 * Delegates to ..._find_ciphertext_v1 when crypt->opts.use_fle2_v2 == false.
 *
 * {d: EDC, s: ESC, l: serverDerivedFromDataToken, cm: maxContentionFactor}
 */
static bool _mongocrypt_fle2_placeholder_to_find_ciphertext(_mongocrypt_key_broker_t *kb,
                                                            _mongocrypt_marking_t *marking,
                                                            _mongocrypt_ciphertext_t *ciphertext,
                                                            mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);

    if (kb->crypt->opts.use_fle2_v2 == false) {
        return _mongocrypt_fle2_placeholder_to_find_ciphertext_v1(kb, marking, ciphertext, status);
    }

    _FLE2EncryptedPayloadCommon_t common = {{0}};
    _mongocrypt_buffer_t value = {0};
    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    mc_FLE2FindEqualityPayloadV2_t payload;
    bool res = false;

    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
    BSON_ASSERT(placeholder->type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND);

    _mongocrypt_buffer_init(&value);
    mc_FLE2FindEqualityPayloadV2_init(&payload);

    _mongocrypt_buffer_from_iter(&value, &placeholder->v_iter);

    if (!_mongocrypt_fle2_placeholder_common(kb,
                                             &common,
                                             &placeholder->index_key_id,
                                             &value,
                                             false, /* derive tokens without contentionFactor */
                                             placeholder->maxContentionFactor, /* ignored */
                                             status)) {
        goto fail;
    }
    BSON_ASSERT(common.eccDerivedToken.data == NULL);

    // d := EDCDerivedToken
    _mongocrypt_buffer_steal(&payload.edcDerivedToken, &common.edcDerivedToken);
    // s := ESCDerivedToken
    _mongocrypt_buffer_steal(&payload.escDerivedToken, &common.escDerivedToken);
    // l := serverDerivedFromDataToken
    _mongocrypt_buffer_steal(&payload.serverDerivedFromDataToken, &common.serverDerivedFromDataToken);

    // cm := maxContentionFactor
    payload.maxContentionFactor = placeholder->maxContentionFactor;

    {
        bson_t out;
        bson_init(&out);
        mc_FLE2FindEqualityPayloadV2_serialize(&payload, &out);
        _mongocrypt_buffer_steal_from_bson(&ciphertext->data, &out);
    }
    // Do not set ciphertext->original_bson_type and ciphertext->key_id. They are
    // not used for FLE2FindEqualityPayloadV2.
    ciphertext->blob_subtype = MC_SUBTYPE_FLE2FindEqualityPayloadV2;

    res = true;
fail:
    mc_FLE2FindEqualityPayloadV2_cleanup(&payload);
    _mongocrypt_buffer_cleanup(&value);
    _FLE2EncryptedPayloadCommon_cleanup(&common);

    return res;
}

static bool isInfinite(bson_iter_t *iter) {
    return mc_isinf(bson_iter_double(iter));
}

// mc_get_mincover_from_FLE2RangeFindSpec creates and returns a mincover from an
// FLE2RangeFindSpec. Returns NULL on error.
mc_mincover_t *mc_get_mincover_from_FLE2RangeFindSpec(mc_FLE2RangeFindSpec_t *findSpec,
                                                      size_t sparsity,
                                                      mongocrypt_status_t *status,
                                                      bool use_range_v2) {
    BSON_ASSERT_PARAM(findSpec);
    BSON_ASSERT(findSpec->edgesInfo.set);

    bson_type_t bsonType = bson_iter_type(&findSpec->edgesInfo.value.indexMin);

    if (bson_iter_type(&findSpec->edgesInfo.value.indexMin) != bson_iter_type(&findSpec->edgesInfo.value.indexMax)) {
        CLIENT_ERR("indexMin and indexMax must have the same type. Got: %s indexMin and "
                   "%s indexMax",
                   mc_bson_type_to_string(bson_iter_type(&findSpec->edgesInfo.value.indexMin)),
                   mc_bson_type_to_string(bson_iter_type(&findSpec->edgesInfo.value.indexMax)));
        return NULL;
    }

    bson_iter_t lowerBound = findSpec->edgesInfo.value.lowerBound;
    bson_iter_t upperBound = findSpec->edgesInfo.value.upperBound;
    bool includeLowerBound = findSpec->edgesInfo.value.lbIncluded;
    bool includeUpperBound = findSpec->edgesInfo.value.ubIncluded;

    // Open-ended ranges are represented with infinity as the other endpoint.
    // Resolve infinite bounds at this point to end at the min or max for this
    // index.
    if (isInfinite(&lowerBound)) {
        lowerBound = findSpec->edgesInfo.value.indexMin;
        includeLowerBound = true;
    }
    if (isInfinite(&upperBound)) {
        upperBound = findSpec->edgesInfo.value.indexMax;
        includeUpperBound = true;
    }

    if (bson_iter_type(&lowerBound) != bsonType) {
        CLIENT_ERR("expected lowerBound to match index type %s, got %s",
                   mc_bson_type_to_string(bsonType),
                   mc_bson_type_to_string(bson_iter_type(&lowerBound)));
        return NULL;
    }

    if (bson_iter_type(&upperBound) != bsonType) {
        CLIENT_ERR("expected upperBound to match index type %s, got %s",
                   mc_bson_type_to_string(bsonType),
                   mc_bson_type_to_string(bson_iter_type(&upperBound)));
        return NULL;
    }

    switch (bsonType) {
    case BSON_TYPE_INT32:
        BSON_ASSERT(bson_iter_type(&lowerBound) == BSON_TYPE_INT32);
        BSON_ASSERT(bson_iter_type(&upperBound) == BSON_TYPE_INT32);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMin) == BSON_TYPE_INT32);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMax) == BSON_TYPE_INT32);

        return mc_getMincoverInt32(
            (mc_getMincoverInt32_args_t){.lowerBound = bson_iter_int32(&lowerBound),
                                         .includeLowerBound = includeLowerBound,
                                         .upperBound = bson_iter_int32(&upperBound),
                                         .includeUpperBound = includeUpperBound,
                                         .min = OPT_I32(bson_iter_int32(&findSpec->edgesInfo.value.indexMin)),
                                         .max = OPT_I32(bson_iter_int32(&findSpec->edgesInfo.value.indexMax)),
                                         .sparsity = sparsity,
                                         .trimFactor = findSpec->edgesInfo.value.trimFactor},
            status,
            use_range_v2);

    case BSON_TYPE_INT64:
        BSON_ASSERT(bson_iter_type(&lowerBound) == BSON_TYPE_INT64);
        BSON_ASSERT(bson_iter_type(&upperBound) == BSON_TYPE_INT64);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMin) == BSON_TYPE_INT64);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMax) == BSON_TYPE_INT64);
        return mc_getMincoverInt64(
            (mc_getMincoverInt64_args_t){.lowerBound = bson_iter_int64(&lowerBound),
                                         .includeLowerBound = includeLowerBound,
                                         .upperBound = bson_iter_int64(&upperBound),
                                         .includeUpperBound = includeUpperBound,
                                         .min = OPT_I64(bson_iter_int64(&findSpec->edgesInfo.value.indexMin)),
                                         .max = OPT_I64(bson_iter_int64(&findSpec->edgesInfo.value.indexMax)),
                                         .sparsity = sparsity,
                                         .trimFactor = findSpec->edgesInfo.value.trimFactor},
            status,
            use_range_v2);
    case BSON_TYPE_DATE_TIME:
        BSON_ASSERT(bson_iter_type(&lowerBound) == BSON_TYPE_DATE_TIME);
        BSON_ASSERT(bson_iter_type(&upperBound) == BSON_TYPE_DATE_TIME);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMin) == BSON_TYPE_DATE_TIME);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMax) == BSON_TYPE_DATE_TIME);
        return mc_getMincoverInt64(
            (mc_getMincoverInt64_args_t){.lowerBound = bson_iter_date_time(&lowerBound),
                                         .includeLowerBound = includeLowerBound,
                                         .upperBound = bson_iter_date_time(&upperBound),
                                         .includeUpperBound = includeUpperBound,
                                         .min = OPT_I64(bson_iter_date_time(&findSpec->edgesInfo.value.indexMin)),
                                         .max = OPT_I64(bson_iter_date_time(&findSpec->edgesInfo.value.indexMax)),
                                         .sparsity = sparsity,
                                         .trimFactor = findSpec->edgesInfo.value.trimFactor},
            status,
            use_range_v2);
    case BSON_TYPE_DOUBLE: {
        BSON_ASSERT(bson_iter_type(&lowerBound) == BSON_TYPE_DOUBLE);
        BSON_ASSERT(bson_iter_type(&upperBound) == BSON_TYPE_DOUBLE);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMin) == BSON_TYPE_DOUBLE);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMax) == BSON_TYPE_DOUBLE);

        mc_getMincoverDouble_args_t args = {.lowerBound = bson_iter_double(&lowerBound),
                                            .includeLowerBound = includeLowerBound,
                                            .upperBound = bson_iter_double(&upperBound),
                                            .includeUpperBound = includeUpperBound,
                                            .sparsity = sparsity,
                                            .trimFactor = findSpec->edgesInfo.value.trimFactor};
        if (findSpec->edgesInfo.value.precision.set) {
            // If precision is set, pass min/max/precision to mc_getMincoverDouble.
            // Do not pass min/max if precision is not set. All three must be set
            // or all three must be unset in mc_getTypeInfoDouble.
            args.min = OPT_DOUBLE(bson_iter_double(&findSpec->edgesInfo.value.indexMin));
            args.max = OPT_DOUBLE(bson_iter_double(&findSpec->edgesInfo.value.indexMax));
            args.precision = findSpec->edgesInfo.value.precision;
        }
        return mc_getMincoverDouble(args, status, use_range_v2);
    }
    case BSON_TYPE_DECIMAL128: {
#if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT
        BSON_ASSERT(bson_iter_type(&lowerBound) == BSON_TYPE_DECIMAL128);
        BSON_ASSERT(bson_iter_type(&upperBound) == BSON_TYPE_DECIMAL128);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMin) == BSON_TYPE_DECIMAL128);
        BSON_ASSERT(bson_iter_type(&findSpec->edgesInfo.value.indexMax) == BSON_TYPE_DECIMAL128);

        mc_getMincoverDecimal128_args_t args = {.lowerBound = mc_dec128_from_bson_iter(&lowerBound),
                                                .includeLowerBound = includeLowerBound,
                                                .upperBound = mc_dec128_from_bson_iter(&upperBound),
                                                .includeUpperBound = includeUpperBound,
                                                .sparsity = sparsity,
                                                .trimFactor = findSpec->edgesInfo.value.trimFactor};
        if (findSpec->edgesInfo.value.precision.set) {
            args.min = OPT_MC_DEC128(mc_dec128_from_bson_iter(&findSpec->edgesInfo.value.indexMin));
            args.max = OPT_MC_DEC128(mc_dec128_from_bson_iter(&findSpec->edgesInfo.value.indexMax));
            args.precision = findSpec->edgesInfo.value.precision;
        }
        return mc_getMincoverDecimal128(args, status, use_range_v2);
#else // ↑↑↑↑↑↑↑↑ With Decimal128 / Without ↓↓↓↓↓↓↓↓↓↓
        CLIENT_ERR("FLE2 find is not supported for Decimal128: libmongocrypt "
                   "was built without Decimal128 support");
        return NULL;
#endif
    }

    case BSON_TYPE_EOD:
    case BSON_TYPE_UTF8:
    case BSON_TYPE_DOCUMENT:
    case BSON_TYPE_ARRAY:
    case BSON_TYPE_BINARY:
    case BSON_TYPE_UNDEFINED:
    case BSON_TYPE_OID:
    case BSON_TYPE_BOOL:
    case BSON_TYPE_NULL:
    case BSON_TYPE_REGEX:
    case BSON_TYPE_DBPOINTER:
    case BSON_TYPE_CODE:
    case BSON_TYPE_SYMBOL:
    case BSON_TYPE_CODEWSCOPE:
    case BSON_TYPE_TIMESTAMP:
    case BSON_TYPE_MAXKEY:
    case BSON_TYPE_MINKEY:
    default: CLIENT_ERR("FLE2 find is not supported for type: %s", mc_bson_type_to_string(bsonType)); return NULL;
    }
}

/**
 * Payload subtype 10: FLE2FindRangePayload
 *
 * {e: serverToken, cm: maxContentionFactor,
 *  g: [{d: EDC, s: ESC, c: ECC}, ...]}
 */
static bool _mongocrypt_fle2_placeholder_to_find_ciphertextForRange_v1(_mongocrypt_key_broker_t *kb,
                                                                       _mongocrypt_marking_t *marking,
                                                                       _mongocrypt_ciphertext_t *ciphertext,
                                                                       mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);
    BSON_ASSERT(kb->crypt);

    const bool use_range_v2 = kb->crypt->opts.use_range_v2;
    _mongocrypt_crypto_t *crypto = kb->crypt->crypto;
    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    mc_FLE2FindRangePayload_t payload;
    bool res = false;
    mc_mincover_t *mincover = NULL;
    _mongocrypt_buffer_t tokenKey = {0};

    BSON_ASSERT(kb->crypt->opts.use_fle2_v2 == false);
    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
    BSON_ASSERT(placeholder);
    BSON_ASSERT(placeholder->type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND);
    BSON_ASSERT(placeholder->algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE);
    mc_FLE2FindRangePayload_init(&payload);

    // Parse the query bounds and index bounds from FLE2EncryptionPlaceholder for
    // range find.
    mc_FLE2RangeFindSpec_t findSpec;
    if (!mc_FLE2RangeFindSpec_parse(&findSpec, &placeholder->v_iter, use_range_v2, status)) {
        goto fail;
    }

    if (findSpec.edgesInfo.set) {
        // cm := Queryable Encryption max contentionFactor
        payload.payload.value.maxContentionFactor = placeholder->maxContentionFactor;

        // e := ServerDataEncryptionLevel1Token
        {
            if (!_get_tokenKey(kb, &placeholder->index_key_id, &tokenKey, status)) {
                goto fail;
            }

            mc_ServerDataEncryptionLevel1Token_t *serverToken =
                mc_ServerDataEncryptionLevel1Token_new(crypto, &tokenKey, status);
            if (!serverToken) {
                goto fail;
            }
            _mongocrypt_buffer_copy_to(mc_ServerDataEncryptionLevel1Token_get(serverToken),
                                       &payload.payload.value.serverEncryptionToken);
            mc_ServerDataEncryptionLevel1Token_destroy(serverToken);
        }

        // g:= array
        {
            BSON_ASSERT(placeholder->sparsity >= 0 && (uint64_t)placeholder->sparsity <= (uint64_t)SIZE_MAX);
            mincover =
                mc_get_mincover_from_FLE2RangeFindSpec(&findSpec, (size_t)placeholder->sparsity, status, use_range_v2);
            if (!mincover) {
                goto fail;
            }

            for (size_t i = 0; i < mc_mincover_len(mincover); i++) {
                // Create a EdgeFindTokenSet from each edge.
                bool loop_ok = false;
                const char *edge = mc_mincover_get(mincover, i);
                _mongocrypt_buffer_t edge_buf = {0};
                _FLE2EncryptedPayloadCommon_t edge_tokens = {{0}};
                mc_EdgeFindTokenSet_t eftc = {{0}};

                if (!_mongocrypt_buffer_from_string(&edge_buf, edge)) {
                    CLIENT_ERR("failed to copy edge to buffer");
                    goto fail_loop;
                }

                if (!_mongocrypt_fle2_placeholder_common(kb,
                                                         &edge_tokens,
                                                         &placeholder->index_key_id,
                                                         &edge_buf,
                                                         false, /* derive tokens using contentionFactor */
                                                         placeholder->maxContentionFactor, /* ignored */
                                                         status)) {
                    goto fail_loop;
                }

                // d := EDCDerivedToken
                _mongocrypt_buffer_steal(&eftc.edcDerivedToken, &edge_tokens.edcDerivedToken);
                // s := ESCDerivedToken
                _mongocrypt_buffer_steal(&eftc.escDerivedToken, &edge_tokens.escDerivedToken);
                // c := ECCDerivedToken
                _mongocrypt_buffer_steal(&eftc.eccDerivedToken, &edge_tokens.eccDerivedToken);

                _mc_array_append_val(&payload.payload.value.edgeFindTokenSetArray, eftc);

                loop_ok = true;
            fail_loop:
                _FLE2EncryptedPayloadCommon_cleanup(&edge_tokens);
                _mongocrypt_buffer_cleanup(&edge_buf);
                if (!loop_ok) {
                    goto fail;
                }
            }
        }
        payload.payload.set = true;
    }

    payload.payloadId = findSpec.payloadId;
    payload.firstOperator = findSpec.firstOperator;
    payload.secondOperator = findSpec.secondOperator;

    // Serialize.
    {
        bson_t out = BSON_INITIALIZER;
        mc_FLE2FindRangePayload_serialize(&payload, &out);
        _mongocrypt_buffer_steal_from_bson(&ciphertext->data, &out);
    }
    _mongocrypt_buffer_steal(&ciphertext->key_id, &placeholder->index_key_id);

    // Do not set ciphertext->original_bson_type and ciphertext->key_id. They are
    // not used for FLE2FindRangePayload.
    ciphertext->blob_subtype = MC_SUBTYPE_FLE2FindRangePayload;

    res = true;
fail:
    mc_mincover_destroy(mincover);
    mc_FLE2FindRangePayload_cleanup(&payload);
    _mongocrypt_buffer_cleanup(&tokenKey);

    return res;
}

/**
 * Payload subtype 13: FLE2FindRangePayloadV2
 * Delegates to ..._find_ciphertextForRange_v1
 *   when crypt->opts.use_fle2_v2 is false
 *
 * {cm: maxContentionFactor,
 *  g: [{d: EDC, s: ESC, l: serverDerivedFromDataToken}, ...]}
 */
static bool _mongocrypt_fle2_placeholder_to_find_ciphertextForRange(_mongocrypt_key_broker_t *kb,
                                                                    _mongocrypt_marking_t *marking,
                                                                    _mongocrypt_ciphertext_t *ciphertext,
                                                                    mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);

    if (kb->crypt->opts.use_fle2_v2 == false) {
        return _mongocrypt_fle2_placeholder_to_find_ciphertextForRange_v1(kb, marking, ciphertext, status);
    }

    const bool use_range_v2 = kb->crypt->opts.use_range_v2;
    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    mc_FLE2FindRangePayloadV2_t payload;
    bool res = false;
    mc_mincover_t *mincover = NULL;
    _mongocrypt_buffer_t tokenKey = {0};

    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
    BSON_ASSERT(placeholder);
    BSON_ASSERT(placeholder->type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND);
    BSON_ASSERT(placeholder->algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE);
    mc_FLE2FindRangePayloadV2_init(&payload);

    // Parse the query bounds and index bounds from FLE2EncryptionPlaceholder for
    // range find.
    mc_FLE2RangeFindSpec_t findSpec;
    if (!mc_FLE2RangeFindSpec_parse(&findSpec, &placeholder->v_iter, use_range_v2, status)) {
        goto fail;
    }

    if (findSpec.edgesInfo.set) {
        // cm := Queryable Encryption max contentionFactor
        payload.payload.value.maxContentionFactor = placeholder->maxContentionFactor;

        // g:= array
        {
            BSON_ASSERT(placeholder->sparsity >= 0 && (uint64_t)placeholder->sparsity <= (uint64_t)SIZE_MAX);
            mincover =
                mc_get_mincover_from_FLE2RangeFindSpec(&findSpec, (size_t)placeholder->sparsity, status, use_range_v2);
            if (!mincover) {
                goto fail;
            }

            for (size_t i = 0; i < mc_mincover_len(mincover); i++) {
                // Create a EdgeFindTokenSet from each edge.
                bool loop_ok = false;
                const char *edge = mc_mincover_get(mincover, i);
                _mongocrypt_buffer_t edge_buf = {0};
                _FLE2EncryptedPayloadCommon_t edge_tokens = {{0}};
                mc_EdgeFindTokenSetV2_t eftc = {{0}};

                if (!_mongocrypt_buffer_from_string(&edge_buf, edge)) {
                    CLIENT_ERR("failed to copy edge to buffer");
                    goto fail_loop;
                }

                if (!_mongocrypt_fle2_placeholder_common(kb,
                                                         &edge_tokens,
                                                         &placeholder->index_key_id,
                                                         &edge_buf,
                                                         false, /* derive tokens without using contentionFactor */
                                                         placeholder->maxContentionFactor, /* ignored */
                                                         status)) {
                    goto fail_loop;
                }

                // d := EDCDerivedToken
                _mongocrypt_buffer_steal(&eftc.edcDerivedToken, &edge_tokens.edcDerivedToken);
                // s := ESCDerivedToken
                _mongocrypt_buffer_steal(&eftc.escDerivedToken, &edge_tokens.escDerivedToken);

                // l := serverDerivedFromDataToken
                _mongocrypt_buffer_steal(&eftc.serverDerivedFromDataToken, &edge_tokens.serverDerivedFromDataToken);

                _mc_array_append_val(&payload.payload.value.edgeFindTokenSetArray, eftc);

                loop_ok = true;
            fail_loop:
                _FLE2EncryptedPayloadCommon_cleanup(&edge_tokens);
                _mongocrypt_buffer_cleanup(&edge_buf);
                if (!loop_ok) {
                    goto fail;
                }
            }
        }
        payload.payload.set = true;

        if (use_range_v2) {
            // Include "range" payload fields introduced in SERVER-91889.
            payload.sparsity = OPT_I64(placeholder->sparsity);
            payload.precision = findSpec.edgesInfo.value.precision;
            payload.trimFactor = OPT_I32(mc_mincover_get_used_trimFactor(mincover));
            bson_value_copy(bson_iter_value(&findSpec.edgesInfo.value.indexMin), &payload.indexMin);
            bson_value_copy(bson_iter_value(&findSpec.edgesInfo.value.indexMax), &payload.indexMax);
        }
    }

    payload.payloadId = findSpec.payloadId;
    payload.firstOperator = findSpec.firstOperator;
    payload.secondOperator = findSpec.secondOperator;

    // Serialize.
    {
        bson_t out = BSON_INITIALIZER;
        mc_FLE2FindRangePayloadV2_serialize(&payload, &out, use_range_v2);
        _mongocrypt_buffer_steal_from_bson(&ciphertext->data, &out);
    }
    _mongocrypt_buffer_steal(&ciphertext->key_id, &placeholder->index_key_id);

    // Do not set ciphertext->original_bson_type and ciphertext->key_id. They are
    // not used for FLE2FindRangePayloadV2.
    ciphertext->blob_subtype = MC_SUBTYPE_FLE2FindRangePayloadV2;

    res = true;
fail:
    mc_mincover_destroy(mincover);
    mc_FLE2FindRangePayloadV2_cleanup(&payload);
    _mongocrypt_buffer_cleanup(&tokenKey);

    return res;
}

static bool _mongocrypt_fle2_placeholder_to_FLE2UnindexedEncryptedValue(_mongocrypt_key_broker_t *kb,
                                                                        _mongocrypt_marking_t *marking,
                                                                        _mongocrypt_ciphertext_t *ciphertext,
                                                                        mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);

    _mongocrypt_buffer_t plaintext = {0};
    mc_FLE2EncryptionPlaceholder_t *placeholder = &marking->fle2;
    _mongocrypt_buffer_t user_key = {0};
    bool res = false;

    BSON_ASSERT(marking->type == MONGOCRYPT_MARKING_FLE2_ENCRYPTION);
    BSON_ASSERT(placeholder);
    BSON_ASSERT(placeholder->algorithm == MONGOCRYPT_FLE2_ALGORITHM_UNINDEXED);
    _mongocrypt_buffer_from_iter(&plaintext, &placeholder->v_iter);

    if (!_mongocrypt_key_broker_decrypted_key_by_id(kb, &placeholder->user_key_id, &user_key)) {
        CLIENT_ERR("unable to retrieve key");
        goto fail;
    }

    BSON_ASSERT(kb->crypt);
    if (kb->crypt->opts.use_fle2_v2) {
        res = mc_FLE2UnindexedEncryptedValueV2_encrypt(kb->crypt->crypto,
                                                       &placeholder->user_key_id,
                                                       bson_iter_type(&placeholder->v_iter),
                                                       &plaintext,
                                                       &user_key,
                                                       &ciphertext->data,
                                                       status);
        ciphertext->blob_subtype = MC_SUBTYPE_FLE2UnindexedEncryptedValueV2;
    } else {
        res = mc_FLE2UnindexedEncryptedValue_encrypt(kb->crypt->crypto,
                                                     &placeholder->user_key_id,
                                                     bson_iter_type(&placeholder->v_iter),
                                                     &plaintext,
                                                     &user_key,
                                                     &ciphertext->data,
                                                     status);
        ciphertext->blob_subtype = MC_SUBTYPE_FLE2UnindexedEncryptedValue;
    }

    if (!res) {
        goto fail;
    }

    _mongocrypt_buffer_steal(&ciphertext->key_id, &placeholder->user_key_id);
    ciphertext->original_bson_type = (uint8_t)bson_iter_type(&placeholder->v_iter);

    res = true;
fail:
    _mongocrypt_buffer_cleanup(&plaintext);
    _mongocrypt_buffer_cleanup(&user_key);

    return res;
}

static bool _mongocrypt_fle1_marking_to_ciphertext(_mongocrypt_key_broker_t *kb,
                                                   _mongocrypt_marking_t *marking,
                                                   _mongocrypt_ciphertext_t *ciphertext,
                                                   mongocrypt_status_t *status) {
    const _mongocrypt_value_encryption_algorithm_t *fle1 = _mcFLE1Algorithm();
    _mongocrypt_buffer_t plaintext;
    _mongocrypt_buffer_t iv;
    _mongocrypt_buffer_t associated_data;
    _mongocrypt_buffer_t key_material;
    _mongocrypt_buffer_t key_id;
    bool ret = false;
    bool key_found;
    uint32_t bytes_written;

    BSON_ASSERT_PARAM(kb);
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);

    BSON_ASSERT((marking->type == MONGOCRYPT_MARKING_FLE1_BY_ID)
                || (marking->type == MONGOCRYPT_MARKING_FLE1_BY_ALTNAME));

    _mongocrypt_buffer_init(&plaintext);
    _mongocrypt_buffer_init(&associated_data);
    _mongocrypt_buffer_init(&iv);
    _mongocrypt_buffer_init(&key_id);
    _mongocrypt_buffer_init(&key_material);

    /* Get the decrypted key for this marking. */
    if (marking->type == MONGOCRYPT_MARKING_FLE1_BY_ALTNAME) {
        key_found = _mongocrypt_key_broker_decrypted_key_by_name(kb, &marking->key_alt_name, &key_material, &key_id);
    } else if (!_mongocrypt_buffer_empty(&marking->key_id)) {
        key_found = _mongocrypt_key_broker_decrypted_key_by_id(kb, &marking->key_id, &key_material);
        _mongocrypt_buffer_copy_to(&marking->key_id, &key_id);
    } else {
        CLIENT_ERR("marking must have either key_id or key_alt_name");
        goto fail;
    }

    if (!key_found) {
        _mongocrypt_status_copy_to(kb->status, status);
        goto fail;
    }

    ciphertext->original_bson_type = (uint8_t)bson_iter_type(&marking->v_iter);
    if (marking->algorithm == MONGOCRYPT_ENCRYPTION_ALGORITHM_DETERMINISTIC) {
        ciphertext->blob_subtype = MC_SUBTYPE_FLE1DeterministicEncryptedValue;
    } else {
        BSON_ASSERT(marking->algorithm == MONGOCRYPT_ENCRYPTION_ALGORITHM_RANDOM);
        ciphertext->blob_subtype = MC_SUBTYPE_FLE1RandomEncryptedValue;
    }
    _mongocrypt_buffer_copy_to(&key_id, &ciphertext->key_id);
    if (!_mongocrypt_ciphertext_serialize_associated_data(ciphertext, &associated_data)) {
        CLIENT_ERR("could not serialize associated data");
        goto fail;
    }

    _mongocrypt_buffer_from_iter(&plaintext, &marking->v_iter);
    ciphertext->data.len = fle1->get_ciphertext_len(plaintext.len, status);
    if (ciphertext->data.len == 0) {
        goto fail;
    }
    ciphertext->data.data = bson_malloc(ciphertext->data.len);
    BSON_ASSERT(ciphertext->data.data);

    ciphertext->data.owned = true;

    BSON_ASSERT(kb->crypt);
    switch (marking->algorithm) {
    case MONGOCRYPT_ENCRYPTION_ALGORITHM_DETERMINISTIC:
        /* Use deterministic encryption. */
        _mongocrypt_buffer_resize(&iv, MONGOCRYPT_IV_LEN);
        ret = _mongocrypt_calculate_deterministic_iv(kb->crypt->crypto,
                                                     &key_material,
                                                     &plaintext,
                                                     &associated_data,
                                                     &iv,
                                                     status);
        if (!ret) {
            goto fail;
        }

        ret = fle1->do_encrypt(kb->crypt->crypto,
                               &iv,
                               &associated_data,
                               &key_material,
                               &plaintext,
                               &ciphertext->data,
                               &bytes_written,
                               status);
        break;
    case MONGOCRYPT_ENCRYPTION_ALGORITHM_RANDOM:
        /* Use randomized encryption.
         * In this case, we must generate a new, random iv. */
        _mongocrypt_buffer_resize(&iv, MONGOCRYPT_IV_LEN);
        if (!_mongocrypt_random(kb->crypt->crypto, &iv, MONGOCRYPT_IV_LEN, status)) {
            goto fail;
        }
        ret = fle1->do_encrypt(kb->crypt->crypto,
                               &iv,
                               &associated_data,
                               &key_material,
                               &plaintext,
                               &ciphertext->data,
                               &bytes_written,
                               status);
        break;
    case MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE:
    default:
        /* Error. */
        CLIENT_ERR("Unsupported value for encryption algorithm");
        goto fail;
    }

    if (!ret) {
        goto fail;
    }

    BSON_ASSERT(bytes_written == ciphertext->data.len);

    ret = true;

fail:
    _mongocrypt_buffer_cleanup(&iv);
    _mongocrypt_buffer_cleanup(&key_id);
    _mongocrypt_buffer_cleanup(&plaintext);
    _mongocrypt_buffer_cleanup(&associated_data);
    _mongocrypt_buffer_cleanup(&key_material);
    return ret;
}

bool _mongocrypt_marking_to_ciphertext(void *ctx,
                                       _mongocrypt_marking_t *marking,
                                       _mongocrypt_ciphertext_t *ciphertext,
                                       mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(marking);
    BSON_ASSERT_PARAM(ciphertext);
    BSON_ASSERT_PARAM(ctx);

    _mongocrypt_key_broker_t *kb = (_mongocrypt_key_broker_t *)ctx;

    switch (marking->type) {
    case MONGOCRYPT_MARKING_FLE2_ENCRYPTION:
        switch (marking->fle2.algorithm) {
        case MONGOCRYPT_FLE2_ALGORITHM_UNINDEXED:
            return _mongocrypt_fle2_placeholder_to_FLE2UnindexedEncryptedValue(kb, marking, ciphertext, status);
        case MONGOCRYPT_FLE2_ALGORITHM_RANGE:
            switch (marking->fle2.type) {
            case MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT:
                return _mongocrypt_fle2_placeholder_to_insert_update_ciphertextForRange(kb,
                                                                                        marking,
                                                                                        ciphertext,
                                                                                        status);
            case MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND:
                return _mongocrypt_fle2_placeholder_to_find_ciphertextForRange(kb, marking, ciphertext, status);
            default: CLIENT_ERR("unexpected fle2 type: %d", (int)marking->fle2.type); return false;
            }
        case MONGOCRYPT_FLE2_ALGORITHM_EQUALITY:
            switch (marking->fle2.type) {
            case MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT:
                return _mongocrypt_fle2_placeholder_to_insert_update_ciphertext(kb, marking, ciphertext, status);
            case MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND:
                return _mongocrypt_fle2_placeholder_to_find_ciphertext(kb, marking, ciphertext, status);
            default: CLIENT_ERR("unexpected fle2 type: %d", (int)marking->fle2.type); return false;
            }
        default: CLIENT_ERR("unexpected algorithm: %d", (int)marking->algorithm); return false;
        }
    case MONGOCRYPT_MARKING_FLE1_BY_ID:
    case MONGOCRYPT_MARKING_FLE1_BY_ALTNAME:
        return _mongocrypt_fle1_marking_to_ciphertext(kb, marking, ciphertext, status);
    default: CLIENT_ERR("unexpected marking type: %d", (int)marking->type); return false;
    }
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-mutex-private.h0000644000175100001660000000257414760300420021575 0ustar  /*
 * Copyright 2018-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_MUTEX_PRIVATE_H
#define MONGOCRYPT_MUTEX_PRIVATE_H

#include 

#if defined(BSON_OS_UNIX)
#include 
#define mongocrypt_mutex_t pthread_mutex_t
#else
#define mongocrypt_mutex_t CRITICAL_SECTION
#endif

void _mongocrypt_mutex_init(mongocrypt_mutex_t *mutex);

void _mongocrypt_mutex_cleanup(mongocrypt_mutex_t *mutex);

void _mongocrypt_mutex_lock(mongocrypt_mutex_t *mutex);

void _mongocrypt_mutex_unlock(mongocrypt_mutex_t *mutex);

#define MONGOCRYPT_WITH_MUTEX(Mutex)                                                                                   \
    for (int only_once = (_mongocrypt_mutex_lock(&(Mutex)), 1); only_once; _mongocrypt_mutex_unlock(&(Mutex)))         \
        for (; only_once; only_once = 0)

#endif /* MONGOCRYPT_MUTEX_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-opts-private.h0000644000175100001660000002336614760300420021422 0ustar  /*
 * Copyright 2018-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_OPTS_PRIVATE_H
#define MONGOCRYPT_OPTS_PRIVATE_H

#include 

#include "mlib/str.h"

#include "mongocrypt-buffer-private.h"
#include "mongocrypt-endpoint-private.h"
#include "mongocrypt-kek-private.h"
#include "mongocrypt-log-private.h"
#include "mongocrypt.h"
#include 

typedef struct {
    char *tenant_id;
    char *client_id;
    char *client_secret;
    _mongocrypt_endpoint_t *identity_platform_endpoint;
    char *access_token;
} _mongocrypt_opts_kms_provider_azure_t;

typedef struct {
    char *email;
    _mongocrypt_buffer_t private_key;
    _mongocrypt_endpoint_t *endpoint;
    char *access_token;
} _mongocrypt_opts_kms_provider_gcp_t;

typedef struct {
    char *secret_access_key;
    char *access_key_id;
    char *session_token;
} _mongocrypt_opts_kms_provider_aws_t;

typedef struct {
    _mongocrypt_buffer_t key;
} _mongocrypt_opts_kms_provider_local_t;

typedef struct {
    _mongocrypt_endpoint_t *endpoint;
} _mongocrypt_opts_kms_provider_kmip_t;

typedef struct {
    // `type` identifies the set field in `value`.
    _mongocrypt_kms_provider_t type;

    union {
        _mongocrypt_opts_kms_provider_local_t local;
        _mongocrypt_opts_kms_provider_aws_t aws;
        _mongocrypt_opts_kms_provider_azure_t azure;
        _mongocrypt_opts_kms_provider_gcp_t gcp;
        _mongocrypt_opts_kms_provider_kmip_t kmip;
    } value;
} mc_kms_creds_t;

typedef struct {
    int configured_providers; /* A bit set of _mongocrypt_kms_provider_t */
    int need_credentials;     /* A bit set of _mongocrypt_kms_provider_t */
    // Fields suffixed with `_mut` are mutated when constructing the `_mongocrypt_opts_kms_providers_t`.
    // Prefer using `_mongocrypt_opts_kms_providers_lookup` to read the values.
    _mongocrypt_opts_kms_provider_local_t local_mut;
    _mongocrypt_opts_kms_provider_aws_t aws_mut;
    _mongocrypt_opts_kms_provider_azure_t azure_mut;
    _mongocrypt_opts_kms_provider_gcp_t gcp_mut;
    _mongocrypt_opts_kms_provider_kmip_t kmip_mut;
    // `named_mut` stores a list of named KMS providers.
    mc_array_t named_mut;
} _mongocrypt_opts_kms_providers_t;

void _mongocrypt_opts_kms_providers_init(_mongocrypt_opts_kms_providers_t *kms_providers);

bool _mongocrypt_parse_kms_providers(mongocrypt_binary_t *kms_providers_definition,
                                     _mongocrypt_opts_kms_providers_t *kms_providers,
                                     mongocrypt_status_t *status,
                                     _mongocrypt_log_t *log);

bool _mongocrypt_opts_kms_providers_lookup(const _mongocrypt_opts_kms_providers_t *kms_providers,
                                           const char *kmsid,
                                           mc_kms_creds_t *out);

typedef struct {
    mongocrypt_log_fn_t log_fn;
    void *log_ctx;
    _mongocrypt_buffer_t schema_map;
    _mongocrypt_buffer_t encrypted_field_config_map;

    _mongocrypt_opts_kms_providers_t kms_providers;
    mongocrypt_hmac_fn sign_rsaes_pkcs1_v1_5;
    void *sign_ctx;

    /// Keep an array of search paths for finding the crypt_shared library
    /// during mongocrypt_init()
    int n_crypt_shared_lib_search_paths;
    mstr *crypt_shared_lib_search_paths;
    /// Optionally, a user may override the default search behavior by specifying
    /// a specifiy path to the library. If this is set, this suppresses the
    /// search behavior.
    mstr crypt_shared_lib_override_path;

    bool use_need_kms_credentials_state;
    bool use_need_mongo_collinfo_with_db_state;
    bool bypass_query_analysis;

    // When creating new encrypted payloads,
    // use V2 variants of the FLE2 datatypes.
    bool use_fle2_v2;

    // Use the Queryable Encryption Range V2 protocol.
    bool use_range_v2;
} _mongocrypt_opts_t;

void _mongocrypt_opts_kms_providers_cleanup(_mongocrypt_opts_kms_providers_t *kms_providers);

/* Merge `source` into `dest`. Does not perform any memory ownership management;
 * values in `dest` will be overwritten with values from `source` without
 * being released. */
void _mongocrypt_opts_merge_kms_providers(_mongocrypt_opts_kms_providers_t *dest,
                                          const _mongocrypt_opts_kms_providers_t *source);

void _mongocrypt_opts_init(_mongocrypt_opts_t *opts);

void _mongocrypt_opts_cleanup(_mongocrypt_opts_t *opts);

bool _mongocrypt_opts_validate(_mongocrypt_opts_t *opts, mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_opts_kms_providers_validate(_mongocrypt_opts_t *opts,
                                             _mongocrypt_opts_kms_providers_t *kms_providers,
                                             mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

/*
 * Parse an optional UTF-8 value from BSON.
 * @dotkey may be a dot separated key like: "a.b.c".
 * @*out is set to a copy of the string if found, NULL otherwise. Caller must
 * clean up with bson_free (*out).
 * Returns true if no error occured.
 */
bool _mongocrypt_parse_optional_utf8(const bson_t *bson, const char *dotkey, char **out, mongocrypt_status_t *status);

/*
 * Parse an optional boolean value from BSON.
 * @dotkey may be a dot separated key like: "a.b.c".
 * @*out is set to a copy of the value if found, false otherwise.
 * Returns true if no error occured.
 */
bool _mongocrypt_parse_optional_bool(const bson_t *bson, const char *dotkey, bool *out, mongocrypt_status_t *status);

/*
 * Parse a required UTF-8 value from BSON.
 * @dotkey may be a dot separated key like: "a.b.c".
 * @*out is set to a copy of the string if found, NULL otherwise. Caller must
 * clean up with bson_free (*out).
 * Returns true if no error occured.
 */
bool _mongocrypt_parse_required_utf8(const bson_t *bson, const char *dotkey, char **out, mongocrypt_status_t *status);

/*
 * Parse an optional endpoint UTF-8 from BSON.
 * @dotkey may be a dot separated key like: "a.b.c".
 * @*out is set to a new _mongocrypt_endpoint_t of the if found, NULL otherwise.
 * @*opts may be set to configure endpoint parsing. It is optional and may be
 * NULL. Caller must clean up with _mongocrypt_endpoint_destroy (*out). Returns
 * true if no error occured.
 */
bool _mongocrypt_parse_optional_endpoint(const bson_t *bson,
                                         const char *dotkey,
                                         _mongocrypt_endpoint_t **out,
                                         _mongocrypt_endpoint_parse_opts_t *opts,
                                         mongocrypt_status_t *status);

/*
 * Parse a required endpoint UTF-8 from BSON.
 * @dotkey may be a dot separated key like: "a.b.c".
 * @*out is set to a new _mongocrypt_endpoint_t of the if found, NULL otherwise.
 * @*opts may be set to configure endpoint parsing. It is optional and may be
 * NULL. Caller must clean up with _mongocrypt_endpoint_destroy (*out). Returns
 * true if no error occured.
 */
bool _mongocrypt_parse_required_endpoint(const bson_t *bson,
                                         const char *dotkey,
                                         _mongocrypt_endpoint_t **out,
                                         _mongocrypt_endpoint_parse_opts_t *opts,
                                         mongocrypt_status_t *status);

/*
 * Parse an optional binary type from BSON.
 * The field parsed is accepted as:
 * - A BSON binary value (of any subtype).
 * - A BSON UTF-8 value, set to base64 encoded data.
 *
 * @dotkey may be a dot separated key like: "a.b.c"
 * @out is initialized with the parsed data, or initialized to empty on error.
 * Caller must clean up with _mongocrypt_buffer_cleanup (out).
 * Returns true if no error occurred.
 */
bool _mongocrypt_parse_optional_binary(const bson_t *bson,
                                       const char *dotkey,
                                       _mongocrypt_buffer_t *out,
                                       mongocrypt_status_t *status);

/*
 * Parse a required binary type from BSON.
 * The field parsed is accepted as:
 * - A BSON binary value (of any subtype).
 * - A BSON UTF-8 value, set to base64 encoded data.
 *
 * @dotkey may be a dot separated key like: "a.b.c"
 * @out is initialized with the parsed data, or initialized to empty on error.
 * Caller must clean up with _mongocrypt_buffer_cleanup (out).
 * Returns true if no error occurred.
 */
bool _mongocrypt_parse_required_binary(const bson_t *bson,
                                       const char *dotkey,
                                       _mongocrypt_buffer_t *out,
                                       mongocrypt_status_t *status);

/*
 * Checks for unrecognized fields in parsing @bson.
 * @dotkey is a dot separated path to a document field, like "a.b.c" or NULL.
 * Pass a list of allowed fields.
 * Returns true if no error occurred.
 */
bool _mongocrypt_check_allowed_fields_va(const bson_t *bson, const char *dotkey, mongocrypt_status_t *status, ...);

#define _mongocrypt_check_allowed_fields(bson, path, status, ...)                                                      \
    _mongocrypt_check_allowed_fields_va(bson, path, status, __VA_ARGS__, NULL)

bool mc_kmsid_parse(const char *kmsid,
                    _mongocrypt_kms_provider_t *type_out,
                    const char **name_out,
                    mongocrypt_status_t *status);
#endif /* MONGOCRYPT_OPTS_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-opts.c0000644000175100001660000011203314760300420017733 0ustar  /*
 * Copyright 2018-present MongoDB, 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.
 */

#include 

#include "mongocrypt-log-private.h"
#include "mongocrypt-opts-private.h"
#include "mongocrypt-private.h"
#include  // mc_iter_document_as_bson

#include 

typedef struct {
    mc_kms_creds_t creds;
    char *kmsid;
} mc_kms_creds_with_id_t;

void _mongocrypt_opts_kms_providers_init(_mongocrypt_opts_kms_providers_t *kms_providers) {
    _mc_array_init(&kms_providers->named_mut, sizeof(mc_kms_creds_with_id_t));
}

void _mongocrypt_opts_init(_mongocrypt_opts_t *opts) {
    BSON_ASSERT_PARAM(opts);
    memset(opts, 0, sizeof(*opts));
    opts->use_range_v2 = true;
    _mongocrypt_opts_kms_providers_init(&opts->kms_providers);
}

static void _mongocrypt_opts_kms_provider_azure_cleanup(_mongocrypt_opts_kms_provider_azure_t *kms_provider_azure) {
    if (!kms_provider_azure) {
        return;
    }
    bson_free(kms_provider_azure->client_id);
    bson_free(kms_provider_azure->client_secret);
    bson_free(kms_provider_azure->tenant_id);
    bson_free(kms_provider_azure->access_token);
    _mongocrypt_endpoint_destroy(kms_provider_azure->identity_platform_endpoint);
}

static void _mongocrypt_opts_kms_provider_gcp_cleanup(_mongocrypt_opts_kms_provider_gcp_t *kms_provider_gcp) {
    if (!kms_provider_gcp) {
        return;
    }
    bson_free(kms_provider_gcp->email);
    _mongocrypt_endpoint_destroy(kms_provider_gcp->endpoint);
    _mongocrypt_buffer_cleanup(&kms_provider_gcp->private_key);
    bson_free(kms_provider_gcp->access_token);
}

static void _mongocrypt_opts_kms_provider_local_cleanup(_mongocrypt_opts_kms_provider_local_t *kms_provider_local) {
    _mongocrypt_buffer_cleanup(&kms_provider_local->key);
}

static void _mongocrypt_opts_kms_provider_aws_cleanup(_mongocrypt_opts_kms_provider_aws_t *kms_provider_aws) {
    bson_free(kms_provider_aws->secret_access_key);
    bson_free(kms_provider_aws->access_key_id);
    bson_free(kms_provider_aws->session_token);
}

static void _mongocrypt_opts_kms_provider_kmip_cleanup(_mongocrypt_opts_kms_provider_kmip_t *kms_provider_kmip) {
    _mongocrypt_endpoint_destroy(kms_provider_kmip->endpoint);
}

void _mongocrypt_opts_kms_providers_cleanup(_mongocrypt_opts_kms_providers_t *kms_providers) {
    if (!kms_providers) {
        return;
    }
    _mongocrypt_opts_kms_provider_aws_cleanup(&kms_providers->aws_mut);
    _mongocrypt_opts_kms_provider_local_cleanup(&kms_providers->local_mut);
    _mongocrypt_opts_kms_provider_azure_cleanup(&kms_providers->azure_mut);
    _mongocrypt_opts_kms_provider_gcp_cleanup(&kms_providers->gcp_mut);
    _mongocrypt_opts_kms_provider_kmip_cleanup(&kms_providers->kmip_mut);
    for (size_t i = 0; i < kms_providers->named_mut.len; i++) {
        mc_kms_creds_with_id_t kcwid = _mc_array_index(&kms_providers->named_mut, mc_kms_creds_with_id_t, i);
        switch (kcwid.creds.type) {
        default:
        case MONGOCRYPT_KMS_PROVIDER_NONE: break;
        case MONGOCRYPT_KMS_PROVIDER_AWS: {
            _mongocrypt_opts_kms_provider_aws_cleanup(&kcwid.creds.value.aws);
            break;
        }
        case MONGOCRYPT_KMS_PROVIDER_LOCAL: {
            _mongocrypt_opts_kms_provider_local_cleanup(&kcwid.creds.value.local);
            break;
        }
        case MONGOCRYPT_KMS_PROVIDER_AZURE: {
            _mongocrypt_opts_kms_provider_azure_cleanup(&kcwid.creds.value.azure);
            break;
        }
        case MONGOCRYPT_KMS_PROVIDER_GCP: {
            _mongocrypt_opts_kms_provider_gcp_cleanup(&kcwid.creds.value.gcp);
            break;
        }
        case MONGOCRYPT_KMS_PROVIDER_KMIP: {
            _mongocrypt_endpoint_destroy(kcwid.creds.value.kmip.endpoint);
            break;
        }
        }
        bson_free(kcwid.kmsid);
    }
    _mc_array_destroy(&kms_providers->named_mut);
}

void _mongocrypt_opts_merge_kms_providers(_mongocrypt_opts_kms_providers_t *dest,
                                          const _mongocrypt_opts_kms_providers_t *source) {
    BSON_ASSERT_PARAM(dest);
    BSON_ASSERT_PARAM(source);

    if (source->configured_providers & MONGOCRYPT_KMS_PROVIDER_AWS) {
        memcpy(&dest->aws_mut, &source->aws_mut, sizeof(source->aws_mut));
        dest->configured_providers |= MONGOCRYPT_KMS_PROVIDER_AWS;
    }
    if (source->configured_providers & MONGOCRYPT_KMS_PROVIDER_LOCAL) {
        memcpy(&dest->local_mut, &source->local_mut, sizeof(source->local_mut));
        dest->configured_providers |= MONGOCRYPT_KMS_PROVIDER_LOCAL;
    }
    if (source->configured_providers & MONGOCRYPT_KMS_PROVIDER_AZURE) {
        memcpy(&dest->azure_mut, &source->azure_mut, sizeof(source->azure_mut));
        dest->configured_providers |= MONGOCRYPT_KMS_PROVIDER_AZURE;
    }
    if (source->configured_providers & MONGOCRYPT_KMS_PROVIDER_GCP) {
        memcpy(&dest->gcp_mut, &source->gcp_mut, sizeof(source->gcp_mut));
        dest->configured_providers |= MONGOCRYPT_KMS_PROVIDER_GCP;
    }
    if (source->configured_providers & MONGOCRYPT_KMS_PROVIDER_KMIP) {
        memcpy(&dest->kmip_mut, &source->kmip_mut, sizeof(source->kmip_mut));
        dest->configured_providers |= MONGOCRYPT_KMS_PROVIDER_KMIP;
    }
    /* ensure all providers were copied */
    BSON_ASSERT(!(source->configured_providers & ~dest->configured_providers));
}

void _mongocrypt_opts_cleanup(_mongocrypt_opts_t *opts) {
    if (!opts) {
        return;
    }
    _mongocrypt_opts_kms_providers_cleanup(&opts->kms_providers);
    _mongocrypt_buffer_cleanup(&opts->schema_map);
    _mongocrypt_buffer_cleanup(&opts->encrypted_field_config_map);
    // Free any lib search paths added by the caller
    for (int i = 0; i < opts->n_crypt_shared_lib_search_paths; ++i) {
        mstr_free(opts->crypt_shared_lib_search_paths[i]);
    }
    bson_free(opts->crypt_shared_lib_search_paths);
    mstr_free(opts->crypt_shared_lib_override_path);
}

bool _mongocrypt_opts_kms_providers_validate(_mongocrypt_opts_t *opts,
                                             _mongocrypt_opts_kms_providers_t *kms_providers,
                                             mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(opts);
    BSON_ASSERT_PARAM(kms_providers);

    if (!kms_providers->configured_providers && !kms_providers->need_credentials && kms_providers->named_mut.len == 0) {
        CLIENT_ERR("no kms provider set");
        return false;
    }

    if (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_AWS) {
        if (!kms_providers->aws_mut.access_key_id || !kms_providers->aws_mut.secret_access_key) {
            CLIENT_ERR("aws credentials unset");
            return false;
        }
    }

    if (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_LOCAL) {
        if (_mongocrypt_buffer_empty(&kms_providers->local_mut.key)) {
            CLIENT_ERR("local data key unset");
            return false;
        }
    }

    if (kms_providers->need_credentials && !opts->use_need_kms_credentials_state) {
        CLIENT_ERR("on-demand credentials not enabled");
        return false;
    }

    return true;
}

/* _shares_bson_fields checks if @one or @two share any top-level field names.
 * Returns false on error and sets @status. Returns true if no error
 * occurred. Sets @found to the first shared field name found.
 * If no shared field names are found, @found is set to NULL.
 */
static bool _shares_bson_fields(bson_t *one, bson_t *two, const char **found, mongocrypt_status_t *status) {
    bson_iter_t iter1;
    bson_iter_t iter2;

    BSON_ASSERT_PARAM(one);
    BSON_ASSERT_PARAM(two);
    BSON_ASSERT_PARAM(found);
    *found = NULL;
    if (!bson_iter_init(&iter1, one)) {
        CLIENT_ERR("error iterating one BSON in _shares_bson_fields");
        return false;
    }
    while (bson_iter_next(&iter1)) {
        const char *key1 = bson_iter_key(&iter1);

        if (!bson_iter_init(&iter2, two)) {
            CLIENT_ERR("error iterating two BSON in _shares_bson_fields");
            return false;
        }
        while (bson_iter_next(&iter2)) {
            const char *key2 = bson_iter_key(&iter2);
            if (0 == strcmp(key1, key2)) {
                *found = key1;
                return true;
            }
        }
    }
    return true;
}

/* _validate_encrypted_field_config_map_and_schema_map validates that the same
 * namespace is not both in encrypted_field_config_map and schema_map. */
static bool _validate_encrypted_field_config_map_and_schema_map(_mongocrypt_buffer_t *encrypted_field_config_map,
                                                                _mongocrypt_buffer_t *schema_map,
                                                                mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(encrypted_field_config_map);
    BSON_ASSERT_PARAM(schema_map);

    const char *found;
    bson_t schema_map_bson;
    bson_t encrypted_field_config_map_bson;

    /* If either map is unset, there is nothing to validate. Return true to
     * signal no error. */
    if (_mongocrypt_buffer_empty(encrypted_field_config_map)) {
        return true;
    }
    if (_mongocrypt_buffer_empty(schema_map)) {
        return true;
    }

    if (!_mongocrypt_buffer_to_bson(schema_map, &schema_map_bson)) {
        CLIENT_ERR("error converting schema_map to BSON");
        return false;
    }
    if (!_mongocrypt_buffer_to_bson(encrypted_field_config_map, &encrypted_field_config_map_bson)) {
        CLIENT_ERR("error converting encrypted_field_config_map to BSON");
        return false;
    }
    if (!_shares_bson_fields(&schema_map_bson, &encrypted_field_config_map_bson, &found, status)) {
        return false;
    }
    if (found != NULL) {
        CLIENT_ERR("%s is present in both schema_map and encrypted_field_config_map", found);
        return false;
    }
    return true;
}

bool _mongocrypt_opts_validate(_mongocrypt_opts_t *opts, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(opts);

    if (!_validate_encrypted_field_config_map_and_schema_map(&opts->encrypted_field_config_map,
                                                             &opts->schema_map,
                                                             status)) {
        return false;
    }
    return _mongocrypt_opts_kms_providers_validate(opts, &opts->kms_providers, status);
}

bool _mongocrypt_opts_kms_providers_lookup(const _mongocrypt_opts_kms_providers_t *kms_providers,
                                           const char *kmsid,
                                           mc_kms_creds_t *out) {
    *out = (mc_kms_creds_t){0};
    if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_AWS) && 0 == strcmp(kmsid, "aws")) {
        out->type = MONGOCRYPT_KMS_PROVIDER_AWS;
        out->value.aws = kms_providers->aws_mut;
        return true;
    }
    if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_AZURE) && 0 == strcmp(kmsid, "azure")) {
        out->type = MONGOCRYPT_KMS_PROVIDER_AZURE;
        out->value.azure = kms_providers->azure_mut;
        return true;
    }

    if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_GCP) && 0 == strcmp(kmsid, "gcp")) {
        out->type = MONGOCRYPT_KMS_PROVIDER_GCP;
        out->value.gcp = kms_providers->gcp_mut;
        return true;
    }

    if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_LOCAL) && 0 == strcmp(kmsid, "local")) {
        out->type = MONGOCRYPT_KMS_PROVIDER_LOCAL;
        out->value.local = kms_providers->local_mut;
        return true;
    }

    if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_KMIP) && 0 == strcmp(kmsid, "kmip")) {
        out->type = MONGOCRYPT_KMS_PROVIDER_KMIP;
        out->value.kmip = kms_providers->kmip_mut;
        return true;
    }

    // Check for KMS providers with a name.
    for (size_t i = 0; i < kms_providers->named_mut.len; i++) {
        mc_kms_creds_with_id_t kcwi = _mc_array_index(&kms_providers->named_mut, mc_kms_creds_with_id_t, i);
        if (0 == strcmp(kmsid, kcwi.kmsid)) {
            *out = kcwi.creds;
            return true;
        }
    }

    return false;
}

bool _mongocrypt_parse_optional_utf8(const bson_t *bson, const char *dotkey, char **out, mongocrypt_status_t *status) {
    bson_iter_t iter;
    bson_iter_t child;

    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(dotkey);
    BSON_ASSERT_PARAM(out);

    *out = NULL;

    if (!bson_iter_init(&iter, bson)) {
        CLIENT_ERR("invalid BSON");
        return false;
    }
    if (!bson_iter_find_descendant(&iter, dotkey, &child)) {
        /* Not found. Not an error. */
        return true;
    }
    if (!BSON_ITER_HOLDS_UTF8(&child)) {
        CLIENT_ERR("expected UTF-8 %s", dotkey);
        return false;
    }

    *out = bson_strdup(bson_iter_utf8(&child, NULL));
    return true;
}

bool _mongocrypt_parse_optional_bool(const bson_t *bson, const char *dotkey, bool *out, mongocrypt_status_t *status) {
    bson_iter_t iter;
    bson_iter_t child;

    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(dotkey);
    BSON_ASSERT_PARAM(out);

    *out = false;

    if (!bson_iter_init(&iter, bson)) {
        CLIENT_ERR("invalid BSON");
        return false;
    }
    if (!bson_iter_find_descendant(&iter, dotkey, &child)) {
        /* Not found. Not an error. */
        return true;
    }
    if (!BSON_ITER_HOLDS_BOOL(&child)) {
        CLIENT_ERR("expected bool %s", dotkey);
        return false;
    }

    *out = bson_iter_bool(&child);
    return true;
}

bool _mongocrypt_parse_required_utf8(const bson_t *bson, const char *dotkey, char **out, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(dotkey);
    BSON_ASSERT_PARAM(out);

    if (!_mongocrypt_parse_optional_utf8(bson, dotkey, out, status)) {
        return false;
    }

    if (!*out) {
        CLIENT_ERR("expected UTF-8 %s", dotkey);
        return false;
    }

    return true;
}

bool _mongocrypt_parse_optional_endpoint(const bson_t *bson,
                                         const char *dotkey,
                                         _mongocrypt_endpoint_t **out,
                                         _mongocrypt_endpoint_parse_opts_t *opts,
                                         mongocrypt_status_t *status) {
    char *endpoint_raw;

    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(dotkey);
    BSON_ASSERT_PARAM(out);

    *out = NULL;

    if (!_mongocrypt_parse_optional_utf8(bson, dotkey, &endpoint_raw, status)) {
        return false;
    }

    /* Not found. Not an error. */
    if (!endpoint_raw) {
        return true;
    }

    *out = _mongocrypt_endpoint_new(endpoint_raw, -1, opts, status);
    bson_free(endpoint_raw);
    return (*out) != NULL;
}

bool _mongocrypt_parse_required_endpoint(const bson_t *bson,
                                         const char *dotkey,
                                         _mongocrypt_endpoint_t **out,
                                         _mongocrypt_endpoint_parse_opts_t *opts,
                                         mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(dotkey);
    BSON_ASSERT_PARAM(out);

    if (!_mongocrypt_parse_optional_endpoint(bson, dotkey, out, opts, status)) {
        return false;
    }

    if (!*out) {
        CLIENT_ERR("expected endpoint %s", dotkey);
        return false;
    }

    return true;
}

bool _mongocrypt_parse_optional_binary(const bson_t *bson,
                                       const char *dotkey,
                                       _mongocrypt_buffer_t *out,
                                       mongocrypt_status_t *status) {
    bson_iter_t iter;
    bson_iter_t child;

    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(dotkey);
    BSON_ASSERT_PARAM(out);

    _mongocrypt_buffer_init(out);

    if (!bson_iter_init(&iter, bson)) {
        CLIENT_ERR("invalid BSON");
        return false;
    }
    if (!bson_iter_find_descendant(&iter, dotkey, &child)) {
        /* Not found. Not an error. */
        return true;
    }
    if (BSON_ITER_HOLDS_UTF8(&child)) {
        size_t out_len;
        /* Attempt to base64 decode. */
        out->data = kms_message_b64_to_raw(bson_iter_utf8(&child, NULL), &out_len);
        if (!out->data) {
            CLIENT_ERR("unable to parse base64 from UTF-8 field %s", dotkey);
            return false;
        }
        BSON_ASSERT(out_len <= UINT32_MAX);
        out->len = (uint32_t)out_len;
        out->owned = true;
    } else if (BSON_ITER_HOLDS_BINARY(&child)) {
        if (!_mongocrypt_buffer_copy_from_binary_iter(out, &child)) {
            CLIENT_ERR("unable to parse binary from field %s", dotkey);
            return false;
        }
    } else {
        CLIENT_ERR("expected UTF-8 or binary %s", dotkey);
        return false;
    }

    return true;
}

bool _mongocrypt_parse_required_binary(const bson_t *bson,
                                       const char *dotkey,
                                       _mongocrypt_buffer_t *out,
                                       mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT_PARAM(dotkey);
    BSON_ASSERT_PARAM(out);

    if (!_mongocrypt_parse_optional_binary(bson, dotkey, out, status)) {
        return false;
    }

    if (out->len == 0) {
        CLIENT_ERR("expected UTF-8 or binary %s", dotkey);
        return false;
    }

    return true;
}

bool _mongocrypt_check_allowed_fields_va(const bson_t *bson, const char *dotkey, mongocrypt_status_t *status, ...) {
    va_list args;
    const char *field;
    bson_iter_t iter;

    BSON_ASSERT_PARAM(bson);

    if (dotkey) {
        bson_iter_t parent;

        bson_iter_init(&parent, bson);
        if (!bson_iter_find_descendant(&parent, dotkey, &iter) || !BSON_ITER_HOLDS_DOCUMENT(&iter)) {
            CLIENT_ERR("invalid BSON, expected %s", dotkey);
            return false;
        }
        bson_iter_recurse(&iter, &iter);
    } else {
        bson_iter_init(&iter, bson);
    }

    while (bson_iter_next(&iter)) {
        bool found = false;

        va_start(args, status);
        field = va_arg(args, const char *);
        while (field) {
            if (0 == strcmp(field, bson_iter_key(&iter))) {
                found = true;
                break;
            }
            field = va_arg(args, const char *);
        }
        va_end(args);

        if (!found) {
            CLIENT_ERR("Unexpected field: '%s'", bson_iter_key(&iter));
            return false;
        }
    }
    return true;
}

#define KEY_HELP "Expected `` or `:`. Example: `local` or `local:name`."

bool mc_kmsid_parse(const char *kmsid,
                    _mongocrypt_kms_provider_t *type_out,
                    const char **name_out,
                    mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(kmsid);
    BSON_ASSERT_PARAM(type_out);
    BSON_ASSERT_PARAM(name_out);
    BSON_ASSERT(status || true); // Optional.

    *type_out = MONGOCRYPT_KMS_PROVIDER_NONE;
    *name_out = NULL;

    const char *type_end = strstr(kmsid, ":");
    size_t type_nchars;

    if (type_end == NULL) {
        // Parse `kmsid` as ``.
        type_nchars = strlen(kmsid);
    } else {
        // Parse `kmsid` as `:`.
        ptrdiff_t diff = type_end - kmsid;
        BSON_ASSERT(diff >= 0 && (uint64_t)diff < SIZE_MAX);
        type_nchars = (size_t)diff;
    }

    if (0 == strncmp("aws", kmsid, type_nchars)) {
        *type_out = MONGOCRYPT_KMS_PROVIDER_AWS;
    } else if (0 == strncmp("azure", kmsid, type_nchars)) {
        *type_out = MONGOCRYPT_KMS_PROVIDER_AZURE;
    } else if (0 == strncmp("gcp", kmsid, type_nchars)) {
        *type_out = MONGOCRYPT_KMS_PROVIDER_GCP;
    } else if (0 == strncmp("kmip", kmsid, type_nchars)) {
        *type_out = MONGOCRYPT_KMS_PROVIDER_KMIP;
    } else if (0 == strncmp("local", kmsid, type_nchars)) {
        *type_out = MONGOCRYPT_KMS_PROVIDER_LOCAL;
    } else {
        CLIENT_ERR("unrecognized KMS provider `%s`: unrecognized type. " KEY_HELP, kmsid);
        return false;
    }

    if (type_end != NULL) {
        // Parse name.
        *name_out = type_end + 1;
        if (0 == strlen(*name_out)) {
            CLIENT_ERR("unrecognized KMS provider `%s`: empty name. " KEY_HELP, kmsid);
            return false;
        }

        // Validate name only contains: [a-zA-Z0-9_]
        for (const char *cp = *name_out; *cp != '\0'; cp++) {
            char c = *cp;
            if (c >= 'a' && c <= 'z') {
                continue;
            }
            if (c >= 'A' && c <= 'Z') {
                continue;
            }
            if (c >= '0' && c <= '9') {
                continue;
            }
            if (c == '_') {
                continue;
            }
            CLIENT_ERR("unrecognized KMS provider `%s`: unsupported character `%c`. Must be of the form `:` where `` only contain characters [a-zA-Z0-9_]",
                       kmsid,
                       c);
            return false;
        }
    }
    return true;
}

static bool _mongocrypt_opts_kms_provider_local_parse(_mongocrypt_opts_kms_provider_local_t *local,
                                                      const char *kmsid,
                                                      const bson_t *def,
                                                      mongocrypt_status_t *status) {
    bool ok = false;
    if (!_mongocrypt_parse_required_binary(def, "key", &local->key, status)) {
        goto fail;
    }

    if (local->key.len != MONGOCRYPT_KEY_LEN) {
        CLIENT_ERR("local key must be %d bytes", MONGOCRYPT_KEY_LEN);
        goto fail;
    }

    if (!_mongocrypt_check_allowed_fields(def, NULL /* root */, status, "key")) {
        goto fail;
    }
    ok = true;
fail:
    if (!ok) {
        // Wrap error to identify the failing `kmsid`.
        CLIENT_ERR("Failed to parse KMS provider `%s`: %s", kmsid, mongocrypt_status_message(status, NULL /* len */));
    }
    return ok;
}

static bool _mongocrypt_opts_kms_provider_azure_parse(_mongocrypt_opts_kms_provider_azure_t *azure,
                                                      const char *kmsid,
                                                      const bson_t *def,
                                                      mongocrypt_status_t *status) {
    bool ok = false;
    if (!_mongocrypt_parse_optional_utf8(def, "accessToken", &azure->access_token, status)) {
        goto done;
    }

    if (azure->access_token) {
        // Caller provides an accessToken directly
        if (!_mongocrypt_check_allowed_fields(def, NULL /* root */, status, "accessToken")) {
            goto done;
        }
        ok = true;
        goto done;
    }

    // No accessToken given, so we'll need to look one up on our own later
    // using the Azure API

    if (!_mongocrypt_parse_required_utf8(def, "tenantId", &azure->tenant_id, status)) {
        goto done;
    }

    if (!_mongocrypt_parse_required_utf8(def, "clientId", &azure->client_id, status)) {
        goto done;
    }

    if (!_mongocrypt_parse_required_utf8(def, "clientSecret", &azure->client_secret, status)) {
        goto done;
    }

    if (!_mongocrypt_parse_optional_endpoint(def,
                                             "identityPlatformEndpoint",
                                             &azure->identity_platform_endpoint,
                                             NULL /* opts */,
                                             status)) {
        goto done;
    }

    if (!_mongocrypt_check_allowed_fields(def,
                                          NULL /* root */,
                                          status,
                                          "tenantId",
                                          "clientId",
                                          "clientSecret",
                                          "identityPlatformEndpoint")) {
        goto done;
    }

    ok = true;
done:
    if (!ok) {
        // Wrap error to identify the failing `kmsid`.
        CLIENT_ERR("Failed to parse KMS provider `%s`: %s", kmsid, mongocrypt_status_message(status, NULL /* len */));
    }
    return ok;
}

static bool _mongocrypt_opts_kms_provider_gcp_parse(_mongocrypt_opts_kms_provider_gcp_t *gcp,
                                                    const char *kmsid,
                                                    const bson_t *def,
                                                    mongocrypt_status_t *status) {
    bool ok = false;
    if (!_mongocrypt_parse_optional_utf8(def, "accessToken", &gcp->access_token, status)) {
        goto done;
    }

    if (gcp->access_token) {
        // Caller provides an accessToken directly
        if (!_mongocrypt_check_allowed_fields(def, NULL /* root */, status, "accessToken")) {
            goto done;
        }
        ok = true;
        goto done;
    }

    // No accessToken given, so we'll need to look one up on our own later
    // using the GCP API

    if (!_mongocrypt_parse_required_utf8(def, "email", &gcp->email, status)) {
        goto done;
    }

    if (!_mongocrypt_parse_required_binary(def, "privateKey", &gcp->private_key, status)) {
        goto done;
    }

    if (!_mongocrypt_parse_optional_endpoint(def, "endpoint", &gcp->endpoint, NULL /* opts */, status)) {
        goto done;
    }

    if (!_mongocrypt_check_allowed_fields(def, NULL /* root */, status, "email", "privateKey", "endpoint")) {
        goto done;
    }

    ok = true;
done:
    if (!ok) {
        // Wrap error to identify the failing `kmsid`.
        CLIENT_ERR("Failed to parse KMS provider `%s`: %s", kmsid, mongocrypt_status_message(status, NULL /* len */));
    }
    return ok;
}

static bool _mongocrypt_opts_kms_provider_aws_parse(_mongocrypt_opts_kms_provider_aws_t *aws,
                                                    const char *kmsid,
                                                    const bson_t *def,
                                                    mongocrypt_status_t *status) {
    bool ok = false;

    if (!_mongocrypt_parse_required_utf8(def, "accessKeyId", &aws->access_key_id, status)) {
        goto done;
    }
    if (!_mongocrypt_parse_required_utf8(def, "secretAccessKey", &aws->secret_access_key, status)) {
        goto done;
    }

    if (!_mongocrypt_parse_optional_utf8(def, "sessionToken", &aws->session_token, status)) {
        goto done;
    }

    if (!_mongocrypt_check_allowed_fields(def,
                                          NULL /* root */,
                                          status,
                                          "accessKeyId",
                                          "secretAccessKey",
                                          "sessionToken")) {
        goto done;
    }

    ok = true;
done:
    if (!ok) {
        // Wrap error to identify the failing `kmsid`.
        CLIENT_ERR("Failed to parse KMS provider `%s`: %s", kmsid, mongocrypt_status_message(status, NULL /* len */));
    }
    return ok;
}

static bool _mongocrypt_opts_kms_provider_kmip_parse(_mongocrypt_opts_kms_provider_kmip_t *kmip,
                                                     const char *kmsid,
                                                     const bson_t *def,
                                                     mongocrypt_status_t *status) {
    bool ok = false;

    _mongocrypt_endpoint_parse_opts_t opts = {0};

    opts.allow_empty_subdomain = true;
    if (!_mongocrypt_parse_required_endpoint(def, "endpoint", &kmip->endpoint, &opts, status)) {
        goto done;
    }

    if (!_mongocrypt_check_allowed_fields(def, NULL /* root */, status, "endpoint")) {
        goto done;
    }

    ok = true;
done:
    if (!ok) {
        // Wrap error to identify the failing `kmsid`.
        CLIENT_ERR("Failed to parse KMS provider `%s`: %s", kmsid, mongocrypt_status_message(status, NULL /* len */));
    }
    return ok;
}

bool _mongocrypt_parse_kms_providers(mongocrypt_binary_t *kms_providers_definition,
                                     _mongocrypt_opts_kms_providers_t *kms_providers,
                                     mongocrypt_status_t *status,
                                     _mongocrypt_log_t *log) {
    bson_t as_bson;
    bson_iter_t iter;

    BSON_ASSERT_PARAM(kms_providers_definition);
    BSON_ASSERT_PARAM(kms_providers);
    if (!_mongocrypt_binary_to_bson(kms_providers_definition, &as_bson) || !bson_iter_init(&iter, &as_bson)) {
        CLIENT_ERR("invalid BSON");
        return false;
    }

    while (bson_iter_next(&iter)) {
        const char *field_name;
        bson_t field_bson;

        field_name = bson_iter_key(&iter);
        if (!mc_iter_document_as_bson(&iter, &field_bson, status)) {
            return false;
        }

        const char *name;
        _mongocrypt_kms_provider_t type;
        if (!mc_kmsid_parse(field_name, &type, &name, status)) {
            return false;
        }

        if (name != NULL) {
            // Check if named provider already is configured.
            for (size_t i = 0; i < kms_providers->named_mut.len; i++) {
                mc_kms_creds_with_id_t kcwi = _mc_array_index(&kms_providers->named_mut, mc_kms_creds_with_id_t, i);
                if (0 == strcmp(kcwi.kmsid, field_name)) {
                    CLIENT_ERR("Got unexpected duplicate entry for KMS provider: `%s`", field_name);
                    return false;
                }
            }
            // Prohibit configuring with an empty document. Named KMS providers do not support on-demand credentials.
            if (bson_empty(&field_bson)) {
                CLIENT_ERR("Unexpected empty document for named KMS provider: '%s'. On-demand credentials are not "
                           "supported for named KMS providers.",
                           field_name);
                return false;
            }
            switch (type) {
            default:
            case MONGOCRYPT_KMS_PROVIDER_NONE: {
                CLIENT_ERR("Unexpected parsing KMS type: none");
                return false;
            }
            case MONGOCRYPT_KMS_PROVIDER_AWS: {
                _mongocrypt_opts_kms_provider_aws_t aws = {0};
                if (!_mongocrypt_opts_kms_provider_aws_parse(&aws, field_name, &field_bson, status)) {
                    _mongocrypt_opts_kms_provider_aws_cleanup(&aws);
                    return false;
                }
                mc_kms_creds_with_id_t kcwi = {.kmsid = bson_strdup(field_name),
                                               .creds = {.type = type, .value = {.aws = aws}}};
                _mc_array_append_val(&kms_providers->named_mut, kcwi);
                break;
            }
            case MONGOCRYPT_KMS_PROVIDER_LOCAL: {
                _mongocrypt_opts_kms_provider_local_t local = {
                    // specify .key to avoid erroneous missing-braces warning in GCC. Refer:
                    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
                    .key = {0}};
                if (!_mongocrypt_opts_kms_provider_local_parse(&local, field_name, &field_bson, status)) {
                    _mongocrypt_opts_kms_provider_local_cleanup(&local);
                    return false;
                }
                mc_kms_creds_with_id_t kcwi = {.kmsid = bson_strdup(field_name),
                                               .creds = {.type = type, .value = {.local = local}}};
                _mc_array_append_val(&kms_providers->named_mut, kcwi);
                break;
            }
            case MONGOCRYPT_KMS_PROVIDER_AZURE: {
                _mongocrypt_opts_kms_provider_azure_t azure = {0};
                if (!_mongocrypt_opts_kms_provider_azure_parse(&azure, field_name, &field_bson, status)) {
                    _mongocrypt_opts_kms_provider_azure_cleanup(&azure);
                    return false;
                }
                mc_kms_creds_with_id_t kcwi = {.kmsid = bson_strdup(field_name),
                                               .creds = {.type = type, .value = {.azure = azure}}};
                _mc_array_append_val(&kms_providers->named_mut, kcwi);
                break;
            }
            case MONGOCRYPT_KMS_PROVIDER_GCP: {
                _mongocrypt_opts_kms_provider_gcp_t gcp = {0};
                if (!_mongocrypt_opts_kms_provider_gcp_parse(&gcp, field_name, &field_bson, status)) {
                    _mongocrypt_opts_kms_provider_gcp_cleanup(&gcp);
                    return false;
                }
                mc_kms_creds_with_id_t kcwi = {.kmsid = bson_strdup(field_name),
                                               .creds = {.type = type, .value = {.gcp = gcp}}};
                _mc_array_append_val(&kms_providers->named_mut, kcwi);
                break;
            }
            case MONGOCRYPT_KMS_PROVIDER_KMIP: {
                _mongocrypt_opts_kms_provider_kmip_t kmip = {0};
                if (!_mongocrypt_opts_kms_provider_kmip_parse(&kmip, field_name, &field_bson, status)) {
                    _mongocrypt_opts_kms_provider_kmip_cleanup(&kmip);
                    return false;
                }
                mc_kms_creds_with_id_t kcwi = {.kmsid = bson_strdup(field_name),
                                               .creds = {.type = type, .value = {.kmip = kmip}}};
                _mc_array_append_val(&kms_providers->named_mut, kcwi);
                break;
            }
            }
        } else if (0 == strcmp(field_name, "azure") && bson_empty(&field_bson)) {
            kms_providers->need_credentials |= MONGOCRYPT_KMS_PROVIDER_AZURE;
        } else if (0 == strcmp(field_name, "azure")) {
            if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_AZURE)) {
                CLIENT_ERR("azure KMS provider already set");
                return false;
            }

            if (!_mongocrypt_opts_kms_provider_azure_parse(&kms_providers->azure_mut,
                                                           field_name,
                                                           &field_bson,
                                                           status)) {
                return false;
            }
            kms_providers->configured_providers |= MONGOCRYPT_KMS_PROVIDER_AZURE;
        } else if (0 == strcmp(field_name, "gcp") && bson_empty(&field_bson)) {
            kms_providers->need_credentials |= MONGOCRYPT_KMS_PROVIDER_GCP;
        } else if (0 == strcmp(field_name, "gcp")) {
            if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_GCP)) {
                CLIENT_ERR("gcp KMS provider already set");
                return false;
            }
            if (!_mongocrypt_opts_kms_provider_gcp_parse(&kms_providers->gcp_mut, field_name, &field_bson, status)) {
                return false;
            }
            kms_providers->configured_providers |= MONGOCRYPT_KMS_PROVIDER_GCP;
        } else if (0 == strcmp(field_name, "local") && bson_empty(&field_bson)) {
            kms_providers->need_credentials |= MONGOCRYPT_KMS_PROVIDER_LOCAL;
        } else if (0 == strcmp(field_name, "local")) {
            if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_LOCAL)) {
                CLIENT_ERR("local KMS provider already set");
                return false;
            }
            if (!_mongocrypt_opts_kms_provider_local_parse(&kms_providers->local_mut,
                                                           field_name,
                                                           &field_bson,
                                                           status)) {
                return false;
            }
            kms_providers->configured_providers |= MONGOCRYPT_KMS_PROVIDER_LOCAL;
        } else if (0 == strcmp(field_name, "aws") && bson_empty(&field_bson)) {
            kms_providers->need_credentials |= MONGOCRYPT_KMS_PROVIDER_AWS;
        } else if (0 == strcmp(field_name, "aws")) {
            if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_AWS)) {
                CLIENT_ERR("aws KMS provider already set");
                return false;
            }
            if (!_mongocrypt_opts_kms_provider_aws_parse(&kms_providers->aws_mut, field_name, &field_bson, status)) {
                return false;
            }
            kms_providers->configured_providers |= MONGOCRYPT_KMS_PROVIDER_AWS;
        } else if (0 == strcmp(field_name, "kmip") && bson_empty(&field_bson)) {
            kms_providers->need_credentials |= MONGOCRYPT_KMS_PROVIDER_KMIP;
        } else if (0 == strcmp(field_name, "kmip")) {
            if (!_mongocrypt_opts_kms_provider_kmip_parse(&kms_providers->kmip_mut, field_name, &field_bson, status)) {
                return false;
            }
            kms_providers->configured_providers |= MONGOCRYPT_KMS_PROVIDER_KMIP;
        } else {
            CLIENT_ERR("unsupported KMS provider: %s", field_name);
            return false;
        }
    }

    if (log && log->trace_enabled) {
        char *as_str = bson_as_relaxed_extended_json(&as_bson, NULL);
        _mongocrypt_log(log, MONGOCRYPT_LOG_LEVEL_TRACE, "%s (%s=\"%s\")", BSON_FUNC, "kms_providers", as_str);
        bson_free(as_str);
    }

    return true;
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-private.h0000644000175100001660000002067614760300420020440 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_PRIVATE_H
#define MONGOCRYPT_PRIVATE_H

#include "bson/bson.h"
#include "mongocrypt-config.h"
#include "mongocrypt.h"

#include "mongocrypt-buffer-private.h"
#include "mongocrypt-cache-key-private.h"
#include "mongocrypt-cache-oauth-private.h"
#include "mongocrypt-cache-private.h"
#include "mongocrypt-crypto-private.h"
#include "mongocrypt-dll-private.h"
#include "mongocrypt-log-private.h"
#include "mongocrypt-mutex-private.h"
#include "mongocrypt-opts-private.h"

#include "mongo_crypt-v1.h"

#include 

#define MONGOCRYPT_GENERIC_ERROR_CODE 1

#define CLIENT_ERR_W_CODE(code, ...) _mongocrypt_set_error(status, MONGOCRYPT_STATUS_ERROR_CLIENT, code, __VA_ARGS__)

#define CLIENT_ERR(fmt, ...) CLIENT_ERR_W_CODE(MONGOCRYPT_GENERIC_ERROR_CODE, fmt, ##__VA_ARGS__)

#define KMS_ERR_W_CODE(code, ...) _mongocrypt_set_error(status, MONGOCRYPT_STATUS_ERROR_KMS, code, __VA_ARGS__)

#define KMS_ERR(...) KMS_ERR_W_CODE(MONGOCRYPT_GENERIC_ERROR_CODE, __VA_ARGS__)

#define MONGOCRYPT_STR_AND_LEN(x) (x), (sizeof(x) / sizeof((x)[0]) - 1)

#define MONGOCRYPT_DATA_AND_LEN(x) ((uint8_t *)x), (sizeof(x) / sizeof((x)[0]) - 1)

/* TODO: Move these to mongocrypt-log-private.h? */
const char *tmp_json(const bson_t *bson);

const char *tmp_buf(const _mongocrypt_buffer_t *buf);

// _mongocrypt_set_error sets an error status.
// `status->message` is set after evaluating `format` and variadic args.
// It is safe to uses a `status->message` as an argument to wrap an error. For
// example: _mongocrypt_set_error (
//    status,
//    MONGOCRYPT_STATUS_ERROR_CLIENT,
//    MONGOCRYPT_GENERIC_ERROR_CODE,
//    "Error occurred. Original error: %s",
//    mongocrypt_status_message (status, NULL /* len */));
MLIB_ANNOTATE_PRINTF(4, 5)
void _mongocrypt_set_error(mongocrypt_status_t *status,
                           mongocrypt_status_type_t type,
                           uint32_t code,
                           const char *format,
                           ...);

typedef struct _mongo_crypt_v1_vtable {
#define MONGOC_CSFLE_FUNCTIONS_X                                                                                       \
    /* status methods */                                                                                               \
    X_FUNC(status_create, mongo_crypt_v1_status *, void)                                                               \
    X_FUNC(status_destroy, void, mongo_crypt_v1_status *status)                                                        \
    X_FUNC(status_get_error, int, const mongo_crypt_v1_status *status)                                                 \
    X_FUNC(status_get_explanation, const char *, const mongo_crypt_v1_status *status)                                  \
    X_FUNC(status_get_code, int, const mongo_crypt_v1_status *status)                                                  \
    /* lib methods */                                                                                                  \
    X_FUNC(lib_create, mongo_crypt_v1_lib *, mongo_crypt_v1_status *status)                                            \
    X_FUNC(lib_destroy, int, mongo_crypt_v1_lib *lib, mongo_crypt_v1_status *status)                                   \
    /* query_analyzer methods */                                                                                       \
    X_FUNC(query_analyzer_create,                                                                                      \
           mongo_crypt_v1_query_analyzer *,                                                                            \
           mongo_crypt_v1_lib *lib,                                                                                    \
           mongo_crypt_v1_status *status)                                                                              \
    X_FUNC(query_analyzer_destroy, void, mongo_crypt_v1_query_analyzer *analyzer)                                      \
    X_FUNC(analyze_query,                                                                                              \
           uint8_t *,                                                                                                  \
           mongo_crypt_v1_query_analyzer *analyer,                                                                     \
           const uint8_t *documentBSON,                                                                                \
           const char *ns_str,                                                                                         \
           uint32_t ns_len,                                                                                            \
           uint32_t *bson_len,                                                                                         \
           mongo_crypt_v1_status *status)                                                                              \
    X_FUNC(get_version, uint64_t, void)                                                                                \
    X_FUNC(get_version_str, const char *, void)                                                                        \
    /* Free bson data created by csfle */                                                                              \
    X_FUNC(bson_free, void, uint8_t *bson)

#define X_FUNC(Name, RetType, ...) RetType (*Name)(__VA_ARGS__);
    MONGOC_CSFLE_FUNCTIONS_X
#undef X_FUNC

    /// Whether the vtable is valid and complete
    bool okay;
} _mongo_crypt_v1_vtable;

struct _mongocrypt_t {
    bool initialized;
    _mongocrypt_opts_t opts;
    mongocrypt_mutex_t mutex;
    /* The collinfo and key cache are protected with an internal mutex. */
    _mongocrypt_cache_t cache_collinfo;
    _mongocrypt_cache_t cache_key;
    _mongocrypt_log_t log;
    mongocrypt_status_t *status;
    _mongocrypt_crypto_t *crypto;
    /* A counter, protected by mutex, for generating unique context ids */
    uint32_t ctx_counter;
    mc_mapof_kmsid_to_token_t *cache_oauth;
    /// A CSFLE DLL vtable, initialized by mongocrypt_init
    _mongo_crypt_v1_vtable csfle;
    /// Pointer to the global csfle_lib object. Should not be freed directly.
    mongo_crypt_v1_lib *csfle_lib;
    bool retry_enabled;
};

typedef enum {
    MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE = 0,
    MONGOCRYPT_ENCRYPTION_ALGORITHM_DETERMINISTIC = 1,
    MONGOCRYPT_ENCRYPTION_ALGORITHM_RANDOM = 2
} mongocrypt_encryption_algorithm_t;

typedef enum {
    MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT = 1,
    MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND = 2
} mongocrypt_fle2_placeholder_type_t;

typedef enum {
    MONGOCRYPT_FLE2_ALGORITHM_UNINDEXED = 1,
    MONGOCRYPT_FLE2_ALGORITHM_EQUALITY = 2,
    MONGOCRYPT_FLE2_ALGORITHM_RANGE = 3
} mongocrypt_fle2_encryption_algorithm_t;

bool _mongocrypt_validate_and_copy_string(const char *in, int32_t in_len, char **out) MONGOCRYPT_WARN_UNUSED_RESULT;

char *_mongocrypt_new_string_from_bytes(const void *in, int len);

char *_mongocrypt_new_json_string_from_binary(mongocrypt_binary_t *binary);

/* _mongocrypt_needs_credentials returns true if @crypt was configured to
 * request credentials for any KMS provider. */
bool _mongocrypt_needs_credentials(mongocrypt_t *crypt);

/* _mongocrypt_needs_credentials returns true if @crypt was configured to
 * request credentials for @provider and optional @name. @name may be NULL. */
bool _mongocrypt_needs_credentials_for_provider(mongocrypt_t *crypt,
                                                _mongocrypt_kms_provider_t provider,
                                                const char *name);

/**
 * Enable/disable the use of FLE2v2 payload types for write.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] enable Whether to enable use of FLE2v2 payloads.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_status
 */
bool mongocrypt_setopt_fle2v2(mongocrypt_t *crypt, bool enable);

#endif /* MONGOCRYPT_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-status-private.h0000644000175100001660000000230114760300420021742 0ustar  /*
 * Copyright 2018-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_STATUS_PRIVATE_H
#define MONGOCRYPT_STATUS_PRIVATE_H

#include "mongocrypt.h"

void _mongocrypt_status_copy_to(mongocrypt_status_t *src, mongocrypt_status_t *dst);

void _mongocrypt_status_reset(mongocrypt_status_t *status);

/* Append the message of @to_append in @status.
 * Example:
 * - @status has the message "status error"
 * - @to_append has the message "append error"
 * After calling, @status will have the message: "status error: append error"
 */
void _mongocrypt_status_append(mongocrypt_status_t *status, mongocrypt_status_t *to_append);

#endif /* MONGOCRYPT_STATUS_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-status.c0000644000175100001660000000716514760300420020302 0ustar  /*
 * Copyright 2018-present MongoDB, 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.
 */

#include 

#include "mongocrypt-status-private.h"

struct _mongocrypt_status_t {
    mongocrypt_status_type_t type;
    uint32_t code;
    char *message;
    uint32_t len;
};

mongocrypt_status_t *mongocrypt_status_new(void) {
    return bson_malloc0(sizeof(mongocrypt_status_t));
}

void mongocrypt_status_set(mongocrypt_status_t *status,
                           mongocrypt_status_type_t type,
                           uint32_t code,
                           const char *message,
                           int32_t message_len) {
    if (!status) {
        return;
    }

    if (message_len < 0) {
        message_len = (int32_t)strlen(message) + 1;
    } else if (message_len == 0) {
        /* This is really an error, since message_len should be one more than the
         * string length. But interpret as the empty string */
        message_len = 1;
    }

    bson_free(status->message);
    status->message = bson_malloc((size_t)message_len);
    BSON_ASSERT(status->message);
    status->message[message_len - 1] = '\0';
    memcpy(status->message, message, (size_t)message_len - 1);
    status->len = (uint32_t)message_len - 1;
    status->type = type;
    status->code = code;
}

const char *mongocrypt_status_message(mongocrypt_status_t *status, uint32_t *len) {
    BSON_ASSERT_PARAM(status);

    if (mongocrypt_status_ok(status)) {
        return NULL;
    }
    if (len) {
        *len = status->len;
    }
    return status->message;
}

uint32_t mongocrypt_status_code(mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(status);

    return status->code;
}

mongocrypt_status_type_t mongocrypt_status_type(mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(status);

    return status->type;
}

bool mongocrypt_status_ok(mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(status);

    return (status->type == MONGOCRYPT_STATUS_OK);
}

void _mongocrypt_status_copy_to(mongocrypt_status_t *src, mongocrypt_status_t *dst) {
    BSON_ASSERT_PARAM(dst);
    BSON_ASSERT_PARAM(src);

    if (dst == src) {
        return;
    }

    dst->type = src->type;
    dst->code = src->code;
    dst->len = src->len;
    if (dst->message) {
        bson_free(dst->message);
        dst->message = NULL;
    }

    if (src->message) {
        dst->message = bson_strdup(src->message);
    }
}

void _mongocrypt_status_reset(mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(status);

    status->type = MONGOCRYPT_STATUS_OK;
    status->code = 0;
    status->len = 0;
    bson_free(status->message);
    status->message = NULL;
}

void mongocrypt_status_destroy(mongocrypt_status_t *status) {
    if (!status) {
        return;
    }

    bson_free(status->message);
    bson_free(status);
}

void _mongocrypt_status_append(mongocrypt_status_t *status, mongocrypt_status_t *to_append) {
    char *orig;

    BSON_ASSERT_PARAM(status);
    BSON_ASSERT_PARAM(to_append);

    orig = status->message;

    if (mongocrypt_status_ok(to_append)) {
        return;
    }
    status->message = bson_strdup_printf("%s: %s", orig, to_append->message);
    bson_free(orig);
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-traverse-util-private.h0000644000175100001660000000405514760300420023235 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_TRAVERSE_UTIL_H
#define MONGOCRYPT_TRAVERSE_UTIL_H

#include "mongocrypt-buffer-private.h"
#include "mongocrypt-status-private.h"

typedef enum {
    TRAVERSE_MATCH_CIPHERTEXT,
    TRAVERSE_MATCH_MARKING,
    TRAVERSE_MATCH_SUBTYPE6,
} traversal_match_t;

typedef bool (*_mongocrypt_traverse_callback_t)(void *ctx, _mongocrypt_buffer_t *in, mongocrypt_status_t *status);

typedef bool (*_mongocrypt_transform_callback_t)(void *ctx,
                                                 _mongocrypt_buffer_t *in,
                                                 bson_value_t *out,
                                                 mongocrypt_status_t *status);

bool _mongocrypt_traverse_binary_in_bson(_mongocrypt_traverse_callback_t cb,
                                         void *ctx,
                                         traversal_match_t match,
                                         bson_iter_t *iter,
                                         mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

bool _mongocrypt_transform_binary_in_bson(_mongocrypt_transform_callback_t cb,
                                          void *ctx,
                                          traversal_match_t match,
                                          bson_iter_t *iter,
                                          bson_t *out,
                                          mongocrypt_status_t *status) MONGOCRYPT_WARN_UNUSED_RESULT;

#endif /* MONGOCRYPT_TRAVERSE_UTIL_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-traverse-util.c0000644000175100001660000001650014760300420021556 0ustar  /*
 * Copyright 2018-present MongoDB, 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.
 */

#include 

#include "mc-fle-blob-subtype-private.h"
#include "mongocrypt-buffer-private.h"
#include "mongocrypt-log-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt-status-private.h"
#include "mongocrypt-traverse-util-private.h"

typedef struct {
    void *ctx;
    bson_iter_t iter;
    bson_t *copy; /* implies transform */
    char *path;   /* only enabled during tracing. */
    _mongocrypt_traverse_callback_t traverse_cb;
    _mongocrypt_transform_callback_t transform_cb;
    mongocrypt_status_t *status;
    traversal_match_t match;
    bson_t child;
} _recurse_state_t;

static bool _check_first_byte(uint8_t byte, traversal_match_t match) {
    switch (match) {
    case TRAVERSE_MATCH_MARKING:
        return byte == MC_SUBTYPE_FLE1EncryptionPlaceholder || byte == MC_SUBTYPE_FLE2EncryptionPlaceholder;
    case TRAVERSE_MATCH_CIPHERTEXT:
        return byte == MC_SUBTYPE_FLE1DeterministicEncryptedValue || byte == MC_SUBTYPE_FLE1RandomEncryptedValue
            || byte == MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue || byte == MC_SUBTYPE_FLE2UnindexedEncryptedValue
            || byte == MC_SUBTYPE_FLE2InsertUpdatePayload || byte == MC_SUBTYPE_FLE2IndexedRangeEncryptedValue
            || byte == MC_SUBTYPE_FLE2InsertUpdatePayloadV2 || byte == MC_SUBTYPE_FLE2UnindexedEncryptedValueV2
            || byte == MC_SUBTYPE_FLE2IndexedEqualityEncryptedValueV2
            || byte == MC_SUBTYPE_FLE2IndexedRangeEncryptedValueV2;
    case TRAVERSE_MATCH_SUBTYPE6: return true;
    default: break;
    }
    return false;
}

static bool _recurse(_recurse_state_t *state) {
    mongocrypt_status_t *status;

    BSON_ASSERT_PARAM(state);

    status = state->status;
    while (bson_iter_next(&state->iter)) {
        if (BSON_ITER_HOLDS_BINARY(&state->iter)) {
            _mongocrypt_buffer_t value;

            BSON_ASSERT(_mongocrypt_buffer_from_binary_iter(&value, &state->iter));

            if (value.subtype == BSON_SUBTYPE_ENCRYPTED && value.len > 0
                && _check_first_byte(value.data[0], state->match)) {
                bool ret;
                /* call the right callback. */
                if (state->copy) {
                    bson_value_t value_out;
                    ret = state->transform_cb(state->ctx, &value, &value_out, status);
                    if (ret) {
                        const uint32_t key_len = bson_iter_key_len(&state->iter);
                        BSON_ASSERT(key_len <= INT_MAX);
                        bson_append_value(state->copy, bson_iter_key(&state->iter), (int)key_len, &value_out);
                        bson_value_destroy(&value_out);
                    }
                } else {
                    ret = state->traverse_cb(state->ctx, &value, status);
                }

                if (!ret) {
                    return false;
                }
                continue;
            }
            /* fall through and copy */
        }

        if (BSON_ITER_HOLDS_ARRAY(&state->iter)) {
            _recurse_state_t child_state;
            bool ret;

            memcpy(&child_state, state, sizeof(_recurse_state_t));
            if (!bson_iter_recurse(&state->iter, &child_state.iter)) {
                CLIENT_ERR("error recursing into array");
                return false;
            }

            if (state->copy) {
                const uint32_t key_len = bson_iter_key_len(&state->iter);
                BSON_ASSERT(key_len <= INT_MAX);
                bson_append_array_begin(state->copy, bson_iter_key(&state->iter), (int)key_len, &state->child);
                child_state.copy = &state->child;
            }
            ret = _recurse(&child_state);

            if (state->copy) {
                bson_append_array_end(state->copy, &state->child);
            }
            if (!ret) {
                return false;
            }
            continue;
        }

        if (BSON_ITER_HOLDS_DOCUMENT(&state->iter)) {
            _recurse_state_t child_state;
            bool ret;

            memcpy(&child_state, state, sizeof(_recurse_state_t));
            if (!bson_iter_recurse(&state->iter, &child_state.iter)) {
                CLIENT_ERR("error recursing into document");
                return false;
            }
            /* TODO: check for errors everywhere. */
            if (state->copy) {
                const uint32_t key_len = bson_iter_key_len(&state->iter);
                BSON_ASSERT(key_len <= INT_MAX);
                bson_append_document_begin(state->copy, bson_iter_key(&state->iter), (int)key_len, &state->child);
                child_state.copy = &state->child;
            }

            ret = _recurse(&child_state);

            if (state->copy) {
                if (!bson_append_document_end(state->copy, &state->child)) {
                    CLIENT_ERR("error appending document");
                    return false;
                }
            }

            if (!ret) {
                return false;
            }
            continue;
        }

        if (state->copy) {
            const uint32_t key_len = bson_iter_key_len(&state->iter);
            BSON_ASSERT(key_len <= INT_MAX);
            bson_append_value(state->copy, bson_iter_key(&state->iter), (int)key_len, bson_iter_value(&state->iter));
        }
    }
    return true;
}

bool _mongocrypt_transform_binary_in_bson(_mongocrypt_transform_callback_t cb,
                                          void *ctx,
                                          traversal_match_t match,
                                          bson_iter_t *iter,
                                          bson_t *out,
                                          mongocrypt_status_t *status) {
    _recurse_state_t starting_state =
        {ctx, *iter, out /* copy */, NULL /* path */, NULL /* traverse callback */, cb, status, match, {0}};

    return _recurse(&starting_state);
}

/*-----------------------------------------------------------------------------
 *
 * _mongocrypt_traverse_binary_in_bson
 *
 *    Traverse the BSON being iterated with iter, and call cb for every binary
 *    subtype 06 (BSON_SUBTYPE_ENCRYPTED) value where the first byte corresponds
 *    to 'match'.
 *
 * Return:
 *    True on success. Returns false on failure and sets error.
 *
 *-----------------------------------------------------------------------------
 */
bool _mongocrypt_traverse_binary_in_bson(_mongocrypt_traverse_callback_t cb,
                                         void *ctx,
                                         traversal_match_t match,
                                         bson_iter_t *iter,
                                         mongocrypt_status_t *status) {
    _recurse_state_t starting_state =
        {ctx, *iter, NULL /* copy */, NULL /* path */, cb, NULL /* transform callback */, status, match, {0}};

    return _recurse(&starting_state);
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-util-private.h0000644000175100001660000000465014760300420021405 0ustar  /*
 * Copyright 2021-present MongoDB, 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.
 */

#ifndef MONGOCRYPT_UTIL_PRIVATE_H
#define MONGOCRYPT_UTIL_PRIVATE_H

#include "mongocrypt-status-private.h"

#include "mlib/str.h"

#include 

#include 
#include 
#include 

/* A utility for safely casting from size_t to uint32_t.
 * Returns false if @in exceeds the maximum value of a uint32_t. */
bool size_to_uint32(size_t in, uint32_t *out);

/**
 * @brief The result type of mpath_current_exe_path()
 *
 * The @ref current_module_result::path member must be freed with mstr_free()
 */
typedef struct current_module_result {
    /// The resulting executable path
    mstr path;
    /// An error, if the path could not be obtained
    int error;
} current_module_result;

/**
 * @brief Obtain the path to the calling executable module
 *
 * If this function is contained in a dynamic library, this will return the path
 * to that library file, otherwise it will return the path to the running
 * executable.
 *
 * @return current_module_result A result object of the operation. Check the
 * `.error` member for non-zero. The `.path` member must be freed with
 * mtsr_free()
 */
current_module_result current_module_path(void);

/* mc_bson_type_to_string returns the string representation of a BSON type. */
const char *mc_bson_type_to_string(bson_type_t bson_type);

/* mc_iter_document_as_bson attempts to read the document from @iter into
 * @bson. */
bool mc_iter_document_as_bson(const bson_iter_t *iter, bson_t *bson, mongocrypt_status_t *status);

// mc_isnan is a wrapper around isnan. It avoids a conversion warning on glibc.
bool mc_isnan(double d);
// mc_isinf is a wrapper around isinf. It avoids a conversion warning on glibc.
bool mc_isinf(double d);
// mc_isfinite is a wrapper around isfinite. It avoids a conversion warning on
// glibc.
bool mc_isfinite(double d);

#endif /* MONGOCRYPT_UTIL_PRIVATE_H */
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt-util.c0000644000175100001660000001162714760300420017732 0ustar  /*
 * Copyright 2021-present MongoDB, 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.
 */

// Turn on libc extensions so that we can use dladdr() on Unix-like systems
#if defined(__has_include) && !(defined(_GNU_SOURCE) || defined(_DARWIN_C_SOURCE))
#if __has_include()
// We're using a glibc-compatible library
#define _GNU_SOURCE
#elif __has_include()
// We're on Apple/Darwin
#define _DARWIN_C_SOURCE
#endif
#else // No __has_include
#if __GNUC__ < 5
// Best guess on older GCC is that we are using glibc
#define _GNU_SOURCE
#endif
#endif

#include "mc-check-conversions-private.h"
#include "mongocrypt-private.h" // CLIENT_ERR
#include "mongocrypt-util-private.h"

#include "mlib/thread.h"

#include 
#include  // isinf, isnan, isfinite

#ifdef _WIN32
#include 
#else
#include 
#endif

bool size_to_uint32(size_t in, uint32_t *out) {
    BSON_ASSERT_PARAM(out);

    if (in > UINT32_MAX) {
        return false;
    }
    *out = (uint32_t)in;
    return true;
}

current_module_result current_module_path(void) {
    mstr ret_str = MSTR_NULL;
    int ret_error = 0;
#ifdef _WIN32
    DWORD acc_size = 512;
    while (!ret_str.data && !ret_error) {
        // Loop until we allocate a large enough buffer or get an error
        wchar_t *path = calloc(acc_size + 1, sizeof(wchar_t));
        SetLastError(0);
        GetModuleFileNameW(NULL, path, acc_size);
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
            // Try again with more buffer
            acc_size *= 2;
        } else if (GetLastError() != 0) {
            ret_error = GetLastError();
        } else {
            mstr_narrow_result narrow = mstr_win32_narrow(path);
            // GetModuleFileNameW should never return invalid Unicode:
            assert(narrow.error == 0);
            ret_str = narrow.string;
        }
        free(path);
    }
#elif defined(_GNU_SOURCE) || defined(_DARWIN_C_SOURCE) || defined(__FreeBSD__)
    // Darwin/BSD/glibc define extensions for finding dynamic library info from
    // the address of a symbol.
    Dl_info info = {0};
    int rc = dladdr((const void *)current_module_path, &info);
    if (rc == 0) {
        // Failed to resolve the symbol
        ret_error = ENOENT;
    } else {
        ret_str = mstr_copy_cstr(info.dli_fname);
    }
#else
    // Not supported on this system.
    ret_error = ENOSYS;
#endif
    return (current_module_result){.path = ret_str, .error = ret_error};
}

const char *mc_bson_type_to_string(bson_type_t t) {
    switch (t) {
    case BSON_TYPE_EOD: return "EOD";
    case BSON_TYPE_DOUBLE: return "DOUBLE";
    case BSON_TYPE_UTF8: return "UTF8";
    case BSON_TYPE_DOCUMENT: return "DOCUMENT";
    case BSON_TYPE_ARRAY: return "ARRAY";
    case BSON_TYPE_BINARY: return "BINARY";
    case BSON_TYPE_UNDEFINED: return "UNDEFINED";
    case BSON_TYPE_OID: return "OID";
    case BSON_TYPE_BOOL: return "BOOL";
    case BSON_TYPE_DATE_TIME: return "DATE_TIME";
    case BSON_TYPE_NULL: return "NULL";
    case BSON_TYPE_REGEX: return "REGEX";
    case BSON_TYPE_DBPOINTER: return "DBPOINTER";
    case BSON_TYPE_CODE: return "CODE";
    case BSON_TYPE_SYMBOL: return "SYMBOL";
    case BSON_TYPE_CODEWSCOPE: return "CODEWSCOPE";
    case BSON_TYPE_INT32: return "INT32";
    case BSON_TYPE_TIMESTAMP: return "TIMESTAMP";
    case BSON_TYPE_INT64: return "INT64";
    case BSON_TYPE_MAXKEY: return "MAXKEY";
    case BSON_TYPE_MINKEY: return "MINKEY";
    case BSON_TYPE_DECIMAL128: return "DECIMAL128";
    default: return "Unknown";
    }
}

bool mc_iter_document_as_bson(const bson_iter_t *iter, bson_t *bson, mongocrypt_status_t *status) {
    BSON_ASSERT_PARAM(iter);
    BSON_ASSERT_PARAM(bson);
    BSON_ASSERT(status || true);

    uint32_t len;
    const uint8_t *data;

    if (!BSON_ITER_HOLDS_DOCUMENT(iter)) {
        CLIENT_ERR("expected BSON document for field: %s", bson_iter_key(iter));
        return false;
    }

    bson_iter_document(iter, &len, &data);
    if (!bson_init_static(bson, data, len)) {
        CLIENT_ERR("unable to initialize BSON document from field: %s", bson_iter_key(iter));
        return false;
    }

    return true;
}

/* Avoid a conversion warning on glibc for isnan, isinf, and isfinite. Refer:
 * MONGOCRYPT-501. */
MC_BEGIN_CONVERSION_IGNORE

bool mc_isnan(double d) {
    return isnan(d);
}

bool mc_isinf(double d) {
    return isinf(d);
}

bool mc_isfinite(double d) {
    return isfinite(d);
}

MC_END_CONVERSION_IGNORE
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt.c0000644000175100001660000012515114760300420016755 0ustar  /*
 * Copyright 2018-present MongoDB, 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.
 */

#include "mongocrypt.h"
#include "mlib/error.h"
#include "mlib/path.h"
#include "mlib/thread.h"

#include 
#include 

#include "mongocrypt-binary-private.h"
#include "mongocrypt-cache-collinfo-private.h"
#include "mongocrypt-cache-key-private.h"
#include "mongocrypt-cache-private.h"
#include "mongocrypt-config.h"
#include "mongocrypt-crypto-private.h"
#include "mongocrypt-log-private.h"
#include "mongocrypt-mutex-private.h"
#include "mongocrypt-opts-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt-status-private.h"
#include "mongocrypt-util-private.h"

/* Assert size for interop with wrapper purposes */
BSON_STATIC_ASSERT(sizeof(mongocrypt_log_level_t) == 4);

const char *mongocrypt_version(uint32_t *len) {
    if (len) {
        *len = (uint32_t)strlen(MONGOCRYPT_VERSION);
    }
    return MONGOCRYPT_VERSION;
}

void _mongocrypt_set_error(mongocrypt_status_t *status,
                           mongocrypt_status_type_t type,
                           uint32_t code,
                           const char *format,
                           ...) {
    va_list args;
    char *prepared_message;

    if (status) {
        va_start(args, format);
        prepared_message = bson_strdupv_printf(format, args);
        if (!prepared_message) {
            mongocrypt_status_set(status, type, code, "Out of memory", -1);
        } else {
            mongocrypt_status_set(status, type, code, prepared_message, -1);
            bson_free(prepared_message);
        }
        va_end(args);
    }
}

const char *tmp_json(const bson_t *bson) {
    static char storage[1024];
    char *json;

    BSON_ASSERT_PARAM(bson);

    memset(storage, 0, 1024);
    json = bson_as_canonical_extended_json(bson, NULL);
    bson_snprintf(storage, sizeof(storage), "%s", json);
    bson_free(json);
    return (const char *)storage;
}

const char *tmp_buf(const _mongocrypt_buffer_t *buf) {
    static char storage[1024];
    size_t i, n;

    BSON_ASSERT_PARAM(buf);

    memset(storage, 0, 1024);
    /* capped at two characters per byte, minus 1 for trailing \0 */
    n = sizeof(storage) / 2 - 1;
    if (buf->len < n) {
        n = buf->len;
    }

    for (i = 0; i < n; i++) {
        bson_snprintf(storage + (i * 2), 3, "%02x", buf->data[i]);
    }

    return (const char *)storage;
}

static void _mongocrypt_do_init(void) {
    (void)kms_message_init();
    _native_crypto_init();
}

mongocrypt_t *mongocrypt_new(void) {
    mongocrypt_t *crypt;

    crypt = bson_malloc0(sizeof(mongocrypt_t));
    BSON_ASSERT(crypt);
    crypt->crypto = bson_malloc0(sizeof(*crypt->crypto));
    BSON_ASSERT(crypt->crypto);

    _mongocrypt_mutex_init(&crypt->mutex);
    _mongocrypt_cache_collinfo_init(&crypt->cache_collinfo);
    _mongocrypt_cache_key_init(&crypt->cache_key);
    crypt->status = mongocrypt_status_new();
    _mongocrypt_opts_init(&crypt->opts);
    _mongocrypt_log_init(&crypt->log);
    // Default to using FLEv2 (aka QEv2)
    crypt->opts.use_fle2_v2 = true;
    crypt->ctx_counter = 1;
    crypt->cache_oauth = mc_mapof_kmsid_to_token_new();
    crypt->csfle = (_mongo_crypt_v1_vtable){.okay = false};

    static mlib_once_flag init_flag = MLIB_ONCE_INITIALIZER;

    if (!mlib_call_once(&init_flag, _mongocrypt_do_init) || !_native_crypto_initialized) {
        mongocrypt_status_t *status = crypt->status;

        CLIENT_ERR("failed to initialize");
        /* Return crypt with failure status so caller can obtain error when
         * calling mongocrypt_init */
    }

    return crypt;
}

#define ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt)                                                                          \
    {                                                                                                                  \
        const mongocrypt_t *_crypt = (crypt);                                                                          \
        BSON_ASSERT_PARAM(_crypt);                                                                                     \
        if (_crypt->initialized) {                                                                                     \
            mongocrypt_status_t *status = _crypt->status;                                                              \
            CLIENT_ERR("options cannot be set after initialization");                                                  \
            return false;                                                                                              \
        }                                                                                                              \
    }

bool mongocrypt_setopt_fle2v2(mongocrypt_t *crypt, bool enable) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    crypt->opts.use_fle2_v2 = enable;
    return true;
}

bool mongocrypt_setopt_use_range_v2(mongocrypt_t *crypt) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    // Nothing to do. As of MONGOCRYPT-661, rangeV2 is the default.
    return true;
}

bool mongocrypt_setopt_log_handler(mongocrypt_t *crypt, mongocrypt_log_fn_t log_fn, void *log_ctx) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);
    crypt->opts.log_fn = log_fn;
    crypt->opts.log_ctx = log_ctx;
    return true;
}

bool mongocrypt_setopt_retry_kms(mongocrypt_t *crypt, bool enable) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);
    crypt->retry_enabled = enable;
    return true;
}

bool mongocrypt_setopt_kms_provider_aws(mongocrypt_t *crypt,
                                        const char *aws_access_key_id,
                                        int32_t aws_access_key_id_len,
                                        const char *aws_secret_access_key,
                                        int32_t aws_secret_access_key_len) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    mongocrypt_status_t *status = crypt->status;
    _mongocrypt_opts_kms_providers_t *const kms_providers = &crypt->opts.kms_providers;

    if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_AWS)) {
        CLIENT_ERR("aws kms provider already set");
        return false;
    }

    if (!_mongocrypt_validate_and_copy_string(aws_access_key_id,
                                              aws_access_key_id_len,
                                              &kms_providers->aws_mut.access_key_id)) {
        CLIENT_ERR("invalid aws access key id");
        return false;
    }

    if (!_mongocrypt_validate_and_copy_string(aws_secret_access_key,
                                              aws_secret_access_key_len,
                                              &kms_providers->aws_mut.secret_access_key)) {
        CLIENT_ERR("invalid aws secret access key");
        return false;
    }

    if (crypt->log.trace_enabled) {
        _mongocrypt_log(&crypt->log,
                        MONGOCRYPT_LOG_LEVEL_TRACE,
                        "%s (%s=\"%s\", %s=%d, %s=\"%s\", %s=%d)",
                        BSON_FUNC,
                        "aws_access_key_id",
                        kms_providers->aws_mut.access_key_id,
                        "aws_access_key_id_len",
                        aws_access_key_id_len,
                        "aws_secret_access_key",
                        kms_providers->aws_mut.secret_access_key,
                        "aws_secret_access_key_len",
                        aws_secret_access_key_len);
    }
    kms_providers->configured_providers |= MONGOCRYPT_KMS_PROVIDER_AWS;
    return true;
}

bool mongocrypt_setopt_key_expiration(mongocrypt_t *crypt, uint64_t cache_expiration_ms) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);
    if (cache_expiration_ms > INT64_MAX) {
        mongocrypt_status_t *status = crypt->status;
        CLIENT_ERR("expiration time must be less than %" PRId64 ", but got %" PRIu64, INT64_MAX, cache_expiration_ms);
        return false;
    }
    crypt->cache_key.expiration = cache_expiration_ms;
    return true;
}

char *_mongocrypt_new_string_from_bytes(const void *in, int len) {
    const int max_bytes = 100;
    const int chars_per_byte = 2;
    int out_size = max_bytes * chars_per_byte;
    const unsigned char *src = in;
    char *out;
    char *ret;

    out_size += len > max_bytes ? (int)sizeof("...") : 1 /* for null */;
    out = bson_malloc0((size_t)out_size);
    BSON_ASSERT(out);

    ret = out;

    for (int i = 0; i < len && i < max_bytes; i++, out += chars_per_byte) {
        sprintf(out, "%02X", src[i]);
    }

    sprintf(out, (len > max_bytes) ? "..." : "");
    return ret;
}

char *_mongocrypt_new_json_string_from_binary(mongocrypt_binary_t *binary) {
    bson_t bson;
    uint32_t len;

    BSON_ASSERT_PARAM(binary);

    if (!_mongocrypt_binary_to_bson(binary, &bson) || !bson_validate(&bson, BSON_VALIDATE_NONE, NULL)) {
        char *hex;
        char *full_str;

        BSON_ASSERT(binary->len <= (uint32_t)INT_MAX);
        hex = _mongocrypt_new_string_from_bytes(binary->data, (int)binary->len);
        full_str = bson_strdup_printf("(malformed) %s", hex);
        bson_free(hex);
        return full_str;
    }
    return bson_as_canonical_extended_json(&bson, (size_t *)&len);
}

bool mongocrypt_setopt_schema_map(mongocrypt_t *crypt, mongocrypt_binary_t *schema_map) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    bson_t tmp;
    bson_error_t bson_err;
    mongocrypt_status_t *status = crypt->status;

    if (!schema_map || !mongocrypt_binary_data(schema_map)) {
        CLIENT_ERR("passed null schema map");
        return false;
    }

    if (!_mongocrypt_buffer_empty(&crypt->opts.schema_map)) {
        CLIENT_ERR("already set schema map");
        return false;
    }

    _mongocrypt_buffer_copy_from_binary(&crypt->opts.schema_map, schema_map);

    /* validate bson */
    if (!_mongocrypt_buffer_to_bson(&crypt->opts.schema_map, &tmp)) {
        CLIENT_ERR("invalid bson");
        return false;
    }

    if (!bson_validate_with_error(&tmp, BSON_VALIDATE_NONE, &bson_err)) {
        CLIENT_ERR("%s", bson_err.message);
        return false;
    }

    return true;
}

bool mongocrypt_setopt_encrypted_field_config_map(mongocrypt_t *crypt, mongocrypt_binary_t *efc_map) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    mongocrypt_status_t *status = crypt->status;
    bson_t as_bson;
    bson_error_t bson_err;

    if (!efc_map || !mongocrypt_binary_data(efc_map)) {
        CLIENT_ERR("passed null encrypted_field_config_map");
        return false;
    }

    if (!_mongocrypt_buffer_empty(&crypt->opts.encrypted_field_config_map)) {
        CLIENT_ERR("already set encrypted_field_config_map");
        return false;
    }

    _mongocrypt_buffer_copy_from_binary(&crypt->opts.encrypted_field_config_map, efc_map);

    /* validate bson */
    if (!_mongocrypt_buffer_to_bson(&crypt->opts.encrypted_field_config_map, &as_bson)) {
        CLIENT_ERR("invalid bson");
        return false;
    }

    if (!bson_validate_with_error(&as_bson, BSON_VALIDATE_NONE, &bson_err)) {
        CLIENT_ERR("%s", bson_err.message);
        return false;
    }

    return true;
}

bool mongocrypt_setopt_kms_provider_local(mongocrypt_t *crypt, mongocrypt_binary_t *key) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    mongocrypt_status_t *status = crypt->status;
    _mongocrypt_opts_kms_providers_t *const kms_providers = &crypt->opts.kms_providers;

    if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_LOCAL)) {
        CLIENT_ERR("local kms provider already set");
        return false;
    }

    if (!key) {
        CLIENT_ERR("passed null key");
        return false;
    }

    if (mongocrypt_binary_len(key) != MONGOCRYPT_KEY_LEN) {
        CLIENT_ERR("local key must be %d bytes", MONGOCRYPT_KEY_LEN);
        return false;
    }

    if (crypt->log.trace_enabled) {
        char *key_val;
        BSON_ASSERT(key->len <= (uint32_t)INT_MAX);
        key_val = _mongocrypt_new_string_from_bytes(key->data, (int)key->len);

        _mongocrypt_log(&crypt->log, MONGOCRYPT_LOG_LEVEL_TRACE, "%s (%s=\"%s\")", BSON_FUNC, "key", key_val);
        bson_free(key_val);
    }

    _mongocrypt_buffer_copy_from_binary(&kms_providers->local_mut.key, key);
    kms_providers->configured_providers |= MONGOCRYPT_KMS_PROVIDER_LOCAL;
    return true;
}

typedef struct {
    /// Whether the load is successful
    bool okay;
    /// The DLL handle to the opened library.
    mcr_dll lib;
    /// A vtable for the functions in the DLL
    _mongo_crypt_v1_vtable vtable;
} _loaded_csfle;

/**
 * @brief Attempt to open the CSFLE dynamic library and initialize a vtable for
 * it.
 *
 * @param status is an optional status to set an error message if `mcr_dll_open` fails.
 */
static _loaded_csfle _try_load_csfle(const char *filepath, mongocrypt_status_t *status, _mongocrypt_log_t *log) {
    // Try to open the dynamic lib
    mcr_dll lib = mcr_dll_open(filepath);
    // Check for errors, which are represented by strings
    if (lib.error_string.data) {
        // Error opening candidate
        _mongocrypt_log(log,
                        MONGOCRYPT_LOG_LEVEL_WARNING,
                        "Error while opening candidate for CSFLE dynamic library [%s]: %s",
                        filepath,
                        lib.error_string.data);
        CLIENT_ERR("Error while opening candidate for CSFLE dynamic library [%s]: %s", filepath, lib.error_string.data);
        // Free resources, which will include the error string
        mcr_dll_close(lib);
        // Bad:
        return (_loaded_csfle){.okay = false};
    }

    // Successfully opened DLL
    _mongocrypt_log(log, MONGOCRYPT_LOG_LEVEL_TRACE, "Loading CSFLE dynamic library [%s]", filepath);

    // Construct the library vtable
    _mongo_crypt_v1_vtable vtable = {.okay = true};
#define X_FUNC(Name, RetType, ...)                                                                                     \
    {                                                                                                                  \
        /* Symbol names are qualified by the lib name and version: */                                                  \
        const char *symname = "mongo_crypt_v1_" #Name;                                                                 \
        vtable.Name = mcr_dll_sym(lib, symname);                                                                       \
        if (vtable.Name == NULL) {                                                                                     \
            /* The requested symbol is not present */                                                                  \
            _mongocrypt_log(log,                                                                                       \
                            MONGOCRYPT_LOG_LEVEL_ERROR,                                                                \
                            "Missing required symbol '%s' from CSFLE dynamic library [%s]",                            \
                            symname,                                                                                   \
                            filepath);                                                                                 \
            /* Mark the vtable as broken, but keep trying to load more symbols to                                      \
             * produce error messages for all missing symbols */                                                       \
            vtable.okay = false;                                                                                       \
        }                                                                                                              \
    }
    MONGOC_CSFLE_FUNCTIONS_X
#undef X_FUNC

    if (!vtable.okay) {
        mcr_dll_close(lib);
        _mongocrypt_log(log,
                        MONGOCRYPT_LOG_LEVEL_ERROR,
                        "One or more required symbols are missing from CSFLE dynamic library "
                        "[%s], so this dynamic library will not be used.",
                        filepath);
        return (_loaded_csfle){.okay = false};
    }

    // Success!
    _mongocrypt_log(log, MONGOCRYPT_LOG_LEVEL_INFO, "Opened CSFLE dynamic library [%s]", filepath);
    return (_loaded_csfle){.okay = true, .lib = lib, .vtable = vtable};
}

/**
 * @brief If the leading path element in `filepath` is $ORIGIN, replace that
 * with the directory containing the current executing module.
 *
 * @return true If no error occurred and the path is valid
 * @return false If there was an error and `filepath` cannot be processed
 */
static bool _try_replace_dollar_origin(mstr *filepath, _mongocrypt_log_t *log) {
    const mstr_view dollar_origin = mstrv_lit("$ORIGIN");

    BSON_ASSERT_PARAM(filepath);

    if (!mstr_starts_with(filepath->view, dollar_origin)) {
        // Nothing to replace
        return true;
    }
    // Check that the next char is a path separator or end-of-string:
    char peek = filepath->data[dollar_origin.len];
    if (peek != 0 && !mpath_is_sep(peek, MPATH_NATIVE)) {
        // Not a single path element
        return true;
    }
    // Replace $ORIGIN with the directory of the current module
    const current_module_result self_exe_r = current_module_path();
    if (self_exe_r.error) {
        // Failed to get the current module to load replace $ORIGIN
        mstr error = merror_system_error_string(self_exe_r.error);
        _mongocrypt_log(log,
                        MONGOCRYPT_LOG_LEVEL_WARNING,
                        "Error while loading the executable module path for "
                        "substitution of $ORIGIN in CSFLE search path [%s]: %s",
                        filepath->data,
                        error.data);
        mstr_free(error);
        return false;
    }
    const mstr_view self_dir = mpath_parent(self_exe_r.path.view, MPATH_NATIVE);
    mstr_inplace_splice(filepath, 0, dollar_origin.len, self_dir);
    mstr_free(self_exe_r.path);
    return true;
}

static _loaded_csfle _try_find_csfle(mongocrypt_t *crypt) {
    _loaded_csfle candidate_csfle = {0};
    mstr csfle_cand_filepath = MSTR_NULL;

    BSON_ASSERT_PARAM(crypt);

    if (crypt->opts.crypt_shared_lib_override_path.data) {
        // If an override path was specified, skip the library searching behavior
        csfle_cand_filepath = mstr_copy(crypt->opts.crypt_shared_lib_override_path.view);
        if (_try_replace_dollar_origin(&csfle_cand_filepath, &crypt->log)) {
            // Succesfully substituted $ORIGIN
            // Do not allow a plain filename to go through, as that will cause the
            // DLL load to search the system.
            mstr_assign(&csfle_cand_filepath, mpath_absolute(csfle_cand_filepath.view, MPATH_NATIVE));
            candidate_csfle = _try_load_csfle(csfle_cand_filepath.data, crypt->status, &crypt->log);
        }
    } else {
        // No override path was specified, so try to find it on the provided
        // search paths.
        for (int i = 0; i < crypt->opts.n_crypt_shared_lib_search_paths; ++i) {
            mstr_view cand_dir = crypt->opts.crypt_shared_lib_search_paths[i].view;
            mstr_view csfle_filename = mstrv_lit("mongo_crypt_v1" MCR_DLL_SUFFIX);
            if (mstr_eq(cand_dir, mstrv_lit("$SYSTEM"))) {
                // Caller wants us to search for the library on the system's default
                // library paths. Pass only the library's filename to cause dll_open
                // to search on the library paths.
                mstr_assign(&csfle_cand_filepath, mstr_copy(csfle_filename));
            } else {
                // Compose the candidate filepath:
                mstr_assign(&csfle_cand_filepath, mpath_join(cand_dir, csfle_filename, MPATH_NATIVE));
                if (!_try_replace_dollar_origin(&csfle_cand_filepath, &crypt->log)) {
                    // Error while substituting $ORIGIN
                    continue;
                }
            }
            // Try to load the file:
            candidate_csfle = _try_load_csfle(csfle_cand_filepath.data, NULL /* status */, &crypt->log);
            if (candidate_csfle.okay) {
                // Stop searching:
                break;
            }
        }
    }

    mstr_free(csfle_cand_filepath);
    return candidate_csfle;
}

/// Global state for the application's csfle library
typedef struct csfle_global_lib_state {
    /// Synchronization around the reference count:
    mongocrypt_mutex_t mtx;
    int refcount;
    /// The open library handle:
    mcr_dll dll;
    /// vtable for the APIs:
    _mongo_crypt_v1_vtable vtable;
    /// The global library state managed by the csfle library:
    mongo_crypt_v1_lib *csfle_lib;
} csfle_global_lib_state;

csfle_global_lib_state g_csfle_state;

static void init_csfle_state(void) {
    _mongocrypt_mutex_init(&g_csfle_state.mtx);
}

mlib_once_flag g_csfle_init_flag = MLIB_ONCE_INITIALIZER;

/**
 * @brief Verify that `found` refers to the same library that is globally loaded
 * for the application.
 *
 * @param crypt The requesting mongocrypt_t. Error information may be set
 * through here.
 * @param found The result of _try_load_csfle()
 * @return true If `found` matches the global state
 * @return false Otherwise
 *
 * @note This function assumes that the global csfle state is valid and will not
 * be destroyed by any other thread. (One must hold the reference count >= 1)
 */
static bool _validate_csfle_singleton(mongocrypt_t *crypt, _loaded_csfle found) {
    mongocrypt_status_t *status;

    BSON_ASSERT_PARAM(crypt);

    if (!mcr_dll_path_supported()) {
        _mongocrypt_log(&crypt->log,
                        MONGOCRYPT_LOG_LEVEL_WARNING,
                        "Cannot get path of loaded library on this platform. Skipping validation to ensure "
                        "exactly one csfle library is loaded.");
        return true;
    }

    status = crypt->status;

    // Path to the existing loaded csfle:
    mcr_dll_path_result existing_path_ = mcr_dll_path(g_csfle_state.dll);
    assert(existing_path_.path.data && "Failed to get path to already-loaded csfle library");
    mstr_view existing_path = existing_path_.path.view;
    bool okay = true;
    if (!found.okay) {
        // There is one loaded, but we failed to find that same library. Error:
        CLIENT_ERR("An existing CSFLE library is loaded by the application at "
                   "[%s], but the current call to mongocrypt_init() failed to "
                   "find that same library.",
                   existing_path.data);
        okay = false;
    } else {
        // Get the path to what we found:
        mcr_dll_path_result found_path = mcr_dll_path(found.lib);
        assert(found_path.path.data
               && "Failed to get the dynamic library filepath of the library that "
                  "was loaded for csfle");
        if (!mstr_eq(found_path.path.view, existing_path)) {
            // Our find-result should only ever find the existing same library.
            // Error:
            CLIENT_ERR("An existing CSFLE library is loaded by the application at [%s], "
                       "but the current call to mongocrypt_init() attempted to load a "
                       "second CSFLE library from [%s]. This is not allowed.",
                       existing_path.data,
                       found_path.path.data);
            okay = false;
        }
        mstr_free(found_path.path);
        mstr_free(found_path.error_string);
    }

    mstr_free(existing_path_.path);
    mstr_free(existing_path_.error_string);
    return okay;
}

/**
 * @brief Drop a reference count to the global csfle loaded library.
 *
 * This should be called as part of mongocrypt_t destruction following a
 * successful loading of csfle.
 */
static void _csfle_drop_global_ref(void) {
    mlib_call_once(&g_csfle_init_flag, init_csfle_state);

    MONGOCRYPT_WITH_MUTEX(g_csfle_state.mtx) {
        assert(g_csfle_state.refcount > 0);
        int new_rc = --g_csfle_state.refcount;
        if (new_rc == 0) {
            mongo_crypt_v1_status *status = g_csfle_state.vtable.status_create();
            const int destroy_rc = g_csfle_state.vtable.lib_destroy(g_csfle_state.csfle_lib, status);
            if (destroy_rc != MONGO_CRYPT_V1_SUCCESS && status) {
                fprintf(stderr,
                        "csfle lib_destroy() failed: %s [Error %d, code %d]\n",
                        g_csfle_state.vtable.status_get_explanation(status),
                        g_csfle_state.vtable.status_get_error(status),
                        g_csfle_state.vtable.status_get_code(status));
            }
            g_csfle_state.vtable.status_destroy(status);
#ifndef __linux__
            mcr_dll_close(g_csfle_state.dll);
#else
            /// NOTE: On Linux, skip closing the CSFLE library itself, since a bug in
            /// the way ld-linux and GCC interact causes static destructors to not run
            /// during dlclose(). Still, free the error string:
            ///
            /// Please see: https://jira.mongodb.org/browse/SERVER-63710
            mstr_free(g_csfle_state.dll.error_string);
#endif
        }
    }
}

/**
 * @brief Following a call to _try_find_csfle, reconcile the result with the
 * current application-global csfle status.
 *
 * csfle contains global state that can only be loaded once for the entire
 * application. For this reason, there is a global object that manages the
 * loaded library. Attempts to create more than one mongocrypt_t that all
 * request csfle requires that all instances attempt to open the same csfle
 * library.
 *
 * This function checks if there is already a csfle loaded for the process. If
 * there is, we validate that the given find-result found the same library
 * that is already loaded. If not, then this function sets an error and returns
 * `false`.
 *
 * If there was no prior loaded csfle and the find-result indicates that it
 * found the library, this function will store the find-result in the global
 * state for later calls to mongocrypt_init() that request csfle.
 *
 * This function performs reference counting on the global state. Following a
 * successful call to this function (i.e. it returns `true`), one must have a
 * corresponding call to _csfle_drop_global_ref(), which will release the
 * resources acquired by this function.
 *
 * @param crypt The requesting mongocrypt_t instance. An error may be set
 * through this object.
 * @param found The result of _try_find_csfle().
 * @return true Upon success AND `found->okay`
 * @return false Otherwise.
 *
 * @note If there was no prior global state loaded, this function will steal
 * the library referenced by `found`. The caller should release `found->lib`
 * regardless.
 */
static bool _csfle_replace_or_take_validate_singleton(mongocrypt_t *crypt, _loaded_csfle *found) {
    mlib_call_once(&g_csfle_init_flag, init_csfle_state);

    // If we have a loaded library, create a csfle_status object to use with
    // lib_create
    mongo_crypt_v1_status *csfle_status = NULL;

    BSON_ASSERT_PARAM(crypt);
    BSON_ASSERT_PARAM(found);

    if (found->okay) {
        // Create the status. Note that this may fail, so do not assume
        // csfle_status is non-null.
        csfle_status = found->vtable.status_create();
    }

    /**
     * Atomically:
     *
     * 1. If there is an existing global library, increment its reference count.
     * 2. Otherwise, if we have successfully loaded a new csfle, replace the
     *    global library and set its reference count to 1.
     * 3. Otherwise, do nothing.
     */
    enum {
        TOOK_REFERENCE,
        DID_NOTHING,
        REPLACED_GLOBAL,
        LIB_CREATE_FAILED,
    } action;

    MONGOCRYPT_WITH_MUTEX(g_csfle_state.mtx) {
        if (g_csfle_state.refcount) {
            // Increment the refcount to prevent the global csfle library from
            // disappearing
            ++g_csfle_state.refcount;
            action = TOOK_REFERENCE;
        } else if (found->okay) {
            // We have found csfle, and no one else is holding one. Our result will
            // now become the global result.
            // Create the single csfle_lib object for the application:
            mongo_crypt_v1_lib *csfle_lib = found->vtable.lib_create(csfle_status);
            if (csfle_lib == NULL) {
                // Creation failed:
                action = LIB_CREATE_FAILED;
            } else {
                // Creation succeeded: Store the result:
                g_csfle_state.dll = found->lib;
                g_csfle_state.vtable = found->vtable;
                g_csfle_state.csfle_lib = csfle_lib;
                g_csfle_state.refcount = 1;
                action = REPLACED_GLOBAL;
            }
        } else {
            // We failed to load the library, and no one else has one either.
            // Nothing to do.
            action = DID_NOTHING;
        }
    }

    // Get the possible failure status information.
    mstr message = MSTR_NULL;
    int err = 0;
    int code = 0;
    if (csfle_status) {
        assert(found->okay);
        message = mstr_copy_cstr(found->vtable.status_get_explanation(csfle_status));
        err = found->vtable.status_get_error(csfle_status);
        code = found->vtable.status_get_code(csfle_status);
        found->vtable.status_destroy(csfle_status);
    }

    bool have_csfle = true;
    switch (action) {
    case TOOK_REFERENCE: {
        const bool is_valid = _validate_csfle_singleton(crypt, *found);
        if (!is_valid) {
            //  We've failed validation, so we're not going to continue to
            //  reference the global instance it. Drop it now:
            _csfle_drop_global_ref();
        }
        have_csfle = is_valid;
        break;
    }
    case REPLACED_GLOBAL:
        // Reset the library in the caller so they can't unload the DLL. The DLL
        // is now managed in the global variable.
        found->lib = MCR_DLL_NULL;
        _mongocrypt_log(&crypt->log, MONGOCRYPT_LOG_LEVEL_TRACE, "Loading new csfle library for the application.");
        have_csfle = true;
        break;
    case LIB_CREATE_FAILED:
        if (!message.data) {
            // We failed to obtain a message about the failure
            _mongocrypt_set_error(crypt->status,
                                  MONGOCRYPT_STATUS_ERROR_CRYPT_SHARED,
                                  MONGOCRYPT_GENERIC_ERROR_CODE,
                                  "csfle lib_create() failed");
        } else {
            // Record the message, error, and code from csfle about the failure
            _mongocrypt_set_error(crypt->status,
                                  MONGOCRYPT_STATUS_ERROR_CRYPT_SHARED,
                                  MONGOCRYPT_GENERIC_ERROR_CODE,
                                  "csfle lib_create() failed: %s [Error %d, code %d]",
                                  message.data,
                                  err,
                                  code);
        }
        have_csfle = false;
        break;
    case DID_NOTHING:
    default: have_csfle = false; break;
    }

    mstr_free(message);
    return have_csfle;
}

/**
 * @return true If the given mongocrypt wants csfle
 * @return false Otherwise
 *
 * @note "Requesting csfle" means that it has set at least one search path OR
 * has set the override path
 */
static bool _wants_csfle(mongocrypt_t *c) {
    BSON_ASSERT_PARAM(c);

    if (c->opts.bypass_query_analysis) {
        return false;
    }
    return c->opts.n_crypt_shared_lib_search_paths != 0 || c->opts.crypt_shared_lib_override_path.data != NULL;
}

/**
 * @brief Try to enable csfle for the given mongocrypt
 *
 * @param crypt The crypt object for which we should enable csfle
 * @return true If no errors occurred
 * @return false Otherwise
 *
 * @note Returns `true` even if loading fails to find the csfle library on the
 * requested paths. `false` is only for hard-errors, which includes failure to
 * load from the override path.
 */
static bool _try_enable_csfle(mongocrypt_t *crypt) {
    mongocrypt_status_t *status;
    _loaded_csfle found;

    BSON_ASSERT_PARAM(crypt);

    found = _try_find_csfle(crypt);

    status = crypt->status;

    // If a crypt_shared override path was specified, but we did not succeed in
    // loading crypt_shared, that is a hard-error.
    if (crypt->opts.crypt_shared_lib_override_path.data && !found.okay) {
        // Wrap error with additional information.
        CLIENT_ERR("A crypt_shared override path was specified [%s], but we failed to open a dynamic "
                   "library at that location. Load error: [%s]",
                   crypt->opts.crypt_shared_lib_override_path.data,
                   mongocrypt_status_message(crypt->status, NULL /* len */));
        return false;
    }

    // Attempt to validate the try-find result against the global state:
    const bool got_csfle = _csfle_replace_or_take_validate_singleton(crypt, &found);
    // Close the lib we found (may have been stolen in validate_singleton())
    mcr_dll_close(found.lib);

    if (got_csfle) {
        crypt->csfle = g_csfle_state.vtable;
        crypt->csfle_lib = g_csfle_state.csfle_lib;
    }
    // In cast of failure, validate_singleton() will set a non-ok status.
    return mongocrypt_status_type(status) == MONGOCRYPT_STATUS_OK;
}

bool mongocrypt_init(mongocrypt_t *crypt) {
    BSON_ASSERT_PARAM(crypt);

    mongocrypt_status_t *status = crypt->status;
    if (crypt->initialized) {
        CLIENT_ERR("already initialized");
        return false;
    }

    crypt->initialized = true;

    if (!mongocrypt_status_ok(crypt->status)) {
        return false;
    }

    if (!_mongocrypt_opts_validate(&crypt->opts, status)) {
        return false;
    }

    if (crypt->opts.log_fn) {
        _mongocrypt_log_set_fn(&crypt->log, crypt->opts.log_fn, crypt->opts.log_ctx);
    }

    if (!crypt->crypto) {
#ifndef MONGOCRYPT_ENABLE_CRYPTO
        CLIENT_ERR("libmongocrypt built with native crypto disabled. crypto "
                   "hooks required");
        return false;
#else
        /* set default hooks. */
        crypt->crypto = bson_malloc0(sizeof(*crypt->crypto));
        BSON_ASSERT(crypt->crypto);
#endif
    }

    if (!_wants_csfle(crypt)) {
        // User does not want csfle. Just succeed.
        return true;
    }

    return _try_enable_csfle(crypt);
}

bool mongocrypt_is_crypto_available(void) {
#ifdef MONGOCRYPT_ENABLE_CRYPTO
    return true;
#else
    return false;
#endif
}

bool mongocrypt_status(mongocrypt_t *crypt, mongocrypt_status_t *out) {
    BSON_ASSERT_PARAM(crypt);

    if (!out) {
        mongocrypt_status_t *status = crypt->status;
        CLIENT_ERR("argument 'out' is required");
        return false;
    }

    if (!mongocrypt_status_ok(crypt->status)) {
        _mongocrypt_status_copy_to(crypt->status, out);
        return false;
    }
    _mongocrypt_status_reset(out);
    return true;
}

void mongocrypt_destroy(mongocrypt_t *crypt) {
    if (!crypt) {
        return;
    }
    _mongocrypt_opts_cleanup(&crypt->opts);
    _mongocrypt_cache_cleanup(&crypt->cache_collinfo);
    _mongocrypt_cache_cleanup(&crypt->cache_key);
    _mongocrypt_mutex_cleanup(&crypt->mutex);
    _mongocrypt_log_cleanup(&crypt->log);
    mongocrypt_status_destroy(crypt->status);
    bson_free(crypt->crypto);
    mc_mapof_kmsid_to_token_destroy(crypt->cache_oauth);

    if (crypt->csfle.okay) {
        _csfle_drop_global_ref();
        crypt->csfle.okay = false;
    }

    bson_free(crypt);
}

const char *mongocrypt_crypt_shared_lib_version_string(const mongocrypt_t *crypt, uint32_t *len) {
    BSON_ASSERT_PARAM(crypt);

    if (!crypt->csfle.okay) {
        if (len) {
            *len = 0;
        }
        return NULL;
    }
    const char *version = crypt->csfle.get_version_str();
    if (len) {
        *len = (uint32_t)(strlen(version));
    }
    return version;
}

uint64_t mongocrypt_crypt_shared_lib_version(const mongocrypt_t *crypt) {
    BSON_ASSERT_PARAM(crypt);

    if (!crypt->csfle.okay) {
        return 0;
    }
    return crypt->csfle.get_version();
}

bool _mongocrypt_validate_and_copy_string(const char *in, int32_t in_len, char **out) {
    BSON_ASSERT_PARAM(out);

    if (!in || in_len < -1) {
        return false;
    }

    const size_t len = in_len < 0 ? strlen(in) : (size_t)in_len;

    if (!bson_utf8_validate(in, len, false)) {
        return false;
    }
    *out = bson_strndup(in, len);
    return true;
}

bool mongocrypt_setopt_crypto_hooks(mongocrypt_t *crypt,
                                    mongocrypt_crypto_fn aes_256_cbc_encrypt,
                                    mongocrypt_crypto_fn aes_256_cbc_decrypt,
                                    mongocrypt_random_fn random,
                                    mongocrypt_hmac_fn hmac_sha_512,
                                    mongocrypt_hmac_fn hmac_sha_256,
                                    mongocrypt_hash_fn sha_256,
                                    void *ctx) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    mongocrypt_status_t *status = crypt->status;

    if (!crypt->crypto) {
        crypt->crypto = bson_malloc0(sizeof(*crypt->crypto));
        BSON_ASSERT(crypt->crypto);
    }

    crypt->crypto->hooks_enabled = true;
    crypt->crypto->ctx = ctx;

    if (!aes_256_cbc_encrypt) {
        CLIENT_ERR("aes_256_cbc_encrypt not set");
        return false;
    }
    crypt->crypto->aes_256_cbc_encrypt = aes_256_cbc_encrypt;

    if (!aes_256_cbc_decrypt) {
        CLIENT_ERR("aes_256_cbc_decrypt not set");
        return false;
    }
    crypt->crypto->aes_256_cbc_decrypt = aes_256_cbc_decrypt;

    if (!random) {
        CLIENT_ERR("random not set");
        return false;
    }
    crypt->crypto->random = random;

    if (!hmac_sha_512) {
        CLIENT_ERR("hmac_sha_512 not set");
        return false;
    }
    crypt->crypto->hmac_sha_512 = hmac_sha_512;

    if (!hmac_sha_256) {
        CLIENT_ERR("hmac_sha_256 not set");
        return false;
    }
    crypt->crypto->hmac_sha_256 = hmac_sha_256;

    if (!sha_256) {
        CLIENT_ERR("sha_256 not set");
        return false;
    }
    crypt->crypto->sha_256 = sha_256;

    return true;
}

bool mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5(mongocrypt_t *crypt,
                                                         mongocrypt_hmac_fn sign_rsaes_pkcs1_v1_5,
                                                         void *sign_ctx) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    if (crypt->opts.sign_rsaes_pkcs1_v1_5) {
        mongocrypt_status_t *status = crypt->status;
        CLIENT_ERR("signature hook already set");
        return false;
    }

    crypt->opts.sign_rsaes_pkcs1_v1_5 = sign_rsaes_pkcs1_v1_5;
    crypt->opts.sign_ctx = sign_ctx;
    return true;
}

bool mongocrypt_setopt_aes_256_ctr(mongocrypt_t *crypt,
                                   mongocrypt_crypto_fn aes_256_ctr_encrypt,
                                   mongocrypt_crypto_fn aes_256_ctr_decrypt,
                                   void *ctx) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    mongocrypt_status_t *status = crypt->status;

    if (!crypt->crypto) {
        crypt->crypto = bson_malloc0(sizeof(*crypt->crypto));
        BSON_ASSERT(crypt->crypto);
    }

    if (!aes_256_ctr_encrypt) {
        CLIENT_ERR("aes_256_ctr_encrypt not set");
        return false;
    }

    if (!aes_256_ctr_decrypt) {
        CLIENT_ERR("aes_256_ctr_decrypt not set");
        return false;
    }

    crypt->crypto->aes_256_ctr_encrypt = aes_256_ctr_encrypt;
    crypt->crypto->aes_256_ctr_decrypt = aes_256_ctr_decrypt;

    return true;
}

bool mongocrypt_setopt_aes_256_ecb(mongocrypt_t *crypt, mongocrypt_crypto_fn aes_256_ecb_encrypt, void *ctx) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);

    if (!crypt->crypto) {
        crypt->crypto = bson_malloc0(sizeof(*crypt->crypto));
        BSON_ASSERT(crypt->crypto);
    }

    if (!aes_256_ecb_encrypt) {
        mongocrypt_status_t *status = crypt->status;
        CLIENT_ERR("aes_256_ecb_encrypt not set");
        return false;
    }

    crypt->crypto->aes_256_ecb_encrypt = aes_256_ecb_encrypt;

    return true;
}

bool mongocrypt_setopt_kms_providers(mongocrypt_t *crypt, mongocrypt_binary_t *kms_providers_definition) {
    ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);
    BSON_ASSERT_PARAM(kms_providers_definition);

    return _mongocrypt_parse_kms_providers(kms_providers_definition,
                                           &crypt->opts.kms_providers,
                                           crypt->status,
                                           &crypt->log);
}

void mongocrypt_setopt_append_crypt_shared_lib_search_path(mongocrypt_t *crypt, const char *path) {
    BSON_ASSERT_PARAM(crypt);
    BSON_ASSERT_PARAM(path);

    // Dup the path string for us to manage
    mstr pathdup = mstr_copy_cstr(path);
    // Increase array len
    BSON_ASSERT(crypt->opts.n_crypt_shared_lib_search_paths < INT_MAX);
    const int new_len = crypt->opts.n_crypt_shared_lib_search_paths + 1;
    BSON_ASSERT(new_len > 0 && sizeof(mstr) <= SIZE_MAX / (size_t)new_len);
    mstr *const new_array = bson_realloc(crypt->opts.crypt_shared_lib_search_paths, sizeof(mstr) * (size_t)new_len);

    // Store the path
    new_array[new_len - 1] = pathdup;
    // Write back opts
    crypt->opts.crypt_shared_lib_search_paths = new_array;
    crypt->opts.n_crypt_shared_lib_search_paths = new_len;
}

void mongocrypt_setopt_use_need_kms_credentials_state(mongocrypt_t *crypt) {
    BSON_ASSERT_PARAM(crypt);

    crypt->opts.use_need_kms_credentials_state = true;
}

void mongocrypt_setopt_use_need_mongo_collinfo_with_db_state(mongocrypt_t *crypt) {
    BSON_ASSERT_PARAM(crypt);

    crypt->opts.use_need_mongo_collinfo_with_db_state = true;
}

void mongocrypt_setopt_set_crypt_shared_lib_path_override(mongocrypt_t *crypt, const char *path) {
    BSON_ASSERT_PARAM(crypt);
    BSON_ASSERT_PARAM(path);

    mstr_assign(&crypt->opts.crypt_shared_lib_override_path, mstr_copy_cstr(path));
}

bool _mongocrypt_needs_credentials(mongocrypt_t *crypt) {
    BSON_ASSERT_PARAM(crypt);

    if (!crypt->opts.use_need_kms_credentials_state) {
        return false;
    }

    return crypt->opts.kms_providers.need_credentials != 0;
}

bool _mongocrypt_needs_credentials_for_provider(mongocrypt_t *crypt,
                                                _mongocrypt_kms_provider_t provider,
                                                const char *name) {
    BSON_ASSERT_PARAM(crypt);

    if (name != NULL) {
        // Named KMS providers do not support on-demand credentials.
        return false;
    }

    if (!crypt->opts.use_need_kms_credentials_state) {
        return false;
    }

    return (crypt->opts.kms_providers.need_credentials & (int)provider) != 0;
}

void mongocrypt_setopt_bypass_query_analysis(mongocrypt_t *crypt) {
    BSON_ASSERT_PARAM(crypt);

    crypt->opts.bypass_query_analysis = true;
}
mongodb-1.21.0/src/libmongocrypt/src/mongocrypt.h0000644000175100001660000016026514760300420016767 0ustar  /*
 * Copyright 2019-present MongoDB, 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.
 */
#ifndef MONGOCRYPT_H
#define MONGOCRYPT_H

/** @file mongocrypt.h The top-level handle to libmongocrypt. */

/**
 * @mainpage libmongocrypt
 * See all public API documentation in: @ref mongocrypt.h
 */

#include "mongocrypt-compat.h"
#include "mongocrypt-export.h"

/* clang-format off */
#ifndef __has_include
   #include "mongocrypt-config.h"
#else
   #if __has_include("mongocrypt-config.h")
      #include "mongocrypt-config.h"
   #else
      #error No "mongocrypt-config.h" header is available. That file must \
             be generated in order to use libmongocrypt.
   #endif
#endif
/* clang-format on */

/**
 * Returns the version string for libmongocrypt.
 *
 * @param[out] len  An optional length of the returned string. May be NULL.
 * @returns a NULL terminated version string for libmongocrypt.
 */
MONGOCRYPT_EXPORT
const char *mongocrypt_version(uint32_t *len);

/**
 * Returns true if libmongocrypt was built with native crypto support.
 *
 * If libmongocrypt was not built with native crypto support, setting crypto
 * hooks is required.
 *
 * @returns True if libmongocrypt was built with native crypto support.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_is_crypto_available(void);

/**
 * A non-owning view of a byte buffer.
 *
 * When constructing a mongocrypt_binary_t it is the responsibility of the
 * caller to maintain the lifetime of the viewed data. However, all public
 * functions that take a mongocrypt_binary_t as an argument will make a copy of
 * the viewed data. For example, the following is valid:
 *
 * @code{.c}
 * mongocrypt_binary_t bin = mongocrypt_binary_new_from_data(mydata, mylen);
 * assert (mongocrypt_setopt_kms_provider_local (crypt), bin);
 * // The viewed data of bin has been copied. Ok to free the view and the data.
 * mongocrypt_binary_destroy (bin);
 * my_free_fn (mydata);
 * @endcode
 *
 * Functions with a mongocrypt_binary_t* out guarantee the lifetime of the
 * viewed data to live as long as the parent object. For example, @ref
 * mongocrypt_ctx_mongo_op guarantees that the viewed data of
 * mongocrypt_binary_t is valid until the parent ctx is destroyed with @ref
 * mongocrypt_ctx_destroy.
 *
 * The `mongocrypt_binary_t` struct definition is public.
 * Consumers may rely on the struct layout.
 */
typedef struct _mongocrypt_binary_t {
    void *data;
    uint32_t len;
} mongocrypt_binary_t;

/**
 * Create a new non-owning view of a buffer (data + length).
 *
 * Use this to create a mongocrypt_binary_t used for output parameters.
 *
 * @returns A new mongocrypt_binary_t.
 */
MONGOCRYPT_EXPORT
mongocrypt_binary_t *mongocrypt_binary_new(void);

/**
 * Create a new non-owning view of a buffer (data + length).
 *
 * @param[in] data A pointer to an array of bytes. This data is not copied. @p
 * data must outlive the binary object.
 * @param[in] len The length of the @p data byte array.
 *
 * @returns A new @ref mongocrypt_binary_t.
 */
MONGOCRYPT_EXPORT
mongocrypt_binary_t *mongocrypt_binary_new_from_data(uint8_t *data, uint32_t len);

/**
 * Get a pointer to the viewed data.
 *
 * @param[in] binary The @ref mongocrypt_binary_t.
 *
 * @returns A pointer to the viewed data.
 */
MONGOCRYPT_EXPORT
uint8_t *mongocrypt_binary_data(const mongocrypt_binary_t *binary);

/**
 * Get the length of the viewed data.
 *
 * @param[in] binary The @ref mongocrypt_binary_t.
 *
 * @returns The length of the viewed data.
 */
MONGOCRYPT_EXPORT
uint32_t mongocrypt_binary_len(const mongocrypt_binary_t *binary);

/**
 * Free the @ref mongocrypt_binary_t.
 *
 * This does not free the viewed data.
 *
 * @param[in] binary The mongocrypt_binary_t destroy.
 */
MONGOCRYPT_EXPORT
void mongocrypt_binary_destroy(mongocrypt_binary_t *binary);

/**
 * Indicates success or contains error information.
 *
 * Functions like @ref mongocrypt_ctx_encrypt_init follow a pattern to expose a
 * status. A boolean is returned. True indicates success, and false indicates
 * failure. On failure a status on the handle is set, and is accessible with a
 * corresponding (handle)_status function. E.g. @ref mongocrypt_ctx_status.
 */
typedef struct _mongocrypt_status_t mongocrypt_status_t;

/**
 * Indicates the type of error.
 */
typedef enum {
    MONGOCRYPT_STATUS_OK = 0,
    MONGOCRYPT_STATUS_ERROR_CLIENT = 1,
    MONGOCRYPT_STATUS_ERROR_KMS = 2,
    MONGOCRYPT_STATUS_ERROR_CRYPT_SHARED = 3,
} mongocrypt_status_type_t;

/**
 * Create a new status object.
 *
 * Use a new status object to retrieve the status from a handle by passing
 * this as an out-parameter to functions like @ref mongocrypt_ctx_status.
 * When done, destroy it with @ref mongocrypt_status_destroy.
 *
 * @returns A new status object.
 */
MONGOCRYPT_EXPORT
mongocrypt_status_t *mongocrypt_status_new(void);

/**
 * Set a status object with message, type, and code.
 *
 * Use this to set the @ref mongocrypt_status_t given in the crypto hooks.
 *
 * @param[in] type The status type.
 * @param[in] code The status code.
 * @param[in] message The message.
 * @param[in] message_len Due to historical behavior, pass 1 + the string length
 * of @p message (which differs from other functions accepting string
 * arguments).
 * Alternatively, if message is NULL terminated this may be -1 to tell
 * mongocrypt
 * to determine the string's length with strlen.
 *
 */
MONGOCRYPT_EXPORT
void mongocrypt_status_set(mongocrypt_status_t *status,
                           mongocrypt_status_type_t type,
                           uint32_t code,
                           const char *message,
                           int32_t message_len);

/**
 * Indicates success or the type of error.
 *
 * @param[in] status The status object.
 *
 * @returns A @ref mongocrypt_status_type_t.
 */
MONGOCRYPT_EXPORT
mongocrypt_status_type_t mongocrypt_status_type(mongocrypt_status_t *status);

/**
 * Get an error code or 0.
 *
 * @param[in] status The status object.
 *
 * @returns An error code.
 */
MONGOCRYPT_EXPORT
uint32_t mongocrypt_status_code(mongocrypt_status_t *status);

/**
 * Get the error message associated with a status or NULL.
 *
 * @param[in] status The status object.
 * @param[out] len An optional length of the returned string (excluding the
 * trailing NULL byte). May be NULL.
 *
 * @returns A NULL terminated error message or NULL.
 */
MONGOCRYPT_EXPORT
const char *mongocrypt_status_message(mongocrypt_status_t *status, uint32_t *len);

/**
 * Returns true if the status indicates success.
 *
 * @param[in] status The status to check.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_status_ok(mongocrypt_status_t *status);

/**
 * Free the memory for a status object.
 *
 * @param[in] status The status to destroy.
 */
MONGOCRYPT_EXPORT
void mongocrypt_status_destroy(mongocrypt_status_t *status);

/**
 * Indicates the type of log message.
 */
typedef enum {
    MONGOCRYPT_LOG_LEVEL_FATAL = 0,
    MONGOCRYPT_LOG_LEVEL_ERROR = 1,
    MONGOCRYPT_LOG_LEVEL_WARNING = 2,
    MONGOCRYPT_LOG_LEVEL_INFO = 3,
    MONGOCRYPT_LOG_LEVEL_TRACE = 4
} mongocrypt_log_level_t;

/**
 * A log callback function. Set a custom log callback with @ref
 * mongocrypt_setopt_log_handler.
 *
 * @param[in] message A NULL terminated message.
 * @param[in] message_len The length of message.
 * @param[in] ctx A context provided by the caller of @ref
 * mongocrypt_setopt_log_handler.
 */
typedef void (*mongocrypt_log_fn_t)(mongocrypt_log_level_t level, const char *message, uint32_t message_len, void *ctx);

/**
 * The top-level handle to libmongocrypt.
 *
 * Create a mongocrypt_t handle to perform operations within libmongocrypt:
 * encryption, decryption, registering log callbacks, etc.
 *
 * Functions on a mongocrypt_t are thread safe, though functions on derived
 * handles (e.g. mongocrypt_ctx_t) are not and must be owned by a single
 * thread. See each handle's documentation for thread-safety considerations.
 *
 * Multiple mongocrypt_t handles may be created.
 */
typedef struct _mongocrypt_t mongocrypt_t;

/**
 * Allocate a new @ref mongocrypt_t object.
 *
 * Set options using mongocrypt_setopt_* functions, then initialize with @ref
 * mongocrypt_init. When done with the @ref mongocrypt_t, free with @ref
 * mongocrypt_destroy.
 *
 * @returns A new @ref mongocrypt_t object.
 */
MONGOCRYPT_EXPORT
mongocrypt_t *mongocrypt_new(void);

/**
 * Set a handler on the @ref mongocrypt_t object to get called on every log
 * message.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] log_fn The log callback.
 * @param[in] log_ctx A context passed as an argument to the log callback every
 * invocation.
 * @pre @ref mongocrypt_init has not been called on @p crypt.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_log_handler(mongocrypt_t *crypt, mongocrypt_log_fn_t log_fn, void *log_ctx);

/**
 * Enable or disable KMS retry behavior.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] enable A boolean indicating whether to retry operations.
 * @pre @ref mongocrypt_init has not been called on @p crypt.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_retry_kms(mongocrypt_t *crypt, bool enable);

/**
 * Configure an AWS KMS provider on the @ref mongocrypt_t object.
 *
 * This has been superseded by the more flexible:
 * @ref mongocrypt_setopt_kms_providers
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] aws_access_key_id The AWS access key ID used to generate KMS
 * messages.
 * @param[in] aws_access_key_id_len The string length (in bytes) of @p
 * aws_access_key_id. Pass -1 to determine the string length with strlen (must
 * be NULL terminated).
 * @param[in] aws_secret_access_key The AWS secret access key used to generate
 * KMS messages.
 * @param[in] aws_secret_access_key_len The string length (in bytes) of @p
 * aws_secret_access_key. Pass -1 to determine the string length with strlen
 * (must be NULL terminated).
 * @pre @ref mongocrypt_init has not been called on @p crypt.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_kms_provider_aws(mongocrypt_t *crypt,
                                        const char *aws_access_key_id,
                                        int32_t aws_access_key_id_len,
                                        const char *aws_secret_access_key,
                                        int32_t aws_secret_access_key_len);

/**
 * Configure a local KMS provider on the @ref mongocrypt_t object.
 *
 * This has been superseded by the more flexible:
 * @ref mongocrypt_setopt_kms_providers
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] key A 96 byte master key used to encrypt and decrypt key vault
 * keys. The viewed data is copied. It is valid to destroy @p key with @ref
 * mongocrypt_binary_destroy immediately after.
 * @pre @ref mongocrypt_init has not been called on @p crypt.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_kms_provider_local(mongocrypt_t *crypt, mongocrypt_binary_t *key);

/**
 * Configure KMS providers with a BSON document.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] kms_providers A BSON document mapping the KMS provider names
 * to credentials. Set a KMS provider value to an empty document to supply
 * credentials on-demand with @ref mongocrypt_ctx_provide_kms_providers.
 * @pre @ref mongocrypt_init has not been called on @p crypt.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_kms_providers(mongocrypt_t *crypt, mongocrypt_binary_t *kms_providers);

/**
 * Set a local schema map for encryption.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] schema_map A BSON document representing the schema map supplied by
 * the user. The keys are collection namespaces and values are JSON schemas. The
 * viewed data copied. It is valid to destroy @p schema_map with @ref
 * mongocrypt_binary_destroy immediately after.
 * @pre @p crypt has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_schema_map(mongocrypt_t *crypt, mongocrypt_binary_t *schema_map);

/**
 * Set a local EncryptedFieldConfigMap for encryption.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] efc_map A BSON document representing the EncryptedFieldConfigMap
 * supplied by the user. The keys are collection namespaces and values are
 * EncryptedFieldConfigMap documents. The viewed data copied. It is valid to
 * destroy @p efc_map with @ref mongocrypt_binary_destroy immediately after.
 * @pre @p crypt has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_encrypted_field_config_map(mongocrypt_t *crypt, mongocrypt_binary_t *efc_map);

/**
 * @brief Append an additional search directory to the search path for loading
 * the crypt_shared dynamic library.
 *
 * @param[in] crypt The @ref mongocrypt_t object to update
 * @param[in] path A null-terminated sequence of bytes for the search path. On
 * some filesystems, this may be arbitrary bytes. On other filesystems, this may
 * be required to be a valid UTF-8 code unit sequence. If the leading element of
 * the path is the literal string "$ORIGIN", that substring will be replaced
 * with the directory path containing the executable libmongocrypt module. If
 * the path string is literal "$SYSTEM", then libmongocrypt will defer to the
 * system's library resolution mechanism to find the crypt_shared library.
 *
 * @note If no crypt_shared dynamic library is found in any of the directories
 * specified by the search paths loaded here, @ref mongocrypt_init() will still
 * succeed and continue to operate without crypt_shared.
 *
 * @note The search paths are searched in the order that they are appended. This
 * allows one to provide a precedence in how the library will be discovered. For
 * example, appending known directories before appending "$SYSTEM" will allow
 * one to supersede the system's installed library, but still fall-back to it if
 * the library wasn't found otherwise. If one does not ever append "$SYSTEM",
 * then the system's library-search mechanism will never be consulted.
 *
 * @note If an absolute path to the library is specified using
 * @ref mongocrypt_setopt_set_crypt_shared_lib_path_override, then paths
 * appended here will have no effect.
 */
MONGOCRYPT_EXPORT
void mongocrypt_setopt_append_crypt_shared_lib_search_path(mongocrypt_t *crypt, const char *path);

/**
 * @brief Set a single override path for loading the crypt_shared dynamic
 * library.
 *
 * @param[in] crypt The @ref mongocrypt_t object to update
 * @param[in] path A null-terminated sequence of bytes for a path to the
 * crypt_shared dynamic library. On some filesystems, this may be arbitrary
 * bytes. On other filesystems, this may be required to be a valid UTF-8 code
 * unit sequence. If the leading element of the path is the literal string
 * `$ORIGIN`, that substring will be replaced with the directory path containing
 * the executable libmongocrypt module.
 *
 * @note This function will do no IO nor path validation. All validation will
 * occur during the call to @ref mongocrypt_init.
 *
 * @note If a crypt_shared library path override is specified here, then no
 * paths given to @ref mongocrypt_setopt_append_crypt_shared_lib_search_path
 * will be consulted when opening the crypt_shared library.
 *
 * @note If a path is provided via this API and @ref mongocrypt_init fails to
 * initialize a valid crypt_shared library instance for the path specified, then
 * the initialization of mongocrypt_t will fail with an error.
 */
MONGOCRYPT_EXPORT
void mongocrypt_setopt_set_crypt_shared_lib_path_override(mongocrypt_t *crypt, const char *path);

/**
 * @brief Opt-into handling the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS state.
 *
 * If set, before entering the MONGOCRYPT_CTX_NEED_KMS state,
 * contexts may enter the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS state
 * and then wait for credentials to be supplied through
 * @ref mongocrypt_ctx_provide_kms_providers.
 *
 * A context will only enter MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS
 * if an empty document was set for a KMS provider in @ref
 * mongocrypt_setopt_kms_providers.
 *
 * @param[in] crypt The @ref mongocrypt_t object to update
 */
MONGOCRYPT_EXPORT
void mongocrypt_setopt_use_need_kms_credentials_state(mongocrypt_t *crypt);

/**
 * @brief Opt-into handling the MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB state.
 *
 * A context enters the MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB state when
 * processing a `bulkWrite` command. The target database of the `bulkWrite` may differ from the command database
 * ("admin").
 *
 * @param[in] crypt The @ref mongocrypt_t object to update
 */
MONGOCRYPT_EXPORT
void mongocrypt_setopt_use_need_mongo_collinfo_with_db_state(mongocrypt_t *crypt);

/**
 * Initialize new @ref mongocrypt_t object.
 *
 * Set options before using @ref mongocrypt_setopt_kms_provider_local, @ref
 * mongocrypt_setopt_kms_provider_aws, or @ref mongocrypt_setopt_log_handler.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status Failure may occur if previously
 * set
 * options are invalid.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_init(mongocrypt_t *crypt);

/**
 * Get the status associated with a @ref mongocrypt_t object.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[out] status Receives the status.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_status(mongocrypt_t *crypt, mongocrypt_status_t *status);

/**
 * Destroy the @ref mongocrypt_t object.
 *
 * @param[in] crypt The @ref mongocrypt_t object to destroy.
 */
MONGOCRYPT_EXPORT
void mongocrypt_destroy(mongocrypt_t *crypt);

/**
 * Obtain a nul-terminated version string of the loaded crypt_shared dynamic
 * library, if available.
 *
 * If no crypt_shared was successfully loaded, this function returns NULL.
 *
 * @param[in] crypt The mongocrypt_t object after a successful call to
 * mongocrypt_init.
 * @param[out] len An optional output parameter to which the length of the
 * returned string is written. If provided and no crypt_shared library was
 * loaded, zero is written to *len.
 *
 * @return A nul-terminated string of the dynamically loaded crypt_shared
 * library.
 *
 * @note For a numeric value that can be compared against, use
 * @ref mongocrypt_crypt_shared_lib_version.
 */
MONGOCRYPT_EXPORT
const char *mongocrypt_crypt_shared_lib_version_string(const mongocrypt_t *crypt, uint32_t *len);

/**
 * @brief Obtain a 64-bit constant encoding the version of the loaded
 * crypt_shared library, if available.
 *
 * @param[in] crypt The mongocrypt_t object after a successful call to
 * mongocrypt_init.
 *
 * @return A 64-bit encoded version number, with the version encoded as four
 * sixteen-bit integers, or zero if no crypt_shared library was loaded.
 *
 * The version is encoded as four 16-bit numbers, from high to low:
 *
 * - Major version
 * - Minor version
 * - Revision
 * - Reserved
 *
 * For example, version 6.2.1 would be encoded as: 0x0006'0002'0001'0000
 */
MONGOCRYPT_EXPORT
uint64_t mongocrypt_crypt_shared_lib_version(const mongocrypt_t *crypt);

/**
 * Manages the state machine for encryption or decryption.
 */
typedef struct _mongocrypt_ctx_t mongocrypt_ctx_t;

/**
 * Create a new uninitialized @ref mongocrypt_ctx_t.
 *
 * Initialize the context with functions like @ref mongocrypt_ctx_encrypt_init.
 * When done, destroy it with @ref mongocrypt_ctx_destroy.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @returns A new context.
 */
MONGOCRYPT_EXPORT
mongocrypt_ctx_t *mongocrypt_ctx_new(mongocrypt_t *crypt);

/**
 * Get the status associated with a @ref mongocrypt_ctx_t object.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[out] status Receives the status.
 *
 * @returns True if the output is an ok status, false if it is an error
 * status.
 *
 * @see mongocrypt_status_ok
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_status(mongocrypt_ctx_t *ctx, mongocrypt_status_t *status);

/**
 * Set the key id to use for explicit encryption.
 *
 * It is an error to set both this and the key alt name.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] key_id The binary corresponding to the _id (a UUID) of the data
 * key to use from the key vault collection. Note, the UUID must be encoded with
 * RFC-4122 byte order. The viewed data is copied. It is valid to destroy
 * @p key_id with @ref mongocrypt_binary_destroy immediately after.
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_key_id(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_id);

/**
 * Set the keyAltName to use for explicit encryption or
 * data key creation.
 *
 * Pass the binary encoding a BSON document like the following:
 *
 *   { "keyAltName" : (BSON UTF8 value) }
 *
 * For explicit encryption, it is an error to set both the keyAltName
 * and the key id.
 *
 * For creating data keys, call this function repeatedly to set
 * multiple keyAltNames.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] key_alt_name The name to use. The viewed data is copied. It is
 * valid to destroy @p key_alt_name with @ref mongocrypt_binary_destroy
 * immediately after.
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_key_alt_name(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_alt_name);

/**
 * Set the keyMaterial to use for encrypting data.
 *
 * Pass the binary encoding of a BSON document like the following:
 *
 *   { "keyMaterial" : (BSON BINARY value) }
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] key_material The data encryption key to use. The viewed data is
 * copied. It is valid to destroy @p key_material with @ref
 * mongocrypt_binary_destroy immediately after.
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_key_material(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_material);

/**
 * Set the algorithm used for encryption to either
 * deterministic or random encryption. This value
 * should only be set when using explicit encryption.
 *
 * If -1 is passed in for "len", then "algorithm" is
 * assumed to be a null-terminated string.
 *
 * Valid values for algorithm are:
 *   "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
 *   "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] algorithm A string specifying the algorithm to
 * use for encryption.
 * @param[in] len The length of the algorithm string.
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t *ctx, const char *algorithm, int len);

/// String constant for setopt_algorithm "Deterministic" encryption
#define MONGOCRYPT_ALGORITHM_DETERMINISTIC_STR "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
/// String constant for setopt_algorithm "Random" encryption
#define MONGOCRYPT_ALGORITHM_RANDOM_STR "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
/// String constant for setopt_algorithm "Indexed" explicit encryption
#define MONGOCRYPT_ALGORITHM_INDEXED_STR "Indexed"
/// String constant for setopt_algorithm "Unindexed" explicit encryption
#define MONGOCRYPT_ALGORITHM_UNINDEXED_STR "Unindexed"
// DEPRECATED: support "RangePreview" has been removed in favor of "range".
#define MONGOCRYPT_ALGORITHM_RANGEPREVIEW_DEPRECATED_STR "RangePreview"
#define MONGOCRYPT_ALGORITHM_RANGE_STR "Range"

/**
 * Identify the AWS KMS master key to use for creating a data key.
 *
 * This has been superseded by the more flexible:
 * @ref mongocrypt_ctx_setopt_key_encryption_key
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] region The AWS region.
 * @param[in] region_len The string length of @p region. Pass -1 to determine
 * the string length with strlen (must be NULL terminated).
 * @param[in] cmk The Amazon Resource Name (ARN) of the customer master key
 * (CMK).
 * @param[in] cmk_len The string length of @p cmk_len. Pass -1 to determine the
 * string length with strlen (must be NULL terminated).
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_masterkey_aws(mongocrypt_ctx_t *ctx,
                                         const char *region,
                                         int32_t region_len,
                                         const char *cmk,
                                         int32_t cmk_len);

/**
 * Identify a custom AWS endpoint when creating a data key.
 * This is used internally to construct the correct HTTP request
 * (with the Host header set to this endpoint). This endpoint
 * is persisted in the new data key, and will be returned via
 * @ref mongocrypt_kms_ctx_endpoint.
 *
 * This has been superseded by the more flexible:
 * @ref mongocrypt_ctx_setopt_key_encryption_key
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] endpoint The endpoint.
 * @param[in] endpoint_len The string length of @p endpoint. Pass -1 to
 * determine the string length with strlen (must be NULL terminated).
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_masterkey_aws_endpoint(mongocrypt_ctx_t *ctx, const char *endpoint, int32_t endpoint_len);

/**
 * Set the master key to "local" for creating a data key.
 * This has been superseded by the more flexible:
 * @ref mongocrypt_ctx_setopt_key_encryption_key
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_masterkey_local(mongocrypt_ctx_t *ctx);

/**
 * Set key encryption key document for creating a data key or for rewrapping
 * datakeys.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] bin BSON representing the key encryption key document with
 * an additional "provider" field. The following forms are accepted:
 *
 * AWS
 * {
 *    provider: "aws",
 *    region: ,
 *    key: ,
 *    endpoint: 
 * }
 *
 * Azure
 * {
 *    provider: "azure",
 *    keyVaultEndpoint: ,
 *    keyName: ,
 *    keyVersion: 
 * }
 *
 * GCP
 * {
 *    provider: "gcp",
 *    projectId: ,
 *    location: ,
 *    keyRing: ,
 *    keyName: ,
 *    keyVersion: ,
 *    endpoint: 
 * }
 *
 * Local
 * {
 *    provider: "local"
 * }
 *
 * KMIP
 * {
 *    provider: "kmip",
 *    keyId: 
 *    endpoint: 
 * }
 *
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_key_encryption_key(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *bin);

/**
 * Initialize a context to create a data key.
 *
 * Associated options:
 * - @ref mongocrypt_ctx_setopt_masterkey_aws
 * - @ref mongocrypt_ctx_setopt_masterkey_aws_endpoint
 * - @ref mongocrypt_ctx_setopt_masterkey_local
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 * @pre A master key option has been set, and an associated KMS provider
 * has been set on the parent @ref mongocrypt_t.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_datakey_init(mongocrypt_ctx_t *ctx);

/**
 * Initialize a context for encryption.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] db The database name.
 * @param[in] db_len The byte length of @p db. Pass -1 to determine the string
 * length with strlen (must
 * be NULL terminated).
 * @param[in] cmd The BSON command to be encrypted. The viewed data is copied.
 * It is valid to destroy @p cmd with @ref mongocrypt_binary_destroy immediately
 * after.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t *ctx, const char *db, int32_t db_len, mongocrypt_binary_t *cmd);

/**
 * Explicit helper method to encrypt a single BSON object. Contexts
 * created for explicit encryption will not go through mongocryptd.
 *
 * To specify a key_id, algorithm, or iv to use, please use the
 * corresponding mongocrypt_setopt methods before calling this.
 *
 * This method expects the passed-in BSON to be of the form:
 * { "v" : BSON value to encrypt }
 *
 * The value of "v" is expected to be the BSON value passed to a driver
 * ClientEncryption.encrypt helper.
 *
 * Associated options for FLE 1:
 * - @ref mongocrypt_ctx_setopt_key_id
 * - @ref mongocrypt_ctx_setopt_key_alt_name
 * - @ref mongocrypt_ctx_setopt_algorithm
 *
 * Associated options for Queryable Encryption:
 * - @ref mongocrypt_ctx_setopt_key_id
 * - @ref mongocrypt_ctx_setopt_index_key_id
 * - @ref mongocrypt_ctx_setopt_contention_factor
 * - @ref mongocrypt_ctx_setopt_query_type
 * - @ref mongocrypt_ctx_setopt_algorithm_range
 *
 * An error is returned if FLE 1 and Queryable Encryption incompatible options
 * are set.
 *
 * @param[in] ctx A @ref mongocrypt_ctx_t.
 * @param[in] msg A @ref mongocrypt_binary_t the plaintext BSON value. The
 * viewed data is copied. It is valid to destroy @p msg with @ref
 * mongocrypt_binary_destroy immediately after.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg);

/**
 * Explicit helper method to encrypt a Match Expression or Aggregate Expression.
 * Contexts created for explicit encryption will not go through mongocryptd.
 * Requires query_type to be "range".
 *
 * This method expects the passed-in BSON to be of the form:
 * { "v" : FLE2RangeFindDriverSpec }
 *
 * FLE2RangeFindDriverSpec is a BSON document with one of these forms:
 *
 * 1. A Match Expression of this form:
 *    {$and: [{: {: , {: {:  }}]}
 * 2. An Aggregate Expression of this form:
 *    {$and: [{: [, ]}, {: [, ]}]
 *
 *  may be $lt, $lte, $gt, or $gte.
 *
 * The value of "v" is expected to be the BSON value passed to a driver
 * ClientEncryption.encryptExpression helper.
 *
 * Associated options for FLE 1:
 * - @ref mongocrypt_ctx_setopt_key_id
 * - @ref mongocrypt_ctx_setopt_key_alt_name
 * - @ref mongocrypt_ctx_setopt_algorithm
 *
 * Associated options for Queryable Encryption:
 * - @ref mongocrypt_ctx_setopt_key_id
 * - @ref mongocrypt_ctx_setopt_index_key_id
 * - @ref mongocrypt_ctx_setopt_contention_factor
 * - @ref mongocrypt_ctx_setopt_query_type
 * - @ref mongocrypt_ctx_setopt_algorithm_range
 *
 * An error is returned if FLE 1 and Queryable Encryption incompatible options
 * are set.
 *
 * @param[in] ctx A @ref mongocrypt_ctx_t.
 * @param[in] msg A @ref mongocrypt_binary_t the plaintext BSON value. The
 * viewed data is copied. It is valid to destroy @p msg with @ref
 * mongocrypt_binary_destroy immediately after.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_explicit_encrypt_expression_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg);

/**
 * Initialize a context for decryption.
 *
 * This method expects the passed-in BSON to be of the form:
 * { "v" : BSON value to encrypt }
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] doc The document to be decrypted. The viewed data is copied. It is
 * valid to destroy @p doc with @ref mongocrypt_binary_destroy immediately
 * after.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_decrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *doc);

/**
 * Explicit helper method to decrypt a single BSON object.
 *
 * Pass the binary encoding of a BSON document containing the BSON value to
 * encrypt like the following:
 *
 *   { "v" : (BSON BINARY value of subtype 6) }
 *
 * @param[in] ctx A @ref mongocrypt_ctx_t.
 * @param[in] msg A @ref mongocrypt_binary_t the encrypted BSON. The viewed data
 * is copied. It is valid to destroy @p msg with @ref mongocrypt_binary_destroy
 * immediately after.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_explicit_decrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *msg);

/**
 * @brief Initialize a context to rewrap datakeys.
 *
 * Associated options:
 * - @ref mongocrypt_ctx_setopt_key_encryption_key
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] filter The filter to use for the find command on the key vault
 * collection to retrieve datakeys to rewrap.
 * @return A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_rewrap_many_datakey_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *filter);

/**
 * Indicates the state of the @ref mongocrypt_ctx_t. Each state requires
 * different handling. See [the integration
 * guide](https://github.com/mongodb/libmongocrypt/blob/master/integrating.md#state-machine)
 * for information on what to do for each state.
 */
typedef enum {
    MONGOCRYPT_CTX_ERROR = 0,
    MONGOCRYPT_CTX_NEED_MONGO_COLLINFO = 1,         /* run on main MongoClient */
    MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB = 8, /* run on main MongoClient */
    MONGOCRYPT_CTX_NEED_MONGO_MARKINGS = 2,         /* run on mongocryptd. */
    MONGOCRYPT_CTX_NEED_MONGO_KEYS = 3,             /* run on key vault */
    MONGOCRYPT_CTX_NEED_KMS = 4,
    MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS = 7, /* fetch/renew KMS credentials */
    MONGOCRYPT_CTX_READY = 5,                /* ready for encryption/decryption */
    MONGOCRYPT_CTX_DONE = 6,
} mongocrypt_ctx_state_t;

/**
 * Get the current state of a context.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @returns A @ref mongocrypt_ctx_state_t.
 */
MONGOCRYPT_EXPORT
mongocrypt_ctx_state_t mongocrypt_ctx_state(mongocrypt_ctx_t *ctx);

/**
 * Get BSON necessary to run the mongo operation when mongocrypt_ctx_t
 * is in MONGOCRYPT_CTX_NEED_MONGO_* states.
 *
 * @p op_bson is a BSON document to be used for the operation.
 * - For MONGOCRYPT_CTX_NEED_MONGO_COLLINFO(_WITH_DB) it is a listCollections filter.
 * - For MONGOCRYPT_CTX_NEED_MONGO_KEYS it is a find filter.
 * - For MONGOCRYPT_CTX_NEED_MONGO_MARKINGS it is a command to send to
 * mongocryptd.
 *
 * The lifetime of @p op_bson is tied to the lifetime of @p ctx. It is valid
 * until @ref mongocrypt_ctx_destroy is called.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[out] op_bson A BSON document for the MongoDB operation. The data
 * viewed by @p op_bson is guaranteed to be valid until @p ctx is destroyed with
 * @ref mongocrypt_ctx_destroy.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_mongo_op(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *op_bson);

/**
 * Get the database to run the mongo operation.
 *
 * Only applies when mongocrypt_ctx_t is in the state:
 * MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB.
 *
 * The lifetime of the returned string is tied to the lifetime of @p ctx. It is
 * valid until @ref mongocrypt_ctx_destroy is called.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @returns A string or NULL. If NULL, an error status is set. Retrieve it with
 * @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
const char *mongocrypt_ctx_mongo_db(mongocrypt_ctx_t *ctx);

/**
 * Feed a BSON reply or result when mongocrypt_ctx_t is in
 * MONGOCRYPT_CTX_NEED_MONGO_* states. This may be called multiple times
 * depending on the operation.
 *
 * reply is a BSON document result being fed back for this operation.
 * - For MONGOCRYPT_CTX_NEED_MONGO_COLLINFO(_WITH_DB) it is a doc from a listCollections
 * cursor. (Note, if listCollections returned no result, do not call this
 * function.)
 * - For MONGOCRYPT_CTX_NEED_MONGO_KEYS it is a doc from a find cursor.
 *   (Note, if find returned no results, do not call this function. reply must
 * not
 *   be NULL.)
 * - For MONGOCRYPT_CTX_NEED_MONGO_MARKINGS it is a reply from mongocryptd.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] reply A BSON document for the MongoDB operation. The viewed data
 * is copied. It is valid to destroy @p reply with @ref
 * mongocrypt_binary_destroy immediately after.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_mongo_feed(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *reply);

/**
 * Call when done feeding the reply (or replies) back to the context.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_mongo_done(mongocrypt_ctx_t *ctx);

/**
 * Manages a single KMS HTTP request/response.
 */
typedef struct _mongocrypt_kms_ctx_t mongocrypt_kms_ctx_t;

/**
 * Get the next KMS handle.
 *
 * Multiple KMS handles may be retrieved at once. Drivers may do this to fan
 * out multiple concurrent KMS HTTP requests. Feeding multiple KMS requests
 * is thread-safe.
 *
 * If KMS handles are being handled synchronously, the driver can reuse the same
 * TLS socket to send HTTP requests and receive responses.
 *
 * The returned KMS handle does not outlive `ctx`.
 *
 * @param[in] ctx A @ref mongocrypt_ctx_t.
 * @returns a new @ref mongocrypt_kms_ctx_t or NULL.
 */
MONGOCRYPT_EXPORT
mongocrypt_kms_ctx_t *mongocrypt_ctx_next_kms_ctx(mongocrypt_ctx_t *ctx);

/**
 * Get the HTTP request message for a KMS handle.
 *
 * The lifetime of @p msg is tied to the lifetime of @p kms. It is valid
 * until @ref mongocrypt_ctx_kms_done is called.
 *
 * @param[in] kms A @ref mongocrypt_kms_ctx_t.
 * @param[out] msg The HTTP request to send to KMS. The data viewed by @p msg is
 * guaranteed to be valid until the call of @ref mongocrypt_ctx_kms_done of the
 * parent @ref mongocrypt_ctx_t.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_kms_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_kms_ctx_message(mongocrypt_kms_ctx_t *kms, mongocrypt_binary_t *msg);

/**
 * Get the hostname from which to connect over TLS.
 *
 * The storage for @p endpoint is not owned by the caller, but
 * is valid until calling @ref mongocrypt_ctx_kms_done.
 *
 * @param[in] kms A @ref mongocrypt_kms_ctx_t.
 * @param[out] endpoint The output endpoint as a NULL terminated string.
 * The endpoint consists of a hostname and port separated by a colon.
 * E.g. "example.com:123". A port is always present.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_kms_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_kms_ctx_endpoint(mongocrypt_kms_ctx_t *kms, const char **endpoint);

/**
 * Indicates how many bytes to feed into @ref mongocrypt_kms_ctx_feed.
 *
 * @param[in] kms The @ref mongocrypt_kms_ctx_t.
 * @returns The number of requested bytes.
 */
MONGOCRYPT_EXPORT
uint32_t mongocrypt_kms_ctx_bytes_needed(mongocrypt_kms_ctx_t *kms);

/**
 * Indicates how long to sleep before sending this request.
 *
 * @param[in] kms The @ref mongocrypt_kms_ctx_t.
 * @returns How long to sleep in microseconds.
 */
MONGOCRYPT_EXPORT
int64_t mongocrypt_kms_ctx_usleep(mongocrypt_kms_ctx_t *kms);

/**
 * Feed bytes from the HTTP response.
 *
 * Feeding more bytes than what has been returned in @ref
 * mongocrypt_kms_ctx_bytes_needed is an error.
 *
 * @param[in] kms The @ref mongocrypt_kms_ctx_t.
 * @param[in] bytes The bytes to feed. The viewed data is copied. It is valid to
 * destroy @p bytes with @ref mongocrypt_binary_destroy immediately after.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_kms_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_kms_ctx_feed(mongocrypt_kms_ctx_t *kms, mongocrypt_binary_t *bytes);

/**
 * Indicate a network-level failure.
 *
 * @param[in] kms The @ref mongocrypt_kms_ctx_t.
 * @return A boolean indicating whether the failed request may be retried.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_kms_ctx_fail(mongocrypt_kms_ctx_t *kms);

/**
 * Get the status associated with a @ref mongocrypt_kms_ctx_t object.
 *
 * @param[in] kms The @ref mongocrypt_kms_ctx_t object.
 * @param[out] status Receives the status.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_kms_ctx_status(mongocrypt_kms_ctx_t *kms, mongocrypt_status_t *status);

/**
 * Get the KMS provider identifier associated with this KMS request.
 *
 * This is used to conditionally configure TLS connections based on the KMS
 * request. It is useful for KMIP, which authenticates with a client
 * certificate.
 *
 * @param[in] kms The @ref mongocrypt_kms_ctx_t object.
 * @param[out] len Receives the length of the returned string. It may be NULL.
 * If it is not NULL, it is set to the length of the returned string without
 * the NULL terminator.
 *
 * @returns One of the NULL terminated static strings: "aws", "azure", "gcp", or
 * "kmip".
 */
MONGOCRYPT_EXPORT
const char *mongocrypt_kms_ctx_get_kms_provider(mongocrypt_kms_ctx_t *kms, uint32_t *len);

/**
 * Call when done handling all KMS contexts.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_kms_done(mongocrypt_ctx_t *ctx);

/**
 * Call in response to the MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS state
 * to set per-context KMS provider settings. These follow the same format
 * as @ref mongocrypt_setopt_kms_providers. If no keys are present in the
 * BSON input, the KMS provider settings configured for the @ref mongocrypt_t
 * at initialization are used.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] kms_providers_definition A BSON document mapping the KMS provider
 * names to credentials.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_provide_kms_providers(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *kms_providers_definition);

/**
 * Perform the final encryption or decryption.
 *
 * @param[in] ctx A @ref mongocrypt_ctx_t.
 * @param[out] out The final BSON. The data viewed by @p out is guaranteed
 * to be valid until @p ctx is destroyed with @ref mongocrypt_ctx_destroy.
 * The meaning of this BSON depends on the type of @p ctx.
 *
 * If @p ctx was initialized with @ref mongocrypt_ctx_encrypt_init, then
 * this BSON is the (possibly) encrypted command to send to the server.
 *
 * If @p ctx was initialized with @ref mongocrypt_ctx_decrypt_init, then
 * this BSON is the decrypted result to return to the user.
 *
 * If @p ctx was initialized with @ref mongocrypt_ctx_explicit_encrypt_init,
 * then this BSON has the form { "v": (BSON binary) } where the BSON binary
 * is the resulting encrypted value.
 *
 * If @p ctx was initialized with @ref mongocrypt_ctx_explicit_decrypt_init,
 * then this BSON has the form { "v": (BSON value) } where the BSON value
 * is the resulting decrypted value.
 *
 * If @p ctx was initialized with @ref mongocrypt_ctx_datakey_init, then
 * this BSON is the document containing the new data key to be inserted into
 * the key vault collection.
 *
 * If @p ctx was initialized with @ref mongocrypt_ctx_rewrap_many_datakey_init,
 * then this BSON has the form:
 *   { "v": [{ "_id": ..., "keyMaterial": ..., "masterKey": ... }, ...] }
 * where each BSON document in the array contains the updated fields of a
 * rewrapped datakey to be bulk-updated into the key vault collection.
 * Note: the updateDate field should be updated using the $currentDate operator.
 *
 * @returns a bool indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out);

/**
 * Destroy and free all memory associated with a @ref mongocrypt_ctx_t.
 *
 * @param[in] ctx A @ref mongocrypt_ctx_t.
 */
MONGOCRYPT_EXPORT
void mongocrypt_ctx_destroy(mongocrypt_ctx_t *ctx);

/**
 * An crypto AES-256-CBC encrypt or decrypt function.
 *
 * Note, @p in is already padded. Encrypt with padding disabled.
 * @param[in] ctx An optional context object that may have been set when hooks
 * were enabled.
 * @param[in] key An encryption key (32 bytes for AES_256).
 * @param[in] iv An initialization vector (16 bytes for AES_256);
 * @param[in] in The input.
 * @param[out] out A preallocated byte array for the output. See @ref
 * mongocrypt_binary_data.
 * @param[out] bytes_written Set this to the number of bytes written to @p out.
 * @param[out] status An optional status to pass error messages. See @ref
 * mongocrypt_status_set.
 * @returns A boolean indicating success. If returning false, set @p status
 * with a message indicating the error using @ref mongocrypt_status_set.
 */
typedef bool (*mongocrypt_crypto_fn)(void *ctx,
                                     mongocrypt_binary_t *key,
                                     mongocrypt_binary_t *iv,
                                     mongocrypt_binary_t *in,
                                     mongocrypt_binary_t *out,
                                     uint32_t *bytes_written,
                                     mongocrypt_status_t *status);

/**
 * A crypto signature or HMAC function.
 *
 * Currently used in callbacks for HMAC SHA-512, HMAC SHA-256, and RSA SHA-256
 * signature.
 *
 * @param[in] ctx An optional context object that may have been set when hooks
 * were enabled.
 * @param[in] key An encryption key (32 bytes for HMAC_SHA512).
 * @param[in] in The input.
 * @param[out] out A preallocated byte array for the output. See @ref
 * mongocrypt_binary_data.
 * @param[out] status An optional status to pass error messages. See @ref
 * mongocrypt_status_set.
 * @returns A boolean indicating success. If returning false, set @p status
 * with a message indicating the error using @ref mongocrypt_status_set.
 */
typedef bool (*mongocrypt_hmac_fn)(void *ctx,
                                   mongocrypt_binary_t *key,
                                   mongocrypt_binary_t *in,
                                   mongocrypt_binary_t *out,
                                   mongocrypt_status_t *status);

/**
 * A crypto hash (SHA-256) function.
 *
 * @param[in] ctx An optional context object that may have been set when hooks
 * were enabled.
 * @param[in] in The input.
 * @param[out] out A preallocated byte array for the output. See @ref
 * mongocrypt_binary_data.
 * @param[out] status An optional status to pass error messages. See @ref
 * mongocrypt_status_set.
 * @returns A boolean indicating success. If returning false, set @p status
 * with a message indicating the error using @ref mongocrypt_status_set.
 */
typedef bool (*mongocrypt_hash_fn)(void *ctx,
                                   mongocrypt_binary_t *in,
                                   mongocrypt_binary_t *out,
                                   mongocrypt_status_t *status);

/**
 * A crypto secure random function.
 *
 * @param[in] ctx An optional context object that may have been set when hooks
 * were enabled.
 * @param[out] out A preallocated byte array for the output. See @ref
 * mongocrypt_binary_data.
 * @param[in] count The number of random bytes requested.
 * @param[out] status An optional status to pass error messages. See @ref
 * mongocrypt_status_set.
 * @returns A boolean indicating success. If returning false, set @p status
 * with a message indicating the error using @ref mongocrypt_status_set.
 */
typedef bool (*mongocrypt_random_fn)(void *ctx, mongocrypt_binary_t *out, uint32_t count, mongocrypt_status_t *status);

MONGOCRYPT_EXPORT
bool mongocrypt_setopt_crypto_hooks(mongocrypt_t *crypt,
                                    mongocrypt_crypto_fn aes_256_cbc_encrypt,
                                    mongocrypt_crypto_fn aes_256_cbc_decrypt,
                                    mongocrypt_random_fn random,
                                    mongocrypt_hmac_fn hmac_sha_512,
                                    mongocrypt_hmac_fn hmac_sha_256,
                                    mongocrypt_hash_fn sha_256,
                                    void *ctx);

/**
 * Set a crypto hook for the AES256-CTR operations.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] aes_256_ctr_encrypt The crypto callback function for encrypt
 * operation.
 * @param[in] aes_256_ctr_decrypt The crypto callback function for decrypt
 * operation.
 * @param[in] ctx Unused.
 * @pre @ref mongocrypt_init has not been called on @p crypt.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_status
 *
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_aes_256_ctr(mongocrypt_t *crypt,
                                   mongocrypt_crypto_fn aes_256_ctr_encrypt,
                                   mongocrypt_crypto_fn aes_256_ctr_decrypt,
                                   void *ctx);

/**
 * Set an AES256-ECB crypto hook for the AES256-CTR operations. If CTR hook was
 * configured using @ref mongocrypt_setopt_aes_256_ctr, ECB hook will be
 * ignored.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] aes_256_ecb_encrypt The crypto callback function for encrypt
 * operation.
 * @param[in] ctx Unused.
 * @pre @ref mongocrypt_init has not been called on @p crypt.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_status
 *
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_aes_256_ecb(mongocrypt_t *crypt, mongocrypt_crypto_fn aes_256_ecb_encrypt, void *ctx);

/**
 * Set a crypto hook for the RSASSA-PKCS1-v1_5 algorithm with a SHA-256 hash.
 *
 * See: https://tools.ietf.org/html/rfc3447#section-8.2
 *
 * Note: this function has the wrong name. It should be:
 * mongocrypt_setopt_crypto_hook_sign_rsassa_pkcs1_v1_5
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 * @param[in] sign_rsaes_pkcs1_v1_5 The crypto callback function.
 * @param[in] sign_ctx A context passed as an argument to the crypto callback
 * every invocation.
 * @pre @ref mongocrypt_init has not been called on @p crypt.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_status
 *
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5(mongocrypt_t *crypt,
                                                         mongocrypt_hmac_fn sign_rsaes_pkcs1_v1_5,
                                                         void *sign_ctx);

/**
 * @brief Opt-into skipping query analysis.
 *
 * If opted in:
 * - The crypt_shared library will not attempt to be loaded.
 * - A mongocrypt_ctx_t will never enter the MONGOCRYPT_CTX_NEED_MARKINGS state.
 *
 * @param[in] crypt The @ref mongocrypt_t object to update
 */
MONGOCRYPT_EXPORT
void mongocrypt_setopt_bypass_query_analysis(mongocrypt_t *crypt);

/**
 * DEPRECATED: Use of `mongocrypt_setopt_use_range_v2` is deprecated. Range V2 is always enabled.
 *
 * @param[in] crypt The @ref mongocrypt_t object.
 *
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_use_range_v2(mongocrypt_t *crypt);

/**
 * Set the contention factor used for explicit encryption.
 * The contention factor is only used for indexed Queryable Encryption.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] contention_factor
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_contention_factor(mongocrypt_ctx_t *ctx, int64_t contention_factor);

/**
 * Set the index key id to use for explicit Queryable Encryption.
 *
 * If the index key id not set, the key id from @ref
 * mongocrypt_ctx_setopt_key_id is used.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] key_id The binary corresponding to the _id (a UUID) of the data
 * key to use from the key vault collection. Note, the UUID must be encoded with
 * RFC-4122 byte order. The viewed data is copied. It is valid to destroy
 * @p key_id with @ref mongocrypt_binary_destroy immediately after.
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_index_key_id(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *key_id);

/**
 * Set the query type to use for explicit Queryable Encryption.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] query_type The query type string
 * @param[in] len The length of query_type, or -1 for automatic
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t *ctx, const char *query_type, int len);

/**
 * Set options for explicit encryption with the "range" algorithm.
 *
 * @p opts is a BSON document of the form:
 * {
 *    "min": Optional,
 *    "max": Optional,
 *    "sparsity": Optional,
 *    "precision": Optional,
 *    "trimFactor": Optional
 * }
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] opts BSON.
 * @pre @p ctx has not been initialized.
 * @returns A boolean indicating success. If false, an error status is set.
 * Retrieve it with @ref mongocrypt_ctx_status
 */
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts);

/**
 * Set the expiration time for the data encryption key cache. Defaults to 60 seconds if not set.
 *
 * @param[in] ctx The @ref mongocrypt_ctx_t object.
 * @param[in] cache_expiration_ms The cache expiration time in milliseconds. If zero, the cache
 * never expires.
 */
MONGOCRYPT_EXPORT
bool mongocrypt_setopt_key_expiration(mongocrypt_t *crypt, uint64_t cache_expiration_ms);

/// String constants for setopt_query_type
#define MONGOCRYPT_QUERY_TYPE_EQUALITY_STR "equality"
// DEPRECATED: Support "rangePreview" has been removed in favor of "range".
#define MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED_STR "rangePreview"
#define MONGOCRYPT_QUERY_TYPE_RANGE_STR "range"

#endif /* MONGOCRYPT_H */
mongodb-1.21.0/src/LIBMONGOCRYPT_VERSION_CURRENT0000644000175100001660000000000714760300420015303 0ustar  1.12.0
mongodb-1.21.0/src/LIBMONGOC_VERSION_CURRENT0000644000175100001660000000000714760300420014564 0ustar  1.30.1
mongodb-1.21.0/src/functions_arginfo.h0000644000175100001660000000623414760300420014617 0ustar  /* This is a generated file, edit the .stub.php file instead.
 * Stub hash: 4d9c8b8131126ce2e67fe1659205aaf7eee8c14e */

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_MongoDB_BSON_fromJSON, 0, 1, IS_STRING, 0)
	ZEND_ARG_TYPE_INFO(0, json, IS_STRING, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_MongoDB_BSON_fromPHP, 0, 1, IS_STRING, 0)
	ZEND_ARG_TYPE_MASK(0, value, MAY_BE_ARRAY|MAY_BE_OBJECT, NULL)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_MongoDB_BSON_toCanonicalExtendedJSON, 0, 1, IS_STRING, 0)
	ZEND_ARG_TYPE_INFO(0, bson, IS_STRING, 0)
ZEND_END_ARG_INFO()

#define arginfo_MongoDB_BSON_toJSON arginfo_MongoDB_BSON_toCanonicalExtendedJSON

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_MongoDB_BSON_toPHP, 0, 1, MAY_BE_ARRAY|MAY_BE_OBJECT)
	ZEND_ARG_TYPE_INFO(0, bson, IS_STRING, 0)
	ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, typemap, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()

#define arginfo_MongoDB_BSON_toRelaxedExtendedJSON arginfo_MongoDB_BSON_toCanonicalExtendedJSON

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_MongoDB_Driver_Monitoring_addSubscriber, 0, 1, IS_VOID, 0)
	ZEND_ARG_OBJ_INFO(0, subscriber, MongoDB\\Driver\\Monitoring\\Subscriber, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_MongoDB_Driver_Monitoring_mongoc_log, 0, 3, IS_VOID, 0)
	ZEND_ARG_TYPE_INFO(0, level, IS_LONG, 0)
	ZEND_ARG_TYPE_INFO(0, domain, IS_STRING, 0)
	ZEND_ARG_TYPE_INFO(0, message, IS_STRING, 0)
ZEND_END_ARG_INFO()

#define arginfo_MongoDB_Driver_Monitoring_removeSubscriber arginfo_MongoDB_Driver_Monitoring_addSubscriber


ZEND_FUNCTION(MongoDB_BSON_fromJSON);
ZEND_FUNCTION(MongoDB_BSON_fromPHP);
ZEND_FUNCTION(MongoDB_BSON_toCanonicalExtendedJSON);
ZEND_FUNCTION(MongoDB_BSON_toJSON);
ZEND_FUNCTION(MongoDB_BSON_toPHP);
ZEND_FUNCTION(MongoDB_BSON_toRelaxedExtendedJSON);
ZEND_FUNCTION(MongoDB_Driver_Monitoring_addSubscriber);
ZEND_FUNCTION(MongoDB_Driver_Monitoring_mongoc_log);
ZEND_FUNCTION(MongoDB_Driver_Monitoring_removeSubscriber);


static const zend_function_entry ext_functions[] = {
	ZEND_NS_DEP_FALIAS("MongoDB\\BSON", fromJSON, MongoDB_BSON_fromJSON, arginfo_MongoDB_BSON_fromJSON)
	ZEND_NS_DEP_FALIAS("MongoDB\\BSON", fromPHP, MongoDB_BSON_fromPHP, arginfo_MongoDB_BSON_fromPHP)
	ZEND_NS_DEP_FALIAS("MongoDB\\BSON", toCanonicalExtendedJSON, MongoDB_BSON_toCanonicalExtendedJSON, arginfo_MongoDB_BSON_toCanonicalExtendedJSON)
	ZEND_NS_DEP_FALIAS("MongoDB\\BSON", toJSON, MongoDB_BSON_toJSON, arginfo_MongoDB_BSON_toJSON)
	ZEND_NS_DEP_FALIAS("MongoDB\\BSON", toPHP, MongoDB_BSON_toPHP, arginfo_MongoDB_BSON_toPHP)
	ZEND_NS_DEP_FALIAS("MongoDB\\BSON", toRelaxedExtendedJSON, MongoDB_BSON_toRelaxedExtendedJSON, arginfo_MongoDB_BSON_toRelaxedExtendedJSON)
	ZEND_NS_FALIAS("MongoDB\\Driver\\Monitoring", addSubscriber, MongoDB_Driver_Monitoring_addSubscriber, arginfo_MongoDB_Driver_Monitoring_addSubscriber)
	ZEND_NS_FALIAS("MongoDB\\Driver\\Monitoring", mongoc_log, MongoDB_Driver_Monitoring_mongoc_log, arginfo_MongoDB_Driver_Monitoring_mongoc_log)
	ZEND_NS_FALIAS("MongoDB\\Driver\\Monitoring", removeSubscriber, MongoDB_Driver_Monitoring_removeSubscriber, arginfo_MongoDB_Driver_Monitoring_removeSubscriber)
	ZEND_FE_END
};
mongodb-1.21.0/src/phongo_apm.c0000644000175100001660000006025014760300420013222 0ustar  /*
 * Copyright 2021-present MongoDB, 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.
 */

#include "bson/bson.h"
#include "mongoc/mongoc.h"

#include 
#include 
#include 
#include 

#include "php_phongo.h"
#include "phongo_apm.h"
#include "phongo_error.h"

ZEND_EXTERN_MODULE_GLOBALS(mongodb)

/* Ensures that instances of @subscriber_ce in @from (those registered with a
 * Manager or globally) are added to the set @to. This is used to build the list
 * of subscribers to notify for an event. */
static void phongo_apm_add_subscribers_to_notify(zend_class_entry* subscriber_ce, HashTable* from, HashTable* to)
{
	zval* subscriber;

	ZEND_HASH_FOREACH_VAL_IND(from, subscriber)
	{
		if (Z_TYPE_P(subscriber) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(subscriber), subscriber_ce)) {
			continue;
		}

		if (zend_hash_index_exists(to, Z_OBJ_HANDLE_P(subscriber))) {
			continue;
		}

		zend_hash_index_update(to, Z_OBJ_HANDLE_P(subscriber), subscriber);
		Z_ADDREF_P(subscriber);
	}
	ZEND_HASH_FOREACH_END();
}

/* Returns a newly allocated HashTable, which will contain all subscribers of a
 * certain type that should be notified for an event on the specified client. */
static HashTable* phongo_apm_get_subscribers_to_notify(zend_class_entry* subscriber_ce, mongoc_client_t* client)
{
	HashTable* subscribers = NULL;

	ALLOC_HASHTABLE(subscribers);
	zend_hash_init(subscribers, 0, NULL, ZVAL_PTR_DTOR, 0);

	if (MONGODB_G(subscribers)) {
		phongo_apm_add_subscribers_to_notify(subscriber_ce, MONGODB_G(subscribers), subscribers);
	}

	if (MONGODB_G(managers)) {
		php_phongo_manager_t* manager;

		ZEND_HASH_FOREACH_PTR(MONGODB_G(managers), manager)
		{
			if (manager->client == client && manager->subscribers) {
				phongo_apm_add_subscribers_to_notify(subscriber_ce, manager->subscribers, subscribers);
			}
		}
		ZEND_HASH_FOREACH_END();
	}

	return subscribers;
}

/* Search for a Manager associated with the given client in the request-scoped
 * registry. If any Manager is found, copy it to @out, increment its ref-count,
 * and return true; otherwise, set @out to undefined and return false. */
static bool phongo_apm_copy_manager_for_client(mongoc_client_t* client, zval* out)
{
	php_phongo_manager_t* manager;

	ZVAL_UNDEF(out);

	if (!MONGODB_G(managers) || zend_hash_num_elements(MONGODB_G(managers)) == 0) {
		return false;
	}

	ZEND_HASH_FOREACH_PTR(MONGODB_G(managers), manager)
	{
		if (manager->client == client) {
			ZVAL_OBJ(out, &manager->std);
			Z_ADDREF_P(out);

			return true;
		}
	}
	ZEND_HASH_FOREACH_END();

	return false;
}

/* Dispatch an event to all subscribers in a HashTable. The caller is
 * responsible for ensuring that subscribers implement the correct interface. */
static void phongo_apm_dispatch_event(HashTable* subscribers, const char* function_name, zval* event)
{
	zval* subscriber;

	ZEND_HASH_FOREACH_VAL_IND(subscribers, subscriber)
	{
		if (EG(exception)) {
			break;
		}

		/* We can't use the zend_call_method_with_1_params macro here, as it
		 * assumes the function name is a string literal. */
		zend_call_method(Z_OBJ_P(subscriber), NULL, NULL, function_name, strlen(function_name), NULL, 1, event, NULL);
	}
	ZEND_HASH_FOREACH_END();
}

static void phongo_apm_command_started(const mongoc_apm_command_started_t* event)
{
	mongoc_client_t*                  client;
	HashTable*                        subscribers;
	php_phongo_commandstartedevent_t* p_event;
	zval                              z_event;

	client      = mongoc_apm_command_started_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_commandsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_commandstartedevent_ce);
	p_event = Z_COMMANDSTARTEDEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_command_started_get_host(event), sizeof(mongoc_host_list_t));

	p_event->command_name         = estrdup(mongoc_apm_command_started_get_command_name(event));
	p_event->database_name        = estrdup(mongoc_apm_command_started_get_database_name(event));
	p_event->server_id            = mongoc_apm_command_started_get_server_id(event);
	p_event->operation_id         = mongoc_apm_command_started_get_operation_id(event);
	p_event->request_id           = mongoc_apm_command_started_get_request_id(event);
	p_event->command              = bson_copy(mongoc_apm_command_started_get_command(event));
	p_event->server_connection_id = mongoc_apm_command_started_get_server_connection_id_int64(event);
	p_event->has_service_id       = mongoc_apm_command_started_get_service_id(event) != NULL;

	if (p_event->has_service_id) {
		bson_oid_copy(mongoc_apm_command_started_get_service_id(event), &p_event->service_id);
	}

	if (!phongo_apm_copy_manager_for_client(client, &p_event->manager)) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Found no Manager for client in APM event context");
		zval_ptr_dtor(&z_event);

		goto cleanup;
	}

	phongo_apm_dispatch_event(subscribers, "commandStarted", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_command_succeeded(const mongoc_apm_command_succeeded_t* event)
{
	mongoc_client_t*                    client;
	HashTable*                          subscribers;
	php_phongo_commandsucceededevent_t* p_event;
	zval                                z_event;

	client      = mongoc_apm_command_succeeded_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_commandsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_commandsucceededevent_ce);
	p_event = Z_COMMANDSUCCEEDEDEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_command_succeeded_get_host(event), sizeof(mongoc_host_list_t));

	p_event->command_name         = estrdup(mongoc_apm_command_succeeded_get_command_name(event));
	p_event->database_name        = estrdup(mongoc_apm_command_succeeded_get_database_name(event));
	p_event->server_id            = mongoc_apm_command_succeeded_get_server_id(event);
	p_event->operation_id         = mongoc_apm_command_succeeded_get_operation_id(event);
	p_event->request_id           = mongoc_apm_command_succeeded_get_request_id(event);
	p_event->duration_micros      = mongoc_apm_command_succeeded_get_duration(event);
	p_event->reply                = bson_copy(mongoc_apm_command_succeeded_get_reply(event));
	p_event->server_connection_id = mongoc_apm_command_succeeded_get_server_connection_id_int64(event);
	p_event->has_service_id       = mongoc_apm_command_succeeded_get_service_id(event) != NULL;

	if (p_event->has_service_id) {
		bson_oid_copy(mongoc_apm_command_succeeded_get_service_id(event), &p_event->service_id);
	}

	if (!phongo_apm_copy_manager_for_client(client, &p_event->manager)) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Found no Manager for client in APM event context");
		zval_ptr_dtor(&z_event);

		goto cleanup;
	}

	phongo_apm_dispatch_event(subscribers, "commandSucceeded", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_command_failed(const mongoc_apm_command_failed_t* event)
{
	mongoc_client_t*                 client;
	HashTable*                       subscribers;
	php_phongo_commandfailedevent_t* p_event;
	zval                             z_event;
	bson_error_t                     tmp_error = { 0 };

	client      = mongoc_apm_command_failed_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_commandsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_commandfailedevent_ce);
	p_event = Z_COMMANDFAILEDEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_command_failed_get_host(event), sizeof(mongoc_host_list_t));

	p_event->command_name         = estrdup(mongoc_apm_command_failed_get_command_name(event));
	p_event->database_name        = estrdup(mongoc_apm_command_failed_get_database_name(event));
	p_event->server_id            = mongoc_apm_command_failed_get_server_id(event);
	p_event->operation_id         = mongoc_apm_command_failed_get_operation_id(event);
	p_event->request_id           = mongoc_apm_command_failed_get_request_id(event);
	p_event->duration_micros      = mongoc_apm_command_failed_get_duration(event);
	p_event->reply                = bson_copy(mongoc_apm_command_failed_get_reply(event));
	p_event->server_connection_id = mongoc_apm_command_failed_get_server_connection_id_int64(event);
	p_event->has_service_id       = mongoc_apm_command_failed_get_service_id(event) != NULL;

	if (p_event->has_service_id) {
		bson_oid_copy(mongoc_apm_command_failed_get_service_id(event), &p_event->service_id);
	}

	if (!phongo_apm_copy_manager_for_client(client, &p_event->manager)) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Found no Manager for client in APM event context");
		zval_ptr_dtor(&z_event);

		goto cleanup;
	}

	/* We need to process and convert the error right here, otherwise
	 * debug_info will turn into a recursive loop, and with the wrong trace
	 * locations */
	mongoc_apm_command_failed_get_error(event, &tmp_error);

	object_init_ex(&p_event->z_error, phongo_exception_from_mongoc_domain(tmp_error.domain, tmp_error.code));
	zend_update_property_string(zend_ce_exception, Z_OBJ_P(&p_event->z_error), ZEND_STRL("message"), tmp_error.message);
	zend_update_property_long(zend_ce_exception, Z_OBJ_P(&p_event->z_error), ZEND_STRL("code"), tmp_error.code);

	phongo_apm_dispatch_event(subscribers, "commandFailed", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_server_changed(const mongoc_apm_server_changed_t* event)
{
	mongoc_client_t*                 client;
	HashTable*                       subscribers;
	php_phongo_serverchangedevent_t* p_event;
	zval                             z_event;

	client      = mongoc_apm_server_changed_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_serverchangedevent_ce);
	p_event = Z_SERVERCHANGEDEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_server_changed_get_host(event), sizeof(mongoc_host_list_t));
	mongoc_apm_server_changed_get_topology_id(event, &p_event->topology_id);
	p_event->new_server_description = mongoc_server_description_new_copy(mongoc_apm_server_changed_get_new_description(event));
	p_event->old_server_description = mongoc_server_description_new_copy(mongoc_apm_server_changed_get_previous_description(event));

	phongo_apm_dispatch_event(subscribers, "serverChanged", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_server_closed(const mongoc_apm_server_closed_t* event)
{
	mongoc_client_t*                client;
	HashTable*                      subscribers;
	php_phongo_serverclosedevent_t* p_event;
	zval                            z_event;

	client      = mongoc_apm_server_closed_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_serverclosedevent_ce);
	p_event = Z_SERVERCLOSEDEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_server_closed_get_host(event), sizeof(mongoc_host_list_t));
	mongoc_apm_server_closed_get_topology_id(event, &p_event->topology_id);

	phongo_apm_dispatch_event(subscribers, "serverClosed", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_server_heartbeat_failed(const mongoc_apm_server_heartbeat_failed_t* event)
{
	mongoc_client_t*                         client;
	HashTable*                               subscribers;
	php_phongo_serverheartbeatfailedevent_t* p_event;
	zval                                     z_event;
	bson_error_t                             tmp_error = { 0 };

	client      = mongoc_apm_server_heartbeat_failed_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_serverheartbeatfailedevent_ce);
	p_event = Z_SERVERHEARTBEATFAILEDEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_server_heartbeat_failed_get_host(event), sizeof(mongoc_host_list_t));
	p_event->awaited         = mongoc_apm_server_heartbeat_failed_get_awaited(event);
	p_event->duration_micros = mongoc_apm_server_heartbeat_failed_get_duration(event);

	/* We need to process and convert the error right here, otherwise
	 * debug_info will turn into a recursive loop, and with the wrong trace
	 * locations */
	mongoc_apm_server_heartbeat_failed_get_error(event, &tmp_error);

	object_init_ex(&p_event->z_error, phongo_exception_from_mongoc_domain(tmp_error.domain, tmp_error.code));
	zend_update_property_string(zend_ce_exception, Z_OBJ_P(&p_event->z_error), ZEND_STRL("message"), tmp_error.message);
	zend_update_property_long(zend_ce_exception, Z_OBJ_P(&p_event->z_error), ZEND_STRL("code"), tmp_error.code);

	phongo_apm_dispatch_event(subscribers, "serverHeartbeatFailed", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_server_heartbeat_succeeded(const mongoc_apm_server_heartbeat_succeeded_t* event)
{
	mongoc_client_t*                            client;
	HashTable*                                  subscribers;
	php_phongo_serverheartbeatsucceededevent_t* p_event;
	zval                                        z_event;

	client      = mongoc_apm_server_heartbeat_succeeded_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_serverheartbeatsucceededevent_ce);
	p_event = Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_server_heartbeat_succeeded_get_host(event), sizeof(mongoc_host_list_t));
	p_event->awaited         = mongoc_apm_server_heartbeat_succeeded_get_awaited(event);
	p_event->duration_micros = mongoc_apm_server_heartbeat_succeeded_get_duration(event);
	p_event->reply           = bson_copy(mongoc_apm_server_heartbeat_succeeded_get_reply(event));

	phongo_apm_dispatch_event(subscribers, "serverHeartbeatSucceeded", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_server_heartbeat_started(const mongoc_apm_server_heartbeat_started_t* event)
{
	mongoc_client_t*                          client;
	HashTable*                                subscribers;
	php_phongo_serverheartbeatstartedevent_t* p_event;
	zval                                      z_event;

	client      = mongoc_apm_server_heartbeat_started_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_serverheartbeatstartedevent_ce);
	p_event = Z_SERVERHEARTBEATSTARTEDEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_server_heartbeat_started_get_host(event), sizeof(mongoc_host_list_t));
	p_event->awaited = mongoc_apm_server_heartbeat_started_get_awaited(event);

	phongo_apm_dispatch_event(subscribers, "serverHeartbeatStarted", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_server_opening(const mongoc_apm_server_opening_t* event)
{
	mongoc_client_t*                 client;
	HashTable*                       subscribers;
	php_phongo_serveropeningevent_t* p_event;
	zval                             z_event;

	client      = mongoc_apm_server_opening_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_serveropeningevent_ce);
	p_event = Z_SERVEROPENINGEVENT_OBJ_P(&z_event);

	memcpy(&p_event->host, mongoc_apm_server_opening_get_host(event), sizeof(mongoc_host_list_t));
	mongoc_apm_server_opening_get_topology_id(event, &p_event->topology_id);

	phongo_apm_dispatch_event(subscribers, "serverOpening", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_topology_changed(const mongoc_apm_topology_changed_t* event)
{
	mongoc_client_t*                   client;
	HashTable*                         subscribers;
	php_phongo_topologychangedevent_t* p_event;
	zval                               z_event;

	client      = mongoc_apm_topology_changed_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_topologychangedevent_ce);
	p_event = Z_TOPOLOGYCHANGEDEVENT_OBJ_P(&z_event);

	mongoc_apm_topology_changed_get_topology_id(event, &p_event->topology_id);
	p_event->new_topology_description = mongoc_topology_description_new_copy(mongoc_apm_topology_changed_get_new_description(event));
	p_event->old_topology_description = mongoc_topology_description_new_copy(mongoc_apm_topology_changed_get_previous_description(event));

	phongo_apm_dispatch_event(subscribers, "topologyChanged", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_topology_closed(const mongoc_apm_topology_closed_t* event)
{
	mongoc_client_t*                  client;
	HashTable*                        subscribers;
	php_phongo_topologyclosedevent_t* p_event;
	zval                              z_event;

	client      = mongoc_apm_topology_closed_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_topologyclosedevent_ce);
	p_event = Z_TOPOLOGYCLOSEDEVENT_OBJ_P(&z_event);

	mongoc_apm_topology_closed_get_topology_id(event, &p_event->topology_id);

	phongo_apm_dispatch_event(subscribers, "topologyClosed", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

static void phongo_apm_topology_opening(const mongoc_apm_topology_opening_t* event)
{
	mongoc_client_t*                   client;
	HashTable*                         subscribers;
	php_phongo_topologyopeningevent_t* p_event;
	zval                               z_event;

	client      = mongoc_apm_topology_opening_get_context(event);
	subscribers = phongo_apm_get_subscribers_to_notify(php_phongo_sdamsubscriber_ce, client);

	/* Return early if there are no APM subscribers to notify */
	if (zend_hash_num_elements(subscribers) == 0) {
		goto cleanup;
	}

	object_init_ex(&z_event, php_phongo_topologyopeningevent_ce);
	p_event = Z_TOPOLOGYOPENINGEVENT_OBJ_P(&z_event);

	mongoc_apm_topology_opening_get_topology_id(event, &p_event->topology_id);

	phongo_apm_dispatch_event(subscribers, "topologyOpening", &z_event);
	zval_ptr_dtor(&z_event);

cleanup:
	zend_hash_destroy(subscribers);
	FREE_HASHTABLE(subscribers);
}

/* Assigns APM callbacks to a client, which will notify any global or per-client
 * subscribers. This should be called for all clients created by the driver.
 * Returns true on success; otherwise, throws an exception and returns false. */
bool phongo_apm_set_callbacks(mongoc_client_t* client)
{
	bool retval;

	mongoc_apm_callbacks_t* callbacks = mongoc_apm_callbacks_new();

	mongoc_apm_set_command_started_cb(callbacks, phongo_apm_command_started);
	mongoc_apm_set_command_succeeded_cb(callbacks, phongo_apm_command_succeeded);
	mongoc_apm_set_command_failed_cb(callbacks, phongo_apm_command_failed);
	mongoc_apm_set_server_changed_cb(callbacks, phongo_apm_server_changed);
	mongoc_apm_set_server_closed_cb(callbacks, phongo_apm_server_closed);
	mongoc_apm_set_server_heartbeat_failed_cb(callbacks, phongo_apm_server_heartbeat_failed);
	mongoc_apm_set_server_heartbeat_succeeded_cb(callbacks, phongo_apm_server_heartbeat_succeeded);
	mongoc_apm_set_server_heartbeat_started_cb(callbacks, phongo_apm_server_heartbeat_started);
	mongoc_apm_set_server_opening_cb(callbacks, phongo_apm_server_opening);
	mongoc_apm_set_topology_changed_cb(callbacks, phongo_apm_topology_changed);
	mongoc_apm_set_topology_closed_cb(callbacks, phongo_apm_topology_closed);
	mongoc_apm_set_topology_opening_cb(callbacks, phongo_apm_topology_opening);

	retval = mongoc_client_set_apm_callbacks(client, callbacks, client);

	if (!retval) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Failed to set APM callbacks");
	}

	mongoc_apm_callbacks_destroy(callbacks);

	return retval;
}

/* Checks args for adding/removing a subscriber. Returns true on success;
 * otherwise, throws an exception and returns false. */
static bool phongo_apm_check_args_for_add_and_remove(HashTable* subscribers, zval* subscriber)
{
	if (!subscribers) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Subscriber HashTable is not initialized");
		return false;
	}

	if (!subscriber || Z_TYPE_P(subscriber) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(subscriber), php_phongo_subscriber_ce)) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Subscriber is not an instance of %s", ZSTR_VAL(php_phongo_subscriber_ce->name));
		return false;
	}

	return true;
}

/* Adds a subscriber to the HashTable (global or Manager). Returns true on
 * success (including NOP if already registered); otherwise, throws an exception
 * and returns false. */
bool phongo_apm_add_subscriber(HashTable* subscribers, zval* subscriber)
{
	if (!phongo_apm_check_args_for_add_and_remove(subscribers, subscriber)) {
		/* Exception should already have been thrown */
		return false;
	}

	/* NOP if the subscriber was already registered */
	if (zend_hash_index_exists(subscribers, Z_OBJ_HANDLE_P(subscriber))) {
		return true;
	}

	zend_hash_index_update(subscribers, Z_OBJ_HANDLE_P(subscriber), subscriber);
	Z_ADDREF_P(subscriber);

	return true;
}

/* Removes a subscriber from the HashTable (global or Manager). Returns true on
 * success (including NOP if never registered); otherwise, throws an exception
 * and returns false. */
bool phongo_apm_remove_subscriber(HashTable* subscribers, zval* subscriber)
{
	if (!phongo_apm_check_args_for_add_and_remove(subscribers, subscriber)) {
		/* Exception should already have been thrown */
		return false;
	}

	/* Note: HashTables should specify ZVAL_PTR_DTOR as their element destructor
	 * so there is no need to decrement the subscriber's reference count here.
	 * We also don't care about whether zend_hash_index_del returns SUCCESS or
	 * FAILURE, as removing an unregistered subscriber is a NOP. */
	zend_hash_index_del(subscribers, Z_OBJ_HANDLE_P(subscriber));

	return true;
}
mongodb-1.21.0/src/phongo_apm.h0000644000175100001660000000163714760300420013233 0ustar  /*
 * Copyright 2021-present MongoDB, 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.
 */

#ifndef PHONGO_APM_H
#define PHONGO_APM_H

#include "mongoc/mongoc.h"

#include 

bool phongo_apm_set_callbacks(mongoc_client_t* client);
bool phongo_apm_add_subscriber(HashTable* subscribers, zval* subscriber);
bool phongo_apm_remove_subscriber(HashTable* subscribers, zval* subscriber);

#endif /* PHONGO_APM_H */
mongodb-1.21.0/src/phongo_atomic.c0000644000175100001660000000605114760300420013720 0ustar  /*
 * Copyright 2024-present MongoDB, 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.
 */

/* Note: this file was derived from libbson's bson-atomic.c */

#include "bson/bson.h"

#include "phongo_atomic.h"

#ifdef BSON_OS_UNIX
/* For sched_yield() */
#include 
#endif

static void _thrd_yield(void)
{
	BSON_IF_WINDOWS(SwitchToThread();)
	BSON_IF_POSIX(sched_yield();)
}

/**
 * Some platforms do not support compiler intrinsics for atomic operations.
 * We emulate that here using a spin lock and regular arithmetic operations
 */
static int8_t gEmulAtomicLock = 0;

static void _lock_emul_atomic(void)
{
	int i;
	if (phongo_atomic_int8_compare_exchange_weak(&gEmulAtomicLock, 0, 1, phongo_memory_order_acquire) == 0) {
		/* Successfully took the spinlock */
		return;
	}
	/* Failed. Try taking ten more times, then begin sleeping. */
	for (i = 0; i < 10; ++i) {
		if (phongo_atomic_int8_compare_exchange_weak(&gEmulAtomicLock, 0, 1, phongo_memory_order_acquire) == 0) {
			/* Succeeded in taking the lock */
			return;
		}
	}
	/* Still don't have the lock. Spin and yield */
	while (phongo_atomic_int8_compare_exchange_weak(&gEmulAtomicLock, 0, 1, phongo_memory_order_acquire) != 0) {
		_thrd_yield();
	}
}

static void _unlock_emul_atomic(void)
{
	int64_t rv = phongo_atomic_int8_exchange(&gEmulAtomicLock, 0, phongo_memory_order_release);
	BSON_ASSERT(rv == 1 && "Released atomic lock while not holding it");
}

int32_t _phongo_emul_atomic_int32_fetch_add(volatile int32_t* p, int32_t n, enum phongo_memory_order _unused)
{
	int32_t ret;

	BSON_UNUSED(_unused);

	_lock_emul_atomic();
	ret = *p;
	*p += n;
	_unlock_emul_atomic();
	return ret;
}

int32_t _phongo_emul_atomic_int32_exchange(volatile int32_t* p, int32_t n, enum phongo_memory_order _unused)
{
	int32_t ret;

	BSON_UNUSED(_unused);

	_lock_emul_atomic();
	ret = *p;
	*p  = n;
	_unlock_emul_atomic();
	return ret;
}

int32_t _phongo_emul_atomic_int32_compare_exchange_strong(
	volatile int32_t*        p,
	int32_t                  expect_value,
	int32_t                  new_value,
	enum phongo_memory_order _unused)
{
	int32_t ret;

	BSON_UNUSED(_unused);

	_lock_emul_atomic();
	ret = *p;
	if (ret == expect_value) {
		*p = new_value;
	}
	_unlock_emul_atomic();
	return ret;
}

int32_t _phongo_emul_atomic_int32_compare_exchange_weak(
	volatile int32_t*        p,
	int32_t                  expect_value,
	int32_t                  new_value,
	enum phongo_memory_order order)
{
	/* We're emulating. We can't do a weak version. */
	return _phongo_emul_atomic_int32_compare_exchange_strong(p, expect_value, new_value, order);
}
mongodb-1.21.0/src/phongo_atomic.h0000644000175100001660000006166114760300420013735 0ustar  /*
 * Copyright 2024-present MongoDB, 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.
 */

/* Note: this file was derived from libbson's bson-atomic.h */

#ifndef PHONGO_ATOMIC_H
#define PHONGO_ATOMIC_H

#include "bson/bson.h"

#ifdef _MSC_VER
#include 
#endif

enum phongo_memory_order {
	phongo_memory_order_seq_cst,
	phongo_memory_order_acquire,
	phongo_memory_order_release,
	phongo_memory_order_relaxed,
	phongo_memory_order_acq_rel,
	phongo_memory_order_consume,
};

#if defined(_M_ARM) /* MSVC memorder atomics are only avail on ARM */
#define MSVC_MEMORDER_SUFFIX(X) X
#else
#define MSVC_MEMORDER_SUFFIX(X)
#endif

#if defined(USE_LEGACY_GCC_ATOMICS) || (!defined(__clang__) && __GNUC__ == 4) || defined(__xlC__)
#define PHONGO_USE_LEGACY_GCC_ATOMICS
#else
#undef PHONGO_USE_LEGACY_GCC_ATOMICS
#endif

/* Not all GCC-like compilers support the current __atomic built-ins.  Older
 * GCC (pre-5) used different built-ins named with the __sync prefix.  When
 * compiling with such older GCC versions, it is necessary to use the applicable
 * functions, which requires redefining BSON_IF_GNU_LIKE and defining the
 * additional PHONGO_IF_GNU_LEGACY_ATOMICS macro here. */
#ifdef PHONGO_USE_LEGACY_GCC_ATOMICS
#undef BSON_IF_GNU_LIKE
#define BSON_IF_GNU_LIKE(...)
#define BSON_IF_MSVC(...)
#define PHONGO_IF_GNU_LEGACY_ATOMICS(...) __VA_ARGS__
#else
#define PHONGO_IF_GNU_LEGACY_ATOMICS(...)
#endif

/* CDRIVER-4229 zSeries with gcc 4.8.4 produces illegal instructions for int and
 * int32 atomic intrinsics. */
#if defined(__s390__) || defined(__s390x__) || defined(__zarch__)
#define PHONGO_EMULATE_INT32
#endif

/* clang-format off */

#define DEF_ATOMIC_OP(MSVC_Intrinsic, GNU_Intrinsic, GNU_Legacy_Intrinsic, Order, ...)                 \
	do {                                                                                                \
		switch (Order) {                                                                                 \
			case phongo_memory_order_acq_rel:                                                             \
				BSON_IF_MSVC(return MSVC_Intrinsic(__VA_ARGS__);)                                          \
				BSON_IF_GNU_LIKE(return GNU_Intrinsic(__VA_ARGS__, __ATOMIC_ACQ_REL);)                     \
				PHONGO_IF_GNU_LEGACY_ATOMICS(return GNU_Legacy_Intrinsic(__VA_ARGS__);)                    \
			case phongo_memory_order_seq_cst:                                                             \
				BSON_IF_MSVC(return MSVC_Intrinsic(__VA_ARGS__);)                                          \
				BSON_IF_GNU_LIKE(return GNU_Intrinsic(__VA_ARGS__, __ATOMIC_SEQ_CST);)                     \
				PHONGO_IF_GNU_LEGACY_ATOMICS(return GNU_Legacy_Intrinsic(__VA_ARGS__);)                    \
			case phongo_memory_order_acquire:                                                             \
				BSON_IF_MSVC(return BSON_CONCAT(MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX(_acq))(__VA_ARGS__);) \
				BSON_IF_GNU_LIKE(return GNU_Intrinsic(__VA_ARGS__, __ATOMIC_ACQUIRE);)                     \
				PHONGO_IF_GNU_LEGACY_ATOMICS(return GNU_Legacy_Intrinsic(__VA_ARGS__);)                    \
			case phongo_memory_order_consume:                                                             \
				BSON_IF_MSVC(return BSON_CONCAT(MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX(_acq))(__VA_ARGS__);) \
				BSON_IF_GNU_LIKE(return GNU_Intrinsic(__VA_ARGS__, __ATOMIC_CONSUME);)                     \
				PHONGO_IF_GNU_LEGACY_ATOMICS(return GNU_Legacy_Intrinsic(__VA_ARGS__);)                    \
			case phongo_memory_order_release:                                                             \
				BSON_IF_MSVC(return BSON_CONCAT(MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX(_rel))(__VA_ARGS__);) \
				BSON_IF_GNU_LIKE(return GNU_Intrinsic(__VA_ARGS__, __ATOMIC_RELEASE);)                     \
				PHONGO_IF_GNU_LEGACY_ATOMICS(return GNU_Legacy_Intrinsic(__VA_ARGS__);)                    \
			case phongo_memory_order_relaxed:                                                             \
				BSON_IF_MSVC(return BSON_CONCAT(MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX(_nf))(__VA_ARGS__);)  \
				BSON_IF_GNU_LIKE(return GNU_Intrinsic(__VA_ARGS__, __ATOMIC_RELAXED);)                     \
				PHONGO_IF_GNU_LEGACY_ATOMICS(return GNU_Legacy_Intrinsic(__VA_ARGS__);)                    \
			default:                                                                                      \
				BSON_UNREACHABLE("Invalid phongo_memory_order value");                                     \
		}                                                                                                \
	} while (0)

#define DEF_ATOMIC_CMPEXCH_STRONG(VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue)      \
	do {                                                                                                    \
		BSON_IF_MSVC(ExpectActualVar = BSON_CONCAT3(_InterlockedCompareExchange, VCSuffix1, VCSuffix2)(      \
						 Ptr, NewValue, ExpectActualVar);)                                                       \
		BSON_IF_GNU_LIKE((void) __atomic_compare_exchange_n(Ptr,                                             \
															&ExpectActualVar,                                             \
															NewValue,                                                     \
															false, /* Not weak */                                         \
															GNU_MemOrder,                                                 \
															GNU_MemOrder);)                                               \
		PHONGO_IF_GNU_LEGACY_ATOMICS(__typeof__(ExpectActualVar) _val;                                       \
									 _val            = __sync_val_compare_and_swap(Ptr, ExpectActualVar, NewValue); \
									 ExpectActualVar = _val;)                                                       \
	} while (0)

#define DEF_ATOMIC_CMPEXCH_WEAK(VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue)        \
	do {                                                                                                    \
		BSON_IF_MSVC(ExpectActualVar = BSON_CONCAT3(_InterlockedCompareExchange, VCSuffix1, VCSuffix2)(      \
						 Ptr, NewValue, ExpectActualVar);)                                                       \
		BSON_IF_GNU_LIKE((void) __atomic_compare_exchange_n(Ptr,                                             \
															&ExpectActualVar,                                             \
															NewValue,                                                     \
															true, /* Yes weak */                                          \
															GNU_MemOrder,                                                 \
															GNU_MemOrder);)                                               \
		PHONGO_IF_GNU_LEGACY_ATOMICS(__typeof__(ExpectActualVar) _val;                                       \
									 _val            = __sync_val_compare_and_swap(Ptr, ExpectActualVar, NewValue); \
									 ExpectActualVar = _val;)                                                       \
	} while (0)

#define DECL_ATOMIC_INTEGRAL(NamePart, Type, VCIntrinSuffix)                                                            \
	static BSON_INLINE Type phongo_atomic_##NamePart##_fetch_add(                                                        \
		Type volatile* a, Type addend, enum phongo_memory_order ord)                                                      \
	{                                                                                                                    \
		DEF_ATOMIC_OP(BSON_CONCAT(_InterlockedExchangeAdd, VCIntrinSuffix),                                               \
					  __atomic_fetch_add,                                                                                    \
					  __sync_fetch_and_add,                                                                                  \
					  ord,                                                                                                   \
					  a,                                                                                                     \
					  addend);                                                                                               \
	}                                                                                                                    \
                                                                                                                        \
	static BSON_INLINE Type phongo_atomic_##NamePart##_fetch_sub(                                                        \
		Type volatile* a, Type subtrahend, enum phongo_memory_order ord)                                                  \
	{                                                                                                                    \
		/* MSVC doesn't have a subtract intrinsic, so just reuse addition    */                                           \
		BSON_IF_MSVC(return phongo_atomic_##NamePart##_fetch_add(a, -subtrahend, ord);)                                   \
		BSON_IF_GNU_LIKE(DEF_ATOMIC_OP(~, __atomic_fetch_sub, ~, ord, a, subtrahend);)                                    \
		PHONGO_IF_GNU_LEGACY_ATOMICS(DEF_ATOMIC_OP(~, ~, __sync_fetch_and_sub, ord, a, subtrahend);)                      \
	}                                                                                                                    \
                                                                                                                        \
	static BSON_INLINE Type phongo_atomic_##NamePart##_fetch(Type volatile const* a, enum phongo_memory_order order)     \
	{                                                                                                                    \
		/* MSVC doesn't have a load intrinsic, so just add zero */                                                        \
		BSON_IF_MSVC(return phongo_atomic_##NamePart##_fetch_add((Type volatile*) a, 0, order);)                          \
		/* GNU doesn't want RELEASE order for the fetch operation, so we can't                                            \
       * just use DEF_ATOMIC_OP. */                                                                                     \
		BSON_IF_GNU_LIKE(switch (order) {                                                                                 \
			case phongo_memory_order_release: /* Fall back to seqcst */                                                    \
			case phongo_memory_order_acq_rel: /* Fall back to seqcst */                                                    \
			case phongo_memory_order_seq_cst:                                                                              \
				return __atomic_load_n(a, __ATOMIC_SEQ_CST);                                                                \
			case phongo_memory_order_acquire:                                                                              \
				return __atomic_load_n(a, __ATOMIC_ACQUIRE);                                                                \
			case phongo_memory_order_consume:                                                                              \
				return __atomic_load_n(a, __ATOMIC_CONSUME);                                                                \
			case phongo_memory_order_relaxed:                                                                              \
				return __atomic_load_n(a, __ATOMIC_RELAXED);                                                                \
			default:                                                                                                       \
				BSON_UNREACHABLE("Invalid phongo_memory_order value");                                                      \
		})                                                                                                                \
		PHONGO_IF_GNU_LEGACY_ATOMICS({                                                                                    \
			BSON_UNUSED(order);                                                                                            \
			__sync_synchronize();                                                                                          \
			return *a;                                                                                                     \
		})                                                                                                                \
	}                                                                                                                    \
                                                                                                                        \
	static BSON_INLINE Type phongo_atomic_##NamePart##_exchange(                                                         \
		Type volatile* a, Type value, enum phongo_memory_order ord)                                                       \
	{                                                                                                                    \
		BSON_IF_MSVC(DEF_ATOMIC_OP(BSON_CONCAT(_InterlockedExchange, VCIntrinSuffix), ~, ~, ord, a, value);)              \
		/* GNU doesn't want CONSUME order for the exchange operation, so we                                               \
       * cannot use DEF_ATOMIC_OP. */                                                                                   \
		BSON_IF_GNU_LIKE(switch (ord) {                                                                                   \
			case phongo_memory_order_acq_rel:                                                                              \
				return __atomic_exchange_n(a, value, __ATOMIC_ACQ_REL);                                                     \
			case phongo_memory_order_release:                                                                              \
				return __atomic_exchange_n(a, value, __ATOMIC_RELEASE);                                                     \
			case phongo_memory_order_seq_cst:                                                                              \
				return __atomic_exchange_n(a, value, __ATOMIC_SEQ_CST);                                                     \
			case phongo_memory_order_consume: /* Fall back to acquire */                                                   \
			case phongo_memory_order_acquire:                                                                              \
				return __atomic_exchange_n(a, value, __ATOMIC_ACQUIRE);                                                     \
			case phongo_memory_order_relaxed:                                                                              \
				return __atomic_exchange_n(a, value, __ATOMIC_RELAXED);                                                     \
			default:                                                                                                       \
				BSON_UNREACHABLE("Invalid phongo_memory_order value");                                                      \
		})                                                                                                                \
		PHONGO_IF_GNU_LEGACY_ATOMICS(BSON_UNUSED(ord); return __sync_val_compare_and_swap(a, *a, value);)                 \
	}                                                                                                                    \
                                                                                                                        \
	static BSON_INLINE Type phongo_atomic_##NamePart##_compare_exchange_strong(                                          \
		Type volatile* a, Type expect, Type new_value, enum phongo_memory_order ord)                                      \
	{                                                                                                                    \
		Type actual = expect;                                                                                             \
		switch (ord) {                                                                                                    \
			case phongo_memory_order_release:                                                                              \
			case phongo_memory_order_acq_rel:                                                                              \
			case phongo_memory_order_seq_cst:                                                                              \
				DEF_ATOMIC_CMPEXCH_STRONG(VCIntrinSuffix, , __ATOMIC_SEQ_CST, a, actual, new_value);                        \
				break;                                                                                                      \
			case phongo_memory_order_acquire:                                                                              \
				DEF_ATOMIC_CMPEXCH_STRONG(                                                                                  \
					VCIntrinSuffix, MSVC_MEMORDER_SUFFIX(_acq), __ATOMIC_ACQUIRE, a, actual, new_value);                     \
				break;                                                                                                      \
			case phongo_memory_order_consume:                                                                              \
				DEF_ATOMIC_CMPEXCH_STRONG(                                                                                  \
					VCIntrinSuffix, MSVC_MEMORDER_SUFFIX(_acq), __ATOMIC_CONSUME, a, actual, new_value);                     \
				break;                                                                                                      \
			case phongo_memory_order_relaxed:                                                                              \
				DEF_ATOMIC_CMPEXCH_STRONG(                                                                                  \
					VCIntrinSuffix, MSVC_MEMORDER_SUFFIX(_nf), __ATOMIC_RELAXED, a, actual, new_value);                      \
				break;                                                                                                      \
			default:                                                                                                       \
				BSON_UNREACHABLE("Invalid phongo_memory_order value");                                                      \
		}                                                                                                                 \
		return actual;                                                                                                    \
	}                                                                                                                    \
                                                                                                                        \
	static BSON_INLINE Type phongo_atomic_##NamePart##_compare_exchange_weak(                                            \
		Type volatile* a, Type expect, Type new_value, enum phongo_memory_order ord)                                      \
	{                                                                                                                    \
		Type actual = expect;                                                                                             \
		switch (ord) {                                                                                                    \
			case phongo_memory_order_release:                                                                              \
			case phongo_memory_order_acq_rel:                                                                              \
			case phongo_memory_order_seq_cst:                                                                              \
				DEF_ATOMIC_CMPEXCH_WEAK(VCIntrinSuffix, , __ATOMIC_SEQ_CST, a, actual, new_value);                          \
				break;                                                                                                      \
			case phongo_memory_order_acquire:                                                                              \
				DEF_ATOMIC_CMPEXCH_WEAK(                                                                                    \
					VCIntrinSuffix, MSVC_MEMORDER_SUFFIX(_acq), __ATOMIC_ACQUIRE, a, actual, new_value);                     \
				break;                                                                                                      \
			case phongo_memory_order_consume:                                                                              \
				DEF_ATOMIC_CMPEXCH_WEAK(                                                                                    \
					VCIntrinSuffix, MSVC_MEMORDER_SUFFIX(_acq), __ATOMIC_CONSUME, a, actual, new_value);                     \
				break;                                                                                                      \
			case phongo_memory_order_relaxed:                                                                              \
				DEF_ATOMIC_CMPEXCH_WEAK(VCIntrinSuffix, MSVC_MEMORDER_SUFFIX(_nf), __ATOMIC_RELAXED, a, actual, new_value); \
				break;                                                                                                      \
			default:                                                                                                       \
				BSON_UNREACHABLE("Invalid phongo_memory_order value");                                                      \
		}                                                                                                                 \
		return actual;                                                                                                    \
	}

/* clang-format on */

#define DECL_ATOMIC_STDINT(Name, VCSuffix) DECL_ATOMIC_INTEGRAL(Name, Name##_t, VCSuffix)

#if defined(_MSC_VER) || defined(PHONGO_USE_LEGACY_GCC_ATOMICS)
/* MSVC and GCC require built-in types (not typedefs) for their atomic
 * intrinsics. */
#if defined(_MSC_VER)
#define DECL_ATOMIC_INTEGRAL_INT8 char
#define DECL_ATOMIC_INTEGRAL_INT32 long
#else
#define DECL_ATOMIC_INTEGRAL_INT8 signed char
#define DECL_ATOMIC_INTEGRAL_INT32 int
#endif
DECL_ATOMIC_INTEGRAL(int8, DECL_ATOMIC_INTEGRAL_INT8, 8)
#if !defined(PHONGO_EMULATE_INT32)
DECL_ATOMIC_INTEGRAL(int32, DECL_ATOMIC_INTEGRAL_INT32, )
#endif
#else
/* Other compilers that we support provide generic intrinsics */
DECL_ATOMIC_STDINT(int8, 8)
#if !defined(PHONGO_EMULATE_INT32)
DECL_ATOMIC_STDINT(int32, )
#endif
#endif

#ifndef DECL_ATOMIC_INTEGRAL_INT32
#define DECL_ATOMIC_INTEGRAL_INT32 int32_t
#endif

int32_t _phongo_emul_atomic_int32_fetch_add(int32_t volatile* val, int32_t v, enum phongo_memory_order);

int32_t _phongo_emul_atomic_int32_exchange(int32_t volatile* val, int32_t v, enum phongo_memory_order);

int32_t _phongo_emul_atomic_int32_compare_exchange_strong(
	int32_t volatile* val,
	int32_t           expect_value,
	int32_t           new_value,
	enum phongo_memory_order);

int32_t _phongo_emul_atomic_int32_compare_exchange_weak(
	int32_t volatile* val,
	int32_t           expect_value,
	int32_t           new_value,
	enum phongo_memory_order);

#if defined(PHONGO_EMULATE_INT32)
static BSON_INLINE int32_t phongo_atomic_int32_fetch(const int32_t volatile* val, enum phongo_memory_order order)
{
	return _phongo_emul_atomic_int32_fetch_add((int32_t volatile*) val, 0, order);
}

static BSON_INLINE int32_t phongo_atomic_int32_fetch_add(int32_t volatile* val, int32_t v, enum phongo_memory_order order)
{
	return _phongo_emul_atomic_int32_fetch_add(val, v, order);
}

static BSON_INLINE int32_t phongo_atomic_int32_fetch_sub(int32_t volatile* val, int32_t v, enum phongo_memory_order order)
{
	return _phongo_emul_atomic_int32_fetch_add(val, -v, order);
}

static BSON_INLINE int32_t phongo_atomic_int32_exchange(int32_t volatile* val, int32_t v, enum phongo_memory_order order)
{
	return _phongo_emul_atomic_int32_exchange(val, v, order);
}

static BSON_INLINE int32_t phongo_atomic_int32_compare_exchange_strong(
	int32_t volatile*        val,
	int32_t                  expect_value,
	int32_t                  new_value,
	enum phongo_memory_order order)
{
	return _phongo_emul_atomic_int32_compare_exchange_strong(val, expect_value, new_value, order);
}

static BSON_INLINE int32_t phongo_atomic_int32_compare_exchange_weak(
	int32_t volatile*        val,
	int32_t                  expect_value,
	int32_t                  new_value,
	enum phongo_memory_order order)
{
	return _phongo_emul_atomic_int32_compare_exchange_weak(val, expect_value, new_value, order);
}
#endif /* PHONGO_EMULATE_INT32 */

#undef DECL_ATOMIC_STDINT
#undef DECL_ATOMIC_INTEGRAL
#undef DEF_ATOMIC_OP
#undef DEF_ATOMIC_CMPEXCH_STRONG
#undef DEF_ATOMIC_CMPEXCH_WEAK
#undef MSVC_MEMORDER_SUFFIX

/* TODO: Redefine BSON_IF_MSVC is necessary (see: CDRIVER-5813) */
#ifdef PHONGO_USE_LEGACY_GCC_ATOMICS
#undef BSON_IF_GNU_LIKE
#define BSON_IF_GNU_LIKE(...) __VA_ARGS__
#endif
#undef PHONGO_IF_GNU_LEGACY_ATOMICS
#undef PHONGO_USE_LEGACY_GCC_ATOMICS

#undef PHONGO_EMULATE_INT32

#endif /* PHONGO_ATOMIC_H */
mongodb-1.21.0/src/phongo_bson.c0000644000175100001660000012760114760300420013412 0ustar  /*
 * Copyright 2014-present MongoDB, 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.
 */

#include "bson/bson.h"

#include 
#include 
#include 
#include 

#include "php_array_api.h"

#include "php_phongo.h"
#include "phongo_bson.h"
#include "phongo_error.h"
#include "BSON/Binary.h"
#include "BSON/DBPointer.h"
#include "BSON/Decimal128.h"
#include "BSON/Document.h"
#include "BSON/Int64.h"
#include "BSON/Javascript.h"
#include "BSON/ObjectId.h"
#include "BSON/PackedArray.h"
#include "BSON/Regex.h"
#include "BSON/Symbol.h"
#include "BSON/Timestamp.h"
#include "BSON/UTCDateTime.h"

#undef MONGOC_LOG_DOMAIN
#define MONGOC_LOG_DOMAIN "PHONGO-BSON"

#define PHONGO_BSON_STATE_ZCHILD(state) (&((php_phongo_bson_state*) (state))->zchild)

#define PHONGO_FIELD_PATH_EXPANSION 8

#define PHONGO_TYPEMAP_FIELD_STR_ARRAY "array"
#define PHONGO_TYPEMAP_FIELD_STR_DOCUMENT "document"
#define PHONGO_TYPEMAP_FIELD_STR_ROOT "root"

#define PHONGO_TYPEMAP_TYPE_STR_ARRAY "array"
#define PHONGO_TYPEMAP_TYPE_STR_BSON "bson"
#define PHONGO_TYPEMAP_TYPE_STR_OBJECT "object"
#define PHONGO_TYPEMAP_TYPE_STR_STDCLASS "stdclass"

/* Forward declarations */
static bool php_phongo_bson_visit_document(const bson_iter_t* iter ARG_UNUSED, const char* key, const bson_t* v_document, void* data);
static bool php_phongo_bson_visit_array(const bson_iter_t* iter ARG_UNUSED, const char* key, const bson_t* v_array, void* data);

static inline bool phongo_is_class_instantiatable(const zend_class_entry* ce)
{
	if (ce->ce_flags & (ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT)) {
		return false;
	}

	if (ce->ce_flags & ZEND_ACC_ENUM) {
		return false;
	}

	return true;
}

/* Path builder */
char* php_phongo_field_path_as_string(php_phongo_field_path* field_path)
{
	size_t length = 1; /* NULL character */
	size_t i;
	char*  path;
	char*  ptr;

	if (!field_path) {
		return estrdup("");
	}
	if (!field_path->elements) {
		return estrdup("");
	}

	for (i = 0; i <= field_path->size; i++) {
		if (!field_path->elements[i]) {
			continue;
		}
		length += (1 + strlen(field_path->elements[i]));
	}

	path = emalloc(length);
	ptr  = path;

	for (i = 0; i <= field_path->size; i++) {
		if (!field_path->elements[i]) {
			continue;
		}
		strcpy(ptr, field_path->elements[i]);
		ptr += strlen(field_path->elements[i]);
		ptr[0] = '.';
		ptr++;
	}
	ptr[-1] = '\0';

	return path;
}

php_phongo_field_path* php_phongo_field_path_alloc(bool owns_elements)
{
	php_phongo_field_path* tmp = ecalloc(1, sizeof(php_phongo_field_path));
	tmp->ref_count             = 1;
	tmp->owns_elements         = owns_elements;

	return tmp;
}

void php_phongo_field_path_free(php_phongo_field_path* field_path)
{
	if (field_path->owns_elements) {
		size_t i;

		for (i = 0; i < field_path->size; i++) {
			efree(field_path->elements[i]);
		}
	}
	if (field_path->elements) {
		efree(field_path->elements);
	}
	if (field_path->element_types) {
		efree(field_path->element_types);
	}
	efree(field_path);
}

static void php_phongo_field_path_ensure_allocation(php_phongo_field_path* field_path, size_t level)
{
	if (level >= field_path->allocated_size) {
		size_t i;

		field_path->allocated_size = field_path->size + PHONGO_FIELD_PATH_EXPANSION;
		field_path->elements       = erealloc(field_path->elements, sizeof(char*) * field_path->allocated_size);
		field_path->element_types  = erealloc(field_path->element_types, sizeof(php_phongo_bson_field_path_item_types) * field_path->allocated_size);

		for (i = level; i < field_path->allocated_size; i++) {
			field_path->elements[i]      = NULL;
			field_path->element_types[i] = PHONGO_FIELD_PATH_ITEM_NONE;
		}
	}
}

void php_phongo_field_path_write_item_at_current_level(php_phongo_field_path* field_path, const char* element)
{
	php_phongo_field_path_ensure_allocation(field_path, field_path->size);

	if (field_path->owns_elements) {
		/* Note: owns_elements is only used for field paths parsed from a type
		 * map, so it's unlikely that an element would already have been
		 * allocated here. This is in contrast to BSON encoding/decoding, which
		 * frequently updates the field path and does not own elements. */
		if (UNEXPECTED(field_path->elements[field_path->size])) {
			efree(field_path->elements[field_path->size]);
		}
		field_path->elements[field_path->size] = estrdup(element);
	} else {
		field_path->elements[field_path->size] = (char*) element;
	}
}

void php_phongo_field_path_write_type_at_current_level(php_phongo_field_path* field_path, php_phongo_bson_field_path_item_types element_type)
{
	php_phongo_field_path_ensure_allocation(field_path, field_path->size);

	field_path->element_types[field_path->size] = element_type;
}

bool php_phongo_field_path_push(php_phongo_field_path* field_path, const char* element, php_phongo_bson_field_path_item_types element_type)
{
	php_phongo_field_path_write_item_at_current_level(field_path, element);
	php_phongo_field_path_write_type_at_current_level(field_path, element_type);

	field_path->size++;

	return true;
}

bool php_phongo_field_path_pop(php_phongo_field_path* field_path)
{
	php_phongo_field_path_ensure_allocation(field_path, field_path->size);

	field_path->elements[field_path->size]      = NULL;
	field_path->element_types[field_path->size] = PHONGO_FIELD_PATH_ITEM_NONE;

	field_path->size--;

	field_path->elements[field_path->size]      = NULL;
	field_path->element_types[field_path->size] = PHONGO_FIELD_PATH_ITEM_NONE;

	return true;
}

inline static bool php_phongo_bson_state_is_initialized(php_phongo_bson_state* state)
{
	return state->field_path != NULL;
}

static void php_phongo_bson_state_ctor(php_phongo_bson_state* state)
{
	state->field_path = php_phongo_field_path_alloc(false);
}

static void php_phongo_bson_state_copy_ctor(php_phongo_bson_state* dst, php_phongo_bson_state* src)
{
	dst->map = src->map;
	if (src->field_path) {
		src->field_path->ref_count++;
	}
	dst->field_path = src->field_path;
}

static void php_phongo_bson_state_dtor(php_phongo_bson_state* state)
{
	if (state->field_path) {
		state->field_path->ref_count--;

		if (state->field_path->ref_count < 1) {
			php_phongo_field_path_free(state->field_path);
		}
		state->field_path = NULL;
	}
}

static void php_phongo_bson_visit_corrupt(const bson_iter_t* iter ARG_UNUSED, void* data ARG_UNUSED)
{
	mongoc_log(MONGOC_LOG_LEVEL_WARNING, MONGOC_LOG_DOMAIN, "Corrupt BSON data detected!");
}

static void php_phongo_bson_visit_unsupported_type(const bson_iter_t* iter ARG_UNUSED, const char* key, uint32_t v_type_code, void* data ARG_UNUSED)
{
	php_phongo_bson_state* state = (php_phongo_bson_state*) data;
	char*                  path_string;

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);
	path_string = php_phongo_field_path_as_string(state->field_path);

	phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Detected unknown BSON type 0x%02hhx for field path \"%s\". Are you using the latest driver?", (unsigned char) v_type_code, path_string);

	efree(path_string);
}

static bool php_phongo_bson_visit_double(const bson_iter_t* iter ARG_UNUSED, const char* key, double v_double, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;

	if (state->is_visiting_array) {
		add_next_index_double(retval, v_double);
	} else {
		add_assoc_double(retval, key, v_double);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_utf8(const bson_iter_t* iter ARG_UNUSED, const char* key, size_t v_utf8_len, const char* v_utf8, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;

	if (state->is_visiting_array) {
		ADD_NEXT_INDEX_STRINGL(retval, v_utf8, v_utf8_len);
	} else {
		ADD_ASSOC_STRING_EX(retval, key, strlen(key), v_utf8, v_utf8_len);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_binary(const bson_iter_t* iter ARG_UNUSED, const char* key, bson_subtype_t v_subtype, size_t v_binary_len, const uint8_t* v_binary, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;

	if (v_subtype == 0x80 && strcmp(key, PHONGO_ODM_FIELD_NAME) == 0) {
		zend_string*      zs_classname = zend_string_init((const char*) v_binary, v_binary_len, 0);
		zend_class_entry* found_ce     = zend_fetch_class(zs_classname, ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_SILENT);
		zend_string_release(zs_classname);

		if (found_ce && phongo_is_class_instantiatable(found_ce) && instanceof_function(found_ce, php_phongo_persistable_ce)) {
			((php_phongo_bson_state*) data)->odm_ce = found_ce;
		}
	}

	{
		zval zchild;

		if (!phongo_binary_new(&zchild, (const char*) v_binary, v_binary_len, v_subtype)) {
			return true;
		}

		if (state->is_visiting_array) {
			add_next_index_zval(retval, &zchild);
		} else {
			ADD_ASSOC_ZVAL(retval, key, &zchild);
		}
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_undefined(const bson_iter_t* iter, const char* key, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	object_init_ex(&zchild, php_phongo_undefined_ce);

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_oid(const bson_iter_t* iter ARG_UNUSED, const char* key, const bson_oid_t* v_oid, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_objectid_new(&zchild, v_oid)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_bool(const bson_iter_t* iter ARG_UNUSED, const char* key, bool v_bool, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;

	if (state->is_visiting_array) {
		add_next_index_bool(retval, v_bool);
	} else {
		add_assoc_bool(retval, key, v_bool);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_date_time(const bson_iter_t* iter ARG_UNUSED, const char* key, int64_t msec_since_epoch, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_utcdatetime_new(&zchild, msec_since_epoch)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_decimal128(const bson_iter_t* iter ARG_UNUSED, const char* key, const bson_decimal128_t* decimal, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_decimal128_new(&zchild, decimal)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_null(const bson_iter_t* iter ARG_UNUSED, const char* key, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;

	if (state->is_visiting_array) {
		add_next_index_null(retval);
	} else {
		add_assoc_null(retval, key);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_regex(const bson_iter_t* iter ARG_UNUSED, const char* key, const char* v_regex, const char* v_options, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_regex_new(&zchild, v_regex, v_options)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_symbol(const bson_iter_t* iter, const char* key, size_t v_symbol_len, const char* v_symbol, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_symbol_new(&zchild, v_symbol, v_symbol_len)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_code(const bson_iter_t* iter ARG_UNUSED, const char* key, size_t v_code_len, const char* v_code, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_javascript_new(&zchild, v_code, v_code_len, NULL)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_dbpointer(const bson_iter_t* iter, const char* key, size_t namespace_len, const char* namespace, const bson_oid_t* oid, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_dbpointer_new(&zchild, namespace, namespace_len, oid)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_codewscope(const bson_iter_t* iter ARG_UNUSED, const char* key, size_t v_code_len, const char* v_code, const bson_t* v_scope, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_javascript_new(&zchild, v_code, v_code_len, v_scope)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_int32(const bson_iter_t* iter ARG_UNUSED, const char* key, int32_t v_int32, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;

	if (state->is_visiting_array) {
		add_next_index_long(retval, v_int32);
	} else {
		add_assoc_long(retval, key, v_int32);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_timestamp(const bson_iter_t* iter ARG_UNUSED, const char* key, uint32_t v_timestamp, uint32_t v_increment, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	if (!phongo_timestamp_new(&zchild, v_increment, v_timestamp)) {
		return true;
	}

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_int64(const bson_iter_t* iter ARG_UNUSED, const char* key, int64_t v_int64, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	if (state->is_visiting_array) {
		if (state->map.int64_as_object) {
			ADD_NEXT_INDEX_INT64_OBJ(retval, v_int64);
		} else {
			ADD_NEXT_INDEX_INT64(retval, v_int64);
		}
	} else {
		if (state->map.int64_as_object) {
			ADD_ASSOC_INT64_OBJ(retval, key, v_int64);
		} else {
			ADD_ASSOC_INT64(retval, key, v_int64);
		}
	}

	return false;
}

static bool php_phongo_bson_visit_maxkey(const bson_iter_t* iter ARG_UNUSED, const char* key, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	object_init_ex(&zchild, php_phongo_maxkey_ce);

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static bool php_phongo_bson_visit_minkey(const bson_iter_t* iter ARG_UNUSED, const char* key, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	php_phongo_bson_state* state  = (php_phongo_bson_state*) data;
	zval                   zchild;

	object_init_ex(&zchild, php_phongo_minkey_ce);

	if (state->is_visiting_array) {
		add_next_index_zval(retval, &zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &zchild);
	}

	php_phongo_field_path_write_item_at_current_level(state->field_path, key);

	return false;
}

static const bson_visitor_t php_bson_visitors = {
	NULL /* php_phongo_bson_visit_before*/,
	NULL /*php_phongo_bson_visit_after*/,
	php_phongo_bson_visit_corrupt,
	php_phongo_bson_visit_double,
	php_phongo_bson_visit_utf8,
	php_phongo_bson_visit_document,
	php_phongo_bson_visit_array,
	php_phongo_bson_visit_binary,
	php_phongo_bson_visit_undefined,
	php_phongo_bson_visit_oid,
	php_phongo_bson_visit_bool,
	php_phongo_bson_visit_date_time,
	php_phongo_bson_visit_null,
	php_phongo_bson_visit_regex,
	php_phongo_bson_visit_dbpointer,
	php_phongo_bson_visit_code,
	php_phongo_bson_visit_symbol,
	php_phongo_bson_visit_codewscope,
	php_phongo_bson_visit_int32,
	php_phongo_bson_visit_timestamp,
	php_phongo_bson_visit_int64,
	php_phongo_bson_visit_maxkey,
	php_phongo_bson_visit_minkey,
	php_phongo_bson_visit_unsupported_type,
	php_phongo_bson_visit_decimal128,
	{ NULL }
};

static inline bool map_element_matches_field_path(php_phongo_field_path_map_element* map_element, php_phongo_field_path* current)
{
	size_t i;

	if (map_element->entry->size != current->size) {
		return false;
	}
	for (i = 0; i < current->size; i++) {
		if (strcmp(map_element->entry->elements[i], "$") == 0) {
			continue;
		}
		if (strcmp(map_element->entry->elements[i], current->elements[i]) != 0) {
			return false;
		}
	}
	return true;
}

static php_phongo_field_path_map_element* map_find_field_path_entry(php_phongo_bson_state* state)
{
	size_t i;

	/* Loop over all field path mappings, and for each, try to see whether it matches the current path */
	for (i = 0; i < state->map.field_paths.size; i++) {
		if (map_element_matches_field_path(state->map.field_paths.map[i], state->field_path)) {
			return state->map.field_paths.map[i];
		}
	}
	return NULL;
}

static void php_phongo_handle_field_path_entry_for_compound_type(php_phongo_bson_state* state, php_phongo_bson_typemap_element* element)
{
	php_phongo_field_path_map_element* entry = map_find_field_path_entry(state);

	if (entry) {
		state->field_type.type = entry->node.type;
		state->field_type.ce   = entry->node.ce;
	} else {
		state->field_type.type = element->type;
		state->field_type.ce   = element->ce;
	}
}

static bool php_phongo_bson_visit_document(const bson_iter_t* iter ARG_UNUSED, const char* key, const bson_t* v_document, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	bson_iter_t            child;
	php_phongo_bson_state* parent_state = (php_phongo_bson_state*) data;
	php_phongo_bson_state  state;

	php_phongo_field_path_push(parent_state->field_path, key, PHONGO_FIELD_PATH_ITEM_DOCUMENT);

	PHONGO_BSON_INIT_STATE(state);
	php_phongo_bson_state_copy_ctor(&state, parent_state);

	/* Check for entries in the fieldPath type map key, and use them to
	 * override the default ones for this type */
	php_phongo_handle_field_path_entry_for_compound_type(&state, &state.map.document);

	/* Only traverse BSON document if we're not returning a raw BSON structure */
	if (state.field_type.type != PHONGO_TYPEMAP_BSON) {
		if (!bson_iter_init(&child, v_document)) {
			php_phongo_bson_state_dtor(&state);
			return false;
		}

		array_init(&state.zchild);

		if (bson_iter_visit_all(&child, &php_bson_visitors, &state) || child.err_off) {
			/* Iteration stopped prematurely due to corruption or a failed
			 * visitor. Free state.zchild, which we just initialized, and return
			 * true to stop iteration for our parent context. */
			zval_ptr_dtor(&state.zchild);
			php_phongo_bson_state_dtor(&state);
			return true;
		}
	}

	/* If php_phongo_bson_visit_binary() finds an ODM class, it should
	 * supersede a default type map and named document class. */
	if (state.odm_ce && state.field_type.type == PHONGO_TYPEMAP_NONE) {
		state.field_type.type = PHONGO_TYPEMAP_CLASS;
	}

	switch (state.field_type.type) {
		case PHONGO_TYPEMAP_BSON: {
			php_phongo_document_t* intern;

			object_init_ex(&state.zchild, php_phongo_document_ce);

			intern       = Z_DOCUMENT_OBJ_P(&state.zchild);
			intern->bson = bson_copy(v_document);
			break;
		}

		case PHONGO_TYPEMAP_NATIVE_ARRAY:
			/* Do nothing, item will be added later */
			break;

		case PHONGO_TYPEMAP_CLASS: {
			zval              obj;
			zend_class_entry* obj_ce = state.odm_ce ? state.odm_ce : state.field_type.ce;

			object_init_ex(&obj, obj_ce);

			zend_call_method_with_1_params(Z_OBJ_P(&obj), NULL, NULL, BSON_UNSERIALIZE_FUNC_NAME, NULL, &state.zchild);
			zval_ptr_dtor(&state.zchild);
			ZVAL_COPY_VALUE(&state.zchild, &obj);

			break;
		}

		case PHONGO_TYPEMAP_NATIVE_OBJECT:
		default:
			convert_to_object(&state.zchild);
	}

	if (parent_state->is_visiting_array) {
		add_next_index_zval(retval, &state.zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &state.zchild);
	}

	php_phongo_bson_state_dtor(&state);
	php_phongo_field_path_pop(parent_state->field_path);

	return false;
}

static bool php_phongo_bson_visit_array(const bson_iter_t* iter ARG_UNUSED, const char* key, const bson_t* v_array, void* data)
{
	zval*                  retval = PHONGO_BSON_STATE_ZCHILD(data);
	bson_iter_t            child;
	php_phongo_bson_state* parent_state = (php_phongo_bson_state*) data;
	php_phongo_bson_state  state;

	php_phongo_field_path_push(parent_state->field_path, key, PHONGO_FIELD_PATH_ITEM_ARRAY);

	PHONGO_BSON_INIT_STATE(state);
	php_phongo_bson_state_copy_ctor(&state, parent_state);

	/* Check for entries in the fieldPath type map key, and use them to
	 * override the default ones for this type */
	php_phongo_handle_field_path_entry_for_compound_type(&state, &state.map.array);

	/* Only traverse BSON array if we're not returning a raw BSON structure */
	if (state.field_type.type != PHONGO_TYPEMAP_BSON) {
		if (!bson_iter_init(&child, v_array)) {
			php_phongo_bson_state_dtor(&state);
			return false;
		}

		/* Note that we are visiting an array, so element visitors know to use
		 * add_next_index() (i.e. disregard BSON keys) instead of add_assoc()
		 * when building the PHP array.
		 */
		state.is_visiting_array = true;

		array_init(&state.zchild);

		if (bson_iter_visit_all(&child, &php_bson_visitors, &state) || child.err_off) {
			/* Iteration stopped prematurely due to corruption or a failed
			 * visitor. Free state.zchild, which we just initialized, and return
			 * true to stop iteration for our parent context. */
			zval_ptr_dtor(&state.zchild);
			php_phongo_bson_state_dtor(&state);
			return true;
		}
	}

	switch (state.field_type.type) {
		case PHONGO_TYPEMAP_BSON: {
			php_phongo_packedarray_t* intern;

			object_init_ex(&state.zchild, php_phongo_packedarray_ce);

			intern       = Z_PACKEDARRAY_OBJ_P(&state.zchild);
			intern->bson = bson_copy(v_array);
			break;
		}

		case PHONGO_TYPEMAP_CLASS: {
			zval obj;

			object_init_ex(&obj, state.field_type.ce);
			zend_call_method_with_1_params(Z_OBJ_P(&obj), NULL, NULL, BSON_UNSERIALIZE_FUNC_NAME, NULL, &state.zchild);
			zval_ptr_dtor(&state.zchild);
			ZVAL_COPY_VALUE(&state.zchild, &obj);
			break;
		}

		case PHONGO_TYPEMAP_NATIVE_OBJECT:
			convert_to_object(&state.zchild);
			break;

		case PHONGO_TYPEMAP_NATIVE_ARRAY:
		default:
			/* Do nothing, will be added later */
			break;
	}

	if (parent_state->is_visiting_array) {
		add_next_index_zval(retval, &state.zchild);
	} else {
		ADD_ASSOC_ZVAL(retval, key, &state.zchild);
	}

	php_phongo_bson_state_dtor(&state);
	php_phongo_field_path_pop(parent_state->field_path);

	return false;
}

/* Converts a BSON document to a PHP value using the default typemap. */
bool php_phongo_bson_to_zval(const bson_t* b, zval* zv)
{
	bool                  retval;
	php_phongo_bson_state state;

	PHONGO_BSON_INIT_STATE(state);

	retval = php_phongo_bson_to_zval_ex(b, &state);
	ZVAL_ZVAL(zv, &state.zchild, 1, 1);

	return retval;
}

/* Converts BSON data to a PHP value using the default typemap. */
bool php_phongo_bson_data_to_zval(const unsigned char* data, int data_len, zval* zv)
{
	bool                  retval;
	php_phongo_bson_state state;

	PHONGO_BSON_INIT_STATE(state);

	retval = php_phongo_bson_data_to_zval_ex(data, data_len, &state);
	ZVAL_ZVAL(zv, &state.zchild, 1, 1);

	return retval;
}

/* Converts a BSON value to a zval, returning BSON objects and arrays as
 * standard PHP types instead of Document or PackedArray instances.
 *
 * On success, the zval will be populated and true will be returned. On error,
 * an exception will have been thrown and false will be returned. */
bool phongo_bson_value_to_zval_legacy(const bson_value_t* value, zval* zv)
{
	if (value->value_type == BSON_TYPE_ARRAY || value->value_type == BSON_TYPE_DOCUMENT) {
		bson_t                bson = BSON_INITIALIZER;
		php_phongo_bson_state state;
		zval*                 return_value;
		bool                  retval = false;

		/* Use php_phongo_bson_to_zval_ex internally to convert arrays and documents */
		PHONGO_BSON_INIT_STATE(state);
		state.map.root.type = PHONGO_TYPEMAP_NATIVE_ARRAY;

		bson_append_value(&bson, "data", 4, value);
		if (!php_phongo_bson_to_zval_ex(&bson, &state)) {
			/* Exception already thrown */
			goto cleanup;
		}

		retval = true;

		return_value = php_array_fetchc(&state.zchild, "data");

		if (return_value) {
			ZVAL_ZVAL(zv, return_value, 1, 0);
		}

	cleanup:
		zval_ptr_dtor(&state.zchild);
		return retval;
	}

	return phongo_bson_value_to_zval(value, zv);
}

/* Converts a BSON value to a zval.
 *
 * On success, the zval will be populated and true will be returned. On error,
 * an exception will have been thrown and false will be returned. */
bool phongo_bson_value_to_zval(const bson_value_t* value, zval* zv)
{
	bson_t bson = BSON_INITIALIZER;

	switch (value->value_type) {
		case BSON_TYPE_INT32:
			ZVAL_LONG(zv, value->value.v_int32);
			return true;

		case BSON_TYPE_INT64:
			phongo_int64_new(zv, value->value.v_int64);
			return true;

		case BSON_TYPE_DOUBLE:
			ZVAL_DOUBLE(zv, value->value.v_double);
			return true;

		case BSON_TYPE_BOOL:
			ZVAL_BOOL(zv, value->value.v_bool);
			return true;

		case BSON_TYPE_NULL:
			ZVAL_NULL(zv);
			return true;

		case BSON_TYPE_UTF8:
			ZVAL_STRINGL(zv, value->value.v_utf8.str, value->value.v_utf8.len);
			return true;

		case BSON_TYPE_BINARY:
			return phongo_binary_new(zv, (char*) value->value.v_binary.data, value->value.v_binary.data_len, value->value.v_binary.subtype);

		case BSON_TYPE_OID:
			return phongo_objectid_new(zv, &value->value.v_oid);

		case BSON_TYPE_DATE_TIME:
			return phongo_utcdatetime_new(zv, value->value.v_datetime);

		case BSON_TYPE_REGEX:
			return phongo_regex_new(zv, value->value.v_regex.regex, value->value.v_regex.options);

		case BSON_TYPE_DBPOINTER:
			return phongo_dbpointer_new(zv, value->value.v_dbpointer.collection, value->value.v_dbpointer.collection_len, &value->value.v_dbpointer.oid);

		case BSON_TYPE_CODE:
			return phongo_javascript_new(zv, value->value.v_code.code, value->value.v_code.code_len, NULL);

		case BSON_TYPE_CODEWSCOPE:
			if (!bson_init_static(&bson, value->value.v_codewscope.scope_data, value->value.v_codewscope.scope_len)) {
				phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Invalid BSON received for BSON_TYPE_CODEWSCOPE");
				return false;
			}

			return phongo_javascript_new(zv, value->value.v_codewscope.code, value->value.v_codewscope.code_len, &bson);

		case BSON_TYPE_SYMBOL:
			return phongo_symbol_new(zv, value->value.v_symbol.symbol, value->value.v_symbol.len);

		case BSON_TYPE_TIMESTAMP:
			return phongo_timestamp_new(zv, value->value.v_timestamp.increment, value->value.v_timestamp.timestamp);

		case BSON_TYPE_DECIMAL128:
			return phongo_decimal128_new(zv, &value->value.v_decimal128);

		case BSON_TYPE_MAXKEY:
			return object_init_ex(zv, php_phongo_maxkey_ce) == SUCCESS;

		case BSON_TYPE_MINKEY:
			return object_init_ex(zv, php_phongo_minkey_ce) == SUCCESS;

		case BSON_TYPE_EOD:
			ZVAL_NULL(zv);
			return true;

		case BSON_TYPE_UNDEFINED:
			return object_init_ex(zv, php_phongo_undefined_ce) == SUCCESS;

		case BSON_TYPE_ARRAY:
			if (!bson_init_static(&bson, value->value.v_doc.data, value->value.v_doc.data_len)) {
				phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Invalid BSON received for BSON_TYPE_ARRAY");
				return false;
			}

			return phongo_packedarray_new(zv, &bson, true);

		case BSON_TYPE_DOCUMENT:
			if (!bson_init_static(&bson, value->value.v_doc.data, value->value.v_doc.data_len)) {
				phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Invalid BSON received for BSON_TYPE_DOCUMENT");
				return false;
			}

			return phongo_document_new(zv, &bson, true);

		default:
			ZVAL_UNDEF(zv);
			phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Detected unsupported BSON type %d", value->value_type);
			return false;
	}
}

/* Converts a BSON document to a PHP value according to the typemap specified in
 * the state argument.
 *
 * On success, the result will be set on the state argument and true will be
 * returned. On error, an exception will have been thrown and false will be
 * returned.
 *
 * Note: the result zval in the state argument will always be initialized for
 * PHP 5.x so that the caller may always zval_ptr_dtor() it. The zval is left
 * as-is on PHP 7; however, it should have the type undefined if the state
 * was initialized to zero.
 */
bool php_phongo_bson_to_zval_ex(const bson_t* b, php_phongo_bson_state* state)
{
	bson_iter_t iter;
	bool        retval          = false;
	bool        must_dtor_state = false;

	if (!php_phongo_bson_state_is_initialized(state)) {
		php_phongo_bson_state_ctor(state);
		must_dtor_state = true;
	}

	// Handle BSON root type early to avoid creating an iterator and visiting elements
	if (state->map.root.type == PHONGO_TYPEMAP_BSON) {
		zval     obj;
		bson_t** bson;

		if (state->is_visiting_array) {
			object_init_ex(&obj, php_phongo_packedarray_ce);
			bson = &Z_PACKEDARRAY_OBJ_P(&obj)->bson;
		} else {
			object_init_ex(&obj, php_phongo_document_ce);
			bson = &Z_DOCUMENT_OBJ_P(&obj)->bson;
		}

		*bson = bson_copy(b);
		zval_ptr_dtor(&state->zchild);
		ZVAL_COPY_VALUE(&state->zchild, &obj);

		retval = true;
		goto cleanup;
	}

	if (!bson_iter_init(&iter, b)) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not initialize BSON iterator");

		goto cleanup;
	}

	/* We initialize an array because it will either be returned as-is (native
	 * array in type map), passed to bsonUnserialize() (ODM class), or used to
	 * initialize a stdClass object (native object in type map). */
	array_init(&state->zchild);

	if (bson_iter_visit_all(&iter, &php_bson_visitors, state) || iter.err_off) {
		/* Iteration stopped prematurely due to corruption or a failed visitor.
		 * While we free the reader, state->zchild should be left as-is, since
		 * the calling code may want to zval_ptr_dtor() it. If an exception has
		 * been thrown already (due to an unsupported BSON type for example,
		 * don't overwrite with a generic exception message. */
		if (!EG(exception)) {
			char* path = php_phongo_field_path_as_string(state->field_path);
			phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Detected corrupt BSON data for field path '%s' at offset %d", path, iter.err_off);
			efree(path);
		}

		goto cleanup;
	}

	/* If the root document is an array, default to a native array type.
	 * If php_phongo_bson_visit_binary() found an ODM class, it should supersede
	 * a default type map and named root class. */
	if (state->map.root.type == PHONGO_TYPEMAP_NONE) {
		if (state->is_visiting_array) {
			state->map.root.type = PHONGO_TYPEMAP_NATIVE_ARRAY;
		} else if (state->odm_ce) {
			state->map.root.type = PHONGO_TYPEMAP_CLASS;
		}
	}

	switch (state->map.root.type) {
		case PHONGO_TYPEMAP_NATIVE_ARRAY:
			/* Nothing to do here */
			break;

		case PHONGO_TYPEMAP_CLASS: {
			zval              obj;
			zend_class_entry* obj_ce = state->odm_ce ? state->odm_ce : state->map.root.ce;

			object_init_ex(&obj, obj_ce);

			zend_call_method_with_1_params(Z_OBJ_P(&obj), NULL, NULL, BSON_UNSERIALIZE_FUNC_NAME, NULL, &state->zchild);
			zval_ptr_dtor(&state->zchild);
			ZVAL_COPY_VALUE(&state->zchild, &obj);

			break;
		}

		case PHONGO_TYPEMAP_NATIVE_OBJECT:
		default:
			convert_to_object(&state->zchild);
	}

	retval = true;

cleanup:
	if (must_dtor_state) {
		php_phongo_bson_state_dtor(state);
	}

	return retval;
}

/* Converts a BSON document to a PHP value according to the typemap specified in
 * the state argument.
 *
 * On success, the result will be set on the state argument and true will be
 * returned. On error, an exception will have been thrown and false will be
 * returned.
 *
 * Note: the result zval in the state argument will always be initialized for
 * PHP 5.x so that the caller may always zval_ptr_dtor() it. The zval is left
 * as-is on PHP 7; however, it should have the type undefined if the state
 * was initialized to zero.
 */
bool php_phongo_bson_data_to_zval_ex(const unsigned char* data, int data_len, php_phongo_bson_state* state)
{
	bson_reader_t* reader = NULL;
	const bson_t*  b;
	bool           eof    = false;
	bool           retval = false;

	reader = bson_reader_new_from_data(data, data_len);

	if (!(b = bson_reader_read(reader, NULL))) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not read document from BSON reader");

		goto cleanup;
	}

	retval = php_phongo_bson_to_zval_ex(b, state);

	if (bson_reader_read(reader, &eof) || !eof) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Reading document did not exhaust input buffer");
		retval = false;

		goto cleanup;
	}

cleanup:
	if (reader) {
		bson_reader_destroy(reader);
	}

	return retval;
}

/* Fetches a zend_class_entry for the given class name and checks that it is
 * also instantiatable and implements a specified interface. Returns the class
 * on success; otherwise, NULL is returned and an exception is thrown. */
static zend_class_entry* php_phongo_bson_state_fetch_class(const char* classname, int classname_len, zend_class_entry* interface_ce)
{
	zend_string*      zs_classname = zend_string_init(classname, classname_len, 0);
	zend_class_entry* found_ce     = zend_fetch_class(zs_classname, ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_SILENT);
	zend_string_release(zs_classname);

	if (!found_ce) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Class %s does not exist", classname);
	} else if (!phongo_is_class_instantiatable(found_ce)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s %s is not instantiatable", zend_get_object_type_uc(found_ce), classname);
	} else if (!instanceof_function(found_ce, interface_ce)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Class %s does not implement %s", classname, ZSTR_VAL(interface_ce->name));
	} else {
		return found_ce;
	}

	return NULL;
}

/* Parses a BSON type (i.e. array, document, or root). On success, the type and
 * type_ce output arguments will be assigned and true will be returned;
 * otherwise, false is returned and an exception is thrown. */
static bool php_phongo_bson_state_parse_type(zval* options, const char* name, php_phongo_bson_typemap_element* element)
{
	char*     type;
	int       type_len;
	zend_bool type_free = 0;
	bool      retval    = true;

	type = php_array_fetch_string(options, name, &type_len, &type_free);

	if (!type_len) {
		goto cleanup;
	}

	if (!strcasecmp(type, PHONGO_TYPEMAP_TYPE_STR_ARRAY)) {
		element->type = PHONGO_TYPEMAP_NATIVE_ARRAY;
		element->ce   = NULL;
	} else if (!strcasecmp(type, PHONGO_TYPEMAP_TYPE_STR_BSON)) {
		element->type = PHONGO_TYPEMAP_BSON;
		element->ce   = NULL;
	} else if (!strcasecmp(type, PHONGO_TYPEMAP_TYPE_STR_STDCLASS) || !strcasecmp(type, PHONGO_TYPEMAP_TYPE_STR_OBJECT)) {
		element->type = PHONGO_TYPEMAP_NATIVE_OBJECT;
		element->ce   = NULL;
	} else {
		if ((element->ce = php_phongo_bson_state_fetch_class(type, type_len, php_phongo_unserializable_ce))) {
			element->type = PHONGO_TYPEMAP_CLASS;
		} else {
			/* Exception already thrown */
			retval = false;
		}
	}

cleanup:
	if (type_free) {
		efree(type);
	}

	return retval;
}

static void field_path_map_element_set_info(php_phongo_field_path_map_element* element, php_phongo_bson_typemap_element* typemap_element)
{
	element->node.type = typemap_element->type;
	element->node.ce   = typemap_element->ce;
}

static void map_add_field_path_element(php_phongo_bson_typemap* map, php_phongo_field_path_map_element* element)
{
	/* Make sure we have allocated enough */
	if (map->field_paths.allocated_size < map->field_paths.size + 1) {
		map->field_paths.allocated_size += PHONGO_FIELD_PATH_EXPANSION;
		map->field_paths.map = erealloc(map->field_paths.map, sizeof(php_phongo_field_path_map_element) * map->field_paths.allocated_size);
	}

	map->field_paths.map[map->field_paths.size] = element;
	map->field_paths.size++;
}

static php_phongo_field_path_map_element* field_path_map_element_alloc(void)
{
	php_phongo_field_path_map_element* tmp = ecalloc(1, sizeof(php_phongo_field_path_map_element));

	tmp->entry = php_phongo_field_path_alloc(true);

	return tmp;
}

static void field_path_map_element_dtor(php_phongo_field_path_map_element* element)
{
	php_phongo_field_path_free(element->entry);
	efree(element);
}

static bool php_phongo_bson_state_add_field_path(php_phongo_bson_typemap* map, char* field_path_original, php_phongo_bson_typemap_element* typemap_element)
{
	char*                              ptr         = NULL;
	char*                              segment_end = NULL;
	php_phongo_field_path_map_element* field_path_map_element;

	if (field_path_original[0] == '.') {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "A 'fieldPaths' key may not start with a '.'");
		return false;
	}

	if (field_path_original[strlen(field_path_original) - 1] == '.') {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "A 'fieldPaths' key may not end with a '.'");
		return false;
	}

	field_path_map_element = field_path_map_element_alloc();
	ptr                    = field_path_original;

	/* Loop over all the segments. A segment is delimited by a "." */
	while ((segment_end = strchr(ptr, '.')) != NULL) {
		char* tmp = NULL;

		/* Bail out if we have an empty segment */
		if (ptr == segment_end) {
			field_path_map_element_dtor(field_path_map_element);
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "A 'fieldPaths' key may not have an empty segment");
			return false;
		}

		tmp = calloc(1, segment_end - ptr + 1);
		memcpy(tmp, ptr, segment_end - ptr);
		php_phongo_field_path_push(field_path_map_element->entry, tmp, PHONGO_FIELD_PATH_ITEM_NONE);
		free(tmp);

		ptr = segment_end + 1;
	}

	/* Add the last (or single) element */
	php_phongo_field_path_push(field_path_map_element->entry, ptr, PHONGO_FIELD_PATH_ITEM_NONE);

	field_path_map_element_set_info(field_path_map_element, typemap_element);
	map_add_field_path_element(map, field_path_map_element);

	return true;
}

void php_phongo_bson_typemap_dtor(php_phongo_bson_typemap* map)
{
	size_t i;

	if (map->field_paths.map) {
		for (i = 0; i < map->field_paths.size; i++) {
			field_path_map_element_dtor(map->field_paths.map[i]);
		}
		efree(map->field_paths.map);
	}

	map->field_paths.map = NULL;
}

/* Loops over each element in the fieldPaths array (if exists, and is an
 * array), and then checks whether each element is a valid type mapping */
static bool php_phongo_bson_state_parse_fieldpaths(zval* typemap, php_phongo_bson_typemap* map)
{
	zval*      fieldpaths = NULL;
	HashTable* ht_data;

	if (!php_array_existsc(typemap, "fieldPaths")) {
		return true;
	}

	fieldpaths = php_array_fetchc_array(typemap, "fieldPaths");

	if (!fieldpaths) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "The 'fieldPaths' element is not an array");
		return false;
	}

	ht_data = HASH_OF(fieldpaths);

	{
		zend_string* string_key = NULL;
		zend_ulong   num_key    = 0;
		zval*        property;

		ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, string_key, property)
		{
			php_phongo_bson_typemap_element element;

			if (!string_key) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "The 'fieldPaths' element is not an associative array");
				return false;
			}

			if (strcmp(ZSTR_VAL(string_key), "") == 0) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "The 'fieldPaths' element may not be an empty string");
				return false;
			}

			if (!php_phongo_bson_state_parse_type(fieldpaths, ZSTR_VAL(string_key), &element)) {
				return false;
			}

			if (!php_phongo_bson_state_add_field_path(map, ZSTR_VAL(string_key), &element)) {
				return false;
			}
		}
		ZEND_HASH_FOREACH_END();
	}

	return true;
}

/* Applies the array argument to a typemap struct. Returns true on success;
 * otherwise, false is returned an an exception is thrown. */
bool php_phongo_bson_typemap_to_state(zval* typemap, php_phongo_bson_typemap* map)
{
	if (!typemap) {
		return true;
	}

	if (!php_phongo_bson_state_parse_type(typemap, PHONGO_TYPEMAP_FIELD_STR_ARRAY, &map->array) ||
		!php_phongo_bson_state_parse_type(typemap, PHONGO_TYPEMAP_FIELD_STR_DOCUMENT, &map->document) ||
		!php_phongo_bson_state_parse_type(typemap, PHONGO_TYPEMAP_FIELD_STR_ROOT, &map->root) ||
		!php_phongo_bson_state_parse_fieldpaths(typemap, map)) {

		/* Exception should already have been thrown */
		return false;
	}

	return true;
}

bool php_phongo_bson_to_json(zval* return_value, const bson_t* bson, php_phongo_json_mode_t mode)
{
	char*  json = NULL;
	size_t json_len;

	if (mode == PHONGO_JSON_MODE_LEGACY) {
		json = bson_as_legacy_extended_json(bson, &json_len);
	} else if (mode == PHONGO_JSON_MODE_CANONICAL) {
		json = bson_as_canonical_extended_json(bson, &json_len);
	} else if (mode == PHONGO_JSON_MODE_RELAXED) {
		json = bson_as_relaxed_extended_json(bson, &json_len);
	}

	if (!json) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Could not convert BSON document to a JSON string");
		return false;
	}

	ZVAL_STRINGL(return_value, json, json_len);
	bson_free(json);

	return true;
}
mongodb-1.21.0/src/phongo_bson.h0000644000175100001660000001077714760300420013424 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#ifndef PHONGO_BSON_H
#define PHONGO_BSON_H

#include "bson/bson.h"

#include 

#define BSON_UNSERIALIZE_FUNC_NAME "bsonUnserialize"
#define BSON_SERIALIZE_FUNC_NAME "bsonSerialize"
#define PHONGO_ODM_FIELD_NAME "__pclass"

typedef enum {
	PHONGO_FIELD_PATH_ITEM_NONE,
	PHONGO_FIELD_PATH_ITEM_ARRAY,
	PHONGO_FIELD_PATH_ITEM_DOCUMENT
} php_phongo_bson_field_path_item_types;

typedef struct {
	char**                                 elements;
	php_phongo_bson_field_path_item_types* element_types;
	size_t                                 allocated_size;
	size_t                                 size;
	size_t                                 ref_count;
	bool                                   owns_elements;
} php_phongo_field_path;

typedef enum {
	PHONGO_TYPEMAP_NONE,
	PHONGO_TYPEMAP_NATIVE_ARRAY,
	PHONGO_TYPEMAP_NATIVE_OBJECT,
	PHONGO_TYPEMAP_CLASS,
	PHONGO_TYPEMAP_BSON
} php_phongo_bson_typemap_types;

typedef struct {
	php_phongo_bson_typemap_types type;
	zend_class_entry*             ce;
} php_phongo_bson_typemap_element;

typedef struct {
	php_phongo_field_path*          entry;
	php_phongo_bson_typemap_element node;
} php_phongo_field_path_map_element;

typedef struct {
	php_phongo_bson_typemap_element document;
	php_phongo_bson_typemap_element array;
	php_phongo_bson_typemap_element root;
	bool                            int64_as_object;
	struct {
		php_phongo_field_path_map_element** map;
		size_t                              allocated_size;
		size_t                              size;
	} field_paths;
} php_phongo_bson_typemap;

typedef struct {
	zval                            zchild;
	php_phongo_bson_typemap         map;
	zend_class_entry*               odm_ce;
	bool                            is_visiting_array;
	php_phongo_field_path*          field_path;
	php_phongo_bson_typemap_element field_type;
} php_phongo_bson_state;

typedef enum {
	PHONGO_JSON_MODE_LEGACY,
	PHONGO_JSON_MODE_CANONICAL,
	PHONGO_JSON_MODE_RELAXED,
} php_phongo_json_mode_t;

#define PHONGO_BSON_INIT_STATE(s)                       \
	do {                                                \
		memset(&(s), 0, sizeof(php_phongo_bson_state)); \
	} while (0)

#define PHONGO_BSON_INIT_DEBUG_STATE(s)                    \
	do {                                                   \
		memset(&(s), 0, sizeof(php_phongo_bson_state));    \
		s.map.root.type     = PHONGO_TYPEMAP_NATIVE_ARRAY; \
		s.map.document.type = PHONGO_TYPEMAP_NATIVE_ARRAY; \
	} while (0)

char*                  php_phongo_field_path_as_string(php_phongo_field_path* field_path);
php_phongo_field_path* php_phongo_field_path_alloc(bool owns_elements);
void                   php_phongo_field_path_free(php_phongo_field_path* field_path);
void                   php_phongo_field_path_write_item_at_current_level(php_phongo_field_path* field_path, const char* element);
void                   php_phongo_field_path_write_type_at_current_level(php_phongo_field_path* field_path, php_phongo_bson_field_path_item_types element_type);
bool                   php_phongo_field_path_push(php_phongo_field_path* field_path, const char* element, php_phongo_bson_field_path_item_types element_type);
bool                   php_phongo_field_path_pop(php_phongo_field_path* field_path);

bool php_phongo_bson_to_json(zval* return_value, const bson_t* bson, php_phongo_json_mode_t mode);
bool php_phongo_bson_to_zval(const bson_t* b, zval* zv);
bool php_phongo_bson_to_zval_ex(const bson_t* b, php_phongo_bson_state* state);
bool php_phongo_bson_data_to_zval(const unsigned char* data, int data_len, zval* zv);
bool php_phongo_bson_data_to_zval_ex(const unsigned char* data, int data_len, php_phongo_bson_state* state);

bool phongo_bson_value_to_zval(const bson_value_t* value, zval* zv);
bool phongo_bson_value_to_zval_legacy(const bson_value_t* value, zval* zv);

bool php_phongo_bson_typemap_to_state(zval* typemap, php_phongo_bson_typemap* map);
void php_phongo_bson_typemap_dtor(php_phongo_bson_typemap* map);

#endif /* PHONGO_BSON_H */
mongodb-1.21.0/src/phongo_bson_encode.c0000644000175100001660000005754514760300420014740 0ustar  /*
 * Copyright 2014-present MongoDB, 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.
 */

#include "bson/bson.h"

#include 
#include 
#include 

#include "php_phongo.h"
#include "phongo_bson.h"
#include "phongo_bson_encode.h"
#include "phongo_compat.h"
#include "phongo_error.h"

#undef MONGOC_LOG_DOMAIN
#define MONGOC_LOG_DOMAIN "PHONGO-BSON"

#if SIZEOF_ZEND_LONG == 8
#define BSON_APPEND_INT(b, key, keylen, val)    \
	if (val > INT32_MAX || val < INT32_MIN) {   \
		bson_append_int64(b, key, keylen, val); \
	} else {                                    \
		bson_append_int32(b, key, keylen, val); \
	}
#elif SIZEOF_ZEND_LONG == 4
#define BSON_APPEND_INT(b, key, keylen, val) \
	bson_append_int32(b, key, keylen, val)
#else
#error Unsupported architecture (integers are neither 32-bit nor 64-bit)
#endif

/* Forwards declarations */
static void php_phongo_bson_append(bson_t* bson, php_phongo_field_path* field_path, php_phongo_bson_flags_t flags, const char* key, long key_len, zval* entry);
static void php_phongo_zval_to_bson_internal(zval* data, php_phongo_field_path* field_path, php_phongo_bson_flags_t flags, bson_t* bson, bson_t** bson_out);

/* Determines whether the argument should be serialized as a BSON array or
 * document. IS_ARRAY is returned if the argument's keys are a sequence of
 * integers starting at zero; otherwise, IS_OBJECT is returned. */
static int php_phongo_is_array_or_document(zval* val)
{
	HashTable* ht_data = HASH_OF(val);
	int        count;

	if (Z_TYPE_P(val) != IS_ARRAY) {
		if (Z_TYPE_P(val) == IS_OBJECT && instanceof_function(Z_OBJCE_P(val), php_phongo_packedarray_ce)) {
			return IS_ARRAY;
		}

		return IS_OBJECT;
	}

	count = ht_data ? zend_hash_num_elements(ht_data) : 0;
	if (count > 0) {
		zend_string* key;
		zend_ulong   index, idx;

		idx = 0;
		ZEND_HASH_FOREACH_KEY(ht_data, index, key)
		{
			if (key) {
				return IS_OBJECT;
			} else {
				if (index != idx) {
					return IS_OBJECT;
				}
			}
			idx++;
		}
		ZEND_HASH_FOREACH_END();
	} else {
		return Z_TYPE_P(val);
	}

	return IS_ARRAY;
}

/* Checks the return type of a bsonSerialize() method. Returns true on
 * success; otherwise, throws an exception and returns false.
 *
 * TODO: obsolete once the tentative return type in Serializable::bsonSerialize is enforced.
 */
static inline bool phongo_check_bson_serialize_return_type(zval* retval, zend_class_entry* ce)
{
	if (instanceof_function(ce, php_phongo_persistable_ce)) {
		// Instances of Persistable must return an array, stdClass, or MongoDB\BSON\Document
		if (
			Z_TYPE_P(retval) != IS_ARRAY && !(Z_TYPE_P(retval) == IS_OBJECT && (instanceof_function(Z_OBJCE_P(retval), zend_standard_class_def) || instanceof_function(Z_OBJCE_P(retval), php_phongo_document_ce)))) {
			phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE,
								   "Expected %s::%s() to return an array, stdClass, or %s, %s given",
								   ZSTR_VAL(ce->name),
								   BSON_SERIALIZE_FUNC_NAME,
								   ZSTR_VAL(php_phongo_document_ce->name),
								   zend_zval_type_name(retval));
			return false;
		}

		return true;
	}

	if (instanceof_function(ce, php_phongo_serializable_ce)) {
		// Instances of Serializable must return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray
		if (
			Z_TYPE_P(retval) != IS_ARRAY && !(Z_TYPE_P(retval) == IS_OBJECT && (instanceof_function(Z_OBJCE_P(retval), zend_standard_class_def) || instanceof_function(Z_OBJCE_P(retval), php_phongo_document_ce) || instanceof_function(Z_OBJCE_P(retval), php_phongo_packedarray_ce)))) {
			phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE,
								   "Expected %s::%s() to return an array, stdClass, %s, or %s, %s given",
								   ZSTR_VAL(ce->name),
								   BSON_SERIALIZE_FUNC_NAME,
								   ZSTR_VAL(php_phongo_document_ce->name),
								   ZSTR_VAL(php_phongo_packedarray_ce->name),
								   zend_zval_type_name(retval));
			return false;
		}

		return true;
	}

	phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE,
						   "Expected to receive instance of %s, %s given",
						   ZSTR_VAL(php_phongo_serializable_ce->name),
						   ZSTR_VAL(ce->name));
	return false;
}

/* Appends the array or object argument to the BSON document.
 *
 * For instances of MongoDB\BSON\Document, raw BSON data is appended as document.
 * For instances of MongoDB\BSON\PackedArray, raw BSON data is appended as array.
 * For instances of MongoDB\BSON\Serializable, the return value of bsonSerialize()
 * will be appended as an embedded document.
 * Other MongoDB\BSON\Type instances will be appended as the appropriate BSON
 * type.
 * Other array or object values will be appended as an embedded document.
 */
static void php_phongo_bson_append_object(bson_t* bson, php_phongo_field_path* field_path, php_phongo_bson_flags_t flags, const char* key, long key_len, zval* object)
{
	if (Z_TYPE_P(object) == IS_OBJECT && instanceof_function(Z_OBJCE_P(object), php_phongo_cursorid_ce)) {
		bson_append_int64(bson, key, key_len, Z_CURSORID_OBJ_P(object)->id);
		return;
	}

	if (Z_TYPE_P(object) == IS_OBJECT && instanceof_function(Z_OBJCE_P(object), php_phongo_type_ce)) {
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_document_ce)) {
			php_phongo_document_t* intern = Z_DOCUMENT_OBJ_P(object);
			bson_append_document(bson, key, key_len, intern->bson);

			return;
		}

		if (instanceof_function(Z_OBJCE_P(object), php_phongo_packedarray_ce)) {
			php_phongo_packedarray_t* intern = Z_PACKEDARRAY_OBJ_P(object);
			bson_append_array(bson, key, key_len, intern->bson);

			return;
		}

		if (instanceof_function(Z_OBJCE_P(object), php_phongo_serializable_ce)) {
			zval   obj_data;
			bson_t child;

			zend_call_method_with_0_params(Z_OBJ_P(object), NULL, NULL, BSON_SERIALIZE_FUNC_NAME, &obj_data);

			if (Z_ISUNDEF(obj_data)) {
				/* zend_call_method() failed or bsonSerialize() threw an
				 * exception. Either way, there is nothing else to do. */
				return;
			}

			if (!phongo_check_bson_serialize_return_type(&obj_data, Z_OBJCE_P(object))) {
				// Exception already thrown
				zval_ptr_dtor(&obj_data);
				return;
			}

			/* Persistable objects must always be serialized as BSON documents;
			 * otherwise, infer based on bsonSerialize()'s return value. */
			if (instanceof_function(Z_OBJCE_P(object), php_phongo_persistable_ce) || php_phongo_is_array_or_document(&obj_data) != IS_ARRAY) {
				bson_append_document_begin(bson, key, key_len, &child);
				if (instanceof_function(Z_OBJCE_P(object), php_phongo_persistable_ce)) {
					bson_append_binary(&child, PHONGO_ODM_FIELD_NAME, -1, 0x80, (const uint8_t*) Z_OBJCE_P(object)->name->val, Z_OBJCE_P(object)->name->len);
				}
				php_phongo_zval_to_bson_internal(&obj_data, field_path, flags, &child, NULL);
				bson_append_document_end(bson, &child);
			} else {
				bson_append_array_begin(bson, key, key_len, &child);
				php_phongo_zval_to_bson_internal(&obj_data, field_path, flags, &child, NULL);
				bson_append_array_end(bson, &child);
			}

			zval_ptr_dtor(&obj_data);
			return;
		}

		if (instanceof_function(Z_OBJCE_P(object), php_phongo_objectid_ce)) {
			bson_oid_t             oid;
			php_phongo_objectid_t* intern = Z_OBJECTID_OBJ_P(object);

			bson_oid_init_from_string(&oid, intern->oid);
			bson_append_oid(bson, key, key_len, &oid);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_utcdatetime_ce)) {
			php_phongo_utcdatetime_t* intern = Z_UTCDATETIME_OBJ_P(object);

			bson_append_date_time(bson, key, key_len, intern->milliseconds);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_binary_ce)) {
			php_phongo_binary_t* intern = Z_BINARY_OBJ_P(object);

			bson_append_binary(bson, key, key_len, intern->type, (const uint8_t*) intern->data, (uint32_t) intern->data_len);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_decimal128_ce)) {
			php_phongo_decimal128_t* intern = Z_DECIMAL128_OBJ_P(object);

			bson_append_decimal128(bson, key, key_len, &intern->decimal);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_int64_ce)) {
			php_phongo_int64_t* intern = Z_INT64_OBJ_P(object);

			bson_append_int64(bson, key, key_len, intern->integer);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_regex_ce)) {
			php_phongo_regex_t* intern = Z_REGEX_OBJ_P(object);

			bson_append_regex(bson, key, key_len, intern->pattern, intern->flags);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_javascript_ce)) {
			php_phongo_javascript_t* intern = Z_JAVASCRIPT_OBJ_P(object);

			if (intern->scope) {
				bson_append_code_with_scope(bson, key, key_len, intern->code, intern->scope);
			} else {
				bson_append_code(bson, key, key_len, intern->code);
			}
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_timestamp_ce)) {
			php_phongo_timestamp_t* intern = Z_TIMESTAMP_OBJ_P(object);

			bson_append_timestamp(bson, key, key_len, intern->timestamp, intern->increment);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_maxkey_ce)) {
			bson_append_maxkey(bson, key, key_len);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_minkey_ce)) {
			bson_append_minkey(bson, key, key_len);
			return;
		}

		/* Deprecated types */
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_dbpointer_ce)) {
			bson_oid_t              oid;
			php_phongo_dbpointer_t* intern = Z_DBPOINTER_OBJ_P(object);

			bson_oid_init_from_string(&oid, intern->id);
			bson_append_dbpointer(bson, key, key_len, intern->ref, &oid);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_symbol_ce)) {
			php_phongo_symbol_t* intern = Z_SYMBOL_OBJ_P(object);

			bson_append_symbol(bson, key, key_len, intern->symbol, intern->symbol_len);
			return;
		}
		if (instanceof_function(Z_OBJCE_P(object), php_phongo_undefined_ce)) {
			bson_append_undefined(bson, key, key_len);
			return;
		}

		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Unexpected %s instance: %s", ZSTR_VAL(php_phongo_type_ce->name), ZSTR_VAL(Z_OBJCE_P(object)->name));
		return;
	}

	if (Z_TYPE_P(object) == IS_OBJECT && Z_OBJCE_P(object)->ce_flags & ZEND_ACC_ENUM) {
		if (Z_OBJCE_P(object)->enum_backing_type == IS_UNDEF) {
			char* path_string = php_phongo_field_path_as_string(field_path);
			phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Non-backed enum %s cannot be serialized for field path \"%s\"", ZSTR_VAL(Z_OBJCE_P(object)->name), path_string);
			efree(path_string);
			return;
		}

		php_phongo_bson_append(bson, field_path, flags, key, key_len, zend_enum_fetch_case_value(Z_OBJ_P(object)));
		return;
	}

	{
		bson_t child;

		bson_append_document_begin(bson, key, key_len, &child);
		php_phongo_zval_to_bson_internal(object, field_path, flags, &child, NULL);
		bson_append_document_end(bson, &child);
	}
}

/* Appends the zval argument to the BSON document. If the argument is an object,
 * or an array that should be serialized as an embedded document, this function
 * will defer to php_phongo_bson_append_object(). */
static void php_phongo_bson_append(bson_t* bson, php_phongo_field_path* field_path, php_phongo_bson_flags_t flags, const char* key, long key_len, zval* entry)
{
	php_phongo_field_path_write_item_at_current_level(field_path, key);

try_again:
	switch (Z_TYPE_P(entry)) {
		case IS_NULL:
			bson_append_null(bson, key, key_len);
			break;
		case IS_TRUE:
			bson_append_bool(bson, key, key_len, true);
			break;

		case IS_FALSE:
			bson_append_bool(bson, key, key_len, false);
			break;

		case IS_LONG:
			BSON_APPEND_INT(bson, key, key_len, Z_LVAL_P(entry));
			break;

		case IS_DOUBLE:
			bson_append_double(bson, key, key_len, Z_DVAL_P(entry));
			break;

		case IS_STRING:
			if (bson_utf8_validate(Z_STRVAL_P(entry), Z_STRLEN_P(entry), true)) {
				bson_append_utf8(bson, key, key_len, Z_STRVAL_P(entry), Z_STRLEN_P(entry));
			} else {
				char* path_string = php_phongo_field_path_as_string(field_path);
				phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Detected invalid UTF-8 for field path \"%s\": %s", path_string, Z_STRVAL_P(entry));
				efree(path_string);
			}
			break;

		case IS_ARRAY:
			if (php_phongo_is_array_or_document(entry) == IS_ARRAY) {
				bson_t     child;
				HashTable* tmp_ht = HASH_OF(entry);

				if (!php_phongo_zend_hash_apply_protection_begin(tmp_ht)) {
					char* path_string = php_phongo_field_path_as_string(field_path);
					phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Detected recursion for field path \"%s\"", path_string);
					efree(path_string);
					break;
				}

				bson_append_array_begin(bson, key, key_len, &child);
				php_phongo_field_path_write_type_at_current_level(field_path, PHONGO_FIELD_PATH_ITEM_ARRAY);
				field_path->size++;
				php_phongo_zval_to_bson_internal(entry, field_path, flags, &child, NULL);
				field_path->size--;
				bson_append_array_end(bson, &child);

				php_phongo_zend_hash_apply_protection_end(tmp_ht);
				break;
			}
			PHONGO_BREAK_INTENTIONALLY_MISSING

		case IS_OBJECT: {
			HashTable* tmp_ht = HASH_OF(entry);

			if (!php_phongo_zend_hash_apply_protection_begin(tmp_ht)) {
				char* path_string = php_phongo_field_path_as_string(field_path);
				phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Detected recursion for field path \"%s\"", path_string);
				efree(path_string);
				break;
			}

			if (Z_TYPE_P(entry) == IS_OBJECT && instanceof_function(Z_OBJCE_P(entry), php_phongo_packedarray_ce)) {
				php_phongo_field_path_write_type_at_current_level(field_path, PHONGO_FIELD_PATH_ITEM_ARRAY);
			} else {
				php_phongo_field_path_write_type_at_current_level(field_path, PHONGO_FIELD_PATH_ITEM_DOCUMENT);
			}

			field_path->size++;
			php_phongo_bson_append_object(bson, field_path, flags, key, key_len, entry);
			field_path->size--;

			php_phongo_zend_hash_apply_protection_end(tmp_ht);
			break;
		}

		case IS_REFERENCE:
			ZVAL_DEREF(entry);
			goto try_again;

		default: {
			char* path_string = php_phongo_field_path_as_string(field_path);
			phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Detected unsupported PHP type for field path \"%s\": %d (%s)", path_string, Z_TYPE_P(entry), zend_get_type_by_const(Z_TYPE_P(entry)));
			efree(path_string);
		}
	}
}

/* This is based on bson_copy_to_excluding_noinit() and is necessary because
 * bson_copy_to() cannot be used with a bson_t allocated with bson_new(). */
static void phongo_bson_copy_to_noinit(const bson_t* src, bson_t* dst)
{
	bson_iter_t iter;

	if (bson_iter_init(&iter, src)) {
		while (bson_iter_next(&iter)) {
			if (!bson_append_iter(dst, NULL, 0, &iter)) {
				/* This should not be able to happen since we are copying from
				 * within a valid bson_t. */
				phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Error copying \"%s\" field from source document", bson_iter_key(&iter));
				return;
			}
		}
	}
}

static void php_phongo_zval_to_bson_internal(zval* data, php_phongo_field_path* field_path, php_phongo_bson_flags_t flags, bson_t* bson, bson_t** bson_out)
{
	HashTable* ht_data = NULL;
	zval       obj_data;

	/* If we will be encoding a class that may contain protected and private
	 * properties, we'll need to filter them out later. */
	bool ht_data_from_properties = false;

	/* If the object is an instance of MongoDB\BSON\Persistable, we will need to
	 * inject the PHP class name as a BSON key and ignore any existing key in
	 * the return value of bsonSerialize(). */
	bool skip_odm_field = false;

	ZVAL_UNDEF(&obj_data);

	switch (Z_TYPE_P(data)) {
		case IS_OBJECT:
			/* Short-circuit MongoDB\BSON\Document and MongoDB\BSON\PackedArray instances - copy the data */
			if (instanceof_function(Z_OBJCE_P(data), php_phongo_document_ce)) {
				php_phongo_document_t* intern = Z_DOCUMENT_OBJ_P(data);
				bson_iter_t            iter;

				phongo_bson_copy_to_noinit(intern->bson, bson);

				// Check if the document instance already has an _id field
				if (flags & PHONGO_BSON_ADD_ID && bson_iter_init_find(&iter, bson, "_id")) {
					flags &= ~PHONGO_BSON_ADD_ID;
				}

				goto done;
			}

			if (instanceof_function(Z_OBJCE_P(data), php_phongo_packedarray_ce)) {
				/* If we are at the root-level, PackedArray instances should be
				 * prohibited unless PHONGO_BSON_ALLOW_ROOT_ARRAY is set. */
				bool is_root_level = (field_path->size == 0);

				if (is_root_level && !(flags & PHONGO_BSON_ALLOW_ROOT_ARRAY)) {
					phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s cannot be serialized as a root document", ZSTR_VAL(Z_OBJCE_P(data)->name));
					return;
				}

				php_phongo_packedarray_t* intern = Z_PACKEDARRAY_OBJ_P(data);

				phongo_bson_copy_to_noinit(intern->bson, bson);

				goto done;
			}

			/* For any MongoDB\BSON\Serializable, invoke the bsonSerialize method
			 * and work with the result. */
			if (instanceof_function(Z_OBJCE_P(data), php_phongo_serializable_ce)) {
				zend_call_method_with_0_params(Z_OBJ_P(data), NULL, NULL, BSON_SERIALIZE_FUNC_NAME, &obj_data);

				if (Z_ISUNDEF(obj_data)) {
					/* zend_call_method() failed or bsonSerialize() threw an
					 * exception. Either way, there is nothing else to do. */
					return;
				}

				if (!phongo_check_bson_serialize_return_type(&obj_data, Z_OBJCE_P(data))) {
					// Exception already thrown
					goto cleanup;
				}

				if (instanceof_function(Z_OBJCE_P(data), php_phongo_persistable_ce)) {
					bson_append_binary(bson, PHONGO_ODM_FIELD_NAME, -1, 0x80, (const uint8_t*) Z_OBJCE_P(data)->name->val, Z_OBJCE_P(data)->name->len);
					/* Ensure that we ignore an existing key with the same name
					 * if one exists in the bsonSerialize() return value. */
					skip_odm_field = true;
				}

				// If bsonSerialize() returns a BSON document or packedArray instance, recurse to copy data over directly
				if (Z_TYPE(obj_data) == IS_OBJECT && (instanceof_function(Z_OBJCE(obj_data), php_phongo_document_ce) || instanceof_function(Z_OBJCE(obj_data), php_phongo_packedarray_ce))) {
					php_phongo_zval_to_bson_internal(&obj_data, field_path, flags, bson, bson_out);

					goto done;
				}

				ht_data = HASH_OF(&obj_data);

				break;
			}

			/* For the error handling that follows, we can safely assume that we
			 * are at the root level, since php_phongo_bson_append_object would
			 * have already been called for a non-root level. */
			if (Z_OBJCE_P(data)->ce_flags & ZEND_ACC_ENUM) {
				phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Enum %s cannot be serialized as a root element", ZSTR_VAL(Z_OBJCE_P(data)->name));
				return;
			}

			if (instanceof_function(Z_OBJCE_P(data), php_phongo_type_ce)) {
				phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "%s instance %s cannot be serialized as a root element", ZSTR_VAL(php_phongo_type_ce->name), ZSTR_VAL(Z_OBJCE_P(data)->name));
				return;
			}

			ht_data                 = Z_OBJ_HT_P(data)->get_properties(Z_OBJ_P(data));
			ht_data_from_properties = true;
			break;

		case IS_ARRAY:
			ht_data = HASH_OF(data);
			break;

		default:
			return;
	}

	{
		zend_string* string_key = NULL;
		zend_ulong   num_key    = 0;
		zval*        value;

		ZEND_HASH_FOREACH_KEY_VAL_IND(ht_data, num_key, string_key, value)
		{
			if (string_key) {
				if (ht_data_from_properties) {
					/* Skip protected and private properties */
					if (ZSTR_VAL(string_key)[0] == '\0' && ZSTR_LEN(string_key) > 0) {
						continue;
					}
				}

				if (strlen(ZSTR_VAL(string_key)) != ZSTR_LEN(string_key)) {
					phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "BSON keys cannot contain null bytes. Unexpected null byte after \"%s\".", ZSTR_VAL(string_key));

					goto cleanup;
				}

				if (skip_odm_field && !strcmp(ZSTR_VAL(string_key), PHONGO_ODM_FIELD_NAME)) {
					continue;
				}

				if (flags & PHONGO_BSON_ADD_ID) {
					if (!strcmp(ZSTR_VAL(string_key), "_id")) {
						flags &= ~PHONGO_BSON_ADD_ID;
					}
				}
			}

			/* Ensure we're working with a string key */
			if (!string_key) {
				string_key = zend_long_to_str(num_key);
			} else {
				zend_string_addref(string_key);
			}

			php_phongo_bson_append(bson, field_path, flags & ~PHONGO_BSON_ADD_ID, ZSTR_VAL(string_key), strlen(ZSTR_VAL(string_key)), value);

			zend_string_release(string_key);
		}
		ZEND_HASH_FOREACH_END();
	}

done:
	if (flags & PHONGO_BSON_ADD_ID) {
		bson_oid_t oid;

		bson_oid_init(&oid, NULL);
		bson_append_oid(bson, "_id", strlen("_id"), &oid);
	}

	if (flags & PHONGO_BSON_RETURN_ID && bson_out) {
		bson_iter_t iter;

		*bson_out = bson_new();

		if (bson_iter_init_find(&iter, bson, "_id") && !bson_append_iter(*bson_out, NULL, 0, &iter)) {
			/* This should not be able to happen since we are copying from
			 * within a valid bson_t. */
			phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Error copying \"_id\" field from encoded document");

			goto cleanup;
		}
	}

cleanup:
	if (!Z_ISUNDEF(obj_data)) {
		zval_ptr_dtor(&obj_data);
	}
}

/* Converts the array or object argument to a BSON document. If the object is an
 * instance of MongoDB\BSON\Serializable, the return value of bsonSerialize()
 * will be used. */
void php_phongo_zval_to_bson(zval* data, php_phongo_bson_flags_t flags, bson_t* bson, bson_t** bson_out)
{
	php_phongo_field_path* field_path = php_phongo_field_path_alloc(false);

	php_phongo_zval_to_bson_internal(data, field_path, flags, bson, bson_out);

	php_phongo_field_path_free(field_path);
}

static void phongo_zval_to_bson_value_ex(zval* data, php_phongo_bson_flags_t flags, bson_value_t* value)
{
	bson_iter_t iter;
	bson_t      bson = BSON_INITIALIZER;
	zval        data_object;

	array_init_size(&data_object, 1);
	add_assoc_zval(&data_object, "data", data);

	Z_TRY_ADDREF_P(data);

	php_phongo_zval_to_bson(&data_object, flags, &bson, NULL);

	if (bson_iter_init_find(&iter, &bson, "data")) {
		bson_value_copy(bson_iter_value(&iter), value);
	}

	bson_destroy(&bson);
	zval_ptr_dtor(&data_object);
}

/* Converts the argument to a bson_value_t. If the object is an instance of
 * MongoDB\BSON\Serializable, the return value of bsonSerialize() will be
 * used. It is the caller's responsibility to call bson_value_destroy.
 *
 * On success, the zval will be populated and true will be returned. On error,
 * an exception will have been thrown and false will be returned. */
bool phongo_zval_to_bson_value(zval* data, bson_value_t* value)
{
	zend_long lvalue;

	ZVAL_DEREF(data);

	switch (Z_TYPE_P(data)) {
		case IS_UNDEF:
		case IS_NULL:
			value->value_type = BSON_TYPE_NULL;
			return true;

		case IS_FALSE:
			value->value_type   = BSON_TYPE_BOOL;
			value->value.v_bool = false;
			return true;

		case IS_TRUE:
			value->value_type   = BSON_TYPE_BOOL;
			value->value.v_bool = true;
			return true;

		case IS_LONG:
			lvalue = Z_LVAL_P(data);

			if (lvalue > INT32_MAX || lvalue < INT32_MIN) {
				value->value_type    = BSON_TYPE_INT64;
				value->value.v_int64 = lvalue;
			} else {
				value->value_type    = BSON_TYPE_INT32;
				value->value.v_int32 = (int32_t) lvalue;
			}

			return true;

		case IS_DOUBLE:
			value->value_type     = BSON_TYPE_DOUBLE;
			value->value.v_double = Z_DVAL_P(data);
			return true;

		case IS_STRING:
			value->value_type       = BSON_TYPE_UTF8;
			value->value.v_utf8.len = Z_STRLEN_P(data);

			/* Duplicate string as bson_value_t is expected to own values */
			value->value.v_utf8.str = bson_malloc(value->value.v_utf8.len + 1);
			memcpy(value->value.v_utf8.str, Z_STRVAL_P(data), value->value.v_utf8.len);
			value->value.v_utf8.str[value->value.v_utf8.len] = '\0';
			return true;

		case IS_ARRAY:
		case IS_OBJECT:
			/* Use php_phongo_zval_to_bson internally to convert arrays and documents */
			phongo_zval_to_bson_value_ex(data, PHONGO_BSON_NONE, value);
			return true;
	}

	phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Unsupported type %s", zend_zval_type_name(data));
	return false;
}
mongodb-1.21.0/src/phongo_bson_encode.h0000644000175100001660000000226614760300420014733 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#ifndef PHONGO_BSON_ENCODE_H
#define PHONGO_BSON_ENCODE_H

#include "bson/bson.h"

#include 

typedef enum {
	PHONGO_BSON_NONE             = 0,
	PHONGO_BSON_ADD_ID           = (1 << 0),
	PHONGO_BSON_RETURN_ID        = (1 << 1),
	PHONGO_BSON_ALLOW_ROOT_ARRAY = (1 << 2)
} php_phongo_bson_flags_t;

void php_phongo_zval_to_bson(zval* data, php_phongo_bson_flags_t flags, bson_t* bson, bson_t** bson_out);
bool phongo_zval_to_bson_value(zval* data, bson_value_t* value);
void php_phongo_bson_append_zval(bson_t* bson, const char* key, long key_len, zval* value);

#endif /* PHONGO_BSON_ENCODE_H */
mongodb-1.21.0/src/phongo_classes.h0000644000175100001660000006226314760300420014115 0ustar  /*
 * Copyright 2014-present MongoDB, 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.
 */

#ifndef PHONGO_CLASSES_H
#define PHONGO_CLASSES_H

#include "phongo_structs.h"

/* Export zend_class_entry dependencies, which are initialized in MINIT */
extern zend_class_entry* php_phongo_json_serializable_ce;

static inline php_phongo_bulkwrite_t* php_bulkwrite_fetch_object(zend_object* obj)
{
	return (php_phongo_bulkwrite_t*) ((char*) obj - XtOffsetOf(php_phongo_bulkwrite_t, std));
}
static inline php_phongo_clientencryption_t* php_clientencryption_fetch_object(zend_object* obj)
{
	return (php_phongo_clientencryption_t*) ((char*) obj - XtOffsetOf(php_phongo_clientencryption_t, std));
}
static inline php_phongo_command_t* php_command_fetch_object(zend_object* obj)
{
	return (php_phongo_command_t*) ((char*) obj - XtOffsetOf(php_phongo_command_t, std));
}
static inline php_phongo_cursor_t* php_cursor_fetch_object(zend_object* obj)
{
	return (php_phongo_cursor_t*) ((char*) obj - XtOffsetOf(php_phongo_cursor_t, std));
}
static inline php_phongo_cursorid_t* php_cursorid_fetch_object(zend_object* obj)
{
	return (php_phongo_cursorid_t*) ((char*) obj - XtOffsetOf(php_phongo_cursorid_t, std));
}
static inline php_phongo_manager_t* php_manager_fetch_object(zend_object* obj)
{
	return (php_phongo_manager_t*) ((char*) obj - XtOffsetOf(php_phongo_manager_t, std));
}
static inline php_phongo_query_t* php_query_fetch_object(zend_object* obj)
{
	return (php_phongo_query_t*) ((char*) obj - XtOffsetOf(php_phongo_query_t, std));
}
static inline php_phongo_readconcern_t* php_readconcern_fetch_object(zend_object* obj)
{
	return (php_phongo_readconcern_t*) ((char*) obj - XtOffsetOf(php_phongo_readconcern_t, std));
}
static inline php_phongo_readpreference_t* php_readpreference_fetch_object(zend_object* obj)
{
	return (php_phongo_readpreference_t*) ((char*) obj - XtOffsetOf(php_phongo_readpreference_t, std));
}
static inline php_phongo_server_t* php_server_fetch_object(zend_object* obj)
{
	return (php_phongo_server_t*) ((char*) obj - XtOffsetOf(php_phongo_server_t, std));
}
static inline php_phongo_serverdescription_t* php_serverdescription_fetch_object(zend_object* obj)
{
	return (php_phongo_serverdescription_t*) ((char*) obj - XtOffsetOf(php_phongo_serverdescription_t, std));
}
static inline php_phongo_topologydescription_t* php_topologydescription_fetch_object(zend_object* obj)
{
	return (php_phongo_topologydescription_t*) ((char*) obj - XtOffsetOf(php_phongo_topologydescription_t, std));
}
static inline php_phongo_serverapi_t* php_serverapi_fetch_object(zend_object* obj)
{
	return (php_phongo_serverapi_t*) ((char*) obj - XtOffsetOf(php_phongo_serverapi_t, std));
}
static inline php_phongo_session_t* php_session_fetch_object(zend_object* obj)
{
	return (php_phongo_session_t*) ((char*) obj - XtOffsetOf(php_phongo_session_t, std));
}
static inline php_phongo_writeconcern_t* php_writeconcern_fetch_object(zend_object* obj)
{
	return (php_phongo_writeconcern_t*) ((char*) obj - XtOffsetOf(php_phongo_writeconcern_t, std));
}
static inline php_phongo_writeconcernerror_t* php_writeconcernerror_fetch_object(zend_object* obj)
{
	return (php_phongo_writeconcernerror_t*) ((char*) obj - XtOffsetOf(php_phongo_writeconcernerror_t, std));
}
static inline php_phongo_writeerror_t* php_writeerror_fetch_object(zend_object* obj)
{
	return (php_phongo_writeerror_t*) ((char*) obj - XtOffsetOf(php_phongo_writeerror_t, std));
}
static inline php_phongo_writeresult_t* php_writeresult_fetch_object(zend_object* obj)
{
	return (php_phongo_writeresult_t*) ((char*) obj - XtOffsetOf(php_phongo_writeresult_t, std));
}
static inline php_phongo_binary_t* php_binary_fetch_object(zend_object* obj)
{
	return (php_phongo_binary_t*) ((char*) obj - XtOffsetOf(php_phongo_binary_t, std));
}
static inline php_phongo_document_t* php_document_fetch_object(zend_object* obj)
{
	return (php_phongo_document_t*) ((char*) obj - XtOffsetOf(php_phongo_document_t, std));
}
static inline php_phongo_iterator_t* php_iterator_fetch_object(zend_object* obj)
{
	return (php_phongo_iterator_t*) ((char*) obj - XtOffsetOf(php_phongo_iterator_t, std));
}
static inline php_phongo_dbpointer_t* php_dbpointer_fetch_object(zend_object* obj)
{
	return (php_phongo_dbpointer_t*) ((char*) obj - XtOffsetOf(php_phongo_dbpointer_t, std));
}
static inline php_phongo_decimal128_t* php_decimal128_fetch_object(zend_object* obj)
{
	return (php_phongo_decimal128_t*) ((char*) obj - XtOffsetOf(php_phongo_decimal128_t, std));
}
static inline php_phongo_int64_t* php_int64_fetch_object(zend_object* obj)
{
	return (php_phongo_int64_t*) ((char*) obj - XtOffsetOf(php_phongo_int64_t, std));
}
static inline php_phongo_javascript_t* php_javascript_fetch_object(zend_object* obj)
{
	return (php_phongo_javascript_t*) ((char*) obj - XtOffsetOf(php_phongo_javascript_t, std));
}
static inline php_phongo_maxkey_t* php_maxkey_fetch_object(zend_object* obj)
{
	return (php_phongo_maxkey_t*) ((char*) obj - XtOffsetOf(php_phongo_maxkey_t, std));
}
static inline php_phongo_minkey_t* php_minkey_fetch_object(zend_object* obj)
{
	return (php_phongo_minkey_t*) ((char*) obj - XtOffsetOf(php_phongo_minkey_t, std));
}
static inline php_phongo_objectid_t* php_objectid_fetch_object(zend_object* obj)
{
	return (php_phongo_objectid_t*) ((char*) obj - XtOffsetOf(php_phongo_objectid_t, std));
}
static inline php_phongo_packedarray_t* php_packedarray_fetch_object(zend_object* obj)
{
	return (php_phongo_packedarray_t*) ((char*) obj - XtOffsetOf(php_phongo_packedarray_t, std));
}
static inline php_phongo_regex_t* php_regex_fetch_object(zend_object* obj)
{
	return (php_phongo_regex_t*) ((char*) obj - XtOffsetOf(php_phongo_regex_t, std));
}
static inline php_phongo_symbol_t* php_symbol_fetch_object(zend_object* obj)
{
	return (php_phongo_symbol_t*) ((char*) obj - XtOffsetOf(php_phongo_symbol_t, std));
}
static inline php_phongo_timestamp_t* php_timestamp_fetch_object(zend_object* obj)
{
	return (php_phongo_timestamp_t*) ((char*) obj - XtOffsetOf(php_phongo_timestamp_t, std));
}
static inline php_phongo_undefined_t* php_undefined_fetch_object(zend_object* obj)
{
	return (php_phongo_undefined_t*) ((char*) obj - XtOffsetOf(php_phongo_undefined_t, std));
}
static inline php_phongo_utcdatetime_t* php_utcdatetime_fetch_object(zend_object* obj)
{
	return (php_phongo_utcdatetime_t*) ((char*) obj - XtOffsetOf(php_phongo_utcdatetime_t, std));
}
static inline php_phongo_commandfailedevent_t* php_commandfailedevent_fetch_object(zend_object* obj)
{
	return (php_phongo_commandfailedevent_t*) ((char*) obj - XtOffsetOf(php_phongo_commandfailedevent_t, std));
}
static inline php_phongo_commandstartedevent_t* php_commandstartedevent_fetch_object(zend_object* obj)
{
	return (php_phongo_commandstartedevent_t*) ((char*) obj - XtOffsetOf(php_phongo_commandstartedevent_t, std));
}
static inline php_phongo_commandsucceededevent_t* php_commandsucceededevent_fetch_object(zend_object* obj)
{
	return (php_phongo_commandsucceededevent_t*) ((char*) obj - XtOffsetOf(php_phongo_commandsucceededevent_t, std));
}
static inline php_phongo_serverchangedevent_t* php_serverchangedevent_fetch_object(zend_object* obj)
{
	return (php_phongo_serverchangedevent_t*) ((char*) obj - XtOffsetOf(php_phongo_serverchangedevent_t, std));
}
static inline php_phongo_serverclosedevent_t* php_serverclosedevent_fetch_object(zend_object* obj)
{
	return (php_phongo_serverclosedevent_t*) ((char*) obj - XtOffsetOf(php_phongo_serverclosedevent_t, std));
}
static inline php_phongo_serverheartbeatfailedevent_t* php_serverheartbeatfailedevent_fetch_object(zend_object* obj)
{
	return (php_phongo_serverheartbeatfailedevent_t*) ((char*) obj - XtOffsetOf(php_phongo_serverheartbeatfailedevent_t, std));
}
static inline php_phongo_serverheartbeatstartedevent_t* php_serverheartbeatstartedevent_fetch_object(zend_object* obj)
{
	return (php_phongo_serverheartbeatstartedevent_t*) ((char*) obj - XtOffsetOf(php_phongo_serverheartbeatstartedevent_t, std));
}
static inline php_phongo_serverheartbeatsucceededevent_t* php_serverheartbeatsucceededevent_fetch_object(zend_object* obj)
{
	return (php_phongo_serverheartbeatsucceededevent_t*) ((char*) obj - XtOffsetOf(php_phongo_serverheartbeatsucceededevent_t, std));
}
static inline php_phongo_serveropeningevent_t* php_serveropeningevent_fetch_object(zend_object* obj)
{
	return (php_phongo_serveropeningevent_t*) ((char*) obj - XtOffsetOf(php_phongo_serveropeningevent_t, std));
}
static inline php_phongo_topologychangedevent_t* php_topologychangedevent_fetch_object(zend_object* obj)
{
	return (php_phongo_topologychangedevent_t*) ((char*) obj - XtOffsetOf(php_phongo_topologychangedevent_t, std));
}
static inline php_phongo_topologyclosedevent_t* php_topologyclosedevent_fetch_object(zend_object* obj)
{
	return (php_phongo_topologyclosedevent_t*) ((char*) obj - XtOffsetOf(php_phongo_topologyclosedevent_t, std));
}
static inline php_phongo_topologyopeningevent_t* php_topologyopeningevent_fetch_object(zend_object* obj)
{
	return (php_phongo_topologyopeningevent_t*) ((char*) obj - XtOffsetOf(php_phongo_topologyopeningevent_t, std));
}

#define Z_CLIENTENCRYPTION_OBJ_P(zv) (php_clientencryption_fetch_object(Z_OBJ_P(zv)))
#define Z_COMMAND_OBJ_P(zv) (php_command_fetch_object(Z_OBJ_P(zv)))
#define Z_CURSOR_OBJ_P(zv) (php_cursor_fetch_object(Z_OBJ_P(zv)))
#define Z_CURSORID_OBJ_P(zv) (php_cursorid_fetch_object(Z_OBJ_P(zv)))
#define Z_MANAGER_OBJ_P(zv) (php_manager_fetch_object(Z_OBJ_P(zv)))
#define Z_QUERY_OBJ_P(zv) (php_query_fetch_object(Z_OBJ_P(zv)))
#define Z_READCONCERN_OBJ_P(zv) (php_readconcern_fetch_object(Z_OBJ_P(zv)))
#define Z_READPREFERENCE_OBJ_P(zv) (php_readpreference_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVER_OBJ_P(zv) (php_server_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVERAPI_OBJ_P(zv) (php_serverapi_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVERDESCRIPTION_OBJ_P(zv) (php_serverdescription_fetch_object(Z_OBJ_P(zv)))
#define Z_SESSION_OBJ_P(zv) (php_session_fetch_object(Z_OBJ_P(zv)))
#define Z_TOPOLOGYDESCRIPTION_OBJ_P(zv) (php_topologydescription_fetch_object(Z_OBJ_P(zv)))
#define Z_BULKWRITE_OBJ_P(zv) (php_bulkwrite_fetch_object(Z_OBJ_P(zv)))
#define Z_WRITECONCERN_OBJ_P(zv) (php_writeconcern_fetch_object(Z_OBJ_P(zv)))
#define Z_WRITECONCERNERROR_OBJ_P(zv) (php_writeconcernerror_fetch_object(Z_OBJ_P(zv)))
#define Z_WRITEERROR_OBJ_P(zv) (php_writeerror_fetch_object(Z_OBJ_P(zv)))
#define Z_WRITERESULT_OBJ_P(zv) (php_writeresult_fetch_object(Z_OBJ_P(zv)))
#define Z_BINARY_OBJ_P(zv) (php_binary_fetch_object(Z_OBJ_P(zv)))
#define Z_DOCUMENT_OBJ_P(zv) (php_document_fetch_object(Z_OBJ_P(zv)))
#define Z_ITERATOR_OBJ_P(zv) (php_iterator_fetch_object(Z_OBJ_P(zv)))
#define Z_DBPOINTER_OBJ_P(zv) (php_dbpointer_fetch_object(Z_OBJ_P(zv)))
#define Z_DECIMAL128_OBJ_P(zv) (php_decimal128_fetch_object(Z_OBJ_P(zv)))
#define Z_INT64_OBJ_P(zv) (php_int64_fetch_object(Z_OBJ_P(zv)))
#define Z_JAVASCRIPT_OBJ_P(zv) (php_javascript_fetch_object(Z_OBJ_P(zv)))
#define Z_MAXKEY_OBJ_P(zv) (php_maxkey_fetch_object(Z_OBJ_P(zv)))
#define Z_MINKEY_OBJ_P(zv) (php_minkey_fetch_object(Z_OBJ_P(zv)))
#define Z_OBJECTID_OBJ_P(zv) (php_objectid_fetch_object(Z_OBJ_P(zv)))
#define Z_PACKEDARRAY_OBJ_P(zv) (php_packedarray_fetch_object(Z_OBJ_P(zv)))
#define Z_REGEX_OBJ_P(zv) (php_regex_fetch_object(Z_OBJ_P(zv)))
#define Z_SYMBOL_OBJ_P(zv) (php_symbol_fetch_object(Z_OBJ_P(zv)))
#define Z_TIMESTAMP_OBJ_P(zv) (php_timestamp_fetch_object(Z_OBJ_P(zv)))
#define Z_UNDEFINED_OBJ_P(zv) (php_undefined_fetch_object(Z_OBJ_P(zv)))
#define Z_UTCDATETIME_OBJ_P(zv) (php_utcdatetime_fetch_object(Z_OBJ_P(zv)))
#define Z_COMMANDFAILEDEVENT_OBJ_P(zv) (php_commandfailedevent_fetch_object(Z_OBJ_P(zv)))
#define Z_COMMANDSTARTEDEVENT_OBJ_P(zv) (php_commandstartedevent_fetch_object(Z_OBJ_P(zv)))
#define Z_COMMANDSUCCEEDEDEVENT_OBJ_P(zv) (php_commandsucceededevent_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVERCHANGEDEVENT_OBJ_P(zv) (php_serverchangedevent_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVERCLOSEDEVENT_OBJ_P(zv) (php_serverclosedevent_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVERHEARTBEATFAILEDEVENT_OBJ_P(zv) (php_serverheartbeatfailedevent_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVERHEARTBEATSTARTEDEVENT_OBJ_P(zv) (php_serverheartbeatstartedevent_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVERHEARTBEATSUCCEEDEDEVENT_OBJ_P(zv) (php_serverheartbeatsucceededevent_fetch_object(Z_OBJ_P(zv)))
#define Z_SERVEROPENINGEVENT_OBJ_P(zv) (php_serveropeningevent_fetch_object(Z_OBJ_P(zv)))
#define Z_TOPOLOGYCHANGEDEVENT_OBJ_P(zv) (php_topologychangedevent_fetch_object(Z_OBJ_P(zv)))
#define Z_TOPOLOGYCLOSEDEVENT_OBJ_P(zv) (php_topologyclosedevent_fetch_object(Z_OBJ_P(zv)))
#define Z_TOPOLOGYOPENINGEVENT_OBJ_P(zv) (php_topologyopeningevent_fetch_object(Z_OBJ_P(zv)))

#define Z_OBJ_CLIENTENCRYPTION(zo) (php_clientencryption_fetch_object(zo))
#define Z_OBJ_COMMAND(zo) (php_command_fetch_object(zo))
#define Z_OBJ_CURSOR(zo) (php_cursor_fetch_object(zo))
#define Z_OBJ_CURSORID(zo) (php_cursorid_fetch_object(zo))
#define Z_OBJ_MANAGER(zo) (php_manager_fetch_object(zo))
#define Z_OBJ_QUERY(zo) (php_query_fetch_object(zo))
#define Z_OBJ_READCONCERN(zo) (php_readconcern_fetch_object(zo))
#define Z_OBJ_READPREFERENCE(zo) (php_readpreference_fetch_object(zo))
#define Z_OBJ_SERVER(zo) (php_server_fetch_object(zo))
#define Z_OBJ_SERVERAPI(zo) (php_serverapi_fetch_object(zo))
#define Z_OBJ_SERVERDESCRIPTION(zo) (php_serverdescription_fetch_object(zo))
#define Z_OBJ_SESSION(zo) (php_session_fetch_object(zo))
#define Z_OBJ_TOPOLOGYDESCRIPTION(zo) (php_topologydescription_fetch_object(zo))
#define Z_OBJ_BULKWRITE(zo) (php_bulkwrite_fetch_object(zo))
#define Z_OBJ_WRITECONCERN(zo) (php_writeconcern_fetch_object(zo))
#define Z_OBJ_WRITECONCERNERROR(zo) (php_writeconcernerror_fetch_object(zo))
#define Z_OBJ_WRITEERROR(zo) (php_writeerror_fetch_object(zo))
#define Z_OBJ_WRITERESULT(zo) (php_writeresult_fetch_object(zo))
#define Z_OBJ_BINARY(zo) (php_binary_fetch_object(zo))
#define Z_OBJ_DOCUMENT(zo) (php_document_fetch_object(zo))
#define Z_OBJ_ITERATOR(zo) (php_iterator_fetch_object(zo))
#define Z_OBJ_DBPOINTER(zo) (php_dbpointer_fetch_object(zo))
#define Z_OBJ_DECIMAL128(zo) (php_decimal128_fetch_object(zo))
#define Z_OBJ_INT64(zo) (php_int64_fetch_object(zo))
#define Z_OBJ_JAVASCRIPT(zo) (php_javascript_fetch_object(zo))
#define Z_OBJ_MAXKEY(zo) (php_maxkey_fetch_object(zo))
#define Z_OBJ_MINKEY(zo) (php_minkey_fetch_object(zo))
#define Z_OBJ_OBJECTID(zo) (php_objectid_fetch_object(zo))
#define Z_OBJ_PACKEDARRAY(zo) (php_packedarray_fetch_object(zo))
#define Z_OBJ_REGEX(zo) (php_regex_fetch_object(zo))
#define Z_OBJ_SYMBOL(zo) (php_symbol_fetch_object(zo))
#define Z_OBJ_TIMESTAMP(zo) (php_timestamp_fetch_object(zo))
#define Z_OBJ_UNDEFINED(zo) (php_undefined_fetch_object(zo))
#define Z_OBJ_UTCDATETIME(zo) (php_utcdatetime_fetch_object(zo))
#define Z_OBJ_COMMANDFAILEDEVENT(zo) (php_commandfailedevent_fetch_object(zo))
#define Z_OBJ_COMMANDSTARTEDEVENT(zo) (php_commandstartedevent_fetch_object(zo))
#define Z_OBJ_COMMANDSUCCEEDEDEVENT(zo) (php_commandsucceededevent_fetch_object(zo))
#define Z_OBJ_SERVERCHANGEDEVENT(zo) (php_serverchangedevent_fetch_object(zo))
#define Z_OBJ_SERVERCLOSEDEVENT(zo) (php_serverclosedevent_fetch_object(zo))
#define Z_OBJ_SERVERHEARTBEATFAILEDEVENT(zo) (php_serverheartbeatfailedevent_fetch_object(zo))
#define Z_OBJ_SERVERHEARTBEATSTARTEDEVENT(zo) (php_serverheartbeatstartedevent_fetch_object(zo))
#define Z_OBJ_SERVERHEARTBEATSUCCEEDEDEVENT(zo) (php_serverheartbeatsucceededevent_fetch_object(zo))
#define Z_OBJ_SERVEROPENINGEVENT(zo) (php_serveropeningevent_fetch_object(zo))
#define Z_OBJ_TOPOLOGYCHANGEDEVENT(zo) (php_topologychangedevent_fetch_object(zo))
#define Z_OBJ_TOPOLOGYCLOSEDEVENT(zo) (php_topologyclosedevent_fetch_object(zo))
#define Z_OBJ_TOPOLOGYOPENINGEVENT(zo) (php_topologyopeningevent_fetch_object(zo))

extern zend_class_entry* php_phongo_clientencryption_ce;
extern zend_class_entry* php_phongo_command_ce;
extern zend_class_entry* php_phongo_cursor_ce;
extern zend_class_entry* php_phongo_cursorid_ce;
extern zend_class_entry* php_phongo_manager_ce;
extern zend_class_entry* php_phongo_query_ce;
extern zend_class_entry* php_phongo_readconcern_ce;
extern zend_class_entry* php_phongo_readpreference_ce;
extern zend_class_entry* php_phongo_server_ce;
extern zend_class_entry* php_phongo_serverapi_ce;
extern zend_class_entry* php_phongo_serverdescription_ce;
extern zend_class_entry* php_phongo_session_ce;
extern zend_class_entry* php_phongo_topologydescription_ce;
extern zend_class_entry* php_phongo_bulkwrite_ce;
extern zend_class_entry* php_phongo_writeconcern_ce;
extern zend_class_entry* php_phongo_writeconcernerror_ce;
extern zend_class_entry* php_phongo_writeerror_ce;
extern zend_class_entry* php_phongo_writeresult_ce;

extern zend_class_entry* php_phongo_cursor_interface_ce;

extern zend_class_entry* php_phongo_exception_ce;
extern zend_class_entry* php_phongo_logicexception_ce;
extern zend_class_entry* php_phongo_runtimeexception_ce;
extern zend_class_entry* php_phongo_serverexception_ce;
extern zend_class_entry* php_phongo_commandexception_ce;
extern zend_class_entry* php_phongo_unexpectedvalueexception_ce;
extern zend_class_entry* php_phongo_invalidargumentexception_ce;
extern zend_class_entry* php_phongo_connectionexception_ce;
extern zend_class_entry* php_phongo_authenticationexception_ce;
extern zend_class_entry* php_phongo_sslconnectionexception_ce;
extern zend_class_entry* php_phongo_encryptionexception_ce;
extern zend_class_entry* php_phongo_executiontimeoutexception_ce;
extern zend_class_entry* php_phongo_connectiontimeoutexception_ce;
extern zend_class_entry* php_phongo_writeexception_ce;
extern zend_class_entry* php_phongo_bulkwriteexception_ce;

extern zend_class_entry* php_phongo_type_ce;
extern zend_class_entry* php_phongo_persistable_ce;
extern zend_class_entry* php_phongo_unserializable_ce;
extern zend_class_entry* php_phongo_serializable_ce;
extern zend_class_entry* php_phongo_binary_ce;
extern zend_class_entry* php_phongo_document_ce;
extern zend_class_entry* php_phongo_iterator_ce;
extern zend_class_entry* php_phongo_dbpointer_ce;
extern zend_class_entry* php_phongo_decimal128_ce;
extern zend_class_entry* php_phongo_int64_ce;
extern zend_class_entry* php_phongo_javascript_ce;
extern zend_class_entry* php_phongo_maxkey_ce;
extern zend_class_entry* php_phongo_minkey_ce;
extern zend_class_entry* php_phongo_objectid_ce;
extern zend_class_entry* php_phongo_packedarray_ce;
extern zend_class_entry* php_phongo_regex_ce;
extern zend_class_entry* php_phongo_symbol_ce;
extern zend_class_entry* php_phongo_timestamp_ce;
extern zend_class_entry* php_phongo_undefined_ce;
extern zend_class_entry* php_phongo_utcdatetime_ce;

extern zend_class_entry* php_phongo_binary_interface_ce;
extern zend_class_entry* php_phongo_decimal128_interface_ce;
extern zend_class_entry* php_phongo_javascript_interface_ce;
extern zend_class_entry* php_phongo_maxkey_interface_ce;
extern zend_class_entry* php_phongo_minkey_interface_ce;
extern zend_class_entry* php_phongo_objectid_interface_ce;
extern zend_class_entry* php_phongo_regex_interface_ce;
extern zend_class_entry* php_phongo_timestamp_interface_ce;
extern zend_class_entry* php_phongo_utcdatetime_interface_ce;

extern zend_class_entry* php_phongo_commandfailedevent_ce;
extern zend_class_entry* php_phongo_commandstartedevent_ce;
extern zend_class_entry* php_phongo_commandsubscriber_ce;
extern zend_class_entry* php_phongo_commandsucceededevent_ce;
extern zend_class_entry* php_phongo_logsubscriber_ce;
extern zend_class_entry* php_phongo_sdamsubscriber_ce;
extern zend_class_entry* php_phongo_subscriber_ce;
extern zend_class_entry* php_phongo_serverchangedevent_ce;
extern zend_class_entry* php_phongo_serverclosedevent_ce;
extern zend_class_entry* php_phongo_serverheartbeatfailedevent_ce;
extern zend_class_entry* php_phongo_serverheartbeatstartedevent_ce;
extern zend_class_entry* php_phongo_serverheartbeatsucceededevent_ce;
extern zend_class_entry* php_phongo_serveropeningevent_ce;
extern zend_class_entry* php_phongo_topologychangedevent_ce;
extern zend_class_entry* php_phongo_topologyclosedevent_ce;
extern zend_class_entry* php_phongo_topologyopeningevent_ce;

extern void php_phongo_binary_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_packedarray_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_document_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_iterator_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_dbpointer_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_decimal128_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_int64_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_javascript_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_maxkey_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_minkey_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_objectid_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_persistable_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_regex_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serializable_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_symbol_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_timestamp_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_type_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_undefined_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_unserializable_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_utcdatetime_init_ce(INIT_FUNC_ARGS);

extern void php_phongo_binary_interface_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_decimal128_interface_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_javascript_interface_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_maxkey_interface_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_minkey_interface_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_objectid_interface_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_regex_interface_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_timestamp_interface_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_utcdatetime_interface_init_ce(INIT_FUNC_ARGS);

extern void php_phongo_bulkwrite_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_clientencryption_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_command_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_cursor_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_cursorid_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_manager_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_query_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_readconcern_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_readpreference_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_server_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serverapi_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serverdescription_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_session_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_topologydescription_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_writeconcern_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_writeconcernerror_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_writeerror_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_writeresult_init_ce(INIT_FUNC_ARGS);

extern void php_phongo_cursor_interface_init_ce(INIT_FUNC_ARGS);

extern void php_phongo_authenticationexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_bulkwriteexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_commandexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_connectionexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_connectiontimeoutexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_encryptionexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_exception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_executiontimeoutexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_invalidargumentexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_logicexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_runtimeexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serverexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_sslconnectionexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_unexpectedvalueexception_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_writeexception_init_ce(INIT_FUNC_ARGS);

extern void php_phongo_commandfailedevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_commandstartedevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_commandsubscriber_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_commandsucceededevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_logsubscriber_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_sdamsubscriber_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_subscriber_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serverchangedevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serverclosedevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serverheartbeatfailedevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serverheartbeatstartedevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serverheartbeatsucceededevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_serveropeningevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_topologychangedevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_topologyclosedevent_init_ce(INIT_FUNC_ARGS);
extern void php_phongo_topologyopeningevent_init_ce(INIT_FUNC_ARGS);

#endif /* PHONGO_CLASSES_H */
mongodb-1.21.0/src/phongo_client.c0000644000175100001660000015337414760300420013735 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#include "bson/bson.h"
#include "mongoc/mongoc.h"

#include 
#include 
#include 

#include "php_array_api.h"

#include "php_phongo.h"
#include "phongo_apm.h"
#include "phongo_bson_encode.h"
#include "phongo_client.h"
#include "phongo_error.h"
#include "phongo_util.h"

#include "MongoDB/ReadPreference.h"
#include "MongoDB/WriteConcern.h"

ZEND_EXTERN_MODULE_GLOBALS(mongodb)

#define PHONGO_METADATA_SEPARATOR " / "
#define PHONGO_METADATA_SEPARATOR_LEN (sizeof(PHONGO_METADATA_SEPARATOR) - 1)
#define PHONGO_METADATA_PHP_VERSION_PREFIX "PHP "
#define PHONGO_METADATA_PHP_VERSION_PREFIX_LEN (sizeof(PHONGO_METADATA_PHP_VERSION_PREFIX) - 1)

/* Structure for tracking libmongoc clients (both persisted and non-persisted).
 * The PID is included to ensure that processes do not destroy clients created
 * by other processes (relevant for forking). We avoid using pid_t for Windows
 * compatibility. */
typedef struct {
	mongoc_client_t* client;
	int              created_by_pid;
	int              last_reset_by_pid;
	bool             is_persistent;
} php_phongo_pclient_t;

static const mongoc_client_t* get_first_pclient_client(HashTable* ht)
{
	if (ht) {
		php_phongo_pclient_t* pclient = NULL;

		zend_hash_internal_pointer_reset(ht);
		pclient = zend_hash_get_current_data_ptr(ht);

		if (pclient) {
			return pclient->client;
		}
	}

	return NULL;
}

/* Returns the version of the crypt_shared library, or NULL if it's unavailable.
 * Querying the version requires a mongoc_client_t pointer. Since the shared
 * library can only be loaded once, any client will return the same result so we
 * consult the first persistent or request-scoped client we can find.
 *
 * Note: this may incorrectly return NULL if crypt_shared was loaded through a
 * mongoc_client_t since destroyed (e.g. single requested-scoped client);
 * however, that's the best can do with libmongoc's API. */
const char* php_phongo_crypt_shared_version(void)
{
	const mongoc_client_t* client = NULL;

	client = get_first_pclient_client(&MONGODB_G(persistent_clients));

	if (!client) {
		client = get_first_pclient_client(MONGODB_G(request_clients));
	}

	if (client) {
		return mongoc_client_get_crypt_shared_version(client);
	}

	return NULL;
}

static mongoc_uri_t* php_phongo_make_uri(const char* uri_string)
{
	mongoc_uri_t* uri;
	bson_error_t  error = { 0 };

	uri = mongoc_uri_new_with_error(uri_string, &error);
	MONGOC_DEBUG("Connection string: '%s'", uri_string);

	if (!uri) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse MongoDB URI: '%s'. %s.", uri_string, error.message);
		return NULL;
	}

	return uri;
}

#define PHONGO_URI_INVALID_TYPE(iter, expected)        \
	phongo_throw_exception(                            \
		PHONGO_ERROR_INVALID_ARGUMENT,                 \
		"Expected %s for \"%s\" URI option, %s given", \
		(expected),                                    \
		bson_iter_key(&(iter)),                        \
		php_phongo_bson_type_to_string(bson_iter_type(&(iter))))

static bool php_phongo_apply_options_to_uri(mongoc_uri_t* uri, bson_t* options)
{
	bson_iter_t iter;

	/* Return early if there are no options to apply */
	if (bson_empty0(options) || !bson_iter_init(&iter, options)) {
		return true;
	}

	while (bson_iter_next(&iter)) {
		const char* key = bson_iter_key(&iter);

		/* Skip read preference, read concern, and write concern options, as
		 * those will be processed by other functions. */
		if (!strcasecmp(key, MONGOC_URI_JOURNAL) ||
			!strcasecmp(key, MONGOC_URI_MAXSTALENESSSECONDS) ||
			!strcasecmp(key, MONGOC_URI_READCONCERNLEVEL) ||
			!strcasecmp(key, MONGOC_URI_READPREFERENCE) ||
			!strcasecmp(key, MONGOC_URI_READPREFERENCETAGS) ||
			!strcasecmp(key, MONGOC_URI_SAFE) ||
			!strcasecmp(key, MONGOC_URI_W) ||
			!strcasecmp(key, MONGOC_URI_WTIMEOUTMS)) {

			continue;
		}

		if (mongoc_uri_option_is_bool(key)) {
			/* The option's type is not validated because bson_iter_as_bool() is
			 * used to cast the value to a boolean. Validation may be introduced
			 * in PHPC-990. */
			if (!mongoc_uri_set_option_as_bool(uri, key, bson_iter_as_bool(&iter))) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				return false;
			}

			continue;
		}

		if (mongoc_uri_option_is_int32(key)) {
			if (!BSON_ITER_HOLDS_INT32(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "32-bit integer");
				return false;
			}

			if (!mongoc_uri_set_option_as_int32(uri, key, bson_iter_int32(&iter))) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				return false;
			}

			continue;
		}

		if (mongoc_uri_option_is_utf8(key)) {
			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				return false;
			}

			if (!strcasecmp(key, MONGOC_URI_REPLICASET) && !strcmp("", bson_iter_utf8(&iter, NULL))) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Value for URI option \"%s\" cannot be empty string.", key);
				return false;
			}

			if (!mongoc_uri_set_option_as_utf8(uri, key, bson_iter_utf8(&iter, NULL))) {
				/* Assignment uses mongoc_uri_set_appname() for the "appname"
				 * option, which validates length in addition to UTF-8 encoding.
				 * For BC, we report the invalid string to the user. */
				if (!strcasecmp(key, MONGOC_URI_APPNAME)) {
					phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Invalid appname value: '%s'", bson_iter_utf8(&iter, NULL));
				} else {
					phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				}
				return false;
			}

			continue;
		}

		if (!strcasecmp(key, "username")) {
			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				return false;
			}

			if (!mongoc_uri_set_username(uri, bson_iter_utf8(&iter, NULL))) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				return false;
			}

			continue;
		}

		if (!strcasecmp(key, "password")) {
			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				return false;
			}

			if (!mongoc_uri_set_password(uri, bson_iter_utf8(&iter, NULL))) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				return false;
			}

			continue;
		}

		if (!strcasecmp(key, MONGOC_URI_AUTHMECHANISM)) {
			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				return false;
			}

			if (!mongoc_uri_set_auth_mechanism(uri, bson_iter_utf8(&iter, NULL))) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				return false;
			}

			continue;
		}

		if (!strcasecmp(key, MONGOC_URI_AUTHSOURCE)) {
			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				return false;
			}

			if (!mongoc_uri_set_auth_source(uri, bson_iter_utf8(&iter, NULL))) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				return false;
			}

			continue;
		}

		if (!strcasecmp(key, MONGOC_URI_AUTHMECHANISMPROPERTIES)) {
			bson_t         properties;
			uint32_t       len;
			const uint8_t* data;

			if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "array or object");
				return false;
			}

			bson_iter_document(&iter, &len, &data);

			if (!bson_init_static(&properties, data, len)) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Could not initialize BSON structure for auth mechanism properties");
				return false;
			}

			if (!mongoc_uri_set_mechanism_properties(uri, &properties)) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				return false;
			}

			continue;
		}

		if (!strcasecmp(key, MONGOC_URI_GSSAPISERVICENAME)) {
			bson_t unused, properties = BSON_INITIALIZER;

			if (mongoc_uri_get_mechanism_properties(uri, &unused)) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "authMechanismProperties SERVICE_NAME already set, ignoring \"%s\"", key);
				return false;
			}

			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				return false;
			}

			bson_append_utf8(&properties, "SERVICE_NAME", -1, bson_iter_utf8(&iter, NULL), -1);

			if (!mongoc_uri_set_mechanism_properties(uri, &properties)) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				bson_destroy(&properties);
				return false;
			}

			bson_destroy(&properties);

			continue;
		}

		if (!strcasecmp(key, MONGOC_URI_COMPRESSORS)) {
			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				return false;
			}

			if (!mongoc_uri_set_compressors(uri, bson_iter_utf8(&iter, NULL))) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" URI option", key);
				return false;
			}

			continue;
		}
	}

	return true;
}

static bool php_phongo_apply_rc_options_to_uri(mongoc_uri_t* uri, bson_t* options)
{
	bson_iter_t                  iter;
	mongoc_read_concern_t*       new_rc;
	const mongoc_read_concern_t* old_rc;

	if (!(old_rc = mongoc_uri_get_read_concern(uri))) {
		phongo_throw_exception(PHONGO_ERROR_MONGOC_FAILED, "mongoc_uri_t does not have a read concern");

		return false;
	}

	/* Return early if there are no options to apply */
	if (bson_empty0(options) || !bson_iter_init(&iter, options)) {
		return true;
	}

	new_rc = mongoc_read_concern_copy(old_rc);

	while (bson_iter_next(&iter)) {
		const char* key = bson_iter_key(&iter);

		if (!strcasecmp(key, MONGOC_URI_READCONCERNLEVEL)) {
			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				mongoc_read_concern_destroy(new_rc);

				return false;
			}

			mongoc_read_concern_set_level(new_rc, bson_iter_utf8(&iter, NULL));
		}
	}

	mongoc_uri_set_read_concern(uri, new_rc);
	mongoc_read_concern_destroy(new_rc);

	return true;
}

static bool php_phongo_apply_rp_options_to_uri(mongoc_uri_t* uri, bson_t* options)
{
	bson_iter_t                iter;
	mongoc_read_prefs_t*       new_rp;
	const mongoc_read_prefs_t* old_rp;

	if (!(old_rp = mongoc_uri_get_read_prefs_t(uri))) {
		phongo_throw_exception(PHONGO_ERROR_MONGOC_FAILED, "mongoc_uri_t does not have a read preference");

		return false;
	}

	/* Return early if there are no options to apply */
	if (bson_empty0(options) || !bson_iter_init(&iter, options)) {
		return true;
	}

	new_rp = mongoc_read_prefs_copy(old_rp);

	while (bson_iter_next(&iter)) {
		const char* key = bson_iter_key(&iter);

		if (!strcasecmp(key, MONGOC_URI_READPREFERENCE)) {
			const char* str;

			if (!BSON_ITER_HOLDS_UTF8(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "string");
				mongoc_read_prefs_destroy(new_rp);

				return false;
			}

			str = bson_iter_utf8(&iter, NULL);

			if (0 == strcasecmp("primary", str)) {
				mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_PRIMARY);
			} else if (0 == strcasecmp("primarypreferred", str)) {
				mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_PRIMARY_PREFERRED);
			} else if (0 == strcasecmp("secondary", str)) {
				mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY);
			} else if (0 == strcasecmp("secondarypreferred", str)) {
				mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_SECONDARY_PREFERRED);
			} else if (0 == strcasecmp("nearest", str)) {
				mongoc_read_prefs_set_mode(new_rp, MONGOC_READ_NEAREST);
			} else {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Unsupported %s value: '%s'", bson_iter_key(&iter), str);
				mongoc_read_prefs_destroy(new_rp);

				return false;
			}
		}

		if (!strcasecmp(key, MONGOC_URI_READPREFERENCETAGS)) {
			bson_t         tags;
			uint32_t       len;
			const uint8_t* data;

			if (!BSON_ITER_HOLDS_ARRAY(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "array");
				mongoc_read_prefs_destroy(new_rp);

				return false;
			}

			bson_iter_array(&iter, &len, &data);

			if (!bson_init_static(&tags, data, len)) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Could not initialize BSON structure for read preference tags");
				mongoc_read_prefs_destroy(new_rp);

				return false;
			}

			if (!php_phongo_read_preference_tags_are_valid(&tags)) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Read preference tags must be an array of zero or more documents");
				mongoc_read_prefs_destroy(new_rp);

				return false;
			}

			mongoc_read_prefs_set_tags(new_rp, &tags);
		}

		if (!strcasecmp(key, MONGOC_URI_MAXSTALENESSSECONDS)) {
			int64_t max_staleness_seconds;

			if (!BSON_ITER_HOLDS_INT(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "integer");
				mongoc_read_prefs_destroy(new_rp);

				return false;
			}

			max_staleness_seconds = bson_iter_as_int64(&iter);

			if (max_staleness_seconds != MONGOC_NO_MAX_STALENESS) {

				if (max_staleness_seconds < MONGOC_SMALLEST_MAX_STALENESS_SECONDS) {
					phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected maxStalenessSeconds to be >= %d, %" PRId64 " given", MONGOC_SMALLEST_MAX_STALENESS_SECONDS, max_staleness_seconds);
					mongoc_read_prefs_destroy(new_rp);

					return false;
				}

				if (max_staleness_seconds > INT32_MAX) {
					phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected maxStalenessSeconds to be <= %d, %" PRId64 " given", INT32_MAX, max_staleness_seconds);
					mongoc_read_prefs_destroy(new_rp);

					return false;
				}

				if (mongoc_read_prefs_get_mode(new_rp) == MONGOC_READ_PRIMARY) {
					phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Primary read preference mode conflicts with maxStalenessSeconds");
					mongoc_read_prefs_destroy(new_rp);

					return false;
				}
			}

			mongoc_read_prefs_set_max_staleness_seconds(new_rp, max_staleness_seconds);
		}
	}

	if (mongoc_read_prefs_get_mode(new_rp) == MONGOC_READ_PRIMARY &&
		!bson_empty(mongoc_read_prefs_get_tags(new_rp))) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Primary read preference mode conflicts with tags");
		mongoc_read_prefs_destroy(new_rp);

		return false;
	}

	/* Make sure maxStalenessSeconds is not combined with primary readPreference */
	if (mongoc_read_prefs_get_mode(new_rp) == MONGOC_READ_PRIMARY &&
		mongoc_read_prefs_get_max_staleness_seconds(new_rp) != MONGOC_NO_MAX_STALENESS) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Primary read preference mode conflicts with maxStalenessSeconds");
		mongoc_read_prefs_destroy(new_rp);

		return false;
	}

	/* This may be redundant in light of the previous checks (primary with tags
	 * or maxStalenessSeconds), but we'll check anyway in case additional
	 * validation is implemented. */
	if (!mongoc_read_prefs_is_valid(new_rp)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Read preference is not valid");
		mongoc_read_prefs_destroy(new_rp);

		return false;
	}

	mongoc_uri_set_read_prefs_t(uri, new_rp);
	mongoc_read_prefs_destroy(new_rp);

	return true;
}

static bool php_phongo_apply_wc_options_to_uri(mongoc_uri_t* uri, bson_t* options)
{
	bson_iter_t                   iter;
	mongoc_write_concern_t*       new_wc;
	const mongoc_write_concern_t* old_wc;
	bool                          ignore_safe = false;

	if (!(old_wc = mongoc_uri_get_write_concern(uri))) {
		phongo_throw_exception(PHONGO_ERROR_MONGOC_FAILED, "mongoc_uri_t does not have a write concern");

		return false;
	}

	/* Return early if there are no options to apply */
	if (bson_empty0(options) || !bson_iter_init(&iter, options)) {
		return true;
	}

	new_wc = mongoc_write_concern_copy(old_wc);

	while (bson_iter_next(&iter)) {
		const char* key = bson_iter_key(&iter);

		if (!ignore_safe && !strcasecmp(key, MONGOC_URI_SAFE)) {
			if (!BSON_ITER_HOLDS_BOOL(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "boolean");
				mongoc_write_concern_destroy(new_wc);

				return false;
			}

			mongoc_write_concern_set_w(new_wc, bson_iter_bool(&iter) ? 1 : MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED);
		}

		if (!strcasecmp(key, MONGOC_URI_WTIMEOUTMS)) {
			int64_t wtimeout;

			if (!BSON_ITER_HOLDS_INT(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "integer");
				mongoc_write_concern_destroy(new_wc);

				return false;
			}

			wtimeout = bson_iter_as_int64(&iter);

			if (wtimeout < 0) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected wtimeoutMS to be >= 0, %" PRId64 " given", wtimeout);
				mongoc_write_concern_destroy(new_wc);

				return false;
			}

			mongoc_write_concern_set_wtimeout_int64(new_wc, wtimeout);
		}

		if (!strcasecmp(key, MONGOC_URI_JOURNAL)) {
			if (!BSON_ITER_HOLDS_BOOL(&iter)) {
				PHONGO_URI_INVALID_TYPE(iter, "boolean");
				mongoc_write_concern_destroy(new_wc);

				return false;
			}

			mongoc_write_concern_set_journal(new_wc, bson_iter_bool(&iter));
		}

		if (!strcasecmp(key, MONGOC_URI_W)) {
			if (BSON_ITER_HOLDS_INT32(&iter)) {
				int32_t value = bson_iter_int32(&iter);

				switch (value) {
					case MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED:
					case MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED:
						mongoc_write_concern_set_w(new_wc, value);
						break;

					default:
						if (value > 0) {
							mongoc_write_concern_set_w(new_wc, value);
							break;
						}
						phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Unsupported w value: %d", value);
						mongoc_write_concern_destroy(new_wc);

						return false;
				}
			} else if (BSON_ITER_HOLDS_UTF8(&iter)) {
				const char* str = bson_iter_utf8(&iter, NULL);

				if (0 == strcasecmp(PHONGO_WRITE_CONCERN_W_MAJORITY, str)) {
					mongoc_write_concern_set_w(new_wc, MONGOC_WRITE_CONCERN_W_MAJORITY);
				} else {
					mongoc_write_concern_set_wtag(new_wc, str);
				}
			} else {
				PHONGO_URI_INVALID_TYPE(iter, "32-bit integer or string");
				mongoc_write_concern_destroy(new_wc);

				return false;
			}

			ignore_safe = true;
		}
	}

	if (mongoc_write_concern_get_journal(new_wc)) {
		int32_t w = mongoc_write_concern_get_w(new_wc);

		if (w == MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED || w == MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Journal conflicts with w value: %d", w);
			mongoc_write_concern_destroy(new_wc);

			return false;
		}
	}

	/* This may be redundant in light of the last check (unacknowledged w with
	   journal), but we'll check anyway in case additional validation is
	   implemented. */
	if (!mongoc_write_concern_is_valid(new_wc)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Write concern is not valid");
		mongoc_write_concern_destroy(new_wc);

		return false;
	}

	mongoc_uri_set_write_concern(uri, new_wc);
	mongoc_write_concern_destroy(new_wc);

	return true;
}

#ifdef MONGOC_ENABLE_SSL
static void php_phongo_mongoc_ssl_opts_from_uri(mongoc_ssl_opt_t* ssl_opt, mongoc_uri_t* uri, bool* any_ssl_option_set)
{
	bool        insecure = mongoc_uri_get_option_as_bool(uri, MONGOC_URI_TLSINSECURE, false);
	const char* pem_file = mongoc_uri_get_option_as_utf8(uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, NULL);
	const char* pem_pwd  = mongoc_uri_get_option_as_utf8(uri, MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD, NULL);
	const char* ca_file  = mongoc_uri_get_option_as_utf8(uri, MONGOC_URI_TLSCAFILE, NULL);

	ssl_opt->pem_file               = pem_file ? estrdup(pem_file) : NULL;
	ssl_opt->pem_pwd                = pem_pwd ? estrdup(pem_pwd) : NULL;
	ssl_opt->ca_file                = ca_file ? estrdup(ca_file) : NULL;
	ssl_opt->weak_cert_validation   = mongoc_uri_get_option_as_bool(uri, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES, insecure);
	ssl_opt->allow_invalid_hostname = mongoc_uri_get_option_as_bool(uri, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES, insecure);

	/* Boolean options default to false, so we cannot consider them for
	 * any_ssl_option_set. This isn't actually a problem as libmongoc will
	 * already have assigned them when creating the client, enabling SSL, and
	 * assigning SSL options. Therefore, we only need to check for non-defaults
	 * (i.e. non-NULL strings, true booleans). */
	if (pem_file || pem_pwd || ca_file || ssl_opt->weak_cert_validation || ssl_opt->allow_invalid_hostname) {
		*any_ssl_option_set = true;
	}
}

static inline char* php_phongo_fetch_ssl_opt_string(zval* zoptions, const char* key)
{
	int       plen;
	zend_bool pfree;
	char*     pval;
	char*     value;

	pval  = php_array_fetch_string(zoptions, key, &plen, &pfree);
	value = pfree ? pval : estrndup(pval, plen);

	return value;
}

static mongoc_ssl_opt_t* php_phongo_make_ssl_opt(mongoc_uri_t* uri, zval* zoptions)
{
	mongoc_ssl_opt_t* ssl_opt;
	bool              any_ssl_option_set = false;

	if (!zoptions) {
		return NULL;
	}

#if defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL) || defined(MONGOC_ENABLE_SSL_SECURE_TRANSPORT)
	if (php_array_existsc(zoptions, "ca_dir")) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "\"ca_dir\" option is not supported by Secure Channel and Secure Transport");
		return NULL;
	}

	if (php_array_existsc(zoptions, "capath")) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "\"capath\" option is not supported by Secure Channel and Secure Transport");
		return NULL;
	}
#endif

#if defined(MONGOC_ENABLE_SSL_LIBRESSL) || defined(MONGOC_ENABLE_SSL_SECURE_TRANSPORT)
	if (php_array_existsc(zoptions, "crl_file")) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "\"crl_file\" option is not supported by LibreSSL and Secure Transport");
		return NULL;
	}
#endif

	ssl_opt = ecalloc(1, sizeof(mongoc_ssl_opt_t));

	/* If SSL options are set in the URL, we need to read them and set them on
	 * the options struct so we can merge potential options from passed in
	 * driverOptions (zoptions) */
	if (mongoc_uri_get_tls(uri)) {
		php_phongo_mongoc_ssl_opts_from_uri(ssl_opt, uri, &any_ssl_option_set);
	}

#define PHONGO_SSL_OPTION_SWAP_STRING(o, n) \
	if ((o)) {                              \
		efree((char*) (o));                 \
	}                                       \
	(o) = php_phongo_fetch_ssl_opt_string(zoptions, n);

	/* Apply driver options that don't have a corresponding URI option. These
	 * are set directly on the SSL options struct. */
	if (php_array_existsc(zoptions, "ca_dir")) {
		PHONGO_SSL_OPTION_SWAP_STRING(ssl_opt->ca_dir, "ca_dir");
		any_ssl_option_set = true;
	} else if (php_array_existsc(zoptions, "capath")) {
		PHONGO_SSL_OPTION_SWAP_STRING(ssl_opt->ca_dir, "capath");
		any_ssl_option_set = true;

		php_error_docref(NULL, E_DEPRECATED, "The \"capath\" context driver option is deprecated. Please use the \"ca_dir\" driver option instead.");
	}

	if (php_array_existsc(zoptions, "crl_file")) {
		PHONGO_SSL_OPTION_SWAP_STRING(ssl_opt->crl_file, "crl_file");
		any_ssl_option_set = true;
	}

#undef PHONGO_SSL_OPTION_SWAP_STRING

	if (!any_ssl_option_set) {
		efree(ssl_opt);
		return NULL;
	}

	return ssl_opt;
}

static void php_phongo_free_ssl_opt(mongoc_ssl_opt_t* ssl_opt)
{
	if (ssl_opt->pem_file) {
		efree((char*) ssl_opt->pem_file);
	}

	if (ssl_opt->pem_pwd) {
		efree((char*) ssl_opt->pem_pwd);
	}

	if (ssl_opt->ca_file) {
		efree((char*) ssl_opt->ca_file);
	}

	if (ssl_opt->ca_dir) {
		efree((char*) ssl_opt->ca_dir);
	}

	if (ssl_opt->crl_file) {
		efree((char*) ssl_opt->crl_file);
	}

	efree(ssl_opt);
}

static inline bool php_phongo_apply_driver_option_to_uri(mongoc_uri_t* uri, zval* zoptions, const char* driverOptionKey, const char* optionKey)
{
	bool  ret;
	char* value;

	value = php_phongo_fetch_ssl_opt_string(zoptions, driverOptionKey);
	ret   = mongoc_uri_set_option_as_utf8(uri, optionKey, value);
	efree(value);

	return ret;
}

static bool php_phongo_apply_driver_options_to_uri(mongoc_uri_t* uri, zval* zoptions)
{
	if (!zoptions) {
		return true;
	}

	/* Map TLS driver options to the canonical tls options in the URI. */
	if (php_array_existsc(zoptions, "allow_invalid_hostname")) {
		if (!mongoc_uri_set_option_as_bool(uri, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES, php_array_fetchc_bool(zoptions, "allow_invalid_hostname"))) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "allow_invalid_hostname");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"allow_invalid_hostname\" driver option is deprecated. Please use the \"tlsAllowInvalidHostnames\" URI option instead.");
	}

	if (php_array_existsc(zoptions, "weak_cert_validation")) {
		if (!mongoc_uri_set_option_as_bool(uri, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES, php_array_fetchc_bool(zoptions, "weak_cert_validation"))) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "weak_cert_validation");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"weak_cert_validation\" driver option is deprecated. Please use the \"tlsAllowInvalidCertificates\" URI option instead.");
	} else if (php_array_existsc(zoptions, "allow_self_signed")) {
		if (!mongoc_uri_set_option_as_bool(uri, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES, php_array_fetchc_bool(zoptions, "allow_self_signed"))) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "allow_self_signed");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"allow_self_signed\" context driver option is deprecated. Please use the \"tlsAllowInvalidCertificates\" URI option instead.");
	}

	if (php_array_existsc(zoptions, "pem_file")) {
		if (!php_phongo_apply_driver_option_to_uri(uri, zoptions, "pem_file", MONGOC_URI_TLSCERTIFICATEKEYFILE)) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "pem_file");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"pem_file\" driver option is deprecated. Please use the \"tlsCertificateKeyFile\" URI option instead.");
	} else if (php_array_existsc(zoptions, "local_cert")) {
		if (!php_phongo_apply_driver_option_to_uri(uri, zoptions, "local_cert", MONGOC_URI_TLSCERTIFICATEKEYFILE)) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "local_cert");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"local_cert\" context driver option is deprecated. Please use the \"tlsCertificateKeyFile\" URI option instead.");
	}

	if (php_array_existsc(zoptions, "pem_pwd")) {
		if (!php_phongo_apply_driver_option_to_uri(uri, zoptions, "pem_pwd", MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD)) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "pem_pwd");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"pem_pwd\" driver option is deprecated. Please use the \"tlsCertificateKeyFilePassword\" URI option instead.");
	} else if (php_array_existsc(zoptions, "passphrase")) {
		if (!php_phongo_apply_driver_option_to_uri(uri, zoptions, "passphrase", MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD)) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "passphrase");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"passphrase\" context driver option is deprecated. Please use the \"tlsCertificateKeyFilePassword\" URI option instead.");
	}

	if (php_array_existsc(zoptions, "ca_file")) {
		if (!php_phongo_apply_driver_option_to_uri(uri, zoptions, "ca_file", MONGOC_URI_TLSCAFILE)) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "ca_file");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"ca_file\" driver option is deprecated. Please use the \"tlsCAFile\" URI option instead.");
	} else if (php_array_existsc(zoptions, "cafile")) {
		if (!php_phongo_apply_driver_option_to_uri(uri, zoptions, "cafile", MONGOC_URI_TLSCAFILE)) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse \"%s\" driver option", "cafile");

			return false;
		}

		php_error_docref(NULL, E_DEPRECATED, "The \"cafile\" context driver option is deprecated. Please use the \"tlsCAFile\" URI option instead.");
	}

	return true;
}
#endif /* MONGOC_ENABLE_SSL */

static zval* php_phongo_manager_prepare_manager_for_hash(zval* driverOptions, bool* free)
{
	php_phongo_manager_t* manager;
	zval*                 autoEncryptionOpts      = NULL;
	zval*                 keyVaultClient          = NULL;
	zval*                 driverOptionsClone      = NULL;
	zval*                 autoEncryptionOptsClone = NULL;
	zval                  stackAutoEncryptionOptsClone;

	*free = false;

	if (!driverOptions) {
		return NULL;
	}

	if (!php_array_existsc(driverOptions, "autoEncryption")) {
		goto ref;
	}

	autoEncryptionOpts = php_array_fetchc(driverOptions, "autoEncryption");
	if (Z_TYPE_P(autoEncryptionOpts) != IS_ARRAY) {
		goto ref;
	}

	if (!php_array_existsc(autoEncryptionOpts, "keyVaultClient")) {
		goto ref;
	}

	keyVaultClient = php_array_fetchc(autoEncryptionOpts, "keyVaultClient");
	if (Z_TYPE_P(keyVaultClient) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(keyVaultClient), php_phongo_manager_ce)) {
		goto ref;
	}

	*free = true;

	manager = Z_MANAGER_OBJ_P(keyVaultClient);

	driverOptionsClone      = ecalloc(1, sizeof(zval));
	autoEncryptionOptsClone = &stackAutoEncryptionOptsClone;

	ZVAL_DUP(autoEncryptionOptsClone, autoEncryptionOpts);
	ADD_ASSOC_STRINGL(autoEncryptionOptsClone, "keyVaultClient", manager->client_hash, manager->client_hash_len);

	ZVAL_DUP(driverOptionsClone, driverOptions);
	ADD_ASSOC_ZVAL_EX(driverOptionsClone, "autoEncryption", autoEncryptionOptsClone);

	return driverOptionsClone;

ref:
	Z_ADDREF_P(driverOptions);
	return driverOptions;
}

/* Creates a hash for a client by concatenating the URI string with serialized
 * options arrays. On success, a persistent string is returned (i.e. pefree()
 * should be used to free it) and hash_len will be set to the string's length.
 * On error, an exception will have been thrown and NULL will be returned. */
static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* options, zval* driverOptions, size_t* hash_len)
{
	char*                hash    = NULL;
	smart_str            var_buf = { 0 };
	php_serialize_data_t var_hash;
	zval*                serializable_driver_options = NULL;
	bool                 free_driver_options         = false;

	zval args;

	array_init_size(&args, 4);
	ADD_ASSOC_LONG_EX(&args, "pid", getpid());
	ADD_ASSOC_STRING(&args, "uri", uri_string);

	if (options) {
		ADD_ASSOC_ZVAL_EX(&args, "options", options);
		Z_ADDREF_P(options);
	} else {
		ADD_ASSOC_NULL_EX(&args, "options");
	}

	if (driverOptions) {
		serializable_driver_options = php_phongo_manager_prepare_manager_for_hash(driverOptions, &free_driver_options);
		ADD_ASSOC_ZVAL_EX(&args, "driverOptions", serializable_driver_options);
	} else {
		ADD_ASSOC_NULL_EX(&args, "driverOptions");
	}

	PHP_VAR_SERIALIZE_INIT(var_hash);
	php_var_serialize(&var_buf, &args, &var_hash);
	PHP_VAR_SERIALIZE_DESTROY(var_hash);

	if (!EG(exception)) {
		*hash_len = ZSTR_LEN(var_buf.s);
		hash      = estrndup(ZSTR_VAL(var_buf.s), *hash_len);
	}

	zval_ptr_dtor(&args);

	if (free_driver_options) {
		efree(serializable_driver_options);
	}

	smart_str_free(&var_buf);

	return hash;
}

static bool php_phongo_extract_handshake_data(zval* driver, const char* key, char** value, size_t* value_len)
{
	zval* zvalue;

	if (!php_array_exists(driver, key)) {
		*value     = NULL;
		*value_len = 0;

		return true;
	}

	zvalue = php_array_fetch_deref(driver, key);

	if (Z_TYPE_P(zvalue) != IS_STRING) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"%s\" handshake option to be a string, %s given", key, zend_zval_type_name(zvalue));
		return false;
	}

	*value     = estrdup(Z_STRVAL_P(zvalue));
	*value_len = Z_STRLEN_P(zvalue);

	return true;
}

static char* php_phongo_concat_handshake_data(const char* default_value, const char* custom_value, size_t custom_value_len)
{
	char* ret;
	/* Length of the returned value needs to include a trailing space and null byte */
	size_t ret_len = strlen(default_value) + 2;

	if (custom_value) {
		/* Increase the length by that of the custom value as well as the separator length */
		ret_len += custom_value_len + PHONGO_METADATA_SEPARATOR_LEN;
	}

	ret = ecalloc(ret_len, sizeof(char));

	if (custom_value) {
		snprintf(ret, ret_len, "%s%s%s ", default_value, PHONGO_METADATA_SEPARATOR, custom_value);
	} else {
		snprintf(ret, ret_len, "%s ", default_value);
	}

	return ret;
}

static void php_phongo_handshake_data_append(const char* name, size_t name_len, const char* version, size_t version_len, const char* platform, size_t platform_len)
{
	char*  php_version_string;
	size_t php_version_string_len;
	char*  driver_name;
	char*  driver_version;
	char*  full_platform;

	php_version_string_len = strlen(PHP_VERSION) + PHONGO_METADATA_PHP_VERSION_PREFIX_LEN + 1;
	php_version_string     = ecalloc(php_version_string_len, sizeof(char));
	snprintf(php_version_string, php_version_string_len, "%s%s", PHONGO_METADATA_PHP_VERSION_PREFIX, PHP_VERSION);

	driver_name    = php_phongo_concat_handshake_data("ext-mongodb:PHP", name, name_len);
	driver_version = php_phongo_concat_handshake_data(PHP_MONGODB_VERSION, version, version_len);
	full_platform  = php_phongo_concat_handshake_data(php_version_string, platform, platform_len);

	MONGOC_DEBUG(
		"Setting driver handshake data: { name: '%s', version: '%s', platform: '%s' }",
		driver_name,
		driver_version,
		full_platform);

	mongoc_handshake_data_append(driver_name, driver_version, full_platform);

	efree(php_version_string);
	efree(driver_name);
	efree(driver_version);
	efree(full_platform);
}

static void php_phongo_set_handshake_data(zval* driverOptions)
{
	char*  name         = NULL;
	size_t name_len     = 0;
	char*  version      = NULL;
	size_t version_len  = 0;
	char*  platform     = NULL;
	size_t platform_len = 0;

	if (driverOptions && php_array_existsc(driverOptions, "driver")) {
		zval* driver = php_array_fetchc_deref(driverOptions, "driver");

		if (Z_TYPE_P(driver) != IS_ARRAY) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"driver\" driver option to be an array, %s given", zend_zval_type_name(driver));
			return;
		}

		if (!php_phongo_extract_handshake_data(driver, "name", &name, &name_len)) {
			/* Exception already thrown */
			goto cleanup;
		}

		if (!php_phongo_extract_handshake_data(driver, "version", &version, &version_len)) {
			/* Exception already thrown */
			goto cleanup;
		}

		if (!php_phongo_extract_handshake_data(driver, "platform", &platform, &platform_len)) {
			/* Exception already thrown */
			goto cleanup;
		}
	}

	php_phongo_handshake_data_append(name, name_len, version, version_len, platform, platform_len);

cleanup:
	if (name) {
		efree(name);
	}
	if (version) {
		efree(version);
	}
	if (platform) {
		efree(platform);
	}
}

static mongoc_client_t* php_phongo_make_mongo_client(const mongoc_uri_t* uri, zval* driverOptions)
{
	const char *     mongoc_version, *bson_version;
	mongoc_client_t* client;
	bson_error_t     error = { 0 };

#ifdef HAVE_SYSTEM_LIBMONGOC
	mongoc_version = mongoc_get_version();
#else
	mongoc_version = "bundled";
#endif

#ifdef HAVE_SYSTEM_LIBBSON
	bson_version = bson_get_version();
#else
	bson_version   = "bundled";
#endif

	MONGOC_DEBUG(
		"Creating Manager, phongo-%s[%s] - mongoc-%s(%s), libbson-%s(%s), php-%s",
		PHP_MONGODB_VERSION,
		PHP_MONGODB_STABILITY,
		MONGOC_VERSION_S,
		mongoc_version,
		BSON_VERSION_S,
		bson_version,
		PHP_VERSION);

	php_phongo_set_handshake_data(driverOptions);

	if (!(client = mongoc_client_new_from_uri_with_error(uri, &error))) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Failed to parse URI options: %s", error.message);
	}

	return client;
}

/* Adds a client to the appropriate registry. Persistent and request-scoped
 * clients each have their own registries (i.e. HashTables), which use different
 * forms of memory allocation. Both registries are used for PID tracking.
 * Returns true if the client was successfully added; otherwise, false. */
bool php_phongo_client_register(php_phongo_manager_t* manager)
{
	bool                  is_persistent = manager->use_persistent_client;
	php_phongo_pclient_t* pclient       = pecalloc(1, sizeof(php_phongo_pclient_t), is_persistent);

	pclient->client         = manager->client;
	pclient->created_by_pid = (int) getpid();
	pclient->is_persistent  = is_persistent;

	if (is_persistent) {
		MONGOC_DEBUG("Stored persistent client with hash: %s", manager->client_hash);
		return zend_hash_str_update_ptr(&MONGODB_G(persistent_clients), manager->client_hash, manager->client_hash_len, pclient) != NULL;
	} else {
		MONGOC_DEBUG("Stored non-persistent client");
		return zend_hash_next_index_insert_ptr(MONGODB_G(request_clients), pclient) != NULL;
	}
}

/* Removes a client from the request-scoped registry. This function is a NOP for
 * persistent clients, since they are destroyed along with their registry (i.e.
 * HashTable) in GSHUTDOWN. Returns true if the client was successfully removed;
 * otherwise, false. */
bool php_phongo_client_unregister(php_phongo_manager_t* manager)
{
	zend_ulong            index;
	php_phongo_pclient_t* pclient;

	/* Persistent clients do not get unregistered. */
	if (manager->use_persistent_client) {
		MONGOC_DEBUG("Not destroying persistent client for Manager");

		return false;
	}

	/* Ensure the request-scoped registry is initialized. This is needed because
	 * RSHUTDOWN may occur before a Manager's free_object handler is
	 * executed. */
	if (MONGODB_G(request_clients) == NULL) {
		return false;
	}

	ZEND_HASH_FOREACH_NUM_KEY_PTR(MONGODB_G(request_clients), index, pclient)
	{
		if (pclient->client == manager->client) {
			MONGOC_DEBUG("Destroying non-persistent client for Manager");

			return zend_hash_index_del(MONGODB_G(request_clients), index) == SUCCESS;
		}
	}
	ZEND_HASH_FOREACH_END();

	return false;
}

static mongoc_client_t* php_phongo_find_persistent_client(const char* hash, size_t hash_len)
{
	php_phongo_pclient_t* pclient = zend_hash_str_find_ptr(&MONGODB_G(persistent_clients), hash, hash_len);

	if (pclient) {
		return pclient->client;
	}

	return NULL;
}

static bool phongo_manager_set_serverapi_opts(php_phongo_manager_t* manager, zval* driverOptions)
{
	zval*                   zServerApi;
	php_phongo_serverapi_t* server_api;
	bson_error_t            error = { 0 };

	if (!driverOptions || !php_array_existsc(driverOptions, "serverApi")) {
		return true;
	}

	zServerApi = php_array_fetchc_deref(driverOptions, "serverApi");

	if (Z_TYPE_P(zServerApi) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(zServerApi), php_phongo_serverapi_ce)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"serverApi\" driver option to be %s, %s given", ZSTR_VAL(php_phongo_serverapi_ce->name), zend_zval_type_name(zServerApi));
		return false;
	}

	server_api = Z_SERVERAPI_OBJ_P(zServerApi);

	if (!mongoc_client_set_server_api(manager->client, server_api->server_api, &error)) {
		phongo_throw_exception_from_bson_error_t(&error);
		return false;
	}

	return true;
}

#ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION
static bool phongo_manager_set_auto_encryption_opts(php_phongo_manager_t* manager, zval* driverOptions)
{
	zval*                          zAutoEncryptionOpts;
	bson_error_t                   error                = { 0 };
	mongoc_auto_encryption_opts_t* auto_encryption_opts = NULL;
	bool                           retval               = false;

	if (!driverOptions || !php_array_existsc(driverOptions, "autoEncryption")) {
		return true;
	}

	zAutoEncryptionOpts = php_array_fetchc_deref(driverOptions, "autoEncryption");

	if (Z_TYPE_P(zAutoEncryptionOpts) != IS_ARRAY) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"autoEncryption\" driver option to be array, %s given", zend_zval_type_name(zAutoEncryptionOpts));
		return false;
	}

	auto_encryption_opts = mongoc_auto_encryption_opts_new();

	if (php_array_existsc(zAutoEncryptionOpts, "bypassAutoEncryption")) {
		mongoc_auto_encryption_opts_set_bypass_auto_encryption(auto_encryption_opts, php_array_fetchc_bool(zAutoEncryptionOpts, "bypassAutoEncryption"));
	}

	if (php_array_existsc(zAutoEncryptionOpts, "bypassQueryAnalysis")) {
		mongoc_auto_encryption_opts_set_bypass_query_analysis(auto_encryption_opts, php_array_fetchc_bool(zAutoEncryptionOpts, "bypassQueryAnalysis"));
	}

	if (php_array_existsc(zAutoEncryptionOpts, "encryptedFieldsMap")) {
		zval*  enc_fields_map = php_array_fetchc_deref(zAutoEncryptionOpts, "encryptedFieldsMap");
		bson_t bson_map       = BSON_INITIALIZER;

		if (Z_TYPE_P(enc_fields_map) != IS_OBJECT && Z_TYPE_P(enc_fields_map) != IS_ARRAY) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"encryptedFieldsMap\" autoEncryption option to be an array or object, %s given", zend_zval_type_name(enc_fields_map));
			goto cleanup;
		}

		php_phongo_zval_to_bson(enc_fields_map, PHONGO_BSON_NONE, &bson_map, NULL);
		if (EG(exception)) {
			goto cleanup;
		}

		mongoc_auto_encryption_opts_set_encrypted_fields_map(auto_encryption_opts, &bson_map);

		bson_destroy(&bson_map);

		/* Copy the encryptedFieldsMap to the Manager since PHPLIB may need to
		 * access it for createCollection and dropCollection helpers. */
		ZVAL_ZVAL(&manager->enc_fields_map, enc_fields_map, 1, 0);
	}

	if (php_array_existsc(zAutoEncryptionOpts, "keyVaultClient")) {
		zval* key_vault_client = php_array_fetchc_deref(zAutoEncryptionOpts, "keyVaultClient");

		if (Z_TYPE_P(key_vault_client) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(key_vault_client), php_phongo_manager_ce)) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"keyVaultClient\" autoEncryption option to be %s, %s given", ZSTR_VAL(php_phongo_manager_ce->name), zend_zval_type_name(key_vault_client));
			goto cleanup;
		}

		/* Ensure the Manager and keyVaultClient are consistent in their use of
		 * persistent clients. A non-persistent Manager could theoretically use
		 * a persistent keyVaultClient, but this prohibition may help prevent
		 * users from inadvertently creating a persistent keyVaultClient. */
		if (manager->use_persistent_client != Z_MANAGER_OBJ_P(key_vault_client)->use_persistent_client) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "The \"disableClientPersistence\" option for a Manager and its \"keyVaultClient\" must be the same");
			goto cleanup;
		}

		mongoc_auto_encryption_opts_set_keyvault_client(auto_encryption_opts, Z_MANAGER_OBJ_P(key_vault_client)->client);

		/* Copy the keyVaultClient to the Manager to allow for ref-counting (for
		 * non-persistent clients) and reset-on-fork behavior. */
		ZVAL_ZVAL(&manager->key_vault_client_manager, key_vault_client, 1, 0);
	}

	if (php_array_existsc(zAutoEncryptionOpts, "keyVaultNamespace")) {
		char*     key_vault_ns;
		char*     db_name;
		char*     coll_name;
		int       plen;
		zend_bool pfree;

		key_vault_ns = php_array_fetchc_string(zAutoEncryptionOpts, "keyVaultNamespace", &plen, &pfree);

		if (!phongo_split_namespace(key_vault_ns, &db_name, &coll_name)) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"keyVaultNamespace\" autoEncryption option to contain a full collection namespace");

			if (pfree) {
				efree(key_vault_ns);
			}

			goto cleanup;
		}

		mongoc_auto_encryption_opts_set_keyvault_namespace(auto_encryption_opts, db_name, coll_name);

		efree(db_name);
		efree(coll_name);

		if (pfree) {
			efree(key_vault_ns);
		}
	}

	if (php_array_existsc(zAutoEncryptionOpts, "kmsProviders")) {
		zval*  kms_providers  = php_array_fetchc_deref(zAutoEncryptionOpts, "kmsProviders");
		bson_t bson_providers = BSON_INITIALIZER;

		if (Z_TYPE_P(kms_providers) != IS_OBJECT && Z_TYPE_P(kms_providers) != IS_ARRAY) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"kmsProviders\" autoEncryption option to be an array or object, %s given", zend_zval_type_name(kms_providers));
			goto cleanup;
		}

		php_phongo_zval_to_bson(kms_providers, PHONGO_BSON_NONE, &bson_providers, NULL);
		if (EG(exception)) {
			goto cleanup;
		}

		mongoc_auto_encryption_opts_set_kms_providers(auto_encryption_opts, &bson_providers);

		bson_destroy(&bson_providers);
	}

	if (php_array_existsc(zAutoEncryptionOpts, "schemaMap")) {
		zval*  schema_map = php_array_fetchc_deref(zAutoEncryptionOpts, "schemaMap");
		bson_t bson_map   = BSON_INITIALIZER;

		if (Z_TYPE_P(schema_map) != IS_OBJECT && Z_TYPE_P(schema_map) != IS_ARRAY) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"schemaMap\" autoEncryption option to be an array or object, %s given", zend_zval_type_name(schema_map));
			goto cleanup;
		}

		php_phongo_zval_to_bson(schema_map, PHONGO_BSON_NONE, &bson_map, NULL);
		if (EG(exception)) {
			goto cleanup;
		}

		mongoc_auto_encryption_opts_set_schema_map(auto_encryption_opts, &bson_map);

		bson_destroy(&bson_map);
	}

	if (php_array_existsc(zAutoEncryptionOpts, "tlsOptions")) {
		zval*  tls_options  = php_array_fetchc_deref(zAutoEncryptionOpts, "tlsOptions");
		bson_t bson_options = BSON_INITIALIZER;

		if (Z_TYPE_P(tls_options) != IS_OBJECT && Z_TYPE_P(tls_options) != IS_ARRAY) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"tlsOptions\" autoEncryption option to be an array or object, %s given", zend_zval_type_name(tls_options));
			goto cleanup;
		}

		php_phongo_zval_to_bson(tls_options, PHONGO_BSON_NONE, &bson_options, NULL);
		if (EG(exception)) {
			goto cleanup;
		}

		mongoc_auto_encryption_opts_set_tls_opts(auto_encryption_opts, &bson_options);

		bson_destroy(&bson_options);
	}

	if (php_array_existsc(zAutoEncryptionOpts, "extraOptions")) {
		zval*  extra_options = php_array_fetchc_deref(zAutoEncryptionOpts, "extraOptions");
		bson_t bson_options  = BSON_INITIALIZER;

		if (Z_TYPE_P(extra_options) != IS_OBJECT && Z_TYPE_P(extra_options) != IS_ARRAY) {
			phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"extraOptions\" autoEncryption option to be an array or object, %s given", zend_zval_type_name(extra_options));
			goto cleanup;
		}

		php_phongo_zval_to_bson(extra_options, PHONGO_BSON_NONE, &bson_options, NULL);
		if (EG(exception)) {
			goto cleanup;
		}

		mongoc_auto_encryption_opts_set_extra(auto_encryption_opts, &bson_options);

		bson_destroy(&bson_options);
	}

	if (!mongoc_client_enable_auto_encryption(manager->client, auto_encryption_opts, &error)) {
		phongo_throw_exception_from_bson_error_t(&error);
		goto cleanup;
	}

	retval = true;

cleanup:
	mongoc_auto_encryption_opts_destroy(auto_encryption_opts);
	return retval;
}
#else  /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */
static bool phongo_manager_set_auto_encryption_opts(php_phongo_manager_t* manager, zval* driverOptions)
{
	if (!driverOptions || !php_array_existsc(driverOptions, "autoEncryption")) {
		return true;
	}

	phongo_throw_exception_no_cse(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot enable automatic field-level encryption.");

	return false;
}
#endif /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */

void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string, zval* options, zval* driverOptions)
{
	bson_t        bson_options = BSON_INITIALIZER;
	mongoc_uri_t* uri          = NULL;
#ifdef MONGOC_ENABLE_SSL
	mongoc_ssl_opt_t* ssl_opt = NULL;
#endif

	if (!(manager->client_hash = php_phongo_manager_make_client_hash(uri_string, options, driverOptions, &manager->client_hash_len))) {
		/* Exception should already have been thrown and there is nothing to free */
		return;
	}

	if (driverOptions && php_array_existsc(driverOptions, "disableClientPersistence")) {
		manager->use_persistent_client = !php_array_fetchc_bool(driverOptions, "disableClientPersistence");
	} else {
		manager->use_persistent_client = true;
	}

	if (manager->use_persistent_client && (manager->client = php_phongo_find_persistent_client(manager->client_hash, manager->client_hash_len))) {
		MONGOC_DEBUG("Found client for hash: %s", manager->client_hash);
		goto cleanup;
	}

	if (options) {
		php_phongo_zval_to_bson(options, PHONGO_BSON_NONE, &bson_options, NULL);
	}

	/* An exception may be thrown during BSON conversion */
	if (EG(exception)) {
		goto cleanup;
	}

	if (!(uri = php_phongo_make_uri(uri_string))) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	if (!php_phongo_apply_options_to_uri(uri, &bson_options) ||
		!php_phongo_apply_rc_options_to_uri(uri, &bson_options) ||
		!php_phongo_apply_rp_options_to_uri(uri, &bson_options) ||
		!php_phongo_apply_wc_options_to_uri(uri, &bson_options)) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

#ifdef MONGOC_ENABLE_SSL
	if (!php_phongo_apply_driver_options_to_uri(uri, driverOptions)) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	ssl_opt = php_phongo_make_ssl_opt(uri, driverOptions);

	/* An exception may be thrown during SSL option creation */
	if (EG(exception)) {
		goto cleanup;
	}
#endif

	manager->client = php_phongo_make_mongo_client(uri, driverOptions);

	if (!manager->client) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	mongoc_client_set_error_api(manager->client, MONGOC_ERROR_API_VERSION_2);

#ifdef MONGOC_ENABLE_SSL
	if (ssl_opt) {
		mongoc_client_set_ssl_opts(manager->client, ssl_opt);
	}
#endif

	if (!phongo_manager_set_auto_encryption_opts(manager, driverOptions)) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	if (!phongo_manager_set_serverapi_opts(manager, driverOptions)) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	if (!phongo_apm_set_callbacks(manager->client)) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	MONGOC_DEBUG("Created client with hash: %s", manager->client_hash);

	/* Register the newly created client in the appropriate registry (for either
	 * persistent or request-scoped clients). */
	if (!php_phongo_client_register(manager)) {
		phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Failed to add Manager client to internal registry");
		goto cleanup;
	}

cleanup:
	bson_destroy(&bson_options);

	if (uri) {
		mongoc_uri_destroy(uri);
	}

#ifdef MONGOC_ENABLE_SSL
	if (ssl_opt) {
		php_phongo_free_ssl_opt(ssl_opt);
	}
#endif
}

static void phongo_pclient_reset_once(php_phongo_pclient_t* pclient, int pid)
{
	if (pclient->last_reset_by_pid != pid) {
		mongoc_client_reset(pclient->client);
		pclient->last_reset_by_pid = pid;
	}
}

/* Resets the libmongoc client if it has not already been reset for the current
 * PID (based on information in the hash table of persisted libmongoc clients).
 * This ensures that we do not reset a client multiple times from the same child
 * process. */
void php_phongo_client_reset_once(php_phongo_manager_t* manager, int pid)
{
	php_phongo_pclient_t* pclient;

	/* Reset associated key vault client */
	if (!Z_ISUNDEF(manager->key_vault_client_manager)) {
		php_phongo_client_reset_once(Z_MANAGER_OBJ_P(&manager->key_vault_client_manager), pid);
	}

	if (manager->use_persistent_client) {
		pclient = zend_hash_str_find_ptr(&MONGODB_G(persistent_clients), manager->client_hash, manager->client_hash_len);

		if (pclient) {
			phongo_pclient_reset_once(pclient, pid);
		}

		return;
	}

	ZEND_HASH_FOREACH_PTR(MONGODB_G(request_clients), pclient)
	{
		if (pclient->client == manager->client) {
			phongo_pclient_reset_once(pclient, pid);

			/* Request-scoped clients are only used by a single Manager, so we
			 * can return early after finding a match. */
			return;
		}
	}
	ZEND_HASH_FOREACH_END();
}

/* Returns whether a Manager exists in the request-scoped registry. If found and
 * the output parameter is non-NULL, the Manager's index will be assigned. */
static bool php_phongo_manager_exists(php_phongo_manager_t* manager, zend_ulong* index_out)
{
	zend_ulong            index;
	php_phongo_manager_t* value;

	if (!MONGODB_G(managers) || zend_hash_num_elements(MONGODB_G(managers)) == 0) {
		return false;
	}

	ZEND_HASH_FOREACH_NUM_KEY_PTR(MONGODB_G(managers), index, value)
	{
		if (value != manager) {
			continue;
		}

		if (index_out) {
			*index_out = index;
		}

		return true;
	}
	ZEND_HASH_FOREACH_END();

	return false;
}

/* Adds a Manager to the request-scoped registry. Returns true if the Manager
 * did not exist and was successfully added; otherwise, returns false. */
bool php_phongo_manager_register(php_phongo_manager_t* manager)
{
	if (!MONGODB_G(managers)) {
		return false;
	}

	if (php_phongo_manager_exists(manager, NULL)) {
		return false;
	}

	return zend_hash_next_index_insert_ptr(MONGODB_G(managers), manager) != NULL;
}

/* Removes a Manager from the request-scoped registry. Returns true if the
 * Manager was found and successfully removed; otherwise, false is returned. */
bool php_phongo_manager_unregister(php_phongo_manager_t* manager)
{
	zend_ulong index;

	/* Ensure the registry is initialized. This is needed because RSHUTDOWN may
	 * occur before a Manager's free_object handler is executed. */
	if (!MONGODB_G(managers)) {
		return false;
	}

	if (php_phongo_manager_exists(manager, &index)) {
		return zend_hash_index_del(MONGODB_G(managers), index) == SUCCESS;
	}

	return false;
}

static void php_phongo_pclient_destroy(php_phongo_pclient_t* pclient)
{
	/* Do not destroy mongoc_client_t objects created by other processes. This
	 * ensures that we do not shutdown sockets that may still be in use by our
	 * parent process (see: PHPC-1522).
	 *
	 * This is a leak; however, we are already in GSHUTDOWN for a persistent
	 * clients. For a request-scoped client, we are either in the Manager's
	 * free_object handler or RSHUTDOWN, but there the application is capable of
	 * freeing its Manager and its client before forking. */
	if (pclient->created_by_pid == getpid()) {
		/* If we are in request shutdown, disable APM to avoid dispatching more
		 * events. This means that certain events (e.g. TopologyClosedEvent,
		 * command monitoring for endSessions) may not be observed. */
		if (EG(flags) & EG_FLAGS_IN_SHUTDOWN) {
			mongoc_client_set_apm_callbacks(pclient->client, NULL, NULL);
		}
		mongoc_client_destroy(pclient->client);
	}

	/* Persistent and request-scoped clients use different memory allocation */
	pefree(pclient, pclient->is_persistent);
}

void php_phongo_pclient_destroy_ptr(zval* ptr)
{
	php_phongo_pclient_destroy(Z_PTR_P(ptr));
}
mongodb-1.21.0/src/phongo_client.h0000644000175100001660000000315314760300420013727 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#ifndef PHONGO_CLIENT_H
#define PHONGO_CLIENT_H

#include 

#include "phongo_classes.h"

const char* php_phongo_crypt_shared_version(void);

void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string, zval* options, zval* driverOptions);

void php_phongo_client_reset_once(php_phongo_manager_t* manager, int pid);
bool php_phongo_client_register(php_phongo_manager_t* manager);
bool php_phongo_client_unregister(php_phongo_manager_t* manager);

bool php_phongo_manager_register(php_phongo_manager_t* manager);
bool php_phongo_manager_unregister(php_phongo_manager_t* manager);

void php_phongo_pclient_destroy_ptr(zval* ptr);

#define PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern, manager) \
	do {                                                    \
		int pid = (int) getpid();                           \
		if ((intern)->created_by_pid != pid) {              \
			php_phongo_client_reset_once((manager), pid);   \
		}                                                   \
	} while (0)

#endif /* PHONGO_CLIENT_H */
mongodb-1.21.0/src/phongo_compat.c0000644000175100001660000000273314760300420013732 0ustar  /*
 * Copyright 2015-present MongoDB, 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.
 */

#include 

#include "phongo_compat.h"

zend_bool php_phongo_zend_hash_apply_protection_begin(zend_array* ht)
{
	if (GC_IS_RECURSIVE(ht)) {
		return 0;
	}
	if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
		GC_PROTECT_RECURSION(ht);
	}
	return 1;
}

zend_bool php_phongo_zend_hash_apply_protection_end(zend_array* ht)
{
	if (!GC_IS_RECURSIVE(ht)) {
		return 0;
	}
	if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
		GC_UNPROTECT_RECURSION(ht);
	}
	return 1;
}

#if PHP_VERSION_ID < 80200
const char* zend_get_object_type_case(const zend_class_entry* ce, zend_bool upper_case)
{
	if (ce->ce_flags & ZEND_ACC_TRAIT) {
		return upper_case ? "Trait" : "trait";
	}
	if (ce->ce_flags & ZEND_ACC_INTERFACE) {
		return upper_case ? "Interface" : "interface";
	}
	if (ce->ce_flags & ZEND_ACC_ENUM) {
		return upper_case ? "Enum" : "enum";
	}
	return upper_case ? "Class" : "class";
}
#endif /* PHP_VERSION_ID < 80200 */
mongodb-1.21.0/src/phongo_compat.h0000644000175100001660000002334514760300420013741 0ustar  /*
 * Copyright 2015-present MongoDB, 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.
 */

#ifndef PHONGO_COMPAT_H
#define PHONGO_COMPAT_H

#include 
#include 
#include 
#include 

/* Include stdbool.h as it might not have been implicitly loaded yet */
#include 
#include "BSON/Int64.h"

#ifdef PHP_WIN32
#include "config.w32.h"
#else
#include 
#endif

#ifndef PHP_FE_END
#define PHP_FE_END       \
	{                    \
		NULL, NULL, NULL \
	}
#endif

#ifndef HASH_KEY_NON_EXISTENT
#define HASH_KEY_NON_EXISTENT HASH_KEY_NON_EXISTANT
#endif

#if defined(__GNUC__)
#define ARG_UNUSED __attribute__((unused))
#else
#define ARG_UNUSED
#endif

#if defined(__GNUC__)
#define PHONGO_GNUC_CHECK_VERSION(major, minor) \
	((__GNUC__ > (major)) ||                    \
	 ((__GNUC__ == (major)) && (__GNUC_MINOR__ >= (minor))))
#else
#define PHONGO_GNUC_CHECK_VERSION(major, minor) 0
#endif

#if PHONGO_GNUC_CHECK_VERSION(7, 0)
#define PHONGO_BREAK_INTENTIONALLY_MISSING __attribute__((fallthrough));
#elif defined(__clang__) && __clang_major__ >= 12
#define PHONGO_BREAK_INTENTIONALLY_MISSING __attribute__((fallthrough));
#else
#define PHONGO_BREAK_INTENTIONALLY_MISSING
#endif

#if SIZEOF_ZEND_LONG == 8
#define PHONGO_LONG_FORMAT PRId64
#elif SIZEOF_ZEND_LONG == 4
#define PHONGO_LONG_FORMAT PRId32
#else
#error Unsupported architecture (integers are neither 32-bit nor 64-bit)
#endif

#define ADD_ASSOC_STR(_zv, _key, _value) add_assoc_string_ex(_zv, ZEND_STRL(_key), (char*) ZSTR_VAL(_value));
#define ADD_ASSOC_STRING(_zv, _key, _value) add_assoc_string_ex(_zv, ZEND_STRL(_key), (char*) (_value));
#define ADD_ASSOC_STRINGL(_zv, _key, _value, _len) add_assoc_stringl_ex(_zv, ZEND_STRL(_key), (char*) (_value), _len);
#define ADD_ASSOC_STRING_EX(_zv, _key, _key_len, _value, _value_len) add_assoc_stringl_ex(_zv, _key, _key_len, (char*) (_value), _value_len);
#define ADD_ASSOC_LONG_EX(_zv, _key, _value) add_assoc_long_ex(_zv, ZEND_STRL(_key), _value);
#define ADD_ASSOC_ZVAL_EX(_zv, _key, _value) add_assoc_zval_ex(_zv, ZEND_STRL(_key), _value);
#define ADD_ASSOC_ZVAL(_zv, _key, _value) add_assoc_zval(_zv, _key, _value);
#define ADD_ASSOC_NULL_EX(_zv, _key) add_assoc_null_ex(_zv, ZEND_STRL(_key));
#define ADD_ASSOC_BOOL_EX(_zv, _key, _value) add_assoc_bool_ex(_zv, ZEND_STRL(_key), _value);
#define ZVAL_INT64_STRING(_zv, _value)                              \
	do {                                                            \
		char tmp[24];                                               \
		int  tmp_len;                                               \
		tmp_len = snprintf(tmp, sizeof(tmp), "%" PRId64, (_value)); \
		ZVAL_STRINGL((_zv), tmp, tmp_len);                          \
	} while (0)
#define ADD_ASSOC_INT64_AS_STRING(_zv, _key, _value) \
	do {                                             \
		zval z_int;                                  \
		ZVAL_INT64_STRING(&z_int, (_value));         \
		ADD_ASSOC_ZVAL_EX((_zv), (_key), &z_int);    \
	} while (0)
#define ADD_NEXT_INDEX_STRINGL(_zv, _value, _len) add_next_index_stringl(_zv, _value, _len);
#define PHONGO_RETVAL_SMART_STR(val) RETVAL_STRINGL(ZSTR_VAL((val).s), ZSTR_LEN((val).s));
#define ZVAL_STATIC_INIT \
	{                    \
		{                \
			0            \
		}                \
	}

#define ADD_NEXT_INDEX_INT64_OBJ(_zv, _value) \
	do {                                      \
		zval zchild;                          \
		phongo_int64_new(&zchild, (_value));  \
		add_next_index_zval((_zv), &zchild);  \
	} while (0);
#define ADD_ASSOC_INT64_OBJ(_zv, _key, _value)  \
	do {                                        \
		zval zchild;                            \
		phongo_int64_new(&zchild, (_value));    \
		add_assoc_zval((_zv), (_key), &zchild); \
	} while (0);
#if SIZEOF_ZEND_LONG == 8
#define ADD_INDEX_INT64(_zv, _index, _value) add_index_long((_zv), (_index), (_value))
#define ADD_NEXT_INDEX_INT64(_zv, _value) add_next_index_long((_zv), (_value))
#define ADD_ASSOC_INT64(_zv, _key, _value) add_assoc_long((_zv), (_key), (_value))
#define ZVAL_INT64(_zv, _value) ZVAL_LONG((_zv), (_value))
#elif SIZEOF_ZEND_LONG == 4
/* The following macros do not handle a false return value for phongo_int64_new.
 * As the function currently does not return false this works fine, but will
 * need updating if that changes. */
#define ADD_INDEX_INT64(_zv, _index, _value)            \
	if ((_value) > INT32_MAX || (_value) < INT32_MIN) { \
		zval zchild;                                    \
		phongo_int64_new(&zchild, (_value));            \
		add_index_zval((_zv), (_index), &zchild);       \
	} else {                                            \
		add_index_long((_zv), (_index), (_value));      \
	}
#define ADD_NEXT_INDEX_INT64(_zv, _value)               \
	if ((_value) > INT32_MAX || (_value) < INT32_MIN) { \
		zval zchild;                                    \
		phongo_int64_new(&zchild, (_value));            \
		add_next_index_zval((_zv), &zchild);            \
	} else {                                            \
		add_next_index_long((_zv), (_value));           \
	}
#define ADD_ASSOC_INT64(_zv, _key, _value)              \
	if ((_value) > INT32_MAX || (_value) < INT32_MIN) { \
		zval zchild;                                    \
		phongo_int64_new(&zchild, (_value));            \
		add_assoc_zval((_zv), (_key), &zchild);         \
	} else {                                            \
		add_assoc_long((_zv), (_key), (_value));        \
	}
#define ZVAL_INT64(_zv, _value)                         \
	if ((_value) > INT32_MAX || (_value) < INT32_MIN) { \
		phongo_int64_new((_zv), (_value));              \
	} else {                                            \
		ZVAL_LONG((_zv), (_value));                     \
	}
#else /* SIZEOF_ZEND_LONG != 8 && SIZEOF_ZEND_LONG != 4 */
#error Unsupported architecture (integers are neither 32-bit nor 64-bit)
#endif /* SIZEOF_ZEND_LONG */

/* Compatibility macros to override error handling logic */
#define PHONGO_PARSE_PARAMETERS_START(min_num_args, max_num_args)               \
	do {                                                                        \
		zend_error_handling error_handling;                                     \
		zend_replace_error_handling(                                            \
			EH_THROW,                                                           \
			phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), \
			&error_handling);                                                   \
	ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)

#define PHONGO_PARSE_PARAMETERS_END()                 \
	ZEND_PARSE_PARAMETERS_END_EX(                     \
		zend_restore_error_handling(&error_handling); \
		return );                                     \
	zend_restore_error_handling(&error_handling);     \
	}                                                 \
	while (0)

#ifndef ZEND_PARSE_PARAMETERS_NONE
#define PHONGO_PARSE_PARAMETERS_NONE()                                          \
	do {                                                                        \
		zend_error_handling error_handling;                                     \
		zend_replace_error_handling(                                            \
			EH_THROW,                                                           \
			phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), \
			&error_handling);                                                   \
		if (zend_parse_parameters_none() == FAILURE) {                          \
			zend_restore_error_handling(&error_handling);                       \
			return;                                                             \
		}                                                                       \
		zend_restore_error_handling(&error_handling);                           \
	} while (0)
#else
#define PHONGO_PARSE_PARAMETERS_NONE()                                          \
	do {                                                                        \
		zend_error_handling error_handling;                                     \
		zend_replace_error_handling(                                            \
			EH_THROW,                                                           \
			phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), \
			&error_handling);                                                   \
		if (UNEXPECTED(ZEND_NUM_ARGS() != 0)) {                                 \
			zend_wrong_parameters_none_error();                                 \
			zend_restore_error_handling(&error_handling);                       \
			return;                                                             \
		}                                                                       \
		zend_restore_error_handling(&error_handling);                           \
	} while (0)
#endif

zend_bool php_phongo_zend_hash_apply_protection_begin(HashTable* ht);
zend_bool php_phongo_zend_hash_apply_protection_end(HashTable* ht);

/* zend_get_object_type_case functions were introduced in PHP 8.2 */
#if PHP_VERSION_ID < 80200
const char* zend_get_object_type_case(const zend_class_entry* ce, zend_bool upper_case);
#define zend_get_object_type(ce) zend_get_object_type_case((ce), false)
#define zend_get_object_type_uc(ce) zend_get_object_type_case((ce), true)
#endif /* PHP_VERSION_ID < 80200 */

#endif /* PHONGO_COMPAT_H */
mongodb-1.21.0/src/phongo_error.c0000644000175100001660000001533714760300420013604 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#include "bson/bson.h"
#include "mongoc/mongoc.h"

#include 
#include 

#include "php_phongo.h"
#include "phongo_error.h"

/* This constant is used for determining if a server error for an exceeded query
 * or command should select ExecutionTimeoutException. */
#define PHONGO_SERVER_ERROR_EXCEEDED_TIME_LIMIT 50

void phongo_add_exception_prop(const char* prop, int prop_len, zval* value)
{
	if (EG(exception)) {
		zval ex;
		ZVAL_OBJ(&ex, EG(exception));
		zend_update_property(Z_OBJCE(ex), Z_OBJ_P(&ex), prop, prop_len, value);
	}
}

zend_class_entry* phongo_exception_from_phongo_domain(php_phongo_error_domain_t domain)
{
	switch (domain) {
		case PHONGO_ERROR_INVALID_ARGUMENT:
			return php_phongo_invalidargumentexception_ce;
		case PHONGO_ERROR_LOGIC:
			return php_phongo_logicexception_ce;
		case PHONGO_ERROR_RUNTIME:
			return php_phongo_runtimeexception_ce;
		case PHONGO_ERROR_UNEXPECTED_VALUE:
			return php_phongo_unexpectedvalueexception_ce;
		case PHONGO_ERROR_MONGOC_FAILED:
			return php_phongo_runtimeexception_ce;
		case PHONGO_ERROR_CONNECTION_FAILED:
			return php_phongo_connectionexception_ce;
	}

	MONGOC_ERROR("Resolving unknown phongo error domain: %d", domain);
	return php_phongo_runtimeexception_ce;
}

zend_class_entry* phongo_exception_from_mongoc_domain(mongoc_error_domain_t domain, mongoc_error_code_t code)
{
	if (domain == MONGOC_ERROR_CLIENT) {
		if (code == MONGOC_ERROR_CLIENT_AUTHENTICATE) {
			return php_phongo_authenticationexception_ce;
		}

		if (code == MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG) {
			return php_phongo_invalidargumentexception_ce;
		}
	}

	if (domain == MONGOC_ERROR_COMMAND && code == MONGOC_ERROR_COMMAND_INVALID_ARG) {
		return php_phongo_invalidargumentexception_ce;
	}

	if (domain == MONGOC_ERROR_SERVER) {
		if (code == PHONGO_SERVER_ERROR_EXCEEDED_TIME_LIMIT) {
			return php_phongo_executiontimeoutexception_ce;
		}

		return php_phongo_serverexception_ce;
	}

	if (domain == MONGOC_ERROR_SERVER_SELECTION && code == MONGOC_ERROR_SERVER_SELECTION_FAILURE) {
		return php_phongo_connectiontimeoutexception_ce;
	}

	if (domain == MONGOC_ERROR_STREAM) {
		if (code == MONGOC_ERROR_STREAM_SOCKET) {
			return php_phongo_connectiontimeoutexception_ce;
		}

		return php_phongo_connectionexception_ce;
	}

	if (domain == MONGOC_ERROR_WRITE_CONCERN) {
		return php_phongo_serverexception_ce;
	}

	if (domain == MONGOC_ERROR_PROTOCOL && code == MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION) {
		return php_phongo_connectionexception_ce;
	}

	if (domain == MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION) {
		return php_phongo_encryptionexception_ce;
	}

	return php_phongo_runtimeexception_ce;
}

void phongo_throw_exception(php_phongo_error_domain_t domain, const char* format, ...)
{
	va_list args;
	char*   message;
	int     message_len;

	va_start(args, format);
	message_len = vspprintf(&message, 0, format, args);
	zend_throw_exception(phongo_exception_from_phongo_domain(domain), message, 0);
	efree(message);
	va_end(args);
}

static int phongo_exception_append_error_labels(zval* labels, const bson_iter_t* iter)
{
	bson_iter_t error_labels;
	uint32_t    label_count = 0;

	if (!BSON_ITER_HOLDS_ARRAY(iter) || !bson_iter_recurse(iter, &error_labels)) {
		return label_count;
	}

	while (bson_iter_next(&error_labels)) {
		if (BSON_ITER_HOLDS_UTF8(&error_labels)) {
			const char* error_label;
			uint32_t    error_label_len;

			error_label = bson_iter_utf8(&error_labels, &error_label_len);
			ADD_NEXT_INDEX_STRINGL(labels, error_label, error_label_len);
			label_count++;
		}
	}

	return label_count;
}

void phongo_exception_add_error_labels(const bson_t* reply)
{
	bson_iter_t iter, child;
	zval        labels;
	uint32_t    label_count = 0;

	if (!reply) {
		return;
	}

	array_init(&labels);

	if (bson_iter_init_find(&iter, reply, "errorLabels")) {
		label_count += phongo_exception_append_error_labels(&labels, &iter);
	}

	if (bson_iter_init_find(&iter, reply, "writeConcernError") && BSON_ITER_HOLDS_DOCUMENT(&iter) &&
		bson_iter_recurse(&iter, &child) && bson_iter_find(&child, "errorLabels")) {
		label_count += phongo_exception_append_error_labels(&labels, &child);
	}

	/* mongoc_write_result_t always reports writeConcernErrors in an array, so
	 * we must iterate this to collect WCE labels for BulkWrite replies. */
	if (bson_iter_init_find(&iter, reply, "writeConcernErrors") && BSON_ITER_HOLDS_ARRAY(&iter) && bson_iter_recurse(&iter, &child)) {
		bson_iter_t wce;

		while (bson_iter_next(&child)) {
			if (BSON_ITER_HOLDS_DOCUMENT(&child) && bson_iter_recurse(&child, &wce) && bson_iter_find(&wce, "errorLabels")) {
				label_count += phongo_exception_append_error_labels(&labels, &wce);
			}
		}
	}

	if (label_count > 0) {
		phongo_add_exception_prop(ZEND_STRL("errorLabels"), &labels);
	}

	zval_ptr_dtor(&labels);
}

void phongo_throw_exception_from_bson_error_t_and_reply(bson_error_t* error, const bson_t* reply)
{
	/* Server errors (other than ExceededTimeLimit) and write concern errors
	 * may use CommandException and report the result document for the
	 * failed command. For BC, ExceededTimeLimit errors will continue to use
	 * ExcecutionTimeoutException and omit the result document. */
	if (reply && ((error->domain == MONGOC_ERROR_SERVER && error->code != PHONGO_SERVER_ERROR_EXCEEDED_TIME_LIMIT) || error->domain == MONGOC_ERROR_WRITE_CONCERN)) {
		zval zv;

		zend_throw_exception(php_phongo_commandexception_ce, error->message, error->code);
		if (php_phongo_bson_to_zval(reply, &zv)) {
			phongo_add_exception_prop(ZEND_STRL("resultDocument"), &zv);
		}

		zval_ptr_dtor(&zv);
	} else {
		zend_throw_exception(phongo_exception_from_mongoc_domain(error->domain, error->code), error->message, error->code);
	}
	phongo_exception_add_error_labels(reply);
}

void phongo_throw_exception_from_bson_error_t(bson_error_t* error)
{
	phongo_throw_exception_from_bson_error_t_and_reply(error, NULL);
}

#ifndef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION
void phongo_throw_exception_no_cse(php_phongo_error_domain_t domain, const char* message)
{
	phongo_throw_exception(domain, "%s Please recompile with support for libmongocrypt using the with-mongodb-client-side-encryption configure switch.", message);
}
#endif /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */
mongodb-1.21.0/src/phongo_error.h0000644000175100001660000000346214760300420013605 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#ifndef PHONGO_ERROR_H
#define PHONGO_ERROR_H

#include "bson/bson.h"
#include "mongoc/mongoc.h"

typedef enum {
	PHONGO_ERROR_INVALID_ARGUMENT  = 1,
	PHONGO_ERROR_RUNTIME           = 2,
	PHONGO_ERROR_UNEXPECTED_VALUE  = 8,
	PHONGO_ERROR_MONGOC_FAILED     = 3,
	PHONGO_ERROR_CONNECTION_FAILED = 7,
	PHONGO_ERROR_LOGIC             = 9
} php_phongo_error_domain_t;

void              phongo_add_exception_prop(const char* prop, int prop_len, zval* value);
zend_class_entry* phongo_exception_from_mongoc_domain(mongoc_error_domain_t domain, mongoc_error_code_t code);
zend_class_entry* phongo_exception_from_phongo_domain(php_phongo_error_domain_t domain);
void              phongo_exception_add_error_labels(const bson_t* reply);
void              phongo_throw_exception(php_phongo_error_domain_t domain, const char* format, ...);
void              phongo_throw_exception_from_bson_error_t(bson_error_t* error);
void              phongo_throw_exception_from_bson_error_t_and_reply(bson_error_t* error, const bson_t* reply);

#ifndef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION
void phongo_throw_exception_no_cse(php_phongo_error_domain_t domain, const char* message);
#endif /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */

#endif /* PHONGO_ERROR_H */
mongodb-1.21.0/src/phongo_execute.c0000644000175100001660000004742614760300420014121 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#include "bson/bson.h"
#include "mongoc/mongoc.h"

#include 
#include 

#include "php_array_api.h"

#include "php_phongo.h"
#include "phongo_error.h"
#include "phongo_execute.h"
#include "phongo_util.h"

#include "MongoDB/Cursor.h"
#include "MongoDB/ReadPreference.h"
#include "MongoDB/Session.h"
#include "MongoDB/WriteResult.h"

static bson_t* create_wrapped_command_envelope(const char* db, bson_t* reply)
{
	bson_t* tmp;
	size_t  max_ns_len = strlen(db) + 5 + 1; /* db + ".$cmd" + '\0' */
	char*   ns         = emalloc(max_ns_len);

	snprintf(ns, max_ns_len, "%s.$cmd", db);
	tmp = BCON_NEW("cursor", "{", "id", BCON_INT64(0), "ns", BCON_UTF8(ns), "firstBatch", "[", BCON_DOCUMENT(reply), "]", "}");
	efree(ns);

	return tmp;
}

static zval* phongo_create_implicit_session(zval* manager)
{
	mongoc_client_session_t* cs;
	zval*                    zsession;

	cs = mongoc_client_start_session(Z_MANAGER_OBJ_P(manager)->client, NULL, NULL);

	if (!cs) {
		return NULL;
	}

	zsession = ecalloc(1, sizeof(zval));

	phongo_session_init(zsession, manager, cs);

	return zsession;
}

/* Parses the "readConcern" option for an execute method. If mongoc_opts is not
 * NULL, the option will be appended. On error, false is returned and an
 * exception is thrown. */
static bool phongo_parse_read_concern(zval* options, bson_t* mongoc_opts)
{
	zval*                  option = NULL;
	mongoc_read_concern_t* read_concern;

	if (!options) {
		return true;
	}

	if (Z_TYPE_P(options) != IS_ARRAY) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected options to be array, %s given", zend_zval_type_name(options));
		return false;
	}

	option = php_array_fetchc_deref(options, "readConcern");

	if (!option) {
		return true;
	}

	if (Z_TYPE_P(option) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(option), php_phongo_readconcern_ce)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"readConcern\" option to be %s, %s given", ZSTR_VAL(php_phongo_readconcern_ce->name), zend_zval_type_name(option));
		return false;
	}

	read_concern = Z_READCONCERN_OBJ_P(option)->read_concern;

	if (mongoc_opts && !mongoc_read_concern_append(read_concern, mongoc_opts)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"readConcern\" option");
		return false;
	}

	return true;
}

/* Parses the "readPreference" option for an execute method. If zreadPreference
 * is not NULL, it will be assigned to the option. On error, false is returned
 * and an exception is thrown. */
bool phongo_parse_read_preference(zval* options, zval** zreadPreference)
{
	zval* option = NULL;

	if (!options) {
		return true;
	}

	if (Z_TYPE_P(options) != IS_ARRAY) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected options to be array, %s given", zend_zval_type_name(options));
		return false;
	}

	option = php_array_fetchc_deref(options, "readPreference");

	if (!option) {
		return true;
	}

	if (Z_TYPE_P(option) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(option), php_phongo_readpreference_ce)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"readPreference\" option to be %s, %s given", ZSTR_VAL(php_phongo_readpreference_ce->name), zend_zval_type_name(option));
		return false;
	}

	if (zreadPreference) {
		*zreadPreference = option;
	}

	return true;
}

/* Parses the "session" option for an execute method. The client object should
 * correspond to the Manager executing the operation and will be used to ensure
 * that the session is correctly associated with that client. If mongoc_opts is
 * not NULL, the option will be appended. If zsession is not NULL, it will be
 * assigned to the option. On error, false is returned and an exception is
 * thrown. */
bool phongo_parse_session(zval* options, mongoc_client_t* client, bson_t* mongoc_opts, zval** zsession)
{
	zval*                          option = NULL;
	const mongoc_client_session_t* client_session;

	if (!options) {
		return true;
	}

	if (Z_TYPE_P(options) != IS_ARRAY) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected options to be array, %s given", zend_zval_type_name(options));
		return false;
	}

	option = php_array_fetchc_deref(options, "session");

	if (!option) {
		return true;
	}

	if (Z_TYPE_P(option) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(option), php_phongo_session_ce)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"session\" option to be %s, %s given", ZSTR_VAL(php_phongo_session_ce->name), zend_zval_type_name(option));
		return false;
	}

	client_session = Z_SESSION_OBJ_P(option)->client_session;

	if (client != mongoc_client_session_get_client(client_session)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot use Session started from a different Manager");
		return false;
	}

	if (mongoc_opts && !mongoc_client_session_append(client_session, mongoc_opts, NULL)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"session\" option");
		return false;
	}

	if (zsession) {
		*zsession = option;
	}

	return true;
}

/* Parses the "writeConcern" option for an execute method. If mongoc_opts is not
 * NULL, the option will be appended. If zwriteConcern is not NULL, it will be
 * assigned to the option. On error, false is returned and an exception is
 * thrown. */
static bool phongo_parse_write_concern(zval* options, bson_t* mongoc_opts, zval** zwriteConcern)
{
	zval*                   option = NULL;
	mongoc_write_concern_t* write_concern;

	if (!options) {
		return true;
	}

	if (Z_TYPE_P(options) != IS_ARRAY) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected options to be array, %s given", zend_zval_type_name(options));
		return false;
	}

	option = php_array_fetchc_deref(options, "writeConcern");

	if (!option) {
		return true;
	}

	if (Z_TYPE_P(option) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(option), php_phongo_writeconcern_ce)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"writeConcern\" option to be %s, %s given", ZSTR_VAL(php_phongo_writeconcern_ce->name), zend_zval_type_name(option));
		return false;
	}

	write_concern = Z_WRITECONCERN_OBJ_P(option)->write_concern;

	if (mongoc_opts && !mongoc_write_concern_append(write_concern, mongoc_opts)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"writeConcern\" option");
		return false;
	}

	if (zwriteConcern) {
		*zwriteConcern = option;
	}

	return true;
}

bool phongo_execute_bulk_write(zval* manager, const char* namespace, php_phongo_bulkwrite_t* bulk_write, zval* options, uint32_t server_id, zval* return_value)
{
	mongoc_client_t*              client = NULL;
	bson_error_t                  error  = { 0 };
	int                           success;
	bson_t                        reply = BSON_INITIALIZER;
	mongoc_bulk_operation_t*      bulk  = bulk_write->bulk;
	php_phongo_writeresult_t*     writeresult;
	zval*                         zwriteConcern = NULL;
	zval*                         zsession      = NULL;
	const mongoc_write_concern_t* write_concern = NULL;

	client = Z_MANAGER_OBJ_P(manager)->client;

	if (bulk_write->executed) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "BulkWrite objects may only be executed once and this instance has already been executed");
		return false;
	}

	if (!phongo_split_namespace(namespace, &bulk_write->database, &bulk_write->collection)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s: %s", "Invalid namespace provided", namespace);
		return false;
	}

	if (!phongo_parse_session(options, client, NULL, &zsession)) {
		/* Exception should already have been thrown */
		return false;
	}

	if (!phongo_parse_write_concern(options, NULL, &zwriteConcern)) {
		/* Exception should already have been thrown */
		return false;
	}

	/* If a write concern was not specified, libmongoc will use the client's
	 * write concern; however, we should still fetch it for the write result.
	 * Additionally, we need to check if an unacknowledged write concern would
	 * conflict with an explicit session. */
	write_concern = zwriteConcern ? Z_WRITECONCERN_OBJ_P(zwriteConcern)->write_concern : mongoc_client_get_write_concern(client);

	if (zsession && !mongoc_write_concern_is_acknowledged(write_concern)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot combine \"session\" option with an unacknowledged write concern");
		return false;
	}

	mongoc_bulk_operation_set_database(bulk, bulk_write->database);
	mongoc_bulk_operation_set_collection(bulk, bulk_write->collection);
	mongoc_bulk_operation_set_client(bulk, client);
	mongoc_bulk_operation_set_server_id(bulk, server_id);

	if (zsession) {
		ZVAL_ZVAL(&bulk_write->session, zsession, 1, 0);
		mongoc_bulk_operation_set_client_session(bulk, Z_SESSION_OBJ_P(zsession)->client_session);
	}

	if (zwriteConcern) {
		mongoc_bulk_operation_set_write_concern(bulk, Z_WRITECONCERN_OBJ_P(zwriteConcern)->write_concern);
	}

	success              = mongoc_bulk_operation_execute(bulk, &reply, &error);
	bulk_write->executed = true;

	writeresult                = phongo_writeresult_init(return_value, &reply, manager, mongoc_bulk_operation_get_server_id(bulk));
	writeresult->write_concern = mongoc_write_concern_copy(write_concern);

	/* A BulkWriteException is always thrown if mongoc_bulk_operation_execute()
	 * fails to ensure that the write result is accessible. If the error does
	 * not originate from the server (e.g. socket error), throw the appropriate
	 * exception first. It will be included in BulkWriteException's message and
	 * will also be accessible via Exception::getPrevious(). */
	if (!success) {
		if (error.domain != MONGOC_ERROR_SERVER && error.domain != MONGOC_ERROR_WRITE_CONCERN) {
			phongo_throw_exception_from_bson_error_t_and_reply(&error, &reply);
		}

		/* Argument errors occur before command execution, so there is no need
		 * to layer this InvalidArgumentException behind a BulkWriteException.
		 * In practice, this will be a "Cannot do an empty bulk write" error. */
		if (error.domain == MONGOC_ERROR_COMMAND && error.code == MONGOC_ERROR_COMMAND_INVALID_ARG) {
			goto cleanup;
		}

		if (EG(exception)) {
			char* message;

			(void) spprintf(&message, 0, "Bulk write failed due to previous %s: %s", PHONGO_ZVAL_EXCEPTION_NAME(EG(exception)), error.message);
			zend_throw_exception(php_phongo_bulkwriteexception_ce, message, 0);
			efree(message);
		} else {
			zend_throw_exception(php_phongo_bulkwriteexception_ce, error.message, error.code);
		}

		/* Ensure error labels are added to the final BulkWriteException. If a
		 * previous exception was also thrown, error labels will already have
		 * been added by phongo_throw_exception_from_bson_error_t_and_reply. */
		phongo_exception_add_error_labels(&reply);
		phongo_add_exception_prop(ZEND_STRL("writeResult"), return_value);
	}

cleanup:
	bson_destroy(&reply);

	return success;
}

bool phongo_execute_command(zval* manager, php_phongo_command_type_t type, const char* db, zval* zcommand, zval* options, uint32_t server_id, zval* return_value)
{
	mongoc_client_t*            client;
	const php_phongo_command_t* command;
	bson_iter_t                 iter;
	bson_t                      reply;
	bson_error_t                error = { 0 };
	bson_t                      opts  = BSON_INITIALIZER;
	mongoc_cursor_t*            cmd_cursor;
	zval*                       zreadPreference                 = NULL;
	zval*                       zsession                        = NULL;
	bool                        result                          = false;
	bool                        free_reply                      = false;
	bool                        free_zsession                   = false;
	bool                        is_unacknowledged_write_concern = false;

	client  = Z_MANAGER_OBJ_P(manager)->client;
	command = Z_COMMAND_OBJ_P(zcommand);

	if ((type & PHONGO_OPTION_READ_CONCERN) && !phongo_parse_read_concern(options, &opts)) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	if ((type & PHONGO_OPTION_READ_PREFERENCE) && !phongo_parse_read_preference(options, &zreadPreference)) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	if (!phongo_parse_session(options, client, &opts, &zsession)) {
		/* Exception should already have been thrown */
		goto cleanup;
	}

	if (type & PHONGO_OPTION_WRITE_CONCERN) {
		zval* zwriteConcern = NULL;

		if (!phongo_parse_write_concern(options, &opts, &zwriteConcern)) {
			/* Exception should already have been thrown */
			goto cleanup;
		}

		/* Determine if the explicit or inherited write concern is
		 * unacknowledged so that we can ensure it does not conflict with an
		 * explicit or implicit session. */
		if (zwriteConcern) {
			is_unacknowledged_write_concern = !mongoc_write_concern_is_acknowledged(Z_WRITECONCERN_OBJ_P(zwriteConcern)->write_concern);
		} else if (type != PHONGO_COMMAND_RAW) {
			is_unacknowledged_write_concern = !mongoc_write_concern_is_acknowledged(mongoc_client_get_write_concern(client));
		}
	}

	if (zsession && is_unacknowledged_write_concern) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Cannot combine \"session\" option with an unacknowledged write concern");
		goto cleanup;
	}

	/* If an explicit session was not provided and the effective write concern
	 * is not unacknowledged, attempt to create an implicit client session
	 * (ignoring any errors). */
	if (!zsession && !is_unacknowledged_write_concern) {
		zsession = phongo_create_implicit_session(manager);

		if (zsession) {
			free_zsession = true;

			if (!mongoc_client_session_append(Z_SESSION_OBJ_P(zsession)->client_session, &opts, NULL)) {
				phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending implicit \"sessionId\" option");
				goto cleanup;
			}
		}
	}

	if (!BSON_APPEND_INT32(&opts, "serverId", server_id)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"serverId\" option");
		goto cleanup;
	}

	/* Although "opts" already always includes the serverId option, the read
	 * preference is added to the command parts, which is relevant for mongos
	 * command construction. */
	switch (type) {
		case PHONGO_COMMAND_RAW:
			result = mongoc_client_command_with_opts(client, db, command->bson, phongo_read_preference_from_zval(zreadPreference), &opts, &reply, &error);
			break;
		case PHONGO_COMMAND_READ:
			result = mongoc_client_read_command_with_opts(client, db, command->bson, phongo_read_preference_from_zval(zreadPreference), &opts, &reply, &error);
			break;
		case PHONGO_COMMAND_WRITE:
			result = mongoc_client_write_command_with_opts(client, db, command->bson, &opts, &reply, &error);
			break;
		case PHONGO_COMMAND_READ_WRITE:
			/* We can pass NULL as readPreference, as this argument was added historically, but has no function */
			result = mongoc_client_read_write_command_with_opts(client, db, command->bson, NULL, &opts, &reply, &error);
			break;
		default:
			/* Should never happen, but if it does: exception */
			phongo_throw_exception(PHONGO_ERROR_LOGIC, "Type '%d' should never have been passed to phongo_execute_command, please file a bug report", type);
			goto cleanup;
	}

	free_reply = true;

	if (!result) {
		phongo_throw_exception_from_bson_error_t_and_reply(&error, &reply);
		goto cleanup;
	}

	/* According to mongoc_cursor_new_from_command_reply_with_opts(), the reply
	 * bson_t is ultimately destroyed on both success and failure. */
	if (bson_iter_init_find(&iter, &reply, "cursor") && BSON_ITER_HOLDS_DOCUMENT(&iter)) {
		bson_t       initial_reply = BSON_INITIALIZER;
		bson_t       cursor_opts   = BSON_INITIALIZER;
		bson_iter_t  iter;
		bson_error_t error = { 0 };

		bson_copy_to(&reply, &initial_reply);

		bson_append_int32(&cursor_opts, "serverId", -1, server_id);

		if (command->max_await_time_ms) {
			bson_append_bool(&cursor_opts, "awaitData", -1, 1);
			bson_append_int64(&cursor_opts, "maxAwaitTimeMS", -1, command->max_await_time_ms);
			bson_append_bool(&cursor_opts, "tailable", -1, 1);
		}

		if (command->batch_size) {
			bson_append_int64(&cursor_opts, "batchSize", -1, command->batch_size);
		}

		if (bson_iter_init(&iter, command->bson) && bson_iter_find(&iter, "comment")) {
			bson_append_value(&cursor_opts, "comment", -1, bson_iter_value(&iter));
		}

		if (zsession && !mongoc_client_session_append(Z_SESSION_OBJ_P(zsession)->client_session, &cursor_opts, &error)) {
			phongo_throw_exception_from_bson_error_t(&error);
			bson_destroy(&initial_reply);
			bson_destroy(&cursor_opts);
			result = false;
			goto cleanup;
		}

		cmd_cursor = mongoc_cursor_new_from_command_reply_with_opts(client, &initial_reply, &cursor_opts);
		bson_destroy(&cursor_opts);
	} else {
		bson_t  cursor_opts   = BSON_INITIALIZER;
		bson_t* wrapped_reply = create_wrapped_command_envelope(db, &reply);

		bson_append_int32(&cursor_opts, "serverId", -1, server_id);
		cmd_cursor = mongoc_cursor_new_from_command_reply_with_opts(client, wrapped_reply, &cursor_opts);
		bson_destroy(&cursor_opts);
	}

	phongo_cursor_init_for_command(return_value, manager, cmd_cursor, db, zcommand, zreadPreference, zsession);

cleanup:
	bson_destroy(&opts);

	if (free_reply) {
		bson_destroy(&reply);
	}

	if (free_zsession) {
		zval_ptr_dtor(zsession);
		efree(zsession);
	}

	return result;
}

bool phongo_execute_query(zval* manager, const char* namespace, zval* zquery, zval* options, uint32_t server_id, zval* return_value)
{
	mongoc_client_t*          client;
	const php_phongo_query_t* query;
	bson_t                    opts = BSON_INITIALIZER;
	mongoc_cursor_t*          cursor;
	char*                     dbname;
	char*                     collname;
	mongoc_collection_t*      collection;
	zval*                     zreadPreference = NULL;
	zval*                     zsession        = NULL;

	client = Z_MANAGER_OBJ_P(manager)->client;

	if (!phongo_split_namespace(namespace, &dbname, &collname)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s: %s", "Invalid namespace provided", namespace);
		return false;
	}
	collection = mongoc_client_get_collection(client, dbname, collname);
	efree(dbname);
	efree(collname);

	query = Z_QUERY_OBJ_P(zquery);

	bson_copy_to(query->opts, &opts);

	if (query->read_concern) {
		mongoc_collection_set_read_concern(collection, query->read_concern);
	}

	if (!phongo_parse_read_preference(options, &zreadPreference)) {
		/* Exception should already have been thrown */
		mongoc_collection_destroy(collection);
		bson_destroy(&opts);
		return false;
	}

	if (!phongo_parse_session(options, client, &opts, &zsession)) {
		/* Exception should already have been thrown */
		mongoc_collection_destroy(collection);
		bson_destroy(&opts);
		return false;
	}

	if (!BSON_APPEND_INT32(&opts, "serverId", server_id)) {
		phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Error appending \"serverId\" option");
		mongoc_collection_destroy(collection);
		bson_destroy(&opts);
		return false;
	}

	cursor = mongoc_collection_find_with_opts(collection, query->filter, &opts, phongo_read_preference_from_zval(zreadPreference));
	mongoc_collection_destroy(collection);
	bson_destroy(&opts);

	/* maxAwaitTimeMS must be set before the cursor is sent */
	if (query->max_await_time_ms) {
		mongoc_cursor_set_max_await_time_ms(cursor, query->max_await_time_ms);
	}

	/* Initialize the cursor and advance it once */
	if (!phongo_cursor_init_for_query(return_value, manager, cursor, namespace, zquery, zreadPreference, zsession)) {
		/* Exception should already have been thrown */
		mongoc_cursor_destroy(cursor);
		return false;
	}

	return true;
}
mongodb-1.21.0/src/phongo_execute.h0000644000175100001660000000374214760300420014117 0ustar  /*
 * Copyright 2022-present MongoDB, 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.
 */

#ifndef PHONGO_EXECUTE_H
#define PHONGO_EXECUTE_H

#include "bson/bson.h"
#include "mongoc/mongoc.h"

#include 

/* This enum is used for processing options and selecting a libmongoc function
 * to use in phongo_execute_command. The values are important, as READ and WRITE
 * are also used as a bit field to determine whether readPreference,
 * readConcern, and writeConcern options are parsed. */
typedef enum {
	PHONGO_OPTION_READ_CONCERN    = 0x01,
	PHONGO_OPTION_READ_PREFERENCE = 0x02,
	PHONGO_OPTION_WRITE_CONCERN   = 0x04,
	PHONGO_COMMAND_RAW            = 0x07,
	PHONGO_COMMAND_READ           = 0x03,
	PHONGO_COMMAND_WRITE          = 0x04,
	PHONGO_COMMAND_READ_WRITE     = 0x05,
} php_phongo_command_type_t;

bool phongo_execute_bulk_write(zval* manager, const char* namespace, php_phongo_bulkwrite_t* bulk_write, zval* zwriteConcern, uint32_t server_id, zval* return_value);
bool phongo_execute_command(zval* manager, php_phongo_command_type_t type, const char* db, zval* zcommand, zval* zreadPreference, uint32_t server_id, zval* return_value);
bool phongo_execute_query(zval* manager, const char* namespace, zval* zquery, zval* zreadPreference, uint32_t server_id, zval* return_value);

bool phongo_parse_read_preference(zval* options, zval** zreadPreference);
bool phongo_parse_session(zval* options, mongoc_client_t* client, bson_t* mongoc_opts, zval** zsession);

#endif /* PHONGO_EXECUTE_H */
mongodb-1.21.0/src/phongo_ini.c0000644000175100001660000000543114760300420013224 0ustar  /*
 * Copyright 2021-present MongoDB, 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.
 */

#include 
#include 

#include 
#include 
#include "php_phongo.h" #include "phongo_ini.h" #include "phongo_log.h" ZEND_EXTERN_MODULE_GLOBALS(mongodb) static FILE* phongo_ini_tmp_file(const char* tmp_dir) { int fd = -1; char* prefix; int len; zend_string* filename = NULL; FILE* stream = NULL; len = spprintf(&prefix, 0, "PHONGO-%ld", time(NULL)); /* TODO: Refactor this to use fdopen (see: PHPC-2181) */ fd = php_open_temporary_fd(tmp_dir, prefix, &filename); if (fd != -1) { close(fd); } if (filename) { stream = VCWD_FOPEN(ZSTR_VAL(filename), "a"); efree(filename); } efree(prefix); return stream; } static PHP_INI_MH(OnUpdateDebug) { FILE* stream = NULL; if (!new_value || zend_string_equals_literal_ci(new_value, "") || zend_string_equals_literal_ci(new_value, "0") || zend_string_equals_literal_ci(new_value, "off") || zend_string_equals_literal_ci(new_value, "no") || zend_string_equals_literal_ci(new_value, "false")) { goto done; } if (zend_string_equals_literal_ci(new_value, "stderr")) { stream = stderr; } else if (zend_string_equals_literal_ci(new_value, "stdout")) { stream = stdout; } else if ( zend_string_equals_literal_ci(new_value, "1") || zend_string_equals_literal_ci(new_value, "on") || zend_string_equals_literal_ci(new_value, "yes") || zend_string_equals_literal_ci(new_value, "true")) { stream = phongo_ini_tmp_file(NULL); } else { stream = phongo_ini_tmp_file(ZSTR_VAL(new_value)); } /* TODO: Consider failing if we do not have a stream by this point */ done: phongo_log_set_stream(stream); /* OnUpdateString should always succeed, but defer to its retval anyway */ return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); } void phongo_display_ini_entries(ZEND_MODULE_INFO_FUNC_ARGS) { DISPLAY_INI_ENTRIES(); } void phongo_register_ini_entries(INIT_FUNC_ARGS) { PHP_INI_BEGIN() STD_PHP_INI_ENTRY("mongodb.debug", "", PHP_INI_ALL, OnUpdateDebug, debug, zend_mongodb_globals, mongodb_globals) PHP_INI_END() REGISTER_INI_ENTRIES(); } void phongo_unregister_ini_entries(SHUTDOWN_FUNC_ARGS) { UNREGISTER_INI_ENTRIES(); } mongodb-1.21.0/src/phongo_ini.h0000644000175100001660000000153314760300420013230 0ustar /* * Copyright 2021-present MongoDB, 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. */ #ifndef PHONGO_INI_H #define PHONGO_INI_H #include void phongo_display_ini_entries(ZEND_MODULE_INFO_FUNC_ARGS); void phongo_register_ini_entries(INIT_FUNC_ARGS); void phongo_unregister_ini_entries(SHUTDOWN_FUNC_ARGS); #endif /* PHONGO_INI_H */ mongodb-1.21.0/src/phongo_log.c0000644000175100001660000001377714760300420013242 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include #include #include #include #include "php_phongo.h" #include "phongo_error.h" #include "phongo_log.h" ZEND_EXTERN_MODULE_GLOBALS(mongodb) static void phongo_log_to_stream(FILE* stream, mongoc_log_level_t level, const char* domain, const char* message) { struct timeval tv; time_t t; zend_long tu; zend_string* dt; bson_gettimeofday(&tv); t = tv.tv_sec; tu = tv.tv_usec; dt = php_format_date((char*) ZEND_STRL("Y-m-d\\TH:i:s"), t, 0); fprintf(stream, "[%s.%06" PHONGO_LONG_FORMAT "+00:00] %10s: %-8s> %s\n", ZSTR_VAL(dt), tu, domain, mongoc_log_level_str(level), message); fflush(stream); efree(dt); } /* Dispatch a log message to all registered loggers. The caller is responsible * for ensuring that loggers implement the correct interface. */ static void phongo_log_dispatch(mongoc_log_level_t level, const char* domain, const char* message) { zval* logger; zval func_name; zval args[3]; /* Trace logging is very verbose and often includes multi-line output, which * takes the form of multiple log messages. Therefore, it is only reported * via streams (i.e. mongodb.debug INI) and not to registered loggers. */ if (level >= MONGOC_LOG_LEVEL_TRACE) { return; } ZVAL_STRING(&func_name, "log"); ZVAL_LONG(&args[0], level); ZVAL_STRING(&args[1], domain); ZVAL_STRING(&args[2], message); ZEND_HASH_FOREACH_VAL_IND(MONGODB_G(loggers), logger) { zval retval; if (EG(exception)) { break; } call_user_function(NULL, logger, &func_name, &retval, 3, args); zval_ptr_dtor(&retval); } ZEND_HASH_FOREACH_END(); zval_ptr_dtor(&func_name); zval_ptr_dtor(&args[0]); zval_ptr_dtor(&args[1]); zval_ptr_dtor(&args[2]); } static void phongo_log_handler(mongoc_log_level_t level, const char* domain, const char* message, void* user_data) { if (MONGODB_G(debug_fd)) { phongo_log_to_stream(MONGODB_G(debug_fd), level, domain, message); } // Trace logs are only reported via streams and not to registered loggers if (level >= MONGOC_LOG_LEVEL_TRACE) { return; } if (MONGODB_G(loggers) && zend_hash_num_elements(MONGODB_G(loggers)) > 0) { phongo_log_dispatch(level, domain, message); } } /* Sets or unsets our libmongoc handler according to whether logging is enabled * (i.e. there is a stream or the loggers HashTable is not empty). This should * be called each time after updating the stream or logger HashTable. */ static void phongo_log_sync_handler(void) { if (MONGODB_G(debug_fd) || (MONGODB_G(loggers) && zend_hash_num_elements(MONGODB_G(loggers)) > 0)) { // Trace logging is only needed if a stream is active if (MONGODB_G(debug_fd)) { mongoc_log_trace_enable(); } mongoc_log_set_handler(phongo_log_handler, NULL); } else { mongoc_log_trace_disable(); mongoc_log_set_handler(NULL, NULL); } } /* Checks args for adding/removing a logger. Returns true on success; otherwise, * throws an exception and returns false. */ static bool phongo_log_check_args_for_add_and_remove(HashTable* loggers, zval* logger) { if (!loggers) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Logger HashTable is not initialized"); return false; } if (!logger || Z_TYPE_P(logger) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(logger), php_phongo_logsubscriber_ce)) { phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Logger is not an instance of %s", ZSTR_VAL(php_phongo_logsubscriber_ce->name)); return false; } return true; } /* Adds a logger to the HashTable. Returns true on success (including NOP if * already registered); otherwise, throws an exception and returns false. */ bool phongo_log_add_logger(zval* logger) { HashTable* loggers = MONGODB_G(loggers); if (!phongo_log_check_args_for_add_and_remove(loggers, logger)) { /* Exception should already have been thrown */ return false; } /* NOP if the logger was already registered */ if (zend_hash_index_exists(loggers, Z_OBJ_HANDLE_P(logger))) { return true; } zend_hash_index_update(loggers, Z_OBJ_HANDLE_P(logger), logger); Z_ADDREF_P(logger); /* Sync log handler after modifying the loggers HashTable */ phongo_log_sync_handler(); return true; } /* Removes a logger from the global HashTable. Returns true on success * (including NOP if never registered); otherwise, throws an exception and * returns false. */ bool phongo_log_remove_logger(zval* logger) { HashTable* loggers = MONGODB_G(loggers); if (!phongo_log_check_args_for_add_and_remove(loggers, logger)) { /* Exception should already have been thrown */ return false; } /* Note: the HashTable should specify ZVAL_PTR_DTOR as its element * destructor so there is no need to decrement the logger's reference count * here. We also don't care about whether zend_hash_index_del returns * SUCCESS or FAILURE, as removing an unregistered logger is a NOP. */ zend_hash_index_del(loggers, Z_OBJ_HANDLE_P(logger)); /* Sync log handler after modifying the loggers HashTable */ phongo_log_sync_handler(); return true; } void phongo_log_set_stream(FILE* stream) { FILE* prev_stream = MONGODB_G(debug_fd); /* NOP if the stream is not being changed */ if (prev_stream == stream) { return; } /* Close the previous stream (excluding stderr/stdout) */ if (prev_stream && prev_stream != stderr && prev_stream != stdout) { fclose(prev_stream); } MONGODB_G(debug_fd) = stream; phongo_log_sync_handler(); } mongodb-1.21.0/src/phongo_log.h0000644000175100001660000000151114760300420013226 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_LOG_H #define PHONGO_LOG_H #include #include bool phongo_log_add_logger(zval* logger); bool phongo_log_remove_logger(zval* logger); void phongo_log_set_stream(FILE* stream); #endif /* PHONGO_LOG_H */ mongodb-1.21.0/src/phongo_structs.h0000644000175100001660000002256514760300420014170 0ustar /* * Copyright 2015-present MongoDB, 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. */ #ifndef PHONGO_STRUCTS_H #define PHONGO_STRUCTS_H #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include "phongo_bson.h" typedef struct { mongoc_bulk_operation_t* bulk; size_t num_ops; bool ordered; int bypass; bson_t* let; bson_value_t* comment; char* database; char* collection; bool executed; zval session; zend_object std; } php_phongo_bulkwrite_t; typedef struct { mongoc_client_encryption_t* client_encryption; zval key_vault_client_manager; char* key_vault_namespace; zend_object std; } php_phongo_clientencryption_t; typedef struct { bson_t* bson; uint32_t max_await_time_ms; uint32_t batch_size; zend_object std; } php_phongo_command_t; typedef struct { mongoc_cursor_t* cursor; zval manager; int created_by_pid; uint32_t server_id; bool advanced; php_phongo_bson_state visitor_data; long current; char* database; char* collection; zval query; zval command; zval read_preference; zval session; zend_object std; } php_phongo_cursor_t; typedef struct { bool initialized; int64_t id; HashTable* properties; zend_object std; } php_phongo_cursorid_t; typedef struct { mongoc_client_t* client; int created_by_pid; char* client_hash; size_t client_hash_len; bool use_persistent_client; zval enc_fields_map; zval key_vault_client_manager; HashTable* subscribers; zend_object std; } php_phongo_manager_t; typedef struct { bson_t* filter; bson_t* opts; mongoc_read_concern_t* read_concern; uint32_t max_await_time_ms; zend_object std; } php_phongo_query_t; typedef struct { mongoc_read_concern_t* read_concern; HashTable* properties; zend_object std; } php_phongo_readconcern_t; typedef struct { mongoc_read_prefs_t* read_preference; HashTable* properties; zend_object std; } php_phongo_readpreference_t; typedef struct { zval manager; int created_by_pid; uint32_t server_id; zend_object std; } php_phongo_server_t; typedef struct { mongoc_server_api_t* server_api; HashTable* properties; zend_object std; } php_phongo_serverapi_t; typedef struct { mongoc_server_description_t* server_description; HashTable* properties; zend_object std; } php_phongo_serverdescription_t; typedef struct { mongoc_client_session_t* client_session; zval manager; int created_by_pid; zend_object std; } php_phongo_session_t; typedef struct { mongoc_topology_description_t* topology_description; HashTable* properties; zend_object std; } php_phongo_topologydescription_t; typedef struct { HashTable* properties; mongoc_write_concern_t* write_concern; zend_object std; } php_phongo_writeconcern_t; typedef struct { int code; char* message; zval info; zend_object std; } php_phongo_writeconcernerror_t; typedef struct { int code; char* message; zval info; uint32_t index; zend_object std; } php_phongo_writeerror_t; typedef struct { mongoc_write_concern_t* write_concern; bson_t* reply; zval manager; uint32_t server_id; zend_object std; } php_phongo_writeresult_t; typedef struct { char* data; int data_len; uint8_t type; HashTable* properties; zend_object std; } php_phongo_binary_t; typedef struct { bson_t* bson; HashTable* properties; zend_object std; } php_phongo_packedarray_t; typedef struct { bson_t* bson; HashTable* properties; zend_object std; } php_phongo_document_t; typedef struct { zval bson; bson_iter_t iter; bool valid; bool is_array; size_t key; zval current; HashTable* properties; zend_object std; } php_phongo_iterator_t; typedef struct { char* ref; size_t ref_len; char id[25]; HashTable* properties; zend_object std; } php_phongo_dbpointer_t; typedef struct { bool initialized; bson_decimal128_t decimal; HashTable* properties; zend_object std; } php_phongo_decimal128_t; typedef struct { bool initialized; int64_t integer; HashTable* properties; zend_object std; } php_phongo_int64_t; typedef struct { char* code; size_t code_len; bson_t* scope; HashTable* properties; zend_object std; } php_phongo_javascript_t; typedef struct { zend_object std; } php_phongo_maxkey_t; typedef struct { zend_object std; } php_phongo_minkey_t; typedef struct { bool initialized; char oid[25]; HashTable* properties; zend_object std; } php_phongo_objectid_t; typedef struct { char* pattern; int pattern_len; char* flags; int flags_len; HashTable* properties; zend_object std; } php_phongo_regex_t; typedef struct { char* symbol; size_t symbol_len; HashTable* properties; zend_object std; } php_phongo_symbol_t; typedef struct { bool initialized; uint32_t increment; uint32_t timestamp; HashTable* properties; zend_object std; } php_phongo_timestamp_t; typedef struct { zend_object std; } php_phongo_undefined_t; typedef struct { bool initialized; int64_t milliseconds; HashTable* properties; zend_object std; } php_phongo_utcdatetime_t; typedef struct { zval manager; char* command_name; char* database_name; uint32_t server_id; int64_t operation_id; int64_t request_id; int64_t duration_micros; bson_t* reply; zval z_error; bool has_service_id; bson_oid_t service_id; int64_t server_connection_id; mongoc_host_list_t host; zend_object std; } php_phongo_commandfailedevent_t; typedef struct { zval manager; char* command_name; char* database_name; uint32_t server_id; int64_t operation_id; int64_t request_id; bson_t* command; bool has_service_id; bson_oid_t service_id; int64_t server_connection_id; mongoc_host_list_t host; zend_object std; } php_phongo_commandstartedevent_t; typedef struct { zval manager; char* command_name; char* database_name; uint32_t server_id; int64_t operation_id; int64_t request_id; int64_t duration_micros; bson_t* reply; bool has_service_id; bson_oid_t service_id; int64_t server_connection_id; mongoc_host_list_t host; zend_object std; } php_phongo_commandsucceededevent_t; typedef struct { bson_oid_t topology_id; mongoc_host_list_t host; mongoc_server_description_t* new_server_description; mongoc_server_description_t* old_server_description; zend_object std; } php_phongo_serverchangedevent_t; typedef struct { bson_oid_t topology_id; mongoc_host_list_t host; zend_object std; } php_phongo_serverclosedevent_t; typedef struct { bool awaited; int64_t duration_micros; zval z_error; mongoc_host_list_t host; zend_object std; } php_phongo_serverheartbeatfailedevent_t; typedef struct { bool awaited; mongoc_host_list_t host; zend_object std; } php_phongo_serverheartbeatstartedevent_t; typedef struct { bool awaited; int64_t duration_micros; mongoc_host_list_t host; bson_t* reply; zend_object std; } php_phongo_serverheartbeatsucceededevent_t; typedef struct { bson_oid_t topology_id; mongoc_host_list_t host; zend_object std; } php_phongo_serveropeningevent_t; typedef struct { bson_oid_t topology_id; mongoc_topology_description_t* new_topology_description; mongoc_topology_description_t* old_topology_description; zend_object std; } php_phongo_topologychangedevent_t; typedef struct { bson_oid_t topology_id; zend_object std; } php_phongo_topologyclosedevent_t; typedef struct { bson_oid_t topology_id; zend_object std; } php_phongo_topologyopeningevent_t; #endif /* PHONGO_STRUCTS */ mongodb-1.21.0/src/phongo_util.c0000644000175100001660000000720414760300420013422 0ustar /* * Copyright 2022-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #include #include "phongo_util.h" const char* php_phongo_bson_type_to_string(bson_type_t type) { switch (type) { case BSON_TYPE_EOD: return "EOD"; case BSON_TYPE_DOUBLE: return "double"; case BSON_TYPE_UTF8: return "string"; case BSON_TYPE_DOCUMENT: return "document"; case BSON_TYPE_ARRAY: return "array"; case BSON_TYPE_BINARY: return "Binary"; case BSON_TYPE_UNDEFINED: return "undefined"; case BSON_TYPE_OID: return "ObjectId"; case BSON_TYPE_BOOL: return "boolean"; case BSON_TYPE_DATE_TIME: return "UTCDateTime"; case BSON_TYPE_NULL: return "null"; case BSON_TYPE_REGEX: return "Regex"; case BSON_TYPE_DBPOINTER: return "DBPointer"; case BSON_TYPE_CODE: return "Javascript"; case BSON_TYPE_SYMBOL: return "symbol"; case BSON_TYPE_CODEWSCOPE: return "Javascript with scope"; case BSON_TYPE_INT32: return "32-bit integer"; case BSON_TYPE_TIMESTAMP: return "Timestamp"; case BSON_TYPE_INT64: return "64-bit integer"; case BSON_TYPE_DECIMAL128: return "Decimal128"; case BSON_TYPE_MAXKEY: return "MaxKey"; case BSON_TYPE_MINKEY: return "MinKey"; default: return "unknown"; } } /* If options is not an array, insert it as a field in a newly allocated array. * This may be used to convert legacy options (e.g. ReadPreference option for * an executeQuery method) into an options array. * * A pointer to the array zval will always be returned. If allocated is set to * true, php_phongo_prep_legacy_option_free() should be used to free the array * zval later. */ zval* php_phongo_prep_legacy_option(zval* options, const char* key, bool* allocated) { *allocated = false; if (options && Z_TYPE_P(options) != IS_ARRAY) { zval* new_options = ecalloc(1, sizeof(zval)); array_init_size(new_options, 1); add_assoc_zval(new_options, key, options); Z_ADDREF_P(options); *allocated = true; php_error_docref(NULL, E_DEPRECATED, "Passing the \"%s\" option directly is deprecated and will be removed in ext-mongodb 2.0", key); return new_options; } return options; } void php_phongo_prep_legacy_option_free(zval* options) { zval_ptr_dtor(options); efree(options); } bool php_phongo_parse_int64(int64_t* retval, const char* data, size_t data_len) { int64_t value; char* endptr = NULL; /* bson_ascii_strtoll() sets errno if conversion fails. If conversion * succeeds, we still want to ensure that the entire string was parsed. */ value = bson_ascii_strtoll(data, &endptr, 10); if (errno || (endptr && endptr != ((const char*) data + data_len))) { return false; } *retval = value; return true; } /* Splits a namespace name into the database and collection names, allocated with estrdup. */ bool phongo_split_namespace(const char* namespace, char** dbname, char** cname) { char* dot = strchr(namespace, '.'); if (!dot) { return false; } if (cname) { *cname = estrdup(namespace + (dot - namespace) + 1); } if (dbname) { *dbname = estrndup(namespace, dot - namespace); } return true; } mongodb-1.21.0/src/phongo_util.h0000644000175100001660000000205714760300420013430 0ustar /* * Copyright 2022-present MongoDB, 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. */ #ifndef PHONGO_UTIL_H #define PHONGO_UTIL_H #include "bson/bson.h" const char* php_phongo_bson_type_to_string(bson_type_t type); zval* php_phongo_prep_legacy_option(zval* options, const char* key, bool* allocated); void php_phongo_prep_legacy_option_free(zval* options); bool php_phongo_parse_int64(int64_t* retval, const char* data, size_t data_len); bool phongo_split_namespace(const char* namespace, char** dbname, char** cname); #endif /* PHONGO_UTIL_H */ mongodb-1.21.0/tests/apm/bug0950-001.phpt0000644000175100001660000000170614760300420014346 0ustar --TEST-- PHPC-950: Segfault killing cursor after subscriber HashTable is destroyed (no subscribers) --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); /* Exiting during iteration on a live cursor will result in * php_phongo_command_started() being invoked for the killCursor command after * RSHUTDOWN has already destroyed the subscriber HashTable */ foreach ($cursor as $data) { echo "Exiting during first iteration on cursor\n"; exit(0); } ?> ===DONE=== --EXPECT-- Exiting during first iteration on cursor mongodb-1.21.0/tests/apm/bug0950-002.phpt0000644000175100001660000000346314760300420014351 0ustar --TEST-- PHPC-950: Segfault killing cursor after subscriber HashTable is destroyed (one subscriber) --SKIPIF-- =', '7.99'); ?> --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("- succeeded: %s\n", $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("- failed: %s\n", $event->getCommandName()); } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new MySubscriber); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); /* Exiting during iteration on a live cursor will result in * php_phongo_command_started() being invoked for the killCursors command after * RSHUTDOWN has already destroyed the subscriber HashTable */ foreach ($cursor as $data) { echo "Exiting during first iteration on cursor\n"; exit(0); } ?> ===DONE=== --EXPECT-- - started: find - succeeded: find Exiting during first iteration on cursor mongodb-1.21.0/tests/apm/commandFailedEvent-001.phpt0000644000175100001660000000403014760300420016771 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent --SKIPIF-- --FILE-- getCommandName()); var_dump($event->getDatabaseName()); var_dump($event->getDurationMicros()); echo "getDurationMicros() returns > 0: ", $event->getDurationMicros() > 0 ? 'yes' : 'no', "\n"; var_dump($event->getError() instanceof MongoDB\Driver\Exception\Exception); var_dump($event->getHost()); var_dump($event->getOperationId()); var_dump($event->getPort()); var_dump($event->getReply()); var_dump($event->getRequestId()); /* Note: getServerConnectionId() and getServiceId() have more stringent * requirements and are tested separately. */ } } $manager = create_test_manager(); $subscriber = new MySubscriber(); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['unsupportedCommand' => 1]); try { $manager->executeCommand('admin', $command); } catch (Exception $e) { } ?> --EXPECTF-- string(18) "unsupportedCommand" string(5) "admin" int(%d) getDurationMicros() returns > 0: yes bool(true) string(%d) "%s" string(%d) "%d" int(%d) object(stdClass)#%d (%d) { %A } string(%d) "%d" mongodb-1.21.0/tests/apm/commandFailedEvent-002.phpt0000644000175100001660000000330614760300420016777 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent: requestId and operationId match --SKIPIF-- --FILE-- getCommandName(), "\n"; $this->startRequestId = $event->getRequestId(); $this->startOperationId = $event->getOperationId(); } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { echo "failed: ", $event->getCommandName(), "\n"; echo "- requestId matches: ", $this->startRequestId == $event->getRequestId() ? 'yes' : 'no', " \n"; echo "- operationId matches: ", $this->startOperationId == $event->getOperationId() ? 'yes' : 'no', " \n"; } } $query = new MongoDB\Driver\Query( [] ); $subscriber = new MySubscriber; MongoDB\Driver\Monitoring\addSubscriber( $subscriber ); $primary = get_primary_server(URI); $command = new \MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$unsupported' => 1]] ]); try { $primary->executeCommand(DATABASE_NAME, $command); } catch (Exception $e) { /* Swallow */ } ?> --EXPECT-- started: aggregate failed: aggregate - requestId matches: yes - operationId matches: yes mongodb-1.21.0/tests/apm/commandFailedEvent-debug-001.phpt0000644000175100001660000000347514760300420020071 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent debug output --SKIPIF-- --FILE-- addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$unsupported' => 1]], ]); /* Note: Although executeCommand() throws a CommandException, CommandFailedEvent * will report a ServerException for its "error" property (PHPC-1990) */ throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, MongoDB\Driver\Exception\CommandException::class); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Monitoring\CommandFailedEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["commandName"]=> string(9) "aggregate" ["durationMicros"]=> int(%d) ["error"]=> object(MongoDB\Driver\Exception\ServerException)#%d (%d) {%A } ["reply"]=> object(stdClass)#%d (%d) {%A } ["operationId"]=> string(%d) "%d" ["requestId"]=> string(%d) "%d" ["server"]=> object(MongoDB\Driver\Server)#%d (%d) {%A } ["serviceId"]=> %r(NULL|object\(MongoDB\\BSON\\ObjectId\).*)%r ["serverConnectionId"]=> %r(NULL|int\(\d+\))%r } OK: Got MongoDB\Driver\Exception\CommandException ===DONE=== mongodb-1.21.0/tests/apm/commandFailedEvent-getReply-001.phpt0000644000175100001660000000270714760300420020573 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent::getReply() --SKIPIF-- --FILE-- getCommandName(), "\n"; } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { var_dump($event); } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { echo "failed: ", $event->getCommandName(), "\n"; var_dump($event->getReply()); } } $subscriber = new MySubscriber; MongoDB\Driver\Monitoring\addSubscriber( $subscriber ); $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['_id' => 'foo'], 'upsert' => true, 'new' => true, ]); try { $manager->executeWriteCommand(DATABASE_NAME, $command); } catch (MongoDB\Driver\Exception\CommandException $e) {} ?> --EXPECTF-- started: findAndModify failed: findAndModify object(stdClass)#%d (%d) {%A ["ok"]=> float(0) ["errmsg"]=> string(49) "Either an update or remove=true must be specified" ["code"]=> int(9) ["codeName"]=> string(13) "FailedToParse"%A } mongodb-1.21.0/tests/apm/commandFailedEvent-getServer-001.phpt0000644000175100001660000000217514760300420020745 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent::getServer() --SKIPIF-- --FILE-- getServer()); } } $manager = create_test_manager(); $subscriber = new MySubscriber(); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['unsupportedCommand' => 1]); try { $manager->executeCommand('admin', $command); } catch (Exception $e) { } ?> --EXPECTF-- Deprecated: %r(Function|Method)%r MongoDB\Driver\Monitoring\CommandFailedEvent::getServer() is deprecated in %s object(MongoDB\Driver\Server)#%d (%d) { %A } mongodb-1.21.0/tests/apm/commandFailedEvent-getServerConnectionId-001.phpt0000644000175100001660000000337214760300420023242 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent includes serverConnectionId for 4.2+ server --SKIPIF-- --FILE-- getCommandName()); $this->commandStartedServerConnectionId = $event->getServerConnectionId(); var_dump($this->commandStartedServerConnectionId); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { printf("commandFailed: %s\n", $event->getCommandName()); printf("same serverConnectionId as last commandStarted: %s\n", $event->getServerConnectionId() == $this->commandStartedServerConnectionId ? 'yes' : 'no'); var_dump($event->getServerConnectionId()); } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$unsupported' => 1]], ]); throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, MongoDB\Driver\Exception\CommandException::class); ?> --EXPECTF-- commandStarted: aggregate int(%d) commandFailed: aggregate same serverConnectionId as last commandStarted: yes int(%d) OK: Got MongoDB\Driver\Exception\CommandException mongodb-1.21.0/tests/apm/commandFailedEvent-getServerConnectionId-002.phpt0000644000175100001660000000262214760300420023240 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent omits serverConnectionId for pre-4.2 server --SKIPIF-- =', '4.2'); ?> --FILE-- getCommandName()); var_dump($event->getServerConnectionId()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { printf("commandFailed: %s\n", $event->getCommandName()); var_dump($event->getServerConnectionId()); } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$unsupported' => 1]], ]); throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, MongoDB\Driver\Exception\CommandException::class); ?> --EXPECTF-- commandStarted: aggregate NULL commandFailed: aggregate NULL OK: Got MongoDB\Driver\Exception\CommandException mongodb-1.21.0/tests/apm/commandFailedEvent-getServiceId-001.phpt0000644000175100001660000000340714760300420021353 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent includes serviceId for load balanced topology --SKIPIF-- --FILE-- getCommandName()); $this->commandStartedServiceId = $event->getServiceId(); var_dump($this->commandStartedServiceId); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { printf("commandFailed: %s\n", $event->getCommandName()); printf("same serviceId as last commandStarted: %s\n", $event->getServiceId() == $this->commandStartedServiceId ? 'yes' : 'no'); var_dump($event->getServiceId()); } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$unsupported' => 1]], ]); throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, MongoDB\Driver\Exception\CommandException::class); ?> --EXPECTF-- commandStarted: aggregate object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } commandFailed: aggregate same serviceId as last commandStarted: yes object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } OK: Got MongoDB\Driver\Exception\CommandException mongodb-1.21.0/tests/apm/commandFailedEvent-getServiceId-002.phpt0000644000175100001660000000253214760300420021352 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandFailedEvent omits serviceId for non-load balanced topology --SKIPIF-- --FILE-- getCommandName()); var_dump($event->getServiceId()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { printf("commandFailed: %s\n", $event->getCommandName()); var_dump($event->getServiceId()); } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$unsupported' => 1]], ]); throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, MongoDB\Driver\Exception\CommandException::class); ?> --EXPECTF-- commandStarted: aggregate NULL commandFailed: aggregate NULL OK: Got MongoDB\Driver\Exception\CommandException mongodb-1.21.0/tests/apm/commandStartedEvent-001.phpt0000644000175100001660000000263414760300420017223 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandStartedEvent --SKIPIF-- --FILE-- getCommand()); var_dump($event->getCommandName()); var_dump($event->getDatabaseName()); var_dump($event->getHost()); var_dump($event->getOperationId()); var_dump($event->getPort()); var_dump($event->getRequestId()); /* Note: getServerConnectionId() and getServiceId() have more stringent * requirements and are tested separately. */ } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $subscriber = new MySubscriber(); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand('admin', $command); ?> --EXPECTF-- object(stdClass)#%d (%d) { %A } string(4) "ping" string(5) "admin" string(%d) "%s" string(%d) "%d" int(%d) string(%d) "%d" mongodb-1.21.0/tests/apm/commandStartedEvent-002.phpt0000644000175100001660000000247414760300420017226 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandStartedEvent during mongoc_client_destroy() --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void {} public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void {} } $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); $singleSubscriber = new MySubscriber(); $manager->addSubscriber($singleSubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command); /* Events dispatched during mongoc_client_destroy can only be observed before * RSHUTDOWN. This means that we must use a non-persistent client and free it * before the script ends. */ unset($manager); ?> ===DONE=== --EXPECT-- Observed commandStarted for ping Observed commandStarted for endSessions ===DONE=== mongodb-1.21.0/tests/apm/commandStartedEvent-debug-001.phpt0000644000175100001660000000254314760300420020306 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandStartedEvent debug output --SKIPIF-- --FILE-- addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Monitoring\CommandStartedEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["commandName"]=> string(4) "ping" ["databaseName"]=> string(%d) "%s" ["command"]=> object(stdClass)#%d (%d) {%A } ["operationId"]=> string(%d) "%d" ["requestId"]=> string(%d) "%d" ["server"]=> object(MongoDB\Driver\Server)#%d (%d) {%A } ["serviceId"]=> %r(NULL|object\(MongoDB\\BSON\\ObjectId\).*)%r ["serverConnectionId"]=> %r(NULL|int\(\d+\))%r } ===DONE=== mongodb-1.21.0/tests/apm/commandStartedEvent-getServer-001.phpt0000644000175100001660000000211314760300420021157 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandStartedEvent::getServer() --SKIPIF-- --FILE-- getServer()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $subscriber = new MySubscriber(); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand('admin', $command); ?> --EXPECTF-- Deprecated: %r(Function|Method)%r MongoDB\Driver\Monitoring\CommandStartedEvent::getServer() is deprecated in %s object(MongoDB\Driver\Server)#%d (%d) { %A } mongodb-1.21.0/tests/apm/commandStartedEvent-getServerConnectionId-001.phpt0000644000175100001660000000322514760300420023461 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandStartedEvent includes serverConnectionId for 4.2+ server --SKIPIF-- --FILE-- getCommandName()); if (isset($this->commandStartedServerConnectionId)) { printf("same serverConnectionId as last commandStarted: %s\n", $event->getServerConnectionId() == $this->commandStartedServerConnectionId ? 'yes' : 'no'); } $this->commandStartedServerConnectionId = $event->getServerConnectionId(); var_dump($this->commandStartedServerConnectionId); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); // Select a single server in case the topology includes multiple mongoses $server = $manager->selectServer(); $server->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $server->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> --EXPECTF-- commandStarted: ping int(%d) commandStarted: ping same serverConnectionId as last commandStarted: yes int(%d) mongodb-1.21.0/tests/apm/commandStartedEvent-getServerConnectionId-002.phpt0000644000175100001660000000200514760300420023455 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandStartedEvent omits serverConnectionId for pre-4.2 server --SKIPIF-- =', '4.2'); ?> --FILE-- getCommandName()); var_dump($event->getServerConnectionId()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> --EXPECTF-- commandStarted: ping NULL mongodb-1.21.0/tests/apm/commandStartedEvent-getServiceId-001.phpt0000644000175100001660000000306514760300420021575 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandStartedEvent includes serviceId for load balanced topology --SKIPIF-- --FILE-- getCommandName()); if (isset($this->commandStartedServiceId)) { printf("same serviceId as last commandStarted: %s\n", $event->getServiceId() == $this->commandStartedServiceId ? 'yes' : 'no'); } $this->commandStartedServiceId = $event->getServiceId(); var_dump($this->commandStartedServiceId); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> --EXPECTF-- commandStarted: ping object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } commandStarted: ping same serviceId as last commandStarted: yes object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } mongodb-1.21.0/tests/apm/commandStartedEvent-getServiceId-002.phpt0000644000175100001660000000172614760300420021600 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandStartedEvent omits serviceId for non-load balanced topology --SKIPIF-- --FILE-- getCommandName()); var_dump($event->getServiceId()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> --EXPECTF-- commandStarted: ping NULL mongodb-1.21.0/tests/apm/commandSucceededEvent-001.phpt0000644000175100001660000000363114760300420017477 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandSucceededEvent --SKIPIF-- --FILE-- getCommandName()); var_dump($event->getDatabaseName()); var_dump($event->getDurationMicros()); echo "getDurationMicros() returns > 0: ", $event->getDurationMicros() > 0 ? 'yes' : 'no', "\n"; var_dump($event->getHost()); var_dump($event->getOperationId()); var_dump($event->getPort()); var_dump($event->getReply()); var_dump($event->getRequestId()); /* Note: getServerConnectionId() and getServiceId() have more stringent * requirements and are tested separately. */ } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $subscriber = new MySubscriber(); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand('admin', $command); ?> --EXPECTF-- string(4) "ping" string(5) "admin" int(%d) getDurationMicros() returns > 0: yes string(%d) "%s" string(%d) "%d" int(%d) object(stdClass)#%d (%d) { %A } string(%d) "%d" mongodb-1.21.0/tests/apm/commandSucceededEvent-002.phpt0000644000175100001660000000275714760300420017510 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandSucceededEvent: requestId and operationId match --SKIPIF-- --FILE-- getCommandName(), "\n"; $this->startRequestId = $event->getRequestId(); $this->startOperationId = $event->getOperationId(); } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { echo "succeeded: ", $event->getCommandName(), "\n"; echo "- requestId matches: ", $this->startRequestId == $event->getRequestId() ? 'yes' : 'no', " \n"; echo "- operationId matches: ", $this->startOperationId == $event->getOperationId() ? 'yes' : 'no', " \n"; } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $query = new MongoDB\Driver\Query( [] ); $subscriber = new MySubscriber; MongoDB\Driver\Monitoring\addSubscriber( $subscriber ); $cursor = $m->executeQuery( "demo.test", $query ); ?> --EXPECT-- started: find succeeded: find - requestId matches: yes - operationId matches: yes mongodb-1.21.0/tests/apm/commandSucceededEvent-debug-001.phpt0000644000175100001660000000253714760300420020567 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandSucceededEvent debug output --SKIPIF-- --FILE-- addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Monitoring\CommandSucceededEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["commandName"]=> string(4) "ping" ["durationMicros"]=> int(%d) ["reply"]=> object(stdClass)#%d (%d) {%A } ["operationId"]=> string(%d) "%d" ["requestId"]=> string(%d) "%d" ["server"]=> object(MongoDB\Driver\Server)#%d (%d) {%A } ["serviceId"]=> %r(NULL|object\(MongoDB\\BSON\\ObjectId\).*)%r ["serverConnectionId"]=> %r(NULL|int\(\d+\))%r } ===DONE=== mongodb-1.21.0/tests/apm/commandSucceededEvent-getServer-001.phpt0000644000175100001660000000215414760300420021442 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandSucceededEvent::getServer() --SKIPIF-- --FILE-- getServer()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $subscriber = new MySubscriber(); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand('admin', $command); ?> --EXPECTF-- Deprecated: %r(Function|Method)%r MongoDB\Driver\Monitoring\CommandSucceededEvent::getServer() is deprecated in %s object(MongoDB\Driver\Server)#%d (%d) { %A } mongodb-1.21.0/tests/apm/commandSucceededEvent-getServerConnectionId-001.phpt0000644000175100001660000000300514760300420023733 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandSucceededEvent includes serverConnectionId for 4.2+ server --SKIPIF-- --FILE-- getCommandName()); $this->commandStartedServerConnectionId = $event->getServerConnectionId(); var_dump($this->commandStartedServerConnectionId); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("commandSucceeded: %s\n", $event->getCommandName()); printf("same serverConnectionId as last commandStarted: %s\n", $event->getServerConnectionId() == $this->commandStartedServerConnectionId ? 'yes' : 'no'); var_dump($event->getServerConnectionId()); } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> --EXPECTF-- commandStarted: ping int(%d) commandSucceeded: ping same serverConnectionId as last commandStarted: yes int(%d) mongodb-1.21.0/tests/apm/commandSucceededEvent-getServerConnectionId-002.phpt0000644000175100001660000000223514760300420023740 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandSucceededEvent omits serverConnectionId for pre-4.2 server --SKIPIF-- =', '4.2'); ?> --FILE-- getCommandName()); var_dump($event->getServerConnectionId()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("commandSucceeded: %s\n", $event->getCommandName()); var_dump($event->getServerConnectionId()); } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> --EXPECTF-- commandStarted: ping NULL commandSucceeded: ping NULL mongodb-1.21.0/tests/apm/commandSucceededEvent-getServiceId-001.phpt0000644000175100001660000000303014760300420022043 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandSucceededEvent includes serviceId for load balanced topology --SKIPIF-- --FILE-- getCommandName()); $this->commandStartedServiceId = $event->getServiceId(); var_dump($this->commandStartedServiceId); } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { printf("commandSucceeded: %s\n", $event->getCommandName()); printf("same serviceId as last commandStarted: %s\n", $event->getServiceId() == $this->commandStartedServiceId ? 'yes' : 'no'); var_dump($event->getServiceId()); } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> --EXPECTF-- commandStarted: ping object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } commandSucceeded: ping same serviceId as last commandStarted: yes object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } mongodb-1.21.0/tests/apm/commandSucceededEvent-getServiceId-002.phpt0000644000175100001660000000215314760300420022051 0ustar --TEST-- MongoDB\Driver\Monitoring\CommandSucceededEvent omits serviceId for non-load balanced topology --SKIPIF-- --FILE-- getCommandName()); var_dump($event->getServiceId()); } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { printf("commandSucceeded: %s\n", $event->getCommandName()); var_dump($event->getServiceId()); } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $manager = create_test_manager(); $manager->addSubscriber(new MySubscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> --EXPECTF-- commandStarted: ping NULL commandSucceeded: ping NULL mongodb-1.21.0/tests/apm/monitoring-addSubscriber-001.phpt0000644000175100001660000000215314760300420020207 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Adding one subscriber --SKIPIF-- --FILE-- getCommandName(), "\n"; } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $query = new MongoDB\Driver\Query( [] ); $subscriber = new MySubscriber; echo "Before addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber ); echo "After addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); ?> --EXPECT-- Before addSubscriber After addSubscriber - started: find mongodb-1.21.0/tests/apm/monitoring-addSubscriber-002.phpt0000644000175100001660000000306214760300420020210 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Adding two subscribers --SKIPIF-- --FILE-- instanceName = $instanceName; } public function commandStarted( \MongoDB\Driver\Monitoring\CommandStartedEvent $event ): void { echo "- ({$this->instanceName}) - started: ", $event->getCommandName(), "\n"; } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $query = new MongoDB\Driver\Query( [] ); $subscriber1 = new MySubscriber( "ONE" ); $subscriber2 = new MySubscriber( "TWO" ); echo "Before addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber1 ); echo "After addSubscriber (ONE)\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber2 ); echo "After addSubscriber (TWO)\n"; $cursor = $m->executeQuery( "demo.test", $query ); ?> --EXPECT-- Before addSubscriber After addSubscriber (ONE) - (ONE) - started: find After addSubscriber (TWO) - (ONE) - started: find - (TWO) - started: find mongodb-1.21.0/tests/apm/monitoring-addSubscriber-003.phpt0000644000175100001660000000245314760300420020214 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Adding one subscriber multiple times --SKIPIF-- --FILE-- getCommandName(), "\n"; } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $query = new MongoDB\Driver\Query( [] ); $subscriber = new MySubscriber(); echo "Before addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber ); echo "After addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber ); echo "After addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); ?> --EXPECT-- Before addSubscriber After addSubscriber - started: find After addSubscriber - started: find mongodb-1.21.0/tests/apm/monitoring-addSubscriber-004.phpt0000644000175100001660000000352214760300420020213 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Adding three subscribers --SKIPIF-- --FILE-- instanceName = $instanceName; } public function commandStarted( \MongoDB\Driver\Monitoring\CommandStartedEvent $event ): void { echo "- ({$this->instanceName}) - started: ", $event->getCommandName(), "\n"; } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $query = new MongoDB\Driver\Query( [] ); $subscriber1 = new MySubscriber( "ONE" ); $subscriber2 = new MySubscriber( "TWO" ); $subscriber3 = new MySubscriber( "THR" ); echo "Before addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber1 ); echo "After addSubscriber (ONE)\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber2 ); echo "After addSubscriber (TWO)\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber3 ); echo "After addSubscriber (THR)\n"; $cursor = $m->executeQuery( "demo.test", $query ); ?> --EXPECT-- Before addSubscriber After addSubscriber (ONE) - (ONE) - started: find After addSubscriber (TWO) - (ONE) - started: find - (TWO) - started: find After addSubscriber (THR) - (ONE) - started: find - (TWO) - started: find - (THR) - started: find mongodb-1.21.0/tests/apm/monitoring-removeSubscriber-001.phpt0000644000175100001660000000243514760300420020757 0ustar --TEST-- MongoDB\Driver\Monitoring\removeSubscriber(): Removing the only subscriber --SKIPIF-- --FILE-- getCommandName(), "\n"; } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $query = new MongoDB\Driver\Query( [] ); $subscriber = new MySubscriber; echo "Before addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber ); echo "After addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\removeSubscriber( $subscriber ); echo "After removeSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); ?> --EXPECT-- Before addSubscriber After addSubscriber - started: find After removeSubscriber mongodb-1.21.0/tests/apm/monitoring-removeSubscriber-002.phpt0000644000175100001660000000342014760300420020753 0ustar --TEST-- MongoDB\Driver\Monitoring\removeSubscriber(): Removing one of multiple subscribers --SKIPIF-- --FILE-- instanceName = $instanceName; } public function commandStarted( \MongoDB\Driver\Monitoring\CommandStartedEvent $event ): void { echo "- ({$this->instanceName}) - started: ", $event->getCommandName(), "\n"; } public function commandSucceeded( \MongoDB\Driver\Monitoring\CommandSucceededEvent $event ): void { } public function commandFailed( \MongoDB\Driver\Monitoring\CommandFailedEvent $event ): void { } } $query = new MongoDB\Driver\Query( [] ); $subscriber1 = new MySubscriber( "ONE" ); $subscriber2 = new MySubscriber( "TWO" ); echo "Before addSubscriber\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber1 ); echo "After addSubscriber (ONE)\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\addSubscriber( $subscriber2 ); echo "After addSubscriber (TWO)\n"; $cursor = $m->executeQuery( "demo.test", $query ); MongoDB\Driver\Monitoring\removeSubscriber( $subscriber2 ); echo "After removeSubscriber (TWO)\n"; $cursor = $m->executeQuery( "demo.test", $query ); ?> --EXPECT-- Before addSubscriber After addSubscriber (ONE) - (ONE) - started: find After addSubscriber (TWO) - (ONE) - started: find - (TWO) - started: find After removeSubscriber (TWO) - (ONE) - started: find mongodb-1.21.0/tests/apm/serverChangedEvent-001.phpt0000644000175100001660000000560314760300420017035 0ustar --TEST-- MongoDB\Driver\Monitoring\ServerChangedEvent --SKIPIF-- --FILE-- isObserved) { return; } $this->isObserved = true; printf("getHost() returns a string: %s\n", is_string($event->getHost()) ? 'yes' : 'no'); printf("getPort() returns an integer: %s\n", is_integer($event->getPort()) ? 'yes' : 'no'); printf("getTopologyId() returns an ObjectId: %s\n", ($event->getTopologyId() instanceof MongoDB\BSON\ObjectId) ? 'yes' : 'no'); printf("getNewDescription() returns a ServerDescription: %s\n", ($event->getNewDescription() instanceof MongoDB\Driver\ServerDescription) ? 'yes' : 'no'); printf("getPreviousDescription() returns a ServerDescription: %s\n", ($event->getPreviousDescription() instanceof MongoDB\Driver\ServerDescription) ? 'yes' : 'no'); var_dump($event); } public function serverClosed(MongoDB\Driver\Monitoring\ServerClosedEvent $event): void {} public function serverHeartbeatFailed(MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent $event): void {} public function serverHeartbeatStarted(MongoDB\Driver\Monitoring\serverHeartbeatStartedEvent $event): void {} public function serverHeartbeatSucceeded(MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent $event): void {} public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void {} public function topologyChanged(MongoDB\Driver\Monitoring\TopologyChangedEvent $event): void {} public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} } $m = create_test_manager(); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); ?> ===DONE=== --EXPECTF-- getHost() returns a string: yes getPort() returns an integer: yes getTopologyId() returns an ObjectId: yes getNewDescription() returns a ServerDescription: yes getPreviousDescription() returns a ServerDescription: yes object(MongoDB\Driver\Monitoring\ServerChangedEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["topologyId"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } ["newDescription"]=> object(MongoDB\Driver\ServerDescription)#%d (%d) {%A } ["oldDescription"]=> object(MongoDB\Driver\ServerDescription)#%d (%d) {%A } } ===DONE=== mongodb-1.21.0/tests/apm/serverClosedEvent-001.phpt0000644000175100001660000000540414760300420016714 0ustar --TEST-- MongoDB\Driver\Monitoring\ServerClosedEvent --SKIPIF-- --FILE-- isObserved) { return; } $this->isObserved = true; printf("getHost() returns a string: %s\n", is_string($event->getHost()) ? 'yes' : 'no'); printf("getPort() returns an integer: %s\n", is_integer($event->getPort()) ? 'yes' : 'no'); printf("getTopologyId() returns an ObjectId: %s\n", ($event->getTopologyId() instanceof MongoDB\BSON\ObjectId) ? 'yes' : 'no'); var_dump($event); } public function serverHeartbeatFailed(MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent $event): void {} public function serverHeartbeatStarted(MongoDB\Driver\Monitoring\serverHeartbeatStartedEvent $event): void {} public function serverHeartbeatSucceeded(MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent $event): void {} public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void {} public function topologyChanged(MongoDB\Driver\Monitoring\TopologyChangedEvent $event): void {} public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} } /* Note: load balanced topologies will always emit ServerClosedEvent before * TopologyClosedEvent. That is easier than adding a non-member to a replica set * URI. A non-persistent client is used to make observation possible. */ $m = create_test_manager(URI, [], ['disableClientPersistence' => true]); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); /* Events dispatched during mongoc_client_destroy can only be observed before * RSHUTDOWN. This means that we must use a non-persistent client and free it * before the script ends. */ unset($m); ?> ===DONE=== --EXPECTF-- getHost() returns a string: yes getPort() returns an integer: yes getTopologyId() returns an ObjectId: yes object(MongoDB\Driver\Monitoring\ServerClosedEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["topologyId"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } ===DONE=== mongodb-1.21.0/tests/apm/serverHeartbeatFailedEvent-001.phpt0000644000175100001660000000640414760300420020510 0ustar --TEST-- MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent --SKIPIF-- --FILE-- getDurationMicros()) ? 'yes' : 'no'); printf("getError() returns an Exception: %s\n", ($event->getError() instanceof Exception) ? 'yes' : 'no'); printf("getHost() returns a string: %s\n", is_string($event->getHost()) ? 'yes' : 'no'); printf("getPort() returns an integer: %s\n", is_integer($event->getPort()) ? 'yes' : 'no'); printf("isAwaited() returns a bool: %s\n", is_bool($event->isAwaited()) ? 'yes' : 'no'); var_dump($event); } public function serverHeartbeatStarted(MongoDB\Driver\Monitoring\serverHeartbeatStartedEvent $event): void {} public function serverHeartbeatSucceeded(MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent $event): void {} public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void {} public function topologyChanged(MongoDB\Driver\Monitoring\TopologyChangedEvent $event): void {} public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} } /* Use a separate client to configure the fail point and trigger a heartbeat * failure on the second client under test. This test should not be run on * load balanced or sharded clusters with multiple mongoses, since we can not * reliably select the same target server across two clients. */ $m2 = create_test_manager(URI, [], ['disableClientPersistence' => true]); configureFailPoint($m2, 'failCommand', ['times' => 1], ['failCommands' => ['isMaster', 'hello'], 'closeConnection' => true]); $m = create_test_manager(URI, [], ['disableClientPersistence' => true]); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); throws(function() use ($m, $command) { $m->executeCommand(DATABASE_NAME, $command); }, MongoDB\Driver\Exception\ConnectionTimeoutException::class); configureFailPoint($m2, 'failCommand', 'off'); ?> ===DONE=== --EXPECTF-- getDurationMicros() returns an integer: yes getError() returns an Exception: yes getHost() returns a string: yes getPort() returns an integer: yes isAwaited() returns a bool: yes object(MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["awaited"]=> bool(%s) ["durationMicros"]=> int(%d) ["error"]=> object(MongoDB\Driver\Exception\RuntimeException)#%d (%d) {%A } } OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException ===DONE=== mongodb-1.21.0/tests/apm/serverHeartbeatStartedEvent-001.phpt0000644000175100001660000000427614760300420020737 0ustar --TEST-- MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent --SKIPIF-- --FILE-- isObserved) { return; } $this->isObserved = true; printf("getHost() returns a string: %s\n", is_string($event->getHost()) ? 'yes' : 'no'); printf("getPort() returns an integer: %s\n", is_integer($event->getPort()) ? 'yes' : 'no'); printf("isAwaited() returns a bool: %s\n", is_bool($event->isAwaited()) ? 'yes' : 'no'); var_dump($event); } public function serverHeartbeatSucceeded(MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent $event): void {} public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void {} public function topologyChanged(MongoDB\Driver\Monitoring\TopologyChangedEvent $event): void {} public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} } $m = create_test_manager(); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); ?> ===DONE=== --EXPECTF-- getHost() returns a string: yes getPort() returns an integer: yes isAwaited() returns a bool: yes object(MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["awaited"]=> bool(%s) } ===DONE=== mongodb-1.21.0/tests/apm/serverHeartbeatSucceededEvent-001.phpt0000644000175100001660000000507614760300420021214 0ustar --TEST-- MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent --SKIPIF-- --FILE-- isObserved) { return; } $this->isObserved = true; printf("getDurationMicros() returns an integer: %s\n", is_integer($event->getDurationMicros()) ? 'yes' : 'no'); printf("getHost() returns a string: %s\n", is_string($event->getHost()) ? 'yes' : 'no'); printf("getPort() returns an integer: %s\n", is_integer($event->getPort()) ? 'yes' : 'no'); printf("getReply() returns an object: %s\n", is_object($event->getReply()) ? 'yes' : 'no'); printf("isAwaited() returns a bool: %s\n", is_bool($event->isAwaited()) ? 'yes' : 'no'); var_dump($event); } public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void {} public function topologyChanged(MongoDB\Driver\Monitoring\TopologyChangedEvent $event): void {} public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} } $m = create_test_manager(); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); ?> ===DONE=== --EXPECTF-- getDurationMicros() returns an integer: yes getHost() returns a string: yes getPort() returns an integer: yes getReply() returns an object: yes isAwaited() returns a bool: yes object(MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["awaited"]=> bool(%s) ["durationMicros"]=> int(%d) ["reply"]=> object(stdClass)#%d (%d) {%A } } ===DONE=== mongodb-1.21.0/tests/apm/serverOpeningEvent-001.phpt0000644000175100001660000000444414760300420017105 0ustar --TEST-- MongoDB\Driver\Monitoring\ServerOpeningEvent --SKIPIF-- --FILE-- isObserved) { return; } $this->isObserved = true; printf("getHost() returns a string: %s\n", is_string($event->getHost()) ? 'yes' : 'no'); printf("getPort() returns an integer: %s\n", is_integer($event->getPort()) ? 'yes' : 'no'); printf("getTopologyId() returns an ObjectId: %s\n", ($event->getTopologyId() instanceof MongoDB\BSON\ObjectId) ? 'yes' : 'no'); var_dump($event); } public function topologyChanged(MongoDB\Driver\Monitoring\TopologyChangedEvent $event): void {} public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} } $m = create_test_manager(); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); ?> ===DONE=== --EXPECTF-- getHost() returns a string: yes getPort() returns an integer: yes getTopologyId() returns an ObjectId: yes object(MongoDB\Driver\Monitoring\ServerOpeningEvent)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["topologyId"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } ===DONE=== mongodb-1.21.0/tests/apm/topologyChangedEvent-001.phpt0000644000175100001660000000513214760300420017400 0ustar --TEST-- MongoDB\Driver\Monitoring\TopologyChangedEvent --SKIPIF-- --FILE-- isObserved) { return; } $this->isObserved = true; printf("getTopologyId() returns an ObjectId: %s\n", ($event->getTopologyId() instanceof MongoDB\BSON\ObjectId) ? 'yes' : 'no'); printf("getNewDescription() returns a TopologyDescription: %s\n", ($event->getNewDescription() instanceof MongoDB\Driver\TopologyDescription) ? 'yes' : 'no'); printf("getPreviousDescription() returns a TopologyDescription: %s\n", ($event->getPreviousDescription() instanceof MongoDB\Driver\TopologyDescription) ? 'yes' : 'no'); var_dump($event); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} } $m = create_test_manager(); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); ?> ===DONE=== --EXPECTF-- getTopologyId() returns an ObjectId: yes getNewDescription() returns a TopologyDescription: yes getPreviousDescription() returns a TopologyDescription: yes object(MongoDB\Driver\Monitoring\TopologyChangedEvent)#%d (%d) { ["topologyId"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } ["newDescription"]=> object(MongoDB\Driver\TopologyDescription)#%d (%d) {%A } ["oldDescription"]=> object(MongoDB\Driver\TopologyDescription)#%d (%d) {%A } } ===DONE=== mongodb-1.21.0/tests/apm/topologyClosedEvent-001.phpt0000644000175100001660000000433414760300420017263 0ustar --TEST-- MongoDB\Driver\Monitoring\TopologyClosedEvent --SKIPIF-- --FILE-- getTopologyId() instanceof MongoDB\BSON\ObjectId) ? 'yes' : 'no'); var_dump($event); } public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} } /* Note: TopologyClosedEvent can only be observed for non-persistent clients. * Persistent clients are destroyed in GSHUTDOWN, long after any PHP objects * (including subscribers) are freed. */ $m = create_test_manager(URI, [], ['disableClientPersistence' => true]); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); /* Events dispatched during mongoc_client_destroy can only be observed before * RSHUTDOWN. This means that we must use a non-persistent client and free it * before the script ends. */ unset($m); ?> ===DONE=== --EXPECTF-- getTopologyId() returns an ObjectId: yes object(MongoDB\Driver\Monitoring\TopologyClosedEvent)#%d (%d) { ["topologyId"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } ===DONE=== mongodb-1.21.0/tests/apm/topologyOpeningEvent-001.phpt0000644000175100001660000000345314760300420017452 0ustar --TEST-- MongoDB\Driver\Monitoring\TopologyOpeningEvent --SKIPIF-- --FILE-- getTopologyId() instanceof MongoDB\BSON\ObjectId) ? 'yes' : 'no'); var_dump($event); } } $m = create_test_manager(); $m->addSubscriber(new MySubscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); ?> ===DONE=== --EXPECTF-- getTopologyId() returns an ObjectId: yes object(MongoDB\Driver\Monitoring\TopologyOpeningEvent)#%d (%d) { ["topologyId"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } ===DONE=== mongodb-1.21.0/tests/apm/topologyOpeningEvent-002.phpt0000644000175100001660000000502514760300420017450 0ustar --TEST-- MongoDB\Driver\Monitoring\TopologyOpeningEvent shares topology ID with other events --SKIPIF-- --FILE-- assertSameTopologyId($event); } public function serverClosed(MongoDB\Driver\Monitoring\ServerClosedEvent $event): void { $this->assertSameTopologyId($event); } public function serverHeartbeatFailed(MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent $event): void {} public function serverHeartbeatStarted(MongoDB\Driver\Monitoring\serverHeartbeatStartedEvent $event): void {} public function serverHeartbeatSucceeded(MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent $event): void {} public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void { $this->assertSameTopologyId($event); } public function topologyChanged(MongoDB\Driver\Monitoring\TopologyChangedEvent $event): void { $this->assertSameTopologyId($event); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void { $this->assertSameTopologyId($event); } public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void { $this->topologyId = $event->getTopologyId(); } private function assertSameTopologyId($event) { $this->numAssertions++; if ($event->getTopologyId() != $this->topologyId) { throw new UnexpectedValueException(sprintf('Topology ID "%s" from %s does not match "%s" from TopologyOpeningEvent', $event->getTopologyId(), (new ReflectionClass($event))->getShortName(), $this->topologyId)); } } } $subscriber = new MySubscriber; $m = create_test_manager(); $m->addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $m->executeCommand(DATABASE_NAME, $command); /* Rather than expecting a specific number or sequence of events, we can expect * that at least one assertion was made and trust that any failures would have * resulted in an exception being thrown by assertSameTopologyId(). */ var_dump($subscriber->numAssertions > 1); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson-corpus/array-decodeError-001.phpt0000644000175100001660000000102214760300420020310 0ustar --TEST-- Array: Array length too long: eats outer terminator --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/array-decodeError-002.phpt0000644000175100001660000000101614760300420020314 0ustar --TEST-- Array: Array length too short: leaks terminator --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/array-decodeError-003.phpt0000644000175100001660000000103314760300420020314 0ustar --TEST-- Array: Invalid Array: bad string length in field --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/array-valid-001.phpt0000644000175100001660000000145114760300420017160 0ustar --TEST-- Array: Empty --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0d000000046100050000000000 {"a":[]} 0d000000046100050000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/array-valid-002.phpt0000644000175100001660000000161114760300420017157 0ustar --TEST-- Array: Single Element Array --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 140000000461000c0000001030000a0000000000 {"a":[{"$numberInt":"10"}]} 140000000461000c0000001030000a0000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/array-valid-003.phpt0000644000175100001660000000261614760300420017166 0ustar --TEST-- Array: Single Element Array with index set incorrectly to empty string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate BSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromPHP(MongoDB\BSON\Document::fromBSON($degenerateBson)->toPHP())), "\n"; // Degenerate BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($degenerateBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 140000000461000c0000001030000a0000000000 {"a":[{"$numberInt":"10"}]} 140000000461000c0000001030000a0000000000 140000000461000c0000001030000a0000000000 {"a":[{"$numberInt":"10"}]} ===DONE===mongodb-1.21.0/tests/bson-corpus/array-valid-004.phpt0000644000175100001660000000261014760300420017161 0ustar --TEST-- Array: Single Element Array with index set incorrectly to ab --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate BSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromPHP(MongoDB\BSON\Document::fromBSON($degenerateBson)->toPHP())), "\n"; // Degenerate BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($degenerateBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 140000000461000c0000001030000a0000000000 {"a":[{"$numberInt":"10"}]} 140000000461000c0000001030000a0000000000 140000000461000c0000001030000a0000000000 {"a":[{"$numberInt":"10"}]} ===DONE===mongodb-1.21.0/tests/bson-corpus/array-valid-005.phpt0000644000175100001660000000277714760300420017200 0ustar --TEST-- Array: Multi Element Array with duplicate indexes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate BSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromPHP(MongoDB\BSON\Document::fromBSON($degenerateBson)->toPHP())), "\n"; // Degenerate BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($degenerateBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 1b000000046100130000001030000a000000103100140000000000 {"a":[{"$numberInt":"10"},{"$numberInt":"20"}]} 1b000000046100130000001030000a000000103100140000000000 1b000000046100130000001030000a000000103100140000000000 {"a":[{"$numberInt":"10"},{"$numberInt":"20"}]} ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-decodeError-001.phpt0000644000175100001660000000103114760300420020456 0ustar --TEST-- Binary type: Length longer than document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-decodeError-002.phpt0000644000175100001660000000075514760300420020473 0ustar --TEST-- Binary type: Negative length --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-decodeError-003.phpt0000644000175100001660000000100614760300420020462 0ustar --TEST-- Binary type: subtype 0x02 length too long --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-decodeError-004.phpt0000644000175100001660000000100714760300420020464 0ustar --TEST-- Binary type: subtype 0x02 length too short --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-decodeError-005.phpt0000644000175100001660000000101214760300420020461 0ustar --TEST-- Binary type: subtype 0x02 length negative one --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-parseError-001.phpt0000644000175100001660000000075514760300420020361 0ustar --TEST-- Binary type: $uuid wrong type --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-parseError-002.phpt0000644000175100001660000000075214760300420020357 0ustar --TEST-- Binary type: $uuid invalid value--too short --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-parseError-003.phpt0000644000175100001660000000076414760300420020363 0ustar --TEST-- Binary type: $uuid invalid value--too long --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-parseError-004.phpt0000644000175100001660000000076714760300420020367 0ustar --TEST-- Binary type: $uuid invalid value--misplaced hyphens --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-parseError-005.phpt0000644000175100001660000000076614760300420020367 0ustar --TEST-- Binary type: $uuid invalid value--too many hyphens --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-001.phpt0000644000175100001660000000163014760300420017325 0ustar --TEST-- Binary type: subtype 0x00 (Zero-length) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0d000000057800000000000000 {"x":{"$binary":{"base64":"","subType":"00"}}} 0d000000057800000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-002.phpt0000644000175100001660000000223514760300420017330 0ustar --TEST-- Binary type: subtype 0x00 (Zero-length, keys reversed) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0d000000057800000000000000 {"x":{"$binary":{"base64":"","subType":"00"}}} 0d000000057800000000000000 0d000000057800000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-003.phpt0000644000175100001660000000164014760300420017330 0ustar --TEST-- Binary type: subtype 0x00 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f0000000578000200000000ffff00 {"x":{"$binary":{"base64":"\/\/8=","subType":"00"}}} 0f0000000578000200000000ffff00 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-004.phpt0000644000175100001660000000164014760300420017331 0ustar --TEST-- Binary type: subtype 0x01 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f0000000578000200000001ffff00 {"x":{"$binary":{"base64":"\/\/8=","subType":"01"}}} 0f0000000578000200000001ffff00 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-005.phpt0000644000175100001660000000167014760300420017335 0ustar --TEST-- Binary type: subtype 0x02 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 13000000057800060000000202000000ffff00 {"x":{"$binary":{"base64":"\/\/8=","subType":"02"}}} 13000000057800060000000202000000ffff00 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-006.phpt0000644000175100001660000000203414760300420017331 0ustar --TEST-- Binary type: subtype 0x03 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1d000000057800100000000373ffd26444b34c6990e8e7d1dfc035d400 {"x":{"$binary":{"base64":"c\/\/SZESzTGmQ6OfR38A11A==","subType":"03"}}} 1d000000057800100000000373ffd26444b34c6990e8e7d1dfc035d400 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-007.phpt0000644000175100001660000000203414760300420017332 0ustar --TEST-- Binary type: subtype 0x04 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1d000000057800100000000473ffd26444b34c6990e8e7d1dfc035d400 {"x":{"$binary":{"base64":"c\/\/SZESzTGmQ6OfR38A11A==","subType":"04"}}} 1d000000057800100000000473ffd26444b34c6990e8e7d1dfc035d400 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-008.phpt0000644000175100001660000000247214760300420017341 0ustar --TEST-- Binary type: subtype 0x04 UUID --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1d000000057800100000000473ffd26444b34c6990e8e7d1dfc035d400 {"x":{"$binary":{"base64":"c\/\/SZESzTGmQ6OfR38A11A==","subType":"04"}}} 1d000000057800100000000473ffd26444b34c6990e8e7d1dfc035d400 1d000000057800100000000473ffd26444b34c6990e8e7d1dfc035d400 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-009.phpt0000644000175100001660000000203414760300420017334 0ustar --TEST-- Binary type: subtype 0x05 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1d000000057800100000000573ffd26444b34c6990e8e7d1dfc035d400 {"x":{"$binary":{"base64":"c\/\/SZESzTGmQ6OfR38A11A==","subType":"05"}}} 1d000000057800100000000573ffd26444b34c6990e8e7d1dfc035d400 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-010.phpt0000644000175100001660000000203414760300420017324 0ustar --TEST-- Binary type: subtype 0x07 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1d000000057800100000000773ffd26444b34c6990e8e7d1dfc035d400 {"x":{"$binary":{"base64":"c\/\/SZESzTGmQ6OfR38A11A==","subType":"07"}}} 1d000000057800100000000773ffd26444b34c6990e8e7d1dfc035d400 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-011.phpt0000644000175100001660000000203414760300420017325 0ustar --TEST-- Binary type: subtype 0x08 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1d000000057800100000000873ffd26444b34c6990e8e7d1dfc035d400 {"x":{"$binary":{"base64":"c\/\/SZESzTGmQ6OfR38A11A==","subType":"08"}}} 1d000000057800100000000873ffd26444b34c6990e8e7d1dfc035d400 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-012.phpt0000644000175100001660000000164014760300420017330 0ustar --TEST-- Binary type: subtype 0x80 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f0000000578000200000080ffff00 {"x":{"$binary":{"base64":"\/\/8=","subType":"80"}}} 0f0000000578000200000080ffff00 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-013.phpt0000644000175100001660000000200314760300420017323 0ustar --TEST-- Binary type: $type query operator (conflicts with legacy $binary form with $type field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1f000000037800170000000224747970650007000000737472696e67000000 {"x":{"$type":"string"}} 1f000000037800170000000224747970650007000000737472696e67000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-014.phpt0000644000175100001660000000175614760300420017342 0ustar --TEST-- Binary type: $type query operator (conflicts with legacy $binary form with $type field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000000378001000000010247479706500020000000000 {"x":{"$type":{"$numberInt":"2"}}} 180000000378001000000010247479706500020000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-015.phpt0000644000175100001660000000176014760300420017336 0ustar --TEST-- Binary type: subtype 0x09 Vector FLOAT32 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 170000000578000a0000000927000000fe420000e04000 {"x":{"$binary":{"base64":"JwAAAP5CAADgQA==","subType":"09"}}} 170000000578000a0000000927000000fe420000e04000 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-016.phpt0000644000175100001660000000167214760300420017341 0ustar --TEST-- Binary type: subtype 0x09 Vector INT8 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 11000000057800040000000903007f0700 {"x":{"$binary":{"base64":"AwB\/Bw==","subType":"09"}}} 11000000057800040000000903007f0700 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-017.phpt0000644000175100001660000000170014760300420017332 0ustar --TEST-- Binary type: subtype 0x09 Vector PACKED_BIT --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 11000000057800040000000910007f0700 {"x":{"$binary":{"base64":"EAB\/Bw==","subType":"09"}}} 11000000057800040000000910007f0700 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-018.phpt0000644000175100001660000000166614760300420017346 0ustar --TEST-- Binary type: subtype 0x09 Vector (Zero-length) FLOAT32 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f0000000578000200000009270000 {"x":{"$binary":{"base64":"JwA=","subType":"09"}}} 0f0000000578000200000009270000 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-019.phpt0000644000175100001660000000166314760300420017344 0ustar --TEST-- Binary type: subtype 0x09 Vector (Zero-length) INT8 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f0000000578000200000009030000 {"x":{"$binary":{"base64":"AwA=","subType":"09"}}} 0f0000000578000200000009030000 ===DONE===mongodb-1.21.0/tests/bson-corpus/binary-valid-020.phpt0000644000175100001660000000167114760300420017333 0ustar --TEST-- Binary type: subtype 0x09 Vector (Zero-length) PACKED_BIT --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f0000000578000200000009100000 {"x":{"$binary":{"base64":"EAA=","subType":"09"}}} 0f0000000578000200000009100000 ===DONE===mongodb-1.21.0/tests/bson-corpus/boolean-decodeError-001.phpt0000644000175100001660000000075414760300420020624 0ustar --TEST-- Boolean: Invalid boolean value of 2 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/boolean-decodeError-002.phpt0000644000175100001660000000075514760300420020626 0ustar --TEST-- Boolean: Invalid boolean value of -1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/boolean-valid-001.phpt0000644000175100001660000000142614760300420017463 0ustar --TEST-- Boolean: True --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 090000000862000100 {"b":true} 090000000862000100 ===DONE===mongodb-1.21.0/tests/bson-corpus/boolean-valid-002.phpt0000644000175100001660000000143114760300420017460 0ustar --TEST-- Boolean: False --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 090000000862000000 {"b":false} 090000000862000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code-decodeError-001.phpt0000644000175100001660000000101614760300420020107 0ustar --TEST-- Javascript Code: bad code string length: 0 (but no 0x00 either) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code-decodeError-002.phpt0000644000175100001660000000077214760300420020120 0ustar --TEST-- Javascript Code: bad code string length: -1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code-decodeError-003.phpt0000644000175100001660000000101714760300420020112 0ustar --TEST-- Javascript Code: bad code string length: eats terminator --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code-decodeError-004.phpt0000644000175100001660000000104014760300420020107 0ustar --TEST-- Javascript Code: bad code string length: longer than rest of document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code-decodeError-005.phpt0000644000175100001660000000101214760300420020107 0ustar --TEST-- Javascript Code: code string is not null-terminated --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code-decodeError-006.phpt0000644000175100001660000000100514760300420020112 0ustar --TEST-- Javascript Code: empty code string, but extra null --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code-decodeError-007.phpt0000644000175100001660000000076114760300420020123 0ustar --TEST-- Javascript Code: invalid UTF-8 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code-valid-001.phpt0000644000175100001660000000152014760300420016751 0ustar --TEST-- Javascript Code: Empty string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0d0000000d6100010000000000 {"a":{"$code":""}} 0d0000000d6100010000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code-valid-002.phpt0000644000175100001660000000153414760300420016757 0ustar --TEST-- Javascript Code: Single character --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0e0000000d610002000000620000 {"a":{"$code":"b"}} 0e0000000d610002000000620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code-valid-003.phpt0000644000175100001660000000166314760300420016763 0ustar --TEST-- Javascript Code: Multi-character --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000d61000d0000006162616261626162616261620000 {"a":{"$code":"abababababab"}} 190000000d61000d0000006162616261626162616261620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code-valid-004.phpt0000644000175100001660000000175514760300420016766 0ustar --TEST-- Javascript Code: two-byte UTF-8 (é) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000d61000d000000c3a9c3a9c3a9c3a9c3a9c3a90000 {"a":{"$code":"\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9"}} 190000000d61000d000000c3a9c3a9c3a9c3a9c3a9c3a90000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code-valid-005.phpt0000644000175100001660000000172614760300420016765 0ustar --TEST-- Javascript Code: three-byte UTF-8 (☆) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000d61000d000000e29886e29886e29886e298860000 {"a":{"$code":"\u2606\u2606\u2606\u2606"}} 190000000d61000d000000e29886e29886e29886e298860000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code-valid-006.phpt0000644000175100001660000000203214760300420016755 0ustar --TEST-- Javascript Code: Embedded nulls --XFAIL-- Embedded null in code string is not supported in libbson (CDRIVER-1879) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000d61000d0000006162006261620062616261620000 {"a":{"$code":"ab\u0000bab\u0000babab"}} 190000000d61000d0000006162006261620062616261620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-001.phpt0000644000175100001660000000106414760300420021631 0ustar --TEST-- Javascript Code with Scope: field length zero --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-002.phpt0000644000175100001660000000107014760300420021627 0ustar --TEST-- Javascript Code with Scope: field length negative --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-003.phpt0000644000175100001660000000105614760300420021634 0ustar --TEST-- Javascript Code with Scope: field length too short (less than minimum size) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-004.phpt0000644000175100001660000000111314760300420021627 0ustar --TEST-- Javascript Code with Scope: field length too short (truncates scope) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-005.phpt0000644000175100001660000000111214760300420021627 0ustar --TEST-- Javascript Code with Scope: field length too long (clips outer doc) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-006.phpt0000644000175100001660000000112014760300420021627 0ustar --TEST-- Javascript Code with Scope: field length too long (longer than outer doc) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-007.phpt0000644000175100001660000000110414760300420021632 0ustar --TEST-- Javascript Code with Scope: bad code string: length too short --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-008.phpt0000644000175100001660000000112114760300420021632 0ustar --TEST-- Javascript Code with Scope: bad code string: length too long (clips scope) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-009.phpt0000644000175100001660000000110314760300420021633 0ustar --TEST-- Javascript Code with Scope: bad code string: negative length --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-010.phpt0000644000175100001660000000111414760300420021625 0ustar --TEST-- Javascript Code with Scope: bad code string: length longer than field --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-decodeError-011.phpt0000644000175100001660000000106614760300420021634 0ustar --TEST-- Javascript Code with Scope: bad scope doc (field has bad string length) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-valid-001.phpt0000644000175100001660000000167614760300420020504 0ustar --TEST-- Javascript Code with Scope: Empty code string, empty scope --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 160000000f61000e0000000100000000050000000000 {"a":{"$code":"","$scope":{}}} 160000000f61000e0000000100000000050000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-valid-002.phpt0000644000175100001660000000174214760300420020477 0ustar --TEST-- Javascript Code with Scope: Non-empty code string, empty scope --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1a0000000f610012000000050000006162636400050000000000 {"a":{"$code":"abcd","$scope":{}}} 1a0000000f610012000000050000006162636400050000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-valid-003.phpt0000644000175100001660000000203314760300420020472 0ustar --TEST-- Javascript Code with Scope: Empty code string, non-empty scope --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1d0000000f61001500000001000000000c000000107800010000000000 {"a":{"$code":"","$scope":{"x":{"$numberInt":"1"}}}} 1d0000000f61001500000001000000000c000000107800010000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-valid-004.phpt0000644000175100001660000000210214760300420020470 0ustar --TEST-- Javascript Code with Scope: Non-empty code string and non-empty scope --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 210000000f6100190000000500000061626364000c000000107800010000000000 {"a":{"$code":"abcd","$scope":{"x":{"$numberInt":"1"}}}} 210000000f6100190000000500000061626364000c000000107800010000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/code_w_scope-valid-005.phpt0000644000175100001660000000213314760300420020475 0ustar --TEST-- Javascript Code with Scope: Unicode and embedded null in code string, empty scope --XFAIL-- Embedded null in code string is not supported in libbson (CDRIVER-1879) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1a0000000f61001200000005000000c3a9006400050000000000 {"a":{"$code":"\u00e9\u0000d","$scope":{}}} 1a0000000f61001200000005000000c3a9006400050000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/datetime-decodeError-001.phpt0000644000175100001660000000076114760300420020777 0ustar --TEST-- DateTime: datetime field truncated --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/datetime-valid-001.phpt0000644000175100001660000000250214760300420017634 0ustar --TEST-- DateTime: epoch --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000096100000000000000000000 {"a":{"$date":{"$numberLong":"0"}}} {"a":{"$date":"1970-01-01T00:00:00Z"}} 10000000096100000000000000000000 {"a":{"$date":"1970-01-01T00:00:00Z"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/datetime-valid-002.phpt0000644000175100001660000000255414760300420017644 0ustar --TEST-- DateTime: positive ms --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000096100c5d8d6cc3b01000000 {"a":{"$date":{"$numberLong":"1356351330501"}}} {"a":{"$date":"2012-12-24T12:15:30.501Z"}} 10000000096100c5d8d6cc3b01000000 {"a":{"$date":"2012-12-24T12:15:30.501Z"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/datetime-valid-003.phpt0000644000175100001660000000257214760300420017645 0ustar --TEST-- DateTime: negative --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000096100c33ce7b9bdffffff00 {"a":{"$date":{"$numberLong":"-284643869501"}}} {"a":{"$date":{"$numberLong":"-284643869501"}}} 10000000096100c33ce7b9bdffffff00 {"a":{"$date":{"$numberLong":"-284643869501"}}} ===DONE===mongodb-1.21.0/tests/bson-corpus/datetime-valid-004.phpt0000644000175100001660000000256414760300420017647 0ustar --TEST-- DateTime: Y10K --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 1000000009610000dc1fd277e6000000 {"a":{"$date":{"$numberLong":"253402300800000"}}} {"a":{"$date":{"$numberLong":"253402300800000"}}} 1000000009610000dc1fd277e6000000 {"a":{"$date":{"$numberLong":"253402300800000"}}} ===DONE===mongodb-1.21.0/tests/bson-corpus/datetime-valid-005.phpt0000644000175100001660000000256014760300420017644 0ustar --TEST-- DateTime: leading zero ms --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000096100d1d6d6cc3b01000000 {"a":{"$date":{"$numberLong":"1356351330001"}}} {"a":{"$date":"2012-12-24T12:15:30.001Z"}} 10000000096100d1d6d6cc3b01000000 {"a":{"$date":"2012-12-24T12:15:30.001Z"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-decodeError-001.phpt0000644000175100001660000000104314760300420021163 0ustar --TEST-- DBPointer type (deprecated): String with negative length --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-decodeError-002.phpt0000644000175100001660000000103714760300420021167 0ustar --TEST-- DBPointer type (deprecated): String with zero length --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-decodeError-003.phpt0000644000175100001660000000104214760300420021164 0ustar --TEST-- DBPointer type (deprecated): String not null terminated --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-decodeError-004.phpt0000644000175100001660000000105614760300420021172 0ustar --TEST-- DBPointer type (deprecated): short OID (less than minimum length for field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-decodeError-005.phpt0000644000175100001660000000106714760300420021175 0ustar --TEST-- DBPointer type (deprecated): short OID (greater than minimum, but truncated) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-decodeError-006.phpt0000644000175100001660000000103514760300420021171 0ustar --TEST-- DBPointer type (deprecated): String with bad UTF-8 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-valid-001.phpt0000644000175100001660000000234614760300420020034 0ustar --TEST-- DBPointer type (deprecated): DBpointer --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1a0000000c610002000000620056e1fc72e0c917e9c471416100 {"a":{"$dbPointer":{"$ref":"b","$id":{"$oid":"56e1fc72e0c917e9c4714161"}}}} 1a0000000c610002000000620056e1fc72e0c917e9c471416100 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-valid-002.phpt0000644000175100001660000000304714760300420020034 0ustar --TEST-- DBPointer type (deprecated): DBpointer with opposite key order --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1a0000000c610002000000620056e1fc72e0c917e9c471416100 {"a":{"$dbPointer":{"$ref":"b","$id":{"$oid":"56e1fc72e0c917e9c4714161"}}}} 1a0000000c610002000000620056e1fc72e0c917e9c471416100 1a0000000c610002000000620056e1fc72e0c917e9c471416100 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbpointer-valid-003.phpt0000644000175100001660000000237714760300420020042 0ustar --TEST-- DBPointer type (deprecated): With two-byte UTF-8 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1b0000000c610003000000c3a90056e1fc72e0c917e9c471416100 {"a":{"$dbPointer":{"$ref":"\u00e9","$id":{"$oid":"56e1fc72e0c917e9c4714161"}}}} 1b0000000c610003000000c3a90056e1fc72e0c917e9c471416100 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-001.phpt0000644000175100001660000000231014760300420017117 0ustar --TEST-- Document type (DBRef sub-documents): DBRef --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 37000000036462726566002b0000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e0000 {"dbref":{"$ref":"collection","$id":{"$oid":"58921b3e6e32ab156a22b59e"}}} 37000000036462726566002b0000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e0000 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-002.phpt0000644000175100001660000000246614760300420017134 0ustar --TEST-- Document type (DBRef sub-documents): DBRef with database --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 4300000003646272656600370000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e0224646200030000006462000000 {"dbref":{"$ref":"collection","$id":{"$oid":"58921b3e6e32ab156a22b59e"},"$db":"db"}} 4300000003646272656600370000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e0224646200030000006462000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-003.phpt0000644000175100001660000000254414760300420017132 0ustar --TEST-- Document type (DBRef sub-documents): DBRef with database and additional fields --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 48000000036462726566003c0000000224726566000b000000636f6c6c656374696f6e0010246964002a00000002246462000300000064620002666f6f0004000000626172000000 {"dbref":{"$ref":"collection","$id":{"$numberInt":"42"},"$db":"db","foo":"bar"}} 48000000036462726566003c0000000224726566000b000000636f6c6c656374696f6e0010246964002a00000002246462000300000064620002666f6f0004000000626172000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-004.phpt0000644000175100001660000000250714760300420017132 0ustar --TEST-- Document type (DBRef sub-documents): DBRef with additional fields --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 4400000003646272656600380000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e02666f6f0004000000626172000000 {"dbref":{"$ref":"collection","$id":{"$oid":"58921b3e6e32ab156a22b59e"},"foo":"bar"}} 4400000003646272656600380000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e02666f6f0004000000626172000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-005.phpt0000644000175100001660000000246114760300420017132 0ustar --TEST-- Document type (DBRef sub-documents): Document with key names similar to those of a DBRef --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 3e0000000224726566000c0000006e6f742d612d646272656600072469640058921b3e6e32ab156a22b59e022462616e616e6100050000007065656c0000 {"$ref":"not-a-dbref","$id":{"$oid":"58921b3e6e32ab156a22b59e"},"$banana":"peel"} 3e0000000224726566000c0000006e6f742d612d646272656600072469640058921b3e6e32ab156a22b59e022462616e616e6100050000007065656c0000 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-006.phpt0000644000175100001660000000271014760300420017130 0ustar --TEST-- Document type (DBRef sub-documents): DBRef with additional dollar-prefixed and dotted fields --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 48000000036462726566003c0000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e10612e62000100000010246300010000000000 {"dbref":{"$ref":"collection","$id":{"$oid":"58921b3e6e32ab156a22b59e"},"a.b":{"$numberInt":"1"},"$c":{"$numberInt":"1"}}} 48000000036462726566003c0000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e10612e62000100000010246300010000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-007.phpt0000644000175100001660000000206514760300420017134 0ustar --TEST-- Document type (DBRef sub-documents): Sub-document resembles DBRef but $id is missing --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 26000000036462726566001a0000000224726566000b000000636f6c6c656374696f6e000000 {"dbref":{"$ref":"collection"}} 26000000036462726566001a0000000224726566000b000000636f6c6c656374696f6e000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-008.phpt0000644000175100001660000000230314760300420017130 0ustar --TEST-- Document type (DBRef sub-documents): Sub-document resembles DBRef but $ref is not a string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 2c000000036462726566002000000010247265660001000000072469640058921b3e6e32ab156a22b59e0000 {"dbref":{"$ref":{"$numberInt":"1"},"$id":{"$oid":"58921b3e6e32ab156a22b59e"}}} 2c000000036462726566002000000010247265660001000000072469640058921b3e6e32ab156a22b59e0000 ===DONE===mongodb-1.21.0/tests/bson-corpus/dbref-valid-009.phpt0000644000175100001660000000254214760300420017136 0ustar --TEST-- Document type (DBRef sub-documents): Sub-document resembles DBRef but $db is not a string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 4000000003646272656600340000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e1024646200010000000000 {"dbref":{"$ref":"collection","$id":{"$oid":"58921b3e6e32ab156a22b59e"},"$db":{"$numberInt":"1"}}} 4000000003646272656600340000000224726566000b000000636f6c6c656374696f6e00072469640058921b3e6e32ab156a22b59e1024646200010000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-001.phpt0000644000175100001660000000166014760300420020033 0ustar --TEST-- Decimal128: Special - Canonical NaN --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007c00 {"d":{"$numberDecimal":"NaN"}} 180000001364000000000000000000000000000000007c00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-002.phpt0000644000175100001660000000136614760300420020037 0ustar --TEST-- Decimal128: Special - Negative NaN --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000fc00 {"d":{"$numberDecimal":"NaN"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-003.phpt0000644000175100001660000000146214760300420020035 0ustar --TEST-- Decimal128: Special - Negative NaN --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000fc00 {"d":{"$numberDecimal":"NaN"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-004.phpt0000644000175100001660000000137014760300420020034 0ustar --TEST-- Decimal128: Special - Canonical SNaN --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007e00 {"d":{"$numberDecimal":"NaN"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-005.phpt0000644000175100001660000000136714760300420020043 0ustar --TEST-- Decimal128: Special - Negative SNaN --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000fe00 {"d":{"$numberDecimal":"NaN"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-006.phpt0000644000175100001660000000137414760300420020042 0ustar --TEST-- Decimal128: Special - NaN with a payload --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001200000000000000000000000000007e00 {"d":{"$numberDecimal":"NaN"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-007.phpt0000644000175100001660000000171014760300420020035 0ustar --TEST-- Decimal128: Special - Canonical Positive Infinity --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007800 {"d":{"$numberDecimal":"Infinity"}} 180000001364000000000000000000000000000000007800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-008.phpt0000644000175100001660000000171214760300420020040 0ustar --TEST-- Decimal128: Special - Canonical Negative Infinity --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000f800 {"d":{"$numberDecimal":"-Infinity"}} 18000000136400000000000000000000000000000000f800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-009.phpt0000644000175100001660000000141114760300420020035 0ustar --TEST-- Decimal128: Special - Invalid representation treated as 0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000106c00 {"d":{"$numberDecimal":"0"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-010.phpt0000644000175100001660000000141414760300420020030 0ustar --TEST-- Decimal128: Special - Invalid representation treated as -0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400dcba9876543210deadbeef00000010ec00 {"d":{"$numberDecimal":"-0"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-011.phpt0000644000175100001660000000142114760300420020027 0ustar --TEST-- Decimal128: Special - Invalid representation treated as 0E3 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffffffffffffffffffffffff116c00 {"d":{"$numberDecimal":"0E+3"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-012.phpt0000644000175100001660000000200614760300420020030 0ustar --TEST-- Decimal128: Regular - Adjusted Exponent Limit --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3cf22f00 {"d":{"$numberDecimal":"0.000001234567890123456789012345678901234"}} 18000000136400f2af967ed05c82de3297ff6fde3cf22f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-013.phpt0000644000175100001660000000166514760300420020043 0ustar --TEST-- Decimal128: Regular - Smallest --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400d204000000000000000000000000343000 {"d":{"$numberDecimal":"0.001234"}} 18000000136400d204000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-014.phpt0000644000175100001660000000172314760300420020037 0ustar --TEST-- Decimal128: Regular - Smallest with Trailing Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640040ef5a07000000000000000000002a3000 {"d":{"$numberDecimal":"0.00123400000"}} 1800000013640040ef5a07000000000000000000002a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-015.phpt0000644000175100001660000000164614760300420020044 0ustar --TEST-- Decimal128: Regular - 0.1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640001000000000000000000000000003e3000 {"d":{"$numberDecimal":"0.1"}} 1800000013640001000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-016.phpt0000644000175100001660000000201114760300420020030 0ustar --TEST-- Decimal128: Regular - 0.1234567890123456789012345678901234 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3cfc2f00 {"d":{"$numberDecimal":"0.1234567890123456789012345678901234"}} 18000000136400f2af967ed05c82de3297ff6fde3cfc2f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-017.phpt0000644000175100001660000000164014760300420020040 0ustar --TEST-- Decimal128: Regular - 0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-018.phpt0000644000175100001660000000164314760300420020044 0ustar --TEST-- Decimal128: Regular - -0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000040b000 {"d":{"$numberDecimal":"-0"}} 18000000136400000000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-019.phpt0000644000175100001660000000165114760300420020044 0ustar --TEST-- Decimal128: Regular - -0.0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003eb000 {"d":{"$numberDecimal":"-0.0"}} 1800000013640000000000000000000000000000003eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-020.phpt0000644000175100001660000000164014760300420020032 0ustar --TEST-- Decimal128: Regular - 2 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000200000000000000000000000000403000 {"d":{"$numberDecimal":"2"}} 180000001364000200000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-021.phpt0000644000175100001660000000165414760300420020040 0ustar --TEST-- Decimal128: Regular - 2.000 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400d0070000000000000000000000003a3000 {"d":{"$numberDecimal":"2.000"}} 18000000136400d0070000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-022.phpt0000644000175100001660000000175014760300420020036 0ustar --TEST-- Decimal128: Regular - Largest --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3c403000 {"d":{"$numberDecimal":"1234567890123456789012345678901234"}} 18000000136400f2af967ed05c82de3297ff6fde3c403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-023.phpt0000644000175100001660000000177114760300420020042 0ustar --TEST-- Decimal128: Scientific - Tiniest --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffff638e8d37c087adbe09ed010000 {"d":{"$numberDecimal":"9.999999999999999999999999999999999E-6143"}} 18000000136400ffffffff638e8d37c087adbe09ed010000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-024.phpt0000644000175100001660000000166214760300420020042 0ustar --TEST-- Decimal128: Scientific - Tiny --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000000000 {"d":{"$numberDecimal":"1E-6176"}} 180000001364000100000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-025.phpt0000644000175100001660000000167514760300420020047 0ustar --TEST-- Decimal128: Scientific - Negative Tiny --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000008000 {"d":{"$numberDecimal":"-1E-6176"}} 180000001364000100000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-026.phpt0000644000175100001660000000200314760300420020032 0ustar --TEST-- Decimal128: Scientific - Adjusted Exponent Limit --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3cf02f00 {"d":{"$numberDecimal":"1.234567890123456789012345678901234E-7"}} 18000000136400f2af967ed05c82de3297ff6fde3cf02f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-027.phpt0000644000175100001660000000167214760300420020046 0ustar --TEST-- Decimal128: Scientific - Fractional --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640064000000000000000000000000002cb000 {"d":{"$numberDecimal":"-1.00E-8"}} 1800000013640064000000000000000000000000002cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-028.phpt0000644000175100001660000000167514760300420020052 0ustar --TEST-- Decimal128: Scientific - 0 with Exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000205f00 {"d":{"$numberDecimal":"0E+6000"}} 180000001364000000000000000000000000000000205f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-029.phpt0000644000175100001660000000170414760300420020044 0ustar --TEST-- Decimal128: Scientific - 0 with Negative Exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000007a2b00 {"d":{"$numberDecimal":"0E-611"}} 1800000013640000000000000000000000000000007a2b00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-030.phpt0000644000175100001660000000170714760300420020037 0ustar --TEST-- Decimal128: Scientific - No Decimal with Signed Exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000463000 {"d":{"$numberDecimal":"1E+3"}} 180000001364000100000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-031.phpt0000644000175100001660000000167514760300420020044 0ustar --TEST-- Decimal128: Scientific - Trailing Zero --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001a04000000000000000000000000423000 {"d":{"$numberDecimal":"1.050E+4"}} 180000001364001a04000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-032.phpt0000644000175100001660000000167214760300420020042 0ustar --TEST-- Decimal128: Scientific - With Decimal --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006900000000000000000000000000423000 {"d":{"$numberDecimal":"1.05E+3"}} 180000001364006900000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-033.phpt0000644000175100001660000000175014760300420020040 0ustar --TEST-- Decimal128: Scientific - Full --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffffffffffffffffffffffff403000 {"d":{"$numberDecimal":"5192296858534827628530496329220095"}} 18000000136400ffffffffffffffffffffffffffff403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-034.phpt0000644000175100001660000000176714760300420020051 0ustar --TEST-- Decimal128: Scientific - Large --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000000000000E+6144"}} 18000000136400000000000a5bc138938d44c64d31fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-035.phpt0000644000175100001660000000177114760300420020045 0ustar --TEST-- Decimal128: Scientific - Largest --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffff638e8d37c087adbe09edff5f00 {"d":{"$numberDecimal":"9.999999999999999999999999999999999E+6144"}} 18000000136400ffffffff638e8d37c087adbe09edff5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-036.phpt0000644000175100001660000000231414760300420020040 0ustar --TEST-- Decimal128: Non-Canonical Parsing - Exponent Normalization --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640064000000000000000000000000002cb000 {"d":{"$numberDecimal":"-1.00E-8"}} 1800000013640064000000000000000000000000002cb000 1800000013640064000000000000000000000000002cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-037.phpt0000644000175100001660000000230314760300420020037 0ustar --TEST-- Decimal128: Non-Canonical Parsing - Unsigned Positive Exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000463000 {"d":{"$numberDecimal":"1E+3"}} 180000001364000100000000000000000000000000463000 180000001364000100000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-038.phpt0000644000175100001660000000230714760300420020044 0ustar --TEST-- Decimal128: Non-Canonical Parsing - Lowercase Exponent Identifier --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000463000 {"d":{"$numberDecimal":"1E+3"}} 180000001364000100000000000000000000000000463000 180000001364000100000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-039.phpt0000644000175100001660000000241714760300420020047 0ustar --TEST-- Decimal128: Non-Canonical Parsing - Long Significand with Exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640079d9e0f9763ada429d0200000000583000 {"d":{"$numberDecimal":"1.2345689012345789012345E+34"}} 1800000013640079d9e0f9763ada429d0200000000583000 1800000013640079d9e0f9763ada429d0200000000583000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-040.phpt0000644000175100001660000000242214760300420020033 0ustar --TEST-- Decimal128: Non-Canonical Parsing - Positive Sign --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3c403000 {"d":{"$numberDecimal":"1234567890123456789012345678901234"}} 18000000136400f2af967ed05c82de3297ff6fde3c403000 18000000136400f2af967ed05c82de3297ff6fde3c403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-041.phpt0000644000175100001660000000424514760300420020041 0ustar --TEST-- Decimal128: Non-Canonical Parsing - Long Decimal String --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000722800 {"d":{"$numberDecimal":"1E-999"}} 180000001364000100000000000000000000000000722800 180000001364000100000000000000000000000000722800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-042.phpt0000644000175100001660000000225214760300420020036 0ustar --TEST-- Decimal128: Non-Canonical Parsing - nan --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007c00 {"d":{"$numberDecimal":"NaN"}} 180000001364000000000000000000000000000000007c00 180000001364000000000000000000000000000000007c00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-043.phpt0000644000175100001660000000225214760300420020037 0ustar --TEST-- Decimal128: Non-Canonical Parsing - nAn --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007c00 {"d":{"$numberDecimal":"NaN"}} 180000001364000000000000000000000000000000007c00 180000001364000000000000000000000000000000007c00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-044.phpt0000644000175100001660000000230014760300420020032 0ustar --TEST-- Decimal128: Non-Canonical Parsing - +infinity --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007800 {"d":{"$numberDecimal":"Infinity"}} 180000001364000000000000000000000000000000007800 180000001364000000000000000000000000000000007800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-045.phpt0000644000175100001660000000227614760300420020047 0ustar --TEST-- Decimal128: Non-Canonical Parsing - infinity --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007800 {"d":{"$numberDecimal":"Infinity"}} 180000001364000000000000000000000000000000007800 180000001364000000000000000000000000000000007800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-046.phpt0000644000175100001660000000227614760300420020050 0ustar --TEST-- Decimal128: Non-Canonical Parsing - infiniTY --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007800 {"d":{"$numberDecimal":"Infinity"}} 180000001364000000000000000000000000000000007800 180000001364000000000000000000000000000000007800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-047.phpt0000644000175100001660000000226414760300420020046 0ustar --TEST-- Decimal128: Non-Canonical Parsing - inf --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007800 {"d":{"$numberDecimal":"Infinity"}} 180000001364000000000000000000000000000000007800 180000001364000000000000000000000000000000007800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-048.phpt0000644000175100001660000000226414760300420020047 0ustar --TEST-- Decimal128: Non-Canonical Parsing - inF --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007800 {"d":{"$numberDecimal":"Infinity"}} 180000001364000000000000000000000000000000007800 180000001364000000000000000000000000000000007800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-049.phpt0000644000175100001660000000230214760300420020041 0ustar --TEST-- Decimal128: Non-Canonical Parsing - -infinity --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000f800 {"d":{"$numberDecimal":"-Infinity"}} 18000000136400000000000000000000000000000000f800 18000000136400000000000000000000000000000000f800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-050.phpt0000644000175100001660000000230214760300420020031 0ustar --TEST-- Decimal128: Non-Canonical Parsing - -infiniTy --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000f800 {"d":{"$numberDecimal":"-Infinity"}} 18000000136400000000000000000000000000000000f800 18000000136400000000000000000000000000000000f800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-051.phpt0000644000175100001660000000227514760300420020043 0ustar --TEST-- Decimal128: Non-Canonical Parsing - -Inf --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000f800 {"d":{"$numberDecimal":"-Infinity"}} 18000000136400000000000000000000000000000000f800 18000000136400000000000000000000000000000000f800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-052.phpt0000644000175100001660000000227014760300420020037 0ustar --TEST-- Decimal128: Non-Canonical Parsing - -inf --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000f800 {"d":{"$numberDecimal":"-Infinity"}} 18000000136400000000000000000000000000000000f800 18000000136400000000000000000000000000000000f800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-053.phpt0000644000175100001660000000227014760300420020040 0ustar --TEST-- Decimal128: Non-Canonical Parsing - -inF --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000f800 {"d":{"$numberDecimal":"-Infinity"}} 18000000136400000000000000000000000000000000f800 18000000136400000000000000000000000000000000f800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-054.phpt0000644000175100001660000000226414760300420020044 0ustar --TEST-- Decimal128: Rounded Subnormal number --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000000000 {"d":{"$numberDecimal":"1E-6176"}} 180000001364000100000000000000000000000000000000 180000001364000100000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-055.phpt0000644000175100001660000000224514760300420020044 0ustar --TEST-- Decimal128: Clamped --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0E+6112"}} 180000001364000a00000000000000000000000000fe5f00 180000001364000a00000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-056.phpt0000644000175100001660000000431414760300420020044 0ustar --TEST-- Decimal128: Exact rounding --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31cc3700 {"d":{"$numberDecimal":"1.000000000000000000000000000000000E+999"}} 18000000136400000000000a5bc138938d44c64d31cc3700 18000000136400000000000a5bc138938d44c64d31cc3700 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-057.phpt0000644000175100001660000000231514760300420020044 0ustar --TEST-- Decimal128: Clamped zeros with a large positive exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fe5f00 {"d":{"$numberDecimal":"0E+6111"}} 180000001364000000000000000000000000000000fe5f00 180000001364000000000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-058.phpt0000644000175100001660000000231514760300420020045 0ustar --TEST-- Decimal128: Clamped zeros with a large negative exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000000000 {"d":{"$numberDecimal":"0E-6176"}} 180000001364000000000000000000000000000000000000 180000001364000000000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-059.phpt0000644000175100001660000000233114760300420020044 0ustar --TEST-- Decimal128: Clamped negative zeros with a large positive exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fedf00 {"d":{"$numberDecimal":"-0E+6111"}} 180000001364000000000000000000000000000000fedf00 180000001364000000000000000000000000000000fedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-1-valid-060.phpt0000644000175100001660000000233114760300420020034 0ustar --TEST-- Decimal128: Clamped negative zeros with a large negative exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000008000 {"d":{"$numberDecimal":"-0E-6176"}} 180000001364000000000000000000000000000000008000 180000001364000000000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-001.phpt0000644000175100001660000000175414760300420020040 0ustar --TEST-- Decimal128: [decq021] Normality --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3c40b000 {"d":{"$numberDecimal":"-1234567890123456789012345678901234"}} 18000000136400f2af967ed05c82de3297ff6fde3c40b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-002.phpt0000644000175100001660000000174414760300420020040 0ustar --TEST-- Decimal128: [decq823] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400010000800000000000000000000040b000 {"d":{"$numberDecimal":"-2147483649"}} 18000000136400010000800000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-003.phpt0000644000175100001660000000174414760300420020041 0ustar --TEST-- Decimal128: [decq822] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000800000000000000000000040b000 {"d":{"$numberDecimal":"-2147483648"}} 18000000136400000000800000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-004.phpt0000644000175100001660000000174414760300420020042 0ustar --TEST-- Decimal128: [decq821] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffff7f0000000000000000000040b000 {"d":{"$numberDecimal":"-2147483647"}} 18000000136400ffffff7f0000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-005.phpt0000644000175100001660000000174414760300420020043 0ustar --TEST-- Decimal128: [decq820] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400feffff7f0000000000000000000040b000 {"d":{"$numberDecimal":"-2147483646"}} 18000000136400feffff7f0000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-006.phpt0000644000175100001660000000170014760300420020034 0ustar --TEST-- Decimal128: [decq152] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400393000000000000000000000000040b000 {"d":{"$numberDecimal":"-12345"}} 18000000136400393000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-007.phpt0000644000175100001660000000167614760300420020051 0ustar --TEST-- Decimal128: [decq154] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400d20400000000000000000000000040b000 {"d":{"$numberDecimal":"-1234"}} 18000000136400d20400000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-008.phpt0000644000175100001660000000170714760300420020045 0ustar --TEST-- Decimal128: [decq006] derivative canonical plain strings --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee0200000000000000000000000040b000 {"d":{"$numberDecimal":"-750"}} 18000000136400ee0200000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-009.phpt0000644000175100001660000000170214760300420020041 0ustar --TEST-- Decimal128: [decq164] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640039300000000000000000000000003cb000 {"d":{"$numberDecimal":"-123.45"}} 1800000013640039300000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-010.phpt0000644000175100001660000000167414760300420020041 0ustar --TEST-- Decimal128: [decq156] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364007b0000000000000000000000000040b000 {"d":{"$numberDecimal":"-123"}} 180000001364007b0000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-011.phpt0000644000175100001660000000171114760300420020032 0ustar --TEST-- Decimal128: [decq008] derivative canonical plain strings --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee020000000000000000000000003eb000 {"d":{"$numberDecimal":"-75.0"}} 18000000136400ee020000000000000000000000003eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-012.phpt0000644000175100001660000000167214760300420020041 0ustar --TEST-- Decimal128: [decq158] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000c0000000000000000000000000040b000 {"d":{"$numberDecimal":"-12"}} 180000001364000c0000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-013.phpt0000644000175100001660000000200114760300420020025 0ustar --TEST-- Decimal128: [decq122] Nmax and similar --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffff638e8d37c087adbe09edffdf00 {"d":{"$numberDecimal":"-9.999999999999999999999999999999999E+6144"}} 18000000136400ffffffff638e8d37c087adbe09edffdf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-014.phpt0000644000175100001660000000174114760300420020040 0ustar --TEST-- Decimal128: [decq002] (mostly derived from the Strawman 4 document and examples) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee020000000000000000000000003cb000 {"d":{"$numberDecimal":"-7.50"}} 18000000136400ee020000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-015.phpt0000644000175100001660000000171714760300420020044 0ustar --TEST-- Decimal128: [decq004] derivative canonical plain strings --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee0200000000000000000000000042b000 {"d":{"$numberDecimal":"-7.50E+3"}} 18000000136400ee0200000000000000000000000042b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-016.phpt0000644000175100001660000000171714760300420020045 0ustar --TEST-- Decimal128: [decq018] derivative canonical plain strings --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee020000000000000000000000002eb000 {"d":{"$numberDecimal":"-7.50E-7"}} 18000000136400ee020000000000000000000000002eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-017.phpt0000644000175100001660000000200114760300420020031 0ustar --TEST-- Decimal128: [decq125] Nmax and similar --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3cfedf00 {"d":{"$numberDecimal":"-1.234567890123456789012345678901234E+6144"}} 18000000136400f2af967ed05c82de3297ff6fde3cfedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-018.phpt0000644000175100001660000000201014760300420020032 0ustar --TEST-- Decimal128: [decq131] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000807f1bcf85b27059c8a43cfedf00 {"d":{"$numberDecimal":"-1.230000000000000000000000000000000E+6144"}} 18000000136400000000807f1bcf85b27059c8a43cfedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-019.phpt0000644000175100001660000000167614760300420020054 0ustar --TEST-- Decimal128: [decq162] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364007b000000000000000000000000003cb000 {"d":{"$numberDecimal":"-1.23"}} 180000001364007b000000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-020.phpt0000644000175100001660000000177714760300420020046 0ustar --TEST-- Decimal128: [decq176] Nmin and below --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400010000000a5bc138938d44c64d31008000 {"d":{"$numberDecimal":"-1.000000000000000000000000000000001E-6143"}} 18000000136400010000000a5bc138938d44c64d31008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-021.phpt0000644000175100001660000000177714760300420020047 0ustar --TEST-- Decimal128: [decq174] Nmin and below --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31008000 {"d":{"$numberDecimal":"-1.000000000000000000000000000000000E-6143"}} 18000000136400000000000a5bc138938d44c64d31008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-022.phpt0000644000175100001660000000201014760300420020025 0ustar --TEST-- Decimal128: [decq133] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31fedf00 {"d":{"$numberDecimal":"-1.000000000000000000000000000000000E+6144"}} 18000000136400000000000a5bc138938d44c64d31fedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-023.phpt0000644000175100001660000000167014760300420020041 0ustar --TEST-- Decimal128: [decq160] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400010000000000000000000000000040b000 {"d":{"$numberDecimal":"-1"}} 18000000136400010000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-024.phpt0000644000175100001660000000167314760300420020045 0ustar --TEST-- Decimal128: [decq172] Nmin and below --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000428000 {"d":{"$numberDecimal":"-1E-6143"}} 180000001364000100000000000000000000000000428000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-025.phpt0000644000175100001660000000171314760300420020041 0ustar --TEST-- Decimal128: [decq010] derivative canonical plain strings --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee020000000000000000000000003ab000 {"d":{"$numberDecimal":"-0.750"}} 18000000136400ee020000000000000000000000003ab000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-026.phpt0000644000175100001660000000171514760300420020044 0ustar --TEST-- Decimal128: [decq012] derivative canonical plain strings --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee0200000000000000000000000038b000 {"d":{"$numberDecimal":"-0.0750"}} 18000000136400ee0200000000000000000000000038b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-027.phpt0000644000175100001660000000172114760300420020042 0ustar --TEST-- Decimal128: [decq014] derivative canonical plain strings --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee0200000000000000000000000034b000 {"d":{"$numberDecimal":"-0.000750"}} 18000000136400ee0200000000000000000000000034b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-028.phpt0000644000175100001660000000172514760300420020047 0ustar --TEST-- Decimal128: [decq016] derivative canonical plain strings --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ee0200000000000000000000000030b000 {"d":{"$numberDecimal":"-0.00000750"}} 18000000136400ee0200000000000000000000000030b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-029.phpt0000644000175100001660000000166014760300420020046 0ustar --TEST-- Decimal128: [decq404] zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000000000 {"d":{"$numberDecimal":"0E-6176"}} 180000001364000000000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-030.phpt0000644000175100001660000000167314760300420020042 0ustar --TEST-- Decimal128: [decq424] negative zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000008000 {"d":{"$numberDecimal":"-0E-6176"}} 180000001364000000000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-031.phpt0000644000175100001660000000165214760300420020040 0ustar --TEST-- Decimal128: [decq407] zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003c3000 {"d":{"$numberDecimal":"0.00"}} 1800000013640000000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-032.phpt0000644000175100001660000000166514760300420020045 0ustar --TEST-- Decimal128: [decq427] negative zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003cb000 {"d":{"$numberDecimal":"-0.00"}} 1800000013640000000000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-033.phpt0000644000175100001660000000164414760300420020043 0ustar --TEST-- Decimal128: [decq409] zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-034.phpt0000644000175100001660000000165714760300420020050 0ustar --TEST-- Decimal128: [decq428] negative zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000040b000 {"d":{"$numberDecimal":"-0"}} 18000000136400000000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-035.phpt0000644000175100001660000000166114760300420020044 0ustar --TEST-- Decimal128: [decq700] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-036.phpt0000644000175100001660000000165214760300420020045 0ustar --TEST-- Decimal128: [decq406] zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003c3000 {"d":{"$numberDecimal":"0.00"}} 1800000013640000000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-037.phpt0000644000175100001660000000166514760300420020052 0ustar --TEST-- Decimal128: [decq426] negative zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003cb000 {"d":{"$numberDecimal":"-0.00"}} 1800000013640000000000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-038.phpt0000644000175100001660000000165214760300420020047 0ustar --TEST-- Decimal128: [decq410] zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000463000 {"d":{"$numberDecimal":"0E+3"}} 180000001364000000000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-039.phpt0000644000175100001660000000166514760300420020054 0ustar --TEST-- Decimal128: [decq431] negative zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000046b000 {"d":{"$numberDecimal":"-0E+3"}} 18000000136400000000000000000000000000000046b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-040.phpt0000644000175100001660000000167314760300420020043 0ustar --TEST-- Decimal128: [decq419] clamped zeros... --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fe5f00 {"d":{"$numberDecimal":"0E+6111"}} 180000001364000000000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-041.phpt0000644000175100001660000000167314760300420020044 0ustar --TEST-- Decimal128: [decq432] negative zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fedf00 {"d":{"$numberDecimal":"-0E+6111"}} 180000001364000000000000000000000000000000fedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-042.phpt0000644000175100001660000000166014760300420020041 0ustar --TEST-- Decimal128: [decq405] zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000000000 {"d":{"$numberDecimal":"0E-6176"}} 180000001364000000000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-043.phpt0000644000175100001660000000167314760300420020046 0ustar --TEST-- Decimal128: [decq425] negative zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000008000 {"d":{"$numberDecimal":"-0E-6176"}} 180000001364000000000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-044.phpt0000644000175100001660000000166514760300420020050 0ustar --TEST-- Decimal128: [decq508] Specials --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007800 {"d":{"$numberDecimal":"Infinity"}} 180000001364000000000000000000000000000000007800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-045.phpt0000644000175100001660000000166714760300420020053 0ustar --TEST-- Decimal128: [decq528] Specials --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000000f800 {"d":{"$numberDecimal":"-Infinity"}} 18000000136400000000000000000000000000000000f800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-046.phpt0000644000175100001660000000165314760300420020047 0ustar --TEST-- Decimal128: [decq541] Specials --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000007c00 {"d":{"$numberDecimal":"NaN"}} 180000001364000000000000000000000000000000007c00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-047.phpt0000644000175100001660000000177514760300420020055 0ustar --TEST-- Decimal128: [decq074] Nmin and below --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31000000 {"d":{"$numberDecimal":"1.000000000000000000000000000000000E-6143"}} 18000000136400000000000a5bc138938d44c64d31000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-048.phpt0000644000175100001660000000200614760300420020042 0ustar --TEST-- Decimal128: [decq602] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000000000000E+6144"}} 18000000136400000000000a5bc138938d44c64d31fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-049.phpt0000644000175100001660000000200414760300420020041 0ustar --TEST-- Decimal128: [decq604] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000081efac855b416d2dee04fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000000000000000E+6143"}} 180000001364000000000081efac855b416d2dee04fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-050.phpt0000644000175100001660000000200214760300420020027 0ustar --TEST-- Decimal128: [decq606] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000080264b91c02220be377e00fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000000000000000E+6142"}} 1800000013640000000080264b91c02220be377e00fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-051.phpt0000644000175100001660000000200014760300420020026 0ustar --TEST-- Decimal128: [decq608] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000040eaed7446d09c2c9f0c00fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000000000E+6141"}} 1800000013640000000040eaed7446d09c2c9f0c00fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-052.phpt0000644000175100001660000000177614760300420020052 0ustar --TEST-- Decimal128: [decq610] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000a0ca17726dae0f1e430100fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000000000000E+6140"}} 18000000136400000000a0ca17726dae0f1e430100fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-053.phpt0000644000175100001660000000177414760300420020051 0ustar --TEST-- Decimal128: [decq612] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000106102253e5ece4f200000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000000000000E+6139"}} 18000000136400000000106102253e5ece4f200000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-054.phpt0000644000175100001660000000177214760300420020050 0ustar --TEST-- Decimal128: [decq614] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000e83c80d09f3c2e3b030000fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000000E+6138"}} 18000000136400000000e83c80d09f3c2e3b030000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-055.phpt0000644000175100001660000000177014760300420020047 0ustar --TEST-- Decimal128: [decq616] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000e4d20cc8dcd2b752000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000000000E+6137"}} 18000000136400000000e4d20cc8dcd2b752000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-056.phpt0000644000175100001660000000176614760300420020055 0ustar --TEST-- Decimal128: [decq618] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000004a48011416954508000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000000000E+6136"}} 180000001364000000004a48011416954508000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-057.phpt0000644000175100001660000000176414760300420020054 0ustar --TEST-- Decimal128: [decq620] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000a1edccce1bc2d300000000fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000E+6135"}} 18000000136400000000a1edccce1bc2d300000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-058.phpt0000644000175100001660000000176214760300420020053 0ustar --TEST-- Decimal128: [decq622] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000080f64ae1c7022d1500000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000000E+6134"}} 18000000136400000080f64ae1c7022d1500000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-059.phpt0000644000175100001660000000176014760300420020052 0ustar --TEST-- Decimal128: [decq624] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000040b2bac9e0191e0200000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000000E+6133"}} 18000000136400000040b2bac9e0191e0200000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-060.phpt0000644000175100001660000000175614760300420020047 0ustar --TEST-- Decimal128: [decq626] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000a0dec5adc935360000000000fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000E+6132"}} 180000001364000000a0dec5adc935360000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-061.phpt0000644000175100001660000000175414760300420020046 0ustar --TEST-- Decimal128: [decq628] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000010632d5ec76b050000000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000E+6131"}} 18000000136400000010632d5ec76b050000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-062.phpt0000644000175100001660000000175214760300420020045 0ustar --TEST-- Decimal128: [decq630] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000e8890423c78a000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000E+6130"}} 180000001364000000e8890423c78a000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-063.phpt0000644000175100001660000000175014760300420020044 0ustar --TEST-- Decimal128: [decq632] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000064a7b3b6e00d000000000000fe5f00 {"d":{"$numberDecimal":"1.000000000000000000E+6129"}} 18000000136400000064a7b3b6e00d000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-064.phpt0000644000175100001660000000174614760300420020052 0ustar --TEST-- Decimal128: [decq634] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000008a5d78456301000000000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000000E+6128"}} 1800000013640000008a5d78456301000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-065.phpt0000644000175100001660000000174414760300420020051 0ustar --TEST-- Decimal128: [decq636] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000c16ff2862300000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000E+6127"}} 180000001364000000c16ff2862300000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-066.phpt0000644000175100001660000000174214760300420020050 0ustar --TEST-- Decimal128: [decq638] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000080c6a47e8d0300000000000000fe5f00 {"d":{"$numberDecimal":"1.000000000000000E+6126"}} 180000001364000080c6a47e8d0300000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-067.phpt0000644000175100001660000000174014760300420020047 0ustar --TEST-- Decimal128: [decq640] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000407a10f35a0000000000000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000E+6125"}} 1800000013640000407a10f35a0000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-068.phpt0000644000175100001660000000173614760300420020055 0ustar --TEST-- Decimal128: [decq642] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000a0724e18090000000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000E+6124"}} 1800000013640000a0724e18090000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-069.phpt0000644000175100001660000000173414760300420020054 0ustar --TEST-- Decimal128: [decq644] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000010a5d4e8000000000000000000fe5f00 {"d":{"$numberDecimal":"1.000000000000E+6123"}} 180000001364000010a5d4e8000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-070.phpt0000644000175100001660000000173214760300420020042 0ustar --TEST-- Decimal128: [decq646] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000e8764817000000000000000000fe5f00 {"d":{"$numberDecimal":"1.00000000000E+6122"}} 1800000013640000e8764817000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-071.phpt0000644000175100001660000000173014760300420020041 0ustar --TEST-- Decimal128: [decq648] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000e40b5402000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000000E+6121"}} 1800000013640000e40b5402000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-072.phpt0000644000175100001660000000172614760300420020047 0ustar --TEST-- Decimal128: [decq650] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000ca9a3b00000000000000000000fe5f00 {"d":{"$numberDecimal":"1.000000000E+6120"}} 1800000013640000ca9a3b00000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-073.phpt0000644000175100001660000000172414760300420020046 0ustar --TEST-- Decimal128: [decq652] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000e1f50500000000000000000000fe5f00 {"d":{"$numberDecimal":"1.00000000E+6119"}} 1800000013640000e1f50500000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-074.phpt0000644000175100001660000000172214760300420020045 0ustar --TEST-- Decimal128: [decq654] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364008096980000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000E+6118"}} 180000001364008096980000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-075.phpt0000644000175100001660000000172014760300420020044 0ustar --TEST-- Decimal128: [decq656] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640040420f0000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.000000E+6117"}} 1800000013640040420f0000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-076.phpt0000644000175100001660000000171614760300420020052 0ustar --TEST-- Decimal128: [decq658] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400a086010000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.00000E+6116"}} 18000000136400a086010000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-077.phpt0000644000175100001660000000171414760300420020051 0ustar --TEST-- Decimal128: [decq660] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001027000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0000E+6115"}} 180000001364001027000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-078.phpt0000644000175100001660000000171214760300420020050 0ustar --TEST-- Decimal128: [decq662] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400e803000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.000E+6114"}} 18000000136400e803000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-079.phpt0000644000175100001660000000171014760300420020047 0ustar --TEST-- Decimal128: [decq664] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006400000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.00E+6113"}} 180000001364006400000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-080.phpt0000644000175100001660000000170614760300420020044 0ustar --TEST-- Decimal128: [decq666] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0E+6112"}} 180000001364000a00000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-081.phpt0000644000175100001660000000166614760300420020052 0ustar --TEST-- Decimal128: [decq060] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000403000 {"d":{"$numberDecimal":"1"}} 180000001364000100000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-082.phpt0000644000175100001660000000170214760300420020042 0ustar --TEST-- Decimal128: [decq670] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000fc5f00 {"d":{"$numberDecimal":"1E+6110"}} 180000001364000100000000000000000000000000fc5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-083.phpt0000644000175100001660000000170214760300420020043 0ustar --TEST-- Decimal128: [decq668] fold-down full sequence --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1E+6111"}} 180000001364000100000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-084.phpt0000644000175100001660000000167114760300420020051 0ustar --TEST-- Decimal128: [decq072] Nmin and below --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000420000 {"d":{"$numberDecimal":"1E-6143"}} 180000001364000100000000000000000000000000420000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-085.phpt0000644000175100001660000000177514760300420020057 0ustar --TEST-- Decimal128: [decq076] Nmin and below --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400010000000a5bc138938d44c64d31000000 {"d":{"$numberDecimal":"1.000000000000000000000000000000001E-6143"}} 18000000136400010000000a5bc138938d44c64d31000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-086.phpt0000644000175100001660000000200614760300420020044 0ustar --TEST-- Decimal128: [decq036] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000807f1bcf85b27059c8a43cfe5f00 {"d":{"$numberDecimal":"1.230000000000000000000000000000000E+6144"}} 18000000136400000000807f1bcf85b27059c8a43cfe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-087.phpt0000644000175100001660000000167414760300420020057 0ustar --TEST-- Decimal128: [decq062] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364007b000000000000000000000000003c3000 {"d":{"$numberDecimal":"1.23"}} 180000001364007b000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-088.phpt0000644000175100001660000000177714760300420020064 0ustar --TEST-- Decimal128: [decq034] Nmax and similar --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3cfe5f00 {"d":{"$numberDecimal":"1.234567890123456789012345678901234E+6144"}} 18000000136400f2af967ed05c82de3297ff6fde3cfe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-089.phpt0000644000175100001660000000165714760300420020062 0ustar --TEST-- Decimal128: [decq441] exponent lengths --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000403000 {"d":{"$numberDecimal":"7"}} 180000001364000700000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-090.phpt0000644000175100001660000000167314760300420020050 0ustar --TEST-- Decimal128: [decq449] exponent lengths --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000001e5f00 {"d":{"$numberDecimal":"7E+5999"}} 1800000013640007000000000000000000000000001e5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-091.phpt0000644000175100001660000000167114760300420020047 0ustar --TEST-- Decimal128: [decq447] exponent lengths --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000000e3800 {"d":{"$numberDecimal":"7E+999"}} 1800000013640007000000000000000000000000000e3800 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-092.phpt0000644000175100001660000000166714760300420020055 0ustar --TEST-- Decimal128: [decq445] exponent lengths --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000063100 {"d":{"$numberDecimal":"7E+99"}} 180000001364000700000000000000000000000000063100 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-093.phpt0000644000175100001660000000166514760300420020054 0ustar --TEST-- Decimal128: [decq443] exponent lengths --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000523000 {"d":{"$numberDecimal":"7E+9"}} 180000001364000700000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-094.phpt0000644000175100001660000000177214760300420020054 0ustar --TEST-- Decimal128: [decq842] VG testcase --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000fed83f4e7c9fe4e269e38a5bcd1700 {"d":{"$numberDecimal":"7.049000000000010795488000000000000E-3097"}} 180000001364000000fed83f4e7c9fe4e269e38a5bcd1700 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-095.phpt0000644000175100001660000000173414760300420020053 0ustar --TEST-- Decimal128: [decq841] VG testcase --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000203b9db5056f000000000000002400 {"d":{"$numberDecimal":"8.000000000000000000E-1550"}} 180000001364000000203b9db5056f000000000000002400 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-096.phpt0000644000175100001660000000174014760300420020051 0ustar --TEST-- Decimal128: [decq840] VG testcase --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003c17258419d710c42f0000000000002400 {"d":{"$numberDecimal":"8.81125000000001349436E-1548"}} 180000001364003c17258419d710c42f0000000000002400 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-097.phpt0000644000175100001660000000166114760300420020054 0ustar --TEST-- Decimal128: [decq701] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000900000000000000000000000000403000 {"d":{"$numberDecimal":"9"}} 180000001364000900000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-098.phpt0000644000175100001660000000177714760300420020065 0ustar --TEST-- Decimal128: [decq032] Nmax and similar --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffff638e8d37c087adbe09edff5f00 {"d":{"$numberDecimal":"9.999999999999999999999999999999999E+6144"}} 18000000136400ffffffff638e8d37c087adbe09edff5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-099.phpt0000644000175100001660000000166314760300420020060 0ustar --TEST-- Decimal128: [decq702] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000403000 {"d":{"$numberDecimal":"10"}} 180000001364000a00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-100.phpt0000644000175100001660000000167014760300420020035 0ustar --TEST-- Decimal128: [decq057] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000c00000000000000000000000000403000 {"d":{"$numberDecimal":"12"}} 180000001364000c00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-101.phpt0000644000175100001660000000166314760300420020040 0ustar --TEST-- Decimal128: [decq703] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001300000000000000000000000000403000 {"d":{"$numberDecimal":"19"}} 180000001364001300000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-102.phpt0000644000175100001660000000166314760300420020041 0ustar --TEST-- Decimal128: [decq704] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001400000000000000000000000000403000 {"d":{"$numberDecimal":"20"}} 180000001364001400000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-103.phpt0000644000175100001660000000166314760300420020042 0ustar --TEST-- Decimal128: [decq705] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001d00000000000000000000000000403000 {"d":{"$numberDecimal":"29"}} 180000001364001d00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-104.phpt0000644000175100001660000000166314760300420020043 0ustar --TEST-- Decimal128: [decq706] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001e00000000000000000000000000403000 {"d":{"$numberDecimal":"30"}} 180000001364001e00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-105.phpt0000644000175100001660000000166314760300420020044 0ustar --TEST-- Decimal128: [decq707] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364002700000000000000000000000000403000 {"d":{"$numberDecimal":"39"}} 180000001364002700000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-106.phpt0000644000175100001660000000166314760300420020045 0ustar --TEST-- Decimal128: [decq708] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364002800000000000000000000000000403000 {"d":{"$numberDecimal":"40"}} 180000001364002800000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-107.phpt0000644000175100001660000000166314760300420020046 0ustar --TEST-- Decimal128: [decq709] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003100000000000000000000000000403000 {"d":{"$numberDecimal":"49"}} 180000001364003100000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-108.phpt0000644000175100001660000000166314760300420020047 0ustar --TEST-- Decimal128: [decq710] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003200000000000000000000000000403000 {"d":{"$numberDecimal":"50"}} 180000001364003200000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-109.phpt0000644000175100001660000000166314760300420020050 0ustar --TEST-- Decimal128: [decq711] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003b00000000000000000000000000403000 {"d":{"$numberDecimal":"59"}} 180000001364003b00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-110.phpt0000644000175100001660000000166314760300420020040 0ustar --TEST-- Decimal128: [decq712] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003c00000000000000000000000000403000 {"d":{"$numberDecimal":"60"}} 180000001364003c00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-111.phpt0000644000175100001660000000166314760300420020041 0ustar --TEST-- Decimal128: [decq713] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004500000000000000000000000000403000 {"d":{"$numberDecimal":"69"}} 180000001364004500000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-112.phpt0000644000175100001660000000166314760300420020042 0ustar --TEST-- Decimal128: [decq714] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004600000000000000000000000000403000 {"d":{"$numberDecimal":"70"}} 180000001364004600000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-113.phpt0000644000175100001660000000166314760300420020043 0ustar --TEST-- Decimal128: [decq715] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004700000000000000000000000000403000 {"d":{"$numberDecimal":"71"}} 180000001364004700000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-114.phpt0000644000175100001660000000166314760300420020044 0ustar --TEST-- Decimal128: [decq716] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004800000000000000000000000000403000 {"d":{"$numberDecimal":"72"}} 180000001364004800000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-115.phpt0000644000175100001660000000166314760300420020045 0ustar --TEST-- Decimal128: [decq717] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004900000000000000000000000000403000 {"d":{"$numberDecimal":"73"}} 180000001364004900000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-116.phpt0000644000175100001660000000166314760300420020046 0ustar --TEST-- Decimal128: [decq718] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004a00000000000000000000000000403000 {"d":{"$numberDecimal":"74"}} 180000001364004a00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-117.phpt0000644000175100001660000000166314760300420020047 0ustar --TEST-- Decimal128: [decq719] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004b00000000000000000000000000403000 {"d":{"$numberDecimal":"75"}} 180000001364004b00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-118.phpt0000644000175100001660000000166314760300420020050 0ustar --TEST-- Decimal128: [decq720] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004c00000000000000000000000000403000 {"d":{"$numberDecimal":"76"}} 180000001364004c00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-119.phpt0000644000175100001660000000166314760300420020051 0ustar --TEST-- Decimal128: [decq721] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004d00000000000000000000000000403000 {"d":{"$numberDecimal":"77"}} 180000001364004d00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-120.phpt0000644000175100001660000000166314760300420020041 0ustar --TEST-- Decimal128: [decq722] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004e00000000000000000000000000403000 {"d":{"$numberDecimal":"78"}} 180000001364004e00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-121.phpt0000644000175100001660000000166314760300420020042 0ustar --TEST-- Decimal128: [decq723] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004f00000000000000000000000000403000 {"d":{"$numberDecimal":"79"}} 180000001364004f00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-122.phpt0000644000175100001660000000167214760300420020043 0ustar --TEST-- Decimal128: [decq056] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364007b00000000000000000000000000403000 {"d":{"$numberDecimal":"123"}} 180000001364007b00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-123.phpt0000644000175100001660000000170014760300420020034 0ustar --TEST-- Decimal128: [decq064] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640039300000000000000000000000003c3000 {"d":{"$numberDecimal":"123.45"}} 1800000013640039300000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-124.phpt0000644000175100001660000000166514760300420020047 0ustar --TEST-- Decimal128: [decq732] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000802000000000000000000000000403000 {"d":{"$numberDecimal":"520"}} 180000001364000802000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-125.phpt0000644000175100001660000000166514760300420020050 0ustar --TEST-- Decimal128: [decq733] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000902000000000000000000000000403000 {"d":{"$numberDecimal":"521"}} 180000001364000902000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-126.phpt0000644000175100001660000000171114760300420020041 0ustar --TEST-- Decimal128: [decq740] DPD: one of each of the huffman groups --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000903000000000000000000000000403000 {"d":{"$numberDecimal":"777"}} 180000001364000903000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-127.phpt0000644000175100001660000000171114760300420020042 0ustar --TEST-- Decimal128: [decq741] DPD: one of each of the huffman groups --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a03000000000000000000000000403000 {"d":{"$numberDecimal":"778"}} 180000001364000a03000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-128.phpt0000644000175100001660000000171114760300420020043 0ustar --TEST-- Decimal128: [decq742] DPD: one of each of the huffman groups --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001303000000000000000000000000403000 {"d":{"$numberDecimal":"787"}} 180000001364001303000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-129.phpt0000644000175100001660000000171114760300420020044 0ustar --TEST-- Decimal128: [decq746] DPD: one of each of the huffman groups --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001f03000000000000000000000000403000 {"d":{"$numberDecimal":"799"}} 180000001364001f03000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-130.phpt0000644000175100001660000000171114760300420020034 0ustar --TEST-- Decimal128: [decq743] DPD: one of each of the huffman groups --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006d03000000000000000000000000403000 {"d":{"$numberDecimal":"877"}} 180000001364006d03000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-131.phpt0000644000175100001660000000173014760300420020036 0ustar --TEST-- Decimal128: [decq753] DPD all-highs cases (includes the 24 redundant codes) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364007803000000000000000000000000403000 {"d":{"$numberDecimal":"888"}} 180000001364007803000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-132.phpt0000644000175100001660000000173014760300420020037 0ustar --TEST-- Decimal128: [decq754] DPD all-highs cases (includes the 24 redundant codes) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364007903000000000000000000000000403000 {"d":{"$numberDecimal":"889"}} 180000001364007903000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-133.phpt0000644000175100001660000000173014760300420020040 0ustar --TEST-- Decimal128: [decq760] DPD all-highs cases (includes the 24 redundant codes) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364008203000000000000000000000000403000 {"d":{"$numberDecimal":"898"}} 180000001364008203000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-134.phpt0000644000175100001660000000173014760300420020041 0ustar --TEST-- Decimal128: [decq764] DPD all-highs cases (includes the 24 redundant codes) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364008303000000000000000000000000403000 {"d":{"$numberDecimal":"899"}} 180000001364008303000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-135.phpt0000644000175100001660000000171114760300420020041 0ustar --TEST-- Decimal128: [decq745] DPD: one of each of the huffman groups --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400d303000000000000000000000000403000 {"d":{"$numberDecimal":"979"}} 18000000136400d303000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-136.phpt0000644000175100001660000000173014760300420020043 0ustar --TEST-- Decimal128: [decq770] DPD all-highs cases (includes the 24 redundant codes) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400dc03000000000000000000000000403000 {"d":{"$numberDecimal":"988"}} 18000000136400dc03000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-137.phpt0000644000175100001660000000173014760300420020044 0ustar --TEST-- Decimal128: [decq774] DPD all-highs cases (includes the 24 redundant codes) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400dd03000000000000000000000000403000 {"d":{"$numberDecimal":"989"}} 18000000136400dd03000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-138.phpt0000644000175100001660000000166514760300420020054 0ustar --TEST-- Decimal128: [decq730] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400e203000000000000000000000000403000 {"d":{"$numberDecimal":"994"}} 18000000136400e203000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-139.phpt0000644000175100001660000000166514760300420020055 0ustar --TEST-- Decimal128: [decq731] Selected DPD codes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400e303000000000000000000000000403000 {"d":{"$numberDecimal":"995"}} 18000000136400e303000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-140.phpt0000644000175100001660000000171114760300420020035 0ustar --TEST-- Decimal128: [decq744] DPD: one of each of the huffman groups --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400e503000000000000000000000000403000 {"d":{"$numberDecimal":"997"}} 18000000136400e503000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-141.phpt0000644000175100001660000000173014760300420020037 0ustar --TEST-- Decimal128: [decq780] DPD all-highs cases (includes the 24 redundant codes) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400e603000000000000000000000000403000 {"d":{"$numberDecimal":"998"}} 18000000136400e603000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-142.phpt0000644000175100001660000000173014760300420020040 0ustar --TEST-- Decimal128: [decq787] DPD all-highs cases (includes the 24 redundant codes) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400e703000000000000000000000000403000 {"d":{"$numberDecimal":"999"}} 18000000136400e703000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-143.phpt0000644000175100001660000000167414760300420020050 0ustar --TEST-- Decimal128: [decq053] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400d204000000000000000000000000403000 {"d":{"$numberDecimal":"1234"}} 18000000136400d204000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-144.phpt0000644000175100001660000000167614760300420020053 0ustar --TEST-- Decimal128: [decq052] fold-downs (more below) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003930000000000000000000000000403000 {"d":{"$numberDecimal":"12345"}} 180000001364003930000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-145.phpt0000644000175100001660000000171514760300420020046 0ustar --TEST-- Decimal128: [decq792] Miscellaneous (testers' queries, etc.) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003075000000000000000000000000403000 {"d":{"$numberDecimal":"30000"}} 180000001364003075000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-146.phpt0000644000175100001660000000171714760300420020051 0ustar --TEST-- Decimal128: [decq793] Miscellaneous (testers' queries, etc.) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640090940d0000000000000000000000403000 {"d":{"$numberDecimal":"890000"}} 1800000013640090940d0000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-147.phpt0000644000175100001660000000174214760300420020050 0ustar --TEST-- Decimal128: [decq824] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400feffff7f00000000000000000000403000 {"d":{"$numberDecimal":"2147483646"}} 18000000136400feffff7f00000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-148.phpt0000644000175100001660000000174214760300420020051 0ustar --TEST-- Decimal128: [decq825] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffff7f00000000000000000000403000 {"d":{"$numberDecimal":"2147483647"}} 18000000136400ffffff7f00000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-149.phpt0000644000175100001660000000174214760300420020052 0ustar --TEST-- Decimal128: [decq826] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000008000000000000000000000403000 {"d":{"$numberDecimal":"2147483648"}} 180000001364000000008000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-150.phpt0000644000175100001660000000174214760300420020042 0ustar --TEST-- Decimal128: [decq827] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100008000000000000000000000403000 {"d":{"$numberDecimal":"2147483649"}} 180000001364000100008000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-151.phpt0000644000175100001660000000174214760300420020043 0ustar --TEST-- Decimal128: [decq828] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400feffffff00000000000000000000403000 {"d":{"$numberDecimal":"4294967294"}} 18000000136400feffffff00000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-152.phpt0000644000175100001660000000174214760300420020044 0ustar --TEST-- Decimal128: [decq829] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffff00000000000000000000403000 {"d":{"$numberDecimal":"4294967295"}} 18000000136400ffffffff00000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-153.phpt0000644000175100001660000000174214760300420020045 0ustar --TEST-- Decimal128: [decq830] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000001000000000000000000403000 {"d":{"$numberDecimal":"4294967296"}} 180000001364000000000001000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-154.phpt0000644000175100001660000000174214760300420020046 0ustar --TEST-- Decimal128: [decq831] values around [u]int32 edges (zeros done earlier) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000001000000000000000000403000 {"d":{"$numberDecimal":"4294967297"}} 180000001364000100000001000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-155.phpt0000644000175100001660000000175214760300420020050 0ustar --TEST-- Decimal128: [decq022] Normality --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400c7711cc7b548f377dc80a131c836403000 {"d":{"$numberDecimal":"1111111111111111111111111111111111"}} 18000000136400c7711cc7b548f377dc80a131c836403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-156.phpt0000644000175100001660000000175214760300420020051 0ustar --TEST-- Decimal128: [decq020] Normality --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f2af967ed05c82de3297ff6fde3c403000 {"d":{"$numberDecimal":"1234567890123456789012345678901234"}} 18000000136400f2af967ed05c82de3297ff6fde3c403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-2-valid-157.phpt0000644000175100001660000000175114760300420020051 0ustar --TEST-- Decimal128: [decq550] Specials --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffff638e8d37c087adbe09ed413000 {"d":{"$numberDecimal":"9999999999999999999999999999999999"}} 18000000136400ffffffff638e8d37c087adbe09ed413000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-001.phpt0000644000175100001660000000234314760300420020034 0ustar --TEST-- Decimal128: [basx066] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400185c0ace0000000000000000000038b000 {"d":{"$numberDecimal":"-345678.5432"}} 18000000136400185c0ace0000000000000000000038b000 18000000136400185c0ace0000000000000000000038b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-002.phpt0000644000175100001660000000234214760300420020034 0ustar --TEST-- Decimal128: [basx065] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400185c0ace0000000000000000000038b000 {"d":{"$numberDecimal":"-345678.5432"}} 18000000136400185c0ace0000000000000000000038b000 18000000136400185c0ace0000000000000000000038b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-003.phpt0000644000175100001660000000174214760300420020040 0ustar --TEST-- Decimal128: [basx064] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400185c0ace0000000000000000000038b000 {"d":{"$numberDecimal":"-345678.5432"}} 18000000136400185c0ace0000000000000000000038b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-004.phpt0000644000175100001660000000172014760300420020035 0ustar --TEST-- Decimal128: [basx041] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364004c0000000000000000000000000040b000 {"d":{"$numberDecimal":"-76"}} 180000001364004c0000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-005.phpt0000644000175100001660000000174314760300420020043 0ustar --TEST-- Decimal128: [basx027] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000f270000000000000000000000003ab000 {"d":{"$numberDecimal":"-9.999"}} 180000001364000f270000000000000000000000003ab000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-006.phpt0000644000175100001660000000174314760300420020044 0ustar --TEST-- Decimal128: [basx026] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364009f230000000000000000000000003ab000 {"d":{"$numberDecimal":"-9.119"}} 180000001364009f230000000000000000000000003ab000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-007.phpt0000644000175100001660000000174114760300420020043 0ustar --TEST-- Decimal128: [basx025] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364008f030000000000000000000000003cb000 {"d":{"$numberDecimal":"-9.11"}} 180000001364008f030000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-008.phpt0000644000175100001660000000173714760300420020051 0ustar --TEST-- Decimal128: [basx024] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364005b000000000000000000000000003eb000 {"d":{"$numberDecimal":"-9.1"}} 180000001364005b000000000000000000000000003eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-009.phpt0000644000175100001660000000242114760300420020041 0ustar --TEST-- Decimal128: [dqbsr531] negatives (Rounded) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640099761cc7b548f377dc80a131c836feaf00 {"d":{"$numberDecimal":"-1.111111111111111111111111111112345"}} 1800000013640099761cc7b548f377dc80a131c836feaf00 1800000013640099761cc7b548f377dc80a131c836feaf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-010.phpt0000644000175100001660000000173714760300420020042 0ustar --TEST-- Decimal128: [basx022] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000003eb000 {"d":{"$numberDecimal":"-1.0"}} 180000001364000a000000000000000000000000003eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-011.phpt0000644000175100001660000000173314760300420020037 0ustar --TEST-- Decimal128: [basx021] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400010000000000000000000000000040b000 {"d":{"$numberDecimal":"-1"}} 18000000136400010000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-012.phpt0000644000175100001660000000225014760300420020033 0ustar --TEST-- Decimal128: [basx601] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000002e3000 {"d":{"$numberDecimal":"0E-9"}} 1800000013640000000000000000000000000000002e3000 1800000013640000000000000000000000000000002e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-013.phpt0000644000175100001660000000225314760300420020037 0ustar --TEST-- Decimal128: [basx622] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000002eb000 {"d":{"$numberDecimal":"-0E-9"}} 1800000013640000000000000000000000000000002eb000 1800000013640000000000000000000000000000002eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-014.phpt0000644000175100001660000000224714760300420020043 0ustar --TEST-- Decimal128: [basx602] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000303000 {"d":{"$numberDecimal":"0E-8"}} 180000001364000000000000000000000000000000303000 180000001364000000000000000000000000000000303000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-015.phpt0000644000175100001660000000225214760300420020040 0ustar --TEST-- Decimal128: [basx621] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000030b000 {"d":{"$numberDecimal":"-0E-8"}} 18000000136400000000000000000000000000000030b000 18000000136400000000000000000000000000000030b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-016.phpt0000644000175100001660000000224614760300420020044 0ustar --TEST-- Decimal128: [basx603] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000323000 {"d":{"$numberDecimal":"0E-7"}} 180000001364000000000000000000000000000000323000 180000001364000000000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-017.phpt0000644000175100001660000000225114760300420020041 0ustar --TEST-- Decimal128: [basx620] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000032b000 {"d":{"$numberDecimal":"-0E-7"}} 18000000136400000000000000000000000000000032b000 18000000136400000000000000000000000000000032b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-018.phpt0000644000175100001660000000166214760300420020047 0ustar --TEST-- Decimal128: [basx604] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000343000 {"d":{"$numberDecimal":"0.000000"}} 180000001364000000000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-019.phpt0000644000175100001660000000166414760300420020052 0ustar --TEST-- Decimal128: [basx619] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000034b000 {"d":{"$numberDecimal":"-0.000000"}} 18000000136400000000000000000000000000000034b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-020.phpt0000644000175100001660000000166014760300420020036 0ustar --TEST-- Decimal128: [basx605] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000363000 {"d":{"$numberDecimal":"0.00000"}} 180000001364000000000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-021.phpt0000644000175100001660000000166214760300420020041 0ustar --TEST-- Decimal128: [basx618] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000036b000 {"d":{"$numberDecimal":"-0.00000"}} 18000000136400000000000000000000000000000036b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-022.phpt0000644000175100001660000000223614760300420020040 0ustar --TEST-- Decimal128: [basx680] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-023.phpt0000644000175100001660000000165614760300420020046 0ustar --TEST-- Decimal128: [basx606] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000383000 {"d":{"$numberDecimal":"0.0000"}} 180000001364000000000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-024.phpt0000644000175100001660000000166014760300420020042 0ustar --TEST-- Decimal128: [basx617] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000038b000 {"d":{"$numberDecimal":"-0.0000"}} 18000000136400000000000000000000000000000038b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-025.phpt0000644000175100001660000000223514760300420020042 0ustar --TEST-- Decimal128: [basx681] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-026.phpt0000644000175100001660000000223614760300420020044 0ustar --TEST-- Decimal128: [basx686] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-027.phpt0000644000175100001660000000224014760300420020040 0ustar --TEST-- Decimal128: [basx687] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000040b000 {"d":{"$numberDecimal":"-0"}} 18000000136400000000000000000000000000000040b000 18000000136400000000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-028.phpt0000644000175100001660000000233214760300420020043 0ustar --TEST-- Decimal128: [basx019] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003cb000 {"d":{"$numberDecimal":"-0.00"}} 1800000013640000000000000000000000000000003cb000 1800000013640000000000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-029.phpt0000644000175100001660000000165414760300420020052 0ustar --TEST-- Decimal128: [basx607] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.000"}} 1800000013640000000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-030.phpt0000644000175100001660000000165614760300420020044 0ustar --TEST-- Decimal128: [basx616] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003ab000 {"d":{"$numberDecimal":"-0.000"}} 1800000013640000000000000000000000000000003ab000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-031.phpt0000644000175100001660000000223414760300420020036 0ustar --TEST-- Decimal128: [basx682] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-032.phpt0000644000175100001660000000226014760300420020036 0ustar --TEST-- Decimal128: [basx155] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.000"}} 1800000013640000000000000000000000000000003a3000 1800000013640000000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-033.phpt0000644000175100001660000000226214760300420020041 0ustar --TEST-- Decimal128: [basx130] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000383000 {"d":{"$numberDecimal":"0.0000"}} 180000001364000000000000000000000000000000383000 180000001364000000000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-034.phpt0000644000175100001660000000233014760300420020036 0ustar --TEST-- Decimal128: [basx290] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000038b000 {"d":{"$numberDecimal":"-0.0000"}} 18000000136400000000000000000000000000000038b000 18000000136400000000000000000000000000000038b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-035.phpt0000644000175100001660000000226414760300420020045 0ustar --TEST-- Decimal128: [basx131] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000363000 {"d":{"$numberDecimal":"0.00000"}} 180000001364000000000000000000000000000000363000 180000001364000000000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-036.phpt0000644000175100001660000000233214760300420020042 0ustar --TEST-- Decimal128: [basx291] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000036b000 {"d":{"$numberDecimal":"-0.00000"}} 18000000136400000000000000000000000000000036b000 18000000136400000000000000000000000000000036b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-037.phpt0000644000175100001660000000226614760300420020051 0ustar --TEST-- Decimal128: [basx132] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000343000 {"d":{"$numberDecimal":"0.000000"}} 180000001364000000000000000000000000000000343000 180000001364000000000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-038.phpt0000644000175100001660000000233414760300420020046 0ustar --TEST-- Decimal128: [basx292] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000034b000 {"d":{"$numberDecimal":"-0.000000"}} 18000000136400000000000000000000000000000034b000 18000000136400000000000000000000000000000034b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-039.phpt0000644000175100001660000000225614760300420020052 0ustar --TEST-- Decimal128: [basx133] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000323000 {"d":{"$numberDecimal":"0E-7"}} 180000001364000000000000000000000000000000323000 180000001364000000000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-040.phpt0000644000175100001660000000232414760300420020036 0ustar --TEST-- Decimal128: [basx293] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000032b000 {"d":{"$numberDecimal":"-0E-7"}} 18000000136400000000000000000000000000000032b000 18000000136400000000000000000000000000000032b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-041.phpt0000644000175100001660000000165214760300420020042 0ustar --TEST-- Decimal128: [basx608] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003c3000 {"d":{"$numberDecimal":"0.00"}} 1800000013640000000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-042.phpt0000644000175100001660000000165414760300420020045 0ustar --TEST-- Decimal128: [basx615] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003cb000 {"d":{"$numberDecimal":"-0.00"}} 1800000013640000000000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-043.phpt0000644000175100001660000000223314760300420020040 0ustar --TEST-- Decimal128: [basx683] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-044.phpt0000644000175100001660000000224414760300420020043 0ustar --TEST-- Decimal128: [basx630] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003c3000 {"d":{"$numberDecimal":"0.00"}} 1800000013640000000000000000000000000000003c3000 1800000013640000000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-045.phpt0000644000175100001660000000224414760300420020044 0ustar --TEST-- Decimal128: [basx670] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003c3000 {"d":{"$numberDecimal":"0.00"}} 1800000013640000000000000000000000000000003c3000 1800000013640000000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-046.phpt0000644000175100001660000000224214760300420020043 0ustar --TEST-- Decimal128: [basx631] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003e3000 {"d":{"$numberDecimal":"0.0"}} 1800000013640000000000000000000000000000003e3000 1800000013640000000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-047.phpt0000644000175100001660000000224614760300420020050 0ustar --TEST-- Decimal128: [basx671] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.000"}} 1800000013640000000000000000000000000000003a3000 1800000013640000000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-048.phpt0000644000175100001660000000226114760300420020046 0ustar --TEST-- Decimal128: [basx134] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000383000 {"d":{"$numberDecimal":"0.0000"}} 180000001364000000000000000000000000000000383000 180000001364000000000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-049.phpt0000644000175100001660000000232714760300420020052 0ustar --TEST-- Decimal128: [basx294] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000038b000 {"d":{"$numberDecimal":"-0.0000"}} 18000000136400000000000000000000000000000038b000 18000000136400000000000000000000000000000038b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-050.phpt0000644000175100001660000000223614760300420020041 0ustar --TEST-- Decimal128: [basx632] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-051.phpt0000644000175100001660000000225014760300420020036 0ustar --TEST-- Decimal128: [basx672] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000383000 {"d":{"$numberDecimal":"0.0000"}} 180000001364000000000000000000000000000000383000 180000001364000000000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-052.phpt0000644000175100001660000000226314760300420020043 0ustar --TEST-- Decimal128: [basx135] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000363000 {"d":{"$numberDecimal":"0.00000"}} 180000001364000000000000000000000000000000363000 180000001364000000000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-053.phpt0000644000175100001660000000233114760300420020040 0ustar --TEST-- Decimal128: [basx295] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000036b000 {"d":{"$numberDecimal":"-0.00000"}} 18000000136400000000000000000000000000000036b000 18000000136400000000000000000000000000000036b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-054.phpt0000644000175100001660000000224414760300420020044 0ustar --TEST-- Decimal128: [basx633] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000423000 {"d":{"$numberDecimal":"0E+1"}} 180000001364000000000000000000000000000000423000 180000001364000000000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-055.phpt0000644000175100001660000000225214760300420020044 0ustar --TEST-- Decimal128: [basx673] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000363000 {"d":{"$numberDecimal":"0.00000"}} 180000001364000000000000000000000000000000363000 180000001364000000000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-056.phpt0000644000175100001660000000226514760300420020051 0ustar --TEST-- Decimal128: [basx136] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000343000 {"d":{"$numberDecimal":"0.000000"}} 180000001364000000000000000000000000000000343000 180000001364000000000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-057.phpt0000644000175100001660000000225414760300420020050 0ustar --TEST-- Decimal128: [basx674] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000343000 {"d":{"$numberDecimal":"0.000000"}} 180000001364000000000000000000000000000000343000 180000001364000000000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-058.phpt0000644000175100001660000000224414760300420020050 0ustar --TEST-- Decimal128: [basx634] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000443000 {"d":{"$numberDecimal":"0E+2"}} 180000001364000000000000000000000000000000443000 180000001364000000000000000000000000000000443000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-059.phpt0000644000175100001660000000225514760300420020053 0ustar --TEST-- Decimal128: [basx137] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000323000 {"d":{"$numberDecimal":"0E-7"}} 180000001364000000000000000000000000000000323000 180000001364000000000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-060.phpt0000644000175100001660000000224414760300420020041 0ustar --TEST-- Decimal128: [basx635] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000463000 {"d":{"$numberDecimal":"0E+3"}} 180000001364000000000000000000000000000000463000 180000001364000000000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-061.phpt0000644000175100001660000000224414760300420020042 0ustar --TEST-- Decimal128: [basx675] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000323000 {"d":{"$numberDecimal":"0E-7"}} 180000001364000000000000000000000000000000323000 180000001364000000000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-062.phpt0000644000175100001660000000224414760300420020043 0ustar --TEST-- Decimal128: [basx636] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000483000 {"d":{"$numberDecimal":"0E+4"}} 180000001364000000000000000000000000000000483000 180000001364000000000000000000000000000000483000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-063.phpt0000644000175100001660000000224414760300420020044 0ustar --TEST-- Decimal128: [basx676] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000303000 {"d":{"$numberDecimal":"0E-8"}} 180000001364000000000000000000000000000000303000 180000001364000000000000000000000000000000303000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-064.phpt0000644000175100001660000000224414760300420020045 0ustar --TEST-- Decimal128: [basx637] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004a3000 {"d":{"$numberDecimal":"0E+5"}} 1800000013640000000000000000000000000000004a3000 1800000013640000000000000000000000000000004a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-065.phpt0000644000175100001660000000224414760300420020046 0ustar --TEST-- Decimal128: [basx677] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000002e3000 {"d":{"$numberDecimal":"0E-9"}} 1800000013640000000000000000000000000000002e3000 1800000013640000000000000000000000000000002e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-066.phpt0000644000175100001660000000224414760300420020047 0ustar --TEST-- Decimal128: [basx638] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004c3000 {"d":{"$numberDecimal":"0E+6"}} 1800000013640000000000000000000000000000004c3000 1800000013640000000000000000000000000000004c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-067.phpt0000644000175100001660000000224614760300420020052 0ustar --TEST-- Decimal128: [basx678] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000002c3000 {"d":{"$numberDecimal":"0E-10"}} 1800000013640000000000000000000000000000002c3000 1800000013640000000000000000000000000000002c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-068.phpt0000644000175100001660000000225414760300420020052 0ustar --TEST-- Decimal128: [basx149] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000523000 {"d":{"$numberDecimal":"0E+9"}} 180000001364000000000000000000000000000000523000 180000001364000000000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-069.phpt0000644000175100001660000000224414760300420020052 0ustar --TEST-- Decimal128: [basx639] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004e3000 {"d":{"$numberDecimal":"0E+7"}} 1800000013640000000000000000000000000000004e3000 1800000013640000000000000000000000000000004e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-070.phpt0000644000175100001660000000224614760300420020044 0ustar --TEST-- Decimal128: [basx679] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000002a3000 {"d":{"$numberDecimal":"0E-11"}} 1800000013640000000000000000000000000000002a3000 1800000013640000000000000000000000000000002a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-071.phpt0000644000175100001660000000234114760300420020041 0ustar --TEST-- Decimal128: [basx063] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400185c0ace00000000000000000000383000 {"d":{"$numberDecimal":"345678.5432"}} 18000000136400185c0ace00000000000000000000383000 18000000136400185c0ace00000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-072.phpt0000644000175100001660000000173714760300420020052 0ustar --TEST-- Decimal128: [basx018] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003eb000 {"d":{"$numberDecimal":"-0.0"}} 1800000013640000000000000000000000000000003eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-073.phpt0000644000175100001660000000165014760300420020045 0ustar --TEST-- Decimal128: [basx609] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003e3000 {"d":{"$numberDecimal":"0.0"}} 1800000013640000000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-074.phpt0000644000175100001660000000165214760300420020050 0ustar --TEST-- Decimal128: [basx614] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003eb000 {"d":{"$numberDecimal":"-0.0"}} 1800000013640000000000000000000000000000003eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-075.phpt0000644000175100001660000000223214760300420020044 0ustar --TEST-- Decimal128: [basx684] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-076.phpt0000644000175100001660000000224114760300420020045 0ustar --TEST-- Decimal128: [basx640] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003e3000 {"d":{"$numberDecimal":"0.0"}} 1800000013640000000000000000000000000000003e3000 1800000013640000000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-077.phpt0000644000175100001660000000224114760300420020046 0ustar --TEST-- Decimal128: [basx660] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003e3000 {"d":{"$numberDecimal":"0.0"}} 1800000013640000000000000000000000000000003e3000 1800000013640000000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-078.phpt0000644000175100001660000000223514760300420020052 0ustar --TEST-- Decimal128: [basx641] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-079.phpt0000644000175100001660000000224314760300420020052 0ustar --TEST-- Decimal128: [basx661] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003c3000 {"d":{"$numberDecimal":"0.00"}} 1800000013640000000000000000000000000000003c3000 1800000013640000000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-080.phpt0000644000175100001660000000232414760300420020042 0ustar --TEST-- Decimal128: [basx296] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003ab000 {"d":{"$numberDecimal":"-0.000"}} 1800000013640000000000000000000000000000003ab000 1800000013640000000000000000000000000000003ab000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-081.phpt0000644000175100001660000000224314760300420020043 0ustar --TEST-- Decimal128: [basx642] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000423000 {"d":{"$numberDecimal":"0E+1"}} 180000001364000000000000000000000000000000423000 180000001364000000000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-082.phpt0000644000175100001660000000224514760300420020046 0ustar --TEST-- Decimal128: [basx662] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.000"}} 1800000013640000000000000000000000000000003a3000 1800000013640000000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-083.phpt0000644000175100001660000000232614760300420020047 0ustar --TEST-- Decimal128: [basx297] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000038b000 {"d":{"$numberDecimal":"-0.0000"}} 18000000136400000000000000000000000000000038b000 18000000136400000000000000000000000000000038b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-084.phpt0000644000175100001660000000224314760300420020046 0ustar --TEST-- Decimal128: [basx643] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000443000 {"d":{"$numberDecimal":"0E+2"}} 180000001364000000000000000000000000000000443000 180000001364000000000000000000000000000000443000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-085.phpt0000644000175100001660000000224714760300420020053 0ustar --TEST-- Decimal128: [basx663] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000383000 {"d":{"$numberDecimal":"0.0000"}} 180000001364000000000000000000000000000000383000 180000001364000000000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-086.phpt0000644000175100001660000000224314760300420020050 0ustar --TEST-- Decimal128: [basx644] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000463000 {"d":{"$numberDecimal":"0E+3"}} 180000001364000000000000000000000000000000463000 180000001364000000000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-087.phpt0000644000175100001660000000225114760300420020050 0ustar --TEST-- Decimal128: [basx664] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000363000 {"d":{"$numberDecimal":"0.00000"}} 180000001364000000000000000000000000000000363000 180000001364000000000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-088.phpt0000644000175100001660000000224314760300420020052 0ustar --TEST-- Decimal128: [basx645] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000483000 {"d":{"$numberDecimal":"0E+4"}} 180000001364000000000000000000000000000000483000 180000001364000000000000000000000000000000483000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-089.phpt0000644000175100001660000000225314760300420020054 0ustar --TEST-- Decimal128: [basx665] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000343000 {"d":{"$numberDecimal":"0.000000"}} 180000001364000000000000000000000000000000343000 180000001364000000000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-090.phpt0000644000175100001660000000224314760300420020043 0ustar --TEST-- Decimal128: [basx646] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004a3000 {"d":{"$numberDecimal":"0E+5"}} 1800000013640000000000000000000000000000004a3000 1800000013640000000000000000000000000000004a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-091.phpt0000644000175100001660000000224314760300420020044 0ustar --TEST-- Decimal128: [basx666] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000323000 {"d":{"$numberDecimal":"0E-7"}} 180000001364000000000000000000000000000000323000 180000001364000000000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-092.phpt0000644000175100001660000000224314760300420020045 0ustar --TEST-- Decimal128: [basx647] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004c3000 {"d":{"$numberDecimal":"0E+6"}} 1800000013640000000000000000000000000000004c3000 1800000013640000000000000000000000000000004c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-093.phpt0000644000175100001660000000224314760300420020046 0ustar --TEST-- Decimal128: [basx667] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000303000 {"d":{"$numberDecimal":"0E-8"}} 180000001364000000000000000000000000000000303000 180000001364000000000000000000000000000000303000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-094.phpt0000644000175100001660000000224314760300420020047 0ustar --TEST-- Decimal128: [basx648] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004e3000 {"d":{"$numberDecimal":"0E+7"}} 1800000013640000000000000000000000000000004e3000 1800000013640000000000000000000000000000004e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-095.phpt0000644000175100001660000000224314760300420020050 0ustar --TEST-- Decimal128: [basx668] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000002e3000 {"d":{"$numberDecimal":"0E-9"}} 1800000013640000000000000000000000000000002e3000 1800000013640000000000000000000000000000002e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-096.phpt0000644000175100001660000000225314760300420020052 0ustar --TEST-- Decimal128: [basx160] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000523000 {"d":{"$numberDecimal":"0E+9"}} 180000001364000000000000000000000000000000523000 180000001364000000000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-097.phpt0000644000175100001660000000225314760300420020053 0ustar --TEST-- Decimal128: [basx161] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000002e3000 {"d":{"$numberDecimal":"0E-9"}} 1800000013640000000000000000000000000000002e3000 1800000013640000000000000000000000000000002e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-098.phpt0000644000175100001660000000224314760300420020053 0ustar --TEST-- Decimal128: [basx649] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000503000 {"d":{"$numberDecimal":"0E+8"}} 180000001364000000000000000000000000000000503000 180000001364000000000000000000000000000000503000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-099.phpt0000644000175100001660000000224514760300420020056 0ustar --TEST-- Decimal128: [basx669] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000002c3000 {"d":{"$numberDecimal":"0E-10"}} 1800000013640000000000000000000000000000002c3000 1800000013640000000000000000000000000000002c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-100.phpt0000644000175100001660000000234014760300420020031 0ustar --TEST-- Decimal128: [basx062] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400185c0ace00000000000000000000383000 {"d":{"$numberDecimal":"345678.5432"}} 18000000136400185c0ace00000000000000000000383000 18000000136400185c0ace00000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-101.phpt0000644000175100001660000000173114760300420020035 0ustar --TEST-- Decimal128: [basx001] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-102.phpt0000644000175100001660000000173314760300420020040 0ustar --TEST-- Decimal128: [basx017] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000040b000 {"d":{"$numberDecimal":"-0"}} 18000000136400000000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-103.phpt0000644000175100001660000000223114760300420020033 0ustar --TEST-- Decimal128: [basx611] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-104.phpt0000644000175100001660000000223414760300420020037 0ustar --TEST-- Decimal128: [basx613] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000040b000 {"d":{"$numberDecimal":"-0"}} 18000000136400000000000000000000000000000040b000 18000000136400000000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-105.phpt0000644000175100001660000000223114760300420020035 0ustar --TEST-- Decimal128: [basx685] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-106.phpt0000644000175100001660000000223214760300420020037 0ustar --TEST-- Decimal128: [basx688] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-107.phpt0000644000175100001660000000223414760300420020042 0ustar --TEST-- Decimal128: [basx689] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000040b000 {"d":{"$numberDecimal":"-0"}} 18000000136400000000000000000000000000000040b000 18000000136400000000000000000000000000000040b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-108.phpt0000644000175100001660000000223314760300420020042 0ustar --TEST-- Decimal128: [basx650] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000403000 {"d":{"$numberDecimal":"0"}} 180000001364000000000000000000000000000000403000 180000001364000000000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-109.phpt0000644000175100001660000000165214760300420020047 0ustar --TEST-- Decimal128: [basx651] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000423000 {"d":{"$numberDecimal":"0E+1"}} 180000001364000000000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-110.phpt0000644000175100001660000000232014760300420020030 0ustar --TEST-- Decimal128: [basx298] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003cb000 {"d":{"$numberDecimal":"-0.00"}} 1800000013640000000000000000000000000000003cb000 1800000013640000000000000000000000000000003cb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-111.phpt0000644000175100001660000000165214760300420020040 0ustar --TEST-- Decimal128: [basx652] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000443000 {"d":{"$numberDecimal":"0E+2"}} 180000001364000000000000000000000000000000443000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-112.phpt0000644000175100001660000000232214760300420020034 0ustar --TEST-- Decimal128: [basx299] some more negative zeros [systematic tests below] --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003ab000 {"d":{"$numberDecimal":"-0.000"}} 1800000013640000000000000000000000000000003ab000 1800000013640000000000000000000000000000003ab000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-113.phpt0000644000175100001660000000165214760300420020042 0ustar --TEST-- Decimal128: [basx653] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000463000 {"d":{"$numberDecimal":"0E+3"}} 180000001364000000000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-114.phpt0000644000175100001660000000165214760300420020043 0ustar --TEST-- Decimal128: [basx654] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000483000 {"d":{"$numberDecimal":"0E+4"}} 180000001364000000000000000000000000000000483000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-115.phpt0000644000175100001660000000165214760300420020044 0ustar --TEST-- Decimal128: [basx655] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004a3000 {"d":{"$numberDecimal":"0E+5"}} 1800000013640000000000000000000000000000004a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-116.phpt0000644000175100001660000000165214760300420020045 0ustar --TEST-- Decimal128: [basx656] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004c3000 {"d":{"$numberDecimal":"0E+6"}} 1800000013640000000000000000000000000000004c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-117.phpt0000644000175100001660000000165214760300420020046 0ustar --TEST-- Decimal128: [basx657] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000004e3000 {"d":{"$numberDecimal":"0E+7"}} 1800000013640000000000000000000000000000004e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-118.phpt0000644000175100001660000000165214760300420020047 0ustar --TEST-- Decimal128: [basx658] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000503000 {"d":{"$numberDecimal":"0E+8"}} 180000001364000000000000000000000000000000503000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-119.phpt0000644000175100001660000000225314760300420020046 0ustar --TEST-- Decimal128: [basx138] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000523000 {"d":{"$numberDecimal":"0E+9"}} 180000001364000000000000000000000000000000523000 180000001364000000000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-120.phpt0000644000175100001660000000166514760300420020044 0ustar --TEST-- Decimal128: [basx139] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000000000000000000000052b000 {"d":{"$numberDecimal":"-0E+9"}} 18000000136400000000000000000000000000000052b000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-121.phpt0000644000175100001660000000166314760300420020043 0ustar --TEST-- Decimal128: [basx144] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000523000 {"d":{"$numberDecimal":"0E+9"}} 180000001364000000000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-122.phpt0000644000175100001660000000225114760300420020036 0ustar --TEST-- Decimal128: [basx154] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000523000 {"d":{"$numberDecimal":"0E+9"}} 180000001364000000000000000000000000000000523000 180000001364000000000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-123.phpt0000644000175100001660000000165214760300420020043 0ustar --TEST-- Decimal128: [basx659] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000523000 {"d":{"$numberDecimal":"0E+9"}} 180000001364000000000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-124.phpt0000644000175100001660000000231514760300420020041 0ustar --TEST-- Decimal128: [basx042] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400fc040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.76"}} 18000000136400fc040000000000000000000000003c3000 18000000136400fc040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-125.phpt0000644000175100001660000000225514760300420020045 0ustar --TEST-- Decimal128: [basx143] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000523000 {"d":{"$numberDecimal":"1E+9"}} 180000001364000100000000000000000000000000523000 180000001364000100000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-126.phpt0000644000175100001660000000233714760300420020047 0ustar --TEST-- Decimal128: [basx061] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400185c0ace00000000000000000000383000 {"d":{"$numberDecimal":"345678.5432"}} 18000000136400185c0ace00000000000000000000383000 18000000136400185c0ace00000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-127.phpt0000644000175100001660000000236614760300420020052 0ustar --TEST-- Decimal128: [basx036] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640015cd5b0700000000000000000000203000 {"d":{"$numberDecimal":"1.23456789E-8"}} 1800000013640015cd5b0700000000000000000000203000 1800000013640015cd5b0700000000000000000000203000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-128.phpt0000644000175100001660000000236514760300420020052 0ustar --TEST-- Decimal128: [basx035] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640015cd5b0700000000000000000000223000 {"d":{"$numberDecimal":"1.23456789E-7"}} 1800000013640015cd5b0700000000000000000000223000 1800000013640015cd5b0700000000000000000000223000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-129.phpt0000644000175100001660000000176714760300420020060 0ustar --TEST-- Decimal128: [basx034] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640015cd5b0700000000000000000000243000 {"d":{"$numberDecimal":"0.00000123456789"}} 1800000013640015cd5b0700000000000000000000243000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-130.phpt0000644000175100001660000000173414760300420020042 0ustar --TEST-- Decimal128: [basx053] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003200000000000000000000000000323000 {"d":{"$numberDecimal":"0.0000050"}} 180000001364003200000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-131.phpt0000644000175100001660000000176514760300420020047 0ustar --TEST-- Decimal128: [basx033] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640015cd5b0700000000000000000000263000 {"d":{"$numberDecimal":"0.0000123456789"}} 1800000013640015cd5b0700000000000000000000263000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-132.phpt0000644000175100001660000000174114760300420020042 0ustar --TEST-- Decimal128: [basx016] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000c000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.012"}} 180000001364000c000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-133.phpt0000644000175100001660000000174114760300420020043 0ustar --TEST-- Decimal128: [basx015] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364007b000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.123"}} 180000001364007b000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-134.phpt0000644000175100001660000000177114760300420020047 0ustar --TEST-- Decimal128: [basx037] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640078df0d8648700000000000000000223000 {"d":{"$numberDecimal":"0.123456789012344"}} 1800000013640078df0d8648700000000000000000223000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-135.phpt0000644000175100001660000000177114760300420020050 0ustar --TEST-- Decimal128: [basx038] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640079df0d8648700000000000000000223000 {"d":{"$numberDecimal":"0.123456789012345"}} 1800000013640079df0d8648700000000000000000223000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-136.phpt0000644000175100001660000000166714760300420020055 0ustar --TEST-- Decimal128: [basx250] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000383000 {"d":{"$numberDecimal":"0.1265"}} 18000000136400f104000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-137.phpt0000644000175100001660000000226314760300420020047 0ustar --TEST-- Decimal128: [basx257] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000383000 {"d":{"$numberDecimal":"0.1265"}} 18000000136400f104000000000000000000000000383000 18000000136400f104000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-138.phpt0000644000175100001660000000226514760300420020052 0ustar --TEST-- Decimal128: [basx256] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000363000 {"d":{"$numberDecimal":"0.01265"}} 18000000136400f104000000000000000000000000363000 18000000136400f104000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-139.phpt0000644000175100001660000000226114760300420020047 0ustar --TEST-- Decimal128: [basx258] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003a3000 {"d":{"$numberDecimal":"1.265"}} 18000000136400f1040000000000000000000000003a3000 18000000136400f1040000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-140.phpt0000644000175100001660000000227214760300420020041 0ustar --TEST-- Decimal128: [basx251] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000103000 {"d":{"$numberDecimal":"1.265E-21"}} 18000000136400f104000000000000000000000000103000 18000000136400f104000000000000000000000000103000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-141.phpt0000644000175100001660000000227214760300420020042 0ustar --TEST-- Decimal128: [basx263] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000603000 {"d":{"$numberDecimal":"1.265E+19"}} 18000000136400f104000000000000000000000000603000 18000000136400f104000000000000000000000000603000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-142.phpt0000644000175100001660000000226714760300420020047 0ustar --TEST-- Decimal128: [basx255] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000343000 {"d":{"$numberDecimal":"0.001265"}} 18000000136400f104000000000000000000000000343000 18000000136400f104000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-143.phpt0000644000175100001660000000226114760300420020042 0ustar --TEST-- Decimal128: [basx259] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.65"}} 18000000136400f1040000000000000000000000003c3000 18000000136400f1040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-144.phpt0000644000175100001660000000227114760300420020044 0ustar --TEST-- Decimal128: [basx254] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000323000 {"d":{"$numberDecimal":"0.0001265"}} 18000000136400f104000000000000000000000000323000 18000000136400f104000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-145.phpt0000644000175100001660000000226114760300420020044 0ustar --TEST-- Decimal128: [basx260] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003e3000 {"d":{"$numberDecimal":"126.5"}} 18000000136400f1040000000000000000000000003e3000 18000000136400f1040000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-146.phpt0000644000175100001660000000227314760300420020050 0ustar --TEST-- Decimal128: [basx253] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000303000 {"d":{"$numberDecimal":"0.00001265"}} 18000000136400f104000000000000000000000000303000 18000000136400f104000000000000000000000000303000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-147.phpt0000644000175100001660000000225714760300420020053 0ustar --TEST-- Decimal128: [basx261] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000403000 {"d":{"$numberDecimal":"1265"}} 18000000136400f104000000000000000000000000403000 18000000136400f104000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-148.phpt0000644000175100001660000000226714760300420020055 0ustar --TEST-- Decimal128: [basx252] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000283000 {"d":{"$numberDecimal":"1.265E-9"}} 18000000136400f104000000000000000000000000283000 18000000136400f104000000000000000000000000283000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-149.phpt0000644000175100001660000000226714760300420020056 0ustar --TEST-- Decimal128: [basx262] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000483000 {"d":{"$numberDecimal":"1.265E+7"}} 18000000136400f104000000000000000000000000483000 18000000136400f104000000000000000000000000483000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-150.phpt0000644000175100001660000000226114760300420020040 0ustar --TEST-- Decimal128: [basx159] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640049000000000000000000000000002e3000 {"d":{"$numberDecimal":"7.3E-8"}} 1800000013640049000000000000000000000000002e3000 1800000013640049000000000000000000000000002e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-151.phpt0000644000175100001660000000173714760300420020050 0ustar --TEST-- Decimal128: [basx004] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640064000000000000000000000000003c3000 {"d":{"$numberDecimal":"1.00"}} 1800000013640064000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-152.phpt0000644000175100001660000000173514760300420020047 0ustar --TEST-- Decimal128: [basx003] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000003e3000 {"d":{"$numberDecimal":"1.0"}} 180000001364000a000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-153.phpt0000644000175100001660000000173114760300420020044 0ustar --TEST-- Decimal128: [basx002] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000403000 {"d":{"$numberDecimal":"1"}} 180000001364000100000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-154.phpt0000644000175100001660000000225414760300420020046 0ustar --TEST-- Decimal128: [basx148] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000523000 {"d":{"$numberDecimal":"1E+9"}} 180000001364000100000000000000000000000000523000 180000001364000100000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-155.phpt0000644000175100001660000000225314760300420020046 0ustar --TEST-- Decimal128: [basx153] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000523000 {"d":{"$numberDecimal":"1E+9"}} 180000001364000100000000000000000000000000523000 180000001364000100000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-156.phpt0000644000175100001660000000225314760300420020047 0ustar --TEST-- Decimal128: [basx141] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000523000 {"d":{"$numberDecimal":"1E+9"}} 180000001364000100000000000000000000000000523000 180000001364000100000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-157.phpt0000644000175100001660000000225314760300420020050 0ustar --TEST-- Decimal128: [basx146] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000523000 {"d":{"$numberDecimal":"1E+9"}} 180000001364000100000000000000000000000000523000 180000001364000100000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-158.phpt0000644000175100001660000000225214760300420020050 0ustar --TEST-- Decimal128: [basx151] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000523000 {"d":{"$numberDecimal":"1E+9"}} 180000001364000100000000000000000000000000523000 180000001364000100000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-159.phpt0000644000175100001660000000166514760300420020060 0ustar --TEST-- Decimal128: [basx142] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000f43000 {"d":{"$numberDecimal":"1E+90"}} 180000001364000100000000000000000000000000f43000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-160.phpt0000644000175100001660000000225514760300420020044 0ustar --TEST-- Decimal128: [basx147] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000f43000 {"d":{"$numberDecimal":"1E+90"}} 180000001364000100000000000000000000000000f43000 180000001364000100000000000000000000000000f43000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-161.phpt0000644000175100001660000000225414760300420020044 0ustar --TEST-- Decimal128: [basx152] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000f43000 {"d":{"$numberDecimal":"1E+90"}} 180000001364000100000000000000000000000000f43000 180000001364000100000000000000000000000000f43000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-162.phpt0000644000175100001660000000166314760300420020050 0ustar --TEST-- Decimal128: [basx140] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000523000 {"d":{"$numberDecimal":"1E+9"}} 180000001364000100000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-163.phpt0000644000175100001660000000225114760300420020043 0ustar --TEST-- Decimal128: [basx150] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000523000 {"d":{"$numberDecimal":"1E+9"}} 180000001364000100000000000000000000000000523000 180000001364000100000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-164.phpt0000644000175100001660000000174114760300420020047 0ustar --TEST-- Decimal128: [basx014] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400d2040000000000000000000000003a3000 {"d":{"$numberDecimal":"1.234"}} 18000000136400d2040000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-165.phpt0000644000175100001660000000166514760300420020055 0ustar --TEST-- Decimal128: [basx170] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003a3000 {"d":{"$numberDecimal":"1.265"}} 18000000136400f1040000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-166.phpt0000644000175100001660000000226014760300420020046 0ustar --TEST-- Decimal128: [basx177] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003a3000 {"d":{"$numberDecimal":"1.265"}} 18000000136400f1040000000000000000000000003a3000 18000000136400f1040000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-167.phpt0000644000175100001660000000226214760300420020051 0ustar --TEST-- Decimal128: [basx176] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000383000 {"d":{"$numberDecimal":"0.1265"}} 18000000136400f104000000000000000000000000383000 18000000136400f104000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-168.phpt0000644000175100001660000000226014760300420020050 0ustar --TEST-- Decimal128: [basx178] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.65"}} 18000000136400f1040000000000000000000000003c3000 18000000136400f1040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-169.phpt0000644000175100001660000000167514760300420020062 0ustar --TEST-- Decimal128: [basx171] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000123000 {"d":{"$numberDecimal":"1.265E-20"}} 18000000136400f104000000000000000000000000123000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-170.phpt0000644000175100001660000000167514760300420020052 0ustar --TEST-- Decimal128: [basx183] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000623000 {"d":{"$numberDecimal":"1.265E+20"}} 18000000136400f104000000000000000000000000623000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-171.phpt0000644000175100001660000000226414760300420020046 0ustar --TEST-- Decimal128: [basx175] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000363000 {"d":{"$numberDecimal":"0.01265"}} 18000000136400f104000000000000000000000000363000 18000000136400f104000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-172.phpt0000644000175100001660000000226014760300420020043 0ustar --TEST-- Decimal128: [basx179] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003e3000 {"d":{"$numberDecimal":"126.5"}} 18000000136400f1040000000000000000000000003e3000 18000000136400f1040000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-173.phpt0000644000175100001660000000226614760300420020052 0ustar --TEST-- Decimal128: [basx174] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000343000 {"d":{"$numberDecimal":"0.001265"}} 18000000136400f104000000000000000000000000343000 18000000136400f104000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-174.phpt0000644000175100001660000000225614760300420020052 0ustar --TEST-- Decimal128: [basx180] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000403000 {"d":{"$numberDecimal":"1265"}} 18000000136400f104000000000000000000000000403000 18000000136400f104000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-175.phpt0000644000175100001660000000227014760300420020047 0ustar --TEST-- Decimal128: [basx173] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000323000 {"d":{"$numberDecimal":"0.0001265"}} 18000000136400f104000000000000000000000000323000 18000000136400f104000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-176.phpt0000644000175100001660000000167314760300420020056 0ustar --TEST-- Decimal128: [basx181] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000423000 {"d":{"$numberDecimal":"1.265E+4"}} 18000000136400f104000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-177.phpt0000644000175100001660000000167314760300420020057 0ustar --TEST-- Decimal128: [basx172] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000002a3000 {"d":{"$numberDecimal":"1.265E-8"}} 18000000136400f1040000000000000000000000002a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-178.phpt0000644000175100001660000000167314760300420020060 0ustar --TEST-- Decimal128: [basx182] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000004a3000 {"d":{"$numberDecimal":"1.265E+8"}} 18000000136400f1040000000000000000000000004a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-179.phpt0000644000175100001660000000166314760300420020060 0ustar --TEST-- Decimal128: [basx157] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000400000000000000000000000000523000 {"d":{"$numberDecimal":"4E+9"}} 180000001364000400000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-180.phpt0000644000175100001660000000225414760300420020045 0ustar --TEST-- Decimal128: [basx067] examples --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000500000000000000000000000000343000 {"d":{"$numberDecimal":"0.000005"}} 180000001364000500000000000000000000000000343000 180000001364000500000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-181.phpt0000644000175100001660000000165514760300420020052 0ustar --TEST-- Decimal128: [basx069] examples --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000500000000000000000000000000323000 {"d":{"$numberDecimal":"5E-7"}} 180000001364000500000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-182.phpt0000644000175100001660000000225714760300420020052 0ustar --TEST-- Decimal128: [basx385] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000403000 {"d":{"$numberDecimal":"7"}} 180000001364000700000000000000000000000000403000 180000001364000700000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-183.phpt0000644000175100001660000000227014760300420020046 0ustar --TEST-- Decimal128: [basx365] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000543000 {"d":{"$numberDecimal":"7E+10"}} 180000001364000700000000000000000000000000543000 180000001364000700000000000000000000000000543000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-184.phpt0000644000175100001660000000170114760300420020045 0ustar --TEST-- Decimal128: [basx405] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000002c3000 {"d":{"$numberDecimal":"7E-10"}} 1800000013640007000000000000000000000000002c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-185.phpt0000644000175100001660000000227014760300420020050 0ustar --TEST-- Decimal128: [basx363] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000563000 {"d":{"$numberDecimal":"7E+11"}} 180000001364000700000000000000000000000000563000 180000001364000700000000000000000000000000563000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-186.phpt0000644000175100001660000000170114760300420020047 0ustar --TEST-- Decimal128: [basx407] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000002a3000 {"d":{"$numberDecimal":"7E-11"}} 1800000013640007000000000000000000000000002a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-187.phpt0000644000175100001660000000227014760300420020052 0ustar --TEST-- Decimal128: [basx361] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000583000 {"d":{"$numberDecimal":"7E+12"}} 180000001364000700000000000000000000000000583000 180000001364000700000000000000000000000000583000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-188.phpt0000644000175100001660000000170114760300420020051 0ustar --TEST-- Decimal128: [basx409] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000283000 {"d":{"$numberDecimal":"7E-12"}} 180000001364000700000000000000000000000000283000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-189.phpt0000644000175100001660000000170114760300420020052 0ustar --TEST-- Decimal128: [basx411] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000263000 {"d":{"$numberDecimal":"7E-13"}} 180000001364000700000000000000000000000000263000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-190.phpt0000644000175100001660000000226514760300420020050 0ustar --TEST-- Decimal128: [basx383] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000423000 {"d":{"$numberDecimal":"7E+1"}} 180000001364000700000000000000000000000000423000 180000001364000700000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-191.phpt0000644000175100001660000000226414760300420020050 0ustar --TEST-- Decimal128: [basx387] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000003e3000 {"d":{"$numberDecimal":"0.7"}} 1800000013640007000000000000000000000000003e3000 1800000013640007000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-192.phpt0000644000175100001660000000226514760300420020052 0ustar --TEST-- Decimal128: [basx381] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000443000 {"d":{"$numberDecimal":"7E+2"}} 180000001364000700000000000000000000000000443000 180000001364000700000000000000000000000000443000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-193.phpt0000644000175100001660000000226614760300420020054 0ustar --TEST-- Decimal128: [basx389] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000003c3000 {"d":{"$numberDecimal":"0.07"}} 1800000013640007000000000000000000000000003c3000 1800000013640007000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-194.phpt0000644000175100001660000000226514760300420020054 0ustar --TEST-- Decimal128: [basx379] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000463000 {"d":{"$numberDecimal":"7E+3"}} 180000001364000700000000000000000000000000463000 180000001364000700000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-195.phpt0000644000175100001660000000227014760300420020051 0ustar --TEST-- Decimal128: [basx391] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.007"}} 1800000013640007000000000000000000000000003a3000 1800000013640007000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-196.phpt0000644000175100001660000000226514760300420020056 0ustar --TEST-- Decimal128: [basx377] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000483000 {"d":{"$numberDecimal":"7E+4"}} 180000001364000700000000000000000000000000483000 180000001364000700000000000000000000000000483000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-197.phpt0000644000175100001660000000227214760300420020055 0ustar --TEST-- Decimal128: [basx393] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000383000 {"d":{"$numberDecimal":"0.0007"}} 180000001364000700000000000000000000000000383000 180000001364000700000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-198.phpt0000644000175100001660000000226514760300420020060 0ustar --TEST-- Decimal128: [basx375] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000004a3000 {"d":{"$numberDecimal":"7E+5"}} 1800000013640007000000000000000000000000004a3000 1800000013640007000000000000000000000000004a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-199.phpt0000644000175100001660000000227414760300420020061 0ustar --TEST-- Decimal128: [basx395] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000363000 {"d":{"$numberDecimal":"0.00007"}} 180000001364000700000000000000000000000000363000 180000001364000700000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-200.phpt0000644000175100001660000000226514760300420020040 0ustar --TEST-- Decimal128: [basx373] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000004c3000 {"d":{"$numberDecimal":"7E+6"}} 1800000013640007000000000000000000000000004c3000 1800000013640007000000000000000000000000004c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-201.phpt0000644000175100001660000000227614760300420020043 0ustar --TEST-- Decimal128: [basx397] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000343000 {"d":{"$numberDecimal":"0.000007"}} 180000001364000700000000000000000000000000343000 180000001364000700000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-202.phpt0000644000175100001660000000226514760300420020042 0ustar --TEST-- Decimal128: [basx371] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000004e3000 {"d":{"$numberDecimal":"7E+7"}} 1800000013640007000000000000000000000000004e3000 1800000013640007000000000000000000000000004e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-203.phpt0000644000175100001660000000167714760300420020051 0ustar --TEST-- Decimal128: [basx399] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000323000 {"d":{"$numberDecimal":"7E-7"}} 180000001364000700000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-204.phpt0000644000175100001660000000226514760300420020044 0ustar --TEST-- Decimal128: [basx369] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000503000 {"d":{"$numberDecimal":"7E+8"}} 180000001364000700000000000000000000000000503000 180000001364000700000000000000000000000000503000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-205.phpt0000644000175100001660000000167714760300420020053 0ustar --TEST-- Decimal128: [basx401] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000303000 {"d":{"$numberDecimal":"7E-8"}} 180000001364000700000000000000000000000000303000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-206.phpt0000644000175100001660000000226514760300420020046 0ustar --TEST-- Decimal128: [basx367] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000700000000000000000000000000523000 {"d":{"$numberDecimal":"7E+9"}} 180000001364000700000000000000000000000000523000 180000001364000700000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-207.phpt0000644000175100001660000000167714760300420020055 0ustar --TEST-- Decimal128: [basx403] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640007000000000000000000000000002e3000 {"d":{"$numberDecimal":"7E-9"}} 1800000013640007000000000000000000000000002e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-208.phpt0000644000175100001660000000173714760300420020053 0ustar --TEST-- Decimal128: [basx007] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640064000000000000000000000000003e3000 {"d":{"$numberDecimal":"10.0"}} 1800000013640064000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-209.phpt0000644000175100001660000000173314760300420020050 0ustar --TEST-- Decimal128: [basx005] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000403000 {"d":{"$numberDecimal":"10"}} 180000001364000a00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-210.phpt0000644000175100001660000000226314760300420020037 0ustar --TEST-- Decimal128: [basx165] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000523000 {"d":{"$numberDecimal":"1.0E+10"}} 180000001364000a00000000000000000000000000523000 180000001364000a00000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-211.phpt0000644000175100001660000000226214760300420020037 0ustar --TEST-- Decimal128: [basx163] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000523000 {"d":{"$numberDecimal":"1.0E+10"}} 180000001364000a00000000000000000000000000523000 180000001364000a00000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-212.phpt0000644000175100001660000000226214760300420020040 0ustar --TEST-- Decimal128: [basx325] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000403000 {"d":{"$numberDecimal":"10"}} 180000001364000a00000000000000000000000000403000 180000001364000a00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-213.phpt0000644000175100001660000000227514760300421020046 0ustar --TEST-- Decimal128: [basx305] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000543000 {"d":{"$numberDecimal":"1.0E+11"}} 180000001364000a00000000000000000000000000543000 180000001364000a00000000000000000000000000543000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-214.phpt0000644000175100001660000000227414760300421020046 0ustar --TEST-- Decimal128: [basx345] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000002c3000 {"d":{"$numberDecimal":"1.0E-9"}} 180000001364000a000000000000000000000000002c3000 180000001364000a000000000000000000000000002c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-215.phpt0000644000175100001660000000227514760300421020050 0ustar --TEST-- Decimal128: [basx303] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000563000 {"d":{"$numberDecimal":"1.0E+12"}} 180000001364000a00000000000000000000000000563000 180000001364000a00000000000000000000000000563000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-216.phpt0000644000175100001660000000227614760300421020052 0ustar --TEST-- Decimal128: [basx347] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000002a3000 {"d":{"$numberDecimal":"1.0E-10"}} 180000001364000a000000000000000000000000002a3000 180000001364000a000000000000000000000000002a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-217.phpt0000644000175100001660000000227514760300421020052 0ustar --TEST-- Decimal128: [basx301] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000583000 {"d":{"$numberDecimal":"1.0E+13"}} 180000001364000a00000000000000000000000000583000 180000001364000a00000000000000000000000000583000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-218.phpt0000644000175100001660000000227614760300421020054 0ustar --TEST-- Decimal128: [basx349] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000283000 {"d":{"$numberDecimal":"1.0E-11"}} 180000001364000a00000000000000000000000000283000 180000001364000a00000000000000000000000000283000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-219.phpt0000644000175100001660000000227614760300421020055 0ustar --TEST-- Decimal128: [basx351] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000263000 {"d":{"$numberDecimal":"1.0E-12"}} 180000001364000a00000000000000000000000000263000 180000001364000a00000000000000000000000000263000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-220.phpt0000644000175100001660000000227214760300421020041 0ustar --TEST-- Decimal128: [basx323] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000423000 {"d":{"$numberDecimal":"1.0E+2"}} 180000001364000a00000000000000000000000000423000 180000001364000a00000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-221.phpt0000644000175100001660000000226514760300421020044 0ustar --TEST-- Decimal128: [basx327] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000003e3000 {"d":{"$numberDecimal":"1.0"}} 180000001364000a000000000000000000000000003e3000 180000001364000a000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-222.phpt0000644000175100001660000000227214760300421020043 0ustar --TEST-- Decimal128: [basx321] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000443000 {"d":{"$numberDecimal":"1.0E+3"}} 180000001364000a00000000000000000000000000443000 180000001364000a00000000000000000000000000443000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-223.phpt0000644000175100001660000000226714760300421020050 0ustar --TEST-- Decimal128: [basx329] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000003c3000 {"d":{"$numberDecimal":"0.10"}} 180000001364000a000000000000000000000000003c3000 180000001364000a000000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-224.phpt0000644000175100001660000000227214760300421020045 0ustar --TEST-- Decimal128: [basx319] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000463000 {"d":{"$numberDecimal":"1.0E+4"}} 180000001364000a00000000000000000000000000463000 180000001364000a00000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-225.phpt0000644000175100001660000000227114760300421020045 0ustar --TEST-- Decimal128: [basx331] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.010"}} 180000001364000a000000000000000000000000003a3000 180000001364000a000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-226.phpt0000644000175100001660000000227214760300421020047 0ustar --TEST-- Decimal128: [basx317] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000483000 {"d":{"$numberDecimal":"1.0E+5"}} 180000001364000a00000000000000000000000000483000 180000001364000a00000000000000000000000000483000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-227.phpt0000644000175100001660000000227314760300421020051 0ustar --TEST-- Decimal128: [basx333] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000383000 {"d":{"$numberDecimal":"0.0010"}} 180000001364000a00000000000000000000000000383000 180000001364000a00000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-228.phpt0000644000175100001660000000227214760300421020051 0ustar --TEST-- Decimal128: [basx315] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000004a3000 {"d":{"$numberDecimal":"1.0E+6"}} 180000001364000a000000000000000000000000004a3000 180000001364000a000000000000000000000000004a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-229.phpt0000644000175100001660000000227514760300421020055 0ustar --TEST-- Decimal128: [basx335] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000363000 {"d":{"$numberDecimal":"0.00010"}} 180000001364000a00000000000000000000000000363000 180000001364000a00000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-230.phpt0000644000175100001660000000227214760300421020042 0ustar --TEST-- Decimal128: [basx313] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000004c3000 {"d":{"$numberDecimal":"1.0E+7"}} 180000001364000a000000000000000000000000004c3000 180000001364000a000000000000000000000000004c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-231.phpt0000644000175100001660000000227714760300421020050 0ustar --TEST-- Decimal128: [basx337] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000343000 {"d":{"$numberDecimal":"0.000010"}} 180000001364000a00000000000000000000000000343000 180000001364000a00000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-232.phpt0000644000175100001660000000227214760300421020044 0ustar --TEST-- Decimal128: [basx311] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000004e3000 {"d":{"$numberDecimal":"1.0E+8"}} 180000001364000a000000000000000000000000004e3000 180000001364000a000000000000000000000000004e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-233.phpt0000644000175100001660000000230114760300421020036 0ustar --TEST-- Decimal128: [basx339] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000323000 {"d":{"$numberDecimal":"0.0000010"}} 180000001364000a00000000000000000000000000323000 180000001364000a00000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-234.phpt0000644000175100001660000000227214760300421020046 0ustar --TEST-- Decimal128: [basx309] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000503000 {"d":{"$numberDecimal":"1.0E+9"}} 180000001364000a00000000000000000000000000503000 180000001364000a00000000000000000000000000503000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-235.phpt0000644000175100001660000000227314760300421020050 0ustar --TEST-- Decimal128: [basx341] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000303000 {"d":{"$numberDecimal":"1.0E-7"}} 180000001364000a00000000000000000000000000303000 180000001364000a00000000000000000000000000303000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-236.phpt0000644000175100001660000000226214760300421020047 0ustar --TEST-- Decimal128: [basx164] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000f43000 {"d":{"$numberDecimal":"1.0E+91"}} 180000001364000a00000000000000000000000000f43000 180000001364000a00000000000000000000000000f43000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-237.phpt0000644000175100001660000000226114760300421020047 0ustar --TEST-- Decimal128: [basx162] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000523000 {"d":{"$numberDecimal":"1.0E+10"}} 180000001364000a00000000000000000000000000523000 180000001364000a00000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-238.phpt0000644000175100001660000000227414760300421020054 0ustar --TEST-- Decimal128: [basx307] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000523000 {"d":{"$numberDecimal":"1.0E+10"}} 180000001364000a00000000000000000000000000523000 180000001364000a00000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-239.phpt0000644000175100001660000000227314760300421020054 0ustar --TEST-- Decimal128: [basx343] Engineering notation tests --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a000000000000000000000000002e3000 {"d":{"$numberDecimal":"1.0E-8"}} 180000001364000a000000000000000000000000002e3000 180000001364000a000000000000000000000000002e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-240.phpt0000644000175100001660000000173714760300421020050 0ustar --TEST-- Decimal128: [basx008] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640065000000000000000000000000003e3000 {"d":{"$numberDecimal":"10.1"}} 1800000013640065000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-241.phpt0000644000175100001660000000173714760300421020051 0ustar --TEST-- Decimal128: [basx009] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640068000000000000000000000000003e3000 {"d":{"$numberDecimal":"10.4"}} 1800000013640068000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-242.phpt0000644000175100001660000000173714760300421020052 0ustar --TEST-- Decimal128: [basx010] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640069000000000000000000000000003e3000 {"d":{"$numberDecimal":"10.5"}} 1800000013640069000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-243.phpt0000644000175100001660000000173714760300421020053 0ustar --TEST-- Decimal128: [basx011] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006a000000000000000000000000003e3000 {"d":{"$numberDecimal":"10.6"}} 180000001364006a000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-244.phpt0000644000175100001660000000173714760300421020054 0ustar --TEST-- Decimal128: [basx012] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006d000000000000000000000000003e3000 {"d":{"$numberDecimal":"10.9"}} 180000001364006d000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-245.phpt0000644000175100001660000000173714760300421020055 0ustar --TEST-- Decimal128: [basx013] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006e000000000000000000000000003e3000 {"d":{"$numberDecimal":"11.0"}} 180000001364006e000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-246.phpt0000644000175100001660000000171614760300421020053 0ustar --TEST-- Decimal128: [basx040] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000c00000000000000000000000000403000 {"d":{"$numberDecimal":"12"}} 180000001364000c00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-247.phpt0000644000175100001660000000166514760300421020057 0ustar --TEST-- Decimal128: [basx190] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.65"}} 18000000136400f1040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-248.phpt0000644000175100001660000000226014760300421020050 0ustar --TEST-- Decimal128: [basx197] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.65"}} 18000000136400f1040000000000000000000000003c3000 18000000136400f1040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-249.phpt0000644000175100001660000000226014760300421020051 0ustar --TEST-- Decimal128: [basx196] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003a3000 {"d":{"$numberDecimal":"1.265"}} 18000000136400f1040000000000000000000000003a3000 18000000136400f1040000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-250.phpt0000644000175100001660000000226014760300421020041 0ustar --TEST-- Decimal128: [basx198] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003e3000 {"d":{"$numberDecimal":"126.5"}} 18000000136400f1040000000000000000000000003e3000 18000000136400f1040000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-251.phpt0000644000175100001660000000227114760300421020044 0ustar --TEST-- Decimal128: [basx191] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000143000 {"d":{"$numberDecimal":"1.265E-19"}} 18000000136400f104000000000000000000000000143000 18000000136400f104000000000000000000000000143000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-252.phpt0000644000175100001660000000227114760300421020045 0ustar --TEST-- Decimal128: [basx203] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000643000 {"d":{"$numberDecimal":"1.265E+21"}} 18000000136400f104000000000000000000000000643000 18000000136400f104000000000000000000000000643000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-253.phpt0000644000175100001660000000226214760300421020046 0ustar --TEST-- Decimal128: [basx195] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000383000 {"d":{"$numberDecimal":"0.1265"}} 18000000136400f104000000000000000000000000383000 18000000136400f104000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-254.phpt0000644000175100001660000000225614760300421020052 0ustar --TEST-- Decimal128: [basx199] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000403000 {"d":{"$numberDecimal":"1265"}} 18000000136400f104000000000000000000000000403000 18000000136400f104000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-255.phpt0000644000175100001660000000226414760300421020052 0ustar --TEST-- Decimal128: [basx194] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000363000 {"d":{"$numberDecimal":"0.01265"}} 18000000136400f104000000000000000000000000363000 18000000136400f104000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-256.phpt0000644000175100001660000000226614760300421020055 0ustar --TEST-- Decimal128: [basx200] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000423000 {"d":{"$numberDecimal":"1.265E+4"}} 18000000136400f104000000000000000000000000423000 18000000136400f104000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-257.phpt0000644000175100001660000000226614760300421020056 0ustar --TEST-- Decimal128: [basx193] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000343000 {"d":{"$numberDecimal":"0.001265"}} 18000000136400f104000000000000000000000000343000 18000000136400f104000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-258.phpt0000644000175100001660000000226614760300421020057 0ustar --TEST-- Decimal128: [basx201] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000443000 {"d":{"$numberDecimal":"1.265E+5"}} 18000000136400f104000000000000000000000000443000 18000000136400f104000000000000000000000000443000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-259.phpt0000644000175100001660000000226614760300421020060 0ustar --TEST-- Decimal128: [basx192] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000002c3000 {"d":{"$numberDecimal":"1.265E-7"}} 18000000136400f1040000000000000000000000002c3000 18000000136400f1040000000000000000000000002c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-260.phpt0000644000175100001660000000226614760300421020050 0ustar --TEST-- Decimal128: [basx202] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000004c3000 {"d":{"$numberDecimal":"1.265E+9"}} 18000000136400f1040000000000000000000000004c3000 18000000136400f1040000000000000000000000004c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-261.phpt0000644000175100001660000000231514760300421020044 0ustar --TEST-- Decimal128: [basx044] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400fc040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.76"}} 18000000136400fc040000000000000000000000003c3000 18000000136400fc040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-262.phpt0000644000175100001660000000172414760300421020050 0ustar --TEST-- Decimal128: [basx042] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400fc040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.76"}} 18000000136400fc040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-263.phpt0000644000175100001660000000230414760300421020044 0ustar --TEST-- Decimal128: [basx046] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001100000000000000000000000000403000 {"d":{"$numberDecimal":"17"}} 180000001364001100000000000000000000000000403000 180000001364001100000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-264.phpt0000644000175100001660000000230514760300421020046 0ustar --TEST-- Decimal128: [basx049] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364002c00000000000000000000000000403000 {"d":{"$numberDecimal":"44"}} 180000001364002c00000000000000000000000000403000 180000001364002c00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-265.phpt0000644000175100001660000000230414760300421020046 0ustar --TEST-- Decimal128: [basx048] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364002c00000000000000000000000000403000 {"d":{"$numberDecimal":"44"}} 180000001364002c00000000000000000000000000403000 180000001364002c00000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-266.phpt0000644000175100001660000000226114760300421020051 0ustar --TEST-- Decimal128: [basx158] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364002c00000000000000000000000000523000 {"d":{"$numberDecimal":"4.4E+10"}} 180000001364002c00000000000000000000000000523000 180000001364002c00000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-267.phpt0000644000175100001660000000225714760300421020057 0ustar --TEST-- Decimal128: [basx068] examples --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364003200000000000000000000000000323000 {"d":{"$numberDecimal":"0.0000050"}} 180000001364003200000000000000000000000000323000 180000001364003200000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-268.phpt0000644000175100001660000000226614760300421020060 0ustar --TEST-- Decimal128: [basx169] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006400000000000000000000000000523000 {"d":{"$numberDecimal":"1.00E+11"}} 180000001364006400000000000000000000000000523000 180000001364006400000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-269.phpt0000644000175100001660000000226514760300421020060 0ustar --TEST-- Decimal128: [basx167] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006400000000000000000000000000523000 {"d":{"$numberDecimal":"1.00E+11"}} 180000001364006400000000000000000000000000523000 180000001364006400000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-270.phpt0000644000175100001660000000226514760300421020050 0ustar --TEST-- Decimal128: [basx168] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006400000000000000000000000000f43000 {"d":{"$numberDecimal":"1.00E+92"}} 180000001364006400000000000000000000000000f43000 180000001364006400000000000000000000000000f43000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-271.phpt0000644000175100001660000000226414760300421020050 0ustar --TEST-- Decimal128: [basx166] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006400000000000000000000000000523000 {"d":{"$numberDecimal":"1.00E+11"}} 180000001364006400000000000000000000000000523000 180000001364006400000000000000000000000000523000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-272.phpt0000644000175100001660000000166514760300421020055 0ustar --TEST-- Decimal128: [basx210] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003e3000 {"d":{"$numberDecimal":"126.5"}} 18000000136400f1040000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-273.phpt0000644000175100001660000000226014760300421020046 0ustar --TEST-- Decimal128: [basx217] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003e3000 {"d":{"$numberDecimal":"126.5"}} 18000000136400f1040000000000000000000000003e3000 18000000136400f1040000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-274.phpt0000644000175100001660000000226014760300421020047 0ustar --TEST-- Decimal128: [basx216] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.65"}} 18000000136400f1040000000000000000000000003c3000 18000000136400f1040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-275.phpt0000644000175100001660000000225614760300421020055 0ustar --TEST-- Decimal128: [basx218] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000403000 {"d":{"$numberDecimal":"1265"}} 18000000136400f104000000000000000000000000403000 18000000136400f104000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-276.phpt0000644000175100001660000000227114760300421020053 0ustar --TEST-- Decimal128: [basx211] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000163000 {"d":{"$numberDecimal":"1.265E-18"}} 18000000136400f104000000000000000000000000163000 18000000136400f104000000000000000000000000163000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-277.phpt0000644000175100001660000000227114760300421020054 0ustar --TEST-- Decimal128: [basx223] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000663000 {"d":{"$numberDecimal":"1.265E+22"}} 18000000136400f104000000000000000000000000663000 18000000136400f104000000000000000000000000663000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-278.phpt0000644000175100001660000000226014760300421020053 0ustar --TEST-- Decimal128: [basx215] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003a3000 {"d":{"$numberDecimal":"1.265"}} 18000000136400f1040000000000000000000000003a3000 18000000136400f1040000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-279.phpt0000644000175100001660000000226614760300421020062 0ustar --TEST-- Decimal128: [basx219] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000423000 {"d":{"$numberDecimal":"1.265E+4"}} 18000000136400f104000000000000000000000000423000 18000000136400f104000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-280.phpt0000644000175100001660000000226214760300421020046 0ustar --TEST-- Decimal128: [basx214] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000383000 {"d":{"$numberDecimal":"0.1265"}} 18000000136400f104000000000000000000000000383000 18000000136400f104000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-281.phpt0000644000175100001660000000226614760300421020053 0ustar --TEST-- Decimal128: [basx220] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000443000 {"d":{"$numberDecimal":"1.265E+5"}} 18000000136400f104000000000000000000000000443000 18000000136400f104000000000000000000000000443000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-282.phpt0000644000175100001660000000226414760300421020052 0ustar --TEST-- Decimal128: [basx213] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000363000 {"d":{"$numberDecimal":"0.01265"}} 18000000136400f104000000000000000000000000363000 18000000136400f104000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-283.phpt0000644000175100001660000000226614760300421020055 0ustar --TEST-- Decimal128: [basx221] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000463000 {"d":{"$numberDecimal":"1.265E+6"}} 18000000136400f104000000000000000000000000463000 18000000136400f104000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-284.phpt0000644000175100001660000000227414760300421020055 0ustar --TEST-- Decimal128: [basx212] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000002e3000 {"d":{"$numberDecimal":"0.000001265"}} 18000000136400f1040000000000000000000000002e3000 18000000136400f1040000000000000000000000002e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-285.phpt0000644000175100001660000000227014760300421020052 0ustar --TEST-- Decimal128: [basx222] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000004e3000 {"d":{"$numberDecimal":"1.265E+10"}} 18000000136400f1040000000000000000000000004e3000 18000000136400f1040000000000000000000000004e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-286.phpt0000644000175100001660000000173714760300421020062 0ustar --TEST-- Decimal128: [basx006] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400e803000000000000000000000000403000 {"d":{"$numberDecimal":"1000"}} 18000000136400e803000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-287.phpt0000644000175100001660000000166314760300421020061 0ustar --TEST-- Decimal128: [basx230] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000403000 {"d":{"$numberDecimal":"1265"}} 18000000136400f104000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-288.phpt0000644000175100001660000000225514760300421020060 0ustar --TEST-- Decimal128: [basx237] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000403000 {"d":{"$numberDecimal":"1265"}} 18000000136400f104000000000000000000000000403000 18000000136400f104000000000000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-289.phpt0000644000175100001660000000225714760300421020063 0ustar --TEST-- Decimal128: [basx236] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003e3000 {"d":{"$numberDecimal":"126.5"}} 18000000136400f1040000000000000000000000003e3000 18000000136400f1040000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-290.phpt0000644000175100001660000000226514760300421020052 0ustar --TEST-- Decimal128: [basx238] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000423000 {"d":{"$numberDecimal":"1.265E+4"}} 18000000136400f104000000000000000000000000423000 18000000136400f104000000000000000000000000423000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-291.phpt0000644000175100001660000000227014760300421020047 0ustar --TEST-- Decimal128: [basx231] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000183000 {"d":{"$numberDecimal":"1.265E-17"}} 18000000136400f104000000000000000000000000183000 18000000136400f104000000000000000000000000183000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-292.phpt0000644000175100001660000000227014760300421020050 0ustar --TEST-- Decimal128: [basx243] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000683000 {"d":{"$numberDecimal":"1.265E+23"}} 18000000136400f104000000000000000000000000683000 18000000136400f104000000000000000000000000683000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-293.phpt0000644000175100001660000000225714760300421020056 0ustar --TEST-- Decimal128: [basx235] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.65"}} 18000000136400f1040000000000000000000000003c3000 18000000136400f1040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-294.phpt0000644000175100001660000000226514760300421020056 0ustar --TEST-- Decimal128: [basx239] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000443000 {"d":{"$numberDecimal":"1.265E+5"}} 18000000136400f104000000000000000000000000443000 18000000136400f104000000000000000000000000443000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-295.phpt0000644000175100001660000000225714760300421020060 0ustar --TEST-- Decimal128: [basx234] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f1040000000000000000000000003a3000 {"d":{"$numberDecimal":"1.265"}} 18000000136400f1040000000000000000000000003a3000 18000000136400f1040000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-296.phpt0000644000175100001660000000226514760300421020060 0ustar --TEST-- Decimal128: [basx240] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000463000 {"d":{"$numberDecimal":"1.265E+6"}} 18000000136400f104000000000000000000000000463000 18000000136400f104000000000000000000000000463000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-297.phpt0000644000175100001660000000226114760300421020055 0ustar --TEST-- Decimal128: [basx233] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000383000 {"d":{"$numberDecimal":"0.1265"}} 18000000136400f104000000000000000000000000383000 18000000136400f104000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-298.phpt0000644000175100001660000000226514760300421020062 0ustar --TEST-- Decimal128: [basx241] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000483000 {"d":{"$numberDecimal":"1.265E+7"}} 18000000136400f104000000000000000000000000483000 18000000136400f104000000000000000000000000483000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-299.phpt0000644000175100001660000000227114760300421020060 0ustar --TEST-- Decimal128: [basx232] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000303000 {"d":{"$numberDecimal":"0.00001265"}} 18000000136400f104000000000000000000000000303000 18000000136400f104000000000000000000000000303000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-300.phpt0000644000175100001660000000226714760300421020044 0ustar --TEST-- Decimal128: [basx242] Numbers with E --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f104000000000000000000000000503000 {"d":{"$numberDecimal":"1.265E+11"}} 18000000136400f104000000000000000000000000503000 18000000136400f104000000000000000000000000503000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-301.phpt0000644000175100001660000000174014760300421020040 0ustar --TEST-- Decimal128: [basx060] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400185c0ace00000000000000000000383000 {"d":{"$numberDecimal":"345678.5432"}} 18000000136400185c0ace00000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-302.phpt0000644000175100001660000000234214760300421020040 0ustar --TEST-- Decimal128: [basx059] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400f198670c08000000000000000000363000 {"d":{"$numberDecimal":"345678.54321"}} 18000000136400f198670c08000000000000000000363000 18000000136400f198670c08000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-303.phpt0000644000175100001660000000174414760300421020046 0ustar --TEST-- Decimal128: [basx058] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006af90b7c50000000000000000000343000 {"d":{"$numberDecimal":"345678.543210"}} 180000001364006af90b7c50000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-304.phpt0000644000175100001660000000174614760300421020051 0ustar --TEST-- Decimal128: [basx057] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006a19562522020000000000000000343000 {"d":{"$numberDecimal":"2345678.543210"}} 180000001364006a19562522020000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-305.phpt0000644000175100001660000000175014760300421020045 0ustar --TEST-- Decimal128: [basx056] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006ab9c8733a0b0000000000000000343000 {"d":{"$numberDecimal":"12345678.543210"}} 180000001364006ab9c8733a0b0000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-306.phpt0000644000175100001660000000176714760300421020056 0ustar --TEST-- Decimal128: [basx031] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640040af0d8648700000000000000000343000 {"d":{"$numberDecimal":"123456789.000000"}} 1800000013640040af0d8648700000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-307.phpt0000644000175100001660000000176714760300421020057 0ustar --TEST-- Decimal128: [basx030] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640080910f8648700000000000000000343000 {"d":{"$numberDecimal":"123456789.123456"}} 1800000013640080910f8648700000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-3-valid-308.phpt0000644000175100001660000000176514760300421020056 0ustar --TEST-- Decimal128: [basx032] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640080910f8648700000000000000000403000 {"d":{"$numberDecimal":"123456789123456"}} 1800000013640080910f8648700000000000000000403000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-001.phpt0000644000175100001660000000070014760300421021056 0ustar --TEST-- Decimal128: [basx564] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-002.phpt0000644000175100001660000000070114760300421021060 0ustar --TEST-- Decimal128: [basx565] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-003.phpt0000644000175100001660000000070214760300421021062 0ustar --TEST-- Decimal128: [basx566] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-004.phpt0000644000175100001660000000070314760300421021064 0ustar --TEST-- Decimal128: [basx567] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-005.phpt0000644000175100001660000000070414760300421021066 0ustar --TEST-- Decimal128: [basx568] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-006.phpt0000644000175100001660000000075314760300421021073 0ustar --TEST-- Decimal128: [basx590] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-007.phpt0000644000175100001660000000070014760300421021064 0ustar --TEST-- Decimal128: [basx562] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-008.phpt0000644000175100001660000000070014760300421021065 0ustar --TEST-- Decimal128: [basx563] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-009.phpt0000644000175100001660000000075714760300421021102 0ustar --TEST-- Decimal128: [dqbas939] overflow results at different rounding modes (Overflow & Inexact & Rounded) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-010.phpt0000644000175100001660000000073714760300421021070 0ustar --TEST-- Decimal128: [dqbsr534] negatives (Rounded & Inexact) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-011.phpt0000644000175100001660000000073714760300421021071 0ustar --TEST-- Decimal128: [dqbsr535] negatives (Rounded & Inexact) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-012.phpt0000644000175100001660000000073714760300421021072 0ustar --TEST-- Decimal128: [dqbsr533] negatives (Rounded & Inexact) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-013.phpt0000644000175100001660000000073714760300421021073 0ustar --TEST-- Decimal128: [dqbsr532] negatives (Rounded & Inexact) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-014.phpt0000644000175100001660000000076014760300421021070 0ustar --TEST-- Decimal128: [dqbsr432] check rounding modes heeded (Rounded & Inexact) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-015.phpt0000644000175100001660000000076014760300421021071 0ustar --TEST-- Decimal128: [dqbsr433] check rounding modes heeded (Rounded & Inexact) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-016.phpt0000644000175100001660000000076014760300421021072 0ustar --TEST-- Decimal128: [dqbsr435] check rounding modes heeded (Rounded & Inexact) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-017.phpt0000644000175100001660000000076014760300421021073 0ustar --TEST-- Decimal128: [dqbsr434] check rounding modes heeded (Rounded & Inexact) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-018.phpt0000644000175100001660000000075614760300421021101 0ustar --TEST-- Decimal128: [dqbas938] overflow results at different rounding modes (Overflow & Inexact & Rounded) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-019.phpt0000644000175100001660000000073714760300421021101 0ustar --TEST-- Decimal128: Inexact rounding#1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-parseError-020.phpt0000644000175100001660000000065214760300421021065 0ustar --TEST-- Decimal128: Inexact rounding#2 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-001.phpt0000644000175100001660000000173714760300421020044 0ustar --TEST-- Decimal128: [basx023] conform to rules and exponent will be in permitted range). --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640001000000000000000000000000003eb000 {"d":{"$numberDecimal":"-0.1"}} 1800000013640001000000000000000000000000003eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-002.phpt0000644000175100001660000000231514760300421020036 0ustar --TEST-- Decimal128: [basx045] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640003000000000000000000000000003a3000 {"d":{"$numberDecimal":"0.003"}} 1800000013640003000000000000000000000000003a3000 1800000013640003000000000000000000000000003a3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-003.phpt0000644000175100001660000000223514760300421020040 0ustar --TEST-- Decimal128: [basx610] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003e3000 {"d":{"$numberDecimal":"0.0"}} 1800000013640000000000000000000000000000003e3000 1800000013640000000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-004.phpt0000644000175100001660000000224014760300421020035 0ustar --TEST-- Decimal128: [basx612] Zeros --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000000000000000000000000003eb000 {"d":{"$numberDecimal":"-0.0"}} 1800000013640000000000000000000000000000003eb000 1800000013640000000000000000000000000000003eb000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-005.phpt0000644000175100001660000000231514760300421020041 0ustar --TEST-- Decimal128: [basx043] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400fc040000000000000000000000003c3000 {"d":{"$numberDecimal":"12.76"}} 18000000136400fc040000000000000000000000003c3000 18000000136400fc040000000000000000000000003c3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-006.phpt0000644000175100001660000000231714760300421020044 0ustar --TEST-- Decimal128: [basx055] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000500000000000000000000000000303000 {"d":{"$numberDecimal":"5E-8"}} 180000001364000500000000000000000000000000303000 180000001364000500000000000000000000000000303000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-007.phpt0000644000175100001660000000231614760300421020044 0ustar --TEST-- Decimal128: [basx054] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000500000000000000000000000000323000 {"d":{"$numberDecimal":"5E-7"}} 180000001364000500000000000000000000000000323000 180000001364000500000000000000000000000000323000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-008.phpt0000644000175100001660000000173214760300421020046 0ustar --TEST-- Decimal128: [basx052] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000500000000000000000000000000343000 {"d":{"$numberDecimal":"0.000005"}} 180000001364000500000000000000000000000000343000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-009.phpt0000644000175100001660000000232314760300421020044 0ustar --TEST-- Decimal128: [basx051] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000500000000000000000000000000363000 {"d":{"$numberDecimal":"0.00005"}} 180000001364000500000000000000000000000000363000 180000001364000500000000000000000000000000363000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-010.phpt0000644000175100001660000000172614760300421020042 0ustar --TEST-- Decimal128: [basx050] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000500000000000000000000000000383000 {"d":{"$numberDecimal":"0.0005"}} 180000001364000500000000000000000000000000383000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-011.phpt0000644000175100001660000000230514760300421020035 0ustar --TEST-- Decimal128: [basx047] strings without E cannot generate E in result --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640005000000000000000000000000003e3000 {"d":{"$numberDecimal":"0.5"}} 1800000013640005000000000000000000000000003e3000 1800000013640005000000000000000000000000003e3000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-012.phpt0000644000175100001660000000244014760300421020036 0ustar --TEST-- Decimal128: [dqbsr431] check rounding modes heeded (Rounded) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640099761cc7b548f377dc80a131c836fe2f00 {"d":{"$numberDecimal":"1.111111111111111111111111111112345"}} 1800000013640099761cc7b548f377dc80a131c836fe2f00 1800000013640099761cc7b548f377dc80a131c836fe2f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-4-valid-013.phpt0000644000175100001660000000241614760300421020042 0ustar --TEST-- Decimal128: OK2 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31fc2f00 {"d":{"$numberDecimal":"0.1000000000000000000000000000000000"}} 18000000136400000000000a5bc138938d44c64d31fc2f00 18000000136400000000000a5bc138938d44c64d31fc2f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-001.phpt0000644000175100001660000000241514760300421020037 0ustar --TEST-- Decimal128: [decq035] fold-downs (more below) (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000807f1bcf85b27059c8a43cfe5f00 {"d":{"$numberDecimal":"1.230000000000000000000000000000000E+6144"}} 18000000136400000000807f1bcf85b27059c8a43cfe5f00 18000000136400000000807f1bcf85b27059c8a43cfe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-002.phpt0000644000175100001660000000241214760300421020035 0ustar --TEST-- Decimal128: [decq037] fold-downs (more below) (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000000000000E+6144"}} 18000000136400000000000a5bc138938d44c64d31fe5f00 18000000136400000000000a5bc138938d44c64d31fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-003.phpt0000644000175100001660000000244314760300421020042 0ustar --TEST-- Decimal128: [decq077] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000081efac855b416d2dee04000000 {"d":{"$numberDecimal":"1.00000000000000000000000000000000E-6144"}} 180000001364000000000081efac855b416d2dee04000000 180000001364000000000081efac855b416d2dee04000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-004.phpt0000644000175100001660000000200714760300421020037 0ustar --TEST-- Decimal128: [decq078] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000081efac855b416d2dee04000000 {"d":{"$numberDecimal":"1.00000000000000000000000000000000E-6144"}} 180000001364000000000081efac855b416d2dee04000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-005.phpt0000644000175100001660000000234514760300421020045 0ustar --TEST-- Decimal128: [decq079] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000000000 {"d":{"$numberDecimal":"1.0E-6175"}} 180000001364000a00000000000000000000000000000000 180000001364000a00000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-006.phpt0000644000175100001660000000171114760300421020042 0ustar --TEST-- Decimal128: [decq080] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000000000 {"d":{"$numberDecimal":"1.0E-6175"}} 180000001364000a00000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-007.phpt0000644000175100001660000000234014760300421020042 0ustar --TEST-- Decimal128: [decq081] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000020000 {"d":{"$numberDecimal":"1E-6175"}} 180000001364000100000000000000000000000000020000 180000001364000100000000000000000000000000020000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-008.phpt0000644000175100001660000000170514760300421020047 0ustar --TEST-- Decimal128: [decq082] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000020000 {"d":{"$numberDecimal":"1E-6175"}} 180000001364000100000000000000000000000000020000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-009.phpt0000644000175100001660000000234114760300421020045 0ustar --TEST-- Decimal128: [decq083] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000000000 {"d":{"$numberDecimal":"1E-6176"}} 180000001364000100000000000000000000000000000000 180000001364000100000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-010.phpt0000644000175100001660000000170514760300421020040 0ustar --TEST-- Decimal128: [decq084] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000000000 {"d":{"$numberDecimal":"1E-6176"}} 180000001364000100000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-011.phpt0000644000175100001660000000236014760300421020037 0ustar --TEST-- Decimal128: [decq090] underflows cannot be tested for simple copies, check edge cases (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000000000 {"d":{"$numberDecimal":"1E-6176"}} 180000001364000100000000000000000000000000000000 180000001364000100000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-012.phpt0000644000175100001660000000252214760300421020040 0ustar --TEST-- Decimal128: [decq100] underflows cannot be tested for simple copies, check edge cases (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffff095bc138938d44c64d31000000 {"d":{"$numberDecimal":"9.99999999999999999999999999999999E-6144"}} 18000000136400ffffffff095bc138938d44c64d31000000 18000000136400ffffffff095bc138938d44c64d31000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-013.phpt0000644000175100001660000000242014760300421020036 0ustar --TEST-- Decimal128: [decq130] fold-downs (more below) (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000807f1bcf85b27059c8a43cfedf00 {"d":{"$numberDecimal":"-1.230000000000000000000000000000000E+6144"}} 18000000136400000000807f1bcf85b27059c8a43cfedf00 18000000136400000000807f1bcf85b27059c8a43cfedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-014.phpt0000644000175100001660000000241514760300421020043 0ustar --TEST-- Decimal128: [decq132] fold-downs (more below) (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31fedf00 {"d":{"$numberDecimal":"-1.000000000000000000000000000000000E+6144"}} 18000000136400000000000a5bc138938d44c64d31fedf00 18000000136400000000000a5bc138938d44c64d31fedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-015.phpt0000644000175100001660000000244614760300421020050 0ustar --TEST-- Decimal128: [decq177] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000081efac855b416d2dee04008000 {"d":{"$numberDecimal":"-1.00000000000000000000000000000000E-6144"}} 180000001364000000000081efac855b416d2dee04008000 180000001364000000000081efac855b416d2dee04008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-016.phpt0000644000175100001660000000201114760300421020035 0ustar --TEST-- Decimal128: [decq178] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000081efac855b416d2dee04008000 {"d":{"$numberDecimal":"-1.00000000000000000000000000000000E-6144"}} 180000001364000000000081efac855b416d2dee04008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-017.phpt0000644000175100001660000000235014760300421020044 0ustar --TEST-- Decimal128: [decq179] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000008000 {"d":{"$numberDecimal":"-1.0E-6175"}} 180000001364000a00000000000000000000000000008000 180000001364000a00000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-018.phpt0000644000175100001660000000171314760300421020047 0ustar --TEST-- Decimal128: [decq180] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000008000 {"d":{"$numberDecimal":"-1.0E-6175"}} 180000001364000a00000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-019.phpt0000644000175100001660000000234314760300421020050 0ustar --TEST-- Decimal128: [decq181] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000028000 {"d":{"$numberDecimal":"-1E-6175"}} 180000001364000100000000000000000000000000028000 180000001364000100000000000000000000000000028000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-020.phpt0000644000175100001660000000170714760300421020043 0ustar --TEST-- Decimal128: [decq182] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000028000 {"d":{"$numberDecimal":"-1E-6175"}} 180000001364000100000000000000000000000000028000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-021.phpt0000644000175100001660000000234414760300421020042 0ustar --TEST-- Decimal128: [decq183] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000008000 {"d":{"$numberDecimal":"-1E-6176"}} 180000001364000100000000000000000000000000008000 180000001364000100000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-022.phpt0000644000175100001660000000170714760300421020045 0ustar --TEST-- Decimal128: [decq184] Nmin and below (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000008000 {"d":{"$numberDecimal":"-1E-6176"}} 180000001364000100000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-023.phpt0000644000175100001660000000231014760300421020035 0ustar --TEST-- Decimal128: [decq190] underflow edge cases (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000100000000000000000000000000008000 {"d":{"$numberDecimal":"-1E-6176"}} 180000001364000100000000000000000000000000008000 180000001364000100000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-024.phpt0000644000175100001660000000245214760300421020045 0ustar --TEST-- Decimal128: [decq200] underflow edge cases (Subnormal) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400ffffffff095bc138938d44c64d31008000 {"d":{"$numberDecimal":"-9.99999999999999999999999999999999E-6144"}} 18000000136400ffffffff095bc138938d44c64d31008000 18000000136400ffffffff095bc138938d44c64d31008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-025.phpt0000644000175100001660000000226414760300421020047 0ustar --TEST-- Decimal128: [decq400] zeros (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000000000 {"d":{"$numberDecimal":"0E-6176"}} 180000001364000000000000000000000000000000000000 180000001364000000000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-026.phpt0000644000175100001660000000226414760300421020050 0ustar --TEST-- Decimal128: [decq401] zeros (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000000000 {"d":{"$numberDecimal":"0E-6176"}} 180000001364000000000000000000000000000000000000 180000001364000000000000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-027.phpt0000644000175100001660000000227714760300421020055 0ustar --TEST-- Decimal128: [decq414] clamped zeros... (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fe5f00 {"d":{"$numberDecimal":"0E+6111"}} 180000001364000000000000000000000000000000fe5f00 180000001364000000000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-028.phpt0000644000175100001660000000227714760300421020056 0ustar --TEST-- Decimal128: [decq416] clamped zeros... (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fe5f00 {"d":{"$numberDecimal":"0E+6111"}} 180000001364000000000000000000000000000000fe5f00 180000001364000000000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-029.phpt0000644000175100001660000000227714760300421020057 0ustar --TEST-- Decimal128: [decq418] clamped zeros... (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fe5f00 {"d":{"$numberDecimal":"0E+6111"}} 180000001364000000000000000000000000000000fe5f00 180000001364000000000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-030.phpt0000644000175100001660000000230014760300421020032 0ustar --TEST-- Decimal128: [decq420] negative zeros (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000008000 {"d":{"$numberDecimal":"-0E-6176"}} 180000001364000000000000000000000000000000008000 180000001364000000000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-031.phpt0000644000175100001660000000230014760300421020033 0ustar --TEST-- Decimal128: [decq421] negative zeros (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000008000 {"d":{"$numberDecimal":"-0E-6176"}} 180000001364000000000000000000000000000000008000 180000001364000000000000000000000000000000008000 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-032.phpt0000644000175100001660000000230214760300421020036 0ustar --TEST-- Decimal128: [decq434] clamped zeros... (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fedf00 {"d":{"$numberDecimal":"-0E+6111"}} 180000001364000000000000000000000000000000fedf00 180000001364000000000000000000000000000000fedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-033.phpt0000644000175100001660000000230214760300421020037 0ustar --TEST-- Decimal128: [decq436] clamped zeros... (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fedf00 {"d":{"$numberDecimal":"-0E+6111"}} 180000001364000000000000000000000000000000fedf00 180000001364000000000000000000000000000000fedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-034.phpt0000644000175100001660000000230214760300421020040 0ustar --TEST-- Decimal128: [decq438] clamped zeros... (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000000000000000000000000fedf00 {"d":{"$numberDecimal":"-0E+6111"}} 180000001364000000000000000000000000000000fedf00 180000001364000000000000000000000000000000fedf00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-035.phpt0000644000175100001660000000241214760300421020043 0ustar --TEST-- Decimal128: [decq601] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000000a5bc138938d44c64d31fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000000000000E+6144"}} 18000000136400000000000a5bc138938d44c64d31fe5f00 18000000136400000000000a5bc138938d44c64d31fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-036.phpt0000644000175100001660000000241014760300421020042 0ustar --TEST-- Decimal128: [decq603] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000000081efac855b416d2dee04fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000000000000000E+6143"}} 180000001364000000000081efac855b416d2dee04fe5f00 180000001364000000000081efac855b416d2dee04fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-037.phpt0000644000175100001660000000240614760300421020050 0ustar --TEST-- Decimal128: [decq605] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000080264b91c02220be377e00fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000000000000000E+6142"}} 1800000013640000000080264b91c02220be377e00fe5f00 1800000013640000000080264b91c02220be377e00fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-038.phpt0000644000175100001660000000240414760300421020047 0ustar --TEST-- Decimal128: [decq607] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000000040eaed7446d09c2c9f0c00fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000000000E+6141"}} 1800000013640000000040eaed7446d09c2c9f0c00fe5f00 1800000013640000000040eaed7446d09c2c9f0c00fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-039.phpt0000644000175100001660000000240214760300421020046 0ustar --TEST-- Decimal128: [decq609] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000a0ca17726dae0f1e430100fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000000000000E+6140"}} 18000000136400000000a0ca17726dae0f1e430100fe5f00 18000000136400000000a0ca17726dae0f1e430100fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-040.phpt0000644000175100001660000000240014760300421020034 0ustar --TEST-- Decimal128: [decq611] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000106102253e5ece4f200000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000000000000E+6139"}} 18000000136400000000106102253e5ece4f200000fe5f00 18000000136400000000106102253e5ece4f200000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-041.phpt0000644000175100001660000000237614760300421020051 0ustar --TEST-- Decimal128: [decq613] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000e83c80d09f3c2e3b030000fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000000E+6138"}} 18000000136400000000e83c80d09f3c2e3b030000fe5f00 18000000136400000000e83c80d09f3c2e3b030000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-042.phpt0000644000175100001660000000237414760300421020050 0ustar --TEST-- Decimal128: [decq615] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000e4d20cc8dcd2b752000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000000000E+6137"}} 18000000136400000000e4d20cc8dcd2b752000000fe5f00 18000000136400000000e4d20cc8dcd2b752000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-043.phpt0000644000175100001660000000237214760300421020047 0ustar --TEST-- Decimal128: [decq617] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000004a48011416954508000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000000000E+6136"}} 180000001364000000004a48011416954508000000fe5f00 180000001364000000004a48011416954508000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-044.phpt0000644000175100001660000000237014760300421020046 0ustar --TEST-- Decimal128: [decq619] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000000a1edccce1bc2d300000000fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000000E+6135"}} 18000000136400000000a1edccce1bc2d300000000fe5f00 18000000136400000000a1edccce1bc2d300000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-045.phpt0000644000175100001660000000236614760300421020054 0ustar --TEST-- Decimal128: [decq621] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000080f64ae1c7022d1500000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000000E+6134"}} 18000000136400000080f64ae1c7022d1500000000fe5f00 18000000136400000080f64ae1c7022d1500000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-046.phpt0000644000175100001660000000236414760300421020053 0ustar --TEST-- Decimal128: [decq623] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000040b2bac9e0191e0200000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000000E+6133"}} 18000000136400000040b2bac9e0191e0200000000fe5f00 18000000136400000040b2bac9e0191e0200000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-047.phpt0000644000175100001660000000236214760300421020052 0ustar --TEST-- Decimal128: [decq625] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000a0dec5adc935360000000000fe5f00 {"d":{"$numberDecimal":"1.000000000000000000000E+6132"}} 180000001364000000a0dec5adc935360000000000fe5f00 180000001364000000a0dec5adc935360000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-048.phpt0000644000175100001660000000236014760300421020051 0ustar --TEST-- Decimal128: [decq627] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000010632d5ec76b050000000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000000000E+6131"}} 18000000136400000010632d5ec76b050000000000fe5f00 18000000136400000010632d5ec76b050000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-049.phpt0000644000175100001660000000235614760300421020057 0ustar --TEST-- Decimal128: [decq629] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000e8890423c78a000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000000E+6130"}} 180000001364000000e8890423c78a000000000000fe5f00 180000001364000000e8890423c78a000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-050.phpt0000644000175100001660000000235414760300421020045 0ustar --TEST-- Decimal128: [decq631] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400000064a7b3b6e00d000000000000fe5f00 {"d":{"$numberDecimal":"1.000000000000000000E+6129"}} 18000000136400000064a7b3b6e00d000000000000fe5f00 18000000136400000064a7b3b6e00d000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-051.phpt0000644000175100001660000000235214760300421020044 0ustar --TEST-- Decimal128: [decq633] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000008a5d78456301000000000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000000E+6128"}} 1800000013640000008a5d78456301000000000000fe5f00 1800000013640000008a5d78456301000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-052.phpt0000644000175100001660000000235014760300421020043 0ustar --TEST-- Decimal128: [decq635] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000000c16ff2862300000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000000E+6127"}} 180000001364000000c16ff2862300000000000000fe5f00 180000001364000000c16ff2862300000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-053.phpt0000644000175100001660000000234614760300421020051 0ustar --TEST-- Decimal128: [decq637] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000080c6a47e8d0300000000000000fe5f00 {"d":{"$numberDecimal":"1.000000000000000E+6126"}} 180000001364000080c6a47e8d0300000000000000fe5f00 180000001364000080c6a47e8d0300000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-054.phpt0000644000175100001660000000234414760300421020050 0ustar --TEST-- Decimal128: [decq639] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000407a10f35a0000000000000000fe5f00 {"d":{"$numberDecimal":"1.00000000000000E+6125"}} 1800000013640000407a10f35a0000000000000000fe5f00 1800000013640000407a10f35a0000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-055.phpt0000644000175100001660000000234214760300421020047 0ustar --TEST-- Decimal128: [decq641] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000a0724e18090000000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000000000E+6124"}} 1800000013640000a0724e18090000000000000000fe5f00 1800000013640000a0724e18090000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-056.phpt0000644000175100001660000000234014760300421020046 0ustar --TEST-- Decimal128: [decq643] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000010a5d4e8000000000000000000fe5f00 {"d":{"$numberDecimal":"1.000000000000E+6123"}} 180000001364000010a5d4e8000000000000000000fe5f00 180000001364000010a5d4e8000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-057.phpt0000644000175100001660000000233614760300421020054 0ustar --TEST-- Decimal128: [decq645] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000e8764817000000000000000000fe5f00 {"d":{"$numberDecimal":"1.00000000000E+6122"}} 1800000013640000e8764817000000000000000000fe5f00 1800000013640000e8764817000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-058.phpt0000644000175100001660000000233414760300421020053 0ustar --TEST-- Decimal128: [decq647] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000e40b5402000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000000E+6121"}} 1800000013640000e40b5402000000000000000000fe5f00 1800000013640000e40b5402000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-059.phpt0000644000175100001660000000233214760300421020052 0ustar --TEST-- Decimal128: [decq649] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000ca9a3b00000000000000000000fe5f00 {"d":{"$numberDecimal":"1.000000000E+6120"}} 1800000013640000ca9a3b00000000000000000000fe5f00 1800000013640000ca9a3b00000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-060.phpt0000644000175100001660000000233014760300421020040 0ustar --TEST-- Decimal128: [decq651] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640000e1f50500000000000000000000fe5f00 {"d":{"$numberDecimal":"1.00000000E+6119"}} 1800000013640000e1f50500000000000000000000fe5f00 1800000013640000e1f50500000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-061.phpt0000644000175100001660000000232614760300421020046 0ustar --TEST-- Decimal128: [decq653] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364008096980000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0000000E+6118"}} 180000001364008096980000000000000000000000fe5f00 180000001364008096980000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-062.phpt0000644000175100001660000000232414760300421020045 0ustar --TEST-- Decimal128: [decq655] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1800000013640040420f0000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.000000E+6117"}} 1800000013640040420f0000000000000000000000fe5f00 1800000013640040420f0000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-063.phpt0000644000175100001660000000232214760300421020044 0ustar --TEST-- Decimal128: [decq657] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400a086010000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.00000E+6116"}} 18000000136400a086010000000000000000000000fe5f00 18000000136400a086010000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-064.phpt0000644000175100001660000000232014760300421020043 0ustar --TEST-- Decimal128: [decq659] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364001027000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0000E+6115"}} 180000001364001027000000000000000000000000fe5f00 180000001364001027000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-065.phpt0000644000175100001660000000231614760300421020051 0ustar --TEST-- Decimal128: [decq661] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 18000000136400e803000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.000E+6114"}} 18000000136400e803000000000000000000000000fe5f00 18000000136400e803000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-066.phpt0000644000175100001660000000231414760300421020050 0ustar --TEST-- Decimal128: [decq663] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364006400000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.00E+6113"}} 180000001364006400000000000000000000000000fe5f00 180000001364006400000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-5-valid-067.phpt0000644000175100001660000000231214760300421020047 0ustar --TEST-- Decimal128: [decq665] fold-down full sequence (Clamped) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000001364000a00000000000000000000000000fe5f00 {"d":{"$numberDecimal":"1.0E+6112"}} 180000001364000a00000000000000000000000000fe5f00 180000001364000a00000000000000000000000000fe5f00 ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-001.phpt0000644000175100001660000000064614760300421021071 0ustar --TEST-- Decimal128: Incomplete Exponent --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-002.phpt0000644000175100001660000000065514760300421021072 0ustar --TEST-- Decimal128: Exponent at the beginning --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-003.phpt0000644000175100001660000000064614760300421021073 0ustar --TEST-- Decimal128: Just a decimal place --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-004.phpt0000644000175100001660000000064414760300421021072 0ustar --TEST-- Decimal128: 2 decimal places --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-005.phpt0000644000175100001660000000064614760300421021075 0ustar --TEST-- Decimal128: 2 decimal places --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-006.phpt0000644000175100001660000000064514760300421021075 0ustar --TEST-- Decimal128: 2 decimal places --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-007.phpt0000644000175100001660000000064614760300421021077 0ustar --TEST-- Decimal128: 2 decimal places --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-008.phpt0000644000175100001660000000064614760300421021100 0ustar --TEST-- Decimal128: 2 decimal places --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-009.phpt0000644000175100001660000000065114760300421021075 0ustar --TEST-- Decimal128: Decimal with no digits --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-010.phpt0000644000175100001660000000063614760300421021070 0ustar --TEST-- Decimal128: 2 signs --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-011.phpt0000644000175100001660000000063614760300421021071 0ustar --TEST-- Decimal128: 2 signs --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-012.phpt0000644000175100001660000000064714760300421021074 0ustar --TEST-- Decimal128: 2 negative signs --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-013.phpt0000644000175100001660000000064714760300421021075 0ustar --TEST-- Decimal128: 2 negative signs --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-014.phpt0000644000175100001660000000065214760300421021072 0ustar --TEST-- Decimal128: End in negative sign --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-015.phpt0000644000175100001660000000065214760300421021073 0ustar --TEST-- Decimal128: 2 negative signs --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-016.phpt0000644000175100001660000000065214760300421021074 0ustar --TEST-- Decimal128: 2 negative signs --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-017.phpt0000644000175100001660000000064114760300421021073 0ustar --TEST-- Decimal128: 2 signs --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-018.phpt0000644000175100001660000000063514760300421021077 0ustar --TEST-- Decimal128: Empty string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-019.phpt0000644000175100001660000000066614760300421021104 0ustar --TEST-- Decimal128: leading white space positive number --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-020.phpt0000644000175100001660000000066714760300421021075 0ustar --TEST-- Decimal128: leading white space negative number --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-021.phpt0000644000175100001660000000064714760300421021074 0ustar --TEST-- Decimal128: trailing white space --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-022.phpt0000644000175100001660000000063114760300421021066 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-023.phpt0000644000175100001660000000063714760300421021075 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-024.phpt0000644000175100001660000000063114760300421021070 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-025.phpt0000644000175100001660000000063214760300421021072 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-026.phpt0000644000175100001660000000063314760300421021074 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-027.phpt0000644000175100001660000000063214760300421021074 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-028.phpt0000644000175100001660000000063314760300421021076 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-029.phpt0000644000175100001660000000063714760300421021103 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-030.phpt0000644000175100001660000000064314760300421021070 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-6-parseError-031.phpt0000644000175100001660000000064414760300421021072 0ustar --TEST-- Decimal128: Invalid --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-001.phpt0000644000175100001660000000070114760300421021062 0ustar --TEST-- Decimal128: [basx572] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-002.phpt0000644000175100001660000000075514760300421021074 0ustar --TEST-- Decimal128: [basx516] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-003.phpt0000644000175100001660000000076014760300421021071 0ustar --TEST-- Decimal128: [basx533] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-004.phpt0000644000175100001660000000076014760300421021072 0ustar --TEST-- Decimal128: [basx534] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-005.phpt0000644000175100001660000000076014760300421021073 0ustar --TEST-- Decimal128: [basx535] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-006.phpt0000644000175100001660000000070014760300421021066 0ustar --TEST-- Decimal128: [basx569] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-007.phpt0000644000175100001660000000070114760300421021070 0ustar --TEST-- Decimal128: [basx571] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-008.phpt0000644000175100001660000000070114760300421021071 0ustar --TEST-- Decimal128: [basx575] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-009.phpt0000644000175100001660000000075514760300421021103 0ustar --TEST-- Decimal128: [basx503] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-010.phpt0000644000175100001660000000075514760300421021073 0ustar --TEST-- Decimal128: [basx504] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-011.phpt0000644000175100001660000000075514760300421021074 0ustar --TEST-- Decimal128: [basx505] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-012.phpt0000644000175100001660000000075514760300421021075 0ustar --TEST-- Decimal128: [basx506] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-013.phpt0000644000175100001660000000075514760300421021076 0ustar --TEST-- Decimal128: [basx510] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-014.phpt0000644000175100001660000000075614760300421021100 0ustar --TEST-- Decimal128: [basx513] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-015.phpt0000644000175100001660000000075614760300421021101 0ustar --TEST-- Decimal128: [basx514] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-016.phpt0000644000175100001660000000075314760300421021077 0ustar --TEST-- Decimal128: [basx501] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-017.phpt0000644000175100001660000000075414760300421021101 0ustar --TEST-- Decimal128: [basx502] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-018.phpt0000644000175100001660000000075214760300421021100 0ustar --TEST-- Decimal128: [basx519] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-019.phpt0000644000175100001660000000075614760300421021105 0ustar --TEST-- Decimal128: [basx525] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-020.phpt0000644000175100001660000000075514760300421021074 0ustar --TEST-- Decimal128: [basx549] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-021.phpt0000644000175100001660000000074614760300421021075 0ustar --TEST-- Decimal128: [basx577] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-022.phpt0000644000175100001660000000074714760300421021077 0ustar --TEST-- Decimal128: [basx578] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-023.phpt0000644000175100001660000000074514760300421021076 0ustar --TEST-- Decimal128: [basx581] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-024.phpt0000644000175100001660000000074614760300421021100 0ustar --TEST-- Decimal128: [basx582] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-025.phpt0000644000175100001660000000074714760300421021102 0ustar --TEST-- Decimal128: [basx583] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-026.phpt0000644000175100001660000000074614760300421021102 0ustar --TEST-- Decimal128: [basx579] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-027.phpt0000644000175100001660000000074514760300421021102 0ustar --TEST-- Decimal128: [basx580] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-028.phpt0000644000175100001660000000074614760300421021104 0ustar --TEST-- Decimal128: [basx584] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-029.phpt0000644000175100001660000000074514760300421021104 0ustar --TEST-- Decimal128: [basx585] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-030.phpt0000644000175100001660000000074714760300421021076 0ustar --TEST-- Decimal128: [basx589] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-031.phpt0000644000175100001660000000074614760300421021076 0ustar --TEST-- Decimal128: [basx586] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-032.phpt0000644000175100001660000000074714760300421021100 0ustar --TEST-- Decimal128: [basx587] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-033.phpt0000644000175100001660000000075514760300421021100 0ustar --TEST-- Decimal128: [basx545] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-034.phpt0000644000175100001660000000070014760300421021067 0ustar --TEST-- Decimal128: [basx561] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-035.phpt0000644000175100001660000000070014760300421021070 0ustar --TEST-- Decimal128: [basx573] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-036.phpt0000644000175100001660000000075014760300421021076 0ustar --TEST-- Decimal128: [basx588] some baddies with dots and Es and dots and specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-037.phpt0000644000175100001660000000075514760300421021104 0ustar --TEST-- Decimal128: [basx544] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-038.phpt0000644000175100001660000000075714760300421021107 0ustar --TEST-- Decimal128: [basx527] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-039.phpt0000644000175100001660000000075714760300421021110 0ustar --TEST-- Decimal128: [basx526] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-040.phpt0000644000175100001660000000075314760300421021074 0ustar --TEST-- Decimal128: [basx515] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-041.phpt0000644000175100001660000000070014760300421021065 0ustar --TEST-- Decimal128: [basx574] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-042.phpt0000644000175100001660000000076014760300421021074 0ustar --TEST-- Decimal128: [basx530] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-043.phpt0000644000175100001660000000075614760300421021102 0ustar --TEST-- Decimal128: [basx500] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-044.phpt0000644000175100001660000000075714760300421021104 0ustar --TEST-- Decimal128: [basx542] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-045.phpt0000644000175100001660000000076214760300421021101 0ustar --TEST-- Decimal128: [basx553] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-046.phpt0000644000175100001660000000076014760300421021100 0ustar --TEST-- Decimal128: [basx543] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-047.phpt0000644000175100001660000000076014760300421021101 0ustar --TEST-- Decimal128: [basx552] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-048.phpt0000644000175100001660000000075614760300421021107 0ustar --TEST-- Decimal128: [basx546] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-049.phpt0000644000175100001660000000075614760300421021110 0ustar --TEST-- Decimal128: [basx547] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-050.phpt0000644000175100001660000000075714760300421021101 0ustar --TEST-- Decimal128: [basx554] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-051.phpt0000644000175100001660000000075714760300421021102 0ustar --TEST-- Decimal128: [basx555] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-052.phpt0000644000175100001660000000075714760300421021103 0ustar --TEST-- Decimal128: [basx556] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-053.phpt0000644000175100001660000000075714760300421021104 0ustar --TEST-- Decimal128: [basx557] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-054.phpt0000644000175100001660000000075714760300421021105 0ustar --TEST-- Decimal128: [basx558] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-055.phpt0000644000175100001660000000075614760300421021105 0ustar --TEST-- Decimal128: [basx559] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-056.phpt0000644000175100001660000000075514760300421021105 0ustar --TEST-- Decimal128: [basx520] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-057.phpt0000644000175100001660000000075414760300421021105 0ustar --TEST-- Decimal128: [basx560] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-058.phpt0000644000175100001660000000075514760300421021107 0ustar --TEST-- Decimal128: [basx548] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-059.phpt0000644000175100001660000000075714760300421021112 0ustar --TEST-- Decimal128: [basx551] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-060.phpt0000644000175100001660000000076014760300421021074 0ustar --TEST-- Decimal128: [basx550] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-061.phpt0000644000175100001660000000076014760300421021075 0ustar --TEST-- Decimal128: [basx529] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-062.phpt0000644000175100001660000000076014760300421021076 0ustar --TEST-- Decimal128: [basx531] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-063.phpt0000644000175100001660000000076014760300421021077 0ustar --TEST-- Decimal128: [basx532] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-064.phpt0000644000175100001660000000075414760300421021103 0ustar --TEST-- Decimal128: [basx518] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-065.phpt0000644000175100001660000000076214760300421021103 0ustar --TEST-- Decimal128: [basx521] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-066.phpt0000644000175100001660000000070014760300421021074 0ustar --TEST-- Decimal128: [basx570] Near-specials (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-067.phpt0000644000175100001660000000075514760300421021107 0ustar --TEST-- Decimal128: [basx512] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-068.phpt0000644000175100001660000000075514760300421021110 0ustar --TEST-- Decimal128: [basx517] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-069.phpt0000644000175100001660000000075514760300421021111 0ustar --TEST-- Decimal128: [basx507] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-070.phpt0000644000175100001660000000075714760300421021103 0ustar --TEST-- Decimal128: [basx508] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-071.phpt0000644000175100001660000000075614760300421021103 0ustar --TEST-- Decimal128: [basx509] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-072.phpt0000644000175100001660000000076214760300421021101 0ustar --TEST-- Decimal128: [basx536] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-073.phpt0000644000175100001660000000076214760300421021102 0ustar --TEST-- Decimal128: [basx537] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-074.phpt0000644000175100001660000000076214760300421021103 0ustar --TEST-- Decimal128: [basx540] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-075.phpt0000644000175100001660000000076214760300421021104 0ustar --TEST-- Decimal128: [basx538] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-076.phpt0000644000175100001660000000076214760300421021105 0ustar --TEST-- Decimal128: [basx539] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-077.phpt0000644000175100001660000000076214760300421021106 0ustar --TEST-- Decimal128: [basx541] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-078.phpt0000644000175100001660000000076014760300421021105 0ustar --TEST-- Decimal128: [basx528] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-079.phpt0000644000175100001660000000077014760300421021107 0ustar --TEST-- Decimal128: [basx523] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/decimal128-7-parseError-080.phpt0000644000175100001660000000076614760300421021104 0ustar --TEST-- Decimal128: [basx522] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE===mongodb-1.21.0/tests/bson-corpus/document-decodeError-001.phpt0000644000175100001660000000107014760300421021014 0ustar --TEST-- Document type (sub-documents): Subdocument length too long: eats outer terminator --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/document-decodeError-002.phpt0000644000175100001660000000105614760300421021021 0ustar --TEST-- Document type (sub-documents): Subdocument length too short: leaks terminator --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/document-decodeError-003.phpt0000644000175100001660000000107514760300421021023 0ustar --TEST-- Document type (sub-documents): Invalid subdocument: bad string length in field --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/document-decodeError-004.phpt0000644000175100001660000000103514760300421021020 0ustar --TEST-- Document type (sub-documents): Null byte in sub-document key --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/document-valid-001.phpt0000644000175100001660000000151014760300421017655 0ustar --TEST-- Document type (sub-documents): Empty subdoc --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0d000000037800050000000000 {"x":{}} 0d000000037800050000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/document-valid-002.phpt0000644000175100001660000000162114760300421017661 0ustar --TEST-- Document type (sub-documents): Empty-string key subdoc --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 150000000378000d00000002000200000062000000 {"x":{"":"b"}} 150000000378000d00000002000200000062000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/document-valid-003.phpt0000644000175100001660000000163514760300421017667 0ustar --TEST-- Document type (sub-documents): Single-character key subdoc --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 160000000378000e0000000261000200000062000000 {"x":{"a":"b"}} 160000000378000e0000000261000200000062000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/document-valid-004.phpt0000644000175100001660000000165514760300421017672 0ustar --TEST-- Document type (sub-documents): Dollar-prefixed key in sub-document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 170000000378000f000000022461000200000062000000 {"x":{"$a":"b"}} 170000000378000f000000022461000200000062000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/document-valid-005.phpt0000644000175100001660000000163714760300421017673 0ustar --TEST-- Document type (sub-documents): Dollar as key in sub-document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 160000000378000e0000000224000200000061000000 {"x":{"$":"a"}} 160000000378000e0000000224000200000061000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/document-valid-006.phpt0000644000175100001660000000165414760300421017673 0ustar --TEST-- Document type (sub-documents): Dotted key in sub-document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000000378001000000002612e62000200000063000000 {"x":{"a.b":"c"}} 180000000378001000000002612e62000200000063000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/document-valid-007.phpt0000644000175100001660000000163414760300421017672 0ustar --TEST-- Document type (sub-documents): Dot as key in sub-document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 160000000378000e000000022e000200000061000000 {"x":{".":"a"}} 160000000378000e000000022e000200000061000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/double-decodeError-001.phpt0000644000175100001660000000075414760300421020460 0ustar --TEST-- Double type: double truncated --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-001.phpt0000644000175100001660000000232614760300421017317 0ustar --TEST-- Double type: +1.0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000000000f03f00 {"d":{"$numberDouble":"1"}} {"d":1} 10000000016400000000000000f03f00 {"d":1} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-002.phpt0000644000175100001660000000233314760300421017316 0ustar --TEST-- Double type: -1.0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000000000f0bf00 {"d":{"$numberDouble":"-1"}} {"d":-1} 10000000016400000000000000f0bf00 {"d":-1} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-003.phpt0000644000175100001660000000244414760300421017322 0ustar --TEST-- Double type: +1.0001220703125 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000008000f03f00 {"d":{"$numberDouble":"1.0001220703125"}} {"d":1.0001220703125} 10000000016400000000008000f03f00 {"d":1.0001220703125} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-004.phpt0000644000175100001660000000245114760300421017321 0ustar --TEST-- Double type: -1.0001220703125 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000008000f0bf00 {"d":{"$numberDouble":"-1.0001220703125"}} {"d":-1.0001220703125} 10000000016400000000008000f0bf00 {"d":-1.0001220703125} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-005.phpt0000644000175100001660000000247314760300421017326 0ustar --TEST-- Double type: 1.2345678921232E+18 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 100000000164002a1bf5f41022b14300 {"d":{"$numberDouble":"1.2345678921232e+18"}} {"d":1.2345678921232e+18} 100000000164002a1bf5f41022b14300 {"d":1.2345678921232e+18} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-006.phpt0000644000175100001660000000250114760300421017317 0ustar --TEST-- Double type: -1.2345678921232E+18 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 100000000164002a1bf5f41022b1c300 {"d":{"$numberDouble":"-1.2345678921232e+18"}} {"d":-1.2345678921232e+18} 100000000164002a1bf5f41022b1c300 {"d":-1.2345678921232e+18} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-007.phpt0000644000175100001660000000232514760300421017324 0ustar --TEST-- Double type: 0.0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000000000000000 {"d":{"$numberDouble":"0"}} {"d":0} 10000000016400000000000000000000 {"d":0} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-008.phpt0000644000175100001660000000233314760300421017324 0ustar --TEST-- Double type: -0.0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000000000008000 {"d":{"$numberDouble":"-0"}} {"d":-0} 10000000016400000000000000008000 {"d":-0} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-009.phpt0000644000175100001660000000215514760300421017327 0ustar --TEST-- Double type: NaN --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000000000f87f00 {"d":{"$numberDouble":"NaN"}} {"d":{"$numberDouble":"NaN"}} {"d":{"$numberDouble":"NaN"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-010.phpt0000644000175100001660000000217214760300421017316 0ustar --TEST-- Double type: NaN with payload --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400120000000000f87f00 {"d":{"$numberDouble":"NaN"}} {"d":{"$numberDouble":"NaN"}} {"d":{"$numberDouble":"NaN"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-011.phpt0000644000175100001660000000245714760300421017325 0ustar --TEST-- Double type: Inf --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000000000f07f00 {"d":{"$numberDouble":"Infinity"}} {"d":{"$numberDouble":"Infinity"}} 10000000016400000000000000f07f00 {"d":{"$numberDouble":"Infinity"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/double-valid-012.phpt0000644000175100001660000000246514760300421017325 0ustar --TEST-- Double type: -Inf --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000016400000000000000f0ff00 {"d":{"$numberDouble":"-Infinity"}} {"d":{"$numberDouble":"-Infinity"}} 10000000016400000000000000f0ff00 {"d":{"$numberDouble":"-Infinity"}} ===DONE===mongodb-1.21.0/tests/bson-corpus/int32-decodeError-001.phpt0000644000175100001660000000075314760300421020144 0ustar --TEST-- Int32 type: Bad int32 field length --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/int32-valid-001.phpt0000644000175100001660000000235114760300421017002 0ustar --TEST-- Int32 type: MinValue --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 0c0000001069000000008000 {"i":{"$numberInt":"-2147483648"}} {"i":-2147483648} 0c0000001069000000008000 {"i":-2147483648} ===DONE===mongodb-1.21.0/tests/bson-corpus/int32-valid-002.phpt0000644000175100001660000000234414760300421017005 0ustar --TEST-- Int32 type: MaxValue --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 0c000000106900ffffff7f00 {"i":{"$numberInt":"2147483647"}} {"i":2147483647} 0c000000106900ffffff7f00 {"i":2147483647} ===DONE===mongodb-1.21.0/tests/bson-corpus/int32-valid-003.phpt0000644000175100001660000000226614760300421017011 0ustar --TEST-- Int32 type: -1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 0c000000106900ffffffff00 {"i":{"$numberInt":"-1"}} {"i":-1} 0c000000106900ffffffff00 {"i":-1} ===DONE===mongodb-1.21.0/tests/bson-corpus/int32-valid-004.phpt0000644000175100001660000000226014760300421017004 0ustar --TEST-- Int32 type: 0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 0c0000001069000000000000 {"i":{"$numberInt":"0"}} {"i":0} 0c0000001069000000000000 {"i":0} ===DONE===mongodb-1.21.0/tests/bson-corpus/int32-valid-005.phpt0000644000175100001660000000226014760300421017005 0ustar --TEST-- Int32 type: 1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 0c0000001069000100000000 {"i":{"$numberInt":"1"}} {"i":1} 0c0000001069000100000000 {"i":1} ===DONE===mongodb-1.21.0/tests/bson-corpus/int64-decodeError-001.phpt0000644000175100001660000000076014760300421020147 0ustar --TEST-- Int64 type: int64 field truncated --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/int64-valid-001.phpt0000644000175100001660000000263714760300421017016 0ustar --TEST-- Int64 type: MinValue --SKIPIF-- --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000126100000000000000008000 {"a":{"$numberLong":"-9223372036854775808"}} {"a":-9223372036854775808} 10000000126100000000000000008000 {"a":-9223372036854775808} ===DONE===mongodb-1.21.0/tests/bson-corpus/int64-valid-002.phpt0000644000175100001660000000263214760300421017012 0ustar --TEST-- Int64 type: MaxValue --SKIPIF-- --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000126100ffffffffffffff7f00 {"a":{"$numberLong":"9223372036854775807"}} {"a":9223372036854775807} 10000000126100ffffffffffffff7f00 {"a":9223372036854775807} ===DONE===mongodb-1.21.0/tests/bson-corpus/int64-valid-003.phpt0000644000175100001660000000232114760300421017006 0ustar --TEST-- Int64 type: -1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000126100ffffffffffffffff00 {"a":{"$numberLong":"-1"}} {"a":-1} 10000000126100ffffffffffffffff00 {"a":-1} ===DONE===mongodb-1.21.0/tests/bson-corpus/int64-valid-004.phpt0000644000175100001660000000231314760300421017010 0ustar --TEST-- Int64 type: 0 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000126100000000000000000000 {"a":{"$numberLong":"0"}} {"a":0} 10000000126100000000000000000000 {"a":0} ===DONE===mongodb-1.21.0/tests/bson-corpus/int64-valid-005.phpt0000644000175100001660000000231314760300421017011 0ustar --TEST-- Int64 type: 1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical BSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toRelaxedExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Relaxed extJSON -> BSON object -> Relaxed extJSON echo json_canonicalize(MongoDB\BSON\Document::fromJSON($relaxedExtJson)->toRelaxedExtendedJSON()), "\n"; ?> ===DONE=== --EXPECT-- 10000000126100010000000000000000 {"a":{"$numberLong":"1"}} {"a":1} 10000000126100010000000000000000 {"a":1} ===DONE===mongodb-1.21.0/tests/bson-corpus/maxkey-valid-001.phpt0000644000175100001660000000145214760300421017342 0ustar --TEST-- Maxkey type: Maxkey --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 080000007f610000 {"a":{"$maxKey":1}} 080000007f610000 ===DONE===mongodb-1.21.0/tests/bson-corpus/minkey-valid-001.phpt0000644000175100001660000000145214760300421017340 0ustar --TEST-- Minkey type: Minkey --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 08000000ff610000 {"a":{"$minKey":1}} 08000000ff610000 ===DONE===mongodb-1.21.0/tests/bson-corpus/multi-type-deprecated-valid-001.phpt0000644000175100001660000002127314760300421022256 0ustar --TEST-- Multiple types within the same document: All BSON types --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 38020000075f69640057e193d7a9cc81b4027498b50e53796d626f6c000700000073796d626f6c0002537472696e670007000000737472696e670010496e743332002a00000012496e743634002a0000000000000001446f75626c6500000000000000f0bf0542696e617279001000000003a34c38f7c3abedc8a37814a992ab8db60542696e61727955736572446566696e656400050000008001020304050d436f6465000e00000066756e6374696f6e2829207b7d000f436f64655769746853636f7065001b0000000e00000066756e6374696f6e2829207b7d00050000000003537562646f63756d656e74001200000002666f6f0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696d657374616d7000010000002a0000000b5265676578007061747465726e0000094461746574696d6545706f6368000000000000000000094461746574696d65506f73697469766500ffffff7f00000000094461746574696d654e656761746976650000000080ffffffff085472756500010846616c736500000c4442506f696e746572000b000000636f6c6c656374696f6e0057e193d7a9cc81b4027498b1034442526566003d0000000224726566000b000000636f6c6c656374696f6e00072469640057fd71e96e32ab4225b723fb02246462000900000064617461626173650000ff4d696e6b6579007f4d61786b6579000a4e756c6c0006556e646566696e65640000 {"_id":{"$oid":"57e193d7a9cc81b4027498b5"},"Symbol":{"$symbol":"symbol"},"String":"string","Int32":{"$numberInt":"42"},"Int64":{"$numberLong":"42"},"Double":{"$numberDouble":"-1"},"Binary":{"$binary":{"base64":"o0w498Or7cijeBSpkquNtg==","subType":"03"}},"BinaryUserDefined":{"$binary":{"base64":"AQIDBAU=","subType":"80"}},"Code":{"$code":"function() {}"},"CodeWithScope":{"$code":"function() {}","$scope":{}},"Subdocument":{"foo":"bar"},"Array":[{"$numberInt":"1"},{"$numberInt":"2"},{"$numberInt":"3"},{"$numberInt":"4"},{"$numberInt":"5"}],"Timestamp":{"$timestamp":{"t":42,"i":1}},"Regex":{"$regularExpression":{"pattern":"pattern","options":""}},"DatetimeEpoch":{"$date":{"$numberLong":"0"}},"DatetimePositive":{"$date":{"$numberLong":"2147483647"}},"DatetimeNegative":{"$date":{"$numberLong":"-2147483648"}},"True":true,"False":false,"DBPointer":{"$dbPointer":{"$ref":"collection","$id":{"$oid":"57e193d7a9cc81b4027498b1"}}},"DBRef":{"$ref":"collection","$id":{"$oid":"57fd71e96e32ab4225b723fb"},"$db":"database"},"Minkey":{"$minKey":1},"Maxkey":{"$maxKey":1},"Null":null,"Undefined":{"$undefined":true}} 38020000075f69640057e193d7a9cc81b4027498b50e53796d626f6c000700000073796d626f6c0002537472696e670007000000737472696e670010496e743332002a00000012496e743634002a0000000000000001446f75626c6500000000000000f0bf0542696e617279001000000003a34c38f7c3abedc8a37814a992ab8db60542696e61727955736572446566696e656400050000008001020304050d436f6465000e00000066756e6374696f6e2829207b7d000f436f64655769746853636f7065001b0000000e00000066756e6374696f6e2829207b7d00050000000003537562646f63756d656e74001200000002666f6f0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696d657374616d7000010000002a0000000b5265676578007061747465726e0000094461746574696d6545706f6368000000000000000000094461746574696d65506f73697469766500ffffff7f00000000094461746574696d654e656761746976650000000080ffffffff085472756500010846616c736500000c4442506f696e746572000b000000636f6c6c656374696f6e0057e193d7a9cc81b4027498b1034442526566003d0000000224726566000b000000636f6c6c656374696f6e00072469640057fd71e96e32ab4225b723fb02246462000900000064617461626173650000ff4d696e6b6579007f4d61786b6579000a4e756c6c0006556e646566696e65640000 ===DONE===mongodb-1.21.0/tests/bson-corpus/multi-type-valid-001.phpt0000644000175100001660000001320714760300421020156 0ustar --TEST-- Multiple types within the same document: All BSON types --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- f4010000075f69640057e193d7a9cc81b4027498b502537472696e670007000000737472696e670010496e743332002a00000012496e743634002a0000000000000001446f75626c6500000000000000f0bf0542696e617279001000000003a34c38f7c3abedc8a37814a992ab8db60542696e61727955736572446566696e656400050000008001020304050d436f6465000e00000066756e6374696f6e2829207b7d000f436f64655769746853636f7065001b0000000e00000066756e6374696f6e2829207b7d00050000000003537562646f63756d656e74001200000002666f6f0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696d657374616d7000010000002a0000000b5265676578007061747465726e0000094461746574696d6545706f6368000000000000000000094461746574696d65506f73697469766500ffffff7f00000000094461746574696d654e656761746976650000000080ffffffff085472756500010846616c73650000034442526566003d0000000224726566000b000000636f6c6c656374696f6e00072469640057fd71e96e32ab4225b723fb02246462000900000064617461626173650000ff4d696e6b6579007f4d61786b6579000a4e756c6c0000 {"_id":{"$oid":"57e193d7a9cc81b4027498b5"},"String":"string","Int32":{"$numberInt":"42"},"Int64":{"$numberLong":"42"},"Double":{"$numberDouble":"-1"},"Binary":{"$binary":{"base64":"o0w498Or7cijeBSpkquNtg==","subType":"03"}},"BinaryUserDefined":{"$binary":{"base64":"AQIDBAU=","subType":"80"}},"Code":{"$code":"function() {}"},"CodeWithScope":{"$code":"function() {}","$scope":{}},"Subdocument":{"foo":"bar"},"Array":[{"$numberInt":"1"},{"$numberInt":"2"},{"$numberInt":"3"},{"$numberInt":"4"},{"$numberInt":"5"}],"Timestamp":{"$timestamp":{"t":42,"i":1}},"Regex":{"$regularExpression":{"pattern":"pattern","options":""}},"DatetimeEpoch":{"$date":{"$numberLong":"0"}},"DatetimePositive":{"$date":{"$numberLong":"2147483647"}},"DatetimeNegative":{"$date":{"$numberLong":"-2147483648"}},"True":true,"False":false,"DBRef":{"$ref":"collection","$id":{"$oid":"57fd71e96e32ab4225b723fb"},"$db":"database"},"Minkey":{"$minKey":1},"Maxkey":{"$maxKey":1},"Null":null} f4010000075f69640057e193d7a9cc81b4027498b502537472696e670007000000737472696e670010496e743332002a00000012496e743634002a0000000000000001446f75626c6500000000000000f0bf0542696e617279001000000003a34c38f7c3abedc8a37814a992ab8db60542696e61727955736572446566696e656400050000008001020304050d436f6465000e00000066756e6374696f6e2829207b7d000f436f64655769746853636f7065001b0000000e00000066756e6374696f6e2829207b7d00050000000003537562646f63756d656e74001200000002666f6f0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696d657374616d7000010000002a0000000b5265676578007061747465726e0000094461746574696d6545706f6368000000000000000000094461746574696d65506f73697469766500ffffff7f00000000094461746574696d654e656761746976650000000080ffffffff085472756500010846616c73650000034442526566003d0000000224726566000b000000636f6c6c656374696f6e00072469640057fd71e96e32ab4225b723fb02246462000900000064617461626173650000ff4d696e6b6579007f4d61786b6579000a4e756c6c0000 ===DONE===mongodb-1.21.0/tests/bson-corpus/null-valid-001.phpt0000644000175100001660000000142214760300421017013 0ustar --TEST-- Null type: Null --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 080000000a610000 {"a":null} 080000000a610000 ===DONE===mongodb-1.21.0/tests/bson-corpus/oid-decodeError-001.phpt0000644000175100001660000000076014760300421017756 0ustar --TEST-- ObjectId: OID truncated --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/oid-valid-001.phpt0000644000175100001660000000163714760300421016624 0ustar --TEST-- ObjectId: All zeroes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1400000007610000000000000000000000000000 {"a":{"$oid":"000000000000000000000000"}} 1400000007610000000000000000000000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/oid-valid-002.phpt0000644000175100001660000000163514760300421016623 0ustar --TEST-- ObjectId: All ones --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 14000000076100ffffffffffffffffffffffff00 {"a":{"$oid":"ffffffffffffffffffffffff"}} 14000000076100ffffffffffffffffffffffff00 ===DONE===mongodb-1.21.0/tests/bson-corpus/oid-valid-003.phpt0000644000175100001660000000163314760300421016622 0ustar --TEST-- ObjectId: Random --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1400000007610056e1fc72e0c917e9c471416100 {"a":{"$oid":"56e1fc72e0c917e9c4714161"}} 1400000007610056e1fc72e0c917e9c471416100 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-decodeError-001.phpt0000644000175100001660000000101114760300421020303 0ustar --TEST-- Regular Expression type: Null byte in pattern string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-decodeError-002.phpt0000644000175100001660000000101114760300421020304 0ustar --TEST-- Regular Expression type: Null byte in flags string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-001.phpt0000644000175100001660000000164614760300421017163 0ustar --TEST-- Regular Expression type: empty regex with no options --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0a0000000b6100000000 {"a":{"$regularExpression":{"pattern":"","options":""}}} 0a0000000b6100000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-002.phpt0000644000175100001660000000167014760300421017161 0ustar --TEST-- Regular Expression type: regex without options --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0d0000000b6100616263000000 {"a":{"$regularExpression":{"pattern":"abc","options":""}}} 0d0000000b6100616263000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-003.phpt0000644000175100001660000000170514760300421017161 0ustar --TEST-- Regular Expression type: regex with options --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f0000000b610061626300696d0000 {"a":{"$regularExpression":{"pattern":"abc","options":"im"}}} 0f0000000b610061626300696d0000 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-004.phpt0000644000175100001660000000233414760300421017161 0ustar --TEST-- Regular Expression type: regex with options (keys reversed) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f0000000b610061626300696d0000 {"a":{"$regularExpression":{"pattern":"abc","options":"im"}}} 0f0000000b610061626300696d0000 0f0000000b610061626300696d0000 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-005.phpt0000644000175100001660000000172414760300421017164 0ustar --TEST-- Regular Expression type: regex with slash --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 110000000b610061622f636400696d0000 {"a":{"$regularExpression":{"pattern":"ab\/cd","options":"im"}}} 110000000b610061622f636400696d0000 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-006.phpt0000644000175100001660000000331314760300421017161 0ustar --TEST-- Regular Expression type: flags not alphabetized --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate BSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromPHP(MongoDB\BSON\Document::fromBSON($degenerateBson)->toPHP())), "\n"; // Degenerate BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($degenerateBson)->toCanonicalExtendedJSON()), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 100000000b610061626300696d780000 {"a":{"$regularExpression":{"pattern":"abc","options":"imx"}}} 100000000b610061626300696d780000 100000000b610061626300696d780000 {"a":{"$regularExpression":{"pattern":"abc","options":"imx"}}} 100000000b610061626300696d780000 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-007.phpt0000644000175100001660000000172214760300421017164 0ustar --TEST-- Regular Expression type: Required escapes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 100000000b610061625c226162000000 {"a":{"$regularExpression":{"pattern":"ab\\\"ab","options":""}}} 100000000b610061625c226162000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-008.phpt0000644000175100001660000000205714760300421017167 0ustar --TEST-- Regular Expression type: Regular expression as value of $regex query operator --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 180000000b247265676578007061747465726e0069780000 {"$regex":{"$regularExpression":{"pattern":"pattern","options":"ix"}}} 180000000b247265676578007061747465726e0069780000 ===DONE===mongodb-1.21.0/tests/bson-corpus/regex-valid-009.phpt0000644000175100001660000000226614760300421017172 0ustar --TEST-- Regular Expression type: Regular expression as value of $regex query operator with $options --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 270000000b247265676578007061747465726e000002246f7074696f6e73000300000069780000 {"$regex":{"$regularExpression":{"pattern":"pattern","options":""}},"$options":"ix"} 270000000b247265676578007061747465726e000002246f7074696f6e73000300000069780000 ===DONE===mongodb-1.21.0/tests/bson-corpus/string-decodeError-001.phpt0000644000175100001660000000100014760300421020475 0ustar --TEST-- String: bad string length: 0 (but no 0x00 either) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/string-decodeError-002.phpt0000644000175100001660000000075414760300421020515 0ustar --TEST-- String: bad string length: -1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/string-decodeError-003.phpt0000644000175100001660000000100114760300421020500 0ustar --TEST-- String: bad string length: eats terminator --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/string-decodeError-004.phpt0000644000175100001660000000102214760300421020504 0ustar --TEST-- String: bad string length: longer than rest of document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/string-decodeError-005.phpt0000644000175100001660000000077414760300421020522 0ustar --TEST-- String: string is not null-terminated --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/string-decodeError-006.phpt0000644000175100001660000000076714760300421020525 0ustar --TEST-- String: empty string, but extra null --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/string-decodeError-007.phpt0000644000175100001660000000075014760300421020516 0ustar --TEST-- String: invalid UTF-8 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/string-valid-001.phpt0000644000175100001660000000146114760300421017352 0ustar --TEST-- String: Empty string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0d000000026100010000000000 {"a":""} 0d000000026100010000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/string-valid-002.phpt0000644000175100001660000000147514760300421017360 0ustar --TEST-- String: Single character --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0e00000002610002000000620000 {"a":"b"} 0e00000002610002000000620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/string-valid-003.phpt0000644000175100001660000000162414760300421017355 0ustar --TEST-- String: Multi-character --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000261000d0000006162616261626162616261620000 {"a":"abababababab"} 190000000261000d0000006162616261626162616261620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/string-valid-004.phpt0000644000175100001660000000171614760300421017360 0ustar --TEST-- String: two-byte UTF-8 (é) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000261000d000000c3a9c3a9c3a9c3a9c3a9c3a90000 {"a":"\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9"} 190000000261000d000000c3a9c3a9c3a9c3a9c3a9c3a90000 ===DONE===mongodb-1.21.0/tests/bson-corpus/string-valid-005.phpt0000644000175100001660000000166714760300421017366 0ustar --TEST-- String: three-byte UTF-8 (☆) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000261000d000000e29886e29886e29886e298860000 {"a":"\u2606\u2606\u2606\u2606"} 190000000261000d000000e29886e29886e29886e298860000 ===DONE===mongodb-1.21.0/tests/bson-corpus/string-valid-006.phpt0000644000175100001660000000165114760300421017360 0ustar --TEST-- String: Embedded nulls --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000261000d0000006162006261620062616261620000 {"a":"ab\u0000bab\u0000babab"} 190000000261000d0000006162006261620062616261620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/string-valid-007.phpt0000644000175100001660000000261714760300421017364 0ustar --TEST-- String: Required escapes --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 320000000261002600000061625c220102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f61620000 {"a":"ab\\\"\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001fab"} 320000000261002600000061625c220102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f61620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-decodeError-001.phpt0000644000175100001660000000100014760300421020474 0ustar --TEST-- Symbol: bad symbol length: 0 (but no 0x00 either) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-decodeError-002.phpt0000644000175100001660000000075414760300421020514 0ustar --TEST-- Symbol: bad symbol length: -1 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-decodeError-003.phpt0000644000175100001660000000100114760300421020477 0ustar --TEST-- Symbol: bad symbol length: eats terminator --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-decodeError-004.phpt0000644000175100001660000000102214760300421020503 0ustar --TEST-- Symbol: bad symbol length: longer than rest of document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-decodeError-005.phpt0000644000175100001660000000077414760300421020521 0ustar --TEST-- Symbol: symbol is not null-terminated --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-decodeError-006.phpt0000644000175100001660000000076714760300421020524 0ustar --TEST-- Symbol: empty symbol, but extra null --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-decodeError-007.phpt0000644000175100001660000000075014760300421020515 0ustar --TEST-- Symbol: invalid UTF-8 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-valid-001.phpt0000644000175100001660000000164214760300421017352 0ustar --TEST-- Symbol: Empty string --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0d0000000e6100010000000000 {"a":{"$symbol":""}} 0d0000000e6100010000000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-valid-002.phpt0000644000175100001660000000166114760300421017354 0ustar --TEST-- Symbol: Single character --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0e0000000e610002000000620000 {"a":{"$symbol":"b"}} 0e0000000e610002000000620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-valid-003.phpt0000644000175100001660000000205114760300421017347 0ustar --TEST-- Symbol: Multi-character --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000e61000d0000006162616261626162616261620000 {"a":{"$symbol":"abababababab"}} 190000000e61000d0000006162616261626162616261620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-valid-004.phpt0000644000175100001660000000210514760300421017350 0ustar --TEST-- Symbol: two-byte UTF-8 (é) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000e61000d000000c3a9c3a9c3a9c3a9c3a9c3a90000 {"a":{"$symbol":"\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9"}} 190000000e61000d000000c3a9c3a9c3a9c3a9c3a9c3a90000 ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-valid-005.phpt0000644000175100001660000000207414760300421017356 0ustar --TEST-- Symbol: three-byte UTF-8 (☆) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000e61000d000000e29886e29886e29886e298860000 {"a":{"$symbol":"\u2606\u2606\u2606\u2606"}} 190000000e61000d000000e29886e29886e29886e298860000 ===DONE===mongodb-1.21.0/tests/bson-corpus/symbol-valid-006.phpt0000644000175100001660000000211214760300421017350 0ustar --TEST-- Symbol: Embedded nulls --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 190000000e61000d0000006162006261620062616261620000 {"a":{"$symbol":"ab\u0000bab\u0000babab"}} 190000000e61000d0000006162006261620062616261620000 ===DONE===mongodb-1.21.0/tests/bson-corpus/timestamp-decodeError-001.phpt0000644000175100001660000000077614760300421021215 0ustar --TEST-- Timestamp type: Truncated timestamp field --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/timestamp-valid-001.phpt0000644000175100001660000000165014760300421020047 0ustar --TEST-- Timestamp type: Timestamp: (123456789, 42) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 100000001161002a00000015cd5b0700 {"a":{"$timestamp":{"t":123456789,"i":42}}} 100000001161002a00000015cd5b0700 ===DONE===mongodb-1.21.0/tests/bson-corpus/timestamp-valid-002.phpt0000644000175100001660000000226214760300421020050 0ustar --TEST-- Timestamp type: Timestamp: (123456789, 42) (keys reversed) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; // Degenerate extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($degenerateExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 100000001161002a00000015cd5b0700 {"a":{"$timestamp":{"t":123456789,"i":42}}} 100000001161002a00000015cd5b0700 100000001161002a00000015cd5b0700 ===DONE===mongodb-1.21.0/tests/bson-corpus/timestamp-valid-003.phpt0000644000175100001660000000174014760300421020051 0ustar --TEST-- Timestamp type: Timestamp with high-order bit set on both seconds and increment --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 10000000116100ffffffffffffffff00 {"a":{"$timestamp":{"t":4294967295,"i":4294967295}}} 10000000116100ffffffffffffffff00 ===DONE===mongodb-1.21.0/tests/bson-corpus/timestamp-valid-004.phpt0000644000175100001660000000176114760300421020055 0ustar --TEST-- Timestamp type: Timestamp with high-order bit set on both seconds and increment (not UINT32_MAX) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1000000011610000286bee00286bee00 {"a":{"$timestamp":{"t":4000000000,"i":4000000000}}} 1000000011610000286bee00286bee00 ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-001.phpt0000644000175100001660000000110114760300421017773 0ustar --TEST-- Top-level document validity: An object size that's too small to even include the object size, but is a well-formed, empty object --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-002.phpt0000644000175100001660000000106714760300421020007 0ustar --TEST-- Top-level document validity: An object size that's only enough for the object size, but is a well-formed, empty object --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-003.phpt0000644000175100001660000000102314760300421020000 0ustar --TEST-- Top-level document validity: One object, with length shorter than size (missing EOO) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-004.phpt0000644000175100001660000000104614760300421020006 0ustar --TEST-- Top-level document validity: One object, sized correctly, with a spot for an EOO, but the EOO is 0x01 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-005.phpt0000644000175100001660000000104614760300421020007 0ustar --TEST-- Top-level document validity: One object, sized correctly, with a spot for an EOO, but the EOO is 0xff --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-006.phpt0000644000175100001660000000104614760300421020010 0ustar --TEST-- Top-level document validity: One object, sized correctly, with a spot for an EOO, but the EOO is 0x70 --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-007.phpt0000644000175100001660000000102714760300421020010 0ustar --TEST-- Top-level document validity: Byte count is zero (with non-zero input length) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-008.phpt0000644000175100001660000000105514760300421020012 0ustar --TEST-- Top-level document validity: Stated length exceeds byte count, with truncated document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-009.phpt0000644000175100001660000000107714760300421020017 0ustar --TEST-- Top-level document validity: Stated length less than byte count, with garbage after envelope --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-010.phpt0000644000175100001660000000105514760300421020003 0ustar --TEST-- Top-level document validity: Stated length exceeds byte count, with valid envelope --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-011.phpt0000644000175100001660000000105714760300421020006 0ustar --TEST-- Top-level document validity: Stated length less than byte count, with valid envelope --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-012.phpt0000644000175100001660000000077514760300421020015 0ustar --TEST-- Top-level document validity: Invalid BSON type low range --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-013.phpt0000644000175100001660000000077614760300421020017 0ustar --TEST-- Top-level document validity: Invalid BSON type high range --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-014.phpt0000644000175100001660000000077414760300421020016 0ustar --TEST-- Top-level document validity: Document truncated mid-key --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-decodeError-015.phpt0000644000175100001660000000100714760300421020005 0ustar --TEST-- Top-level document validity: Null byte in document key --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- toPHP(); }, 'MongoDB\Driver\Exception\UnexpectedValueException'); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-001.phpt0000644000175100001660000000103614760300421017671 0ustar --TEST-- Top-level document validity: Bad $regularExpression (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-002.phpt0000644000175100001660000000100614760300421017667 0ustar --TEST-- Top-level document validity: Bad $regularExpression (missing options field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-003.phpt0000644000175100001660000000103514760300421017672 0ustar --TEST-- Top-level document validity: Bad $regularExpression (pattern is number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-004.phpt0000644000175100001660000000103614760300421017674 0ustar --TEST-- Top-level document validity: Bad $regularExpression (options are number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-005.phpt0000644000175100001660000000100414760300421017670 0ustar --TEST-- Top-level document validity: Bad $regularExpression (missing pattern field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-006.phpt0000644000175100001660000000073014760300421017676 0ustar --TEST-- Top-level document validity: Bad $oid (number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-007.phpt0000644000175100001660000000077414760300421017707 0ustar --TEST-- Top-level document validity: Bad $oid (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-008.phpt0000644000175100001660000000074414760300421017705 0ustar --TEST-- Top-level document validity: Bad $numberInt (number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-009.phpt0000644000175100001660000000076214760300421017706 0ustar --TEST-- Top-level document validity: Bad $numberInt (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-010.phpt0000644000175100001660000000074614760300421017700 0ustar --TEST-- Top-level document validity: Bad $numberLong (number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-011.phpt0000644000175100001660000000076414760300421017701 0ustar --TEST-- Top-level document validity: Bad $numberLong (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-012.phpt0000644000175100001660000000075214760300421017677 0ustar --TEST-- Top-level document validity: Bad $numberDouble (number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-013.phpt0000644000175100001660000000077014760300421017700 0ustar --TEST-- Top-level document validity: Bad $numberDouble (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-014.phpt0000644000175100001660000000075414760300421017703 0ustar --TEST-- Top-level document validity: Bad $numberDecimal (number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-015.phpt0000644000175100001660000000077214760300421017704 0ustar --TEST-- Top-level document validity: Bad $numberDecimal (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-016.phpt0000644000175100001660000000100614760300421017674 0ustar --TEST-- Top-level document validity: Bad $binary (binary is number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-017.phpt0000644000175100001660000000100214760300421017671 0ustar --TEST-- Top-level document validity: Bad $binary (type is number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-018.phpt0000644000175100001660000000075214760300421017705 0ustar --TEST-- Top-level document validity: Bad $binary (missing $type) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-019.phpt0000644000175100001660000000075314760300421017707 0ustar --TEST-- Top-level document validity: Bad $binary (missing $binary) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-020.phpt0000644000175100001660000000101214760300421017664 0ustar --TEST-- Top-level document validity: Bad $binary (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-021.phpt0000644000175100001660000000074214760300421017676 0ustar --TEST-- Top-level document validity: Bad $code (type is number, not string) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-022.phpt0000644000175100001660000000101514760300421017671 0ustar --TEST-- Top-level document validity: Bad $code (type is number, not string) when $scope is also present --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-023.phpt0000644000175100001660000000074614760300421017704 0ustar --TEST-- Top-level document validity: Bad $code (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-024.phpt0000644000175100001660000000077314760300421017705 0ustar --TEST-- Top-level document validity: Bad $code with $scope (scope is number, not doc) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-025.phpt0000644000175100001660000000075214760300421017703 0ustar --TEST-- Top-level document validity: Bad $timestamp (type is number, not doc) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-026.phpt0000644000175100001660000000101514760300421017675 0ustar --TEST-- Top-level document validity: Bad $timestamp ('t' type is string, not number) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-027.phpt0000644000175100001660000000101514760300421017676 0ustar --TEST-- Top-level document validity: Bad $timestamp ('i' type is string, not number) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-028.phpt0000644000175100001660000000105314760300421017701 0ustar --TEST-- Top-level document validity: Bad $timestamp (extra field at same level as $timestamp) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-029.phpt0000644000175100001660000000105014760300421017677 0ustar --TEST-- Top-level document validity: Bad $timestamp (extra field at same level as t and i) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-030.phpt0000644000175100001660000000074714760300421017703 0ustar --TEST-- Top-level document validity: Bad $timestamp (missing t) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-031.phpt0000644000175100001660000000075614760300421017704 0ustar --TEST-- Top-level document validity: Bad $timestamp (missing i) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-032.phpt0000644000175100001660000000105214760300421017673 0ustar --TEST-- Top-level document validity: Bad $date (number, not string or hash) --XFAIL-- Legacy extended JSON $date syntax uses numbers (CDRIVER-2223) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-033.phpt0000644000175100001660000000100514760300421017672 0ustar --TEST-- Top-level document validity: Bad $date (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-034.phpt0000644000175100001660000000074214760300421017702 0ustar --TEST-- Top-level document validity: Bad $minKey (boolean, not integer) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-035.phpt0000644000175100001660000000073014760300421017700 0ustar --TEST-- Top-level document validity: Bad $minKey (wrong integer) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-036.phpt0000644000175100001660000000075114760300421017704 0ustar --TEST-- Top-level document validity: Bad $minKey (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-037.phpt0000644000175100001660000000074214760300421017705 0ustar --TEST-- Top-level document validity: Bad $maxKey (boolean, not integer) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-038.phpt0000644000175100001660000000073014760300421017703 0ustar --TEST-- Top-level document validity: Bad $maxKey (wrong integer) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-039.phpt0000644000175100001660000000075114760300421017707 0ustar --TEST-- Top-level document validity: Bad $maxKey (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-040.phpt0000644000175100001660000000110614760300421017672 0ustar --TEST-- Top-level document validity: Bad DBpointer (extra field) --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-041.phpt0000644000175100001660000000071714760300421017702 0ustar --TEST-- Top-level document validity: Null byte in document key --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-042.phpt0000644000175100001660000000073314760300421017701 0ustar --TEST-- Top-level document validity: Null byte in sub-document key --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-043.phpt0000644000175100001660000000102714760300421017677 0ustar --TEST-- Top-level document validity: Null byte in $regularExpression pattern --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-parseError-044.phpt0000644000175100001660000000102714760300421017700 0ustar --TEST-- Top-level document validity: Null byte in $regularExpression options --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE===mongodb-1.21.0/tests/bson-corpus/top-valid-001.phpt0000644000175100001660000000162714760300421016652 0ustar --TEST-- Top-level document validity: Dollar-prefixed key in top-level document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0f00000010246b6579002a00000000 {"$key":{"$numberInt":"42"}} 0f00000010246b6579002a00000000 ===DONE===mongodb-1.21.0/tests/bson-corpus/top-valid-002.phpt0000644000175100001660000000154414760300421016651 0ustar --TEST-- Top-level document validity: Dollar as key in top-level document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0e00000002240002000000610000 {"$":"a"} 0e00000002240002000000610000 ===DONE===mongodb-1.21.0/tests/bson-corpus/top-valid-003.phpt0000644000175100001660000000156114760300421016651 0ustar --TEST-- Top-level document validity: Dotted key in top-level document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 1000000002612e620002000000630000 {"a.b":"c"} 1000000002612e620002000000630000 ===DONE===mongodb-1.21.0/tests/bson-corpus/top-valid-004.phpt0000644000175100001660000000154114760300421016650 0ustar --TEST-- Top-level document validity: Dot as key in top-level document --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0e000000022e0002000000610000 {".":"a"} 0e000000022e0002000000610000 ===DONE===mongodb-1.21.0/tests/bson-corpus/undefined-valid-001.phpt0000644000175100001660000000163314760300421020006 0ustar --TEST-- Undefined type (deprecated): Undefined --DESCRIPTION-- Generated by scripts/convert-bson-corpus-tests.php DO NOT EDIT THIS FILE --FILE-- BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromBSON($canonicalBson)), "\n"; // Canonical BSON -> BSON object -> Canonical extJSON echo json_canonicalize(MongoDB\BSON\Document::fromBSON($canonicalBson)->toCanonicalExtendedJSON()), "\n"; // Canonical extJSON -> BSON object -> Canonical BSON echo bin2hex((string) MongoDB\BSON\Document::fromJSON($canonicalExtJson)), "\n"; ?> ===DONE=== --EXPECT-- 0800000006610000 {"a":{"$undefined":true}} 0800000006610000 ===DONE===mongodb-1.21.0/tests/bson/bson-binary-001.phpt0000644000175100001660000001154714760300421015667 0ustar --TEST-- MongoDB\BSON\Binary construction from various types --FILE-- getData() === 'randomBinaryData'); var_dump($binary->getType() === $type); $tests[] = array("binary" => $binary); } foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Test#0 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "00" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "00" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "00" } } }" bool(true) Test#1 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "01" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "01" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "01" } } }" bool(true) Test#2 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "02" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "02" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "02" } } }" bool(true) Test#3 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "03" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "03" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "03" } } }" bool(true) Test#4 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "04" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "04" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "04" } } }" bool(true) Test#5 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "05" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "05" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "05" } } }" bool(true) Test#6 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "06" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "06" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "06" } } }" bool(true) Test#7 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "07" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "07" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "07" } } }" bool(true) Test#8 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "08" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "08" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "08" } } }" bool(true) Test#9 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "80" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "80" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "80" } } }" bool(true) Test#10 { "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "85" } } } string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "85" } } }" string(90) "{ "binary" : { "$binary" : { "base64" : "cmFuZG9tQmluYXJ5RGF0YQ==", "subType" : "85" } } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-002.phpt0000644000175100001660000000060314760300421015657 0ustar --TEST-- MongoDB\BSON\Binary::__construct() defaults to TYPE_GENERIC --FILE-- getData() === 'randomBinaryString'); var_dump($binaryWithDefaultType->getType() === MongoDB\BSON\Binary::TYPE_GENERIC); ?> ===DONE=== --EXPECT-- bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-clone-001.phpt0000644000175100001660000000363614760300421016765 0ustar --TEST-- MongoDB\BSON\Binary can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(0) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(1) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(2) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(3) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(4) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(5) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(128) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(133) } ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-clone-002.phpt0000644000175100001660000000363614760300421016766 0ustar --TEST-- MongoDB\BSON\Binary can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(0) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(1) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(2) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(3) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(4) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(5) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(128) } bool(true) bool(false) object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(16) "randomBinaryData" ["type"]=> int(133) } ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-compare-001.phpt0000644000175100001660000000205314760300421017303 0ustar --TEST-- MongoDB\BSON\Binary comparisons --FILE-- new MongoDB\BSON\Binary('foobar', 1)); // Data length is compared first var_dump(new MongoDB\BSON\Binary('c', 1) < new MongoDB\BSON\Binary('aa', 0)); var_dump(new MongoDB\BSON\Binary('bb', 0) > new MongoDB\BSON\Binary('a', 1)); // Type is compared second var_dump(new MongoDB\BSON\Binary('foobar', 1) < new MongoDB\BSON\Binary('foobar', 2)); var_dump(new MongoDB\BSON\Binary('foobar', 1) > new MongoDB\BSON\Binary('foobar', 0)); // Data is compared last var_dump(new MongoDB\BSON\Binary('foobar', 1) < new MongoDB\BSON\Binary('foobat', 1)); var_dump(new MongoDB\BSON\Binary('foobar', 1) > new MongoDB\BSON\Binary('foobap', 1)); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-compare-002.phpt0000644000175100001660000000220314760300421017301 0ustar --TEST-- MongoDB\BSON\Binary comparisons with null bytes --FILE-- new MongoDB\BSON\Binary("foo\x00bar", 1)); // Data length is compared first var_dump(new MongoDB\BSON\Binary("c\x00", 1) < new MongoDB\BSON\Binary("a\x00a", 0)); var_dump(new MongoDB\BSON\Binary("b\x00b", 0) > new MongoDB\BSON\Binary("a\x00", 1)); // Type is compared second var_dump(new MongoDB\BSON\Binary("foo\x00bar", 1) < new MongoDB\BSON\Binary("foo\x00bar", 2)); var_dump(new MongoDB\BSON\Binary("foo\x00bar", 1) > new MongoDB\BSON\Binary("foo\x00bar", 0)); // Data is compared last var_dump(new MongoDB\BSON\Binary("foo\x00bar", 1) < new MongoDB\BSON\Binary("foo\x00bat", 1)); var_dump(new MongoDB\BSON\Binary("foo\x00bar", 1) > new MongoDB\BSON\Binary("foo\x00bap", 1)); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-constants.phpt0000644000175100001660000000102614760300421017372 0ustar --TEST-- MongoDB\BSON\Binary constants --FILE-- ===DONE=== --EXPECT-- int(0) int(1) int(2) int(3) int(4) int(5) int(6) int(7) int(8) int(128) ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-get_properties-001.phpt0000644000175100001660000000050714760300421020712 0ustar --TEST-- MongoDB\BSON\Binary get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECT-- array(2) { ["data"]=> string(6) "foobar" ["type"]=> int(0) } ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-get_properties-002.phpt0000644000175100001660000000054414760300421020714 0ustar --TEST-- MongoDB\BSON\Binary get_properties handler (foreach) --FILE-- $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECT-- string(4) "data" string(6) "foobar" string(4) "type" int(0) ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-jsonserialize-001.phpt0000644000175100001660000000047614760300421020545 0ustar --TEST-- MongoDB\BSON\Binary::jsonSerialize() return value --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(2) { ["$binary"]=> string(20) "Z2FyZ2xlYmxhc3Rlcg==" ["$type"]=> string(2) "18" } ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-jsonserialize-002.phpt0000644000175100001660000000122414760300421020536 0ustar --TEST-- MongoDB\BSON\Binary::jsonSerialize() with json_encode() --FILE-- new MongoDB\BSON\Binary('gargleblaster', 24)]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$binary" : { "base64" : "Z2FyZ2xlYmxhc3Rlcg==", "subType" : "18" } } } {"foo":{"$binary":"Z2FyZ2xlYmxhc3Rlcg==","$type":"18"}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(13) "gargleblaster" ["type"]=> int(24) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-serialization-002.phpt0000644000175100001660000000372614760300421020543 0ustar --TEST-- MongoDB\BSON\Binary serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(6) "foobar" ["type"]=> int(0) } string(70) "O:19:"MongoDB\BSON\Binary":2:{s:4:"data";s:6:"foobar";s:4:"type";i:0;}" object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(6) "foobar" ["type"]=> int(0) } object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(0) "" ["type"]=> int(0) } string(64) "O:19:"MongoDB\BSON\Binary":2:{s:4:"data";s:0:"";s:4:"type";i:0;}" object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(0) "" ["type"]=> int(0) } object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(4) "%sfoo" ["type"]=> int(0) } string(68) "O:19:"MongoDB\BSON\Binary":2:{s:4:"data";s:4:"%sfoo";s:4:"type";i:0;}" object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(4) "%sfoo" ["type"]=> int(0) } object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%s" ["type"]=> int(4) } string(81) "O:19:"MongoDB\BSON\Binary":2:{s:4:"data";s:16:"%s";s:4:"type";i:4;}" object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%s" ["type"]=> int(4) } object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%s" ["type"]=> int(5) } string(81) "O:19:"MongoDB\BSON\Binary":2:{s:4:"data";s:16:"%s";s:4:"type";i:5;}" object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%s" ["type"]=> int(5) } ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-serialization_error-001.phpt0000644000175100001660000000224014760300421021741 0ustar --TEST-- MongoDB\BSON\Binary unserialization requires "data" string and "type" integer fields (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-serialization_error-002.phpt0000644000175100001660000000150214760300421021742 0ustar --TEST-- MongoDB\BSON\Binary unserialization requires unsigned 8-bit integer for type (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected type to be an unsigned 8-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected type to be an unsigned 8-bit integer, 256 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-serialization_error-003.phpt0000644000175100001660000000263714760300421021755 0ustar --TEST-- MongoDB\BSON\Binary unserialization requires 16-byte data length for UUID types (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 15 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 17 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 15 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 17 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-serialization_error-004.phpt0000644000175100001660000000222214760300421021744 0ustar --TEST-- MongoDB\BSON\Binary unserialization requires "data" string and "type" integer fields (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-serialization_error-005.phpt0000644000175100001660000000147314760300421021754 0ustar --TEST-- MongoDB\BSON\Binary unserialization requires unsigned 8-bit integer for type (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected type to be an unsigned 8-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected type to be an unsigned 8-bit integer, 256 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-serialization_error-006.phpt0000644000175100001660000000261214760300421021751 0ustar --TEST-- MongoDB\BSON\Binary unserialization requires 16-byte data length for UUID types (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 15 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 17 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 15 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 17 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-set_state-001.phpt0000644000175100001660000000211614760300421017650 0ustar --TEST-- MongoDB\BSON\Binary::__set_state() --FILE-- $data, 'type' => $type, ])); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Binary::__set_state(array( 'data' => 'foobar', 'type' => 0, )) %r\\?%rMongoDB\BSON\Binary::__set_state(array( 'data' => '', 'type' => 0, )) %r\\?%rMongoDB\BSON\Binary::__set_state(array( 'data' => '' . "\0" . 'foo', 'type' => 0, )) %r\\?%rMongoDB\BSON\Binary::__set_state(array( 'data' => '>Egè›Ó¤VBfUD' . "\0" . '' . "\0" . '', 'type' => 4, )) %r\\?%rMongoDB\BSON\Binary::__set_state(array( 'data' => '8Xö"0¬<‘_0 fCÆ?', 'type' => 5, )) ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-set_state_error-001.phpt0000644000175100001660000000210114760300421021053 0ustar --TEST-- MongoDB\BSON\Binary::__set_state() requires "data" string and "type" integer fields --FILE-- 'foobar']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Binary::__set_state(['type' => 0]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Binary::__set_state(['data' => 0, 'type' => 'foobar']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary initialization requires "data" string and "type" integer fields ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-set_state_error-002.phpt0000644000175100001660000000136614760300421021070 0ustar --TEST-- MongoDB\BSON\Binary::__set_state() requires unsigned 8-bit integer for type --FILE-- 'foobar', 'type' => -1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Binary::__set_state(['data' => 'foobar', 'type' => 256]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected type to be an unsigned 8-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected type to be an unsigned 8-bit integer, 256 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-set_state_error-003.phpt0000644000175100001660000000263114760300421021065 0ustar --TEST-- MongoDB\BSON\Binary::__set_state() requires 16-byte data length for UUID types --FILE-- '0123456789abcde', 'type' => MongoDB\BSON\Binary::TYPE_OLD_UUID]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Binary::__set_state(['data' => '0123456789abcdefg', 'type' => MongoDB\BSON\Binary::TYPE_OLD_UUID]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Binary::__set_state(['data' => '0123456789abcde', 'type' => MongoDB\BSON\Binary::TYPE_UUID]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Binary::__set_state(['data' => '0123456789abcdefg', 'type' => MongoDB\BSON\Binary::TYPE_UUID]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 15 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 17 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 15 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 17 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binary-tostring-001.phpt0000644000175100001660000000036114760300421017526 0ustar --TEST-- MongoDB\BSON\Binary::__toString() --FILE-- ===DONE=== --EXPECT-- string(6) "foobar" ===DONE=== mongodb-1.21.0/tests/bson/bson-binary_error-001.phpt0000644000175100001660000000225414760300421017073 0ustar --TEST-- MongoDB\BSON\Binary argument count errors --SKIPIF-- =', '7.99'); ?> --FILE-- getData(2); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() use ($binary) { $binary->getType(2); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { new MongoDB\BSON\Binary(); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary::getData() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary::getType() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Binary::__construct() expects at least 1 %r(argument|parameter)%r, 0 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binary_error-002.phpt0000644000175100001660000000035714760300421017076 0ustar --TEST-- MongoDB\BSON\Binary cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyBinary %s final class %SMongoDB\BSON\Binary%S in %s on line %d mongodb-1.21.0/tests/bson/bson-binary_error-003.phpt0000644000175100001660000000125714760300421017077 0ustar --TEST-- MongoDB\BSON\Binary constructor requires unsigned 8-bit integer for type --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected type to be an unsigned 8-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected type to be an unsigned 8-bit integer, 256 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binary_error-004.phpt0000644000175100001660000000243214760300421017074 0ustar --TEST-- MongoDB\BSON\Binary constructor requires 16-byte data length for UUID types --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 15 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 17 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 15 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected UUID length to be 16 bytes, 17 given ===DONE=== mongodb-1.21.0/tests/bson/bson-binaryinterface-001.phpt0000644000175100001660000000044614760300421017544 0ustar --TEST-- MongoDB\BSON\BinaryInterface is implemented by MongoDB\BSON\Binary --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-001.phpt0000644000175100001660000000172114760300421016362 0ustar --TEST-- MongoDB\BSON\DBPointer #001 --FILE-- toPHP(), ); foreach($tests as $n => $test) { echo "Test#{$n}", "\n"; $s = fromPHP($test); $testagain = toPHP($s); var_dump($test->dbref instanceof MongoDB\BSON\DBPointer); var_dump($testagain->dbref instanceof MongoDB\BSON\DBPointer); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- Test#0 bool(true) bool(true) string(108) "{ "dbref" : { "$dbPointer" : { "$ref" : "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" } } } }" string(108) "{ "dbref" : { "$dbPointer" : { "$ref" : "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" } } } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-002.phpt0000644000175100001660000000066214760300421016366 0ustar --TEST-- MongoDB\BSON\DBPointer debug handler --FILE-- toPHP(); var_dump($dbptr->dbref); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\DBPointer)#%d (%d) { ["ref"]=> string(11) "phongo.test" ["id"]=> string(24) "5a2e78accd485d55b405ac12" } ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-clone-001.phpt0000644000175100001660000000137014760300421017460 0ustar --TEST-- MongoDB\BSON\DBPointer can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- toPHP(); $dbPointer = $test->dbref; $clone = clone($dbPointer); var_dump($clone == $dbPointer); var_dump($clone === $dbPointer); unset($dbPointer); var_dump($clone); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\DBPointer)#%d (2) { ["ref"]=> string(11) "phongo.test" ["id"]=> string(24) "5a2e78accd485d55b405ac12" } ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-clone-002.phpt0000644000175100001660000000137014760300421017461 0ustar --TEST-- MongoDB\BSON\DBPointer can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- toPHP(); $dbPointer = $test->dbref; $clone = clone($dbPointer); var_dump($clone == $dbPointer); var_dump($clone === $dbPointer); unset($dbPointer); var_dump($clone); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\DBPointer)#%d (2) { ["ref"]=> string(11) "phongo.test" ["id"]=> string(24) "5a2e78accd485d55b405ac12" } ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-compare-001.phpt0000644000175100001660000000246014760300421020007 0ustar --TEST-- MongoDB\BSON\DBPointer comparisons --FILE-- toPHP(); $jsonTest1a = MongoDB\BSON\Document::fromJSON('{ "dbref": {"$dbPointer": {"$ref": "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b4051111" } }} }')->toPHP(); $jsonTest1b = MongoDB\BSON\Document::fromJSON('{ "dbref": {"$dbPointer": {"$ref": "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b4051111" } }} }')->toPHP(); $jsonTest2 = MongoDB\BSON\Document::fromJSON('{ "dbref": {"$dbPointer": {"$ref": "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b4052222" } }} }')->toPHP(); $jsonAAAA = MongoDB\BSON\Document::fromJSON('{ "dbref": {"$dbPointer": {"$ref": "phongo.aaaa", "$id" : { "$oid" : "5a2e78accd485d55b4051111" } }} }')->toPHP(); $jsonZZZZ = MongoDB\BSON\Document::fromJSON('{ "dbref": {"$dbPointer": {"$ref": "phongo.zzzz", "$id" : { "$oid" : "5a2e78accd485d55b4051111" } }} }')->toPHP(); var_dump($jsonTest1a == $jsonTest1b); var_dump($jsonTest0 < $jsonTest1b); var_dump($jsonTest2 > $jsonTest1b); var_dump($jsonAAAA < $jsonTest1b); var_dump($jsonZZZZ > $jsonTest1b); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-get_properties-001.phpt0000644000175100001660000000071114760300421021411 0ustar --TEST-- MongoDB\BSON\DBPointer get_properties handler (get_object_vars) --FILE-- toPHP(); $dbptr = $document->dbptr; var_dump(get_object_vars($dbptr)); ?> ===DONE=== --EXPECT-- array(2) { ["ref"]=> string(11) "phongo.test" ["id"]=> string(24) "5a2e78accd485d55b405ac12" } ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-get_properties-002.phpt0000644000175100001660000000074614760300421021422 0ustar --TEST-- MongoDB\BSON\DBPointer get_properties handler (foreach) --FILE-- toPHP(); $dbptr = $document->dbptr; foreach ($dbptr as $key => $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECT-- string(3) "ref" string(11) "phongo.test" string(2) "id" string(24) "5a2e78accd485d55b405ac12" ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-jsonserialize-001.phpt0000644000175100001660000000101214760300421021232 0ustar --TEST-- MongoDB\BSON\DBPointer::jsonSerialize() return value --FILE-- toPHP()->dbref; var_dump($dbref->jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$dbPointer"]=> array(2) { ["$ref"]=> string(11) "phongo.test" ["$id"]=> array(1) { ["$oid"]=> string(24) "5a2e78accd485d55b4050000" } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-jsonserialize-003.phpt0000644000175100001660000000150414760300421021242 0ustar --TEST-- MongoDB\BSON\DBPointer::jsonSerialize() with json_encode() --FILE-- toPHP(); $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$dbPointer" : { "$ref" : "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b4050000" } } } } {"foo":{"$dbPointer":{"$ref":"phongo.test","$id":{"$oid":"5a2e78accd485d55b4050000"}}}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\DBPointer)#%d (%d) { ["ref"]=> string(11) "phongo.test" ["id"]=> string(24) "5a2e78accd485d55b4050000" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-serialization-002.phpt0000644000175100001660000000142514760300421021237 0ustar --TEST-- MongoDB\BSON\DBPointer serialization (__serialize and __unserialize) --FILE-- toPHP()->dbref; var_dump($test); var_dump($s = serialize($test)); var_dump(unserialize($s)); echo "\n"; ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\DBPointer)#%d (%d) { ["ref"]=> string(11) "phongo.test" ["id"]=> string(24) "5a2e78accd485d55b4050000" } string(104) "O:22:"MongoDB\BSON\DBPointer":2:{s:3:"ref";s:11:"phongo.test";s:2:"id";s:24:"5a2e78accd485d55b4050000";}" object(MongoDB\BSON\DBPointer)#%d (%d) { ["ref"]=> string(11) "phongo.test" ["id"]=> string(24) "5a2e78accd485d55b4050000" } ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-serialization_error-001.phpt0000644000175100001660000000153014760300421022444 0ustar --TEST-- MongoDB\BSON\DBPointer unserialization requires "ref" and "id" string fields (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\DBPointer initialization requires "ref" and "id" string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\DBPointer initialization requires "ref" and "id" string fields ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-serialization_error-002.phpt0000644000175100001660000000157414760300421022455 0ustar --TEST-- MongoDB\BSON\DBPointer unserialization requires "id" string field to be valid (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: QQQQ78accd485d55b4050000 OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: 52e78accd485d55b4050000 ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-serialization_error-003.phpt0000644000175100001660000000151314760300421022447 0ustar --TEST-- MongoDB\BSON\DBPointer unserialization requires "ref" and "id" string fields (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\DBPointer initialization requires "ref" and "id" string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\DBPointer initialization requires "ref" and "id" string fields ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-serialization_error-004.phpt0000644000175100001660000000156514760300421022457 0ustar --TEST-- MongoDB\BSON\DBPointer unserialization requires "id" string field to be valid (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: QQQQ78accd485d55b4050000 OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: 52e78accd485d55b4050000 ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-set_state-001.phpt0000644000175100001660000000116614760300421020356 0ustar --TEST-- MongoDB\BSON\DBPointer::__set_state() --FILE-- toPHP()->dbref; $s = var_export($dbPointer, true); echo $s, "\n"; var_dump(eval('return ' . $s . ';')); ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\DBPointer::__set_state(array( 'ref' => 'phongo.test', 'id' => '5a2e78accd485d55b4050000', )) object(MongoDB\BSON\DBPointer)#%d (%d) { ["ref"]=> string(11) "phongo.test" ["id"]=> string(24) "5a2e78accd485d55b4050000" } ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer-tostring-001.phpt0000644000175100001660000000055114760300421020231 0ustar --TEST-- MongoDB\BSON\DBPointer::__toString() --FILE-- toPHP()->dbref; var_dump((string) $dbref); ?> ===DONE=== --EXPECT-- string(38) "[phongo.test/5a2e78accd485d55b4050000]" ===DONE=== mongodb-1.21.0/tests/bson/bson-dbpointer_error-002.phpt0000644000175100001660000000037614760300421017601 0ustar --TEST-- MongoDB\BSON\DBPointer cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyDBPointer %s final class %SMongoDB\BSON\DBPointer%S in %s on line %d mongodb-1.21.0/tests/bson/bson-decimal128-001.phpt0000644000175100001660000000103414760300421016222 0ustar --TEST-- MongoDB\BSON\Decimal128 --FILE-- ===DONE=== --EXPECT-- 1234.5678 -1234.5678 1.234E+8 1.234E+8 1.23456E-75 -234.567 2.345E+9 0.002345 1234.5678 -1234.5678 -234.567 123400000 1.23456E-75 ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-002.phpt0000644000175100001660000000046214760300421016227 0ustar --TEST-- MongoDB\BSON\Decimal128 NaN values --FILE-- ===DONE=== --EXPECT-- NaN NaN NaN NaN NaN NaN ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-003.phpt0000644000175100001660000000066414760300421016234 0ustar --TEST-- MongoDB\BSON\Decimal128 Infinity values --FILE-- ===DONE=== --EXPECT-- Infinity Infinity Infinity Infinity Infinity Infinity Infinity Infinity ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-004.phpt0000644000175100001660000000074014760300421016230 0ustar --TEST-- MongoDB\BSON\Decimal128 debug handler --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(9) "1234.5678" } object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(3) "NaN" } object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(8) "Infinity" } ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-clone-001.phpt0000644000175100001660000000101114760300421017313 0ustar --TEST-- MongoDB\BSON\Decimal128 can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Decimal128)#%d (1) { ["dec"]=> string(9) "1234.5678" } ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-clone-002.phpt0000644000175100001660000000101114760300421017314 0ustar --TEST-- MongoDB\BSON\Decimal128 can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Decimal128)#%d (1) { ["dec"]=> string(9) "1234.5678" } ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-get_properties-001.phpt0000644000175100001660000000043514760300421021257 0ustar --TEST-- MongoDB\BSON\Decimal128 get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECT-- array(1) { ["dec"]=> string(9) "1234.5678" } ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-get_properties-002.phpt0000644000175100001660000000047014760300421021257 0ustar --TEST-- MongoDB\BSON\Decimal128 get_properties handler (foreach) --FILE-- $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECT-- string(3) "dec" string(9) "1234.5678" ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-jsonserialize-001.phpt0000644000175100001660000000044714760300421021110 0ustar --TEST-- MongoDB\BSON\Decimal128::jsonSerialize() return value --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$numberDecimal"]=> string(14) "12389719287312" } ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-jsonserialize-002.phpt0000644000175100001660000000112614760300421021104 0ustar --TEST-- MongoDB\BSON\Decimal128::jsonSerialize() with json_encode() --FILE-- new MongoDB\BSON\Decimal128('12389719287312')]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$numberDecimal" : "12389719287312" } } {"foo":{"$numberDecimal":"12389719287312"}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(14) "12389719287312" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-serialization-002.phpt0000644000175100001660000000306514760300421021104 0ustar --TEST-- MongoDB\BSON\Decimal128 serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(9) "1234.5678" } string(61) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:9:"1234.5678";}" object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(9) "1234.5678" } object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(10) "-1234.5678" } string(63) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:10:"-1234.5678";}" object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(10) "-1234.5678" } object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(11) "1.23456E-75" } string(64) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:11:"1.23456E-75";}" object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(11) "1.23456E-75" } object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(8) "Infinity" } string(60) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:8:"Infinity";}" object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(8) "Infinity" } object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(3) "NaN" } string(55) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:3:"NaN";}" object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(3) "NaN" } ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-serialization_error-001.phpt0000644000175100001660000000077614760300421022322 0ustar --TEST-- MongoDB\BSON\Decimal128 unserialization requires "dec" string field (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Decimal128 initialization requires "dec" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-serialization_error-002.phpt0000644000175100001660000000076014760300421022314 0ustar --TEST-- MongoDB\BSON\Decimal128 unserialization requires valid decimal string (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing Decimal128 string: INVALID ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-serialization_error-003.phpt0000644000175100001660000000077614760300421022324 0ustar --TEST-- MongoDB\BSON\Decimal128 unserialization requires "dec" string field (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Decimal128 initialization requires "dec" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-serialization_error-004.phpt0000644000175100001660000000076014760300421022316 0ustar --TEST-- MongoDB\BSON\Decimal128 unserialization requires valid decimal string (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing Decimal128 string: INVALID ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-set_state-001.phpt0000644000175100001660000000146614760300421020224 0ustar --TEST-- MongoDB\BSON\Decimal128::__set_state() --FILE-- $value, ])); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Decimal128::__set_state(array( 'dec' => '1234.5678', )) %r\\?%rMongoDB\BSON\Decimal128::__set_state(array( 'dec' => '-1234.5678', )) %r\\?%rMongoDB\BSON\Decimal128::__set_state(array( 'dec' => 'Infinity', )) %r\\?%rMongoDB\BSON\Decimal128::__set_state(array( 'dec' => 'Infinity', )) %r\\?%rMongoDB\BSON\Decimal128::__set_state(array( 'dec' => 'NaN', )) %r\\?%rMongoDB\BSON\Decimal128::__set_state(array( 'dec' => 'NaN', )) ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-set_state_error-001.phpt0000644000175100001660000000071714760300421021433 0ustar --TEST-- MongoDB\BSON\Decimal128::__set_state() requires "dec" string field --FILE-- 0]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Decimal128 initialization requires "dec" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128-set_state_error-002.phpt0000644000175100001660000000067714760300421021441 0ustar --TEST-- MongoDB\BSON\Decimal128::__set_state() requires valid decimal string --FILE-- 'INVALID']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing Decimal128 string: INVALID ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128_error-001.phpt0000644000175100001660000000126514760300421017441 0ustar --TEST-- MongoDB\BSON\Decimal128 requires valid decimal string --SKIPIF-- =', '7.99'); ?> --FILE-- ===DONE=== --EXPECTF-- OK: Got TypeError %SMongoDB\BSON\Decimal128::__construct()%sstring, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing Decimal128 string: foo ===DONE=== mongodb-1.21.0/tests/bson/bson-decimal128_error-002.phpt0000644000175100001660000000040314760300421017433 0ustar --TEST-- MongoDB\BSON\Decimal128 cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyDecimal128 %s final class %SMongoDB\BSON\Decimal128%S in %s on line %d mongodb-1.21.0/tests/bson/bson-decimal128interface-001.phpt0000644000175100001660000000043314760300421020105 0ustar --TEST-- MongoDB\BSON\Decimal128Interface is implemented by MongoDB\BSON\Decimal128 --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-decode-001.phpt0000644000175100001660000000400214760300421015612 0ustar --TEST-- BSON encoding: Encoding data into BSON representation, and BSON into Extended JSON --FILE-- "world"), array((object)array("hello" => "world")), array(null), array(123), array(4.125), array(true), array(false), array("string"), array("string", true), array('test', 'foo', 'bar'), array('test' => 'test', 'foo' => 'foo', 'bar' => 'bar'), array('foo' => 'test', 'foo', 'bar'), /* (object)array("hello" => "world"), array(array("hello" => "world")), array(array(1, 2, 3, 4, 5, 6, 7, 8, 9)), array((object)array(1, 2, 3, 4, 5, 6, 7, 8, 9)), array(array("0" => 1, "1" => 2, "2" => 3, "3" => 4, "4" => 5, "5" => 6, "6" => 7, "7" => 8, "8" => 9)), array("int" => 3, "boolean" => true, "array" => array("foo", "bar"), "object" => new stdclass, "string" => "test", 3 => "test"), array(array("string", true)), array(array('test', 'foo', 'bar')), array(array('test' => 'test', 'foo' => 'foo', 'bar' => 'bar')), array(array('foo' => 'test', 'foo', 'bar')), array(array("int" => 3, "boolean" => true, "array" => array("foo", "bar"), "object" => new stdclass, "string" => "test", 3 => "test")), */ ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", toJSON($s), "\n"; $val = toPHP($s); if ($val == (object) $test) { echo "OK\n"; } else { var_dump($val, $test); } } ?> ===DONE=== --EXPECT-- Test#0 { "hello" : "world" } OK Test#1 { "0" : { "hello" : "world" } } OK Test#2 { "0" : null } OK Test#3 { "0" : { "$numberInt" : "123" } } OK Test#4 { "0" : { "$numberDouble" : "4.125" } } OK Test#5 { "0" : true } OK Test#6 { "0" : false } OK Test#7 { "0" : "string" } OK Test#8 { "0" : "string", "1" : true } OK Test#9 { "0" : "test", "1" : "foo", "2" : "bar" } OK Test#10 { "test" : "test", "foo" : "foo", "bar" : "bar" } OK Test#11 { "foo" : "test", "0" : "foo", "1" : "bar" } OK ===DONE=== mongodb-1.21.0/tests/bson/bson-decode-002.phpt0000644000175100001660000000520014760300421015614 0ustar --TEST-- BSON encoding: Encoding object/arrays data into user specificied classes --FILE-- "world")), array((object)array("hello" => "world")), array("my" => array("hello" => "world")), array("my" => (object)array("hello" => "world")), array("my" => array(array("hello", "world"))), array("my" => (object)array(array("hello", "world"))), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", toJSON($s), "\n"; $val = toPHP($s, array("root"=> "MyArrayObject", "document"=> "MyArrayObject", "array" => "MyArrayObject")); var_dump($val); } ?> ===DONE=== --EXPECTF-- Test#%d { "0" : { "hello" : "world" } } object(MyArrayObject)#%d (1) { [%s]=> array(1) { [0]=> object(MyArrayObject)#%d (1) { [%s]=> array(1) { ["hello"]=> string(5) "world" } } } } Test#%d { "0" : { "hello" : "world" } } object(MyArrayObject)#%d (1) { [%s]=> array(1) { [0]=> object(MyArrayObject)#%d (1) { [%s]=> array(1) { ["hello"]=> string(5) "world" } } } } Test#%d { "my" : { "hello" : "world" } } object(MyArrayObject)#%d (1) { [%s]=> array(1) { ["my"]=> object(MyArrayObject)#%d (1) { [%s]=> array(1) { ["hello"]=> string(5) "world" } } } } Test#%d { "my" : { "hello" : "world" } } object(MyArrayObject)#%d (1) { [%s]=> array(1) { ["my"]=> object(MyArrayObject)#%d (1) { [%s]=> array(1) { ["hello"]=> string(5) "world" } } } } Test#%d { "my" : [ [ "hello", "world" ] ] } object(MyArrayObject)#%d (1) { [%s]=> array(1) { ["my"]=> object(MyArrayObject)#%d (1) { [%s]=> array(1) { [0]=> object(MyArrayObject)#%d (1) { [%s]=> array(2) { [0]=> string(5) "hello" [1]=> string(5) "world" } } } } } } Test#%d { "my" : { "0" : [ "hello", "world" ] } } object(MyArrayObject)#%d (1) { [%s]=> array(1) { ["my"]=> object(MyArrayObject)#%d (1) { [%s]=> array(1) { [0]=> object(MyArrayObject)#%d (1) { [%s]=> array(2) { [0]=> string(5) "hello" [1]=> string(5) "world" } } } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access-001.phpt0000644000175100001660000000114714760300421020567 0ustar --TEST-- MongoDB\BSON\Document array access (dimension object accessors) --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); var_dump(isset($document['foo'])); var_dump(isset($document['int64'])); var_dump(isset($document['baz'])); var_dump($document['foo']); var_dump($document['int64']); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) bool(false) string(3) "bar" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access-002.phpt0000644000175100001660000000127514760300421020572 0ustar --TEST-- MongoDB\BSON\Document array access (ArrayAccess methods) --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); var_dump($document->offsetExists('foo')); var_dump($document->offsetExists('int64')); var_dump($document->offsetExists('baz')); var_dump($document->offsetExists(0)); var_dump($document->offsetGet('foo')); var_dump($document->offsetGet('int64')); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) bool(false) bool(false) string(3) "bar" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access-003.phpt0000644000175100001660000000067414760300421020575 0ustar --TEST-- MongoDB\BSON\Document array access (coalesce operator) --FILE-- ===DONE=== --EXPECT-- bool(false) string(8) "fallback" bool(false) string(8) "fallback" ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access-004.phpt0000644000175100001660000000115114760300421020565 0ustar --TEST-- MongoDB\BSON\Document array access with integers (dimension object accessors) --FILE-- 'foo', '1' => 'bar', ]); // Use a variable to assert that conversion doesn't affect the original zval $key = 1; var_dump(isset($document[0])); var_dump(isset($document[$key])); var_dump(isset($document[2])); var_dump($document[0]); var_dump($document[$key]); var_dump($key); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(false) string(3) "foo" string(3) "bar" int(1) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access-005.phpt0000644000175100001660000000121514760300421020567 0ustar --TEST-- MongoDB\BSON\Document array access with integers (ArrayAccess methods) --FILE-- 'foo', '1' => 'bar', ]); // Use a variable to assert that conversion doesn't affect the original zval $key = 1; var_dump($document->offsetExists(0)); var_dump($document->offsetExists($key)); var_dump($document->offsetExists(2)); var_dump($document->offsetGet(0)); var_dump($document->offsetGet($key)); var_dump($key); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(false) string(3) "foo" string(3) "bar" int(1) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access_error-001.phpt0000644000175100001660000000143114760300421021774 0ustar --TEST-- MongoDB\BSON\Document array access does not allow writing (dimension object accessors) --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); echo throws(function() use ($document) { $document['foo'] = 'baz'; }, MongoDB\Driver\Exception\LogicException::class), "\n"; echo throws(function() use ($document) { unset($document['foo']); }, MongoDB\Driver\Exception\LogicException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\LogicException Cannot write to MongoDB\BSON\Document property OK: Got MongoDB\Driver\Exception\LogicException Cannot unset MongoDB\BSON\Document property ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access_error-002.phpt0000644000175100001660000000144214760300421021777 0ustar --TEST-- MongoDB\BSON\Document array access does not allow writing (ArrayAccess methods) --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); echo throws(function() use ($document) { $document->offsetSet('foo', 'baz'); }, MongoDB\Driver\Exception\LogicException::class), "\n"; echo throws(function() use ($document) { $document->offsetUnset('foo'); }, MongoDB\Driver\Exception\LogicException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\LogicException Cannot write to MongoDB\BSON\Document property OK: Got MongoDB\Driver\Exception\LogicException Cannot unset MongoDB\BSON\Document property ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access_error-003.phpt0000644000175100001660000000142114760300421021775 0ustar --TEST-- MongoDB\BSON\Document array access checks types (dimension object handlers) --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); echo throws(function() use ($document) { $document[0.1]; }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; echo throws(function() use ($document) { $document[false]; }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key of type "float" in BSON document OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key of type "bool" in BSON document ===DONE=== mongodb-1.21.0/tests/bson/bson-document-array-access_error-004.phpt0000644000175100001660000000144114760300421022000 0ustar --TEST-- MongoDB\BSON\Document array access checks types (ArrayAccess methods) --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); echo throws(function() use ($document) { $document->offsetGet(0.1); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; echo throws(function() use ($document) { $document->offsetGet(false); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key of type "float" in BSON document OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key of type "bool" in BSON document ===DONE=== mongodb-1.21.0/tests/bson/bson-document-clone-001.phpt0000644000175100001660000000144014760300421017306 0ustar --TEST-- MongoDB\BSON\Document can be cloned --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(48) "JAAAAARmb28AGgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "GgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAA=" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-compare-001.phpt0000644000175100001660000000064014760300421017635 0ustar --TEST-- MongoDB\BSON\Document comparisons --FILE-- 1, 'bar' => 2]); $barfoo = MongoDB\BSON\Document::fromPHP(['bar' => 1, 'foo' => 2]); var_dump($foobar == $barfoo); var_dump($foobar < $barfoo); var_dump($foobar > $barfoo); var_dump($foobar == $foobar); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-debug-001.phpt0000644000175100001660000000052114760300421017273 0ustar --TEST-- MongoDB\BSON\Document debug output --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(8) "BQAAAAA=" ["value"]=> object(stdClass)#%d (%d) { } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromBSON-001.phpt0000644000175100001660000000072314760300421017636 0ustar --TEST-- MongoDB\BSON\Document::fromBSON(): Decoding from BSON string --FILE-- ===DONE=== --EXPECT-- 0 : 12 00 00 00 02 66 6f 6f 00 04 00 00 00 62 61 72 [.....foo.....bar] 10 : 00 00 [..] ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromBSON_error-001.phpt0000644000175100001660000000156114760300421021050 0ustar --TEST-- MongoDB\BSON\Document::fromBSON(): BSON decoding exceptions --DESCRIPTION-- This test was adapted from bson-toPHP_error-002.phpt --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader OK: Got MongoDB\Driver\Exception\UnexpectedValueException Reading document did not exhaust input buffer ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromBSON_error-002.phpt0000644000175100001660000000146714760300421021056 0ustar --TEST-- MongoDB\BSON\Document::fromBSON(): BSON decoding exceptions for malformed documents --DESCRIPTION-- This test was adapted from bson-toPHP_error-003.phpt --FILE-- ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromBSON_error-003.phpt0000644000175100001660000000417614760300421021057 0ustar --TEST-- MongoDB\BSON\Document::fromBSON(): BSON decoding exceptions for bson_iter_visit_all() failure --DESCRIPTION-- This test was adapted from bson-toPHP_error-004.phpt --FILE-- 'bar'])), // Invalid UTF-8 character in embedded document's field name str_replace('INVALID!', "INVALID\xFE", fromPHP(['foo' => ['INVALID!' => 'bar']])), // Invalid UTF-8 character in string within array field str_replace('INVALID!', "INVALID\xFE", fromPHP(['foo' => ['INVALID!']])), /* Note: we don't use a three-character string in the underflow case, as * the 4-byte string length and payload (i.e. three characters + null byte) * coincidentally satisfy the expected size for an 8-byte double. We also * don't use a four-character string, since its null byte would be * interpreted as the document terminator. The actual document terminator * would then remain in the buffer and trigger a "did not exhaust" error. */ pack('VCa*xVa*xx', 17, 1, 'foo', 3, 'ab'), // Invalid field type (underflow) pack('VCa*xVa*xx', 20, 1, 'foo', 6, 'abcde'), // Invalid field type (overflow) ]; foreach ($tests as $bson) { echo throws(function() use ($bson) { MongoDB\BSON\Document::fromBSON($bson)->toPHP(); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path '' at offset 4 OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo' at offset 0 OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo' at offset 0 OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path '' at offset 9 OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected unknown BSON type 0x65 for field path "". Are you using the latest driver? ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromBSON_error-004.phpt0000644000175100001660000000303614760300421021052 0ustar --TEST-- MongoDB\BSON\Document::fromBSON(): Field path values with bson_iter_visit_all() failures --DESCRIPTION-- This test was adapted from bson-toPHP_error-005.phpt --FILE-- ['INVALID!' => 'bar'] ])), str_replace('INVALID!', "INVALID\xFE", fromPHP(['foo' => ['bar' => ['INVALID!' => 'bar']]])), str_replace('INVALID!', "INVALID\xFE", fromPHP(['foo' => ['bar' => ['INVALID!']]])), str_replace('INVALID!', "INVALID\xFE", fromPHP(['foo' => [['INVALID!']]])), str_replace('INVALID!', "INVALID\xFE", fromPHP(['foo' => [ ['bar' => ['INVALID!' => 'bar']], 6 ]])), ]; foreach ($tests as $bson) { echo throws(function() use ($bson) { MongoDB\BSON\Document::fromBSON($bson)->toPHP(); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo' at offset 0 OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo.bar' at offset 0 OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo.bar' at offset 0 OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo.0' at offset 0 OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo.0.bar' at offset 0 ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromBSON_error-005.phpt0000644000175100001660000000123114760300421021046 0ustar --TEST-- MongoDB\BSON\Document::fromBSON(): BSON decoding exception with unknown BSON type --DESCRIPTION-- This test was adapted from bson-toPHP_error-006.phpt --FILE-- ["cruel" => "world"]]); $bson[15] = chr(0x42); echo throws(function() use ($bson) { MongoDB\BSON\Document::fromBSON($bson)->toPHP(); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected unknown BSON type 0x42 for field path "hello.cruel". Are you using the latest driver? ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromJSON-001.phpt0000644000175100001660000000247614760300421017655 0ustar --TEST-- MongoDB\BSON\Document::fromJSON(): Decoding JSON --FILE-- ===DONE=== --EXPECT-- Test {} 0 : 05 00 00 00 00 [.....] Test { "foo": "bar" } 0 : 12 00 00 00 02 66 6f 6f 00 04 00 00 00 62 61 72 [.....foo.....bar] 10 : 00 00 [..] Test { "foo": [ 1, 2, 3 ]} 0 : 24 00 00 00 04 66 6f 6f 00 1a 00 00 00 10 30 00 [$....foo......0.] 10 : 01 00 00 00 10 31 00 02 00 00 00 10 32 00 03 00 [.....1......2...] 20 : 00 00 00 00 [....] Test { "foo": { "bar": 1 }} 0 : 18 00 00 00 03 66 6f 6f 00 0e 00 00 00 10 62 61 [.....foo......ba] 10 : 72 00 01 00 00 00 00 00 [r.......] Test [ 1, 2, 3 ] 0 : 1a 00 00 00 10 30 00 01 00 00 00 10 31 00 02 00 [.....0......1...] 10 : 00 00 10 32 00 03 00 00 00 00 [...2......] ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromJSON-002.phpt0000644000175100001660000000442214760300421017647 0ustar --TEST-- MongoDB\BSON\Document::fromJSON(): Decoding extended JSON types --FILE-- ===DONE=== --EXPECT-- Test { "_id": { "$oid": "56315a7c6118fd1b920270b1" }} 0 : 16 00 00 00 07 5f 69 64 00 56 31 5a 7c 61 18 fd [....._id.V1Z|a..] 10 : 1b 92 02 70 b1 00 [...p..] Test { "binary": { "$binary": "Zm9v", "$type": "00" }} 0 : 15 00 00 00 05 62 69 6e 61 72 79 00 03 00 00 00 [.....binary.....] 10 : 00 66 6f 6f 00 [.foo.] Test { "date": { "$date": "2015-10-28T00:00:00Z" }} 0 : 13 00 00 00 09 64 61 74 65 00 00 80 be ab 50 01 [.....date.....P.] 10 : 00 00 00 [...] Test { "timestamp": { "$timestamp": { "t": 1446084619, "i": 0 }}} 0 : 18 00 00 00 11 74 69 6d 65 73 74 61 6d 70 00 00 [.....timestamp..] 10 : 00 00 00 0b 80 31 56 00 [.....1V.] Test { "regex": { "$regex": "pattern", "$options": "i" }} 0 : 16 00 00 00 0b 72 65 67 65 78 00 70 61 74 74 65 [.....regex.patte] 10 : 72 6e 00 69 00 00 [rn.i..] Test { "undef": { "$undefined": true }} 0 : 0c 00 00 00 06 75 6e 64 65 66 00 00 [.....undef..] Test { "minkey": { "$minKey": 1 }} 0 : 0d 00 00 00 ff 6d 69 6e 6b 65 79 00 00 [.....minkey..] Test { "maxkey": { "$maxKey": 1 }} 0 : 0d 00 00 00 7f 6d 61 78 6b 65 79 00 00 [.....maxkey..] Test { "long": { "$numberLong": "1234" }} 0 : 13 00 00 00 12 6c 6f 6e 67 00 d2 04 00 00 00 00 [.....long.......] 10 : 00 00 00 [...] ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromJSON_error-001.phpt0000644000175100001660000000054214760300421021056 0ustar --TEST-- MongoDB\BSON\Document::fromJSON(): invalid JSON --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromPHP-001.phpt0000644000175100001660000000271514760300421017527 0ustar --TEST-- MongoDB\BSON\Document::fromPHP(): Serializable::bsonSerialize() returns array or stdClass --FILE-- data = $data; } #[ReturnTypeWillChange] public function bsonSerialize() { return $this->data; } } $tests = [ [1, 2, 3], ['foo' => 'bar'], (object) [1, 2, 3], (object) ['foo' => 'bar'], ]; echo "Testing top-level objects\n"; foreach ($tests as $test) { try { echo MongoDB\BSON\Document::fromPHP(new MyDocument($test))->toRelaxedExtendedJson(), "\n"; } catch (MongoDB\Driver\Exception\UnexpectedValueException $e) { echo $e->getMessage(), "\n"; } } echo "\nTesting nested objects\n"; foreach ($tests as $test) { try { echo MongoDB\BSON\Document::fromPHP(new MyDocument(['nested' => new MyDocument($test)]))->toRelaxedExtendedJson(), "\n"; } catch (MongoDB\Driver\Exception\UnexpectedValueException $e) { echo $e->getMessage(), "\n"; } } ?> ===DONE=== --EXPECT-- Testing top-level objects { "0" : 1, "1" : 2, "2" : 3 } { "foo" : "bar" } { "0" : 1, "1" : 2, "2" : 3 } { "foo" : "bar" } Testing nested objects { "nested" : [ 1, 2, 3 ] } { "nested" : { "foo" : "bar" } } { "nested" : { "0" : 1, "1" : 2, "2" : 3 } } { "nested" : { "foo" : "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromPHP-002.phpt0000644000175100001660000000063214760300421017524 0ustar --TEST-- MongoDB\BSON\Document::fromPHP(): Encodes non-Serializable objects as a document --FILE-- toRelaxedExtendedJSON(), "\n"; ?> ===DONE=== --EXPECT-- { "baz" : 3 } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromPHP-003.phpt0000644000175100001660000000147214760300421017530 0ustar --TEST-- MongoDB\BSON\Document::fromPHP(): Encodes Persistable objects as a document --FILE-- $this->foo, 'bar' => $this->bar, 'baz' => $this->baz, ]; } public function bsonUnserialize(array $data): void { // Unused } } $bson = MongoDB\BSON\Document::fromPHP(new MyDocument); echo $bson->toRelaxedExtendedJSON(), "\n"; ?> ===DONE=== --EXPECT-- { "__pclass" : { "$binary" : { "base64" : "TXlEb2N1bWVudA==", "subType" : "80" } }, "foo" : 1, "bar" : 2, "baz" : 3 } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-fromPHP-004.phpt0000644000175100001660000000127514760300421017532 0ustar --TEST-- MongoDB\BSON\Document::fromPHP() copies BSON data from Document and PackedArray --FILE-- toRelaxedExtendedJSON(), "\n"; // This will be interpreted as an object after copying, i.e. { "0": 1, "1": 2, "2": 3 } $packedArray = MongoDB\BSON\PackedArray::fromPHP([ 1, 2, 3 ]); $fromPackedArray = MongoDB\BSON\Document::fromPHP($packedArray); echo $fromPackedArray->toRelaxedExtendedJSON(), "\n"; ?> ===DONE=== --EXPECT-- { "foo" : "bar" } { "0" : 1, "1" : 2, "2" : 3 } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-get-001.phpt0000644000175100001660000000134214760300421016766 0ustar --TEST-- MongoDB\BSON\Document::get() key access --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); var_dump($document->get('foo')); var_dump($document->get('bar')); var_dump($document->get('int64')); echo throws(function() use ($document) { var_dump($document->get('baz')); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECTF-- string(3) "bar" string(3) "baz" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key "baz" in BSON document ===DONE=== mongodb-1.21.0/tests/bson/bson-document-get-002.phpt0000644000175100001660000000071114760300421016766 0ustar --TEST-- MongoDB\BSON\Document::get() key access --FILE-- (object) ['foo' => 'bar']]); $child = $document->get('document'); unset($document); var_dump($child); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-get-003.phpt0000644000175100001660000000064014760300421016770 0ustar --TEST-- MongoDB\BSON\Document::get() key access --FILE-- (object) ['foo' => 'bar']])->get('document'); var_dump($child); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-getIterator-001.phpt0000644000175100001660000000064614760300421020506 0ustar --TEST-- MongoDB\BSON\Document::getIterator() tests --FILE-- 'bar', 'bar' => 'baz'])->getIterator(); echo get_class($iterator), "\n"; foreach ($iterator as $key => $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECTF-- MongoDB\BSON\Iterator string(3) "foo" string(3) "bar" string(3) "bar" string(3) "baz" ===DONE=== mongodb-1.21.0/tests/bson/bson-document-get_properties-001.phpt0000644000175100001660000000042314760300421021241 0ustar --TEST-- MongoDB\BSON\Document get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECTF-- array(1) { ["data"]=> string(8) "BQAAAAA=" } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-has-001.phpt0000644000175100001660000000052514760300421016764 0ustar --TEST-- MongoDB\BSON\Document::has() checks if key exists --FILE-- 'bar', 'bar' => 'baz']); var_dump($document->has('foo')); var_dump($document->has('bar')); var_dump($document->has('baz')); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-property-access-001.phpt0000644000175100001660000000144314760300421021334 0ustar --TEST-- MongoDB\BSON\Document property access --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); var_dump(isset($document->foo)); var_dump(isset($document->int64)); var_dump(isset($document->baz)); var_dump($document->foo); var_dump($document->int64); echo throws(function() use ($document) { var_dump($document->baz); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECTF-- bool(true) bool(true) bool(false) string(3) "bar" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } OK: Got MongoDB\Driver\Exception\RuntimeException Could not find key "baz" in BSON document ===DONE=== mongodb-1.21.0/tests/bson/bson-document-property-access-002.phpt0000644000175100001660000000052414760300421021334 0ustar --TEST-- MongoDB\BSON\Document property access (coalesce operator) --FILE-- foo)); var_dump($document->foo ?? 'fallback'); ?> ===DONE=== --EXPECT-- bool(false) string(8) "fallback" ===DONE=== mongodb-1.21.0/tests/bson/bson-document-property-access_error-001.phpt0000644000175100001660000000137414760300421022550 0ustar --TEST-- MongoDB\BSON\Document property access does not allow writing --FILE-- 'bar', 'bar' => 'baz', 'int64' => new MongoDB\BSON\Int64(123), ]); echo throws(function() use ($document) { $document->foo = 'baz'; }, MongoDB\Driver\Exception\LogicException::class), "\n"; echo throws(function() use ($document) { unset($document->foo); }, MongoDB\Driver\Exception\LogicException::class), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\LogicException Cannot write to MongoDB\BSON\Document property OK: Got MongoDB\Driver\Exception\LogicException Cannot unset MongoDB\BSON\Document property ===DONE=== mongodb-1.21.0/tests/bson/bson-document-serialization-002.phpt0000644000175100001660000000401614760300421021066 0ustar --TEST-- MongoDB\BSON\Document serialization (__serialize and __unserialize) --FILE-- 1, 'array' => [0, 1, 'foo'], 'document' => ['foo' => 'bar']]); var_dump($document); var_dump($s = serialize($document)); var_dump(unserialize($s)); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(108) "TwAAABBfaWQAAQAAAARhcnJheQAeAAAAEDAAAAAAABAxAAEAAAACMgAEAAAAZm9vAAADZG9jdW1lbnQAEgAAAAJmb28ABAAAAGJhcgAAAA==" ["value"]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["array"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(40) "HgAAABAwAAAAAAAQMQABAAAAAjIABAAAAGZvbwAA" ["value"]=> array(3) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "foo" } } ["document"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } string(161) "O:21:"MongoDB\BSON\Document":1:{s:4:"data";s:108:"TwAAABBfaWQAAQAAAARhcnJheQAeAAAAEDAAAAAAABAxAAEAAAACMgAEAAAAZm9vAAADZG9jdW1lbnQAEgAAAAJmb28ABAAAAGJhcgAAAA==";}" object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(108) "TwAAABBfaWQAAQAAAARhcnJheQAeAAAAEDAAAAAAABAxAAEAAAACMgAEAAAAZm9vAAADZG9jdW1lbnQAEgAAAAJmb28ABAAAAGJhcgAAAA==" ["value"]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["array"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(40) "HgAAABAwAAAAAAAQMQABAAAAAjIABAAAAGZvbwAA" ["value"]=> array(3) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "foo" } } ["document"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-set_state-001.phpt0000644000175100001660000000245514760300421020210 0ustar --TEST-- MongoDB\BSON\Document::__set_state() --FILE-- 1, 'array' => [0, 1, 'foo'], 'document' => ['foo' => 'bar'] ]); $s = var_export($document, true); echo $s, "\n"; var_dump($o = eval('return ' . $s . ';')); var_dump($o == $document); ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Document::__set_state(array( 'data' => 'TwAAABBfaWQAAQAAAARhcnJheQAeAAAAEDAAAAAAABAxAAEAAAACMgAEAAAAZm9vAAADZG9jdW1lbnQAEgAAAAJmb28ABAAAAGJhcgAAAA==', )) object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(108) "TwAAABBfaWQAAQAAAARhcnJheQAeAAAAEDAAAAAAABAxAAEAAAACMgAEAAAAZm9vAAADZG9jdW1lbnQAEgAAAAJmb28ABAAAAGJhcgAAAA==" ["value"]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["array"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(40) "HgAAABAwAAAAAAAQMQABAAAAAjIABAAAAGZvbwAA" ["value"]=> array(3) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "foo" } } ["document"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-set_state_error-001.phpt0000644000175100001660000000222514760300421021414 0ustar --TEST-- MongoDB\BSON\Document::__set_state() handles invalid BSON payload correctly --FILE-- '', 'Last byte is non-zero' => pack( 'VCa*xVa*', 4 + 1 + 4 + 4 + 2, // Size: 4 bytes for size, 1 byte for type, 4 bytes for key, 4 bytes for string length, 2 bytes for string 0x02, 'foo', 2, 'a' ), 'Length does not match document length' => pack('VCa*Va*xx', 7, 0x02, 'foo', 1, 'a'), ]; foreach ($tests as $test) { echo throws(function() use ($test) { MongoDB\BSON\Document::__set_state([ 'data' => base64_encode($test), ]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Document initialization requires valid BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Document initialization requires valid BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Document initialization requires valid BSON ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toCanonicalJSON-001.phpt0000644000175100001660000000170214760300421021133 0ustar --TEST-- MongoDB\BSON\Document::toCanonicalExtendedJSON(): Encoding JSON --FILE-- null ], [ 'boolean' => true ], [ 'string' => 'foo' ], [ 'integer' => 123 ], [ 'double' => 1.0, ], [ 'nan' => NAN ], [ 'pos_inf' => INF ], [ 'neg_inf' => -INF ], [ 'array' => [ 'foo', 'bar' ]], [ 'document' => [ 'foo' => 'bar' ]], ]; foreach ($tests as $value) { echo MongoDB\BSON\Document::fromPHP($value)->toCanonicalExtendedJSON(), "\n"; } ?> ===DONE=== --EXPECT-- { } { "null" : null } { "boolean" : true } { "string" : "foo" } { "integer" : { "$numberInt" : "123" } } { "double" : { "$numberDouble" : "1.0" } } { "nan" : { "$numberDouble" : "NaN" } } { "pos_inf" : { "$numberDouble" : "Infinity" } } { "neg_inf" : { "$numberDouble" : "-Infinity" } } { "array" : [ "foo", "bar" ] } { "document" : { "foo" : "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toCanonicalJSON-002.phpt0000644000175100001660000000275314760300421021143 0ustar --TEST-- MongoDB\BSON\Document::toCanonicalExtendedJSON(): Encoding extended JSON types --FILE-- new MongoDB\BSON\ObjectId('56315a7c6118fd1b920270b1') ], [ 'binary' => new MongoDB\BSON\Binary('foo', MongoDB\BSON\Binary::TYPE_GENERIC) ], [ 'date' => new MongoDB\BSON\UTCDateTime(new MongoDB\BSON\Int64('1445990400000')) ], [ 'timestamp' => new MongoDB\BSON\Timestamp(1234, 5678) ], [ 'regex' => new MongoDB\BSON\Regex('pattern', 'i') ], [ 'code' => new MongoDB\BSON\Javascript('function() { return 1; }') ], [ 'code_ws' => new MongoDB\BSON\Javascript('function() { return a; }', ['a' => 1]) ], [ 'minkey' => new MongoDB\BSON\MinKey ], [ 'maxkey' => new MongoDB\BSON\MaxKey ], ]; foreach ($tests as $value) { echo MongoDB\BSON\Document::fromPHP($value)->toCanonicalExtendedJSON(), "\n"; } ?> ===DONE=== --EXPECT-- { "_id" : { "$oid" : "56315a7c6118fd1b920270b1" } } { "binary" : { "$binary" : { "base64" : "Zm9v", "subType" : "00" } } } { "date" : { "$date" : { "$numberLong" : "1445990400000" } } } { "timestamp" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } } { "regex" : { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } } { "code" : { "$code" : "function() { return 1; }" } } { "code_ws" : { "$code" : "function() { return a; }", "$scope" : { "a" : { "$numberInt" : "1" } } } } { "minkey" : { "$minKey" : 1 } } { "maxkey" : { "$maxKey" : 1 } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-001.phpt0000644000175100001660000000457314760300421017212 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): __pclass must be both instantiatable and Persistable --FILE-- unserialized = true; } } // Create base64-encoded class names for __pclass field's binary data $bMyAbstractDocument = base64_encode('MyAbstractDocument'); $bMyDocument = base64_encode('MyDocument'); $bUnserializable = base64_encode('MongoDB\BSON\Unserializable'); $bPersistable = base64_encode('MongoDB\BSON\Persistable'); $tests = [ '{ "foo": "yes", "__pclass": { "$binary": "' . $bMyAbstractDocument . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bMyDocument . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bUnserializable . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bPersistable . '", "$type": "44" } }', ]; foreach ($tests as $test) { echo $test, "\n"; var_dump(MongoDB\BSON\Document::fromJSON($test)->toPHP()); echo "\n"; } ?> ===DONE=== --EXPECTF-- { "foo": "yes", "__pclass": { "$binary": "TXlBYnN0cmFjdERvY3VtZW50", "$type": "80" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(18) "MyAbstractDocument" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "TXlEb2N1bWVudA==", "$type": "80" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "TW9uZ29EQlxCU09OXFVuc2VyaWFsaXphYmxl", "$type": "80" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(27) "MongoDB\BSON\Unserializable" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "TW9uZ29EQlxCU09OXFBlcnNpc3RhYmxl", "$type": "44" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(24) "MongoDB\BSON\Persistable" ["type"]=> int(68) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-002.phpt0000644000175100001660000000253514760300421017207 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): Null type map values imply default behavior --FILE-- data = [ 'list' => [1, 2, 3], 'map' => (object) ['foo' => 'bar'], ]; } public function bsonSerialize(): array { return $this->data; } public function bsonUnserialize(array $data): void { foreach (['list', 'map'] as $key) { if (isset($data[$key])) { $this->data[$key] = $data[$key]; } } } } $bson = MongoDB\BSON\Document::fromPHP(new MyDocument); echo "Test ", $bson->toRelaxedExtendedJSON(), "\n"; $typeMap = [ 'array' => null, 'document' => null, 'root' => null, ]; var_dump($bson->toPHP($typeMap)); ?> ===DONE=== --EXPECTF-- Test { "__pclass" : { "$binary" : { "base64" : "TXlEb2N1bWVudA==", "subType" : "80" } }, "list" : [ 1, 2, 3 ], "map" : { "foo" : "bar" } } object(MyDocument)#%d (1) { ["data"]=> array(2) { ["list"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["map"]=> object(stdClass)#%d (1) { ["foo"]=> string(3) "bar" } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-003.phpt0000644000175100001660000002450614760300421017212 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): Tests from serialization specification --FILE-- $value) { $this->$key = $value; } $this->unserialized = true; } } #[\AllowDynamicProperties] class OurClass implements MongoDB\BSON\Persistable { function bsonSerialize(): array { // Not tested with this test, so return empty array return []; } function bsonUnserialize(array $data): void { foreach ($data as $key => $value) { $this->$key = $value; } $this->unserialized = true; } } class TheirClass extends OurClass { } // Create base64-encoded class names for __pclass field's binary data $bMyClass = base64_encode('MyClass'); $bYourClass = base64_encode('YourClass'); $bOurClass = base64_encode('OurClass'); $bTheirClass = base64_encode('TheirClass'); $bInterface = base64_encode('MongoDB\BSON\Unserializable'); $testGroups = [ [ 'name' => 'DEFAULT TYPEMAP', 'typemap' => [], 'tests' => [ '{ "foo": "yes", "bar" : false }', '{ "foo": "no", "array" : [ 5, 6 ] }', '{ "foo": "no", "obj" : { "embedded" : 4.125 } }', '{ "foo": "yes", "__pclass": "MyClass" }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bMyClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bYourClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bOurClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bYourClass . '", "$type": "44" } }', ], ], [ 'name' => 'NONEXISTING CLASS', 'typemap' => ['root' => 'MissingClass'], 'tests' => [ '{ "foo": "yes" }', ], ], [ 'name' => 'DOES NOT IMPLEMENT UNSERIALIZABLE', 'typemap' => ['root' => 'MyClass'], 'tests' => [ '{ "foo": "yes", "__pclass": { "$binary": "' . $bMyClass . '", "$type": "80" } }', ], ], [ 'name' => 'IS NOT A CONCRETE CLASS', 'typemap' => ['root' => 'MongoDB\BSON\Unserializable'], 'tests' => [ '{ "foo": "yes" }', ], ], [ 'name' => 'IS NOT A CONCRETE CLASS VIA PCLASS', 'typemap' => ['root' => 'YourClass'], 'tests' => [ '{ "foo": "yes", "__pclass" : { "$binary": "' . $bInterface . '", "$type": "80" } }', ], ], [ 'name' => 'PCLASS OVERRIDES TYPEMAP (1)', 'typemap' => ['root' => 'YourClass'], 'tests' => [ '{ "foo": "yes", "__pclass" : { "$binary": "' . $bMyClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bOurClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bTheirClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bYourClass . '", "$type": "80" } }', ], ], [ 'name' => 'PCLASS OVERRIDES TYPEMAP (2)', 'typemap' => ['root' => 'OurClass'], 'tests' => [ '{ "foo": "yes", "__pclass" : { "$binary": "' . $bTheirClass . '", "$type": "80" } }', ], ], [ 'name' => 'OBJECTS AS ARRAY', 'typemap' => ['root' => 'array', 'document' => 'array'], 'tests' => [ '{ "foo": "yes", "bar" : false }', '{ "foo": "no", "array" : [ 5, 6 ] }', '{ "foo": "no", "obj" : { "embedded" : 4.125 } }', '{ "foo": "yes", "__pclass": "MyClass" }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bMyClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bOurClass . '", "$type": "80" } }', ], ], [ 'name' => 'OBJECTS AS STDCLASS', 'typemap' => ['root' => 'object', 'document' => 'object'], 'tests' => [ '{ "foo": "yes", "__pclass" : { "$binary": "' . $bMyClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bOurClass . '", "$type": "80" } }', ], ], ]; foreach ($testGroups as $testGroup) { printf("=== %s ===\n\n", $testGroup['name']); foreach ($testGroup['tests'] as $test) { echo $test, "\n"; $bson = MongoDB\BSON\Document::fromJSON($test); try { var_dump($bson->toPHP($testGroup['typemap'])); } catch (MongoDB\Driver\Exception\Exception $e) { echo $e->getMessage(), "\n"; } echo "\n"; } echo "\n"; } ?> ===DONE=== --EXPECTF-- === DEFAULT TYPEMAP === { "foo": "yes", "bar" : false } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["bar"]=> bool(false) } { "foo": "no", "array" : [ 5, 6 ] } object(stdClass)#%d (2) { ["foo"]=> string(2) "no" ["array"]=> array(2) { [0]=> int(5) [1]=> int(6) } } { "foo": "no", "obj" : { "embedded" : 4.125 } } object(stdClass)#%d (2) { ["foo"]=> string(2) "no" ["obj"]=> object(stdClass)#%d (1) { ["embedded"]=> float(4.125) } } { "foo": "yes", "__pclass": "MyClass" } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> string(7) "MyClass" } { "foo": "yes", "__pclass": { "$binary": "TXlDbGFzcw==", "$type": "80" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "WW91ckNsYXNz", "$type": "80" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(9) "YourClass" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "T3VyQ2xhc3M=", "$type": "80" } } object(OurClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "OurClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } { "foo": "yes", "__pclass": { "$binary": "WW91ckNsYXNz", "$type": "44" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(9) "YourClass" ["type"]=> int(68) } } === NONEXISTING CLASS === { "foo": "yes" } Class MissingClass does not exist === DOES NOT IMPLEMENT UNSERIALIZABLE === { "foo": "yes", "__pclass": { "$binary": "TXlDbGFzcw==", "$type": "80" } } Class MyClass does not implement MongoDB\BSON\Unserializable === IS NOT A CONCRETE CLASS === { "foo": "yes" } Interface MongoDB\BSON\Unserializable is not instantiatable === IS NOT A CONCRETE CLASS VIA PCLASS === { "foo": "yes", "__pclass" : { "$binary": "TW9uZ29EQlxCU09OXFVuc2VyaWFsaXphYmxl", "$type": "80" } } object(YourClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(27) "MongoDB\BSON\Unserializable" ["type"]=> int(128) } ["unserialized"]=> bool(true) } === PCLASS OVERRIDES TYPEMAP (1) === { "foo": "yes", "__pclass" : { "$binary": "TXlDbGFzcw==", "$type": "80" } } object(YourClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } { "foo": "yes", "__pclass" : { "$binary": "T3VyQ2xhc3M=", "$type": "80" } } object(OurClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "OurClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } { "foo": "yes", "__pclass" : { "$binary": "VGhlaXJDbGFzcw==", "$type": "80" } } object(TheirClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(10) "TheirClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } { "foo": "yes", "__pclass" : { "$binary": "WW91ckNsYXNz", "$type": "80" } } object(YourClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(9) "YourClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } === PCLASS OVERRIDES TYPEMAP (2) === { "foo": "yes", "__pclass" : { "$binary": "VGhlaXJDbGFzcw==", "$type": "80" } } object(TheirClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(10) "TheirClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } === OBJECTS AS ARRAY === { "foo": "yes", "bar" : false } array(2) { ["foo"]=> string(3) "yes" ["bar"]=> bool(false) } { "foo": "no", "array" : [ 5, 6 ] } array(2) { ["foo"]=> string(2) "no" ["array"]=> array(2) { [0]=> int(5) [1]=> int(6) } } { "foo": "no", "obj" : { "embedded" : 4.125 } } array(2) { ["foo"]=> string(2) "no" ["obj"]=> array(1) { ["embedded"]=> float(4.125) } } { "foo": "yes", "__pclass": "MyClass" } array(2) { ["foo"]=> string(3) "yes" ["__pclass"]=> string(7) "MyClass" } { "foo": "yes", "__pclass" : { "$binary": "TXlDbGFzcw==", "$type": "80" } } array(2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } } { "foo": "yes", "__pclass" : { "$binary": "T3VyQ2xhc3M=", "$type": "80" } } array(2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "OurClass" ["type"]=> int(128) } } === OBJECTS AS STDCLASS === { "foo": "yes", "__pclass" : { "$binary": "TXlDbGFzcw==", "$type": "80" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } } { "foo": "yes", "__pclass" : { "$binary": "T3VyQ2xhc3M=", "$type": "80" } } object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "OurClass" ["type"]=> int(128) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-007.phpt0000644000175100001660000001010414760300421017203 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): fieldPath typemaps without server --FILE-- 1, 'object' => [ 'parent1' => [ 'child1' => [ 1, 2, 3 ], 'child2' => [ 4, 5, 6 ], ], 'parent2' => [ 'child1' => [ 7, 8, 9 ], 'child2' => [ 10, 11, 12 ], ], ], ] ); function fetch($bson, $typeMap = []) { for ($i = 0; $i < 25000; $i++) { $documents = [ $bson->toPHP($typeMap) ]; } return $documents; } echo "\nSetting 'object.$.child1' path to 'MyWildCardArrayObject'\n"; $documents = fetch($bson, ["fieldPaths" => [ 'object.$.child1' => "MyWildCardArrayObject" ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildCardArrayObject); var_dump(is_array($documents[0]->object->parent1->child2)); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump($documents[0]->object->parent2->child1 instanceof MyWildCardArrayObject); var_dump(is_array($documents[0]->object->parent2->child2)); echo "\nSetting 'object.parent1.$' path to 'MyWildCardArrayObject' and 'object.parent2.child1' to 'MyArrayObject'\n"; $documents = fetch($bson, ["fieldPaths" => [ 'object.parent1.$' => "MyWildCardArrayObject", 'object.parent2.child1' => "MyArrayObject", ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildCardArrayObject); var_dump($documents[0]->object->parent1->child2 instanceof MyWildCardArrayObject); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump($documents[0]->object->parent2->child1 instanceof MyArrayObject); var_dump(is_array($documents[0]->object->parent2->child2)); echo "\nSetting 'object.parent1.$' path to 'MyWildCardArrayObject' and 'object.$.$' to 'MyArrayObject'\n"; $documents = fetch($bson, ["fieldPaths" => [ 'object.parent1.$' => "MyWildCardArrayObject", 'object.$.$' => "MyArrayObject", ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildCardArrayObject); var_dump($documents[0]->object->parent1->child2 instanceof MyWildCardArrayObject); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump($documents[0]->object->parent2->child1 instanceof MyArrayObject); var_dump($documents[0]->object->parent2->child2 instanceof MyArrayObject); echo "\nSetting 'object.parent1.$' path to 'MyWildCardArrayObject' and 'object.$.child2' to 'MyArrayObject'\n"; $documents = fetch($bson, ["fieldPaths" => [ 'object.parent1.child1' => "MyWildCardArrayObject", 'object.$.child2' => "MyArrayObject", ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildCardArrayObject); var_dump($documents[0]->object->parent1->child2 instanceof MyArrayObject); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump(is_array($documents[0]->object->parent2->child1)); var_dump($documents[0]->object->parent2->child2 instanceof MyArrayObject); ?> ===DONE=== --EXPECT-- Setting 'object.$.child1' path to 'MyWildCardArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildCardArrayObject' and 'object.parent2.child1' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildCardArrayObject' and 'object.$.$' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildCardArrayObject' and 'object.$.child2' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-008.phpt0000644000175100001660000000307414760300421017214 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): Setting fieldPath typemaps for compound types with string keys --FILE-- 1, 'array' => [1, 2, 3], 'object' => ['string' => 'keys', 'for' => 'ever'] ] ); function fetch($bson, $typeMap = []) { return $bson->toPHP($typeMap); } echo "Default\n"; $document = fetch($bson); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->object instanceof stdClass); echo "\nSetting 'object' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object' => "MyArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->object instanceof MyArrayObject); echo "\nSetting 'object' and 'array' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object' => "MyArrayObject", 'array' => "MyArrayObject", ]]); var_dump($document instanceof stdClass); var_dump($document->array instanceof MyArrayObject); var_dump($document->object instanceof MyArrayObject); ?> ===DONE=== --EXPECT-- Default bool(true) bool(true) bool(true) Setting 'object' path to 'MyArrayObject' bool(true) bool(true) bool(true) Setting 'object' and 'array' path to 'MyArrayObject' bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-009.phpt0000644000175100001660000000417714760300421017222 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): Setting fieldPath typemaps for compound types with numerical keys --FILE-- 1, 'array0' => [0 => [ 4, 5, 6 ], 1 => [ 7, 8, 9 ]], 'array1' => [1 => [ 4, 5, 6 ], 2 => [ 7, 8, 9 ]], ] ); function fetch($bson, $typeMap = []) { return $bson->toPHP($typeMap); } echo "Default\n"; $document = fetch($bson); var_dump($document instanceof stdClass); var_dump(is_array($document->array0)); var_dump(is_object($document->array1)); var_dump($document->array1 instanceof stdClass); echo "\nSetting 'array0' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array0' => "MyArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->array0)); var_dump($document->array0 instanceof MyArrayObject); echo "\nSetting 'array0.1' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array0.1' => "MyArrayObject", ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array0)); var_dump(is_array($document->array0[0])); var_dump($document->array0[1] instanceof MyArrayObject); echo "\nSetting 'array1.1' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array1.1' => "MyArrayObject", ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->array1)); var_dump($document->array1 instanceof stdClass); $a = ((array) $document->array1); var_dump($a[1] instanceof MyArrayObject); var_dump(is_array($a[2])); ?> ===DONE=== --EXPECT-- Default bool(true) bool(true) bool(true) bool(true) Setting 'array0' path to 'MyArrayObject' bool(true) bool(true) bool(true) Setting 'array0.1' path to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'array1.1' path to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-010.phpt0000644000175100001660000000774714760300421017220 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): Setting fieldPath typemaps for compound types with wildcard keys --FILE-- 1, 'array' => [0 => [ 4, 5, 6 ], 1 => [ 7, 8, 9 ]], 'object' => ['one' => [ 4, 5, 6 ], 'two' => [ 7, 8, 9 ]], ] ); function fetch($bson, $typeMap = []) { return $bson->toPHP($typeMap); } echo "\nSetting 'array.$' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array.$' => "MyWildcardArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->array[0] instanceof MyWildcardArrayObject); var_dump($document->array[1] instanceof MyWildcardArrayObject); echo "\nSetting 'array.1' to 'MyArrayObject' and 'array.$' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array.1' => "MyArrayObject", 'array.$' => "MyWildcardArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->array[0] instanceof MyWildcardArrayObject); var_dump($document->array[1] instanceof MyArrayObject); echo "\nSetting 'array.$' to 'MyWildcardArrayObject' and 'array.1' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array.$' => "MyWildcardArrayObject", 'array.1' => "MyArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->array[0] instanceof MyWildcardArrayObject); var_dump($document->array[1] instanceof MyWildcardArrayObject); echo "\nSetting 'object.$' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.$' => "MyWildcardArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->object)); var_dump($document->object->one instanceof MyWildcardArrayObject); var_dump($document->object->two instanceof MyWildcardArrayObject); echo "\nSetting 'object.two' to 'MyArrayObject' and 'object.$' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.two' => "MyArrayObject", 'object.$' => "MyWildcardArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->object)); var_dump($document->object->one instanceof MyWildcardArrayObject); var_dump($document->object->two instanceof MyArrayObject); echo "\nSetting 'object.$' to 'MyWildcardArrayObject' and 'object.one' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.$' => "MyWildcardArrayObject", 'object.one' => "MyArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->object)); var_dump($document->object->one instanceof MyWildcardArrayObject); var_dump($document->object->two instanceof MyWildcardArrayObject); ?> ===DONE=== --EXPECT-- Setting 'array.$' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'array.1' to 'MyArrayObject' and 'array.$' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'array.$' to 'MyWildcardArrayObject' and 'array.1' path to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'object.$' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'object.two' to 'MyArrayObject' and 'object.$' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'object.$' to 'MyWildcardArrayObject' and 'object.one' path to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-011.phpt0000644000175100001660000001147614760300421017213 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): Setting fieldPath typemaps for compound types with wildcard keys (nested) --FILE-- 1, 'object' => [ 'parent1' => [ 'child1' => [ 1, 2, 3 ], 'child2' => [ 4, 5, 6 ], ], 'parent2' => [ 'child1' => [ 7, 8, 9 ], 'child2' => [ 10, 11, 12 ], ], ], ] ); function fetch($bson, $typeMap = []) { return $bson->toPHP($typeMap); } echo "\nSetting 'object.$.child1' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.$.child1' => "MyWildcardArrayObject" ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump(is_array($document->object->parent1->child2)); var_dump($document->object->parent2 instanceof stdClass); var_dump($document->object->parent2->child1 instanceof MyWildcardArrayObject); var_dump(is_array($document->object->parent2->child2)); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.parent2.child1' to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.parent1.$' => "MyWildcardArrayObject", 'object.parent2.child1' => "MyArrayObject", ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent1->child2 instanceof MyWildcardArrayObject); var_dump($document->object->parent2 instanceof stdClass); var_dump($document->object->parent2->child1 instanceof MyArrayObject); var_dump(is_array($document->object->parent2->child2)); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.$' to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.parent1.$' => "MyWildcardArrayObject", 'object.$.$' => "MyArrayObject", ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent1->child2 instanceof MyWildcardArrayObject); var_dump($document->object->parent2 instanceof stdClass); var_dump($document->object->parent2->child1 instanceof MyArrayObject); var_dump($document->object->parent2->child2 instanceof MyArrayObject); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.child2' to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.parent1.child1' => "MyWildcardArrayObject", 'object.$.child2' => "MyArrayObject", ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent1->child2 instanceof MyArrayObject); var_dump($document->object->parent2 instanceof stdClass); var_dump(is_array($document->object->parent2->child1)); var_dump($document->object->parent2->child2 instanceof MyArrayObject); echo "\nSetting 'object.parent1.child2 path to 'MyArrayObject' and 'object.$.$' to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.parent1.child2' => "MyArrayObject", 'object.$.$' => "MyWildcardArrayObject", ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent1->child2 instanceof MyArrayObject); var_dump($document->object->parent2 instanceof stdClass); var_dump($document->object->parent2->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent2->child2 instanceof MyWildcardArrayObject); ?> ===DONE=== --EXPECT-- Setting 'object.$.child1' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.parent2.child1' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.$' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.child2' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.child2 path to 'MyArrayObject' and 'object.$.$' to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toPHP-012.phpt0000644000175100001660000000067214760300421017210 0ustar --TEST-- MongoDB\BSON\Document::toPHP(): int64 values are returned as Int64 instances --FILE-- 123, 'int64' => new MongoDB\BSON\Int64(123), ]); var_dump($bson->toPHP()); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["int32"]=> int(123) ["int64"]=> object(MongoDB\BSON\Int64)#%d (1) { ["integer"]=> string(3) "123" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toRelaxedJSON-001.phpt0000644000175100001660000000162114760300421020630 0ustar --TEST-- MongoDB\BSON\Document::toRelaxedExtendedJSON(): Encoding JSON --FILE-- null ], [ 'boolean' => true ], [ 'string' => 'foo' ], [ 'integer' => 123 ], [ 'double' => 1.0, ], [ 'nan' => NAN ], [ 'pos_inf' => INF ], [ 'neg_inf' => -INF ], [ 'array' => [ 'foo', 'bar' ]], [ 'document' => [ 'foo' => 'bar' ]], ]; foreach ($tests as $value) { echo MongoDB\BSON\Document::fromPHP($value)->toRelaxedExtendedJSON(), "\n"; } ?> ===DONE=== --EXPECT-- { } { "null" : null } { "boolean" : true } { "string" : "foo" } { "integer" : 123 } { "double" : 1.0 } { "nan" : { "$numberDouble" : "NaN" } } { "pos_inf" : { "$numberDouble" : "Infinity" } } { "neg_inf" : { "$numberDouble" : "-Infinity" } } { "array" : [ "foo", "bar" ] } { "document" : { "foo" : "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-toRelaxedJSON-002.phpt0000644000175100001660000000270514760300421020635 0ustar --TEST-- MongoDB\BSON\Document::toRelaxedExtendedJSON(): Encoding extended JSON types --FILE-- new MongoDB\BSON\ObjectId('56315a7c6118fd1b920270b1') ], [ 'binary' => new MongoDB\BSON\Binary('foo', MongoDB\BSON\Binary::TYPE_GENERIC) ], [ 'date' => new MongoDB\BSON\UTCDateTime(new MongoDB\BSON\Int64('1445990400000')) ], [ 'timestamp' => new MongoDB\BSON\Timestamp(1234, 5678) ], [ 'regex' => new MongoDB\BSON\Regex('pattern', 'i') ], [ 'code' => new MongoDB\BSON\Javascript('function() { return 1; }') ], [ 'code_ws' => new MongoDB\BSON\Javascript('function() { return a; }', ['a' => 1]) ], [ 'minkey' => new MongoDB\BSON\MinKey ], [ 'maxkey' => new MongoDB\BSON\MaxKey ], ]; foreach ($tests as $value) { echo MongoDB\BSON\Document::fromPHP($value)->toRelaxedExtendedJSON(), "\n"; } ?> ===DONE=== --EXPECT-- { "_id" : { "$oid" : "56315a7c6118fd1b920270b1" } } { "binary" : { "$binary" : { "base64" : "Zm9v", "subType" : "00" } } } { "date" : { "$date" : "2015-10-28T00:00:00Z" } } { "timestamp" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } } { "regex" : { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } } { "code" : { "$code" : "function() { return 1; }" } } { "code_ws" : { "$code" : "function() { return a; }", "$scope" : { "a" : 1 } } } { "minkey" : { "$minKey" : 1 } } { "maxkey" : { "$maxKey" : 1 } } ===DONE=== mongodb-1.21.0/tests/bson/bson-document-unserialize_error-002.phpt0000644000175100001660000000255214760300421021757 0ustar --TEST-- MongoDB\BSON\Document::__unserialize() throws on errors --FILE-- '', 'Last byte is non-zero' => pack( 'VCa*xVa*', 4 + 1 + 4 + 4 + 2, // Size: 4 bytes for size, 1 byte for type, 4 bytes for key, 4 bytes for string length, 2 bytes for string 0x02, 'foo', 2, 'a' ), 'Length does not match document length' => pack('VCa*Va*xx', 7, 0x02, 'foo', 1, 'a'), ]; foreach ($tests as $test) { echo throws(function() use ($test) { $data = base64_encode($test); $dataLength = strlen($data); $payload = sprintf( 'O:%d:"%s":1:{s:4:"data";s:%d:"%s";}', strlen(MongoDB\BSON\Document::class), MongoDB\BSON\Document::class, $dataLength, $data ); unserialize($payload); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Document initialization requires valid BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Document initialization requires valid BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Document initialization requires valid BSON ===DONE=== mongodb-1.21.0/tests/bson/bson-encode-001.phpt0000644000175100001660000002017714760300421015637 0ustar --TEST-- BSON encoding: Encoding data into BSON representation, and BSON into Extended JSON --FILE-- "world"), (object)array("hello" => "world"), array(array("hello" => "world")), array((object)array("hello" => "world")), array(array(1, 2, 3, 4, 5, 6, 7, 8, 9)), array((object)array(1, 2, 3, 4, 5, 6, 7, 8, 9)), array(array("0" => 1, "1" => 2, "2" => 3, "3" => 4, "4" => 5, "5" => 6, "6" => 7, "7" => 8, "8" => 9)), array(null), array(123), array(4.125), array(true), array(false), array("string"), array("string", true), array('test', 'foo', 'bar'), array('test' => 'test', 'foo' => 'foo', 'bar' => 'bar'), array('foo' => 'test', 'foo', 'bar'), array("int" => 3, "boolean" => true, "array" => array("foo", "bar"), "object" => new stdclass, "string" => "test", 3 => "test"), array(array("string", true)), array(array('test', 'foo', 'bar')), array(array('test' => 'test', 'foo' => 'foo', 'bar' => 'bar')), array(array('foo' => 'test', 'foo', 'bar')), array(array("int" => 3, "boolean" => true, "array" => array("foo", "bar"), "object" => new stdclass, "string" => "test", 3 => "test")), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", toJSON($s), "\n"; hex_dump($s); } ?> ===DONE=== --EXPECTF-- Test#0 { "hello" : "world" } 0 : 16 00 00 00 02 68 65 6c 6c 6f 00 06 00 00 00 77 [.....hello.....w] 10 : 6f 72 6c 64 00 00 [orld..] Test#1 { "hello" : "world" } 0 : 16 00 00 00 02 68 65 6c 6c 6f 00 06 00 00 00 77 [.....hello.....w] 10 : 6f 72 6c 64 00 00 [orld..] Test#2 { "0" : { "hello" : "world" } } 0 : 1e 00 00 00 03 30 00 16 00 00 00 02 68 65 6c 6c [.....0......hell] 10 : 6f 00 06 00 00 00 77 6f 72 6c 64 00 00 00 [o.....world...] Test#3 { "0" : { "hello" : "world" } } 0 : 1e 00 00 00 03 30 00 16 00 00 00 02 68 65 6c 6c [.....0......hell] 10 : 6f 00 06 00 00 00 77 6f 72 6c 64 00 00 00 [o.....world...] Test#4 { "0" : [ { "$numberInt" : "1" }, { "$numberInt" : "2" }, { "$numberInt" : "3" }, { "$numberInt" : "4" }, { "$numberInt" : "5" }, { "$numberInt" : "6" }, { "$numberInt" : "7" }, { "$numberInt" : "8" }, { "$numberInt" : "9" } ] } 0 : 4c 00 00 00 04 30 00 44 00 00 00 10 30 00 01 00 [L....0.D....0...] 10 : 00 00 10 31 00 02 00 00 00 10 32 00 03 00 00 00 [...1......2.....] 20 : 10 33 00 04 00 00 00 10 34 00 05 00 00 00 10 35 [.3......4......5] 30 : 00 06 00 00 00 10 36 00 07 00 00 00 10 37 00 08 [......6......7..] 40 : 00 00 00 10 38 00 09 00 00 00 00 00 [....8.......] Test#5 { "0" : { "0" : { "$numberInt" : "1" }, "1" : { "$numberInt" : "2" }, "2" : { "$numberInt" : "3" }, "3" : { "$numberInt" : "4" }, "4" : { "$numberInt" : "5" }, "5" : { "$numberInt" : "6" }, "6" : { "$numberInt" : "7" }, "7" : { "$numberInt" : "8" }, "8" : { "$numberInt" : "9" } } } 0 : 4c 00 00 00 03 30 00 44 00 00 00 10 30 00 01 00 [L....0.D....0...] 10 : 00 00 10 31 00 02 00 00 00 10 32 00 03 00 00 00 [...1......2.....] 20 : 10 33 00 04 00 00 00 10 34 00 05 00 00 00 10 35 [.3......4......5] 30 : 00 06 00 00 00 10 36 00 07 00 00 00 10 37 00 08 [......6......7..] 40 : 00 00 00 10 38 00 09 00 00 00 00 00 [....8.......] Test#6 { "0" : [ { "$numberInt" : "1" }, { "$numberInt" : "2" }, { "$numberInt" : "3" }, { "$numberInt" : "4" }, { "$numberInt" : "5" }, { "$numberInt" : "6" }, { "$numberInt" : "7" }, { "$numberInt" : "8" }, { "$numberInt" : "9" } ] } 0 : 4c 00 00 00 04 30 00 44 00 00 00 10 30 00 01 00 [L....0.D....0...] 10 : 00 00 10 31 00 02 00 00 00 10 32 00 03 00 00 00 [...1......2.....] 20 : 10 33 00 04 00 00 00 10 34 00 05 00 00 00 10 35 [.3......4......5] 30 : 00 06 00 00 00 10 36 00 07 00 00 00 10 37 00 08 [......6......7..] 40 : 00 00 00 10 38 00 09 00 00 00 00 00 [....8.......] Test#7 { "0" : null } 0 : 08 00 00 00 0a 30 00 00 [.....0..] Test#8 { "0" : { "$numberInt" : "123" } } 0 : 0c 00 00 00 10 30 00 7b 00 00 00 00 [.....0.{....] Test#9 { "0" : { "$numberDouble" : "4.125" } } 0 : 10 00 00 00 01 30 00 00 00 00 00 00 80 10 40 00 [.....0........@.] Test#10 { "0" : true } 0 : 09 00 00 00 08 30 00 01 00 [.....0...] Test#11 { "0" : false } 0 : 09 00 00 00 08 30 00 00 00 [.....0...] Test#12 { "0" : "string" } 0 : 13 00 00 00 02 30 00 07 00 00 00 73 74 72 69 6e [.....0.....strin] 10 : 67 00 00 [g..] Test#13 { "0" : "string", "1" : true } 0 : 17 00 00 00 02 30 00 07 00 00 00 73 74 72 69 6e [.....0.....strin] 10 : 67 00 08 31 00 01 00 [g..1...] Test#14 { "0" : "test", "1" : "foo", "2" : "bar" } 0 : 27 00 00 00 02 30 00 05 00 00 00 74 65 73 74 00 ['....0.....test.] 10 : 02 31 00 04 00 00 00 66 6f 6f 00 02 32 00 04 00 [.1.....foo..2...] 20 : 00 00 62 61 72 00 00 [..bar..] Test#15 { "test" : "test", "foo" : "foo", "bar" : "bar" } 0 : 2e 00 00 00 02 74 65 73 74 00 05 00 00 00 74 65 [.....test.....te] 10 : 73 74 00 02 66 6f 6f 00 04 00 00 00 66 6f 6f 00 [st..foo.....foo.] 20 : 02 62 61 72 00 04 00 00 00 62 61 72 00 00 [.bar.....bar..] Test#16 { "foo" : "test", "0" : "foo", "1" : "bar" } 0 : 29 00 00 00 02 66 6f 6f 00 05 00 00 00 74 65 73 [)....foo.....tes] 10 : 74 00 02 30 00 04 00 00 00 66 6f 6f 00 02 31 00 [t..0.....foo..1.] 20 : 04 00 00 00 62 61 72 00 00 [....bar..] Test#17 { "int" : { "$numberInt" : "3" }, "boolean" : true, "array" : [ "foo", "bar" ], "object" : { %w}, "string" : "test", "3" : "test" } 0 : 64 00 00 00 10 69 6e 74 00 03 00 00 00 08 62 6f [d....int......bo] 10 : 6f 6c 65 61 6e 00 01 04 61 72 72 61 79 00 1b 00 [olean...array...] 20 : 00 00 02 30 00 04 00 00 00 66 6f 6f 00 02 31 00 [...0.....foo..1.] 30 : 04 00 00 00 62 61 72 00 00 03 6f 62 6a 65 63 74 [....bar...object] 40 : 00 05 00 00 00 00 02 73 74 72 69 6e 67 00 05 00 [.......string...] 50 : 00 00 74 65 73 74 00 02 33 00 05 00 00 00 74 65 [..test..3.....te] 60 : 73 74 00 00 [st..] Test#18 { "0" : [ "string", true ] } 0 : 1f 00 00 00 04 30 00 17 00 00 00 02 30 00 07 00 [.....0......0...] 10 : 00 00 73 74 72 69 6e 67 00 08 31 00 01 00 00 [..string..1....] Test#19 { "0" : [ "test", "foo", "bar" ] } 0 : 2f 00 00 00 04 30 00 27 00 00 00 02 30 00 05 00 [/....0.'....0...] 10 : 00 00 74 65 73 74 00 02 31 00 04 00 00 00 66 6f [..test..1.....fo] 20 : 6f 00 02 32 00 04 00 00 00 62 61 72 00 00 00 [o..2.....bar...] Test#20 { "0" : { "test" : "test", "foo" : "foo", "bar" : "bar" } } 0 : 36 00 00 00 03 30 00 2e 00 00 00 02 74 65 73 74 [6....0......test] 10 : 00 05 00 00 00 74 65 73 74 00 02 66 6f 6f 00 04 [.....test..foo..] 20 : 00 00 00 66 6f 6f 00 02 62 61 72 00 04 00 00 00 [...foo..bar.....] 30 : 62 61 72 00 00 00 [bar...] Test#21 { "0" : { "foo" : "test", "0" : "foo", "1" : "bar" } } 0 : 31 00 00 00 03 30 00 29 00 00 00 02 66 6f 6f 00 [1....0.)....foo.] 10 : 05 00 00 00 74 65 73 74 00 02 30 00 04 00 00 00 [....test..0.....] 20 : 66 6f 6f 00 02 31 00 04 00 00 00 62 61 72 00 00 [foo..1.....bar..] 30 : 00 [.] Test#22 { "0" : { "int" : { "$numberInt" : "3" }, "boolean" : true, "array" : [ "foo", "bar" ], "object" : { %w}, "string" : "test", "3" : "test" } } 0 : 6c 00 00 00 03 30 00 64 00 00 00 10 69 6e 74 00 [l....0.d....int.] 10 : 03 00 00 00 08 62 6f 6f 6c 65 61 6e 00 01 04 61 [.....boolean...a] 20 : 72 72 61 79 00 1b 00 00 00 02 30 00 04 00 00 00 [rray......0.....] 30 : 66 6f 6f 00 02 31 00 04 00 00 00 62 61 72 00 00 [foo..1.....bar..] 40 : 03 6f 62 6a 65 63 74 00 05 00 00 00 00 02 73 74 [.object.......st] 50 : 72 69 6e 67 00 05 00 00 00 74 65 73 74 00 02 33 [ring.....test..3] 60 : 00 05 00 00 00 74 65 73 74 00 00 00 [.....test...] ===DONE=== mongodb-1.21.0/tests/bson/bson-encode-002.phpt0000644000175100001660000000764714760300421015647 0ustar --TEST-- BSON encoding: Encoding objects into BSON representation --FILE-- "class", "data"); } public function bsonUnserialize(array $data): void { echo __METHOD__, "() was called with data:\n"; var_dump($data); } } class NumericArray implements MongoDB\BSON\Serializable, MongoDB\BSON\Unserializable { #[\ReturnTypeWillChange] public function bsonSerialize() { return array(1, 2, 3); } public function bsonUnserialize(array $data): void { echo __METHOD__, "() was called with data:\n"; var_dump($data); } } echo "Testing top-level AssociativeArray:\n"; $bson = fromPHP(new AssociativeArray); echo toJSON($bson), "\n"; echo "Encoded BSON:\n"; hex_dump($bson); $value = toPHP($bson, array("root" => 'AssociativeArray')); echo "Decoded BSON:\n"; var_dump($value); echo "\nTesting embedded AssociativeArray:\n"; $bson = fromPHP(array('embed' => new AssociativeArray)); echo toJSON($bson), "\n"; echo "Encoded BSON:\n"; hex_dump($bson); $value = toPHP($bson, array("document" => 'AssociativeArray')); echo "Decoded BSON:\n"; var_dump($value); echo "\nTesting top-level NumericArray:\n"; $bson = fromPHP(new NumericArray); echo toJSON($bson), "\n"; echo "Encoded BSON:\n"; hex_dump($bson); $value = toPHP($bson, array("root" => 'NumericArray')); echo "Decoded BSON:\n"; var_dump($value); echo "\nTesting embedded NumericArray:\n"; $bson = fromPHP(array('embed' => new NumericArray)); echo toJSON($bson), "\n"; echo "Encoded BSON:\n"; hex_dump($bson); $value = toPHP($bson, array("array" => 'NumericArray')); echo "Decoded BSON:\n"; var_dump($value); ?> ===DONE=== --EXPECTF-- Testing top-level AssociativeArray: { "random" : "class", "0" : "data" } Encoded BSON: 0 : 23 00 00 00 02 72 61 6e 64 6f 6d 00 06 00 00 00 [#....random.....] 10 : 63 6c 61 73 73 00 02 30 00 05 00 00 00 64 61 74 [class..0.....dat] 20 : 61 00 00 [a..] AssociativeArray::bsonUnserialize() was called with data: array(2) { ["random"]=> string(5) "class" [0]=> string(4) "data" } Decoded BSON: object(AssociativeArray)#%d (0) { } Testing embedded AssociativeArray: { "embed" : { "random" : "class", "0" : "data" } } Encoded BSON: 0 : 2f 00 00 00 03 65 6d 62 65 64 00 23 00 00 00 02 [/....embed.#....] 10 : 72 61 6e 64 6f 6d 00 06 00 00 00 63 6c 61 73 73 [random.....class] 20 : 00 02 30 00 05 00 00 00 64 61 74 61 00 00 00 [..0.....data...] AssociativeArray::bsonUnserialize() was called with data: array(2) { ["random"]=> string(5) "class" [0]=> string(4) "data" } Decoded BSON: object(stdClass)#%d (1) { ["embed"]=> object(AssociativeArray)#%d (0) { } } Testing top-level NumericArray: { "0" : { "$numberInt" : "1" }, "1" : { "$numberInt" : "2" }, "2" : { "$numberInt" : "3" } } Encoded BSON: 0 : 1a 00 00 00 10 30 00 01 00 00 00 10 31 00 02 00 [.....0......1...] 10 : 00 00 10 32 00 03 00 00 00 00 [...2......] NumericArray::bsonUnserialize() was called with data: array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } Decoded BSON: object(NumericArray)#%d (0) { } Testing embedded NumericArray: { "embed" : [ { "$numberInt" : "1" }, { "$numberInt" : "2" }, { "$numberInt" : "3" } ] } Encoded BSON: 0 : 26 00 00 00 04 65 6d 62 65 64 00 1a 00 00 00 10 [&....embed......] 10 : 30 00 01 00 00 00 10 31 00 02 00 00 00 10 32 00 [0......1......2.] 20 : 03 00 00 00 00 00 [......] NumericArray::bsonUnserialize() was called with data: array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } Decoded BSON: object(stdClass)#%d (1) { ["embed"]=> object(NumericArray)#%d (0) { } } ===DONE=== mongodb-1.21.0/tests/bson/bson-encode-003.phpt0000644000175100001660000001101314760300421015626 0ustar --TEST-- BSON encoding: Encoding objects into BSON representation --FILE-- "class", "data" ); } public function bsonUnserialize(array $data): void { $this->props = $data; } } class MyClass2 implements MongoDB\BSON\Persistable { private $props; #[\ReturnTypeWillChange] public function bsonSerialize() { return array( 1, 2, 3, ); } public function bsonUnserialize(array $data): void { $this->props = $data; } } $tests = array( array("stuff" => new MyClass), array("stuff" => new MyClass2), array("stuff" => array(new MyClass, new MyClass2)), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", toJSON($s), "\n"; hex_dump($s); $ret = toPHP($s); var_dump($ret); } ?> ===DONE=== --EXPECTF-- Test#0 { "stuff" : { "__pclass" : { "$binary" : { "base64" : "TXlDbGFzcw==", "subType" : "80" } }, "random" : "class", "0" : "data" } } 0 : 45 00 00 00 03 73 74 75 66 66 00 39 00 00 00 05 [E....stuff.9....] 10 : 5f 5f 70 63 6c 61 73 73 00 07 00 00 00 80 4d 79 [__pclass......My] 20 : 43 6c 61 73 73 02 72 61 6e 64 6f 6d 00 06 00 00 [Class.random....] 30 : 00 63 6c 61 73 73 00 02 30 00 05 00 00 00 64 61 [.class..0.....da] 40 : 74 61 00 00 00 [ta...] object(stdClass)#%d (1) { ["stuff"]=> object(MyClass)#%d (1) { ["props":"MyClass":private]=> array(3) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } ["random"]=> string(5) "class" [0]=> string(4) "data" } } } Test#1 { "stuff" : { "__pclass" : { "$binary" : { "base64" : "TXlDbGFzczI=", "subType" : "80" } }, "0" : { "$numberInt" : "1" }, "1" : { "$numberInt" : "2" }, "2" : { "$numberInt" : "3" } } } 0 : 3d 00 00 00 03 73 74 75 66 66 00 31 00 00 00 05 [=....stuff.1....] 10 : 5f 5f 70 63 6c 61 73 73 00 08 00 00 00 80 4d 79 [__pclass......My] 20 : 43 6c 61 73 73 32 10 30 00 01 00 00 00 10 31 00 [Class2.0......1.] 30 : 02 00 00 00 10 32 00 03 00 00 00 00 00 [.....2.......] object(stdClass)#%d (1) { ["stuff"]=> object(MyClass2)#%d (1) { ["props":"MyClass2":private]=> array(4) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "MyClass2" ["type"]=> int(128) } [0]=> int(1) [1]=> int(2) [2]=> int(3) } } } Test#2 { "stuff" : [ { "__pclass" : { "$binary" : { "base64" : "TXlDbGFzcw==", "subType" : "80" } }, "random" : "class", "0" : "data" }, { "__pclass" : { "$binary" : { "base64" : "TXlDbGFzczI=", "subType" : "80" } }, "0" : { "$numberInt" : "1" }, "1" : { "$numberInt" : "2" }, "2" : { "$numberInt" : "3" } } ] } 0 : 81 00 00 00 04 73 74 75 66 66 00 75 00 00 00 03 [.....stuff.u....] 10 : 30 00 39 00 00 00 05 5f 5f 70 63 6c 61 73 73 00 [0.9....__pclass.] 20 : 07 00 00 00 80 4d 79 43 6c 61 73 73 02 72 61 6e [.....MyClass.ran] 30 : 64 6f 6d 00 06 00 00 00 63 6c 61 73 73 00 02 30 [dom.....class..0] 40 : 00 05 00 00 00 64 61 74 61 00 00 03 31 00 31 00 [.....data...1.1.] 50 : 00 00 05 5f 5f 70 63 6c 61 73 73 00 08 00 00 00 [...__pclass.....] 60 : 80 4d 79 43 6c 61 73 73 32 10 30 00 01 00 00 00 [.MyClass2.0.....] 70 : 10 31 00 02 00 00 00 10 32 00 03 00 00 00 00 00 [.1......2.......] 80 : 00 [.] object(stdClass)#%d (1) { ["stuff"]=> array(2) { [0]=> object(MyClass)#%d (1) { ["props":"MyClass":private]=> array(3) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } ["random"]=> string(5) "class" [0]=> string(4) "data" } } [1]=> object(MyClass2)#%d (1) { ["props":"MyClass2":private]=> array(4) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "MyClass2" ["type"]=> int(128) } [0]=> int(1) [1]=> int(2) [2]=> int(3) } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-encode-004.phpt0000644000175100001660000001063214760300421015635 0ustar --TEST-- BSON encoding: Object Document Mapper --FILE-- addAddress($sunnyvale); $hannes->addAddress($kopavogur); $mikola = new Person("Jeremy", 21); $michigan = new Address(48169, "USA"); $hannes->addFriend($mikola); var_dump($hannes); $s = fromPHP(array($hannes)); echo "Test ", toJSON($s), "\n"; hex_dump($s); $ret = toPHP($s); var_dump($ret); ?> ===DONE=== --EXPECTF-- object(Person)#%d (5) { ["name":protected]=> string(6) "Hannes" ["age":protected]=> int(42) ["addresses":protected]=> array(2) { [0]=> object(Address)#%d (2) { ["zip":protected]=> int(94086) ["country":protected]=> string(3) "USA" } [1]=> object(Address)#%d (2) { ["zip":protected]=> int(200) ["country":protected]=> string(7) "Iceland" } } ["friends":protected]=> array(1) { [0]=> object(Person)#%d (5) { ["name":protected]=> string(6) "Jeremy" ["age":protected]=> int(21) ["addresses":protected]=> array(0) { } ["friends":protected]=> array(0) { } ["secret":protected]=> string(24) "Jeremy confidential info" } } ["secret":protected]=> string(24) "Hannes confidential info" } Test { "0" : { "__pclass" : { "$binary" : { "base64" : "UGVyc29u", "subType" : "80" } }, "name" : "Hannes", "age" : { "$numberInt" : "42" }, "addresses" : [ { "__pclass" : { "$binary" : { "base64" : "QWRkcmVzcw==", "subType" : "80" } }, "zip" : { "$numberInt" : "94086" }, "country" : "USA" }, { "__pclass" : { "$binary" : { "base64" : "QWRkcmVzcw==", "subType" : "80" } }, "zip" : { "$numberInt" : "200" }, "country" : "Iceland" } ], "friends" : [ { "__pclass" : { "$binary" : { "base64" : "UGVyc29u", "subType" : "80" } }, "name" : "Jeremy", "age" : { "$numberInt" : "21" }, "addresses" : [ %w], "friends" : [ %w] } ] } } 0 : 23 01 00 00 03 30 00 1b 01 00 00 05 5f 5f 70 63 [#....0......__pc] 10 : 6c 61 73 73 00 06 00 00 00 80 50 65 72 73 6f 6e [lass......Person] 20 : 02 6e 61 6d 65 00 07 00 00 00 48 61 6e 6e 65 73 [.name.....Hannes] 30 : 00 10 61 67 65 00 2a 00 00 00 04 61 64 64 72 65 [..age.*....addre] 40 : 73 73 65 73 00 79 00 00 00 03 30 00 35 00 00 00 [sses.y....0.5...] 50 : 05 5f 5f 70 63 6c 61 73 73 00 07 00 00 00 80 41 [.__pclass......A] 60 : 64 64 72 65 73 73 10 7a 69 70 00 86 6f 01 00 02 [ddress.zip..o...] 70 : 63 6f 75 6e 74 72 79 00 04 00 00 00 55 53 41 00 [country.....USA.] 80 : 00 03 31 00 39 00 00 00 05 5f 5f 70 63 6c 61 73 [..1.9....__pclas] 90 : 73 00 07 00 00 00 80 41 64 64 72 65 73 73 10 7a [s......Address.z] A0 : 69 70 00 c8 00 00 00 02 63 6f 75 6e 74 72 79 00 [ip......country.] B0 : 08 00 00 00 49 63 65 6c 61 6e 64 00 00 00 04 66 [....Iceland....f] C0 : 72 69 65 6e 64 73 00 5a 00 00 00 03 30 00 52 00 [riends.Z....0.R.] D0 : 00 00 05 5f 5f 70 63 6c 61 73 73 00 06 00 00 00 [...__pclass.....] E0 : 80 50 65 72 73 6f 6e 02 6e 61 6d 65 00 07 00 00 [.Person.name....] F0 : 00 4a 65 72 65 6d 79 00 10 61 67 65 00 15 00 00 [.Jeremy..age....] 100 : 00 04 61 64 64 72 65 73 73 65 73 00 05 00 00 00 [..addresses.....] 110 : 00 04 66 72 69 65 6e 64 73 00 05 00 00 00 00 00 [..friends.......] 120 : 00 00 00 [...] object(stdClass)#%d (1) { ["0"]=> object(Person)#%d (5) { ["name":protected]=> string(6) "Hannes" ["age":protected]=> int(42) ["addresses":protected]=> array(2) { [0]=> object(Address)#%d (2) { ["zip":protected]=> int(94086) ["country":protected]=> string(3) "USA" } [1]=> object(Address)#%d (2) { ["zip":protected]=> int(200) ["country":protected]=> string(7) "Iceland" } } ["friends":protected]=> array(1) { [0]=> object(Person)#%d (5) { ["name":protected]=> string(6) "Jeremy" ["age":protected]=> int(21) ["addresses":protected]=> array(0) { } ["friends":protected]=> array(0) { } ["secret":protected]=> string(4) "none" } } ["secret":protected]=> string(4) "none" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-encode-005.phpt0000644000175100001660000000134114760300421015633 0ustar --TEST-- BSON encoding: Object Document Mapper --FILE-- array(), "emptyclass" => new stdclass, ); $s = fromPHP($data); echo "Test ", toJSON($s), "\n"; hex_dump($s); $ret = toPHP($s); var_dump($ret); ?> ===DONE=== --EXPECTF-- Test { "emptyarray" : [ %w], "emptyclass" : { %w} } 0 : 27 00 00 00 04 65 6d 70 74 79 61 72 72 61 79 00 ['....emptyarray.] 10 : 05 00 00 00 00 03 65 6d 70 74 79 63 6c 61 73 73 [......emptyclass] 20 : 00 05 00 00 00 00 00 [.......] object(stdClass)#%d (2) { ["emptyarray"]=> array(0) { } ["emptyclass"]=> object(stdClass)#%d (0) { } } ===DONE=== mongodb-1.21.0/tests/bson/bson-enum-001.phpt0000644000175100001660000000071014760300421015335 0ustar --TEST-- Backed enums serialize as their case value --FILE-- MyIntBackedEnum::A, 'y' => MyStringBackedEnum::A, ]; echo toCanonicalExtendedJSON(fromPHP($document)), "\n"; ?> ===DONE=== --EXPECTF-- { "x" : { "$numberInt" : "1" }, "y" : "a" } ===DONE=== mongodb-1.21.0/tests/bson/bson-enum-002.phpt0000644000175100001660000000215214760300421015340 0ustar --TEST-- Backed enums round-tripped through parent document --FILE-- $this->x, 'y' => $this->y, ]; } public function bsonUnserialize(array $data): void { if (isset($data['x'])) { $this->x = MyIntBackedEnum::from($data['x']); } if (isset($data['y'])) { $this->y = MyStringBackedEnum::from($data['y']); } } } $document = new MyDocument(MyIntBackedEnum::A, MyStringBackedEnum::A); var_dump(toPHP(fromPHP($document))); ?> ===DONE=== --EXPECTF-- object(MyDocument)#%d (%d) { ["x":"MyDocument":private]=> enum(MyIntBackedEnum::A) ["y":"MyDocument":private]=> enum(MyStringBackedEnum::A) } ===DONE=== mongodb-1.21.0/tests/bson/bson-enum-003.phpt0000644000175100001660000000321414760300421015341 0ustar --TEST-- Enums implementing Serializable round-tripped through parent document --FILE-- $this->x, 'y' => $this->y, ]; } public function bsonUnserialize(array $data): void { if (isset($data['x'])) { // See: https://www.php.net/manual/en/language.enumerations.basics.php#127112 $this->x = constant(MyEnum::class . '::' . $data['x']->name); } if (isset($data['y'])) { $this->y = MyBackedEnum::from($data['y']->value); } } } $document = new MyDocument(MyEnum::A, MyBackedEnum::A); var_dump(toPHP(fromPHP($document))); ?> ===DONE=== --EXPECTF-- object(MyDocument)#%d (%d) { ["x":"MyDocument":private]=> enum(MyEnum::A) ["y":"MyDocument":private]=> enum(MyBackedEnum::A) } ===DONE=== mongodb-1.21.0/tests/bson/bson-enum_error-001.phpt0000644000175100001660000000052014760300421016545 0ustar --TEST-- Enum cannot implement Unserializable --FILE-- ===DONE=== --EXPECTF-- Fatal error: Enum class MyEnum cannot implement interface MongoDB\BSON\Unserializable in %s on line %d mongodb-1.21.0/tests/bson/bson-enum_error-002.phpt0000644000175100001660000000055414760300421016555 0ustar --TEST-- Backed enum cannot implement Unserializable --FILE-- ===DONE=== --EXPECTF-- Fatal error: Enum class MyBackedEnum cannot implement interface MongoDB\BSON\Unserializable in %s on line %d mongodb-1.21.0/tests/bson/bson-enum_error-003.phpt0000644000175100001660000000056614760300421016561 0ustar --TEST-- Enum cannot implement Persistable --FILE-- ===DONE=== --EXPECTF-- Fatal error: Enum class MyEnum cannot implement interface MongoDB\BSON\Persistable in %s on line %d mongodb-1.21.0/tests/bson/bson-enum_error-004.phpt0000644000175100001660000000062214760300421016553 0ustar --TEST-- Backed enum cannot implement Persistable --FILE-- ===DONE=== --EXPECTF-- Fatal error: Enum class MyBackedEnum cannot implement interface MongoDB\BSON\Persistable in %s on line %d mongodb-1.21.0/tests/bson/bson-enum_error-005.phpt0000644000175100001660000000130614760300421016554 0ustar --TEST-- Enums cannot be serialized as a root element --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Enum MyEnum cannot be serialized as a root element OK: Got MongoDB\Driver\Exception\UnexpectedValueException Enum MyBackedEnum cannot be serialized as a root element ===DONE=== mongodb-1.21.0/tests/bson/bson-enum_error-006.phpt0000644000175100001660000000067114760300421016561 0ustar --TEST-- Non-backed enums cannot be serialized --FILE-- MyEnum::A]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Non-backed enum MyEnum cannot be serialized for field path "x" ===DONE=== mongodb-1.21.0/tests/bson/bson-fromJSON-001.phpt0000644000175100001660000000245014760300421016031 0ustar --TEST-- MongoDB\BSON\fromJSON(): Decoding JSON --FILE-- ===DONE=== --EXPECTF-- Test {} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 05 00 00 00 00 [.....] Test { "foo": "bar" } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 12 00 00 00 02 66 6f 6f 00 04 00 00 00 62 61 72 [.....foo.....bar] 10 : 00 00 [..] Test { "foo": [ 1, 2, 3 ]} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 24 00 00 00 04 66 6f 6f 00 1a 00 00 00 10 30 00 [$....foo......0.] 10 : 01 00 00 00 10 31 00 02 00 00 00 10 32 00 03 00 [.....1......2...] 20 : 00 00 00 00 [....] Test { "foo": { "bar": 1 }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 18 00 00 00 03 66 6f 6f 00 0e 00 00 00 10 62 61 [.....foo......ba] 10 : 72 00 01 00 00 00 00 00 [r.......] ===DONE=== mongodb-1.21.0/tests/bson/bson-fromJSON-002.phpt0000644000175100001660000000551014760300421016032 0ustar --TEST-- MongoDB\BSON\fromJSON(): Decoding extended JSON types --FILE-- ===DONE=== --EXPECTF-- Test { "_id": { "$oid": "56315a7c6118fd1b920270b1" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 16 00 00 00 07 5f 69 64 00 56 31 5a 7c 61 18 fd [....._id.V1Z|a..] 10 : 1b 92 02 70 b1 00 [...p..] Test { "binary": { "$binary": "Zm9v", "$type": "00" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 15 00 00 00 05 62 69 6e 61 72 79 00 03 00 00 00 [.....binary.....] 10 : 00 66 6f 6f 00 [.foo.] Test { "date": { "$date": "2015-10-28T00:00:00Z" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 13 00 00 00 09 64 61 74 65 00 00 80 be ab 50 01 [.....date.....P.] 10 : 00 00 00 [...] Test { "timestamp": { "$timestamp": { "t": 1446084619, "i": 0 }}} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 18 00 00 00 11 74 69 6d 65 73 74 61 6d 70 00 00 [.....timestamp..] 10 : 00 00 00 0b 80 31 56 00 [.....1V.] Test { "regex": { "$regex": "pattern", "$options": "i" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 16 00 00 00 0b 72 65 67 65 78 00 70 61 74 74 65 [.....regex.patte] 10 : 72 6e 00 69 00 00 [rn.i..] Test { "undef": { "$undefined": true }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 0c 00 00 00 06 75 6e 64 65 66 00 00 [.....undef..] Test { "minkey": { "$minKey": 1 }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 0d 00 00 00 ff 6d 69 6e 6b 65 79 00 00 [.....minkey..] Test { "maxkey": { "$maxKey": 1 }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 0d 00 00 00 7f 6d 61 78 6b 65 79 00 00 [.....maxkey..] Test { "long": { "$numberLong": "1234" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 13 00 00 00 12 6c 6f 6e 67 00 d2 04 00 00 00 00 [.....long.......] 10 : 00 00 00 [...] ===DONE=== mongodb-1.21.0/tests/bson/bson-fromJSON-003.phpt0000644000175100001660000000114314760300421016031 0ustar --TEST-- MongoDB\BSON\fromJSON(): Decoding JSON with duplicate field names --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s 0 : 1f 00 00 00 02 66 6f 6f 00 04 00 00 00 62 61 72 [.....foo.....bar] 10 : 00 02 66 6f 6f 00 04 00 00 00 62 61 7a 00 00 [..foo.....baz..] ===DONE=== mongodb-1.21.0/tests/bson/bson-fromJSON_error-001.phpt0000644000175100001660000000062014760300421017237 0ustar --TEST-- MongoDB\BSON\fromJSON(): invalid JSON --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP-001.phpt0000644000175100001660000001535014760300421015712 0ustar --TEST-- MongoDB\BSON\fromPHP(): bsonSerialize() allows arrays, stdClass instances, BSON arrays, and BSON documents --FILE-- data = $data; } #[\ReturnTypeWillChange] public function bsonSerialize() { return $this->data; } } class MyPersistableDocument extends MyDocument implements MongoDB\BSON\Persistable { public function bsonUnserialize(array $data): void { $this->data = $data; } } $tests = array( array(1, 2, 3), array('foo' => 'bar'), (object) array(1, 2, 3), (object) array('foo' => 'bar'), /* PackedArray cannot be serialized as a root document. Additionally, it * will fail return type validation for Persistable::bsonSerialize(). */ MongoDB\BSON\PackedArray::fromPHP([1, 2, 3]), MongoDB\BSON\Document::fromPHP(['foo' => 'bar']), ); echo "Testing top-level objects\n"; foreach ($tests as $test) { try { echo MongoDB\BSON\toJson(MongoDB\BSON\fromPHP(new MyDocument($test))), "\n"; } catch (Exception $e) { printf("%s: %s\n", get_class($e), $e->getMessage()); } try { echo MongoDB\BSON\toJson(MongoDB\BSON\fromPHP(new MyPersistableDocument($test))), "\n"; } catch (Exception $e) { printf("%s: %s\n", get_class($e), $e->getMessage()); } } echo "\nTesting nested objects\n"; foreach ($tests as $test) { try { echo MongoDB\BSON\toJson(MongoDB\BSON\fromPHP(new MyDocument(['nested' => new MyDocument($test)]))), "\n"; } catch (Exception $e) { printf("%s: %s\n", get_class($e), $e->getMessage()); } try { echo MongoDB\BSON\toJson(MongoDB\BSON\fromPHP(new MyDocument(['nested' => new MyPersistableDocument($test)]))), "\n"; } catch (Exception $e) { printf("%s: %s\n", get_class($e), $e->getMessage()); } } ?> ===DONE=== --EXPECTF-- Testing top-level objects Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "0" : 1, "1" : 2, "2" : 3 } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "0" : 1, "1" : 2, "2" : 3 } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "foo" : "bar" } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "0" : 1, "1" : 2, "2" : 3 } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "0" : 1, "1" : 2, "2" : 3 } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "foo" : "bar" } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s MongoDB\Driver\Exception\UnexpectedValueException: MongoDB\BSON\PackedArray cannot be serialized as a root document Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s MongoDB\Driver\Exception\UnexpectedValueException: Expected MyPersistableDocument::bsonSerialize() to return an array, stdClass, or MongoDB\BSON\Document, MongoDB\BSON\PackedArray given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "foo" : "bar" } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" } Testing nested objects Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : [ 1, 2, 3 ] } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "0" : 1, "1" : 2, "2" : 3 } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "foo" : "bar" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "0" : 1, "1" : 2, "2" : 3 } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "0" : 1, "1" : 2, "2" : 3 } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "foo" : "bar" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : [ 1, 2, 3 ] } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s MongoDB\Driver\Exception\UnexpectedValueException: Expected MyPersistableDocument::bsonSerialize() to return an array, stdClass, or MongoDB\BSON\Document, MongoDB\BSON\PackedArray given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "foo" : "bar" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nested" : { "__pclass" : { "$binary" : "TXlQZXJzaXN0YWJsZURvY3VtZW50", "$type" : "80" }, "foo" : "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP-002.phpt0000644000175100001660000000114614760300421015711 0ustar --TEST-- MongoDB\BSON\fromPHP(): Encoding non-Persistable objects as a document --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "baz" : 3 } 0 : 0e 00 00 00 10 62 61 7a 00 03 00 00 00 00 [.....baz......] ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP-003.phpt0000644000175100001660000000340614760300421015713 0ustar --TEST-- MongoDB\BSON\fromPHP(): Encoding non-Persistable objects as a document field value --FILE-- new MongoDB\BSON\UTCDateTime(new MongoDB\BSON\Int64('1416445411987'))), array(new MyDocument), array('x' => new MyDocument), ); foreach ($tests as $document) { $s = MongoDB\BSON\fromPHP($document); echo "Test " . MongoDB\BSON\toJSON($s) . "\n"; hex_dump($s); } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "0" : { "$date" : 1416445411987 } } 0 : 10 00 00 00 09 30 00 93 c2 b9 ca 49 01 00 00 00 [.....0.....I....] Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : { "$date" : 1416445411987 } } 0 : 10 00 00 00 09 78 00 93 c2 b9 ca 49 01 00 00 00 [.....x.....I....] Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "0" : { "baz" : 3 } } 0 : 16 00 00 00 03 30 00 0e 00 00 00 10 62 61 7a 00 [.....0......baz.] 10 : 03 00 00 00 00 00 [......] Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : { "baz" : 3 } } 0 : 16 00 00 00 03 78 00 0e 00 00 00 10 62 61 7a 00 [.....x......baz.] 10 : 03 00 00 00 00 00 [......] ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP-005.phpt0000644000175100001660000000152014760300421015710 0ustar --TEST-- MongoDB\BSON\fromPHP(): PHP document with public property whose name is an empty string --FILE-- 1], (object) ['' => 1], ]; foreach ($tests as $document) { $s = MongoDB\BSON\fromPHP($document); echo "Test " . MongoDB\BSON\toJSON($s) . "\n"; hex_dump($s); } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "" : 1 } 0 : 0b 00 00 00 10 00 01 00 00 00 00 [...........] Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "" : 1 } 0 : 0b 00 00 00 10 00 01 00 00 00 00 [...........] ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP-006.phpt0000644000175100001660000000200314760300421015706 0ustar --TEST-- MongoDB\BSON\fromPHP(): PHP documents with null bytes in field name --FILE-- 1])); echo "\nTesting object with multiple null bytes in field name\n"; hex_dump(MongoDB\BSON\fromPHP((object) ["\0\0\0" => 1])); ?> ===DONE=== --EXPECTF-- Testing object with one leading null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s 0 : 05 00 00 00 00 [.....] Testing object with multiple null bytes in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s 0 : 05 00 00 00 00 [.....] ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-001.phpt0000644000175100001660000000610314760300421017117 0ustar --TEST-- MongoDB\BSON\fromPHP(): bsonSerialize() must return an array or stdClass --FILE-- data = $data; } #[\ReturnTypeWillChange] public function bsonSerialize() { return $this->data; } } $invalidValues = array(null, 123, 'foo', true, new MyDocument); echo "Testing top-level objects\n"; foreach ($invalidValues as $invalidValue) { try { hex_dump(MongoDB\BSON\fromPHP(new MyDocument($invalidValue))); } catch (MongoDB\Driver\Exception\UnexpectedValueException $e) { echo $e->getMessage(), "\n"; } } echo "\nTesting nested objects\n"; foreach ($invalidValues as $invalidValue) { try { hex_dump(MongoDB\BSON\fromPHP(new MyDocument(array('nested' => new MyDocument($invalidValue))))); } catch (MongoDB\Driver\Exception\UnexpectedValueException $e) { echo $e->getMessage(), "\n"; } } ?> ===DONE=== --EXPECTF-- Testing top-level objects Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, null given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, int given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, string given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, bool given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, MyDocument given Testing nested objects Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, null given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, int given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, string given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, bool given Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Expected MyDocument::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, MyDocument given ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-002.phpt0000644000175100001660000000156014760300421017122 0ustar --TEST-- MongoDB\BSON\fromPHP(): Encoding unknown Type objects as a document field value --FILE-- new UnknownType()), ); foreach ($tests as $document) { echo throws(function() use ($document) { MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Unexpected MongoDB\BSON\Type instance: UnknownType Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Unexpected MongoDB\BSON\Type instance: UnknownType ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-003.phpt0000644000175100001660000000535014760300421017124 0ustar --TEST-- MongoDB\BSON\fromPHP(): Encoding non-Serializable Type objects as a root element --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance UnknownType cannot be serialized as a root element Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance MongoDB\BSON\Binary cannot be serialized as a root element Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance MongoDB\BSON\Javascript cannot be serialized as a root element Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance MongoDB\BSON\MinKey cannot be serialized as a root element Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance MongoDB\BSON\MaxKey cannot be serialized as a root element Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance MongoDB\BSON\ObjectId cannot be serialized as a root element Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance MongoDB\BSON\Regex cannot be serialized as a root element Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance MongoDB\BSON\Timestamp cannot be serialized as a root element Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\Type instance MongoDB\BSON\UTCDateTime cannot be serialized as a root element ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-004.phpt0000644000175100001660000000614014760300421017123 0ustar --TEST-- MongoDB\BSON\fromPHP(): PHP documents with circular references --FILE-- 1, 'y' => []]; $document['y'][] = &$document['y']; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting packed array with circular reference at 3rd position\n"; echo throws(function() { $document = ['x' => 1, 'y' => [1, 2, 3]]; $document['y'][] = &$document['y']; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting associative array with circular reference\n"; echo throws(function() { $document = ['x' => 1, 'y' => []]; $document['y']['z'] = &$document['y']; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting associative array and nested array with circular reference\n"; echo throws(function() { $document = ['x' => 1, 'y' => []]; $document['y'][0]['z'] = &$document['y']; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting object with circular reference\n"; echo throws(function() { $document = (object) ['x' => 1, 'y' => (object) []]; $document->y->z = &$document->y; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting nested object with circular reference\n"; echo throws(function() { $document = (object) ['x' => 1, 'y' => (object) ['z' => (object) []]]; $document->y->z->a = &$document->y; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- Testing packed array with circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.0" Testing packed array with circular reference at 3rd position Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.3" Testing associative array with circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.z" Testing associative array and nested array with circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.0.z" Testing object with circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.z" Testing nested object with circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.z.a" ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-005.phpt0000644000175100001660000000304114760300421017121 0ustar --TEST-- MongoDB\BSON\fromPHP(): Serializable with circular references --FILE-- $this]; } } echo "\nTesting Serializable with direct circular reference\n"; echo throws(function() { MongoDB\BSON\fromPHP(new MyRecursiveSerializable); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting Serializable with indirect circular reference\n"; echo throws(function() { MongoDB\BSON\fromPHP(new MyIndirectlyRecursiveSerializable); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- Testing Serializable with direct circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Expected MyRecursiveSerializable::bsonSerialize() to return an array, stdClass, MongoDB\BSON\Document, or MongoDB\BSON\PackedArray, MyRecursiveSerializable given Testing Serializable with indirect circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "parent.parent" ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-006.phpt0000644000175100001660000000470114760300421017126 0ustar --TEST-- MongoDB\BSON\fromPHP(): PHP documents with null bytes in field name --DESCRIPTION-- BSON Corpus spec prose test #1 --FILE-- 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting array with one trailing null byte in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(["a\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting array with multiple null bytes in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(["\0\0\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting object with one trailing null byte in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP((object) ["a\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting nested array with one trailing null byte in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(['a' => ["b\0" => 1]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- Testing array with one leading null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". Testing array with one trailing null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "a". Testing array with multiple null bytes in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". Testing object with one trailing null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "a". Testing nested array with one trailing null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "b". ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-007.phpt0000644000175100001660000000710214760300421017125 0ustar --TEST-- MongoDB\BSON\fromPHP(): Serializable returns document with null bytes in field name --FILE-- data = $data; } #[\ReturnTypeWillChange] public function bsonSerialize() { return $this->data; } } echo "\nTesting array with one leading null byte in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(new MySerializable(["\0" => 1])); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting array with one trailing null byte in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(new MySerializable(["a\0" => 1])); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting array with multiple null bytes in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(new MySerializable(["\0\0\0" => 1])); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; /* Per PHPC-884, field names with a leading null byte are ignored when encoding * a document from an object's property hash table, since PHP uses leading bytes * to denote protected and private properties. However, in this case the object * was returned from Serializable::bsonSerialize() and we skip the check for * protected and private properties. */ echo "\nTesting object with one leading null byte in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(new MySerializable((object) ["\0" => 1])); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting object with one trailing null byte in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(new MySerializable((object) ["a\0" => 1])); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting object with multiple null bytes in field name\n"; echo throws(function() { MongoDB\BSON\fromPHP(new MySerializable((object) ["\0\0\0" => 1])); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- Testing array with one leading null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". Testing array with one trailing null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "a". Testing array with multiple null bytes in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". Testing object with one leading null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". Testing object with one trailing null byte in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "a". Testing object with multiple null bytes in field name Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-008.phpt0000644000175100001660000000314114760300421017125 0ustar --TEST-- MongoDB\BSON\fromPHP(): PHP documents with circular references --FILE-- 1, 'y' => [1, 2, 3]]; $document['y'][] = &$document['y']; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting associative array with circular reference\n"; echo throws(function() { $document = ['x' => 1, 'y' => []]; $document['y'][0]['z'] = &$document['y']; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; echo "\nTesting object with circular reference\n"; echo throws(function() { $document = (object) ['x' => 1, 'y' => (object) []]; $document->y->z = &$document->y; MongoDB\BSON\fromPHP($document); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- Testing packed array with circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.3" Testing associative array with circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.0.z" Testing object with circular reference Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected recursion for field path "y.z" ===DONE=== mongodb-1.21.0/tests/bson/bson-fromPHP_error-009.phpt0000644000175100001660000000104314760300421017125 0ustar --TEST-- MongoDB\BSON\fromPHP(): PackedArray cannot be serialized as root document --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/bson/bson-generate-document-id.phpt0000644000175100001660000000270614760300421020102 0ustar --TEST-- _id should only be generated for top-level document, not embedded docs --SKIPIF-- --FILE-- "bob", "address" => [ "street" => "Main St.", "city" => "New York", ], ]; $bulk = new MongoDB\Driver\BulkWrite(); $user["_id"] = $bulk->insert($user); $result = $manager->executeBulkWrite(NS, $bulk); echo "Dumping inserted user document with injected _id:\n"; var_dump($user); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(["_id" => $user["_id"]])); echo "\nDumping fetched user document:\n"; $array = $cursor->toArray(); var_dump($array[0]); ?> ===DONE=== --EXPECTF-- Dumping inserted user document with injected _id: array(3) { ["username"]=> string(3) "bob" ["address"]=> array(2) { ["street"]=> string(8) "Main St." ["city"]=> string(8) "New York" } ["_id"]=> object(%s\ObjectId)#%d (%d) { ["oid"]=> string(24) "%s" } } Dumping fetched user document: object(stdClass)#%d (3) { ["_id"]=> object(%s\ObjectId)#%d (%d) { ["oid"]=> string(24) "%s" } ["username"]=> string(3) "bob" ["address"]=> object(stdClass)#%d (%d) { ["street"]=> string(8) "Main St." ["city"]=> string(8) "New York" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-001.phpt0000644000175100001660000000567314760300421015352 0ustar --TEST-- MongoDB\BSON\Int64 roundtripped through BSON on 32-bit platforms --SKIPIF-- --FILE-- new MongoDB\BSON\Int64('9223372036854775807')], (object) ['int64' => new MongoDB\BSON\Int64('-9223372036854775808')], (object) ['int64' => new MongoDB\BSON\Int64('2147483648')], (object) ['int64' => new MongoDB\BSON\Int64('-2147483649')], ]; foreach($tests as $test) { $bson = MongoDB\BSON\fromPHP($test); $testRoundtripped = MongoDB\BSON\toPHP($bson); $bsonRoundtripped = MongoDB\BSON\fromPHP($testRoundtripped); $json = MongoDB\BSON\toJSON($bson); $jsonRoundtripped = MongoDB\BSON\toJSON($bsonRoundtripped); var_dump($test->int64 instanceof MongoDB\BSON\Int64); var_dump($testRoundtripped->int64 instanceof MongoDB\BSON\Int64); var_dump($json, $jsonRoundtripped); var_dump($test == $testRoundtripped); echo "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s bool(true) bool(true) string(33) "{ "int64" : 9223372036854775807 }" string(33) "{ "int64" : 9223372036854775807 }" bool(true) Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s bool(true) bool(true) string(34) "{ "int64" : -9223372036854775808 }" string(34) "{ "int64" : -9223372036854775808 }" bool(true) Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s bool(true) bool(true) string(24) "{ "int64" : 2147483648 }" string(24) "{ "int64" : 2147483648 }" bool(true) Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s bool(true) bool(true) string(25) "{ "int64" : -2147483649 }" string(25) "{ "int64" : -2147483649 }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-002.phpt0000644000175100001660000000460714760300421015347 0ustar --TEST-- MongoDB\BSON\Int64 wraps 64-bit integers on 32-bit platforms --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["max64"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["min64"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(20) "-9223372036854775808" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["max32+1"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(10) "2147483648" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["min32-1"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(11) "-2147483649" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["max32"]=> int(2147483647) } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["min32"]=> int(-2147483648) } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["zero"]=> int(0) } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-003.phpt0000644000175100001660000000241014760300421015336 0ustar --TEST-- MongoDB\BSON\Int64 encoded as 64-bit integer in BSON --FILE-- new MongoDB\BSON\Int64('9223372036854775807')], ['int64' => new MongoDB\BSON\Int64('-9223372036854775808')], ['int64' => new MongoDB\BSON\Int64('2147483648')], ['int64' => new MongoDB\BSON\Int64('-2147483649')], ['int64' => new MongoDB\BSON\Int64(0)], ]; foreach($tests as $test) { $bson = fromPHP($test); hex_dump($bson); echo "\n"; } ?> ===DONE=== --EXPECT-- 0 : 14 00 00 00 12 69 6e 74 36 34 00 ff ff ff ff ff [.....int64......] 10 : ff ff 7f 00 [....] 0 : 14 00 00 00 12 69 6e 74 36 34 00 00 00 00 00 00 [.....int64......] 10 : 00 00 80 00 [....] 0 : 14 00 00 00 12 69 6e 74 36 34 00 00 00 00 80 00 [.....int64......] 10 : 00 00 00 00 [....] 0 : 14 00 00 00 12 69 6e 74 36 34 00 ff ff ff 7f ff [.....int64......] 10 : ff ff ff 00 [....] 0 : 14 00 00 00 12 69 6e 74 36 34 00 00 00 00 00 00 [.....int64......] 10 : 00 00 00 00 [....] ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-cast-001.phpt0000644000175100001660000000107614760300421016273 0ustar --TEST-- MongoDB\BSON\Int64 casting --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "2" } int(2) float(2) string(1) "2" bool(true) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "0" } int(0) float(0) string(1) "0" bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-cast-002.phpt0000644000175100001660000000151614760300421016273 0ustar --TEST-- MongoDB\BSON\Int64 casting (64-bit platform) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } int(9223372036854775807) float(9.22%d%r[eE]%r+18) string(19) "9223372036854775807" bool(true) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(20) "-9223372036854775808" } int(-9223372036854775808) float(-9.22%d%r[eE]%r+18) string(20) "-9223372036854775808" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-cast-003.phpt0000644000175100001660000000200714760300421016270 0ustar --TEST-- MongoDB\BSON\Int64 casting (32-bit platform) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } Warning: Truncating 64-bit integer value 9223372036854775807 to 32 bits %s int(-1) float(9.22%d%r[eE]%r+18) string(19) "9223372036854775807" bool(true) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(20) "-9223372036854775808" } Warning: Truncating 64-bit integer value -9223372036854775808 to 32 bits %s int(0) float(-9.22%d%r[eE]%r+18) string(20) "-9223372036854775808" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-clone-001.phpt0000644000175100001660000000120314760300421016431 0ustar --TEST-- MongoDB\BSON\Int64 can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-clone-002.phpt0000644000175100001660000000120314760300421016432 0ustar --TEST-- MongoDB\BSON\Int64 can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-compare-001.phpt0000644000175100001660000000111414760300421016760 0ustar --TEST-- MongoDB\BSON\Int64 comparisons between objects --FILE-- $min); var_dump($max > $zero); var_dump($min == $min); var_dump($min < $max); var_dump($min < $zero); var_dump($zero == $zero); var_dump($zero < $max); var_dump($zero > $min); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-compare-002.phpt0000644000175100001660000000203414760300421016763 0ustar --TEST-- MongoDB\BSON\Int64 comparisons with scalars --FILE-- 123, 'matching numeric string' => '123', 'matching float' => 123.0, 'matching float string' => '123.0', 'wrong int' => 456, 'wrong numeric string' => '456', 'wrong float' => 456.0, 'wrong float string' => '456.0', 'float with decimals' => 123.456, 'string float with decimals' => '123.456', 'non-numeric string' => 'foo', ]; foreach ($tests as $name => $value) { printf('Testing %s: %s' . PHP_EOL, $name, var_export($int64 == $value, true)); } ?> ===DONE=== --EXPECT-- Testing matching int: true Testing matching numeric string: true Testing matching float: true Testing matching float string: true Testing wrong int: false Testing wrong numeric string: false Testing wrong float: false Testing wrong float string: false Testing float with decimals: false Testing string float with decimals: false Testing non-numeric string: false ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-compare-003.phpt0000644000175100001660000000175214760300421016772 0ustar --TEST-- MongoDB\BSON\Int64 comparisons with scalars (64-bit values) --FILE-- '8589934592', 'matching float' => 8589934592.0, 'matching float string' => '8589934592.0', 'wrong numeric string' => '8589934593', 'wrong float' => 8589934593.0, 'wrong float string' => '8589934593.0', 'float with decimals' => 8589934592.1, 'string float with decimals' => '8589934592.1', ]; foreach ($tests as $name => $value) { printf('Testing %s: %s' . PHP_EOL, $name, var_export($int64 == $value, true)); } ?> ===DONE=== --EXPECT-- Testing matching numeric string: true Testing matching float: true Testing matching float string: true Testing wrong numeric string: false Testing wrong float: false Testing wrong float string: false Testing float with decimals: false Testing string float with decimals: false ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-compare-004.phpt0000644000175100001660000000103414760300421016764 0ustar --TEST-- MongoDB\BSON\Int64 comparisons with scalars (64-bit values, all platforms) --FILE-- (float) 2**33, 'wrong int' => 0, ]; foreach ($tests as $name => $value) { printf('Testing %s: %s' . PHP_EOL, $name, var_export($int64 == $value, true)); } var_dump($int64 > 123); ?> ===DONE=== --EXPECT-- Testing matching float: true Testing wrong int: false bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-compare-005.phpt0000644000175100001660000000113014760300421016762 0ustar --TEST-- MongoDB\BSON\Int64 comparisons with scalars (64-bit values, 64-bit platforms only) --SKIPIF-- --FILE-- 8589934592, 'wrong int' => 8589934593, ]; foreach ($tests as $name => $value) { printf('Testing %s: %s' . PHP_EOL, $name, var_export($int64 == $value, true)); } ?> ===DONE=== --EXPECT-- Testing matching int: true Testing wrong int: false ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-ctor-001.phpt0000644000175100001660000000112314760300421016301 0ustar --TEST-- MongoDB\BSON\Int64 constructor --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "2" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "2" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(20) "-9223372036854775808" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-ctor-002.phpt0000644000175100001660000000075414760300421016313 0ustar --TEST-- MongoDB\BSON\Int64 constructor (64-bit int value) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(20) "-9223372036854775808" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-ctor_error-001.phpt0000644000175100001660000000233514760300421017520 0ustar --TEST-- MongoDB\BSON\Int64 constructor with invalid data --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "0x2" as 64-bit integer for MongoDB\BSON\Int64 initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "9223372036854775807LL" as 64-bit integer for MongoDB\BSON\Int64 initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "9223372036854775808" as 64-bit integer for MongoDB\BSON\Int64 initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "-9223372036854775809" as 64-bit integer for MongoDB\BSON\Int64 initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected value to be integer or string, float given ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-debug-001.phpt0000644000175100001660000000100714760300421016421 0ustar --TEST-- MongoDB\BSON\Int64 debug output --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(20) "-9223372036854775808" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "0" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-get_properties-001.phpt0000644000175100001660000000102314760300421020364 0ustar --TEST-- MongoDB\BSON\Int64 get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECT-- array(1) { ["integer"]=> string(19) "9223372036854775807" } array(1) { ["integer"]=> string(20) "-9223372036854775808" } array(1) { ["integer"]=> string(1) "0" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-get_properties-002.phpt0000644000175100001660000000104414760300421020370 0ustar --TEST-- MongoDB\BSON\Int64 get_properties handler (foreach) --FILE-- $value) { var_dump($key); var_dump($value); } } ?> ===DONE=== --EXPECT-- string(7) "integer" string(19) "9223372036854775807" string(7) "integer" string(20) "-9223372036854775808" string(7) "integer" string(1) "0" ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-jsonserialize-001.phpt0000644000175100001660000000077114760300421020223 0ustar --TEST-- MongoDB\BSON\Int64::jsonSerialize() return value --FILE-- jsonSerialize()); } ?> ===DONE=== --EXPECT-- array(1) { ["$numberLong"]=> string(19) "9223372036854775807" } array(1) { ["$numberLong"]=> string(20) "-9223372036854775808" } array(1) { ["$numberLong"]=> string(1) "0" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-jsonserialize-002.phpt0000644000175100001660000000111614760300421020216 0ustar --TEST-- MongoDB\BSON\Int64::jsonSerialize() with json_encode() --FILE-- new MongoDB\BSON\Int64('9223372036854775807')], ['min' => new MongoDB\BSON\Int64('-9223372036854775808')], ['zero' => new MongoDB\BSON\Int64(0)], ]; foreach ($tests as $test) { var_dump(json_encode($test)); } ?> ===DONE=== --EXPECT-- string(45) "{"max":{"$numberLong":"9223372036854775807"}}" string(46) "{"min":{"$numberLong":"-9223372036854775808"}}" string(28) "{"zero":{"$numberLong":"0"}}" ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-operation-001.phpt0000644000175100001660000000236714760300421017345 0ustar --TEST-- MongoDB\BSON\Int64 operations: arithmetics --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "12" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "8" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "20" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "5" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "1" } float(9.22%d%r[eE]%r+18) float(-9.22%d%r[eE]%r+18) float(1.844%d%r[eE]%r+19) float(4.61%d%r[eE]%r+18) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "4611686018427387903" } float(9.22%d%r[eE]%r+18) float(9.22%d%r[eE]%r+18) ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-operation-002.phpt0000644000175100001660000000125314760300421017337 0ustar --TEST-- MongoDB\BSON\Int64 operations: exponentiation --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(4) "1000" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "1" } float(0.001) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(14) "10000000000000" } float(3.68%d%r[eE]%r+19) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "0" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-operation-003.phpt0000644000175100001660000000160314760300421017337 0ustar --TEST-- MongoDB\BSON\Int64 operations: increment/decrement --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "10" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "11" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "12" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "12" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "12" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "11" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "10" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "10" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-operation-004.phpt0000644000175100001660000000212214760300421017335 0ustar --TEST-- MongoDB\BSON\Int64 operations: bitwise operators --FILE-- > 1); var_dump($int64Max << 1); var_dump($value | 1); // 11 var_dump($value & 8); // 8 var_dump($value ^ 2); // 8 var_dump(~$value); // -11 var_dump(~$int64Min); // 9223372036854775807 ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "80" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "5" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "-2" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "11" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "8" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "8" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "-11" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-operation-005.phpt0000644000175100001660000000135514760300421017345 0ustar --TEST-- MongoDB\BSON\Int64 operations: other operations --FILE-- ===DONE=== --EXPECTF-- bool(false) bool(true) bool(false) bool(true) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(2) "12" } float(13.14) float(13.14) float(13) ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-operation_error-001.phpt0000644000175100001660000000130114760300421020541 0ustar --TEST-- MongoDB\BSON\Int64 operation errors --FILE-- ===DONE=== --EXPECT-- OK: Got TypeError Unsupported operand types: MongoDB\BSON\Int64 + string OK: Got DivisionByZeroError Division by zero OK: Got DivisionByZeroError Division by zero ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-serialization-002.phpt0000644000175100001660000000222514760300421020214 0ustar --TEST-- MongoDB\BSON\Int64 serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } string(71) "O:18:"MongoDB\BSON\Int64":1:{s:7:"integer";s:19:"9223372036854775807";}" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(20) "-9223372036854775808" } string(72) "O:18:"MongoDB\BSON\Int64":1:{s:7:"integer";s:20:"-9223372036854775808";}" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(20) "-9223372036854775808" } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "0" } string(52) "O:18:"MongoDB\BSON\Int64":1:{s:7:"integer";s:1:"0";}" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "0" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-serialization_error-001.phpt0000644000175100001660000000076714760300421021435 0ustar --TEST-- MongoDB\BSON\Int64 unserialization requires "int" string field (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Int64 initialization requires "integer" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-serialization_error-002.phpt0000644000175100001660000000103714760300421021425 0ustar --TEST-- MongoDB\BSON\Int64 unserialization requires "int" string field to be valid (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1234.5678" as 64-bit integer for MongoDB\BSON\Int64 initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-serialization_error-003.phpt0000644000175100001660000000076714760300421021437 0ustar --TEST-- MongoDB\BSON\Int64 unserialization requires "int" string field (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Int64 initialization requires "integer" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-serialization_error-004.phpt0000644000175100001660000000103714760300421021427 0ustar --TEST-- MongoDB\BSON\Int64 unserialization requires "int" string field to be valid (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1234.5678" as 64-bit integer for MongoDB\BSON\Int64 initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-set_state-001.phpt0000644000175100001660000000057214760300421017334 0ustar --TEST-- MongoDB\BSON\Int64::__set_state() --FILE-- ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Int64::__set_state(array( 'integer' => '2', )) object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(1) "2" } ===DONE=== mongodb-1.21.0/tests/bson/bson-int64-tostring-001.phpt0000644000175100001660000000054314760300421017210 0ustar --TEST-- MongoDB\BSON\Int64::__toString() --FILE-- ===DONE=== --EXPECT-- string(19) "9223372036854775807" string(20) "-9223372036854775808" string(1) "0" ===DONE=== mongodb-1.21.0/tests/bson/bson-int64_error-001.phpt0000644000175100001660000000035214760300421016550 0ustar --TEST-- MongoDB\BSON\Int64 cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyInt64 %s final class %SMongoDB\BSON\Int64%S in %s on line %d mongodb-1.21.0/tests/bson/bson-iterator-clone-001.phpt0000644000175100001660000000164414760300421017327 0ustar --TEST-- MongoDB\BSON\Iterator can be cloned --FILE-- getIterator(); $clone = clone $iterator; var_dump($clone == $iterator); var_dump($clone === $iterator); unset($iterator); var_dump($clone); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Iterator)#%d (%d) { ["bson"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(48) "JAAAAARmb28AGgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "GgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAA=" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-iterator-clone-002.phpt0000644000175100001660000000056314760300421017327 0ustar --TEST-- MongoDB\BSON\Iterator is rewound when cloning --FILE-- getIterator(); $iterator->next(); $clone = clone $iterator; var_dump($iterator->current()); var_dump($clone->current()); ?> ===DONE=== --EXPECTF-- int(2) int(1) ===DONE=== mongodb-1.21.0/tests/bson/bson-iterator-debug-001.phpt0000644000175100001660000000064514760300421017315 0ustar --TEST-- MongoDB\BSON\Iterator debug output --FILE-- getIterator()); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Iterator)#%d (%d) { ["bson"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(8) "BQAAAAA=" ["value"]=> object(stdClass)#%d (%d) { } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-iterator-get_properties-001.phpt0000644000175100001660000000063714760300421021263 0ustar --TEST-- MongoDB\BSON\Iterator get_properties handler (get_object_vars) --FILE-- getIterator(); var_dump(get_object_vars($iterator)); ?> ===DONE=== --EXPECTF-- array(%d) { ["bson"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(8) "BQAAAAA=" ["value"]=> object(stdClass)#%d (%d) { } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-iterator-iterator-001.phpt0000644000175100001660000000630614760300421020060 0ustar --TEST-- MongoDB\BSON\Iterator iterating objects and arrays --FILE-- new MongoDB\BSON\ObjectId('56315a7c6118fd1b920270b1'), 'string' => 'foo', 'int32' => 123, 'int64' => new MongoDB\BSON\Int64(123), 'float' => 3.1415926, 'document' => MongoDB\BSON\Document::fromJSON('{ "foo": "bar" }'), 'object' => (object) ['foo' => 'bar'], 'bson_array' => MongoDB\BSON\PackedArray::fromPHP([1, 2, 'foo']), 'array' => [0, 1, 'bar'], ]; $iterator = MongoDB\BSON\Document::fromPHP($data)->getIterator(); var_dump(iterator_to_array($iterator)); $iterator = MongoDB\BSON\PackedArray::fromPHP(array_values($data))->getIterator(); var_dump(iterator_to_array($iterator)); ?> ===DONE=== --EXPECTF-- array(9) { ["objectId"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "56315a7c6118fd1b920270b1" } ["string"]=> string(3) "foo" ["int32"]=> int(123) ["int64"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } ["float"]=> float(3.1415926) ["document"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } ["object"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } ["bson_array"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(40) "HgAAABAwAAEAAAAQMQACAAAAAjIABAAAAGZvbwAA" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> string(3) "foo" } } ["array"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(40) "HgAAABAwAAAAAAAQMQABAAAAAjIABAAAAGJhcgAA" ["value"]=> array(3) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "bar" } } } array(9) { [0]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "56315a7c6118fd1b920270b1" } [1]=> string(3) "foo" [2]=> int(123) [3]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } [4]=> float(3.1415926) [5]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } [6]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } [7]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(40) "HgAAABAwAAEAAAAQMQACAAAAAjIABAAAAGZvbwAA" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> string(3) "foo" } } [8]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(40) "HgAAABAwAAAAAAAQMQABAAAAAjIABAAAAGJhcgAA" ["value"]=> array(3) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "bar" } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-iterator-iterator-002.phpt0000644000175100001660000000143114760300421020053 0ustar --TEST-- MongoDB\BSON\Iterator maintains reference to its yielding Document or PackedArray --FILE-- (object) ['foo' => 'bar']]); $iterator = $document->getIterator(); unset($document); var_dump(iterator_to_array($iterator)); $array = MongoDB\BSON\PackedArray::fromPHP([0, 1, "foo"]); $iterator = $array->getIterator(); unset($array); var_dump(iterator_to_array($iterator)); ?> ===DONE=== --EXPECTF-- array(1) { ["document"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } array(3) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "foo" } ===DONE=== mongodb-1.21.0/tests/bson/bson-iterator-iterator-003.phpt0000644000175100001660000000216414760300421020060 0ustar --TEST-- MongoDB\BSON\Iterator does not extend past the last element in a structure --FILE-- valid()); var_dump($iterator->current()); var_dump($iterator->key()); } $array = MongoDB\BSON\PackedArray::fromPHP([10, 20]); $iterator = $array->getIterator(); showIteratorStatus($iterator); $iterator->next(); showIteratorStatus($iterator); // Will take the iterator to an invalid state $iterator->next(); var_dump($iterator->valid()); echo throws(function () use ($iterator) { $iterator->current(); }, MongoDB\Driver\Exception\LogicException::class), "\n"; echo throws(function () use ($iterator) { $iterator->key(); }, MongoDB\Driver\Exception\LogicException::class), "\n"; ?> ===DONE=== --EXPECTF-- bool(true) int(10) int(0) bool(true) int(20) int(1) bool(false) OK: Got MongoDB\Driver\Exception\LogicException Cannot call current() on an exhausted iterator OK: Got MongoDB\Driver\Exception\LogicException Cannot call key() on an exhausted iterator ===DONE=== mongodb-1.21.0/tests/bson/bson-iterator-rewind-001.phpt0000644000175100001660000000104514760300421017512 0ustar --TEST-- MongoDB\BSON\Iterator::rewind() tests --FILE-- 'bar', 'bar' => 'foo'])->getIterator(); var_dump($iterator->key()); $iterator->rewind(); var_dump($iterator->key()); $iterator->next(); var_dump($iterator->key()); $iterator->rewind(); var_dump($iterator->key()); ?> ===DONE=== --EXPECT-- string(3) "foo" string(3) "foo" string(3) "bar" string(3) "foo" ===DONE=== mongodb-1.21.0/tests/bson/bson-iterator-serialization_error-001.phpt0000644000175100001660000000066414760300421022316 0ustar --TEST-- MongoDB\BSON\Iterator cannot be serialized --FILE-- 'bar']]); echo throws(function () use ($array) { serialize($array->getIterator()); }, \Exception::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got Exception Serialization of 'MongoDB\BSON\Iterator' is not allowed ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-001.phpt0000644000175100001660000000135714760300421016547 0ustar --TEST-- MongoDB\BSON\Javascript #001 --FILE-- 42)); $tests = array( array("js" => $js), array("js" => $jswscope), ); foreach($tests as $n => $test) { echo "Test#{$n}", "\n"; $s = fromPHP($test); $testagain = toPHP($s); var_dump($test['js'] instanceof MongoDB\BSON\Javascript); var_dump($testagain->js instanceof MongoDB\BSON\Javascript); } ?> ===DONE=== --EXPECT-- Test#0 bool(true) bool(true) Test#1 bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-002.phpt0000644000175100001660000000220614760300421016542 0ustar --TEST-- MongoDB\BSON\Javascript debug handler --FILE-- 42), ), array( 'function() { return id; }', array('id' => new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603')), ), ); foreach ($tests as $test) { list($code, $scope) = $test; $js = new MongoDB\BSON\Javascript($code, $scope); var_dump($js); } ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(29) "function(bar) { return bar; }" ["scope"]=> object(stdClass)#%d (%d) { } } object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(26) "function() { return foo; }" ["scope"]=> object(stdClass)#%d (%d) { ["foo"]=> int(42) } } object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(25) "function() { return id; }" ["scope"]=> object(stdClass)#%d (%d) { ["id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-clone-001.phpt0000644000175100001660000000140414760300421017636 0ustar --TEST-- MongoDB\BSON\Javascript can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- 42]); $clone = clone $javascript; var_dump($clone == $javascript); var_dump($clone === $javascript); unset($javascript); var_dump($clone); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(58) "function(bar) {var baz = bar; var bar = foo; return bar; }" ["scope"]=> object(stdClass)#%d (%d) { ["foo"]=> int(42) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-clone-002.phpt0000644000175100001660000000140414760300421017637 0ustar --TEST-- MongoDB\BSON\Javascript can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- 42]); $clone = clone $javascript; var_dump($clone == $javascript); var_dump($clone === $javascript); unset($javascript); var_dump($clone); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(58) "function(bar) {var baz = bar; var bar = foo; return bar; }" ["scope"]=> object(stdClass)#%d (%d) { ["foo"]=> int(42) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-compare-001.phpt0000644000175100001660000000103514760300421020164 0ustar --TEST-- MongoDB\BSON\Javascript comparisons (without scope) --FILE-- new MongoDB\BSON\Javascript('function() { return 0; }')); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-compare-002.phpt0000644000175100001660000000122314760300421020164 0ustar --TEST-- MongoDB\BSON\Javascript comparisons (with scope) --FILE-- 1]) == new MongoDB\BSON\Javascript('function() { return 1; }', ['x' => 1])); var_dump(new MongoDB\BSON\Javascript('function() { return 1; }', ['x' => 1]) == new MongoDB\BSON\Javascript('function() { return 1; }', ['x' => 0])); var_dump(new MongoDB\BSON\Javascript('function() { return 1; }', ['x' => 1]) == new MongoDB\BSON\Javascript('function() { return 1; }', ['x' => 2])); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-getCode-001.phpt0000644000175100001660000000125214760300421020111 0ustar --TEST-- MongoDB\BSON\Javascript::getCode() --FILE-- 42]], ['function() { return id; }', ['id' => new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603')]], ]; foreach ($tests as $test) { list($code, $scope) = $test; $js = new MongoDB\BSON\Javascript($code, $scope); var_dump($js->getCode()); } ?> ===DONE=== --EXPECT-- string(29) "function(bar) { return bar; }" string(29) "function(bar) { return bar; }" string(26) "function() { return foo; }" string(25) "function() { return id; }" ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-getScope-001.phpt0000644000175100001660000000135314760300421020312 0ustar --TEST-- MongoDB\BSON\Javascript::getScope() --FILE-- 42]], ['function() { return id; }', ['id' => new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603')]], ]; foreach ($tests as $test) { list($code, $scope) = $test; $js = new MongoDB\BSON\Javascript($code, $scope); var_dump($js->getScope()); } ?> ===DONE=== --EXPECTF-- NULL object(stdClass)#%d (%d) { } object(stdClass)#%d (%d) { ["foo"]=> int(42) } object(stdClass)#%d (%d) { ["id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-get_properties-001.phpt0000644000175100001660000000113614760300421021573 0ustar --TEST-- MongoDB\BSON\Javascript get_properties handler (get_object_vars) --FILE-- 42]), ]; foreach ($tests as $test) { var_dump(get_object_vars($test)); } ?> ===DONE=== --EXPECTF-- array(2) { ["code"]=> string(29) "function(bar) { return bar; }" ["scope"]=> NULL } array(2) { ["code"]=> string(26) "function() { return bar; }" ["scope"]=> object(stdClass)#%d (%d) { ["bar"]=> int(42) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-get_properties-002.phpt0000644000175100001660000000117014760300421021572 0ustar --TEST-- MongoDB\BSON\Javascript get_properties handler (foreach) --FILE-- 42]), ]; foreach ($tests as $test) { foreach ($test as $key => $value) { var_dump($key); var_dump($value); } } ?> ===DONE=== --EXPECTF-- string(4) "code" string(29) "function(bar) { return bar; }" string(5) "scope" NULL string(4) "code" string(26) "function() { return bar; }" string(5) "scope" object(stdClass)#%d (%d) { ["bar"]=> int(42) } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-jsonserialize-001.phpt0000644000175100001660000000050214760300421021415 0ustar --TEST-- MongoDB\BSON\Javascript::jsonSerialize() return value (without scope) --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$code"]=> string(29) "function(bar) { return bar; }" } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-jsonserialize-002.phpt0000644000175100001660000000063114760300421021421 0ustar --TEST-- MongoDB\BSON\Javascript::jsonSerialize() return value (with scope) --FILE-- 42]); var_dump($js->jsonSerialize()); ?> ===DONE=== --EXPECTF-- array(2) { ["$code"]=> string(29) "function(bar) { return bar; }" ["$scope"]=> object(stdClass)#%d (%d) { ["foo"]=> int(42) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-jsonserialize-003.phpt0000644000175100001660000000125214760300421021422 0ustar --TEST-- MongoDB\BSON\Javascript::jsonSerialize() with json_encode() (without scope) --FILE-- new MongoDB\BSON\Javascript('function(bar) { return bar; }')]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$code" : "function(bar) { return bar; }" } } {"foo":{"$code":"function(bar) { return bar; }"}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(29) "function(bar) { return bar; }" ["scope"]=> NULL } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-jsonserialize-004.phpt0000644000175100001660000000146414760300421021430 0ustar --TEST-- MongoDB\BSON\Javascript::jsonSerialize() with json_encode() (with scope) --FILE-- new MongoDB\BSON\Javascript('function(bar) { return bar; }', ['foo' => 42])]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$code" : "function(bar) { return bar; }", "$scope" : { "foo" : { "$numberInt" : "42" } } } } {"foo":{"$code":"function(bar) { return bar; }","$scope":{"foo":42}}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(29) "function(bar) { return bar; }" ["scope"]=> object(stdClass)#%d (%d) { ["foo"]=> int(42) } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-serialization-002.phpt0000644000175100001660000000511014760300421021412 0ustar --TEST-- MongoDB\BSON\Javascript serialization (__serialize and __unserialize) --FILE-- 42]], ['function() { return id; }', ['id' => new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603')]], ]; foreach ($tests as $test) { list($code, $scope) = $test; var_dump($js = new MongoDB\BSON\Javascript($code, $scope)); var_dump($s = serialize($js)); var_dump(unserialize($s)); echo "\n"; } ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(29) "function(bar) { return bar; }" ["scope"]=> NULL } string(97) "O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:29:"function(bar) { return bar; }";s:5:"scope";N;}" object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(29) "function(bar) { return bar; }" ["scope"]=> NULL } object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(29) "function(bar) { return bar; }" ["scope"]=> object(stdClass)#%d (%d) { } } string(114) "O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:29:"function(bar) { return bar; }";s:5:"scope";O:8:"stdClass":0:{}}" object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(29) "function(bar) { return bar; }" ["scope"]=> object(stdClass)#%d (%d) { } } object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(26) "function() { return foo; }" ["scope"]=> object(stdClass)#%d (%d) { ["foo"]=> int(42) } } string(126) "O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:26:"function() { return foo; }";s:5:"scope";O:8:"stdClass":1:{s:3:"foo";i:42;}}" object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(26) "function() { return foo; }" ["scope"]=> object(stdClass)#%d (%d) { ["foo"]=> int(42) } } object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(25) "function() { return id; }" ["scope"]=> object(stdClass)#%d (%d) { ["id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } } } string(194) "O:23:"MongoDB\BSON\Javascript":2:{s:4:"code";s:25:"function() { return id; }";s:5:"scope";O:8:"stdClass":1:{s:2:"id";O:21:"MongoDB\BSON\ObjectId":1:{s:3:"oid";s:24:"53e2a1c40640fd72175d4603";}}}" object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(25) "function() { return id; }" ["scope"]=> object(stdClass)#%d (%d) { ["id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-serialization_error-001.phpt0000644000175100001660000000100114760300421022615 0ustar --TEST-- MongoDB\BSON\Javascript unserialization requires "code" string field (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Javascript initialization requires "code" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-serialization_error-002.phpt0000644000175100001660000000105314760300421022625 0ustar --TEST-- MongoDB\BSON\Javascript unserialization expects optional scope to be array or object (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected scope to be array or object, string given ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-serialization_error-003.phpt0000644000175100001660000000102214760300421022622 0ustar --TEST-- MongoDB\BSON\Javascript unserialization does not allow code to contain null bytes (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Code cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-serialization_error-004.phpt0000644000175100001660000000100114760300421022620 0ustar --TEST-- MongoDB\BSON\Javascript unserialization requires "code" string field (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Javascript initialization requires "code" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-serialization_error-005.phpt0000644000175100001660000000105314760300421022630 0ustar --TEST-- MongoDB\BSON\Javascript unserialization expects optional scope to be array or object (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected scope to be array or object, string given ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-serialization_error-006.phpt0000644000175100001660000000102214760300421022625 0ustar --TEST-- MongoDB\BSON\Javascript unserialization does not allow code to contain null bytes (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Code cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-set_state-001.phpt0000644000175100001660000000275014760300421020536 0ustar --TEST-- MongoDB\BSON\Javascript::__set_state() --FILE-- 42]], ['function() { return id; }', ['id' => new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603')]], ]; foreach ($tests as $test) { list($code, $scope) = $test; var_export(MongoDB\BSON\Javascript::__set_state([ 'code' => $code, 'scope' => $scope, ])); echo "\n\n"; } // Test with missing scope field var_export(MongoDB\BSON\Javascript::__set_state([ 'code' => 'function(bar) { return bar; }', ])); echo "\n\n"; ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Javascript::__set_state(array( 'code' => 'function(bar) { return bar; }', 'scope' => NULL, )) %r\\?%rMongoDB\BSON\Javascript::__set_state(array( 'code' => 'function(bar) { return bar; }', 'scope' =>%w (object) array( ), )) %r\\?%rMongoDB\BSON\Javascript::__set_state(array( 'code' => 'function() { return foo; }', 'scope' =>%w (object) array( 'foo' => 42, ), )) %r\\?%rMongoDB\BSON\Javascript::__set_state(array( 'code' => 'function() { return id; }', 'scope' =>%w (object) array( 'id' =>%w %r\\?%rMongoDB\BSON\ObjectId::__set_state(array( 'oid' => '53e2a1c40640fd72175d4603', )), ), )) %r\\?%rMongoDB\BSON\Javascript::__set_state(array( 'code' => 'function(bar) { return bar; }', 'scope' => NULL, )) ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-set_state_error-001.phpt0000644000175100001660000000072214760300421021744 0ustar --TEST-- MongoDB\BSON\Javascript::__set_state() requires "code" string field --FILE-- 0]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Javascript initialization requires "code" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-set_state_error-002.phpt0000644000175100001660000000076614760300421021755 0ustar --TEST-- MongoDB\BSON\Javascript::__set_state() expects optional scope to be array or object --FILE-- 'function() {}', 'scope' => 'INVALID']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected scope to be array or object, string given ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-set_state_error-003.phpt0000644000175100001660000000072614760300421021752 0ustar --TEST-- MongoDB\BSON\Javascript::__set_state() does not allow code to contain null bytes --FILE-- "function() { return '\0'; }"]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Code cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript-tostring-001.phpt0000644000175100001660000000060314760300421020407 0ustar --TEST-- MongoDB\BSON\Javascript::__toString() --FILE-- 1]); var_dump((string) $js); ?> ===DONE=== --EXPECT-- string(24) "function() { return 1; }" string(26) "function() { return bar; }" ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript_error-001.phpt0000644000175100001660000000106214760300421017751 0ustar --TEST-- MongoDB\BSON\Javascript argument count errors --SKIPIF-- =', '7.99'); ?> --FILE-- ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Javascript::__construct() expects at least 1 %r(argument|parameter)%r, 0 given ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript_error-002.phpt0000644000175100001660000000040314760300421017750 0ustar --TEST-- MongoDB\BSON\Javascript cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyJavascript %s final class %SMongoDB\BSON\Javascript%S in %s on line %d mongodb-1.21.0/tests/bson/bson-javascript_error-003.phpt0000644000175100001660000000070114760300421017752 0ustar --TEST-- MongoDB\BSON\Javascript::__construct() does not allow code to contain null bytes --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Code cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-javascript_error-004.phpt0000644000175100001660000000100714760300421017753 0ustar --TEST-- MongoDB\BSON\Javascript::__construct() does not allow PackedArray for scope --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/bson/bson-javascriptinterface-001.phpt0000644000175100001660000000050014760300421020415 0ustar --TEST-- MongoDB\BSON\JavascriptInterface is implemented by MongoDB\BSON\Javascript --FILE-- 1]); var_dump($javascript instanceof MongoDB\BSON\JavascriptInterface); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey-001.phpt0000644000175100001660000000122014760300421015664 0ustar --TEST-- MongoDB\BSON\MaxKey #001 --FILE-- $maxkey), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- Test#0 { "max" : { "$maxKey" : 1 } } string(29) "{ "max" : { "$maxKey" : 1 } }" string(29) "{ "max" : { "$maxKey" : 1 } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey-clone-001.phpt0000644000175100001660000000065214760300421016772 0ustar --TEST-- MongoDB\BSON\MaxKey can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey-clone-002.phpt0000644000175100001660000000065214760300421016773 0ustar --TEST-- MongoDB\BSON\MaxKey can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey-compare-001.phpt0000644000175100001660000000051314760300421017314 0ustar --TEST-- MongoDB\BSON\MaxKey comparisons --FILE-- new MongoDB\BSON\MaxKey); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey-jsonserialize-001.phpt0000644000175100001660000000035714760300421020555 0ustar --TEST-- MongoDB\BSON\MaxKey::jsonSerialize() return value --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$maxKey"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey-jsonserialize-002.phpt0000644000175100001660000000073614760300421020557 0ustar --TEST-- MongoDB\BSON\MaxKey::jsonSerialize() with json_encode() --FILE-- new MongoDB\BSON\MaxKey]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$maxKey" : 1 } } {"foo":{"$maxKey":1}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\MaxKey)#%d (%d) { } } ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey-serialization-002.phpt0000644000175100001660000000057314760300421020552 0ustar --TEST-- MongoDB\BSON\MaxKey serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\MaxKey)#%d (%d) { } string(31) "O:19:"MongoDB\BSON\MaxKey":0:{}" object(MongoDB\BSON\MaxKey)#%d (%d) { } ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey-set_state-001.phpt0000644000175100001660000000034314760300421017662 0ustar --TEST-- MongoDB\BSON\MaxKey::__set_state() --FILE-- ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\MaxKey::__set_state(array( )) ===DONE=== mongodb-1.21.0/tests/bson/bson-maxkey_error-001.phpt0000644000175100001660000000035714760300421017107 0ustar --TEST-- MongoDB\BSON\MaxKey cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyMaxKey %s final class %SMongoDB\BSON\MaxKey%S in %s on line %d mongodb-1.21.0/tests/bson/bson-maxkeyinterface-001.phpt0000644000175100001660000000037414760300421017556 0ustar --TEST-- MongoDB\BSON\MaxKeyInterface is implemented by MongoDB\BSON\MaxKey --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey-001.phpt0000644000175100001660000000122014760300421015662 0ustar --TEST-- MongoDB\BSON\MinKey #001 --FILE-- $minkey), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- Test#0 { "min" : { "$minKey" : 1 } } string(29) "{ "min" : { "$minKey" : 1 } }" string(29) "{ "min" : { "$minKey" : 1 } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey-clone-001.phpt0000644000175100001660000000065214760300421016770 0ustar --TEST-- MongoDB\BSON\MinKey can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey-clone-002.phpt0000644000175100001660000000065214760300421016771 0ustar --TEST-- MongoDB\BSON\MinKey can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey-compare-001.phpt0000644000175100001660000000051414760300421017313 0ustar --TEST-- MongoDB\BSON\MinKey comparisons --FILE-- new MongoDB\BSON\MinKey); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey-jsonserialize-001.phpt0000644000175100001660000000035714760300421020553 0ustar --TEST-- MongoDB\BSON\MinKey::jsonSerialize() return value --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$minKey"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey-jsonserialize-002.phpt0000644000175100001660000000073614760300421020555 0ustar --TEST-- MongoDB\BSON\MinKey::jsonSerialize() with json_encode() --FILE-- new MongoDB\BSON\MinKey]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$minKey" : 1 } } {"foo":{"$minKey":1}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\MinKey)#%d (%d) { } } ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey-serialization-002.phpt0000644000175100001660000000057314760300421020550 0ustar --TEST-- MongoDB\BSON\MinKey serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\MinKey)#%d (%d) { } string(31) "O:19:"MongoDB\BSON\MinKey":0:{}" object(MongoDB\BSON\MinKey)#%d (%d) { } ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey-set_state-001.phpt0000644000175100001660000000034314760300421017660 0ustar --TEST-- MongoDB\BSON\MinKey::__set_state() --FILE-- ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\MinKey::__set_state(array( )) ===DONE=== mongodb-1.21.0/tests/bson/bson-minkey_error-001.phpt0000644000175100001660000000035714760300421017105 0ustar --TEST-- MongoDB\BSON\MinKey cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyMinKey %s final class %SMongoDB\BSON\MinKey%S in %s on line %d mongodb-1.21.0/tests/bson/bson-minkeyinterface-001.phpt0000644000175100001660000000037414760300421017554 0ustar --TEST-- MongoDB\BSON\MinKeyInterface is implemented by MongoDB\BSON\MinKey --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-001.phpt0000644000175100001660000000612114760300421016156 0ustar --TEST-- MongoDB\BSON\ObjectId #001 --SKIPIF-- =', '7.99'); ?> --FILE-- my = $sameid; $samearr = array("my" => $sameid); $std = new stdclass; $std->_id = new MongoDB\BSON\ObjectId; $array = array( "_id" => new MongoDB\BSON\ObjectId, "id" => new MongoDB\BSON\ObjectId, "d" => new MongoDB\BSON\ObjectId, ); $pregenerated = new MongoDB\BSON\ObjectId("53e28b650640fd3162152de1"); $tests = array( $array, $std, $samestd, $samearr, array("pregenerated" => $pregenerated), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } throws(function() { $id = new MongoDB\BSON\ObjectId("53e28b650640fd3162152de12"); }, MongoDB\Driver\Exception\InvalidArgumentException::class); throws(function() { $id = new MongoDB\BSON\ObjectId("53e28b650640fd3162152dg1"); }, MongoDB\Driver\Exception\InvalidArgumentException::class); throws(function() { $id = new MongoDB\BSON\ObjectId("-3e28b650640fd3162152da1"); }, MongoDB\Driver\Exception\InvalidArgumentException::class); throws(function() { $id = new MongoDB\BSON\ObjectId(" 3e28b650640fd3162152da1"); }, MongoDB\Driver\Exception\InvalidArgumentException::class); throws(function() use ($pregenerated) { $pregenerated->__toString(1); }, MongoDB\Driver\Exception\InvalidArgumentException::class); ?> ===DONE=== --EXPECTF-- Test#0 { "_id" : { "$oid" : "%s" }, "id" : { "$oid" : "%s" }, "d" : { "$oid" : "%s" } } string(146) "{ "_id" : { "$oid" : "%s" }, "id" : { "$oid" : "%s" }, "d" : { "$oid" : "%s" } }" string(146) "{ "_id" : { "$oid" : "%s" }, "id" : { "$oid" : "%s" }, "d" : { "$oid" : "%s" } }" bool(true) Test#1 { "_id" : { "$oid" : "%s" } } string(51) "{ "_id" : { "$oid" : "%s" } }" string(51) "{ "_id" : { "$oid" : "%s" } }" bool(true) Test#2 { "my" : { "$oid" : "53e2a1c40640fd72175d4603" } } string(50) "{ "my" : { "$oid" : "53e2a1c40640fd72175d4603" } }" string(50) "{ "my" : { "$oid" : "53e2a1c40640fd72175d4603" } }" bool(true) Test#3 { "my" : { "$oid" : "53e2a1c40640fd72175d4603" } } string(50) "{ "my" : { "$oid" : "53e2a1c40640fd72175d4603" } }" string(50) "{ "my" : { "$oid" : "53e2a1c40640fd72175d4603" } }" bool(true) Test#4 { "pregenerated" : { "$oid" : "53e28b650640fd3162152de1" } } string(60) "{ "pregenerated" : { "$oid" : "53e28b650640fd3162152de1" } }" string(60) "{ "pregenerated" : { "$oid" : "53e28b650640fd3162152de1" } }" bool(true) OK: Got MongoDB\Driver\Exception\InvalidArgumentException OK: Got MongoDB\Driver\Exception\InvalidArgumentException OK: Got MongoDB\Driver\Exception\InvalidArgumentException OK: Got MongoDB\Driver\Exception\InvalidArgumentException OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-002.phpt0000644000175100001660000000061014760300421016154 0ustar --TEST-- MongoDB\BSON\ObjectId #002 generates ObjectId for null or missing constructor argument --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-003.phpt0000644000175100001660000000152614760300421016164 0ustar --TEST-- MongoDB\BSON\ObjectId #003 construction with string argument --FILE-- value = (string) $value; } public function __toString() { return $this->value; } } $oid = new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603'); $str = new StringObject('53e2a1c40640fd72175d4603'); var_dump($oid); var_dump(new MongoDB\BSON\ObjectId($oid)); var_dump(new MongoDB\BSON\ObjectId($str)); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-004.phpt0000644000175100001660000000047614760300421016170 0ustar --TEST-- MongoDB\BSON\ObjectId #004 Constructor supports uppercase hexadecimal strings --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "56925b7330616224d0000001" } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-clone-001.phpt0000644000175100001660000000112514760300421017253 0ustar --TEST-- MongoDB\BSON\ObjectId can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\ObjectId)#%d (1) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-clone-002.phpt0000644000175100001660000000112514760300421017254 0ustar --TEST-- MongoDB\BSON\ObjectId can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\ObjectId)#%d (1) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-compare-001.phpt0000644000175100001660000000141214760300421017600 0ustar --TEST-- MongoDB\BSON\ObjectId comparisons --FILE-- new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603')); var_dump(new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603') < new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4604')); var_dump(new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4603') > new MongoDB\BSON\ObjectId('53e2a1c40640fd72175d4602')); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-compare-002.phpt0000644000175100001660000000143214760300421017603 0ustar --TEST-- MongoDB\BSON\ObjectId comparisons with null bytes --FILE-- new MongoDB\BSON\ObjectId('00e2a1c40640fd72175d4603')); var_dump(new MongoDB\BSON\ObjectId('00e2a1c40640fd72175d4603') < new MongoDB\BSON\ObjectId('00e2a1c40640fd72175d4604')); var_dump(new MongoDB\BSON\ObjectId('00e2a1c40640fd72175d4603') > new MongoDB\BSON\ObjectId('00e2a1c40640fd72175d4602')); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-getTimestamp-001.phpt0000644000175100001660000000047714760300421020627 0ustar --TEST-- MongoDB\BSON\ObjectId::getTimestamp --FILE-- getTimestamp(); echo $ts, "\n"; echo date_create( "@{$ts}" )->format( "Y-m-d H:i:s" ), "\n"; ?> --EXPECT-- 1447757782 2015-11-17 10:56:22 mongodb-1.21.0/tests/bson/bson-objectid-getTimestamp-002.phpt0000644000175100001660000000131714760300421020622 0ustar --TEST-- MongoDB\BSON\ObjectId::getTimestamp: Ensure that the Timestamp field is represented as an unsigned 32-bit integer --FILE-- getTimestamp()); echo $ts, "\n"; echo date_create("@{$ts}")->format("Y-m-d H:i:s"), "\n"; } create_object_id('000000000000000000000000'); create_object_id('7FFFFFFF0000000000000000'); create_object_id('800000000000000000000000'); create_object_id('FFFFFFFF0000000000000000'); ?> --EXPECT-- 0 1970-01-01 00:00:00 2147483647 2038-01-19 03:14:07 2147483648 2038-01-19 03:14:08 4294967295 2106-02-07 06:28:15mongodb-1.21.0/tests/bson/bson-objectid-get_properties-001.phpt0000644000175100001660000000046014760300421021207 0ustar --TEST-- MongoDB\BSON\ObjectId get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECT-- array(1) { ["oid"]=> string(24) "53e2a1c40640fd72175d4603" } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-get_properties-002.phpt0000644000175100001660000000051314760300421021207 0ustar --TEST-- MongoDB\BSON\ObjectId get_properties handler (foreach) --FILE-- $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECT-- string(3) "oid" string(24) "53e2a1c40640fd72175d4603" ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-jsonserialize-001.phpt0000644000175100001660000000044514760300421021040 0ustar --TEST-- MongoDB\BSON\ObjectId::jsonSerialize() return value --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$oid"]=> string(24) "5820ca4bef62d52d9924d0d8" } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-jsonserialize-002.phpt0000644000175100001660000000114414760300421021036 0ustar --TEST-- MongoDB\BSON\ObjectId::jsonSerialize() with json_encode() --FILE-- new MongoDB\BSON\ObjectId('5820ca4bef62d52d9924d0d8')]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$oid" : "5820ca4bef62d52d9924d0d8" } } {"foo":{"$oid":"5820ca4bef62d52d9924d0d8"}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "5820ca4bef62d52d9924d0d8" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-serialization-002.phpt0000644000175100001660000000105514760300421021033 0ustar --TEST-- MongoDB\BSON\ObjectId serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "576c25db6118fd406e6e6471" } string(75) "O:21:"MongoDB\BSON\ObjectId":1:{s:3:"oid";s:24:"576c25db6118fd406e6e6471";}" object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "576c25db6118fd406e6e6471" } ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-serialization_error-001.phpt0000644000175100001660000000077014760300421022246 0ustar --TEST-- MongoDB\BSON\ObjectId unserialization requires "oid" string field (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\ObjectId initialization requires "oid" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-serialization_error-002.phpt0000644000175100001660000000143014760300421022241 0ustar --TEST-- MongoDB\BSON\ObjectId unserialization requires valid hex string (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: 0123456789abcdefghijklmn OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: INVALID ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-serialization_error-003.phpt0000644000175100001660000000077014760300421022250 0ustar --TEST-- MongoDB\BSON\ObjectId unserialization requires "oid" string field (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\ObjectId initialization requires "oid" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-serialization_error-004.phpt0000644000175100001660000000142114760300421022243 0ustar --TEST-- MongoDB\BSON\ObjectId unserialization requires valid hex string (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: 0123456789abcdefghijklmn OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: INVALID ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-set_state-001.phpt0000644000175100001660000000047114760300421020151 0ustar --TEST-- MongoDB\BSON\ObjectId::__set_state() --FILE-- '576c25db6118fd406e6e6471', ])); echo "\n"; ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\ObjectId::__set_state(array( 'oid' => '576c25db6118fd406e6e6471', )) ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-set_state_error-001.phpt0000644000175100001660000000071114760300421021357 0ustar --TEST-- MongoDB\BSON\ObjectId::__set_state() requires "oid" string field --FILE-- 0]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\ObjectId initialization requires "oid" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-set_state_error-002.phpt0000644000175100001660000000131714760300421021363 0ustar --TEST-- MongoDB\BSON\ObjectId::__set_state() requires valid hex string --FILE-- '0123456789abcdefghijklmn']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\ObjectId::__set_state(['oid' => 'INVALID']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: 0123456789abcdefghijklmn OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: INVALID ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid-tostring_error-001.phpt0000644000175100001660000000121114760300421021231 0ustar --TEST-- MongoDB\BSON\ObjectId raises warning on invalid arguments --SKIPIF-- =', '7.99'); ?> --FILE-- __toString(1); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\ObjectId::__toString() expects exactly 0 parameters, 1 given ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid_error-001.phpt0000644000175100001660000000075214760300421017373 0ustar --TEST-- MongoDB\BSON\ObjectId constructor type validation --SKIPIF-- =', '7.99'); ?> --FILE-- ===DONE=== --EXPECTF-- OK: Got TypeError %SMongoDB\BSON\ObjectId::__construct()%sstring or null, %r(object|stdClass)%r given ===DONE=== mongodb-1.21.0/tests/bson/bson-objectid_error-002.phpt0000644000175100001660000000037114760300421017371 0ustar --TEST-- MongoDB\BSON\ObjectId cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyObjectId %s final class %SMongoDB\BSON\ObjectId%S in %s on line %d mongodb-1.21.0/tests/bson/bson-objectid_error-003.phpt0000644000175100001660000000124714760300421017375 0ustar --TEST-- MongoDB\BSON\ObjectId::__construct() requires valid hex string --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: 0123456789abcdefghijklmn OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing ObjectId string: INVALID ===DONE=== mongodb-1.21.0/tests/bson/bson-objectidinterface-001.phpt0000644000175100001660000000037614760300421020045 0ustar --TEST-- MongoDB\BSON\ObjectIdInterface is implemented by MongoDB\BSON\ObjectId --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-array-access-001.phpt0000644000175100001660000000107414760300421021236 0ustar --TEST-- MongoDB\BSON\PackedArray array access (dimension object accessors) --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(true) bool(false) bool(false) string(3) "foo" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-array-access-002.phpt0000644000175100001660000000114714760300421021240 0ustar --TEST-- MongoDB\BSON\PackedArray array access (ArrayAccess methods) --FILE-- offsetExists(0)); var_dump($array->offsetExists(1)); var_dump($array->offsetExists(2)); var_dump($array->offsetExists('foo')); var_dump($array->offsetGet(0)); var_dump($array->offsetGet(1)); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) bool(false) bool(false) string(3) "foo" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-array-access-003.phpt0000644000175100001660000000066314760300421021243 0ustar --TEST-- MongoDB\BSON\PackedArray array access (coalesce operator) --FILE-- ===DONE=== --EXPECT-- bool(false) string(8) "fallback" bool(false) string(8) "fallback" ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-array-access_error-001.phpt0000644000175100001660000000142014760300421022442 0ustar --TEST-- MongoDB\BSON\PackedArray array access does not allow writing (dimension object handlers) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\LogicException Cannot write to MongoDB\BSON\PackedArray offset OK: Got MongoDB\Driver\Exception\LogicException Cannot unset MongoDB\BSON\PackedArray offset ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-array-access_error-002.phpt0000644000175100001660000000143214760300421022446 0ustar --TEST-- MongoDB\BSON\PackedArray array access does not allow writing (ArrayAccess methods) --FILE-- offsetSet(0, 'bar'); }, MongoDB\Driver\Exception\LogicException::class), "\n"; // Unsetting causes exception echo throws(function() use ($array) { $array->offsetUnset(0); }, MongoDB\Driver\Exception\LogicException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\LogicException Cannot write to MongoDB\BSON\PackedArray offset OK: Got MongoDB\Driver\Exception\LogicException Cannot unset MongoDB\BSON\PackedArray offset ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-array-access_error-003.phpt0000644000175100001660000000221114760300421022443 0ustar --TEST-- MongoDB\BSON\PackedArray array access checks types (dimension object handlers) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index of type "string" in BSON array OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index of type "string" in BSON array OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index of type "float" in BSON array OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index of type "bool" in BSON array ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-array-access_error-004.phpt0000644000175100001660000000225714760300421022456 0ustar --TEST-- MongoDB\BSON\PackedArray array access checks types (ArrayAccess methods) --FILE-- offsetGet('foo'); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; echo throws(function() use ($array) { $array->offsetGet('0'); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; echo throws(function() use ($array) { $array->offsetGet(0.1); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; echo throws(function() use ($array) { $array->offsetGet(false); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index of type "string" in BSON array OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index of type "string" in BSON array OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index of type "float" in BSON array OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index of type "bool" in BSON array ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-clone-001.phpt0000644000175100001660000000105714760300421017762 0ustar --TEST-- MongoDB\BSON\PackedArray can be cloned --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "GgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAA=" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-compare-001.phpt0000644000175100001660000000061314760300421020305 0ustar --TEST-- MongoDB\BSON\PackedArray comparisons --FILE-- $barfoo); var_dump($foobar == $foobar); ?> ===DONE=== --EXPECT-- bool(false) bool(true) bool(false) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-debug-001.phpt0000644000175100001660000000050714760300421017747 0ustar --TEST-- MongoDB\BSON\PackedArray debug output --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(8) "BQAAAAA=" ["value"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-fromJSON-001.phpt0000644000175100001660000000245314760300421020320 0ustar --TEST-- MongoDB\BSON\PackedArray::fromJSON(): Decoding JSON --FILE-- ===DONE=== --EXPECT-- Test [] 0 : 05 00 00 00 00 [.....] Test [ 1, 2, 3 ] 0 : 1a 00 00 00 10 30 00 01 00 00 00 10 31 00 02 00 [.....0......1...] 10 : 00 00 10 32 00 03 00 00 00 00 [...2......] Test [[ 1, 2, 3 ]] 0 : 22 00 00 00 04 30 00 1a 00 00 00 10 30 00 01 00 ["....0......0...] 10 : 00 00 10 31 00 02 00 00 00 10 32 00 03 00 00 00 [...1......2.....] 20 : 00 00 [..] Test [{ "bar": 1 }] 0 : 16 00 00 00 03 30 00 0e 00 00 00 10 62 61 72 00 [.....0......bar.] 10 : 01 00 00 00 00 00 [......] Test { "0": "foo", "1": "bar" } 0 : 1b 00 00 00 02 30 00 04 00 00 00 66 6f 6f 00 02 [.....0.....foo..] 10 : 31 00 04 00 00 00 62 61 72 00 00 [1.....bar..] ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-fromJSON-002.phpt0000644000175100001660000000350314760300421020316 0ustar --TEST-- MongoDB\BSON\PackedArray::fromJSON(): Decoding extended JSON types --FILE-- ===DONE=== --EXPECT-- Test [{ "$oid": "56315a7c6118fd1b920270b1" }] 0 : 14 00 00 00 07 30 00 56 31 5a 7c 61 18 fd 1b 92 [.....0.V1Z|a....] 10 : 02 70 b1 00 [.p..] Test [{ "$binary": "Zm9v", "$type": "00" }] 0 : 10 00 00 00 05 30 00 03 00 00 00 00 66 6f 6f 00 [.....0......foo.] Test [{ "$date": "2015-10-28T00:00:00Z" }] 0 : 10 00 00 00 09 30 00 00 80 be ab 50 01 00 00 00 [.....0.....P....] Test [{ "$timestamp": { "t": 1446084619, "i": 0 }}] 0 : 10 00 00 00 11 30 00 00 00 00 00 0b 80 31 56 00 [.....0.......1V.] Test [{ "$regex": "pattern", "$options": "i" }] 0 : 12 00 00 00 0b 30 00 70 61 74 74 65 72 6e 00 69 [.....0.pattern.i] 10 : 00 00 [..] Test [{ "$undefined": true }] 0 : 08 00 00 00 06 30 00 00 [.....0..] Test [{ "$minKey": 1 }] 0 : 08 00 00 00 ff 30 00 00 [.....0..] Test [{ "$maxKey": 1 }] 0 : 08 00 00 00 7f 30 00 00 [.....0..] Test [{ "$numberLong": "1234" }] 0 : 10 00 00 00 12 30 00 d2 04 00 00 00 00 00 00 00 [.....0..........] ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-fromJSON_error-001.phpt0000644000175100001660000000236014760300421021526 0ustar --TEST-- MongoDB\BSON\PackedArray::fromJSON(): invalid JSON --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Got parse error at "o", position 1: "SPECIAL_EXPECTED" OK: Got MongoDB\Driver\Exception\UnexpectedValueException Received invalid JSON array: expected key 0, but found "foo" OK: Got MongoDB\Driver\Exception\UnexpectedValueException Received invalid JSON array: expected key 0, but found "00" OK: Got MongoDB\Driver\Exception\UnexpectedValueException Received invalid JSON array: expected key 1, but found "foo" ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-fromPHP-001.phpt0000644000175100001660000000067714760300421020204 0ustar --TEST-- MongoDB\BSON\PackedArray::fromPHP(): create from PHP array --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "GgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAA=" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-fromPHP_error-001.phpt0000644000175100001660000000151714760300421021407 0ustar --TEST-- MongoDB\BSON\PackedArray::fromPHP(): requires a packed array --FILE-- 1, 2, 3], // Keys: 1, 2, 3 [1, 2 => 2, 3], // Keys: 0, 2, 3 [0, 1, 'foo' => 'bar'], // Keys: 0, 1, bar ]; foreach ($tests as $test) { echo throws(function() use ($test) { MongoDB\BSON\PackedArray::fromPHP($test); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected value to be a list, but given array is not OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected value to be a list, but given array is not OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected value to be a list, but given array is not ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-get-001.phpt0000644000175100001660000000123714760300421017441 0ustar --TEST-- MongoDB\BSON\PackedArray::get() index access --FILE-- get(0)); var_dump($document->get(2)); var_dump($document->get(3)); echo throws(function() use ($document) { var_dump($document->get(4)); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECTF-- int(0) string(3) "foo" object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(3) "123" } OK: Got MongoDB\Driver\Exception\RuntimeException Could not find index "4" in BSON array ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-get-002.phpt0000644000175100001660000000071114760300421017436 0ustar --TEST-- MongoDB\BSON\PackedArray::get() index access returns BSON structures --FILE-- 'bar']]); $child = $array->get(0); unset($array); var_dump($child); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-get-003.phpt0000644000175100001660000000062114760300421017437 0ustar --TEST-- MongoDB\BSON\PackedArray::get() index access --FILE-- 'bar']])->get(0); var_dump($child); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-get-004.phpt0000644000175100001660000000065414760300421017446 0ustar --TEST-- MongoDB\BSON\PackedArray::get() fixes invalid keys --FILE-- get('a'); var_dump($packedArray->has(0)); var_dump($packedArray->get(0)); var_dump($packedArray->toPHP()); ?> ===DONE=== --EXPECTF-- bool(true) int(10) array(1) { [0]=> int(10) } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-get-005.phpt0000644000175100001660000000103714760300421017443 0ustar --TEST-- MongoDB\BSON\PackedArray::get() fixes duplicate keys --FILE-- get('a'); var_dump($packedArray->has(0)); var_dump($packedArray->get(0)); var_dump($packedArray->has(1)); var_dump($packedArray->get(1)); var_dump($packedArray->toPHP()); ?> ===DONE=== --EXPECTF-- bool(true) int(10) bool(true) int(20) array(2) { [0]=> int(10) [1]=> int(20) } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-getIterator-001.phpt0000644000175100001660000000055614760300421021156 0ustar --TEST-- MongoDB\BSON\PackedArray::getIterator() tests --FILE-- getIterator(); echo get_class($iterator), "\n"; foreach ($iterator as $key => $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECTF-- MongoDB\BSON\Iterator int(0) int(1) int(1) int(2) ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-get_properties-001.phpt0000644000175100001660000000042614760300421021714 0ustar --TEST-- MongoDB\BSON\PackedArray get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECTF-- array(1) { ["data"]=> string(8) "BQAAAAA=" } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-has-001.phpt0000644000175100001660000000047614760300421017441 0ustar --TEST-- MongoDB\BSON\PackedArray::has() checks if index exists --FILE-- has(0)); var_dump($document->has(2)); var_dump($document->has(3)); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-serialization-002.phpt0000644000175100001660000000255514760300421021544 0ustar --TEST-- MongoDB\BSON\PackedArray serialization (__serialize and __unserialize) --FILE-- 'bar']]); var_dump($array); var_dump($s = serialize($array)); var_dump(unserialize($s)); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(68) "MwAAABAwAAAAAAAQMQABAAAAAjIABAAAAGZvbwADMwASAAAAAmZvbwAEAAAAYmFyAAAA" ["value"]=> array(4) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "foo" [3]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } string(123) "O:24:"MongoDB\BSON\PackedArray":1:{s:4:"data";s:68:"MwAAABAwAAAAAAAQMQABAAAAAjIABAAAAGZvbwADMwASAAAAAmZvbwAEAAAAYmFyAAAA";}" object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(68) "MwAAABAwAAAAAAAQMQABAAAAAjIABAAAAGZvbwADMwASAAAAAmZvbwAEAAAAYmFyAAAA" ["value"]=> array(4) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "foo" [3]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-set_state-001.phpt0000644000175100001660000000167514760300421020663 0ustar --TEST-- MongoDB\BSON\PackedArray::__set_state() --FILE-- 'bar'] ]); $s = var_export($array, true); echo $s, "\n"; var_dump($a = eval('return ' . $s . ';')); var_dump($a == $array); ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\PackedArray::__set_state(array( 'data' => 'MwAAABAwAAAAAAAQMQABAAAAAjIABAAAAGZvbwADMwASAAAAAmZvbwAEAAAAYmFyAAAA', )) object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(68) "MwAAABAwAAAAAAAQMQABAAAAAjIABAAAAGZvbwADMwASAAAAAmZvbwAEAAAAYmFyAAAA" ["value"]=> array(4) { [0]=> int(0) [1]=> int(1) [2]=> string(3) "foo" [3]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-set_state_error-001.phpt0000644000175100001660000000224214760300421022063 0ustar --TEST-- MongoDB\BSON\PackedArray::__set_state() handles invalid BSON payload correctly --FILE-- '', 'Last byte is non-zero' => pack( 'VCa*xVa*', 4 + 1 + 2 + 4 + 2, // Size: 4 bytes for size, 1 byte for type, 4 bytes for key, 4 bytes for string length, 2 bytes for string 0x02, '0', 2, 'a' ), 'Length does not match document length' => pack('VCa*Va*xx', 7, 0x02, 'foo', 1, 'a'), ]; foreach ($tests as $test) { echo throws(function() use ($test) { MongoDB\BSON\PackedArray::__set_state([ 'data' => base64_encode($test), ]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\PackedArray initialization requires valid BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\PackedArray initialization requires valid BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\PackedArray initialization requires valid BSON ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toCanonicalExtendedJSON-001.phpt0000644000175100001660000000134214760300421023264 0ustar --TEST-- MongoDB\BSON\PackedArray::toCanonicalExtendedJSON(): Encoding JSON --FILE-- 'bar' ]], ]; foreach ($tests as $value) { echo MongoDB\BSON\PackedArray::fromPHP($value)->toCanonicalExtendedJSON(), "\n"; } ?> ===DONE=== --EXPECT-- [ ] [ null ] [ true ] [ "foo" ] [ { "$numberInt" : "123" } ] [ { "$numberDouble" : "1.0" } ] [ { "$numberDouble" : "NaN" } ] [ { "$numberDouble" : "Infinity" } ] [ { "$numberDouble" : "-Infinity" } ] [ [ "foo", "bar" ] ] [ { "foo" : "bar" } ] ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toCanonicalJSON-002.phpt0000644000175100001660000000244114760300421021605 0ustar --TEST-- MongoDB\BSON\PackedArray::toCanonicalExtendedJSON(): Encoding extended JSON types --FILE-- 1]) ], [new MongoDB\BSON\MinKey ], [new MongoDB\BSON\MaxKey ], ]; foreach ($tests as $value) { echo MongoDB\BSON\PackedArray::fromPHP($value)->toCanonicalExtendedJSON(), "\n"; } ?> ===DONE=== --EXPECT-- [ { "$oid" : "56315a7c6118fd1b920270b1" } ] [ { "$binary" : { "base64" : "Zm9v", "subType" : "00" } } ] [ { "$date" : { "$numberLong" : "1445990400000" } } ] [ { "$timestamp" : { "t" : 5678, "i" : 1234 } } ] [ { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } ] [ { "$code" : "function() { return 1; }" } ] [ { "$code" : "function() { return a; }", "$scope" : { "a" : { "$numberInt" : "1" } } } ] [ { "$minKey" : 1 } ] [ { "$maxKey" : 1 } ] ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toPHP-001.phpt0000644000175100001660000000054514760300421017655 0ustar --TEST-- MongoDB\BSON\PackedArray::toPHP(): Type map defaults to array root type --FILE-- toPHP()); ?> ===DONE=== --EXPECT-- array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toPHP-002.phpt0000644000175100001660000000060314760300421017651 0ustar --TEST-- MongoDB\BSON\PackedArray::toPHP(): Use object as root type --FILE-- toPHP(['root' => 'object'])); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["0"]=> int(1) ["1"]=> int(2) ["2"]=> int(3) } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toPHP-003.phpt0000644000175100001660000000113514760300421017653 0ustar --TEST-- MongoDB\BSON\PackedArray::toPHP(): Unserializable as root type --FILE-- data = $data; } } $packedArray = MongoDB\BSON\PackedArray::fromPHP([1, 2, 3]); var_dump($packedArray->toPHP(['root' => MyArray::class])); ?> ===DONE=== --EXPECTF-- object(MyArray)#%d (%d) { ["data"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toPHP-004.phpt0000644000175100001660000000076514760300421017664 0ustar --TEST-- MongoDB\BSON\PackedArray::toPHP(): Use bson as root type --FILE-- toPHP(['root' => 'bson'])); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "GgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAA=" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toPHP-005.phpt0000644000175100001660000000061614760300421017660 0ustar --TEST-- MongoDB\BSON\PackedArray::toPHP(): int64 values are returned as Int64 instances --FILE-- toPHP()); ?> ===DONE=== --EXPECTF-- array(2) { [0]=> int(123) [1]=> object(MongoDB\BSON\Int64)#%d (1) { ["integer"]=> string(3) "123" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toRelaxedExtendedJSON-001.phpt0000644000175100001660000000126114760300421022761 0ustar --TEST-- MongoDB\BSON\PackedArray::toRelaxedExtendedJSON(): Encoding JSON --FILE-- 'bar' ]], ]; foreach ($tests as $value) { echo MongoDB\BSON\PackedArray::fromPHP($value)->toRelaxedExtendedJSON(), "\n"; } ?> ===DONE=== --EXPECT-- [ ] [ null ] [ true ] [ "foo" ] [ 123 ] [ 1.0 ] [ { "$numberDouble" : "NaN" } ] [ { "$numberDouble" : "Infinity" } ] [ { "$numberDouble" : "-Infinity" } ] [ [ "foo", "bar" ] ] [ { "foo" : "bar" } ] ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-toRelaxedExtendedJSON-002.phpt0000644000175100001660000000240414760300421022762 0ustar --TEST-- MongoDB\BSON\PackedArray::toRelaxedExtendedJSON(): Encoding extended JSON types --FILE-- 1]) ], [ new MongoDB\BSON\MinKey ], [ new MongoDB\BSON\MaxKey ], ]; foreach ($tests as $value) { echo MongoDB\BSON\PackedArray::fromPHP($value)->toRelaxedExtendedJSON(), "\n"; } ?> ===DONE=== --EXPECT-- [ { "$oid" : "56315a7c6118fd1b920270b1" } ] [ { "$binary" : { "base64" : "Zm9v", "subType" : "00" } } ] [ { "$date" : "2015-10-28T00:00:00Z" } ] [ { "$timestamp" : { "t" : 5678, "i" : 1234 } } ] [ { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } ] [ { "$code" : "function() { return 1; }" } ] [ { "$code" : "function() { return a; }", "$scope" : { "a" : 1 } } ] [ { "$minKey" : 1 } ] [ { "$maxKey" : 1 } ] ===DONE=== mongodb-1.21.0/tests/bson/bson-packedarray-unserialize_error-002.phpt0000644000175100001660000000257414760300421022433 0ustar --TEST-- MongoDB\BSON\PackedArray::__unserialize() throws on errors --FILE-- '', 'Last byte is non-zero' => pack( 'VCa*xVa*', 4 + 1 + 4 + 4 + 2, // Size: 4 bytes for size, 1 byte for type, 4 bytes for key, 4 bytes for string length, 2 bytes for string 0x02, 'foo', 2, 'a' ), 'Length does not match document length' => pack('VCa*Va*xx', 7, 0x02, 'foo', 1, 'a'), ]; foreach ($tests as $test) { echo throws(function() use ($test) { $data = base64_encode($test); $dataLength = strlen($data); $payload = sprintf( 'O:%d:"%s":1:{s:4:"data";s:%d:"%s";}', strlen(MongoDB\BSON\PackedArray::class), MongoDB\BSON\PackedArray::class, $dataLength, $data ); unserialize($payload); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\PackedArray initialization requires valid BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\PackedArray initialization requires valid BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\PackedArray initialization requires valid BSON ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-001.phpt0000644000175100001660000000200514760300421015502 0ustar --TEST-- MongoDB\BSON\Regex #001 --FILE-- getPattern()); printf("Flags: %s\n", $regexp->getFlags()); printf("String representation: %s\n", $regexp); $tests = array( array("regex" => $regexp), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- Pattern: regexp Flags: i String representation: /regexp/i Test#0 { "regex" : { "$regularExpression" : { "pattern" : "regexp", "options" : "i" } } } string(82) "{ "regex" : { "$regularExpression" : { "pattern" : "regexp", "options" : "i" } } }" string(82) "{ "regex" : { "$regularExpression" : { "pattern" : "regexp", "options" : "i" } } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-002.phpt0000644000175100001660000000043714760300421015512 0ustar --TEST-- MongoDB\BSON\Regex debug handler --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(1) "i" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-003.phpt0000644000175100001660000000201114760300421015501 0ustar --TEST-- MongoDB\BSON\Regex with flags omitted --FILE-- getPattern()); printf("Flags: %s\n", $regexp->getFlags()); printf("String representation: %s\n", $regexp); $tests = array( array("regex" => $regexp), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- Pattern: regexp Flags: String representation: /regexp/ Test#0 { "regex" : { "$regularExpression" : { "pattern" : "regexp", "options" : "" } } } string(81) "{ "regex" : { "$regularExpression" : { "pattern" : "regexp", "options" : "" } } }" string(81) "{ "regex" : { "$regularExpression" : { "pattern" : "regexp", "options" : "" } } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-004.phpt0000644000175100001660000000045414760300421015513 0ustar --TEST-- MongoDB\BSON\Regex debug handler with flags omitted --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(0) "" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-005.phpt0000644000175100001660000000050114760300421015505 0ustar --TEST-- MongoDB\BSON\Regex initialization will alphabetize flags --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(6) "ilmsux" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-clone-001.phpt0000644000175100001660000000110514760300421016600 0ustar --TEST-- MongoDB\BSON\Regex can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Regex)#%d (2) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(1) "i" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-clone-002.phpt0000644000175100001660000000110514760300421016601 0ustar --TEST-- MongoDB\BSON\Regex can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Regex)#%d (2) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(1) "i" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-compare-001.phpt0000644000175100001660000000110514760300421017126 0ustar --TEST-- MongoDB\BSON\Regex comparisons (without flags) --FILE-- new MongoDB\BSON\Regex('regexp')); var_dump(new MongoDB\BSON\Regex('regexp') < new MongoDB\BSON\Regex('regexr')); var_dump(new MongoDB\BSON\Regex('regexp') > new MongoDB\BSON\Regex('regexo')); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-compare-002.phpt0000644000175100001660000000132314760300421017131 0ustar --TEST-- MongoDB\BSON\Regex comparisons (with flags) --FILE-- new MongoDB\BSON\Regex('regexp', 'm')); var_dump(new MongoDB\BSON\Regex('regexp', 'm') < new MongoDB\BSON\Regex('regexp', 'x')); var_dump(new MongoDB\BSON\Regex('regexp', 'm') > new MongoDB\BSON\Regex('regexp', 'i')); var_dump(new MongoDB\BSON\Regex('regexp', 'm') > new MongoDB\BSON\Regex('regexp')); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-get_properties-001.phpt0000644000175100001660000000046014760300421020536 0ustar --TEST-- MongoDB\BSON\Regex get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECT-- array(2) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(1) "i" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-get_properties-002.phpt0000644000175100001660000000051514760300421020540 0ustar --TEST-- MongoDB\BSON\Regex get_properties handler (foreach) --FILE-- $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECT-- string(7) "pattern" string(6) "regexp" string(5) "flags" string(1) "i" ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-jsonserialize-001.phpt0000644000175100001660000000046214760300421020366 0ustar --TEST-- MongoDB\BSON\Regex::jsonSerialize() return value (without flags) --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(2) { ["$regex"]=> string(7) "pattern" ["$options"]=> string(0) "" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-jsonserialize-002.phpt0000644000175100001660000000046514760300421020372 0ustar --TEST-- MongoDB\BSON\Regex::jsonSerialize() return value (with flags) --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(2) { ["$regex"]=> string(7) "pattern" ["$options"]=> string(1) "i" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-jsonserialize-003.phpt0000644000175100001660000000121114760300421020361 0ustar --TEST-- MongoDB\BSON\Regex::jsonSerialize() with json_encode() (without flags) --FILE-- new MongoDB\BSON\Regex('pattern')]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$regularExpression" : { "pattern" : "pattern", "options" : "" } } } {"foo":{"$regex":"pattern","$options":""}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(7) "pattern" ["flags"]=> string(0) "" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-jsonserialize-004.phpt0000644000175100001660000000121614760300421020367 0ustar --TEST-- MongoDB\BSON\Regex::jsonSerialize() with json_encode() (with flags) --FILE-- new MongoDB\BSON\Regex('pattern', 'i')]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } } {"foo":{"$regex":"pattern","$options":"i"}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(7) "pattern" ["flags"]=> string(1) "i" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-serialization-003.phpt0000644000175100001660000000060714760300421020365 0ustar --TEST-- MongoDB\BSON\Regex unserialization will alphabetize flags (Serializable interface) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(6) "ilmsux" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-serialization-004.phpt0000644000175100001660000000107014760300421020361 0ustar --TEST-- MongoDB\BSON\Regex serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(1) "i" } string(77) "O:18:"MongoDB\BSON\Regex":2:{s:7:"pattern";s:6:"regexp";s:5:"flags";s:1:"i";}" object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(1) "i" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-serialization-005.phpt0000644000175100001660000000110314760300421020357 0ustar --TEST-- MongoDB\BSON\Regex serialization with flags omitted (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(0) "" } string(76) "O:18:"MongoDB\BSON\Regex":2:{s:7:"pattern";s:6:"regexp";s:5:"flags";s:0:"";}" object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(0) "" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-serialization-006.phpt0000644000175100001660000000060714760300421020370 0ustar --TEST-- MongoDB\BSON\Regex unserialization will alphabetize flags (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(6) "regexp" ["flags"]=> string(6) "ilmsux" } ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-serialization_error-001.phpt0000644000175100001660000000221414760300421021570 0ustar --TEST-- MongoDB\BSON\Regex unserialization requires "pattern" and "flags" string fields (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-serialization_error-002.phpt0000644000175100001660000000156114760300421021575 0ustar --TEST-- MongoDB\BSON\Regex unserialization does not allow pattern or flags to contain null bytes (Serializable interface) --DESCRIPTION-- BSON Corpus spec prose test #1 --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Pattern cannot contain null bytes OK: Got MongoDB\Driver\Exception\InvalidArgumentException Flags cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-serialization_error-003.phpt0000644000175100001660000000217614760300421021601 0ustar --TEST-- MongoDB\BSON\Regex unserialization requires "pattern" and "flags" string fields (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-serialization_error-004.phpt0000644000175100001660000000155214760300421021577 0ustar --TEST-- MongoDB\BSON\Regex unserialization does not allow pattern or flags to contain null bytes (__serialize and __unserialize) --DESCRIPTION-- BSON Corpus spec prose test #1 --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Pattern cannot contain null bytes OK: Got MongoDB\Driver\Exception\InvalidArgumentException Flags cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-set_state-001.phpt0000644000175100001660000000047514760300421017504 0ustar --TEST-- MongoDB\BSON\Regex::__set_state() --FILE-- 'regexp', 'flags' => 'i', ])); echo "\n"; ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Regex::__set_state(array( 'pattern' => 'regexp', 'flags' => 'i', )) ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-set_state-002.phpt0000644000175100001660000000053614760300421017503 0ustar --TEST-- MongoDB\BSON\Regex::__set_state() will alphabetize flags --FILE-- 'regexp', 'flags' => 'xusmli', ])); echo "\n"; ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Regex::__set_state(array( 'pattern' => 'regexp', 'flags' => 'ilmsux', )) ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-set_state_error-001.phpt0000644000175100001660000000205514760300421020711 0ustar --TEST-- MongoDB\BSON\Regex::__set_state() requires "pattern" and "flags" string fields --FILE-- 'regexp']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Regex::__set_state(['flags' => 'i']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Regex::__set_state(['pattern' => 0, 'flags' => 0]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex initialization requires "pattern" and "flags" string fields ===DONE=== mongodb-1.21.0/tests/bson/bson-regex-set_state_error-002.phpt0000644000175100001660000000141514760300421020711 0ustar --TEST-- MongoDB\BSON\Regex::__set_state() does not allow pattern or flags to contain null bytes --DESCRIPTION-- BSON Corpus spec prose test #1 --FILE-- "regexp\0", 'flags' => 'i']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Regex::__set_state(['pattern' => 'regexp', 'flags' => "i\0"]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Pattern cannot contain null bytes OK: Got MongoDB\Driver\Exception\InvalidArgumentException Flags cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-regex_error-001.phpt0000644000175100001660000000220114760300421016711 0ustar --TEST-- MongoDB\BSON\Regex argument count errors --SKIPIF-- =', '7.99'); ?> --FILE-- getPattern(true); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() use ($regex) { $regex->getFlags(true); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { new MongoDB\BSON\Regex; }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex::getPattern() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex::getFlags() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Regex::__construct() expects at least 1 %r(argument|parameter)%r, 0 given ===DONE=== mongodb-1.21.0/tests/bson/bson-regex_error-002.phpt0000644000175100001660000000035214760300421016717 0ustar --TEST-- MongoDB\BSON\Regex cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyRegex %s final class %SMongoDB\BSON\Regex%S in %s on line %d mongodb-1.21.0/tests/bson/bson-regex_error-003.phpt0000644000175100001660000000130714760300421016721 0ustar --TEST-- MongoDB\BSON\Regex::__construct() does not allow pattern or flags to contain null bytes --DESCRIPTION-- BSON Corpus spec prose test #1 --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Pattern cannot contain null bytes OK: Got MongoDB\Driver\Exception\InvalidArgumentException Flags cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-regexinterface-001.phpt0000644000175100001660000000040614760300421017366 0ustar --TEST-- MongoDB\BSON\RegexInterface is implemented by MongoDB\BSON\Regex --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-001.phpt0000644000175100001660000000123414760300421015700 0ustar --TEST-- MongoDB\BSON\Symbol #001 --FILE-- toPHP(), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $testagain = toPHP($s); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- Test#0 { "symbol" : { "$symbol" : "test" } } string(37) "{ "symbol" : { "$symbol" : "test" } }" string(37) "{ "symbol" : { "$symbol" : "test" } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-clone-001.phpt0000644000175100001660000000114614760300421017000 0ustar --TEST-- MongoDB\BSON\Symbol can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- toPHP(); $symbol = $test->symbol; $clone = clone $symbol; var_dump($clone == $symbol); var_dump($clone === $symbol); unset($symbol); var_dump($clone); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Symbol)#%d (1) { ["symbol"]=> string(4) "test" } ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-clone-002.phpt0000644000175100001660000000114614760300421017001 0ustar --TEST-- MongoDB\BSON\Symbol can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- toPHP(); $symbol = $test->symbol; $clone = clone $symbol; var_dump($clone == $symbol); var_dump($clone === $symbol); unset($symbol); var_dump($clone); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Symbol)#%d (1) { ["symbol"]=> string(4) "test" } ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-compare-001.phpt0000644000175100001660000000121514760300421017323 0ustar --TEST-- MongoDB\BSON\Symbol comparisons --FILE-- toPHP() == MongoDB\BSON\Document::fromJSON('{ "symbol": {"$symbol": "val1"} }')->toPHP()); var_dump(MongoDB\BSON\Document::fromJSON('{ "symbol": {"$symbol": "val1"} }')->toPHP() < MongoDB\BSON\Document::fromJSON('{ "symbol": {"$symbol": "val2"} }')->toPHP()); var_dump(MongoDB\BSON\Document::fromJSON('{ "symbol": {"$symbol": "val1"} }')->toPHP() > MongoDB\BSON\Document::fromJSON('{ "symbol": {"$symbol": "val0"} }')->toPHP()); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-get_properties-001.phpt0000644000175100001660000000052514760300421020733 0ustar --TEST-- MongoDB\BSON\Symbol get_properties handler (get_object_vars) --FILE-- toPHP(); $symbol = $document->symbol; var_dump(get_object_vars($symbol)); ?> ===DONE=== --EXPECT-- array(1) { ["symbol"]=> string(4) "test" } ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-get_properties-002.phpt0000644000175100001660000000056014760300421020733 0ustar --TEST-- MongoDB\BSON\Symbol get_properties handler (foreach) --FILE-- toPHP(); $symbol = $document->symbol; foreach ($symbol as $key => $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECT-- string(6) "symbol" string(4) "test" ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-jsonserialize-001.phpt0000644000175100001660000000047114760300421020561 0ustar --TEST-- MongoDB\BSON\Symbol::jsonSerialize() return value --FILE-- toPHP()->symbol; var_dump($js->jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$symbol"]=> string(9) "valSymbol" } ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-jsonserialize-002.phpt0000644000175100001660000000112314760300421020555 0ustar --TEST-- MongoDB\BSON\Symbol::jsonSerialize() with json_encode() --FILE-- toPHP(); $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$symbol" : "symbolValue" } } {"foo":{"$symbol":"symbolValue"}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Symbol)#%d (%d) { ["symbol"]=> string(11) "symbolValue" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-serialization-002.phpt0000644000175100001660000000110414760300421020550 0ustar --TEST-- MongoDB\BSON\Symbol serialization (__serialize and __unserialize) --FILE-- toPHP()->symbol; var_dump($symbol = $test); var_dump($s = serialize($symbol)); var_dump(unserialize($s)); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Symbol)#%d (%d) { ["symbol"]=> string(11) "symbolValue" } string(63) "O:19:"MongoDB\BSON\Symbol":1:{s:6:"symbol";s:11:"symbolValue";}" object(MongoDB\BSON\Symbol)#%d (%d) { ["symbol"]=> string(11) "symbolValue" } ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-serialization_error-001.phpt0000644000175100001660000000077314760300421021773 0ustar --TEST-- MongoDB\BSON\Symbol unserialization requires "symbol" string field (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Symbol initialization requires "symbol" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-serialization_error-002.phpt0000644000175100001660000000077214760300421021773 0ustar --TEST-- MongoDB\BSON\Symbol unserialization does not allow string to contain null bytes (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Symbol cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-serialization_error-003.phpt0000644000175100001660000000077314760300421021775 0ustar --TEST-- MongoDB\BSON\Symbol unserialization requires "symbol" string field (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Symbol initialization requires "symbol" string field ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-serialization_error-004.phpt0000644000175100001660000000077214760300421021775 0ustar --TEST-- MongoDB\BSON\Symbol unserialization does not allow string to contain null bytes (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Symbol cannot contain null bytes ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-set_state-001.phpt0000644000175100001660000000067714760300421017703 0ustar --TEST-- MongoDB\BSON\Symbol::__set_state() --FILE-- toPHP()->symbol; $s = var_export($symbol, true); echo $s, "\n"; var_dump(eval('return ' . $s . ';')); ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Symbol::__set_state(array( 'symbol' => 'test', )) object(MongoDB\BSON\Symbol)#%d (%d) { ["symbol"]=> string(4) "test" } ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol-tostring-001.phpt0000644000175100001660000000041714760300421017551 0ustar --TEST-- MongoDB\BSON\Symbol::__toString() --FILE-- toPHP()->symbol; var_dump((string) $symbol); ?> ===DONE=== --EXPECT-- string(11) "symbolValue" ===DONE=== mongodb-1.21.0/tests/bson/bson-symbol_error-001.phpt0000644000175100001660000000035714760300421017116 0ustar --TEST-- MongoDB\BSON\Symbol cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MySymbol %s final class %SMongoDB\BSON\Symbol%S in %s on line %d mongodb-1.21.0/tests/bson/bson-timestamp-001.phpt0000644000175100001660000000153514760300421016402 0ustar --TEST-- MongoDB\BSON\Timestamp #001 --FILE-- $timestamp), ); $s = new MongoDB\BSON\Timestamp(1234, 5678); echo $s, "\n"; foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- [1234:5678] Test#0 { "timestamp" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } } string(63) "{ "timestamp" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } }" string(63) "{ "timestamp" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-002.phpt0000644000175100001660000000046714760300421016406 0ustar --TEST-- MongoDB\BSON\Timestamp debug handler --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-003.phpt0000644000175100001660000000121214760300421016374 0ustar --TEST-- MongoDB\BSON\Timestamp constructor requires positive unsigned 32-bit integers --FILE-- ===DONE=== --EXPECTF-- Test [2147483647:0] object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(10) "2147483647" ["timestamp"]=> string(1) "0" } Test [0:2147483647] object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(1) "0" ["timestamp"]=> string(10) "2147483647" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-004.phpt0000644000175100001660000000136614760300421016407 0ustar --TEST-- MongoDB\BSON\Timestamp constructor requires 64-bit integers to be positive unsigned 32-bit integers --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- Test [4294967295:0] object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(10) "4294967295" ["timestamp"]=> string(1) "0" } Test [0:4294967295] object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(1) "0" ["timestamp"]=> string(10) "4294967295" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-005.phpt0000644000175100001660000000203614760300421016403 0ustar --TEST-- MongoDB\BSON\Timestamp constructor requires positive unsigned 32-bit integers (as string) --FILE-- ===DONE=== --EXPECTF-- Test [2147483647:0] object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(10) "2147483647" ["timestamp"]=> string(1) "0" } Test [0:2147483647] object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(1) "0" ["timestamp"]=> string(10) "2147483647" } Test [4294967295:0] object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(10) "4294967295" ["timestamp"]=> string(1) "0" } Test [0:4294967295] object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(1) "0" ["timestamp"]=> string(10) "4294967295" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-clone-001.phpt0000644000175100001660000000114414760300421017474 0ustar --TEST-- MongoDB\BSON\Timestamp can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Timestamp)#%d (2) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-clone-002.phpt0000644000175100001660000000114414760300421017475 0ustar --TEST-- MongoDB\BSON\Timestamp can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\Timestamp)#%d (2) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-compare-001.phpt0000644000175100001660000000160114760300421020020 0ustar --TEST-- MongoDB\BSON\Timestamp comparisons --FILE-- new MongoDB\BSON\Timestamp(1234, 5678)); // Timestamp is compared first var_dump(new MongoDB\BSON\Timestamp(1234, 5678) < new MongoDB\BSON\Timestamp(1233, 5679)); var_dump(new MongoDB\BSON\Timestamp(1234, 5678) > new MongoDB\BSON\Timestamp(1235, 5677)); // Increment is compared second var_dump(new MongoDB\BSON\Timestamp(1234, 5678) < new MongoDB\BSON\Timestamp(1235, 5678)); var_dump(new MongoDB\BSON\Timestamp(1234, 5678) > new MongoDB\BSON\Timestamp(1233, 5678)); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-getIncrement-001.phpt0000644000175100001660000000074014760300421021021 0ustar --TEST-- MongoDB\BSON\Timestamp::getIncrement() --FILE-- getIncrement()); echo "\n"; } ?> ===DONE=== --EXPECTF-- Test [1234:5678] int(1234) Test [2147483647:0] int(2147483647) Test [0:2147483647] int(0) ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-getTimestamp-001.phpt0000644000175100001660000000074014760300421021040 0ustar --TEST-- MongoDB\BSON\Timestamp::getTimestamp() --FILE-- getTimestamp()); echo "\n"; } ?> ===DONE=== --EXPECTF-- Test [1234:5678] int(5678) Test [2147483647:0] int(0) Test [0:2147483647] int(2147483647) ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-get_properties-001.phpt0000644000175100001660000000050414760300421021426 0ustar --TEST-- MongoDB\BSON\Timestamp get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECT-- array(2) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-get_properties-002.phpt0000644000175100001660000000054114760300421021430 0ustar --TEST-- MongoDB\BSON\Timestamp get_properties handler (foreach) --FILE-- $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECT-- string(9) "increment" string(4) "1234" string(9) "timestamp" string(4) "5678" ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-jsonserialize-001.phpt0000644000175100001660000000047414760300421021262 0ustar --TEST-- MongoDB\BSON\Timestamp::jsonSerialize() return value --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$timestamp"]=> array(2) { ["t"]=> int(5678) ["i"]=> int(1234) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-jsonserialize-002.phpt0000644000175100001660000000117214760300421021257 0ustar --TEST-- MongoDB\BSON\Timestamp::jsonSerialize() with json_encode() --FILE-- new MongoDB\BSON\Timestamp('1234', '5678')]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } } {"foo":{"$timestamp":{"t":5678,"i":1234}}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization-003.phpt0000644000175100001660000000271614760300421021261 0ustar --TEST-- MongoDB\BSON\Timestamp serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } string(88) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";s:4:"1234";s:9:"timestamp";s:4:"5678";}" object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(10) "2147483647" ["timestamp"]=> string(1) "0" } string(92) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";s:10:"2147483647";s:9:"timestamp";s:1:"0";}" object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(10) "2147483647" ["timestamp"]=> string(1) "0" } object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(1) "0" ["timestamp"]=> string(10) "2147483647" } string(92) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";s:1:"0";s:9:"timestamp";s:10:"2147483647";}" object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(1) "0" ["timestamp"]=> string(10) "2147483647" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization-004.phpt0000644000175100001660000000231214760300421021252 0ustar --TEST-- MongoDB\BSON\Timestamp serialization (__serialize and __unserialize) (64-bit) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(10) "4294967295" ["timestamp"]=> string(1) "0" } string(92) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";s:10:"4294967295";s:9:"timestamp";s:1:"0";}" object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(10) "4294967295" ["timestamp"]=> string(1) "0" } object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(1) "0" ["timestamp"]=> string(10) "4294967295" } string(92) "O:22:"MongoDB\BSON\Timestamp":2:{s:9:"increment";s:1:"0";s:9:"timestamp";s:10:"4294967295";}" object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(1) "0" ["timestamp"]=> string(10) "4294967295" } ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization_error-001.phpt0000644000175100001660000000317014760300421022463 0ustar --TEST-- MongoDB\BSON\Timestamp unserialization requires "increment" and "timestamp" integer fields (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization_error-002.phpt0000644000175100001660000000277114760300421022472 0ustar --TEST-- MongoDB\BSON\Timestamp unserialization requires positive unsigned 32-bit integers (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, -2147483648 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, -2147483648 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization_error-003.phpt0000644000175100001660000000175314760300421022472 0ustar --TEST-- MongoDB\BSON\Timestamp unserialization requires 64-bit integers to be positive unsigned 32-bit integers (Serializable interface) --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, 4294967296 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, 4294967296 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization_error-004.phpt0000644000175100001660000000165714760300421022476 0ustar --TEST-- MongoDB\BSON\Timestamp unserialization requires strings to parse as 64-bit integers (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1.23" as 64-bit integer increment for MongoDB\BSON\Timestamp initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "5.67" as 64-bit integer timestamp for MongoDB\BSON\Timestamp initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization_error-005.phpt0000644000175100001660000000314314760300421022467 0ustar --TEST-- MongoDB\BSON\Timestamp unserialization requires "increment" and "timestamp" integer fields (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization_error-006.phpt0000644000175100001660000000274414760300421022476 0ustar --TEST-- MongoDB\BSON\Timestamp unserialization requires positive unsigned 32-bit integers (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, -2147483648 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, -2147483648 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization_error-007.phpt0000644000175100001660000000174414760300421022476 0ustar --TEST-- MongoDB\BSON\Timestamp unserialization requires 64-bit integers to be positive unsigned 32-bit integers (__serialize and __unserialize) --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, 4294967296 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, 4294967296 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-serialization_error-008.phpt0000644000175100001660000000165014760300421022473 0ustar --TEST-- MongoDB\BSON\Timestamp unserialization requires strings to parse as 64-bit integers (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1.23" as 64-bit integer increment for MongoDB\BSON\Timestamp initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "5.67" as 64-bit integer timestamp for MongoDB\BSON\Timestamp initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-set_state-001.phpt0000644000175100001660000000134414760300421020371 0ustar --TEST-- MongoDB\BSON\Timestamp::__set_state() --FILE-- $increment, 'timestamp' => $timestamp, ])); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Timestamp::__set_state(array( 'increment' => '1234', 'timestamp' => '5678', )) %r\\?%rMongoDB\BSON\Timestamp::__set_state(array( 'increment' => '2147483647', 'timestamp' => '0', )) %r\\?%rMongoDB\BSON\Timestamp::__set_state(array( 'increment' => '0', 'timestamp' => '2147483647', )) ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-set_state-002.phpt0000644000175100001660000000130714760300421020371 0ustar --TEST-- MongoDB\BSON\Timestamp::__set_state() (64-bit) --SKIPIF-- --FILE-- $increment, 'timestamp' => $timestamp, ])); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Timestamp::__set_state(array( 'increment' => '4294967295', 'timestamp' => '0', )) %r\\?%rMongoDB\BSON\Timestamp::__set_state(array( 'increment' => '0', 'timestamp' => '4294967295', )) ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-set_state_error-001.phpt0000644000175100001660000000300214760300421021573 0ustar --TEST-- MongoDB\BSON\Timestamp::__set_state() requires "increment" and "timestamp" integer fields --FILE-- 1234]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Timestamp::__set_state(['timestamp' => 5678]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Timestamp::__set_state(['increment' => '1234', 'timestamp' => 5678]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Timestamp::__set_state(['increment' => 1234, 'timestamp' => '5678']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp initialization requires "increment" and "timestamp" integer or numeric string fields ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-set_state_error-002.phpt0000644000175100001660000000260314760300421021602 0ustar --TEST-- MongoDB\BSON\Timestamp::__set_state() requires positive unsigned 32-bit integers --FILE-- -1, 'timestamp' => 5678]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Timestamp::__set_state(['increment' => -2147483647, 'timestamp' => 5678]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Timestamp::__set_state(['increment' => 1234, 'timestamp' => -1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Timestamp::__set_state(['increment' => 1234, 'timestamp' => -2147483647]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, -2147483647 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, -2147483647 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-set_state_error-003.phpt0000644000175100001660000000164314760300421021606 0ustar --TEST-- MongoDB\BSON\Timestamp::__set_state() requires 64-bit integers to be positive unsigned 32-bit integers --SKIPIF-- --FILE-- 4294967296, 'timestamp' => 5678]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Timestamp::__set_state(['increment' => 1234, 'timestamp' => 4294967296]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, 4294967296 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, 4294967296 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp-set_state_error-004.phpt0000644000175100001660000000153714760300421021611 0ustar --TEST-- MongoDB\BSON\Timestamp::__set_state() requires strings to parse as 64-bit integers --FILE-- '1.23', 'timestamp' => '5678']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\Timestamp::__set_state(['increment' => '1234', 'timestamp' => '5.67']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1.23" as 64-bit integer increment for MongoDB\BSON\Timestamp initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "5.67" as 64-bit integer timestamp for MongoDB\BSON\Timestamp initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp_error-001.phpt0000644000175100001660000000105714760300421017612 0ustar --TEST-- MongoDB\BSON\Timestamp argument count errors --SKIPIF-- =', '7.99'); ?> --FILE-- ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\Timestamp::__construct() expects exactly 2 %r(argument|parameter)%rs, 0 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp_error-002.phpt0000644000175100001660000000037614760300421017616 0ustar --TEST-- MongoDB\BSON\Timestamp cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyTimestamp %s final class %SMongoDB\BSON\Timestamp%S in %s on line %d mongodb-1.21.0/tests/bson/bson-timestamp_error-003.phpt0000644000175100001660000000273014760300421017613 0ustar --TEST-- MongoDB\BSON\Timestamp constructor requires positive unsigned 32-bit integers --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, -2147483648 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, -2147483648 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp_error-004.phpt0000644000175100001660000000151014760300421017607 0ustar --TEST-- MongoDB\BSON\Timestamp constructor requires 64-bit integers to be positive unsigned 32-bit integers --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer, 4294967296 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer, 4294967296 given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp_error-005.phpt0000644000175100001660000000141214760300421017611 0ustar --TEST-- MongoDB\BSON\Timestamp constructor requires strings to parse as 64-bit integers --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1.23" as 64-bit integer increment for MongoDB\BSON\Timestamp initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "5.67" as 64-bit integer timestamp for MongoDB\BSON\Timestamp initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-timestamp_error-006.phpt0000644000175100001660000000374614760300421017626 0ustar --TEST-- MongoDB\BSON\Timestamp constructor requires integer or string arguments --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer or string, null given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer or string, float given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer or string, bool given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer or string, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected increment to be an unsigned 32-bit integer or string, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer or string, null given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer or string, float given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer or string, bool given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer or string, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected timestamp to be an unsigned 32-bit integer or string, stdClass given ===DONE=== mongodb-1.21.0/tests/bson/bson-timestampinterface-001.phpt0000644000175100001660000000043214760300421020256 0ustar --TEST-- MongoDB\BSON\TimestampInterface is implemented by MongoDB\BSON\Timestamp --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-toCanonicalJSON-001.phpt0000644000175100001660000000502214760300421017316 0ustar --TEST-- MongoDB\BSON\toCanonicalExtendedJSON(): Encoding JSON --FILE-- null ], [ 'boolean' => true ], [ 'string' => 'foo' ], [ 'integer' => 123 ], [ 'double' => 1.0, ], [ 'nan' => NAN ], [ 'pos_inf' => INF ], [ 'neg_inf' => -INF ], [ 'array' => [ 'foo', 'bar' ]], [ 'document' => [ 'foo' => 'bar' ]], ]; foreach ($tests as $value) { $bson = MongoDB\BSON\fromPHP($value); echo MongoDB\BSON\toCanonicalExtendedJSON($bson), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "null" : null } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "boolean" : true } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "string" : "foo" } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "integer" : { "$numberInt" : "123" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "double" : { "$numberDouble" : "1.0" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "nan" : { "$numberDouble" : "NaN" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "pos_inf" : { "$numberDouble" : "Infinity" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "neg_inf" : { "$numberDouble" : "-Infinity" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "array" : [ "foo", "bar" ] } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "document" : { "foo" : "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toCanonicalJSON-002.phpt0000644000175100001660000000542714760300421017330 0ustar --TEST-- MongoDB\BSON\toCanonicalExtendedJSON(): Encoding extended JSON types --FILE-- new MongoDB\BSON\ObjectId('56315a7c6118fd1b920270b1') ], [ 'binary' => new MongoDB\BSON\Binary('foo', MongoDB\BSON\Binary::TYPE_GENERIC) ], [ 'date' => new MongoDB\BSON\UTCDateTime(new MongoDB\BSON\Int64('1445990400000')) ], [ 'timestamp' => new MongoDB\BSON\Timestamp(1234, 5678) ], [ 'regex' => new MongoDB\BSON\Regex('pattern', 'i') ], [ 'code' => new MongoDB\BSON\Javascript('function() { return 1; }') ], [ 'code_ws' => new MongoDB\BSON\Javascript('function() { return a; }', ['a' => 1]) ], [ 'minkey' => new MongoDB\BSON\MinKey ], [ 'maxkey' => new MongoDB\BSON\MaxKey ], ]; foreach ($tests as $value) { $bson = MongoDB\BSON\fromPHP($value); echo MongoDB\BSON\toCanonicalExtendedJSON($bson), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "_id" : { "$oid" : "56315a7c6118fd1b920270b1" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "binary" : { "$binary" : { "base64" : "Zm9v", "subType" : "00" } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "date" : { "$date" : { "$numberLong" : "1445990400000" } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "timestamp" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "regex" : { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "code" : { "$code" : "function() { return 1; }" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "code_ws" : { "$code" : "function() { return a; }", "$scope" : { "a" : { "$numberInt" : "1" } } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "minkey" : { "$minKey" : 1 } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s { "maxkey" : { "$maxKey" : 1 } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toCanonicalJSON_error-001.phpt0000644000175100001660000000202514760300421020527 0ustar --TEST-- MongoDB\BSON\toCanonicalExtendedJSON(): BSON decoding exceptions --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Reading document did not exhaust input buffer ===DONE=== mongodb-1.21.0/tests/bson/bson-toCanonicalJSON_error-002.phpt0000644000175100001660000000163014760300421020531 0ustar --TEST-- MongoDB\BSON\toCanonicalExtendedJSON(): BSON decoding exceptions for malformed documents --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader ===DONE=== mongodb-1.21.0/tests/bson/bson-toCanonicalJSON_error-003.phpt0000644000175100001660000000332414760300421020534 0ustar --TEST-- MongoDB\BSON\toCanonicalExtendedJSON(): BSON decoding exceptions for bson_as_canonical_json() failure --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string Deprecated: Function MongoDB\BSON\toCanonicalExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string ===DONE=== mongodb-1.21.0/tests/bson/bson-toJSON-001.phpt0000644000175100001660000000461614760300421015516 0ustar --TEST-- MongoDB\BSON\toJSON(): Encoding JSON --FILE-- null ], [ 'boolean' => true ], [ 'string' => 'foo' ], [ 'integer' => 123 ], [ 'double' => 1.0, ], /* Note: MongoDB\BSON\toJSON() does not properly handle NAN and INF values. * MongoDB\BSON\toCanonicalExtendedJSON() or MongoDB\BSON\toRelaxedExtendedJSON() should be used * instead. */ [ 'nan' => NAN ], [ 'pos_inf' => INF ], [ 'neg_inf' => -INF ], [ 'array' => [ 'foo', 'bar' ]], [ 'document' => [ 'foo' => 'bar' ]], ]; foreach ($tests as $value) { $bson = MongoDB\BSON\fromPHP($value); echo MongoDB\BSON\toJSON($bson), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "null" : null } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "boolean" : true } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "string" : "foo" } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "integer" : 123 } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "double" : 1.0 } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "nan" : %r-?nan(\(ind\))?%r } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "pos_inf" : inf } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "neg_inf" : -inf } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "array" : [ "foo", "bar" ] } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "document" : { "foo" : "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toJSON-002.phpt0000644000175100001660000000500514760300421015510 0ustar --TEST-- MongoDB\BSON\toJSON(): Encoding extended JSON types --FILE-- new MongoDB\BSON\ObjectId('56315a7c6118fd1b920270b1') ], [ 'binary' => new MongoDB\BSON\Binary('foo', MongoDB\BSON\Binary::TYPE_GENERIC) ], [ 'date' => new MongoDB\BSON\UTCDateTime(new MongoDB\BSON\Int64('1445990400000')) ], [ 'timestamp' => new MongoDB\BSON\Timestamp(1234, 5678) ], [ 'regex' => new MongoDB\BSON\Regex('pattern', 'i') ], [ 'code' => new MongoDB\BSON\Javascript('function() { return 1; }') ], [ 'code_ws' => new MongoDB\BSON\Javascript('function() { return a; }', ['a' => 1]) ], [ 'minkey' => new MongoDB\BSON\MinKey ], [ 'maxkey' => new MongoDB\BSON\MaxKey ], ]; foreach ($tests as $value) { $bson = MongoDB\BSON\fromPHP($value); echo MongoDB\BSON\toJSON($bson), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "_id" : { "$oid" : "56315a7c6118fd1b920270b1" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "binary" : { "$binary" : "Zm9v", "$type" : "00" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "date" : { "$date" : 1445990400000 } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "timestamp" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "regex" : { "$regex" : "pattern", "$options" : "i" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "code" : { "$code" : "function() { return 1; }" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "code_ws" : { "$code" : "function() { return a; }", "$scope" : { "a" : 1 } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "minkey" : { "$minKey" : 1 } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "maxkey" : { "$maxKey" : 1 } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toJSON-003.phpt0000644000175100001660000000107714760300421015516 0ustar --TEST-- MongoDB\BSON\toJSON(): Encoding JSON with duplicate field names --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s { "foo" : "bar", "foo" : "baz" } ===DONE=== mongodb-1.21.0/tests/bson/bson-toJSON_error-001.phpt0000644000175100001660000000172114760300421016721 0ustar --TEST-- MongoDB\BSON\toJSON(): BSON decoding exceptions --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Reading document did not exhaust input buffer ===DONE=== mongodb-1.21.0/tests/bson/bson-toJSON_error-002.phpt0000644000175100001660000000152414760300421016723 0ustar --TEST-- MongoDB\BSON\toJSON(): BSON decoding exceptions for malformed documents --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader ===DONE=== mongodb-1.21.0/tests/bson/bson-toJSON_error-003.phpt0000644000175100001660000000316514760300421016727 0ustar --TEST-- MongoDB\BSON\toJSON(): BSON decoding exceptions for bson_as_json() failure --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-001.phpt0000644000175100001660000000557314760300421015377 0ustar --TEST-- MongoDB\BSON\toPHP(): __pclass must be both instantiatable and Persistable --FILE-- unserialized = true; } } // Create base64-encoded class names for __pclass field's binary data $bMyAbstractDocument = base64_encode('MyAbstractDocument'); $bMyDocument = base64_encode('MyDocument'); $bUnserializable = base64_encode('MongoDB\BSON\Unserializable'); $bPersistable = base64_encode('MongoDB\BSON\Persistable'); $tests = array( '{ "foo": "yes", "__pclass": { "$binary": "' . $bMyAbstractDocument . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bMyDocument . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bUnserializable . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bPersistable . '", "$type": "44" } }', ); foreach ($tests as $test) { echo $test, "\n"; var_dump(MongoDB\BSON\toPHP(MongoDB\BSON\fromJSON($test))); echo "\n"; } ?> ===DONE=== --EXPECTF-- { "foo": "yes", "__pclass": { "$binary": "TXlBYnN0cmFjdERvY3VtZW50", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(18) "MyAbstractDocument" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "TXlEb2N1bWVudA==", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "TW9uZ29EQlxCU09OXFVuc2VyaWFsaXphYmxl", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(27) "MongoDB\BSON\Unserializable" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "TW9uZ29EQlxCU09OXFBlcnNpc3RhYmxl", "$type": "44" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(24) "MongoDB\BSON\Persistable" ["type"]=> int(68) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-002.phpt0000644000175100001660000000401014760300421015361 0ustar --TEST-- MongoDB\BSON\fromPHP(): Null type map values imply default behavior --FILE-- data = array( 'list' => array(1, 2, 3), 'map' => (object) array('foo' => 'bar'), ); } #[\ReturnTypeWillChange] public function bsonSerialize() { return $this->data; } public function bsonUnserialize(array $data): void { foreach (array('list', 'map') as $key) { if (isset($data[$key])) { $this->data[$key] = $data[$key]; } } } } $bson = MongoDB\BSON\fromPHP(new MyDocument); echo "Test " . MongoDB\BSON\toJSON($bson) . "\n"; hex_dump($bson); $typeMap = array( 'array' => null, 'document' => null, 'root' => null, ); var_dump(MongoDB\BSON\toPHP($bson, $typeMap)); ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "__pclass" : { "$binary" : "TXlEb2N1bWVudA==", "$type" : "80" }, "list" : [ 1, 2, 3 ], "map" : { "foo" : "bar" } } 0 : 55 00 00 00 05 5f 5f 70 63 6c 61 73 73 00 0a 00 [U....__pclass...] 10 : 00 00 80 4d 79 44 6f 63 75 6d 65 6e 74 04 6c 69 [...MyDocument.li] 20 : 73 74 00 1a 00 00 00 10 30 00 01 00 00 00 10 31 [st......0......1] 30 : 00 02 00 00 00 10 32 00 03 00 00 00 00 03 6d 61 [......2.......ma] 40 : 70 00 12 00 00 00 02 66 6f 6f 00 04 00 00 00 62 [p......foo.....b] 50 : 61 72 00 00 00 [ar...] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(MyDocument)#%d (1) { ["data"]=> array(2) { ["list"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["map"]=> object(stdClass)#%d (1) { ["foo"]=> string(3) "bar" } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-003.phpt0000644000175100001660000003322414760300421015373 0ustar --TEST-- MongoDB\BSON\toPHP(): Tests from serialization specification --FILE-- $value) { $this->$key = $value; } $this->unserialized = true; } } #[\AllowDynamicProperties] class OurClass implements MongoDB\BSON\Persistable { #[\ReturnTypeWillChange] public function bsonSerialize() { // Not tested with this test, so return empty array return array(); } public function bsonUnserialize(array $data): void { foreach ($data as $key => $value) { $this->$key = $value; } $this->unserialized = true; } } class TheirClass extends OurClass { } // Create base64-encoded class names for __pclass field's binary data $bMyClass = base64_encode('MyClass'); $bYourClass = base64_encode('YourClass'); $bOurClass = base64_encode('OurClass'); $bTheirClass = base64_encode('TheirClass'); $bInterface = base64_encode('MongoDB\BSON\Unserializable'); $testGroups = array( array( 'name' => 'DEFAULT TYPEMAP', 'typemap' => array(), 'tests' => array( '{ "foo": "yes", "bar" : false }', '{ "foo": "no", "array" : [ 5, 6 ] }', '{ "foo": "no", "obj" : { "embedded" : 4.125 } }', '{ "foo": "yes", "__pclass": "MyClass" }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bMyClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bYourClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bOurClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass": { "$binary": "' . $bYourClass . '", "$type": "44" } }', ), ), array( 'name' => 'NONEXISTING CLASS', 'typemap' => array('root' => 'MissingClass'), 'tests' => array( '{ "foo": "yes" }', ), ), array( 'name' => 'DOES NOT IMPLEMENT UNSERIALIZABLE', 'typemap' => array('root' => 'MyClass'), 'tests' => array( '{ "foo": "yes", "__pclass": { "$binary": "' . $bMyClass . '", "$type": "80" } }', ), ), array( 'name' => 'IS NOT A CONCRETE CLASS', 'typemap' => array('root' => 'MongoDB\BSON\Unserializable'), 'tests' => array( '{ "foo": "yes" }', ), ), array( 'name' => 'IS NOT A CONCRETE CLASS VIA PCLASS', 'typemap' => array('root' => 'YourClass'), 'tests' => array( '{ "foo": "yes", "__pclass" : { "$binary": "' . $bInterface . '", "$type": "80" } }', ), ), array( 'name' => 'PCLASS OVERRIDES TYPEMAP (1)', 'typemap' => array('root' => 'YourClass'), 'tests' => array( '{ "foo": "yes", "__pclass" : { "$binary": "' . $bMyClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bOurClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bTheirClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bYourClass . '", "$type": "80" } }', ), ), array( 'name' => 'PCLASS OVERRIDES TYPEMAP (2)', 'typemap' => array('root' => 'OurClass'), 'tests' => array( '{ "foo": "yes", "__pclass" : { "$binary": "' . $bTheirClass . '", "$type": "80" } }', ), ), array( 'name' => 'OBJECTS AS ARRAY', 'typemap' => array('root' => 'array', 'document' => 'array'), 'tests' => array( '{ "foo": "yes", "bar" : false }', '{ "foo": "no", "array" : [ 5, 6 ] }', '{ "foo": "no", "obj" : { "embedded" : 4.125 } }', '{ "foo": "yes", "__pclass": "MyClass" }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bMyClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bOurClass . '", "$type": "80" } }', ), ), array( 'name' => 'OBJECTS AS STDCLASS', 'typemap' => array('root' => 'object', 'document' => 'object'), 'tests' => array( '{ "foo": "yes", "__pclass" : { "$binary": "' . $bMyClass . '", "$type": "80" } }', '{ "foo": "yes", "__pclass" : { "$binary": "' . $bOurClass . '", "$type": "80" } }', ), ), ); foreach ($testGroups as $testGroup) { printf("=== %s ===\n\n", $testGroup['name']); foreach ($testGroup['tests'] as $test) { echo $test, "\n"; $bson = MongoDB\BSON\fromJSON($test); try { var_dump(MongoDB\BSON\toPHP($bson, $testGroup['typemap'])); } catch (MongoDB\Driver\Exception\Exception $e) { echo $e->getMessage(), "\n"; } echo "\n"; } echo "\n"; } ?> ===DONE=== --EXPECTF-- === DEFAULT TYPEMAP === { "foo": "yes", "bar" : false } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["bar"]=> bool(false) } { "foo": "no", "array" : [ 5, 6 ] } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(2) "no" ["array"]=> array(2) { [0]=> int(5) [1]=> int(6) } } { "foo": "no", "obj" : { "embedded" : 4.125 } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(2) "no" ["obj"]=> object(stdClass)#%d (1) { ["embedded"]=> float(4.125) } } { "foo": "yes", "__pclass": "MyClass" } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> string(7) "MyClass" } { "foo": "yes", "__pclass": { "$binary": "TXlDbGFzcw==", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "WW91ckNsYXNz", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(9) "YourClass" ["type"]=> int(128) } } { "foo": "yes", "__pclass": { "$binary": "T3VyQ2xhc3M=", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(OurClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "OurClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } { "foo": "yes", "__pclass": { "$binary": "WW91ckNsYXNz", "$type": "44" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(9) "YourClass" ["type"]=> int(68) } } === NONEXISTING CLASS === { "foo": "yes" } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Class MissingClass does not exist === DOES NOT IMPLEMENT UNSERIALIZABLE === { "foo": "yes", "__pclass": { "$binary": "TXlDbGFzcw==", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Class MyClass does not implement MongoDB\BSON\Unserializable === IS NOT A CONCRETE CLASS === { "foo": "yes" } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Interface MongoDB\BSON\Unserializable is not instantiatable === IS NOT A CONCRETE CLASS VIA PCLASS === { "foo": "yes", "__pclass" : { "$binary": "TW9uZ29EQlxCU09OXFVuc2VyaWFsaXphYmxl", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(YourClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(27) "MongoDB\BSON\Unserializable" ["type"]=> int(128) } ["unserialized"]=> bool(true) } === PCLASS OVERRIDES TYPEMAP (1) === { "foo": "yes", "__pclass" : { "$binary": "TXlDbGFzcw==", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(YourClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } { "foo": "yes", "__pclass" : { "$binary": "T3VyQ2xhc3M=", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(OurClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "OurClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } { "foo": "yes", "__pclass" : { "$binary": "VGhlaXJDbGFzcw==", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(TheirClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(10) "TheirClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } { "foo": "yes", "__pclass" : { "$binary": "WW91ckNsYXNz", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(YourClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(9) "YourClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } === PCLASS OVERRIDES TYPEMAP (2) === { "foo": "yes", "__pclass" : { "$binary": "VGhlaXJDbGFzcw==", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(TheirClass)#%d (3) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(10) "TheirClass" ["type"]=> int(128) } ["unserialized"]=> bool(true) } === OBJECTS AS ARRAY === { "foo": "yes", "bar" : false } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s array(2) { ["foo"]=> string(3) "yes" ["bar"]=> bool(false) } { "foo": "no", "array" : [ 5, 6 ] } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s array(2) { ["foo"]=> string(2) "no" ["array"]=> array(2) { [0]=> int(5) [1]=> int(6) } } { "foo": "no", "obj" : { "embedded" : 4.125 } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s array(2) { ["foo"]=> string(2) "no" ["obj"]=> array(1) { ["embedded"]=> float(4.125) } } { "foo": "yes", "__pclass": "MyClass" } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s array(2) { ["foo"]=> string(3) "yes" ["__pclass"]=> string(7) "MyClass" } { "foo": "yes", "__pclass" : { "$binary": "TXlDbGFzcw==", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s array(2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } } { "foo": "yes", "__pclass" : { "$binary": "T3VyQ2xhc3M=", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s array(2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "OurClass" ["type"]=> int(128) } } === OBJECTS AS STDCLASS === { "foo": "yes", "__pclass" : { "$binary": "TXlDbGFzcw==", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(7) "MyClass" ["type"]=> int(128) } } { "foo": "yes", "__pclass" : { "$binary": "T3VyQ2xhc3M=", "$type": "80" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(8) "OurClass" ["type"]=> int(128) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-004.phpt0000644000175100001660000003432414760300421015376 0ustar --TEST-- MongoDB\BSON\toPHP(): BSON array keys should be disregarded during visitation --FILE-- [$value]]); // Alter the key of the BSON array's first element $bson[12] = '1'; var_dump(MongoDB\BSON\toPHP($bson)); /* Note that numeric indexes within the HashTable are not accessible without * casting the object to an array. This is because the entries are only * stored with numeric indexes and do not also have string equivalents, as * might be created with zend_symtable_update(). This behavior is not unique * to the driver, as `(object) ['foo']` would demonstrate the same issue. */ var_dump(MongoDB\BSON\toPHP($bson, ['array' => 'object'])); var_dump(MongoDB\BSON\toPHP($bson, ['array' => 'MyArrayObject'])); echo "\n"; } ?> ===DONE=== --EXPECTF-- Testing NULL visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> NULL } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> NULL } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> NULL } } } Testing boolean visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> bool(true) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> bool(true) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> bool(true) } } } Testing integer visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> int(1) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> int(1) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> int(1) } } } Testing double visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> float(4.125) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> float(4.125) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> float(4.125) } } } Testing string visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> string(3) "foo" } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> string(3) "foo" } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> string(3) "foo" } } } Testing array visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> array(0) { } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(stdClass)#%d (0) { } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(0) { } } } } } Testing stdClass visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(stdClass)#%d (0) { } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(stdClass)#%d (0) { } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(stdClass)#%d (0) { } } } } Testing MongoDB\BSON\Binary visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(3) "foo" ["type"]=> int(0) } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(3) "foo" ["type"]=> int(0) } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\Binary)#%d (2) { ["data"]=> string(3) "foo" ["type"]=> int(0) } } } } Testing MongoDB\BSON\Decimal128 visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\Decimal128)#%d (1) { ["dec"]=> string(4) "3.14" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\Decimal128)#%d (1) { ["dec"]=> string(4) "3.14" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\Decimal128)#%d (1) { ["dec"]=> string(4) "3.14" } } } } Testing MongoDB\BSON\Javascript visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\Javascript)#%d (2) { ["code"]=> string(12) "function(){}" ["scope"]=> NULL } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\Javascript)#%d (2) { ["code"]=> string(12) "function(){}" ["scope"]=> NULL } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\Javascript)#%d (2) { ["code"]=> string(12) "function(){}" ["scope"]=> NULL } } } } Testing MongoDB\BSON\MaxKey visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\MaxKey)#%d (0) { } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\MaxKey)#%d (0) { } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\MaxKey)#%d (0) { } } } } Testing MongoDB\BSON\MinKey visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\MinKey)#%d (0) { } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\MinKey)#%d (0) { } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\MinKey)#%d (0) { } } } } Testing MongoDB\BSON\ObjectId visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\ObjectId)#%d (1) { ["oid"]=> string(24) "586c18d86118fd6c9012dec1" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\ObjectId)#%d (1) { ["oid"]=> string(24) "586c18d86118fd6c9012dec1" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\ObjectId)#%d (1) { ["oid"]=> string(24) "586c18d86118fd6c9012dec1" } } } } Testing MongoDB\BSON\Regex visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\Regex)#%d (2) { ["pattern"]=> string(3) "foo" ["flags"]=> string(0) "" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\Regex)#%d (2) { ["pattern"]=> string(3) "foo" ["flags"]=> string(0) "" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\Regex)#%d (2) { ["pattern"]=> string(3) "foo" ["flags"]=> string(0) "" } } } } Testing MongoDB\BSON\Timestamp visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\Timestamp)#%d (2) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\Timestamp)#%d (2) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\Timestamp)#%d (2) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } } } } Testing MongoDB\BSON\UTCDateTime visitor function Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> array(1) { [0]=> object(MongoDB\BSON\UTCDateTime)#%d (1) { ["milliseconds"]=> string(13) "1483479256924" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(stdClass)#%d (1) { ["0"]=> object(MongoDB\BSON\UTCDateTime)#%d (1) { ["milliseconds"]=> string(13) "1483479256924" } } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (1) { ["x"]=> object(MyArrayObject)#%d (1) { ["storage":"ArrayObject":private]=> array(1) { [0]=> object(MongoDB\BSON\UTCDateTime)#%d (1) { ["milliseconds"]=> string(13) "1483479256924" } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-006.phpt0000644000175100001660000000343314760300421015375 0ustar --TEST-- MongoDB\BSON\toPHP(): Decodes Binary UUID types with any data length --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(15) "0123456789abcde" ["type"]=> int(3) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(17) "0123456789abcdefg" ["type"]=> int(3) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(15) "0123456789abcde" ["type"]=> int(4) } } Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(17) "0123456789abcdefg" ["type"]=> int(4) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-008.phpt0000644000175100001660000000347314760300421015403 0ustar --TEST-- MongoDB\BSON\toPHP(): Setting fieldPath typemaps for compound types with string keys --FILE-- 1, 'array' => [1, 2, 3], 'object' => ['string' => 'keys', 'for' => 'ever'] ] ); function fetch($bson, $typeMap = []) { return \MongoDB\BSON\toPHP($bson, $typeMap); } echo "Default\n"; $document = fetch($bson); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->object instanceof stdClass); echo "\nSetting 'object' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object' => "MyArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->object instanceof MyArrayObject); echo "\nSetting 'object' and 'array' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object' => "MyArrayObject", 'array' => "MyArrayObject", ]]); var_dump($document instanceof stdClass); var_dump($document->array instanceof MyArrayObject); var_dump($document->object instanceof MyArrayObject); ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Default Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) Setting 'object' path to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) Setting 'object' and 'array' path to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-009.phpt0000644000175100001660000000467514760300421015411 0ustar --TEST-- MongoDB\BSON\toPHP(): Setting fieldPath typemaps for compound types with numerical keys --FILE-- 1, 'array0' => [0 => [ 4, 5, 6 ], 1 => [ 7, 8, 9 ]], 'array1' => [1 => [ 4, 5, 6 ], 2 => [ 7, 8, 9 ]], ] ); function fetch($bson, $typeMap = []) { return \MongoDB\BSON\toPHP($bson, $typeMap); } echo "Default\n"; $document = fetch($bson); var_dump($document instanceof stdClass); var_dump(is_array($document->array0)); var_dump(is_object($document->array1)); var_dump($document->array1 instanceof stdClass); echo "\nSetting 'array0' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array0' => "MyArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->array0)); var_dump($document->array0 instanceof MyArrayObject); echo "\nSetting 'array0.1' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array0.1' => "MyArrayObject", ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array0)); var_dump(is_array($document->array0[0])); var_dump($document->array0[1] instanceof MyArrayObject); echo "\nSetting 'array1.1' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array1.1' => "MyArrayObject", ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->array1)); var_dump($document->array1 instanceof stdClass); $a = ((array) $document->array1); var_dump($a[1] instanceof MyArrayObject); var_dump(is_array($a[2])); ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Default Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) Setting 'array0' path to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) Setting 'array0.1' path to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) Setting 'array1.1' path to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-010.phpt0000644000175100001660000001065314760300421015372 0ustar --TEST-- MongoDB\BSON\toPHP(): Setting fieldPath typemaps for compound types with wildcard keys --FILE-- 1, 'array' => [0 => [ 4, 5, 6 ], 1 => [ 7, 8, 9 ]], 'object' => ['one' => [ 4, 5, 6 ], 'two' => [ 7, 8, 9 ]], ] ); function fetch($bson, $typeMap = []) { return \MongoDB\BSON\toPHP($bson, $typeMap); } echo "\nSetting 'array.$' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array.$' => "MyWildcardArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->array[0] instanceof MyWildcardArrayObject); var_dump($document->array[1] instanceof MyWildcardArrayObject); echo "\nSetting 'array.1' to 'MyArrayObject' and 'array.$' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array.1' => "MyArrayObject", 'array.$' => "MyWildcardArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->array[0] instanceof MyWildcardArrayObject); var_dump($document->array[1] instanceof MyArrayObject); echo "\nSetting 'array.$' to 'MyWildcardArrayObject' and 'array.1' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'array.$' => "MyWildcardArrayObject", 'array.1' => "MyArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_array($document->array)); var_dump($document->array[0] instanceof MyWildcardArrayObject); var_dump($document->array[1] instanceof MyWildcardArrayObject); echo "\nSetting 'object.$' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.$' => "MyWildcardArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->object)); var_dump($document->object->one instanceof MyWildcardArrayObject); var_dump($document->object->two instanceof MyWildcardArrayObject); echo "\nSetting 'object.two' to 'MyArrayObject' and 'object.$' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.two' => "MyArrayObject", 'object.$' => "MyWildcardArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->object)); var_dump($document->object->one instanceof MyWildcardArrayObject); var_dump($document->object->two instanceof MyArrayObject); echo "\nSetting 'object.$' to 'MyWildcardArrayObject' and 'object.one' path to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.$' => "MyWildcardArrayObject", 'object.one' => "MyArrayObject" ]]); var_dump($document instanceof stdClass); var_dump(is_object($document->object)); var_dump($document->object->one instanceof MyWildcardArrayObject); var_dump($document->object->two instanceof MyWildcardArrayObject); ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Setting 'array.$' path to 'MyWildcardArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) Setting 'array.1' to 'MyArrayObject' and 'array.$' path to 'MyWildcardArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) Setting 'array.$' to 'MyWildcardArrayObject' and 'array.1' path to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) Setting 'object.$' path to 'MyWildcardArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) Setting 'object.two' to 'MyArrayObject' and 'object.$' path to 'MyWildcardArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) Setting 'object.$' to 'MyWildcardArrayObject' and 'object.one' path to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-011.phpt0000644000175100001660000001227414760300421015374 0ustar --TEST-- MongoDB\BSON\toPHP(): Setting fieldPath typemaps for compound types with wildcard keys (nested) --FILE-- 1, 'object' => [ 'parent1' => [ 'child1' => [ 1, 2, 3 ], 'child2' => [ 4, 5, 6 ], ], 'parent2' => [ 'child1' => [ 7, 8, 9 ], 'child2' => [ 10, 11, 12 ], ], ], ] ); function fetch($bson, $typeMap = []) { return \MongoDB\BSON\toPHP($bson, $typeMap); } echo "\nSetting 'object.$.child1' path to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.$.child1' => "MyWildcardArrayObject" ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump(is_array($document->object->parent1->child2)); var_dump($document->object->parent2 instanceof stdClass); var_dump($document->object->parent2->child1 instanceof MyWildcardArrayObject); var_dump(is_array($document->object->parent2->child2)); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.parent2.child1' to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.parent1.$' => "MyWildcardArrayObject", 'object.parent2.child1' => "MyArrayObject", ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent1->child2 instanceof MyWildcardArrayObject); var_dump($document->object->parent2 instanceof stdClass); var_dump($document->object->parent2->child1 instanceof MyArrayObject); var_dump(is_array($document->object->parent2->child2)); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.$' to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.parent1.$' => "MyWildcardArrayObject", 'object.$.$' => "MyArrayObject", ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent1->child2 instanceof MyWildcardArrayObject); var_dump($document->object->parent2 instanceof stdClass); var_dump($document->object->parent2->child1 instanceof MyArrayObject); var_dump($document->object->parent2->child2 instanceof MyArrayObject); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.child2' to 'MyArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.parent1.child1' => "MyWildcardArrayObject", 'object.$.child2' => "MyArrayObject", ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent1->child2 instanceof MyArrayObject); var_dump($document->object->parent2 instanceof stdClass); var_dump(is_array($document->object->parent2->child1)); var_dump($document->object->parent2->child2 instanceof MyArrayObject); echo "\nSetting 'object.parent1.child2 path to 'MyArrayObject' and 'object.$.$' to 'MyWildcardArrayObject'\n"; $document = fetch($bson, ["fieldPaths" => [ 'object.parent1.child2' => "MyArrayObject", 'object.$.$' => "MyWildcardArrayObject", ]]); var_dump($document->object->parent1 instanceof stdClass); var_dump($document->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent1->child2 instanceof MyArrayObject); var_dump($document->object->parent2 instanceof stdClass); var_dump($document->object->parent2->child1 instanceof MyWildcardArrayObject); var_dump($document->object->parent2->child2 instanceof MyWildcardArrayObject); ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Setting 'object.$.child1' path to 'MyWildcardArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.parent2.child1' to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.$' to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.child2' to 'MyArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.child2 path to 'MyArrayObject' and 'object.$.$' to 'MyWildcardArrayObject' Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-012.phpt0000644000175100001660000000107014760300421015365 0ustar --TEST-- MongoDB\BSON\toPHP(): Decoding BSON with duplicate field names --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["foo"]=> string(3) "baz" } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-013.phpt0000644000175100001660000000471614760300421015400 0ustar --TEST-- Uninstantiatable classes are ignored when processing __pclass --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(12) "MissingClass" ["type"]=> int(128) } ["y"]=> int(1) } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(18) "MyAbstractDocument" ["type"]=> int(128) } ["y"]=> int(1) } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } ["y"]=> int(1) } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(7) "MyTrait" ["type"]=> int(128) } ["y"]=> int(1) } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(24) "MongoDB\BSON\Persistable" ["type"]=> int(128) } ["y"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-014.phpt0000644000175100001660000000311214760300421015366 0ustar --TEST-- Uninstantiatable classes are ignored when processing __pclass (enums) --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(6) "MyEnum" ["type"]=> int(128) } ["name"]=> string(1) "A" } } Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(12) "MyBackedEnum" ["type"]=> int(128) } ["name"]=> string(1) "A" ["value"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-015.phpt0000644000175100001660000002101114760300421015365 0ustar --TEST-- MongoDB\BSON\toPHP(): Type map values can override Persistable behavior --DESCRIPTION-- The special type map values below always override Persistable behavior. Note that an Unserializable class name will only override Persistable behavior if the class specified in __pclass does not exist or does not implement MongoDB\BSON\Persistable. --FILE-- data = array( 'list' => array(1, 2, 3), 'map' => (object) array('foo' => 'bar'), ); } #[\ReturnTypeWillChange] public function bsonSerialize() { return $this->data; } public function bsonUnserialize(array $data): void { foreach (array('list', 'map') as $key) { if (isset($data[$key])) { $this->data[$key] = $data[$key]; } } } } $tests = [ 'root document as object' => [ new MyDocument, ['root' => 'object'], ], 'root document as array' => [ new MyDocument, ['root' => 'array'], ], 'root document as bson' => [ new MyDocument, ['root' => 'bson'], ], 'embedded document as object' => [ ['embedded' => new MyDocument], ['document' => 'object'], ], 'embedded document as array' => [ ['embedded' => new MyDocument], ['document' => 'array'], ], 'embedded document as bson' => [ ['embedded' => new MyDocument], ['document' => 'bson'], ], 'fieldPath document as object' => [ ['embedded' => new MyDocument], ['fieldPaths' => ['embedded' => 'object']], ], 'fieldPath document as array' => [ ['embedded' => new MyDocument], ['fieldPaths' => ['embedded' => 'array']], ], 'fieldPath document as bson' => [ ['embedded' => new MyDocument], ['fieldPaths' => ['embedded' => 'bson']], ], ]; foreach ($tests as $test => [$document, $typeMap]) { echo "Test ", $test, "\n"; $bson = MongoDB\BSON\fromPHP($document); var_dump(MongoDB\BSON\toPHP($bson, $typeMap)); } ?> ===DONE=== --EXPECTF-- Test root document as object Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } ["list"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["map"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } Test root document as array Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s array(3) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } ["list"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["map"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } Test root document as bson Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(116) "VQAAAAVfX3BjbGFzcwAKAAAAgE15RG9jdW1lbnQEbGlzdAAaAAAAEDAAAQAAABAxAAIAAAAQMgADAAAAAANtYXAAEgAAAAJmb28ABAAAAGJhcgAAAA==" ["value"]=> object(MyDocument)#%d (%d) { ["data"]=> array(2) { ["list"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "GgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAA=" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ["map"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } } Test embedded document as object Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["embedded"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } ["list"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["map"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } Test embedded document as array Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["embedded"]=> array(3) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } ["list"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["map"]=> array(1) { ["foo"]=> string(3) "bar" } } } Test embedded document as bson Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["embedded"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(116) "VQAAAAVfX3BjbGFzcwAKAAAAgE15RG9jdW1lbnQEbGlzdAAaAAAAEDAAAQAAABAxAAIAAAAQMgADAAAAAANtYXAAEgAAAAJmb28ABAAAAGJhcgAAAA==" ["value"]=> object(MyDocument)#%d (%d) { ["data"]=> array(2) { ["list"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "GgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAA=" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ["map"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } } } Test fieldPath document as object Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["embedded"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } ["list"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["map"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } Test fieldPath document as array Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["embedded"]=> array(3) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } ["list"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["map"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } Test fieldPath document as bson Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["embedded"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(116) "VQAAAAVfX3BjbGFzcwAKAAAAgE15RG9jdW1lbnQEbGlzdAAaAAAAEDAAAQAAABAxAAIAAAAQMgADAAAAAANtYXAAEgAAAAJmb28ABAAAAGJhcgAAAA==" ["value"]=> object(MyDocument)#%d (%d) { ["data"]=> array(2) { ["list"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "GgAAABAwAAEAAAAQMQACAAAAEDIAAwAAAAA=" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ["map"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(24) "EgAAAAJmb28ABAAAAGJhcgAA" ["value"]=> object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } } } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-016.phpt0000644000175100001660000002106314760300421015375 0ustar --TEST-- MongoDB\BSON\toPHP(): Decoding with raw BSON type --FILE-- 1, 'object' => [ 'parent1' => [ 'child1' => [ 1, 2, 3 ], 'child2' => [ 4, 5, 6 ], ], 'parent2' => [ 'child1' => [ 7, 8, 9 ], 'child2' => [ 10, 11, 12 ], ], ], ]); $tests = [ 'Root as BSON' => ['root' => 'bson'], 'Arrays as BSON' => ['array' => 'bson'], 'Documents as BSON' => ['document' => 'bson'], 'Field path as BSON' => ['fieldPaths' => ['object.parent1.child1' => 'bson', 'object.parent2' => 'bson']], 'Non-complex field ignores BSON typemap element' => ['fieldPaths' => ['_id' => 'bson']], ]; foreach ($tests as $name => $typeMap) { echo "\n" . $name . "\n"; var_dump(MongoDB\BSON\toPHP($bson, $typeMap)); } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Root as BSON Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(256) "%a" ["value"]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["object"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(228) "%a" ["value"]=> object(stdClass)#%d (%d) { ["parent1"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(100) "%a" ["value"]=> object(stdClass)#%d (%d) { ["child1"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ["child2"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(4) [1]=> int(5) [2]=> int(6) } } } } ["parent2"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(100) "%a" ["value"]=> object(stdClass)#%d (%d) { ["child1"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(7) [1]=> int(8) [2]=> int(9) } } ["child2"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(10) [1]=> int(11) [2]=> int(12) } } } } } } } } Arrays as BSON Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["_id"]=> int(1) ["object"]=> object(stdClass)#%d (%d) { ["parent1"]=> object(stdClass)#%d (%d) { ["child1"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ["child2"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(4) [1]=> int(5) [2]=> int(6) } } } ["parent2"]=> object(stdClass)#%d (%d) { ["child1"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(7) [1]=> int(8) [2]=> int(9) } } ["child2"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(10) [1]=> int(11) [2]=> int(12) } } } } } Documents as BSON Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["_id"]=> int(1) ["object"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(228) "%a" ["value"]=> object(stdClass)#%d (%d) { ["parent1"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(100) "%a" ["value"]=> object(stdClass)#%d (%d) { ["child1"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ["child2"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(4) [1]=> int(5) [2]=> int(6) } } } } ["parent2"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(100) "%a" ["value"]=> object(stdClass)#%d (%d) { ["child1"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(7) [1]=> int(8) [2]=> int(9) } } ["child2"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(10) [1]=> int(11) [2]=> int(12) } } } } } } } Field path as BSON Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["_id"]=> int(1) ["object"]=> object(stdClass)#%d (%d) { ["parent1"]=> object(stdClass)#%d (%d) { ["child1"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } ["child2"]=> array(3) { [0]=> int(4) [1]=> int(5) [2]=> int(6) } } ["parent2"]=> object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(100) "%a" ["value"]=> object(stdClass)#%d (%d) { ["child1"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(7) [1]=> int(8) [2]=> int(9) } } ["child2"]=> object(MongoDB\BSON\PackedArray)#%d (%d) { ["data"]=> string(36) "%a" ["value"]=> array(3) { [0]=> int(10) [1]=> int(11) [2]=> int(12) } } } } } } Non-complex field ignores BSON typemap element Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["_id"]=> int(1) ["object"]=> object(stdClass)#%d (%d) { ["parent1"]=> object(stdClass)#%d (%d) { ["child1"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["child2"]=> array(3) { [0]=> int(4) [1]=> int(5) [2]=> int(6) } } ["parent2"]=> object(stdClass)#%d (%d) { ["child1"]=> array(3) { [0]=> int(7) [1]=> int(8) [2]=> int(9) } ["child2"]=> array(3) { [0]=> int(10) [1]=> int(11) [2]=> int(12) } } } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP-017.phpt0000644000175100001660000000102714760300421015374 0ustar --TEST-- MongoDB\BSON\toPHP(): int64 values are returned as int scalars --FILE-- 123, // Using a 32-bit value to simplify testing 'int64' => new MongoDB\BSON\Int64(123), ]); var_dump(MongoDB\BSON\toPHP($bson)); ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["int32"]=> int(123) ["int64"]=> int(123) } ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP_error-001.phpt0000644000175100001660000001472514760300421016607 0ustar --TEST-- MongoDB\BSON\toPHP(): Type map classes must be instantiatable and implement Unserializable --FILE-- $class], ['document' => $class], ['root' => $class], ['fieldPaths' => ['x' => $class]], ]; foreach ($typeMaps as $typeMap) { printf("Test typeMap: %s\n", json_encode($typeMap)); echo throws(function() use ($typeMap) { MongoDB\BSON\toPHP(MongoDB\BSON\fromJSON('{}'), $typeMap); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n\n"; } } ?> ===DONE=== --EXPECTF-- Test typeMap: {"array":"MissingClass"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist Test typeMap: {"document":"MissingClass"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist Test typeMap: {"root":"MissingClass"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist Test typeMap: {"fieldPaths":{"x":"MissingClass"}} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist Test typeMap: {"array":"MyAbstractDocument"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyAbstractDocument is not instantiatable Test typeMap: {"document":"MyAbstractDocument"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyAbstractDocument is not instantiatable Test typeMap: {"root":"MyAbstractDocument"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyAbstractDocument is not instantiatable Test typeMap: {"fieldPaths":{"x":"MyAbstractDocument"}} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyAbstractDocument is not instantiatable Test typeMap: {"array":"MyDocument"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyDocument does not implement MongoDB\BSON\Unserializable Test typeMap: {"document":"MyDocument"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyDocument does not implement MongoDB\BSON\Unserializable Test typeMap: {"root":"MyDocument"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyDocument does not implement MongoDB\BSON\Unserializable Test typeMap: {"fieldPaths":{"x":"MyDocument"}} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyDocument does not implement MongoDB\BSON\Unserializable Test typeMap: {"array":"MyTrait"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Trait MyTrait is not instantiatable Test typeMap: {"document":"MyTrait"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Trait MyTrait is not instantiatable Test typeMap: {"root":"MyTrait"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Trait MyTrait is not instantiatable Test typeMap: {"fieldPaths":{"x":"MyTrait"}} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Trait MyTrait is not instantiatable Test typeMap: {"array":"MongoDB\\BSON\\Unserializable"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Interface MongoDB\BSON\Unserializable is not instantiatable Test typeMap: {"document":"MongoDB\\BSON\\Unserializable"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Interface MongoDB\BSON\Unserializable is not instantiatable Test typeMap: {"root":"MongoDB\\BSON\\Unserializable"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Interface MongoDB\BSON\Unserializable is not instantiatable Test typeMap: {"fieldPaths":{"x":"MongoDB\\BSON\\Unserializable"}} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Interface MongoDB\BSON\Unserializable is not instantiatable ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP_error-002.phpt0000644000175100001660000000160214760300421016576 0ustar --TEST-- MongoDB\BSON\toPHP(): BSON decoding exceptions --FILE-- getMessage(), "\n"; } } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Could not read document from BSON reader Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s Reading document did not exhaust input buffer ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP_error-003.phpt0000644000175100001660000000152514760300421016603 0ustar --TEST-- MongoDB\BSON\toPHP(): BSON decoding exceptions for malformed documents --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP_error-004.phpt0000644000175100001660000000507314760300421016606 0ustar --TEST-- MongoDB\BSON\toPHP(): BSON decoding exceptions for bson_iter_visit_all() failure --FILE-- 'bar'])), // Invalid UTF-8 character in embedded document's field name str_replace('INVALID!', "INVALID\xFE", MongoDB\BSON\fromPHP(['foo' => ['INVALID!' => 'bar']])), // Invalid UTF-8 character in string within array field str_replace('INVALID!', "INVALID\xFE", MongoDB\BSON\fromPHP(['foo' => ['INVALID!']])), /* Note: we don't use a three-character string in the underflow case, as * the 4-byte string length and payload (i.e. three characters + null byte) * coincidentally satisfy the expected size for an 8-byte double. We also * don't use a four-character string, since its null byte would be * interpreted as the document terminator. The actual document terminator * would then remain in the buffer and trigger a "did not exhaust" error. */ pack('VCa*xVa*xx', 17, 1, 'foo', 3, 'ab'), // Invalid field type (underflow) pack('VCa*xVa*xx', 20, 1, 'foo', 6, 'abcde'), // Invalid field type (overflow) ); foreach ($tests as $bson) { echo throws(function() use ($bson) { MongoDB\BSON\toPHP($bson); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path '' at offset 4 Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo' at offset 0 Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo' at offset 0 Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path '' at offset 9 Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected unknown BSON type 0x65 for field path "". Are you using the latest driver? ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP_error-005.phpt0000644000175100001660000000416714760300421016612 0ustar --TEST-- MongoDB\BSON\toPHP(): Field path values with bson_iter_visit_all() failures --FILE-- ['INVALID!' => 'bar'] ])), str_replace('INVALID!', "INVALID\xFE", MongoDB\BSON\fromPHP(['foo' => ['bar' => ['INVALID!' => 'bar']]])), str_replace('INVALID!', "INVALID\xFE", MongoDB\BSON\fromPHP(['foo' => ['bar' => ['INVALID!']]])), str_replace('INVALID!', "INVALID\xFE", MongoDB\BSON\fromPHP(['foo' => [['INVALID!']]])), str_replace('INVALID!', "INVALID\xFE", MongoDB\BSON\fromPHP(['foo' => [ ['bar' => ['INVALID!' => 'bar']], 6 ]])), ); foreach ($tests as $bson) { echo throws(function() use ($bson) { MongoDB\BSON\toPHP($bson); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo' at offset 0 Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo.bar' at offset 0 Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo.bar' at offset 0 Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo.0' at offset 0 Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected corrupt BSON data for field path 'foo.0.bar' at offset 0 ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP_error-006.phpt0000644000175100001660000000127114760300421016604 0ustar --TEST-- MongoDB\BSON\toPHP(): BSON decoding exception with unknown BSON type --FILE-- ["cruel" => "world"]]); $bson[15] = chr(0x42); echo throws(function() use ($bson) { MongoDB\BSON\toPHP($bson); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected unknown BSON type 0x42 for field path "hello.cruel". Are you using the latest driver? ===DONE=== mongodb-1.21.0/tests/bson/bson-toPHP_error-007.phpt0000644000175100001660000000563114760300421016611 0ustar --TEST-- MongoDB\BSON\toPHP(): Type map classes must be instantiatable and implement Unserializable (enums) --FILE-- $class], ['document' => $class], ['root' => $class], ['fieldPaths' => ['x' => $class]], ]; foreach ($typeMaps as $typeMap) { printf("Test typeMap: %s\n", json_encode($typeMap)); echo throws(function() use ($typeMap) { MongoDB\BSON\toPHP(MongoDB\BSON\fromJSON('{}'), $typeMap); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n\n"; } } ?> ===DONE=== --EXPECTF-- Test typeMap: {"array":"MyEnum"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Enum MyEnum is not instantiatable Test typeMap: {"document":"MyEnum"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Enum MyEnum is not instantiatable Test typeMap: {"root":"MyEnum"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Enum MyEnum is not instantiatable Test typeMap: {"fieldPaths":{"x":"MyEnum"}} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Enum MyEnum is not instantiatable Test typeMap: {"array":"MyBackedEnum"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Enum MyBackedEnum is not instantiatable Test typeMap: {"document":"MyBackedEnum"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Enum MyBackedEnum is not instantiatable Test typeMap: {"root":"MyBackedEnum"} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Enum MyBackedEnum is not instantiatable Test typeMap: {"fieldPaths":{"x":"MyBackedEnum"}} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Enum MyBackedEnum is not instantiatable ===DONE=== mongodb-1.21.0/tests/bson/bson-toRelaxedJSON-001.phpt0000644000175100001660000000471314760300421017021 0ustar --TEST-- MongoDB\BSON\toRelaxedExtendedJSON(): Encoding JSON --FILE-- null ], [ 'boolean' => true ], [ 'string' => 'foo' ], [ 'integer' => 123 ], [ 'double' => 1.0, ], [ 'nan' => NAN ], [ 'pos_inf' => INF ], [ 'neg_inf' => -INF ], [ 'array' => [ 'foo', 'bar' ]], [ 'document' => [ 'foo' => 'bar' ]], ]; foreach ($tests as $value) { $bson = MongoDB\BSON\fromPHP($value); echo MongoDB\BSON\toRelaxedExtendedJSON($bson), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "null" : null } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "boolean" : true } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "string" : "foo" } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "integer" : 123 } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "double" : 1.0 } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "nan" : { "$numberDouble" : "NaN" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "pos_inf" : { "$numberDouble" : "Infinity" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "neg_inf" : { "$numberDouble" : "-Infinity" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "array" : [ "foo", "bar" ] } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "document" : { "foo" : "bar" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toRelaxedJSON-002.phpt0000644000175100001660000000533714760300421017025 0ustar --TEST-- MongoDB\BSON\toRelaxedExtendedJSON(): Encoding extended JSON types --FILE-- new MongoDB\BSON\ObjectId('56315a7c6118fd1b920270b1') ], [ 'binary' => new MongoDB\BSON\Binary('foo', MongoDB\BSON\Binary::TYPE_GENERIC) ], [ 'date' => new MongoDB\BSON\UTCDateTime(new MongoDB\BSON\Int64('1445990400000')) ], [ 'timestamp' => new MongoDB\BSON\Timestamp(1234, 5678) ], [ 'regex' => new MongoDB\BSON\Regex('pattern', 'i') ], [ 'code' => new MongoDB\BSON\Javascript('function() { return 1; }') ], [ 'code_ws' => new MongoDB\BSON\Javascript('function() { return a; }', ['a' => 1]) ], [ 'minkey' => new MongoDB\BSON\MinKey ], [ 'maxkey' => new MongoDB\BSON\MaxKey ], ]; foreach ($tests as $value) { $bson = MongoDB\BSON\fromPHP($value); echo MongoDB\BSON\toRelaxedExtendedJSON($bson), "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "_id" : { "$oid" : "56315a7c6118fd1b920270b1" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "binary" : { "$binary" : { "base64" : "Zm9v", "subType" : "00" } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "date" : { "$date" : "2015-10-28T00:00:00Z" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "timestamp" : { "$timestamp" : { "t" : 5678, "i" : 1234 } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "regex" : { "$regularExpression" : { "pattern" : "pattern", "options" : "i" } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "code" : { "$code" : "function() { return 1; }" } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "code_ws" : { "$code" : "function() { return a; }", "$scope" : { "a" : 1 } } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "minkey" : { "$minKey" : 1 } } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s { "maxkey" : { "$maxKey" : 1 } } ===DONE=== mongodb-1.21.0/tests/bson/bson-toRelaxedJSON_error-001.phpt0000644000175100001660000000201514760300421020223 0ustar --TEST-- MongoDB\BSON\toRelaxedExtendedJSON(): BSON decoding exceptions --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Reading document did not exhaust input buffer ===DONE=== mongodb-1.21.0/tests/bson/bson-toRelaxedJSON_error-002.phpt0000644000175100001660000000162014760300421020225 0ustar --TEST-- MongoDB\BSON\toRelaxedExtendedJSON(): BSON decoding exceptions for malformed documents --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not read document from BSON reader ===DONE=== mongodb-1.21.0/tests/bson/bson-toRelaxedJSON_error-003.phpt0000644000175100001660000000331214760300421020226 0ustar --TEST-- MongoDB\BSON\toRelaxedExtendedJSON(): BSON decoding exceptions for bson_as_canonical_json() failure --FILE-- ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string Deprecated: Function MongoDB\BSON\toRelaxedExtendedJSON() is deprecated in %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Could not convert BSON document to a JSON string ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-001.phpt0000644000175100001660000000131614760300421016335 0ustar --TEST-- MongoDB\BSON\Undefined #001 --FILE-- toPHP(), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- Test#0 { "undefined" : { "$undefined" : true } } string(41) "{ "undefined" : { "$undefined" : true } }" string(41) "{ "undefined" : { "$undefined" : true } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-clone-001.phpt0000644000175100001660000000101614760300421017430 0ustar --TEST-- MongoDB\BSON\Undefined can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- toPHP(); $undefined = $test->undefined; $clone = clone $undefined; var_dump($clone == $undefined); var_dump($clone === $undefined); ?> ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-clone-002.phpt0000644000175100001660000000101614760300421017431 0ustar --TEST-- MongoDB\BSON\Undefined can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- toPHP(); $undefined = $test->undefined; $clone = clone $undefined; var_dump($clone == $undefined); var_dump($clone === $undefined); ?> ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-compare-001.phpt0000644000175100001660000000125214760300421017760 0ustar --TEST-- MongoDB\BSON\Undefined comparisons --FILE-- toPHP() == MongoDB\BSON\Document::fromJSON('{ "undefined": {"$undefined": true} }')->toPHP()); var_dump(MongoDB\BSON\Document::fromJSON('{ "undefined": {"$undefined": true} }')->toPHP() < MongoDB\BSON\Document::fromJSON('{ "undefined": {"$undefined": true} }')->toPHP()); var_dump(MongoDB\BSON\Document::fromJSON('{ "undefined": {"$undefined": true} }')->toPHP() > MongoDB\BSON\Document::fromJSON('{ "undefined": {"$undefined": true} }')->toPHP()); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-jsonserialize-001.phpt0000644000175100001660000000050414760300421021212 0ustar --TEST-- MongoDB\BSON\Undefined::jsonSerialize() return value --FILE-- toPHP()->undefined; var_dump($undefined->jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$undefined"]=> bool(true) } ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-jsonserialize-002.phpt0000644000175100001660000000103114760300421021207 0ustar --TEST-- MongoDB\BSON\Undefined::jsonSerialize() with json_encode() --FILE-- toPHP(); $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$undefined" : true } } {"foo":{"$undefined":true}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\Undefined)#%d (%d) { } } ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-serialization-002.phpt0000644000175100001660000000072214760300421021211 0ustar --TEST-- MongoDB\BSON\Undefined serialization (__serialize and __unserialize) --FILE-- toPHP()->undefined); var_dump($s = serialize($undefined)); var_dump(unserialize($s)); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Undefined)#%d (%d) { } string(34) "O:22:"MongoDB\BSON\Undefined":0:{}" object(MongoDB\BSON\Undefined)#%d (%d) { } ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-set_state-001.phpt0000644000175100001660000000063414760300421020330 0ustar --TEST-- MongoDB\BSON\Undefined::__set_state() --FILE-- toPHP()->undefined; $s = var_export($undefined, true); echo $s, "\n"; var_dump(eval('return ' . $s . ';')); ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\Undefined::__set_state(array( )) object(MongoDB\BSON\Undefined)#%d (%d) { } ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined-tostring-001.phpt0000644000175100001660000000041414760300421020202 0ustar --TEST-- MongoDB\BSON\Undefined::__toString() --FILE-- toPHP()->undefined; var_dump((string) $undefined); ?> ===DONE=== --EXPECT-- string(0) "" ===DONE=== mongodb-1.21.0/tests/bson/bson-undefined_error-001.phpt0000644000175100001660000000037614760300421017553 0ustar --TEST-- MongoDB\BSON\Undefined cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyUndefined %s final class %SMongoDB\BSON\Undefined%S in %s on line %d mongodb-1.21.0/tests/bson/bson-unknown-001.phpt0000644000175100001660000000112014760300421016064 0ustar --TEST-- BSON Serializing a PHP resource should throw exception --FILE-- STDERR); $b = fromPHP($a); }, "MongoDB\Driver\Exception\UnexpectedValueException"); throws(function() { $a = array("stderr" => STDERR, "stdout" => STDOUT); $b = fromPHP($a); }, "MongoDB\Driver\Exception\UnexpectedValueException"); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException OK: Got MongoDB\Driver\Exception\UnexpectedValueException ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-001.phpt0000644000175100001660000000271714760300421016712 0ustar --TEST-- MongoDB\BSON\UTCDateTime #001 --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => $utcdatetime)); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(array('_id' => 1)); $cursor = $manager->executeQuery(NS, $query); $results = iterator_to_array($cursor); $tests = array( array($utcdatetime), array($results[0]->x), ); foreach($tests as $n => $test) { $s = fromPHP($test); echo "Test#{$n} ", $json = toJSON($s), "\n"; $bson = fromJSON($json); $testagain = toPHP($bson); var_dump(toJSON(fromPHP($test)), toJSON(fromPHP($testagain))); var_dump((object)$test == (object)$testagain); } ?> ===DONE=== --EXPECT-- Test#0 { "0" : { "$date" : { "$numberLong" : "1416445411987" } } } string(59) "{ "0" : { "$date" : { "$numberLong" : "1416445411987" } } }" string(59) "{ "0" : { "$date" : { "$numberLong" : "1416445411987" } } }" bool(true) Test#1 { "0" : { "$date" : { "$numberLong" : "1416445411987" } } } string(59) "{ "0" : { "$date" : { "$numberLong" : "1416445411987" } } }" string(59) "{ "0" : { "$date" : { "$numberLong" : "1416445411987" } } }" bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-002.phpt0000644000175100001660000000050614760300421016705 0ustar --TEST-- MongoDB\BSON\UTCDateTime debug handler --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-003.phpt0000644000175100001660000000070414760300421016706 0ustar --TEST-- MongoDB\BSON\UTCDateTime construction from 64-bit integer --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-004.phpt0000644000175100001660000000070314760300421016706 0ustar --TEST-- MongoDB\BSON\UTCDateTime constructor defaults to current time --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "%d" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "%d" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-005.phpt0000644000175100001660000000140714760300421016711 0ustar --TEST-- MongoDB\BSON\UTCDateTime construction from DateTime --INI-- date.timezone=UTC --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "%d" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1215282385000" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1293894181012" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "2551871655999" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-006.phpt0000644000175100001660000000146414760300421016715 0ustar --TEST-- MongoDB\BSON\UTCDateTime construction from DateTimeImmutable --INI-- date.timezone=UTC --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "%d" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1215282385000" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1293894181012" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "2551871655999" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-007.phpt0000644000175100001660000000223114760300421016707 0ustar --TEST-- MongoDB\BSON\UTCDateTime constructor truncates floating point values --FILE-- ===DONE=== --EXPECTF-- Deprecated: MongoDB\BSON\UTCDateTime::__construct(): Creating a MongoDB\BSON\UTCDateTime instance with a float is deprecated and will be removed in ext-mongodb 2.0 in %s on line %d Deprecated: MongoDB\BSON\UTCDateTime::__construct(): Creating a MongoDB\BSON\UTCDateTime instance with a float is deprecated and will be removed in ext-mongodb 2.0 in %s on line %d Deprecated: MongoDB\BSON\UTCDateTime::__construct(): Creating a MongoDB\BSON\UTCDateTime instance with a float is deprecated and will be removed in ext-mongodb 2.0 in %s on line %d object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1416445411987" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(10) "2147483647" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(4) "1234" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-008.phpt0000644000175100001660000000104514760300421016712 0ustar --TEST-- MongoDB\BSON\UTCDateTime construction from 64-bit integer as string --FILE-- ===DONE=== --EXPECTF-- Deprecated: MongoDB\BSON\UTCDateTime::__construct(): Creating a MongoDB\BSON\UTCDateTime instance with a string is deprecated and will be removed in ext-mongodb 2.0 in %s object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-009.phpt0000644000175100001660000000060614760300421016715 0ustar --TEST-- MongoDB\BSON\UTCDateTime construction from Int64 object --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-clone-001.phpt0000644000175100001660000000117114760300421020001 0ustar --TEST-- MongoDB\BSON\UTCDateTime can be cloned (PHP < 8.2) --SKIPIF-- =', '8.2'); ?> --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\UTCDateTime)#%d (1) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-clone-002.phpt0000644000175100001660000000117114760300421020002 0ustar --TEST-- MongoDB\BSON\UTCDateTime can be cloned (PHP >= 8.2) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- bool(true) bool(false) object(MongoDB\BSON\UTCDateTime)#%d (1) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-compare-001.phpt0000644000175100001660000000111714760300421020327 0ustar --TEST-- MongoDB\BSON\UTCDateTime comparisons --FILE-- new MongoDB\BSON\UTCDateTime(1234)); var_dump(new MongoDB\BSON\UTCDateTime(1234) < new MongoDB\BSON\UTCDateTime(1235)); var_dump(new MongoDB\BSON\UTCDateTime(1234) > new MongoDB\BSON\UTCDateTime(1233)); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-get_properties-001.phpt0000644000175100001660000000052114760300421021732 0ustar --TEST-- MongoDB\BSON\UTCDateTime get_properties handler (get_object_vars) --FILE-- ===DONE=== --EXPECT-- array(1) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-get_properties-002.phpt0000644000175100001660000000055514760300421021742 0ustar --TEST-- MongoDB\BSON\UTCDateTime get_properties handler (foreach) --FILE-- $value) { var_dump($key); var_dump($value); } ?> ===DONE=== --EXPECT-- string(12) "milliseconds" string(13) "1416445411987" ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-jsonserialize-001.phpt0000644000175100001660000000053314760300421021563 0ustar --TEST-- MongoDB\BSON\UTCDateTime::jsonSerialize() return value --FILE-- jsonSerialize()); ?> ===DONE=== --EXPECT-- array(1) { ["$date"]=> array(1) { ["$numberLong"]=> string(13) "1476192866817" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-jsonserialize-002.phpt0000644000175100001660000000121414760300421021561 0ustar --TEST-- MongoDB\BSON\UTCDateTime::jsonSerialize() with json_encode() --FILE-- new MongoDB\BSON\UTCDateTime(new DateTime('2016-10-11 13:34:26.817 UTC'))]; $json = json_encode($doc); echo toJSON(fromPHP($doc)), "\n"; echo $json, "\n"; var_dump(toPHP(fromJSON($json))); ?> ===DONE=== --EXPECTF-- { "foo" : { "$date" : { "$numberLong" : "1476192866817" } } } {"foo":{"$date":{"$numberLong":"1476192866817"}}} object(stdClass)#%d (%d) { ["foo"]=> object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1476192866817" } } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-serialization-003.phpt0000644000175100001660000000235514760300421021565 0ustar --TEST-- MongoDB\BSON\UTCDateTime serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(1) "0" } string(64) "O:24:"MongoDB\BSON\UTCDateTime":1:{s:12:"milliseconds";s:1:"0";}" object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(1) "0" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(14) "-1416445411987" } string(78) "O:24:"MongoDB\BSON\UTCDateTime":1:{s:12:"milliseconds";s:14:"-1416445411987";}" object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(14) "-1416445411987" } object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1416445411987" } string(77) "O:24:"MongoDB\BSON\UTCDateTime":1:{s:12:"milliseconds";s:13:"1416445411987";}" object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-serialization-004.phpt0000644000175100001660000000212314760300421021557 0ustar --TEST-- MongoDB\BSON\UTCDateTime serialization (unserialize 32-bit data on 64-bit) (__serialize and __unserialize) --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- string(64) "O:24:"MongoDB\BSON\UTCDateTime":1:{s:12:"milliseconds";s:1:"0";}" object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(1) "0" } string(78) "O:24:"MongoDB\BSON\UTCDateTime":1:{s:12:"milliseconds";s:14:"-1416445411987";}" object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(14) "-1416445411987" } string(77) "O:24:"MongoDB\BSON\UTCDateTime":1:{s:12:"milliseconds";s:13:"1416445411987";}" object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1416445411987" } ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-serialization_error-001.phpt0000644000175100001660000000110314760300421022762 0ustar --TEST-- MongoDB\BSON\UTCDateTime unserialization requires "milliseconds" integer or numeric string field (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\UTCDateTime initialization requires "milliseconds" integer or numeric string field ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-serialization_error-002.phpt0000644000175100001660000000322014760300421022765 0ustar --TEST-- MongoDB\BSON\UTCDateTime unserialization requires "milliseconds" string to parse as 64-bit integer (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1234.5678" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "9223372036854775808" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "-9223372036854775809" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "18446744073709551615" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-serialization_error-003.phpt0000644000175100001660000000110314760300421022764 0ustar --TEST-- MongoDB\BSON\UTCDateTime unserialization requires "milliseconds" integer or numeric string field (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\UTCDateTime initialization requires "milliseconds" integer or numeric string field ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-serialization_error-004.phpt0000644000175100001660000000317314760300421022776 0ustar --TEST-- MongoDB\BSON\UTCDateTime unserialization requires "milliseconds" string to parse as 64-bit integer (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1234.5678" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "9223372036854775808" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "-9223372036854775809" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "18446744073709551615" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-set_state-001.phpt0000644000175100001660000000115314760300421020674 0ustar --TEST-- MongoDB\BSON\UTCDateTime::__set_state() --FILE-- $milliseconds, ])); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\UTCDateTime::__set_state(array( 'milliseconds' => '0', )) %r\\?%rMongoDB\BSON\UTCDateTime::__set_state(array( 'milliseconds' => '-1416445411987', )) %r\\?%rMongoDB\BSON\UTCDateTime::__set_state(array( 'milliseconds' => '1416445411987', )) ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-set_state-002.phpt0000644000175100001660000000130414760300421020673 0ustar --TEST-- MongoDB\BSON\UTCDateTime::__set_state() (64-bit) --SKIPIF-- --FILE-- $milliseconds, ])); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\BSON\UTCDateTime::__set_state(array( 'milliseconds' => '0', )) %r\\?%rMongoDB\BSON\UTCDateTime::__set_state(array( 'milliseconds' => '-1416445411987', )) %r\\?%rMongoDB\BSON\UTCDateTime::__set_state(array( 'milliseconds' => '1416445411987', )) ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-set_state_error-001.phpt0000644000175100001660000000102514760300421022103 0ustar --TEST-- MongoDB\BSON\UTCDateTime::__set_state() requires "milliseconds" integer or numeric string field --FILE-- 1.0]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\BSON\UTCDateTime initialization requires "milliseconds" integer or numeric string field ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-set_state_error-002.phpt0000644000175100001660000000302314760300421022104 0ustar --TEST-- MongoDB\BSON\UTCDateTime::__set_state() requires "milliseconds" string to parse as 64-bit integer --FILE-- '1234.5678']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; // Out-of-range values echo throws(function() { MongoDB\BSON\UTCDateTime::__set_state(['milliseconds' => '9223372036854775808']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\UTCDateTime::__set_state(['milliseconds' => '-9223372036854775809']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\BSON\UTCDateTime::__set_state(['milliseconds' => '18446744073709551615']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1234.5678" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "9223372036854775808" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "-9223372036854775809" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "18446744073709551615" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-todatetime-001.phpt0000644000175100001660000000065014760300421021041 0ustar --TEST-- MongoDB\BSON\UTCDateTime::toDateTime() --INI-- date.timezone=America/Los_Angeles --FILE-- toDateTime(); var_dump(get_class($datetime)); var_dump($datetime->format(DATE_RSS)); ?> ===DONE=== --EXPECT-- string(8) "DateTime" string(31) "Thu, 20 Nov 2014 01:03:31 +0000" ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-todatetime-002.phpt0000644000175100001660000000063414760300421021044 0ustar --TEST-- MongoDB\BSON\UTCDateTime::toDateTime() dumping seconds and microseconds --INI-- date.timezone=UTC --FILE-- toDateTime(); var_dump(get_class($datetime)); echo $datetime->format('U.u'), "\n"; ?> ===DONE=== --EXPECT-- string(8) "DateTime" 1416445411.987000 ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-todatetime-003.phpt0000644000175100001660000000131114760300421021036 0ustar --TEST-- MongoDB\BSON\UTCDateTime::toDateTime() with dates before the Unix epoch --INI-- date.timezone=UTC --FILE-- format(DateTimeInterface::RFC3339_EXTENDED), PHP_EOL; $utcDateTime = new MongoDB\BSON\UTCDateTime($dateTime); $newDate = $utcDateTime->toDateTime(); echo $newDate->format(DateTimeInterface::RFC3339_EXTENDED), PHP_EOL, PHP_EOL; } ?> ===DONE=== --EXPECT-- 1960-01-01T12:12:12.100+00:00 1960-01-01T12:12:12.100+00:00 1969-12-31T23:59:59.999+00:00 1969-12-31T23:59:59.999+00:00 ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-todatetimeimmutable-001.phpt0000644000175100001660000000070414760300421022741 0ustar --TEST-- MongoDB\BSON\UTCDateTime::toDateTimeImmutable() --INI-- date.timezone=America/Los_Angeles --FILE-- toDateTimeImmutable(); var_dump(get_class($datetime)); var_dump($datetime->format(DATE_RSS)); ?> ===DONE=== --EXPECT-- string(17) "DateTimeImmutable" string(31) "Thu, 20 Nov 2014 01:03:31 +0000" ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-todatetimeimmutable-002.phpt0000644000175100001660000000067014760300421022744 0ustar --TEST-- MongoDB\BSON\UTCDateTime::toDateTimeImmutable() dumping seconds and microseconds --INI-- date.timezone=UTC --FILE-- toDateTimeImmutable(); var_dump(get_class($datetime)); echo $datetime->format('U.u'), "\n"; ?> ===DONE=== --EXPECT-- string(17) "DateTimeImmutable" 1416445411.987000 ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-todatetimeimmutable-003.phpt0000644000175100001660000000133314760300421022742 0ustar --TEST-- MongoDB\BSON\UTCDateTime::toDateTimeImmutable() with dates before the Unix epoch --INI-- date.timezone=UTC --FILE-- format(DateTimeInterface::RFC3339_EXTENDED), PHP_EOL; $utcDateTime = new MongoDB\BSON\UTCDateTime($dateTime); $newDate = $utcDateTime->toDateTimeImmutable(); echo $newDate->format(DateTimeInterface::RFC3339_EXTENDED), PHP_EOL, PHP_EOL; } ?> ===DONE=== --EXPECT-- 1960-01-01T12:12:12.100+00:00 1960-01-01T12:12:12.100+00:00 1969-12-31T23:59:59.999+00:00 1969-12-31T23:59:59.999+00:00 ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime-tostring-001.phpt0000644000175100001660000000041114760300421020546 0ustar --TEST-- MongoDB\BSON\UTCDateTime::__toString() --FILE-- ===DONE=== --EXPECT-- string(13) "1416445411987" ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime_error-001.phpt0000644000175100001660000000073714760300421020123 0ustar --TEST-- MongoDB\BSON\UTCDateTime requires object argument to implement DateTimeInterface --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected instance of DateTimeInterface or MongoDB\BSON\Int64, stdClass given ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime_error-002.phpt0000644000175100001660000000041014760300421020110 0ustar --TEST-- MongoDB\BSON\UTCDateTime cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyUTCDateTime %s final class %SMongoDB\BSON\UTCDateTime%S in %s on line %d mongodb-1.21.0/tests/bson/bson-utcdatetime_error-003.phpt0000644000175100001660000000410014760300421020111 0ustar --TEST-- MongoDB\BSON\UTCDateTime constructor requires strings to parse as 64-bit integers --FILE-- ===DONE=== --EXPECTF-- Deprecated: MongoDB\BSON\UTCDateTime::__construct(): Creating a MongoDB\BSON\UTCDateTime instance with a string is deprecated and will be removed in ext-mongodb 2.0 in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "1234.5678" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization Deprecated: MongoDB\BSON\UTCDateTime::__construct(): Creating a MongoDB\BSON\UTCDateTime instance with a string is deprecated and will be removed in ext-mongodb 2.0 in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "9223372036854775808" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization Deprecated: MongoDB\BSON\UTCDateTime::__construct(): Creating a MongoDB\BSON\UTCDateTime instance with a string is deprecated and will be removed in ext-mongodb 2.0 in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "-9223372036854775809" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization Deprecated: MongoDB\BSON\UTCDateTime::__construct(): Creating a MongoDB\BSON\UTCDateTime instance with a string is deprecated and will be removed in ext-mongodb 2.0 in %s OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "18446744073709551615" as 64-bit integer for MongoDB\BSON\UTCDateTime initialization ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetime_error-004.phpt0000644000175100001660000000155714760300421020127 0ustar --TEST-- MongoDB\BSON\UTCDateTime constructor requires integer or string argument --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected integer or string, bool given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected integer or string, array given ===DONE=== mongodb-1.21.0/tests/bson/bson-utcdatetimeinterface-001.phpt0000644000175100001660000000046514760300421020571 0ustar --TEST-- MongoDB\BSON\UTCDateTimeInterface is implemented by MongoDB\BSON\UTCDateTime --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bug0274.phpt0000644000175100001660000000266214760300421014236 0ustar --TEST-- Test for PHPC-274: zval_to_bson() should process BSON\Serializable instances --FILE-- "class", "data"); } } class NumericArray implements MongoDB\BSON\Serializable { #[\ReturnTypeWillChange] public function bsonSerialize() { return array(1, 2, 3); } } echo "Testing top-level AssociativeArray:\n"; $bson = fromPHP(new AssociativeArray); echo toJSON($bson), "\n"; echo "Encoded BSON:\n"; hex_dump($bson); echo "\nTesting top-level NumericArray:\n"; $bson = fromPHP(new NumericArray); echo toJSON($bson), "\n"; echo "Encoded BSON:\n"; hex_dump($bson); ?> ===DONE=== --EXPECT-- Testing top-level AssociativeArray: { "random" : "class", "0" : "data" } Encoded BSON: 0 : 23 00 00 00 02 72 61 6e 64 6f 6d 00 06 00 00 00 [#....random.....] 10 : 63 6c 61 73 73 00 02 30 00 05 00 00 00 64 61 74 [class..0.....dat] 20 : 61 00 00 [a..] Testing top-level NumericArray: { "0" : { "$numberInt" : "1" }, "1" : { "$numberInt" : "2" }, "2" : { "$numberInt" : "3" } } Encoded BSON: 0 : 1a 00 00 00 10 30 00 01 00 00 00 10 31 00 02 00 [.....0......1...] 10 : 00 00 10 32 00 03 00 00 00 00 [...2......] ===DONE=== mongodb-1.21.0/tests/bson/bug0325.phpt0000644000175100001660000000070714760300421014231 0ustar --TEST-- Test for PHPC-325: Memory leak decoding buffers with multiple documents --FILE-- getMessage(), "\n"; } ?> ===DONE=== --EXPECT-- Reading document did not exhaust input buffer ===DONE=== mongodb-1.21.0/tests/bson/bug0334-001.phpt0000644000175100001660000000120014760300421014514 0ustar --TEST-- PHPC-334: Injected __pclass should override a __pclass key in bsonSerialize() return value --FILE-- "baz", "foo" => "bar", ); } public function bsonUnserialize(array $data): void { } } $bson = fromPHP(new MyClass); $php = toPHP($bson, array('root' => 'array')); var_dump($php['__pclass']->getData()); ?> ===DONE=== --EXPECT-- string(7) "MyClass" ===DONE=== mongodb-1.21.0/tests/bson/bug0334-002.phpt0000644000175100001660000000133214760300421014523 0ustar --TEST-- PHPC-334: Encoded BSON should never have multiple __pclass keys --FILE-- "baz", "foo" => "bar", ); } public function bsonUnserialize(array $data): void { } } hex_dump(fromPHP(new MyClass)) ?> ===DONE=== --EXPECT-- 0 : 28 00 00 00 05 5f 5f 70 63 6c 61 73 73 00 07 00 [(....__pclass...] 10 : 00 00 80 4d 79 43 6c 61 73 73 02 66 6f 6f 00 04 [...MyClass.foo..] 20 : 00 00 00 62 61 72 00 00 [...bar..] ===DONE=== mongodb-1.21.0/tests/bson/bug0341.phpt0000644000175100001660000000143014760300421014221 0ustar --TEST-- PHPC-341: fromJSON() leaks when JSON contains array or object fields --FILE-- ===DONE=== --EXPECTF-- object(stdClass)#%d (2) { ["foo"]=> string(3) "yes" ["bar"]=> bool(false) } object(stdClass)#%d (2) { ["foo"]=> string(2) "no" ["array"]=> array(2) { [0]=> int(5) [1]=> int(6) } } object(stdClass)#%d (2) { ["foo"]=> string(2) "no" ["obj"]=> object(stdClass)#%d (1) { ["embedded"]=> float(4.125) } } ===DONE=== mongodb-1.21.0/tests/bson/bug0347.phpt0000644000175100001660000000054014760300421014230 0ustar --TEST-- Test for PHPC-347: Memory leak decoding empty buffer --FILE-- getMessage(), "\n"; } ?> ===DONE=== --EXPECT-- Could not read document from BSON reader ===DONE=== mongodb-1.21.0/tests/bson/bug0528.phpt0000644000175100001660000000047114760300421014234 0ustar --TEST-- PHPC-528: Cannot append reference to BSON --FILE-- &$embedded]; $bson = fromPHP($data); echo toJson(fromPHP($data)), "\n"; ?> ===DONE=== --EXPECT-- { "embedded" : [ "foo" ] } ===DONE=== mongodb-1.21.0/tests/bson/bug0531-001.phpt0000644000175100001660000000101014760300421014512 0ustar --TEST-- PHPC-531: Segfault due to double free by corrupt BSON visitor (top-level) --FILE-- "world"]); $bson[4] = 1; echo throws(function() use ($bson) { toPHP($bson); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected unknown BSON type 0x31 for field path "hello". Are you using the latest driver? ===DONE=== mongodb-1.21.0/tests/bson/bug0544.phpt0000644000175100001660000000732114760300421014233 0ustar --TEST-- PHPC-544: Consult SIZEOF_ZEND_LONG for 64-bit integer support --SKIPIF-- --FILE-- -2147483648], ['x' => 2147483647], ['x' => -4294967294], ['x' => 4294967294], ['x' => -4294967295], ['x' => 4294967295], ['x' => -9223372036854775807], ['x' => 9223372036854775807], ]; foreach ($tests as $test) { $bson = MongoDB\BSON\fromPHP($test); /* Note: Although libbson can parse the extended JSON representation for * 64-bit integers (i.e. "$numberLong"), it currently prints them as * doubles (see: https://jira.mongodb.org/browse/CDRIVER-375). */ printf("Test %s\n", MongoDB\BSON\toJSON($bson)); hex_dump($bson); var_dump(MongoDB\BSON\toPHP($bson)); echo "\n"; } ?> ===DONE=== --EXPECTF-- Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : -2147483648 } 0 : 0c 00 00 00 10 78 00 00 00 00 80 00 [.....x......] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(-2147483648) } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : 2147483647 } 0 : 0c 00 00 00 10 78 00 ff ff ff 7f 00 [.....x......] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(2147483647) } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : -4294967294 } 0 : 10 00 00 00 12 78 00 02 00 00 00 ff ff ff ff 00 [.....x..........] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(-4294967294) } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : 4294967294 } 0 : 10 00 00 00 12 78 00 fe ff ff ff 00 00 00 00 00 [.....x..........] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(4294967294) } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : -4294967295 } 0 : 10 00 00 00 12 78 00 01 00 00 00 ff ff ff ff 00 [.....x..........] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(-4294967295) } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : 4294967295 } 0 : 10 00 00 00 12 78 00 ff ff ff ff 00 00 00 00 00 [.....x..........] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(4294967295) } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : -9223372036854775807 } 0 : 10 00 00 00 12 78 00 01 00 00 00 00 00 00 80 00 [.....x..........] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(-9223372036854775807) } Deprecated: Function MongoDB\BSON\fromPHP() is deprecated in %s Deprecated: Function MongoDB\BSON\toJSON() is deprecated in %s Test { "x" : 9223372036854775807 } 0 : 10 00 00 00 12 78 00 ff ff ff ff ff ff ff 7f 00 [.....x..........] Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(9223372036854775807) } ===DONE=== mongodb-1.21.0/tests/bson/bug0592.phpt0000644000175100001660000001003714760300421014234 0ustar --TEST-- PHPC-592: Property name corrupted when unserializing 64-bit integer on 32-bit platform --SKIPIF-- --FILE-- getMessage(), "\n"; } echo "\n"; } ?> ===DONE=== --EXPECTF-- Test { "x": { "$numberLong": "-2147483648" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(-2147483648) } Test { "x": { "$numberLong": "2147483647" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> int(2147483647) } Test { "x": { "$numberLong": "4294967294" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(10) "4294967294" } } Test { "x": { "$numberLong": "4294967295" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(10) "4294967295" } } Test { "x": { "$numberLong": "9223372036854775807" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["x"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } } Test { "longFieldName": { "$numberLong": "-2147483648" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["longFieldName"]=> int(-2147483648) } Test { "longFieldName": { "$numberLong": "2147483647" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["longFieldName"]=> int(2147483647) } Test { "longFieldName": { "$numberLong": "4294967294" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["longFieldName"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(10) "4294967294" } } Test { "longFieldName": { "$numberLong": "4294967295" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["longFieldName"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(10) "4294967295" } } Test { "longFieldName": { "$numberLong": "9223372036854775807" }} Deprecated: Function MongoDB\BSON\fromJSON() is deprecated in %s Deprecated: Function MongoDB\BSON\toPHP() is deprecated in %s object(stdClass)#%d (%d) { ["longFieldName"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(19) "9223372036854775807" } } ===DONE=== mongodb-1.21.0/tests/bson/bug0623.phpt0000644000175100001660000000306614760300421014233 0ustar --TEST-- PHPC-623: Numeric keys limited to unsigned 32-bit integer --SKIPIF-- --FILE-- 'a', 'X9781449410247' => 'b', 9781449410248 => 'c', ], [ '4294967295' => 'a', '4294967296' => 'b', '4294967297' => 'c', ] ]; foreach ($tests as $test) { printf("Test %s\n", json_encode($test)); $bson = fromPHP($test); hex_dump($bson); echo toJSON($bson), "\n\n"; } ?> ===DONE=== --EXPECT-- Test {"9781449410247":"a","X9781449410247":"b","9781449410248":"c"} 0 : 45 00 00 00 02 39 37 38 31 34 34 39 34 31 30 32 [E....97814494102] 10 : 34 37 00 02 00 00 00 61 00 02 58 39 37 38 31 34 [47.....a..X97814] 20 : 34 39 34 31 30 32 34 37 00 02 00 00 00 62 00 02 [49410247.....b..] 30 : 39 37 38 31 34 34 39 34 31 30 32 34 38 00 02 00 [9781449410248...] 40 : 00 00 63 00 00 [..c..] { "9781449410247" : "a", "X9781449410247" : "b", "9781449410248" : "c" } Test {"4294967295":"a","4294967296":"b","4294967297":"c"} 0 : 3b 00 00 00 02 34 32 39 34 39 36 37 32 39 35 00 [;....4294967295.] 10 : 02 00 00 00 61 00 02 34 32 39 34 39 36 37 32 39 [....a..429496729] 20 : 36 00 02 00 00 00 62 00 02 34 32 39 34 39 36 37 [6.....b..4294967] 30 : 32 39 37 00 02 00 00 00 63 00 00 [297.....c..] { "4294967295" : "a", "4294967296" : "b", "4294967297" : "c" } ===DONE=== mongodb-1.21.0/tests/bson/bug0631.phpt0000644000175100001660000000156714760300421014236 0ustar --TEST-- PHPC-631: UTCDateTime::toDateTime() may return object that cannot be serialized --INI-- date.timezone=UTC --FILE-- toDateTime(); $s = serialize($datetime); var_dump($datetime); echo "\n", $s, "\n\n"; var_dump(unserialize($s)); ?> ===DONE=== --EXPECTF-- object(DateTime)#%d (%d) { ["date"]=> string(26) "2016-06-21 20:25:55.123000" ["timezone_type"]=> int(1) ["timezone"]=> string(6) "+00:00" } O:8:"DateTime":3:{s:4:"date";s:26:"2016-06-21 20:25:55.123000";s:13:"timezone_type";i:1;s:8:"timezone";s:6:"+00:00";} object(DateTime)#%d (%d) { ["date"]=> string(26) "2016-06-21 20:25:55.123000" ["timezone_type"]=> int(1) ["timezone"]=> string(6) "+00:00" } ===DONE=== mongodb-1.21.0/tests/bson/bug0672.phpt0000644000175100001660000000126214760300421014233 0ustar --TEST-- PHPC-672: ObjectId constructor should not modify string argument's memory --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "56925b7330616224d0000001" } string(24) "56925B7330616224D0000001" OK: Got MongoDB\Driver\Exception\InvalidArgumentException string(7) "T123456" ===DONE=== mongodb-1.21.0/tests/bson/bug0894-001.phpt0000644000175100001660000000126114760300421014536 0ustar --TEST-- PHPC-849: BSON get_properties handlers leak during gc_possible_root() checks --FILE-- 42]), new MongoDB\BSON\MaxKey, new MongoDB\BSON\MinKey, new MongoDB\BSON\ObjectId, new MongoDB\BSON\Regex('foo', 'i'), new MongoDB\BSON\Timestamp(1234, 5678), new MongoDB\BSON\UTCDateTime, ]; printf("Created array of %d BSON objects\n", count($objects)); gc_collect_cycles(); ?> ===DONE=== --EXPECT-- Created array of 9 BSON objects ===DONE=== mongodb-1.21.0/tests/bson/bug0923-001.phpt0000644000175100001660000000156714760300421014540 0ustar --TEST-- PHPC-923: Use zend_string_release() to free class names (type map) --FILE-- 'MissingClass'])); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; var_dump($classes); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist array(1) { [0]=> string(12) "MissingClass" } ===DONE=== mongodb-1.21.0/tests/bson/bug0923-002.phpt0000644000175100001660000000212214760300421014525 0ustar --TEST-- PHPC-923: Use zend_string_release() to free class names (__pclass) --FILE-- ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["x"]=> object(stdClass)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(12) "MissingClass" ["type"]=> int(128) } } } array(1) { [0]=> string(12) "MissingClass" } ===DONE=== mongodb-1.21.0/tests/bson/bug0939-001.phpt0000644000175100001660000000435514760300421014545 0ustar --TEST-- PHPC-939: BSON classes should not assign public properties after var_dump() --FILE-- 42]), ['code', 'scope'] ], [ new MongoDB\BSON\MaxKey, [] ], [ new MongoDB\BSON\MinKey, [] ], [ new MongoDB\BSON\ObjectId, ['oid'] ], [ new MongoDB\BSON\Regex('foo', 'i'), ['pattern', 'flags'] ], [ new MongoDB\BSON\Timestamp(1234, 5678), ['increment', 'timestamp'] ], [ new MongoDB\BSON\UTCDateTime, ['milliseconds'] ], ]; foreach ($tests as $test) { list($object, $properties) = $test; var_dump($object); foreach ($properties as $property) { printf("%s::$%s exists: %s\n", get_class($object), $property, property_exists($object, $property) ? 'yes' : 'no'); } echo "\n"; } ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(3) "foo" ["type"]=> int(0) } MongoDB\BSON\Binary::$data exists: no MongoDB\BSON\Binary::$type exists: no object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(4) "3.14" } MongoDB\BSON\Decimal128::$dec exists: no object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(26) "function() { return bar; }" ["scope"]=> object(stdClass)#%d (%d) { ["bar"]=> int(42) } } MongoDB\BSON\Javascript::$code exists: no MongoDB\BSON\Javascript::$scope exists: no object(MongoDB\BSON\MaxKey)#%d (%d) { } object(MongoDB\BSON\MinKey)#%d (%d) { } object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } MongoDB\BSON\ObjectId::$oid exists: no object(MongoDB\BSON\Regex)#%d (%d) { ["pattern"]=> string(3) "foo" ["flags"]=> string(1) "i" } MongoDB\BSON\Regex::$pattern exists: no MongoDB\BSON\Regex::$flags exists: no object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } MongoDB\BSON\Timestamp::$increment exists: no MongoDB\BSON\Timestamp::$timestamp exists: no object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(%d) "%d" } MongoDB\BSON\UTCDateTime::$milliseconds exists: no ===DONE=== mongodb-1.21.0/tests/bson/bug0974-001.phpt0000644000175100001660000000215714760300421014542 0ustar --TEST-- PHPC-974: Converting JSON to BSON to PHP introduces gaps in array indexes --FILE-- ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["myArray"]=> array(1) { [0]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "201700601301102102609060" } } } object(stdClass)#%d (%d) { ["0"]=> int(1) ["1"]=> int(2) ["2"]=> int(3) ["3"]=> object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1497352886906" } } object(stdClass)#%d (%d) { ["0"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "55f2b3f1f657b3fa97c9c0a2" } ["1"]=> object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1497352886906" } } ===DONE=== mongodb-1.21.0/tests/bson/bug1006-001.phpt0000644000175100001660000000204614760300421014522 0ustar --TEST-- PHPC-1006: Do not modify memory of Persistable::bsonSerialize() return value --FILE-- data = [ '__pclass' => 'baz', 'foo' => 'bar', ]; } #[\ReturnTypeWillChange] public function bsonSerialize() { return $this->data; } public function bsonUnserialize(array $data): void { } } $obj = new MyClass; var_dump($obj->data); hex_dump(fromPHP($obj)); var_dump($obj->data); ?> ===DONE=== --EXPECT-- array(2) { ["__pclass"]=> string(3) "baz" ["foo"]=> string(3) "bar" } 0 : 28 00 00 00 05 5f 5f 70 63 6c 61 73 73 00 07 00 [(....__pclass...] 10 : 00 00 80 4d 79 43 6c 61 73 73 02 66 6f 6f 00 04 [...MyClass.foo..] 20 : 00 00 00 62 61 72 00 00 [...bar..] array(2) { ["__pclass"]=> string(3) "baz" ["foo"]=> string(3) "bar" } ===DONE=== mongodb-1.21.0/tests/bson/bug1006-002.phpt0000644000175100001660000000124614760300421014524 0ustar --TEST-- PHPC-1006: Do not skip __pclass in Serializable::bsonSerialize() return value --FILE-- 'baz', 'foo' => 'bar', ]; } } hex_dump(fromPHP(new MyClass)); ?> ===DONE=== --EXPECT-- 0 : 24 00 00 00 02 5f 5f 70 63 6c 61 73 73 00 04 00 [$....__pclass...] 10 : 00 00 62 61 7a 00 02 66 6f 6f 00 04 00 00 00 62 [..baz..foo.....b] 20 : 61 72 00 00 [ar..] ===DONE=== mongodb-1.21.0/tests/bson/bug1053.phpt0000644000175100001660000000047114760300421014226 0ustar --TEST-- PHPC-1053: MongoDB\BSON\UTCDateTime's constructor has argument defined as required --FILE-- getParameters()[0]->isOptional()); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bson/bug1067.phpt0000644000175100001660000000066614760300421014241 0ustar --TEST-- PHPC-1067: BSON document produces driver segfault with insert --FILE-- new MongoDB\BSON\ObjectID('111111111111111111111111'), '___________________________________' => new MongoDB\BSON\Regex('_______________________________________________________', 'i'), ]; $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert($x); ?> ==DONE== --EXPECT-- ==DONE== mongodb-1.21.0/tests/bson/bug1266.phpt0000644000175100001660000000277214760300421014242 0ustar --TEST-- Test for PHPC-1266: Empty deeply nested BSON document causes unallocated memory writes --FILE-- toPHP()); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["value"]=> object(stdClass)#%d (%d) { ["payload"]=> object(stdClass)#%d (%d) { ["PayloadMasterDataMeteringPointPartyEvent"]=> object(stdClass)#%d (%d) { ["MeteringPointPartyDetailMeteringPointPartyCharacteristic"]=> object(stdClass)#%d (%d) { ["AdministrativePartyMPAdministrativeParty"]=> array(%d) { [0]=> object(stdClass)#%d (%d) { ["AdministrativePartyAddressLocationAddress"]=> object(stdClass)#%d (%d) { ["StreetCode"]=> object(stdClass)#%d (%d) { } } } } } } } } } ===DONE=== mongodb-1.21.0/tests/bson/bug1598-001.phpt0000644000175100001660000000444114760300421014543 0ustar --TEST-- PHPC-1598: BSON type get_gc should not invoke get_properties --FILE-- new MongoDB\BSON\Binary('foo', MongoDB\BSON\Binary::TYPE_GENERIC) ], // Use serialized strings to construct types with disabled constructors [ 'dbpointer' => unserialize('C:22:"MongoDB\BSON\DBPointer":76:{a:2:{s:3:"ref";s:11:"phongo.test";s:2:"id";s:24:"5a2e78accd485d55b4050000";}}') ], [ 'decimal128' => new MongoDB\BSON\Decimal128('1234.5678') ], [ 'int64' => new MongoDB\BSON\Int64('9223372036854775807') ], // JavaScript w/ scope may not be necessary (same code path as w/o scope), but we'll test it anyway [ 'javascript' => new MongoDB\BSON\Javascript('function() { return 1; }') ], [ 'javascript_ws' => new MongoDB\BSON\Javascript('function() { return a; }', ['a' => 1]) ], // MaxKey and MinKey don't have get_properties or get_gc handlers, but we'll test them anyway [ 'maxkey' => new MongoDB\BSON\MaxKey ], [ 'minkey' => new MongoDB\BSON\MinKey ], [ 'objectid' => new MongoDB\BSON\ObjectId ], [ 'regex' => new MongoDB\BSON\Regex('pattern', 'i') ], [ 'symbol' => unserialize('C:19:"MongoDB\BSON\Symbol":38:{a:1:{s:6:"symbol";s:11:"symbolValue";}}') ], [ 'timestamp' => new MongoDB\BSON\Timestamp(1234, 5678) ], [ 'utcdatetime' => new MongoDB\BSON\UTCDateTime ], ]; foreach ($tests as $test) { echo key($test), "\n"; $a = (object) $test; $b = (object) $test; $a->b = $b; $b->a = $a; printf("Collected cycles: %d\n", gc_collect_cycles()); unset($a, $b); printf("Collected cycles: %d\n\n", gc_collect_cycles()); } ?> ===DONE=== --EXPECT-- binary Collected cycles: 0 Collected cycles: 2 dbpointer Collected cycles: 0 Collected cycles: 2 decimal128 Collected cycles: 0 Collected cycles: 2 int64 Collected cycles: 0 Collected cycles: 2 javascript Collected cycles: 0 Collected cycles: 2 javascript_ws Collected cycles: 0 Collected cycles: 2 maxkey Collected cycles: 0 Collected cycles: 2 minkey Collected cycles: 0 Collected cycles: 2 objectid Collected cycles: 0 Collected cycles: 2 regex Collected cycles: 0 Collected cycles: 2 symbol Collected cycles: 0 Collected cycles: 2 timestamp Collected cycles: 0 Collected cycles: 2 utcdatetime Collected cycles: 0 Collected cycles: 2 ===DONE=== mongodb-1.21.0/tests/bson/bug1598-002.phpt0000644000175100001660000000553614760300421014552 0ustar --TEST-- PHPC-1598: BSON type get_gc should delegate to zend_std_get_properties --SKIPIF-- =', '8.1.99'); ?> --FILE-- new MongoDB\BSON\Binary('foo', MongoDB\BSON\Binary::TYPE_GENERIC) ], // Use serialized strings to construct types with disabled constructors [ 'dbpointer' => unserialize('C:22:"MongoDB\BSON\DBPointer":76:{a:2:{s:3:"ref";s:11:"phongo.test";s:2:"id";s:24:"5a2e78accd485d55b4050000";}}') ], [ 'decimal128' => new MongoDB\BSON\Decimal128('1234.5678') ], [ 'int64' => new MongoDB\BSON\Int64('9223372036854775807') ], // JavaScript w/ scope may not be necessary (same code path as w/o scope), but we'll test it anyway [ 'javascript' => new MongoDB\BSON\Javascript('function() { return 1; }') ], [ 'javascript_ws' => new MongoDB\BSON\Javascript('function() { return a; }', ['a' => 1]) ], // MaxKey and MinKey don't have get_properties or get_gc handlers, but we'll test them anyway [ 'maxkey' => new MongoDB\BSON\MaxKey ], [ 'minkey' => new MongoDB\BSON\MinKey ], [ 'objectid' => new MongoDB\BSON\ObjectId ], [ 'regex' => new MongoDB\BSON\Regex('pattern', 'i') ], [ 'symbol' => unserialize('C:19:"MongoDB\BSON\Symbol":38:{a:1:{s:6:"symbol";s:11:"symbolValue";}}') ], [ 'timestamp' => new MongoDB\BSON\Timestamp(1234, 5678) ], [ 'utcdatetime' => new MongoDB\BSON\UTCDateTime ], ]; foreach ($tests as &$test) { echo key($test), "\n"; /* Store an additional object reference as a public property on the BSON * object. This will leak if get_gc returns internally cached properties * (from our get_properties handler) instead of zend_std_get_properties. */ $a = new stdClass; $a->bson = current($test); $a->bson->a = $a; /* Unset the original BSON object from the test so that its only reference * is from the new object we just created. This also requires iterating the * test cases by reference. */ unset($test[key($test)]); printf("Collected cycles: %d\n", gc_collect_cycles()); unset($a); printf("Collected cycles: %d\n\n", gc_collect_cycles()); } ?> ===DONE=== --EXPECT-- binary Collected cycles: 0 Collected cycles: 2 dbpointer Collected cycles: 0 Collected cycles: 2 decimal128 Collected cycles: 0 Collected cycles: 2 int64 Collected cycles: 0 Collected cycles: 2 javascript Collected cycles: 0 Collected cycles: 2 javascript_ws Collected cycles: 0 Collected cycles: 2 maxkey Collected cycles: 0 Collected cycles: 2 minkey Collected cycles: 0 Collected cycles: 2 objectid Collected cycles: 0 Collected cycles: 2 regex Collected cycles: 0 Collected cycles: 2 symbol Collected cycles: 0 Collected cycles: 2 timestamp Collected cycles: 0 Collected cycles: 2 utcdatetime Collected cycles: 0 Collected cycles: 2 ===DONE=== mongodb-1.21.0/tests/bson/bug1839-005.phpt0000644000175100001660000000214714760300421014546 0ustar --TEST-- PHPC-1839: Referenced, out-of-scope, non-interned string in typeMap (PHP >= 8.1) --FILE-- &$rootValue, 'document' => &$documentValue]; return $typemap; } $typemap = createTypemap(); $bson = MongoDB\BSON\Document::fromPHP((object) []); echo "Before:\n"; debug_zval_dump($typemap); $bson->toPHP($typemap); echo "After:\n"; debug_zval_dump($typemap); ?> ===DONE=== --EXPECT-- Before: array(2) refcount(2){ ["root"]=> reference refcount(1) { string(5) "array" refcount(1) } ["document"]=> reference refcount(1) { string(5) "array" refcount(1) } } After: array(2) refcount(2){ ["root"]=> reference refcount(1) { string(5) "array" refcount(1) } ["document"]=> reference refcount(1) { string(5) "array" refcount(1) } } ===DONE=== mongodb-1.21.0/tests/bson/bug1839-006.phpt0000644000175100001660000000167514760300421014554 0ustar --TEST-- PHPC-1839: Referenced, local, non-interned string in typeMap (PHP >= 8.1) --FILE-- &$rootValue, 'document' => &$documentValue]; $bson = MongoDB\BSON\Document::fromPHP((object) []); echo "Before:\n"; debug_zval_dump($typemap); $bson->toPHP($typemap); echo "After:\n"; debug_zval_dump($typemap); ?> ===DONE=== --EXPECT-- Before: array(2) refcount(2){ ["root"]=> reference refcount(2) { string(5) "array" refcount(1) } ["document"]=> reference refcount(2) { string(5) "array" refcount(1) } } After: array(2) refcount(2){ ["root"]=> reference refcount(2) { string(5) "array" refcount(1) } ["document"]=> reference refcount(2) { string(5) "array" refcount(1) } } ===DONE=== mongodb-1.21.0/tests/bson/bug1839-007.phpt0000644000175100001660000000166614760300421014555 0ustar --TEST-- PHPC-1839: Referenced, out-of-scope, interned string in typeMap (PHP >= 8.1) --FILE-- &$rootValue, 'document' => &$documentValue]; return $typemap; } $typemap = createTypemap(); $bson = MongoDB\BSON\Document::fromPHP((object) []); echo "Before:\n"; debug_zval_dump($typemap); $bson->toPHP($typemap); echo "After:\n"; debug_zval_dump($typemap); ?> ===DONE=== --EXPECT-- Before: array(2) refcount(2){ ["root"]=> reference refcount(1) { string(5) "array" interned } ["document"]=> reference refcount(1) { string(5) "array" interned } } After: array(2) refcount(2){ ["root"]=> reference refcount(1) { string(5) "array" interned } ["document"]=> reference refcount(1) { string(5) "array" interned } } ===DONE=== mongodb-1.21.0/tests/bson/bug1839-008.phpt0000644000175100001660000000152314760300421014546 0ustar --TEST-- PHPC-1839: Referenced, local, interned string in typeMap (PHP >= 8.1) --FILE-- &$rootValue, 'document' => &$documentValue]; $bson = MongoDB\BSON\Document::fromPHP((object) []); echo "Before:\n"; debug_zval_dump($typemap); $bson->toPHP($typemap); echo "After:\n"; debug_zval_dump($typemap); ?> ===DONE=== --EXPECT-- Before: array(2) refcount(2){ ["root"]=> reference refcount(2) { string(5) "array" interned } ["document"]=> reference refcount(2) { string(5) "array" interned } } After: array(2) refcount(2){ ["root"]=> reference refcount(2) { string(5) "array" interned } ["document"]=> reference refcount(2) { string(5) "array" interned } } ===DONE=== mongodb-1.21.0/tests/bson/bug2456-001.phpt0000644000175100001660000000062214760300421014532 0ustar --TEST-- PHPC-2456: References passed in a typeMap --FILE-- &$fieldPaths]; var_dump(MongoDB\BSON\Document::fromPHP([])->toPHP($typeMap)); var_dump(MongoDB\BSON\PackedArray::fromPHP([])->toPHP($typeMap)); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (0) { } array(0) { } ===DONE=== mongodb-1.21.0/tests/bson/typemap-001.phpt0000644000175100001660000000757514760300421015131 0ustar --TEST-- MongoDB\Driver\Cursor::setTypeMap(): Setting typemaps --SKIPIF-- --FILE-- insert(array('_id' => 1, 'bson_array' => array(1, 2, 3), 'bson_object' => array("string" => "keys", "for" => "ever"))); $bulk->insert(array('_id' => 2, 'bson_array' => array(4, 5, 6))); $manager->executeBulkWrite(NS, $bulk); function fetch($manager, $typemap = array()) { $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array('bson_array' => 1))); if ($typemap) { $cursor->setTypeMap($typemap); } $documents = $cursor->toArray(); return $documents; } echo "Default\n"; $documents = fetch($manager); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->bson_array)); var_dump($documents[0]->bson_object instanceof stdClass); echo "\nSetting to 'MyArrayObject' for arrays\n"; $documents = fetch($manager, array("array" => "MyArrayObject")); var_dump($documents[0] instanceof stdClass); var_dump($documents[0]->bson_array instanceof MyArrayObject); var_dump($documents[0]->bson_object instanceof stdClass); echo "\nSetting to 'MyArrayObject' for arrays, embedded, and root documents\n"; $documents = fetch($manager, array("array" => "MyArrayObject", "document" => "MyArrayObject", "root" => "MyArrayObject")); var_dump($documents[0] instanceof MyArrayObject); var_dump($documents[0]['bson_array'] instanceof MyArrayObject); var_dump($documents[0]['bson_object'] instanceof MyArrayObject); echo "\nSetting to 'array' for arrays, embedded, and root documents\n"; $documents = fetch($manager, array("array" => "array", "document" => "array", "root" => "array")); var_dump(is_array($documents[0])); var_dump(is_array($documents[0]['bson_array'])); var_dump(is_array($documents[0]['bson_object'])); echo "\nSetting to 'stdclass' for arrays and 'array' for embedded and root documents\n"; $documents = fetch($manager, array("array" => "stdclass", "document" => "array", "root" => "array")); var_dump(is_array($documents[0])); var_dump($documents[0]['bson_array'] instanceof stdClass); var_dump(is_array($documents[0]['bson_object'])); echo "\nSetting to 'array' for arrays, 'stdclass' for embedded document, and 'MyArrayObject' for root document\n"; $documents = fetch($manager, array("array" => "array", "document" => "stdclass", "root" => "MyArrayObject")); var_dump($documents[0] instanceof MyArrayObject); var_dump(is_array($documents[0]['bson_array'])); var_dump($documents[0]['bson_object'] instanceof stdClass); echo "\nSetting to 'stdclass' for arrays, embedded, and root documents\n"; $documents = fetch($manager, array("array" => "stdclass", "document" => "stdclass", "root" => "stdclass")); var_dump($documents[0] instanceof stdClass); var_dump($documents[0]->bson_array instanceof stdClass); var_dump($documents[0]->bson_object instanceof stdClass); ?> ===DONE=== --EXPECT-- Default bool(true) bool(true) bool(true) Setting to 'MyArrayObject' for arrays bool(true) bool(true) bool(true) Setting to 'MyArrayObject' for arrays, embedded, and root documents bool(true) bool(true) bool(true) Setting to 'array' for arrays, embedded, and root documents bool(true) bool(true) bool(true) Setting to 'stdclass' for arrays and 'array' for embedded and root documents bool(true) bool(true) bool(true) Setting to 'array' for arrays, 'stdclass' for embedded document, and 'MyArrayObject' for root document bool(true) bool(true) bool(true) Setting to 'stdclass' for arrays, embedded, and root documents bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/typemap-002.phpt0000644000175100001660000000424714760300421015123 0ustar --TEST-- MongoDB\Driver\Cursor::setTypeMap(): Setting using type "object" --SKIPIF-- --FILE-- insert(array('_id' => 1, 'bson_array' => array(1, 2, 3), 'bson_object' => array("string" => "keys", "for" => "ever"))); $bulk->insert(array('_id' => 2, 'bson_array' => array(4, 5, 6))); $manager->executeBulkWrite(NS, $bulk); function fetch($manager, $typemap = array()) { $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array('bson_array' => 1))); if ($typemap) { $cursor->setTypeMap($typemap); } $documents = $cursor->toArray(); return $documents; } echo "Setting to 'object' for arrays and 'array' for embedded and root documents\n"; $documents = fetch($manager, array("array" => "object", "document" => "array", "root" => "array")); var_dump(is_array($documents[0])); var_dump($documents[0]['bson_array'] instanceof stdClass); var_dump(is_array($documents[0]['bson_object'])); echo "\nSetting to 'array' for arrays and 'object' for embedded and root documents\n"; $documents = fetch($manager, array("array" => "array", "document" => "object", "root" => "object")); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->bson_array)); var_dump($documents[0]->bson_object instanceof stdClass); echo "\nSetting to 'object' for arrays, embedded, and root documents\n"; $documents = fetch($manager, array("array" => "object", "document" => "object", "root" => "object")); var_dump($documents[0] instanceof stdClass); var_dump($documents[0]->bson_array instanceof stdClass); var_dump($documents[0]->bson_object instanceof stdClass); ?> ===DONE=== --EXPECT-- Setting to 'object' for arrays and 'array' for embedded and root documents bool(true) bool(true) bool(true) Setting to 'array' for arrays and 'object' for embedded and root documents bool(true) bool(true) bool(true) Setting to 'object' for arrays, embedded, and root documents bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/typemap-003.phpt0000644000175100001660000000377614760300421015132 0ustar --TEST-- MongoDB\Driver\Cursor::setTypeMap(): Setting and replacing typemaps --SKIPIF-- --FILE-- 1, 'array' => [1, 2, 3], 'object' => ['string' => ['sleutels', 'keys'] ] ]; $document2 = [ '_id' => 2, 'array' => [4, 5, 6], 'object' => ['associative' => ['elementen', 'elements' ]] ]; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert($document1); $bulk->insert($document2); $manager->executeBulkWrite(NS, $bulk); $typemap1 = ["fieldPaths" => [ 'object.string' => "MyArrayObject", 'object' => "MyArrayObject", ]]; $typemap2 = ["fieldPaths" => [ 'object.associative' => "MyProperties", 'object' => "MyArrayObject", ]]; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); $cursor->setTypeMap($typemap1); $cursor->setTypeMap($typemap2); $documents = $cursor->toArray(); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->array)); var_dump($documents[0]->object instanceof MyArrayObject); var_dump(is_array($documents[0]->object['string'])); var_dump(is_array($documents[0]->object->string)); var_dump($documents[1] instanceof stdClass); var_dump(is_array($documents[1]->array)); var_dump($documents[1]->object instanceof MyArrayObject); var_dump($documents[1]->object['associative'] instanceof MyProperties); var_dump($documents[1]->object->associative instanceof MyProperties); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/typemap-004.phpt0000644000175100001660000000375614760300421015131 0ustar --TEST-- MongoDB\Driver\Cursor::setTypeMap(): Setting fieldPath typemaps for compound types with string keys --SKIPIF-- --FILE-- 1, 'array' => [1, 2, 3], 'object' => ['string' => 'keys', 'for' => 'ever'] ]; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert($document); $manager->executeBulkWrite(NS, $bulk); function fetch($manager, $typemap = []) { $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); if ($typemap) { $cursor->setTypeMap($typemap); } return $cursor->toArray(); } echo "Default\n"; $documents = fetch($manager); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->array)); var_dump($documents[0]->object instanceof stdClass); echo "\nSetting 'object' path to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object' => "MyArrayObject" ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->array)); var_dump($documents[0]->object instanceof MyArrayObject); echo "\nSetting 'object' and 'array' path to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object' => "MyArrayObject", 'array' => "MyArrayObject", ]]); var_dump($documents[0] instanceof stdClass); var_dump($documents[0]->array instanceof MyArrayObject); var_dump($documents[0]->object instanceof MyArrayObject); ?> ===DONE=== --EXPECT-- Default bool(true) bool(true) bool(true) Setting 'object' path to 'MyArrayObject' bool(true) bool(true) bool(true) Setting 'object' and 'array' path to 'MyArrayObject' bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/typemap-005.phpt0000644000175100001660000000515214760300421015122 0ustar --TEST-- MongoDB\Driver\Cursor::setTypeMap(): Setting fieldPath typemaps for compound types with numerical keys --SKIPIF-- --FILE-- 1, 'array0' => [0 => [ 4, 5, 6 ], 1 => [ 7, 8, 9 ]], 'array1' => [1 => [ 4, 5, 6 ], 2 => [ 7, 8, 9 ]], ]; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert($document); $manager->executeBulkWrite(NS, $bulk); function fetch($manager, $typemap = []) { $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); if ($typemap) { $cursor->setTypeMap($typemap); } $documents = $cursor->toArray(); return $documents; } echo "Default\n"; $documents = fetch($manager); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->array0)); var_dump(is_object($documents[0]->array1)); var_dump($documents[0]->array1 instanceof stdClass); echo "\nSetting 'array0' path to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'array0' => "MyArrayObject" ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_object($documents[0]->array0)); var_dump($documents[0]->array0 instanceof MyArrayObject); echo "\nSetting 'array0.1' path to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'array0.1' => "MyArrayObject", ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->array0)); var_dump(is_array($documents[0]->array0[0])); var_dump($documents[0]->array0[1] instanceof MyArrayObject); echo "\nSetting 'array1.1' path to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'array1.1' => "MyArrayObject", ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_object($documents[0]->array1)); var_dump($documents[0]->array1 instanceof stdClass); $a = ((array) $documents[0]->array1); var_dump($a[1] instanceof MyArrayObject); var_dump(is_array($a[2])); ?> ===DONE=== --EXPECT-- Default bool(true) bool(true) bool(true) bool(true) Setting 'array0' path to 'MyArrayObject' bool(true) bool(true) bool(true) Setting 'array0.1' path to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'array1.1' path to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/typemap-006.phpt0000644000175100001660000001100514760300421015115 0ustar --TEST-- MongoDB\Driver\Cursor::setTypeMap(): Setting fieldPath typemaps for compound types with wildcard keys --SKIPIF-- --FILE-- 1, 'array' => [0 => [ 4, 5, 6 ], 1 => [ 7, 8, 9 ]], 'object' => ['one' => [ 4, 5, 6 ], 'two' => [ 7, 8, 9 ]], ]; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert($document); $manager->executeBulkWrite(NS, $bulk); function fetch($manager, $typemap = []) { $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); if ($typemap) { $cursor->setTypeMap($typemap); } $documents = $cursor->toArray(); return $documents; } echo "\nSetting 'array.$' path to 'MyWildcardArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'array.$' => "MyWildcardArrayObject" ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->array)); var_dump($documents[0]->array[0] instanceof MyWildcardArrayObject); var_dump($documents[0]->array[1] instanceof MyWildcardArrayObject); echo "\nSetting 'array.1' to 'MyArrayObject' and 'array.$' path to 'MyWildcardArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'array.1' => "MyArrayObject", 'array.$' => "MyWildcardArrayObject" ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->array)); var_dump($documents[0]->array[0] instanceof MyWildcardArrayObject); var_dump($documents[0]->array[1] instanceof MyArrayObject); echo "\nSetting 'array.$' to 'MyWildcardArrayObject' and 'array.1' path to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'array.$' => "MyWildcardArrayObject", 'array.1' => "MyArrayObject" ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_array($documents[0]->array)); var_dump($documents[0]->array[0] instanceof MyWildcardArrayObject); var_dump($documents[0]->array[1] instanceof MyWildcardArrayObject); echo "\nSetting 'object.$' path to 'MyWildcardArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object.$' => "MyWildcardArrayObject" ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_object($documents[0]->object)); var_dump($documents[0]->object->one instanceof MyWildcardArrayObject); var_dump($documents[0]->object->two instanceof MyWildcardArrayObject); echo "\nSetting 'object.two' to 'MyArrayObject' and 'object.$' path to 'MyWildcardArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object.two' => "MyArrayObject", 'object.$' => "MyWildcardArrayObject" ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_object($documents[0]->object)); var_dump($documents[0]->object->one instanceof MyWildcardArrayObject); var_dump($documents[0]->object->two instanceof MyArrayObject); echo "\nSetting 'object.$' to 'MyWildcardArrayObject' and 'object.one' path to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object.$' => "MyWildcardArrayObject", 'object.one' => "MyArrayObject" ]]); var_dump($documents[0] instanceof stdClass); var_dump(is_object($documents[0]->object)); var_dump($documents[0]->object->one instanceof MyWildcardArrayObject); var_dump($documents[0]->object->two instanceof MyWildcardArrayObject); ?> ===DONE=== --EXPECT-- Setting 'array.$' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'array.1' to 'MyArrayObject' and 'array.$' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'array.$' to 'MyWildcardArrayObject' and 'array.1' path to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'object.$' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'object.two' to 'MyArrayObject' and 'object.$' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) Setting 'object.$' to 'MyWildcardArrayObject' and 'object.one' path to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bson/typemap-007.phpt0000644000175100001660000001255114760300421015125 0ustar --TEST-- MongoDB\Driver\Cursor::setTypeMap(): Setting fieldPath typemaps for compound types with wildcard keys (nested) --SKIPIF-- --FILE-- 1, 'object' => [ 'parent1' => [ 'child1' => [ 1, 2, 3 ], 'child2' => [ 4, 5, 6 ], ], 'parent2' => [ 'child1' => [ 7, 8, 9 ], 'child2' => [ 10, 11, 12 ], ], ], ]; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert($document); $manager->executeBulkWrite(NS, $bulk); function fetch($manager, $typemap = []) { $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); if ($typemap) { $cursor->setTypeMap($typemap); } $documents = $cursor->toArray(); return $documents; } echo "\nSetting 'object.$.child1' path to 'MyWildcardArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object.$.child1' => "MyWildcardArrayObject" ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump(is_array($documents[0]->object->parent1->child2)); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump($documents[0]->object->parent2->child1 instanceof MyWildcardArrayObject); var_dump(is_array($documents[0]->object->parent2->child2)); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.parent2.child1' to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object.parent1.$' => "MyWildcardArrayObject", 'object.parent2.child1' => "MyArrayObject", ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($documents[0]->object->parent1->child2 instanceof MyWildcardArrayObject); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump($documents[0]->object->parent2->child1 instanceof MyArrayObject); var_dump(is_array($documents[0]->object->parent2->child2)); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.$' to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object.parent1.$' => "MyWildcardArrayObject", 'object.$.$' => "MyArrayObject", ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($documents[0]->object->parent1->child2 instanceof MyWildcardArrayObject); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump($documents[0]->object->parent2->child1 instanceof MyArrayObject); var_dump($documents[0]->object->parent2->child2 instanceof MyArrayObject); echo "\nSetting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.child2' to 'MyArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object.parent1.child1' => "MyWildcardArrayObject", 'object.$.child2' => "MyArrayObject", ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($documents[0]->object->parent1->child2 instanceof MyArrayObject); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump(is_array($documents[0]->object->parent2->child1)); var_dump($documents[0]->object->parent2->child2 instanceof MyArrayObject); echo "\nSetting 'object.parent1.child2 path to 'MyArrayObject' and 'object.$.$' to 'MyWildcardArrayObject'\n"; $documents = fetch($manager, ["fieldPaths" => [ 'object.parent1.child2' => "MyArrayObject", 'object.$.$' => "MyWildcardArrayObject", ]]); var_dump($documents[0]->object->parent1 instanceof stdClass); var_dump($documents[0]->object->parent1->child1 instanceof MyWildcardArrayObject); var_dump($documents[0]->object->parent1->child2 instanceof MyArrayObject); var_dump($documents[0]->object->parent2 instanceof stdClass); var_dump($documents[0]->object->parent2->child1 instanceof MyWildcardArrayObject); var_dump($documents[0]->object->parent2->child2 instanceof MyWildcardArrayObject); ?> ===DONE=== --EXPECT-- Setting 'object.$.child1' path to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.parent2.child1' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.$' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.$' path to 'MyWildcardArrayObject' and 'object.$.child2' to 'MyArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Setting 'object.parent1.child2 path to 'MyArrayObject' and 'object.$.$' to 'MyWildcardArrayObject' bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/bulk/bug0667.phpt0000644000175100001660000000067314760300421014240 0ustar --TEST-- PHPC-667: BulkWrite::insert() does not generate ObjectId if another field has "_id" prefix --FILE-- insert(['_ids' => 1])); var_dump($bulk->insert((object) ['_ids' => 1])); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-count-001.phpt0000644000175100001660000000117614760300421016573 0ustar --TEST-- MongoDB\Driver\BulkWrite::count() should return the number of operations --FILE-- count()); $bulk->insert(['x' => 1]); var_dump($bulk->count()); $bulk->insert(['x' => 2]); var_dump($bulk->count()); $bulk->update(['x' => 3], ['$set' => ['y' => 3]]); var_dump($bulk->count()); $bulk->update(['x' => 4], ['$set' => ['y' => 4]]); var_dump($bulk->count()); $bulk->delete(['x' => 5]); var_dump($bulk->count()); $bulk->delete(['x' => 6]); var_dump($bulk->count()); ?> ===DONE=== --EXPECT-- int(0) int(1) int(2) int(3) int(4) int(5) int(6) ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-countable-001.phpt0000644000175100001660000000032514760300421017412 0ustar --TEST-- MongoDB\Driver\BulkWrite implements Countable --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-ctor-comment-001.phpt0000644000175100001660000000330614760300421020047 0ustar --TEST-- MongoDB\Driver\BulkWrite::__construct(): comment option --SKIPIF-- --FILE-- getCommand(); if (!isset($command->comment)) { printf("%s does not include comment option\n", $event->getCommandName()); return; } printf("%s included comment: %s\n", $event->getCommandName(), json_encode($command->comment)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(['comment' => ['foo' => 1]]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->delete(['_id' => 1]); $bulk->update(['_id' => 2], ['$set' => ['x' => 1]]); $manager->addSubscriber(new CommandLogger); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- insert included comment: {"foo":1} delete included comment: {"foo":1} update included comment: {"foo":1} find does not include comment option array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-ctor-comment_error-001.phpt0000644000175100001660000000110414760300421021252 0ustar --TEST-- MongoDB\Driver\BulkWrite::__construct(): comment option bsonSerialize() exception --FILE-- new Comment()]); }, Exception::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got Exception phongo_zval_to_bson_value fails ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-ctor-let-001.phpt0000644000175100001660000000335414760300421017174 0ustar --TEST-- MongoDB\Driver\BulkWrite::__construct(): let option --SKIPIF-- --FILE-- getCommand(); if (!isset($command->let)) { printf("%s does not include let option\n", $event->getCommandName()); return; } printf("%s included let: %s\n", $event->getCommandName(), json_encode($command->let)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(['let' => ['id' => 1, 'x' => 'foo']]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->delete(['$expr' => ['$eq' => ['$_id', '$$id']]]); $bulk->update(['_id' => 2], [['$set' => ['x' => '$$x']]]); $manager->addSubscriber(new CommandLogger); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- insert does not include let option delete included let: {"id":1,"x":"foo"} update included let: {"id":1,"x":"foo"} find does not include let option array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["x"]=> string(3) "foo" } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-ctor-let_error-001.phpt0000644000175100001660000000231214760300421020376 0ustar --TEST-- MongoDB\Driver\BulkWrite::__construct(): let option invalid type --FILE-- $invalidValue]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } echo throws(function() { new MongoDB\Driver\BulkWrite(['let' => MongoDB\BSON\PackedArray::fromPHP([])]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "let" option to be array or object, bool given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "let" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "let" option to be array or object, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "let" option to be array or object, null given OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-debug-001.phpt0000644000175100001660000000500414760300421016523 0ustar --TEST-- MongoDB\Driver\BulkWrite debug output before execution --FILE-- true], ['ordered' => false], ['bypassDocumentValidation' => true], ['bypassDocumentValidation' => false], ['comment' => ['foo' => 1]], ['let' => ['id' => 1, 'x' => 'foo']], ]; foreach ($tests as $options) { var_dump(new MongoDB\Driver\BulkWrite($options)); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(false) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> bool(true) ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> bool(false) ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["comment"]=> object(stdClass)#%d (%d) { ["foo"]=> int(1) } ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["let"]=> object(stdClass)#%d (%d) { ["id"]=> int(1) ["x"]=> string(3) "foo" } ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-debug-002.phpt0000644000175100001660000000224214760300421016525 0ustar --TEST-- MongoDB\Driver\BulkWrite debug output after execution --SKIPIF-- --FILE-- $manager->startSession()], ]; foreach ($tests as $options) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['foo' => 'bar']); $manager->executeBulkWrite(NS, $bulk, $options); var_dump($bulk); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> %s ["collection"]=> %s ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(true) ["server_id"]=> int(%d) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> %s ["collection"]=> %s ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(true) ["server_id"]=> int(%d) ["session"]=> object(MongoDB\Driver\Session)#%d (%d) { %a } ["write_concern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-delete-001.phpt0000644000175100001660000000374514760300421016711 0ustar --TEST-- MongoDB\Driver\BulkWrite::delete() should always encode __pclass for Persistable objects --SKIPIF-- --FILE-- id = $id; $this->child = $child; } #[\ReturnTypeWillChange] public function bsonSerialize() { return [ '_id' => $this->id, 'child' => $this->child, ]; } public function bsonUnserialize(array $data): void { $this->id = $data['_id']; $this->child = $data['child']; } } $manager = create_test_manager(); $document = new MyClass('foo', new MyClass('bar', new MyClass('baz'))); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert($document); $result = $manager->executeBulkWrite(NS, $bulk); printf("Inserted %d document(s)\n", $result->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->delete($document); $result = $manager->executeBulkWrite(NS, $bulk); printf("Deleted %d document(s)\n", $result->getDeletedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- Inserted 1 document(s) array(1) { [0]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "foo" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "bar" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "baz" ["child":"MyClass":private]=> NULL } } } } Deleted 1 document(s) array(0) { } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-delete-002.phpt0000644000175100001660000000272314760300421016705 0ustar --TEST-- MongoDB\Driver\BulkWrite::delete() with hint option --SKIPIF-- --FILE-- getCommandName() !== 'delete') { return; } printf("delete included hint: %s\n", json_encode($event->getCommand()->deletes[0]->hint)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $bulk = new MongoDB\Driver\BulkWrite; $bulk->delete(['_id' => 1], ['hint' => '_id_']); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite; $bulk->delete(['_id' => 2], ['hint' => ['_id' => 1]]); $manager->executeBulkWrite(NS, $bulk); ?> ===DONE=== --EXPECTF-- delete included hint: "_id_" delete included hint: {"_id":1} ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-delete-003.phpt0000644000175100001660000000132314760300421016701 0ustar --TEST-- MongoDB\Driver\BulkWrite::delete() $filter is MongoDB\BSON\Document --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $manager->executeBulkWrite(NS, $bulk); $filter = MongoDB\BSON\Document::fromJSON('{ "_id": { "$gt": 1 } }'); $bulk = new MongoDB\Driver\BulkWrite; $bulk->delete($filter); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getDeletedCount()); ?> ===DONE=== --EXPECT-- int(1) ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-delete_error-001.phpt0000644000175100001660000000137514760300421020117 0ustar --TEST-- MongoDB\Driver\BulkWrite::delete() with invalid options --FILE-- delete(['x' => 1], ['collation' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->delete(['x' => 1], ['hint' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "collation" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "hint" option to be string, array, or object, int given ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-delete_error-002.phpt0000644000175100001660000000141514760300421020113 0ustar --TEST-- MongoDB\Driver\BulkWrite::delete() with BSON encoding error (invalid UTF-8 string) --FILE-- delete(['x' => "\xc3\x28"]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->delete(['x' => 1], ['collation' => ['locale' => "\xc3\x28"]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected invalid UTF-8 for field path "x": %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected invalid UTF-8 for field path "locale": %s ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-delete_error-003.phpt0000644000175100001660000000357214760300421020122 0ustar --TEST-- MongoDB\Driver\BulkWrite::delete() with BSON encoding error (null bytes in keys) --FILE-- delete(["\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->delete(["x\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->delete(["\0\0\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->delete(['x' => 1], ['collation' => ["\0" => 1]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->delete(['x' => 1], ['collation' => ["x\0" => 1]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->delete(['x' => 1], ['collation' => ["\0\0\0" => 1]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "x". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "x". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-delete_error-004.phpt0000644000175100001660000000216314760300421020116 0ustar --TEST-- MongoDB\Driver\BulkWrite::delete() prohibits PackedArray for document values --FILE-- delete(MongoDB\BSON\PackedArray::fromPHP([])); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; echo throws(function() use ($bulk) { $bulk->delete([], ['collation' => MongoDB\BSON\PackedArray::fromPHP([])]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; echo throws(function() use ($bulk) { $bulk->delete([], ['hint' => MongoDB\BSON\PackedArray::fromPHP([])]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-delete_error-005.phpt0000644000175100001660000000133714760300421020121 0ustar --TEST-- MongoDB\Driver\BulkWrite::delete() hint option requires MongoDB 4.4 (server-side error) --SKIPIF-- =', '4.3.4'); ?> --FILE-- delete(['_id' => 1], ['hint' => '_id_']); echo throws(function() use ($manager, $bulk) { $manager->executeBulkWrite(NS, $bulk); }, 'MongoDB\Driver\Exception\BulkWriteException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\BulkWriteException BSON field 'delete.deletes.hint' is an unknown field. ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-insert-001.phpt0000644000175100001660000000322314760300421016742 0ustar --TEST-- MongoDB\Driver\BulkWrite::insert() should always encode __pclass for Persistable objects --SKIPIF-- --FILE-- id = $id; $this->child = $child; } #[\ReturnTypeWillChange] public function bsonSerialize() { return [ '_id' => $this->id, 'child' => $this->child, ]; } public function bsonUnserialize(array $data): void { $this->id = $data['_id']; $this->child = $data['child']; } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(new MyClass('foo', new MyClass('bar', new MyClass('baz')))); $result = $manager->executeBulkWrite(NS, $bulk); printf("Inserted %d document(s)\n", $result->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- Inserted 1 document(s) array(1) { [0]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "foo" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "bar" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "baz" ["child":"MyClass":private]=> NULL } } } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-insert-002.phpt0000644000175100001660000000116314760300421016744 0ustar --TEST-- MongoDB\Driver\BulkWrite::insert() $document is MongoDB\BSON\Document --SKIPIF-- --FILE-- insert($document); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($insertedId); var_dump($result->getInsertedCount()); ?> ===DONE=== --EXPECT-- int(2) int(1) ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-insert-003.phpt0000644000175100001660000000214614760300421016747 0ustar --TEST-- MongoDB\Driver\BulkWrite::insert() appends ID when inserting Document instances --SKIPIF-- --FILE-- 'bar']); $bulk = new MongoDB\Driver\BulkWrite(); $insertedId = $bulk->insert($document); $result = $manager->executeBulkWrite(NS, $bulk); printf("Inserted %d document(s)\n", $result->getInsertedCount()); var_dump($insertedId); var_dump($document->toPHP()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- Inserted 1 document(s) object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } ["foo"]=> string(3) "bar" } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-insert-004.phpt0000644000175100001660000000464014760300421016751 0ustar --TEST-- MongoDB\Driver\BulkWrite::insert() returns "_id" of inserted document --SKIPIF-- --FILE-- id = $id; } #[\ReturnTypeWillChange] public function bsonSerialize() { return ['id' => $this->id]; } } class MyPersistableId extends MySerializableId implements MongoDB\BSON\Persistable { public function bsonUnserialize(array $data): void { $this->id = $data['id']; } } $documents = [ ['x' => 1], ['_id' => new MongoDB\BSON\ObjectId('590b72d606e9660190656a55')], ['_id' => ['foo' => 1]], ['_id' => new MySerializableId('foo')], ['_id' => new MyPersistableId('bar')], ]; $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); foreach ($documents as $document) { var_dump($bulk->insert($document)); } $result = $manager->executeBulkWrite(NS, $bulk); printf("Inserted %d document(s)\n", $result->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "590b72d606e9660190656a55" } object(stdClass)#%d (%d) { ["foo"]=> int(1) } object(stdClass)#%d (%d) { ["id"]=> string(3) "foo" } object(MyPersistableId)#%d (%d) { ["id"]=> string(3) "bar" } Inserted 5 document(s) array(5) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } ["x"]=> int(1) } [1]=> object(stdClass)#%d (%d) { ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "590b72d606e9660190656a55" } } [2]=> object(stdClass)#%d (%d) { ["_id"]=> object(stdClass)#%d (%d) { ["foo"]=> int(1) } } [3]=> object(stdClass)#%d (%d) { ["_id"]=> object(stdClass)#%d (%d) { ["id"]=> string(3) "foo" } } [4]=> object(stdClass)#%d (%d) { ["_id"]=> object(MyPersistableId)#%d (%d) { ["id"]=> string(3) "bar" } } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-insert_error-001.phpt0000644000175100001660000000127314760300421020156 0ustar --TEST-- MongoDB\Driver\BulkWrite::insert() with invalid insert document --FILE-- insert(['' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->insert(["\xc3\x28" => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException invalid document for insert: empty key OK: Got MongoDB\Driver\Exception\InvalidArgumentException invalid document for insert: corrupt BSON ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-insert_error-002.phpt0000644000175100001660000000075614760300421020164 0ustar --TEST-- MongoDB\Driver\BulkWrite::insert() with BSON encoding error (invalid UTF-8 string) --FILE-- insert(['x' => "\xc3\x28"]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected invalid UTF-8 for field path "x": %s ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-insert_error-003.phpt0000644000175100001660000000201314760300421020151 0ustar --TEST-- MongoDB\Driver\BulkWrite::insert() with BSON encoding error (null bytes in keys) --FILE-- insert(["\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->insert(["x\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->insert(["\0\0\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "x". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-insert_error-004.phpt0000644000175100001660000000101214760300421020150 0ustar --TEST-- MongoDB\Driver\BulkWrite::insert() prohibits PackedArray for document --FILE-- insert(MongoDB\BSON\PackedArray::fromPHP([])); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update-001.phpt0000644000175100001660000000477114760300421016731 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() should always encode __pclass for Persistable objects --SKIPIF-- --FILE-- id = $id; $this->child = $child; } #[\ReturnTypeWillChange] public function bsonSerialize() { return [ '_id' => $this->id, 'child' => $this->child, ]; } public function bsonUnserialize(array $data): void { $this->id = $data['_id']; $this->child = $data['child']; } } $manager = create_test_manager(); $document = new MyClass('foo', new MyClass('bar', new MyClass('baz'))); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update( ['_id' => 'foo'], $document, ['upsert' => true] ); $result = $manager->executeBulkWrite(NS, $bulk); printf("Upserted %d document(s)\n", $result->getUpsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update( $document, ['$set' => ['child' => new MyClass('yip', new MyClass('yap'))]] ); $result = $manager->executeBulkWrite(NS, $bulk); printf("Modified %d document(s)\n", $result->getModifiedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- Upserted 1 document(s) array(1) { [0]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "foo" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "bar" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "baz" ["child":"MyClass":private]=> NULL } } } } Modified 1 document(s) array(1) { [0]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "foo" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "yip" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "yap" ["child":"MyClass":private]=> NULL } } } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update-002.phpt0000644000175100001660000000326714760300421016731 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with arrayFilters option --SKIPIF-- --FILE-- insert([ '_id' => 1, 'grades' => [ 95, 92, 90 ] ]); $bulk->insert([ '_id' => 2, 'grades' => [ 98, 100, 102 ] ]); $bulk->insert([ '_id' => 3, 'grades' => [ 95, 110, 100 ] ]); $manager->executeBulkWrite(DATABASE_NAME . '.' . COLLECTION_NAME, $bulk); $updateBulk = new MongoDB\Driver\BulkWrite(); $query = ['grades' => ['$gte' => 100]]; $update = [ '$set' => [ 'grades.$[element]' => 100 ] ]; $options = [ 'arrayFilters' => [ [ 'element' => [ '$gte' => 100 ] ] ], 'multi' => true ]; $updateBulk->update($query, $update, $options); $manager->executeBulkWrite(DATABASE_NAME . '.' . COLLECTION_NAME, $updateBulk); $cursor = $manager->executeQuery( DATABASE_NAME . '.' . COLLECTION_NAME, new \MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- array(%d) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["grades"]=> array(%d) { [0]=> int(95) [1]=> int(92) [2]=> int(90) } } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["grades"]=> array(%d) { [0]=> int(98) [1]=> int(100) [2]=> int(100) } } [2]=> object(stdClass)#%d (%d) { ["_id"]=> int(3) ["grades"]=> array(%d) { [0]=> int(95) [1]=> int(100) [2]=> int(100) } } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update-003.phpt0000644000175100001660000000240114760300421016717 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with pipeline option --SKIPIF-- --FILE-- insert([ '_id' => 1, 'x' => 1, 'y' => 1, 't' => [ 'u' => [ 'v' => 1 ] ] ]); $bulk->insert([ '_id' => 2, 'x' => 2, 'y' => 1]); $manager->executeBulkWrite(NS, $bulk); $updateBulk = new MongoDB\Driver\BulkWrite(); $query = ['_id' => 1]; $update = [ [ '$replaceRoot' => [ 'newRoot' => '$t' ], ], [ '$addFields' => [ 'foo' => 1 ], ], ]; $updateBulk->update($query, $update); $manager->executeBulkWrite(NS, $updateBulk); $cursor = $manager->executeQuery(NS, new \MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- array(%d) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["u"]=> object(stdClass)#%d (%d) { ["v"]=> int(1) } ["foo"]=> int(1) } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["x"]=> int(2) ["y"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update-004.phpt0000644000175100001660000000300314760300421016717 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with hint option --SKIPIF-- --FILE-- getCommandName() !== 'update') { return; } printf("update included hint: %s\n", json_encode($event->getCommand()->updates[0]->hint)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['_id' => 1], ['$set' => ['x' => 11]], ['hint' => '_id_']); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['_id' => 2], ['$set' => ['x' => 22]], ['hint' => ['_id' => 1]]); $manager->executeBulkWrite(NS, $bulk); ?> ===DONE=== --EXPECTF-- update included hint: "_id_" update included hint: {"_id":1} ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update-005.phpt0000644000175100001660000000153414760300421016727 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() $filter and $newObj are MongoDB\BSON\Document --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $manager->executeBulkWrite(NS, $bulk); $filter = MongoDB\BSON\Document::fromJSON('{ "_id": { "$gt": 1 } }'); $newObj = MongoDB\BSON\Document::fromJSON('{ "$set": { "x": 1 } }'); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update($filter, $newObj); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getMatchedCount()); var_dump($result->getModifiedCount()); ?> ===DONE=== --EXPECT-- int(1) int(1) ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update-006.phpt0000644000175100001660000000237114760300421016730 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() PackedArray for update pipeline --SKIPIF-- --FILE-- insert(['_id' => 1, 'x' => 1, 'y' => 1, 't' => ['u' => ['v' => 1]]]); $bulk->insert(['_id' => 2, 'x' => 2, 'y' => 1]); $manager->executeBulkWrite(NS, $bulk); $updateBulk = new MongoDB\Driver\BulkWrite(); $updateBulk->update( ['_id' => 1], MongoDB\BSON\PackedArray::fromPHP([ ['$replaceRoot' => ['newRoot' => '$t']], ['$addFields' => ['foo' => 1]], ]) ); $manager->executeBulkWrite(NS, $updateBulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- array(%d) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["u"]=> object(stdClass)#%d (%d) { ["v"]=> int(1) } ["foo"]=> int(1) } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["x"]=> int(2) ["y"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update-007.phpt0000644000175100001660000000311014760300421016721 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() PackedArray for arrayFilters option --SKIPIF-- --FILE-- insert(['_id' => 1, 'grades' => [95, 92, 90]]); $bulk->insert(['_id' => 2, 'grades' => [98, 100, 102]]); $bulk->insert(['_id' => 3, 'grades' => [95, 110, 100]]); $manager->executeBulkWrite(NS, $bulk); $updateBulk = new MongoDB\Driver\BulkWrite(); $updateBulk->update( ['grades' => ['$gte' => 100]], ['$set' => ['grades.$[element]' => 100]], [ 'arrayFilters' => MongoDB\BSON\PackedArray::fromPHP([['element' => ['$gte' => 100]]]), 'multi' => true, ] ); $manager->executeBulkWrite(NS, $updateBulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- array(%d) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["grades"]=> array(%d) { [0]=> int(95) [1]=> int(92) [2]=> int(90) } } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["grades"]=> array(%d) { [0]=> int(98) [1]=> int(100) [2]=> int(100) } } [2]=> object(stdClass)#%d (%d) { ["_id"]=> int(3) ["grades"]=> array(%d) { [0]=> int(95) [1]=> int(100) [2]=> int(100) } } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update-008.phpt0000644000175100001660000000364014760300421016732 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with sort option --SKIPIF-- --FILE-- getCommandName() !== 'update') { return; } printf("update included sort: %s\n", json_encode($event->getCommand()->updates[0]->sort)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['_id' => ['$gt' => 1]], ['$set' => ['x' => 11]], ['sort' => ['_id' => 1]]); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['_id' => ['$gt' => 1]], ['x' => 22], ['sort' => ['_id' => -1]]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- update included sort: {"_id":1} update included sort: {"_id":-1} array(3) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["x"]=> int(11) } [2]=> object(stdClass)#%d (%d) { ["_id"]=> int(3) ["x"]=> int(22) } } ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update_error-001.phpt0000644000175100001660000000133114760300421020127 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with invalid replacement document --FILE-- update(['x' => 1], ['' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ["\xc3\x28" => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException invalid argument for replace: empty key OK: Got MongoDB\Driver\Exception\InvalidArgumentException invalid argument for replace: corrupt BSON ===DONE===mongodb-1.21.0/tests/bulk/bulkwrite-update_error-002.phpt0000644000175100001660000000244414760300421020136 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with invalid update document --FILE-- update(['x' => 1], ['$set' => ['x' => ['' => 1]]]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['$set' => ['x' => ["\xc3\x28" => 1]]]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; /* This newObj argument mixes an update and replacement document, but * php_phongo_bulkwrite_update_has_operators() will categorize it as an update * due to the presence of an atomic operator. As such, _mongoc_validate_update() * will report the error. */ echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['$set' => ['y' => 1], 'z' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException invalid argument for update: empty key OK: Got MongoDB\Driver\Exception\InvalidArgumentException invalid argument for update: corrupt BSON OK: Got MongoDB\Driver\Exception\InvalidArgumentException Invalid key 'z': update only works with $ operators and pipelines ===DONE===mongodb-1.21.0/tests/bulk/bulkwrite-update_error-003.phpt0000644000175100001660000000371214760300421020136 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with invalid options --FILE-- update(['x' => 1], ['y' => 1], ['multi' => true]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['y' => 1], ['collation' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['$set' => ['y' => 1]], ['collation' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['$set' => ['y' => 1]], ['arrayFilters' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['$set' => ['y' => 1]], ['arrayFilters' => ['foo' => 'bar']]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['$set' => ['y' => 1]], ['hint' => 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Replacement document conflicts with true "multi" option OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "collation" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "collation" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "arrayFilters" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException "arrayFilters" option has invalid keys for a BSON array OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "hint" option to be string, array, or object, int given ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update_error-004.phpt0000644000175100001660000000247614760300421020145 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with BSON encoding error (invalid UTF-8 string) --FILE-- update(['x' => "\xc3\x28"], ['x' => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['x' => "\xc3\x28"]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['$set' => ['x' => "\xc3\x28"]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['y' => 1], ['collation' => ['locale' => "\xc3\x28"]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected invalid UTF-8 for field path "x": %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected invalid UTF-8 for field path "x": %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected invalid UTF-8 for field path "$set.x": %s OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected invalid UTF-8 for field path "locale": %s ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update_error-005.phpt0000644000175100001660000000537614760300421020150 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with BSON encoding error (null bytes in keys) --FILE-- update(["\0" => 1], ['x' => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(["x\0" => 1], ['x' => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(["\0\0\0" => 1], ['x' => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ["\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ["x\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ["\0\0\0" => 1]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['y' => 1], ['collation' => ["\0" => 1]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['y' => 1], ['collation' => ["x\0" => 1]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n\n"; echo throws(function() use ($bulk) { $bulk->update(['x' => 1], ['y' => 1], ['collation' => ["\0\0\0" => 1]]); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "x". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "x". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "x". OK: Got MongoDB\Driver\Exception\UnexpectedValueException BSON keys cannot contain null bytes. Unexpected null byte after "". ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update_error-006.phpt0000644000175100001660000000217714760300421020145 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() prohibits PackedArray for document values --FILE-- update(MongoDB\BSON\PackedArray::fromPHP([]), []); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; echo throws(function() use ($bulk) { $bulk->update([], [], ['collation' => MongoDB\BSON\PackedArray::fromPHP([])]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; echo throws(function() use ($bulk) { $bulk->update([], [], ['hint' => MongoDB\BSON\PackedArray::fromPHP([])]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update_error-008.phpt0000644000175100001660000000136614760300421020146 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() hint option requires MongoDB 4.2 (server-side error) --SKIPIF-- =', '4.2'); ?> --FILE-- update(['_id' => 1], ['$set' => ['x' => 11]], ['hint' => '_id_']); echo throws(function() use ($manager, $bulk) { $manager->executeBulkWrite(NS, $bulk); }, 'MongoDB\Driver\Exception\BulkWriteException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\BulkWriteException BSON field 'update.updates.hint' is an unknown field. ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite-update_error-009.phpt0000644000175100001660000000120314760300421020135 0ustar --TEST-- MongoDB\Driver\BulkWrite::update() with multi:true prohibits sort option --SKIPIF-- --FILE-- update(['x' => ['$gt' => 1]], ['$set' => ['y' => 11]], ['multi' => true, 'sort' => ['x' => 1]]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Invalid option 'sort' ===DONE=== mongodb-1.21.0/tests/bulk/bulkwrite_error-001.phpt0000644000175100001660000000040414760300421016647 0ustar --TEST-- MongoDB\Driver\BulkWrite cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyBulkWrite %s final class %SMongoDB\Driver\BulkWrite%S in %s on line %d mongodb-1.21.0/tests/bulk/bulkwrite_error-002.phpt0000644000175100001660000000153514760300421016656 0ustar --TEST-- MongoDB\Driver\BulkWrite cannot be executed multiple times --SKIPIF-- --FILE-- insert(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); printf("Inserted %d document(s)\n", $result->getInsertedCount()); echo throws(function() use ($manager, $bulk) { $result = $manager->executeBulkWrite(NS, $bulk); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECTF-- Inserted 1 document(s) OK: Got MongoDB\Driver\Exception\InvalidArgumentException BulkWrite objects may only be executed once and this instance has already been executed ===DONE=== mongodb-1.21.0/tests/bulk/write-0001.phpt0000644000175100001660000000505614760300421014650 0ustar --TEST-- MongoDB\Driver\BulkWrite: #001 Variety Bulk --SKIPIF-- --FILE-- insert(array("my" => "value")); $bulk->insert(array("my" => "value", "foo" => "bar")); $bulk->insert(array("my" => "value", "foo" => "bar")); var_dump($bulk); $bulk->delete(array("my" => "value", "foo" => "bar"), array("limit" => 1)); var_dump($bulk); $bulk->update(array("foo" => "bar"), array('$set' => array("foo" => "baz")), array("limit" => 1, "upsert" => 0)); var_dump($bulk); $retval = $manager->executeBulkWrite(NS, $bulk); var_dump($bulk); printf("Inserted: %d\n", getInsertCount($retval)); printf("Deleted: %d\n", getDeletedCount($retval)); printf("Updated: %d\n", getModifiedCount($retval)); printf("Upserted: %d\n", getUpsertedCount($retval)); foreach(getWriteErrors($retval) as $error) { printf("WriteErrors: %", $error); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> string(15) "bulk_write_0001" ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(true) ["server_id"]=> int(%r[1-9]\d*%r) ["session"]=> NULL ["write_concern"]=> NULL } Inserted: 3 Deleted: 1 Updated: 1 Upserted: 0 ===DONE=== mongodb-1.21.0/tests/bulk/write-0002.phpt0000644000175100001660000000344014760300421014644 0ustar --TEST-- MongoDB\Driver\BulkWrite: #002 Get the generated ID --SKIPIF-- --FILE-- "Hannes", "country" => "USA", "gender" => "male"); $hayley = array("name" => "Bayley", "country" => "USA", "gender" => "female"); $insertBulk = new \MongoDB\Driver\BulkWrite(['ordered' => true]); $hannes_id = $insertBulk->insert($hannes); $hayley_id = $insertBulk->insert($hayley); $w = 1; $wtimeout = 1000; $writeConcern = new \MongoDB\Driver\WriteConcern($w, $wtimeout); var_dump($insertBulk); $result = $manager->executeBulkWrite(NS, $insertBulk, ['writeConcern' => $writeConcern]); var_dump($insertBulk); assert($result instanceof \MongoDB\Driver\WriteResult); printf( "Inserted %d documents to %s\n", $result->getInsertedCount(), $result->getServer()->getHost() ); printf("hannes: %s\nhayley: %s\n", $hannes_id, $hayley_id); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> NULL ["collection"]=> NULL ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(false) ["server_id"]=> int(0) ["session"]=> NULL ["write_concern"]=> NULL } object(MongoDB\Driver\BulkWrite)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> string(15) "bulk_write_0002" ["ordered"]=> bool(true) ["bypassDocumentValidation"]=> NULL ["executed"]=> bool(true) ["server_id"]=> int(%r[1-9]\d*%r) ["session"]=> NULL ["write_concern"]=> array(%d) { ["w"]=> int(1) ["wtimeout"]=> int(1000) } } Inserted 2 documents to %s hannes: %s hayley: %s ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-001.phpt0000644000175100001660000000127714760300421022120 0ustar --TEST-- Causal consistency: new session has no operation time --DESCRIPTION-- Causal consistency spec prose test #1 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- startSession(); echo "Initial operation time:\n"; var_dump($session->getOperationTime()); ?> ===DONE=== --EXPECT-- Initial operation time: NULL ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-002.phpt0000644000175100001660000000213314760300421022111 0ustar --TEST-- Causal consistency: first read in session does not include afterClusterTime --DESCRIPTION-- Causal consistency spec prose test #2 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- observe( function() { $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); }, function(stdClass $command) { $hasAfterClusterTime = isset($command->readConcern->afterClusterTime); printf("Read includes afterClusterTime: %s\n", ($hasAfterClusterTime ? 'yes' : 'no')); } ); ?> ===DONE=== --EXPECT-- Read includes afterClusterTime: no ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-003.phpt0000644000175100001660000000710614760300421022117 0ustar --TEST-- Causal consistency: first read or write in session updates operationTime --DESCRIPTION-- Causal consistency spec prose test #3 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); printf("Session reports last seen operationTime: %s\n", ($session->getOperationTime() == $this->lastSeenOperationTime) ? 'yes' : 'no'); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function executeCommand() { $this->lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); printf("Session reports last seen operationTime: %s\n", ($session->getOperationTime() == $this->lastSeenOperationTime) ? 'yes' : 'no'); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function executeQuery() { $this->lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); printf("Session reports last seen operationTime: %s\n", ($session->getOperationTime() == $this->lastSeenOperationTime) ? 'yes' : 'no'); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { $reply = $event->getReply(); $hasOperationTime = isset($reply->{'operationTime'}); printf("%s command reply includes operationTime: %s\n", $event->getCommandName(), $hasOperationTime ? 'yes' : 'no'); if ($hasOperationTime) { $this->lastSeenOperationTime = $reply->operationTime; } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } echo "Testing executeBulkWrite()\n"; (new Test)->executeBulkWrite(); echo "\nTesting executeCommand()\n"; (new Test)->executeCommand(); echo "\nTesting executeQuery()\n"; (new Test)->executeQuery(); ?> ===DONE=== --EXPECT-- Testing executeBulkWrite() insert command reply includes operationTime: yes Session reports last seen operationTime: yes Testing executeCommand() ping command reply includes operationTime: yes Session reports last seen operationTime: yes Testing executeQuery() find command reply includes operationTime: yes Session reports last seen operationTime: yes ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-004.phpt0000644000175100001660000001110014760300421022105 0ustar --TEST-- Causal consistency: first read or write in session updates operationTime (even on error) --DESCRIPTION-- Causal consistency spec prose test #3 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 1]); throws(function() use ($manager, $bulk, $session) { $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); }, 'MongoDB\Driver\Exception\BulkWriteException'); printf("Session reports last seen operationTime: %s\n", ($session->getOperationTime() == $this->lastSeenOperationTime) ? 'yes' : 'no'); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function executeCommand() { $this->lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$unsupportedOperator' => 1], ], 'cursor' => new stdClass, ]); throws(function() use ($manager, $command, $session) { $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); }, 'MongoDB\Driver\Exception\RuntimeException'); /* We cannot access the server reply if an exception is thrown for a * failed command (see: PHPC-1076). For the time being, just assert that * the operationTime is not null. */ printf("Session has non-null operationTime: %s\n", ($session->getOperationTime() !== null ? 'yes' : 'no')); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function executeQuery() { $this->lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query(['$unsupportedOperator' => 1]); throws(function() use ($manager, $query, $session) { $manager->executeQuery(NS, $query, ['session' => $session]); }, 'MongoDB\Driver\Exception\RuntimeException'); /* We cannot access the server reply if an exception is thrown for a * failed command (see: PHPC-1076). For the time being, just assert that * the operationTime is not null. */ printf("Session has non-null operationTime: %s\n", ($session->getOperationTime() !== null ? 'yes' : 'no')); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { $reply = $event->getReply(); $hasOperationTime = isset($reply->operationTime); printf("%s command reply includes operationTime: %s\n", $event->getCommandName(), $hasOperationTime ? 'yes' : 'no'); if ($hasOperationTime) { $this->lastSeenOperationTime = $reply->operationTime; } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } echo "Testing executeBulkWrite()\n"; (new Test)->executeBulkWrite(); echo "\nTesting executeCommand()\n"; (new Test)->executeCommand(); echo "\nTesting executeQuery()\n"; (new Test)->executeQuery(); ?> ===DONE=== --EXPECT-- Testing executeBulkWrite() insert command reply includes operationTime: yes OK: Got MongoDB\Driver\Exception\BulkWriteException Session reports last seen operationTime: yes Testing executeCommand() OK: Got MongoDB\Driver\Exception\RuntimeException Session has non-null operationTime: yes Testing executeQuery() OK: Got MongoDB\Driver\Exception\RuntimeException Session has non-null operationTime: yes ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-005.phpt0000644000175100001660000000702314760300421022117 0ustar --TEST-- Causal consistency: second read's afterClusterTime uses last reply's operationTime --DESCRIPTION-- Causal consistency spec prose test #4 and #5 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); $manager->executeQuery(NS, $query, ['session' => $session]); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function executeReadAfterWrite() { $this->lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $hasAfterClusterTime = isset($command->readConcern->afterClusterTime); printf("%s command includes afterClusterTime: %s\n", $event->getCommandName(), ($hasAfterClusterTime ? 'yes' : 'no')); if ($hasAfterClusterTime && $this->lastSeenOperationTime !== null) { printf("%s command uses last seen operationTime: %s\n", $event->getCommandName(), ($command->readConcern->afterClusterTime == $this->lastSeenOperationTime) ? 'yes' : 'no'); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { $reply = $event->getReply(); $hasOperationTime = isset($reply->operationTime); printf("%s command reply includes operationTime: %s\n", $event->getCommandName(), $hasOperationTime ? 'yes' : 'no'); if ($hasOperationTime) { $this->lastSeenOperationTime = $reply->operationTime; } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } echo "Testing read after read\n"; (new Test)->executeReadAfterRead(); echo "\nTesting read after write\n"; (new Test)->executeReadAfterWrite(); ?> ===DONE=== --EXPECT-- Testing read after read find command includes afterClusterTime: no find command reply includes operationTime: yes find command includes afterClusterTime: yes find command uses last seen operationTime: yes find command reply includes operationTime: yes Testing read after write insert command includes afterClusterTime: no insert command reply includes operationTime: yes find command includes afterClusterTime: yes find command uses last seen operationTime: yes find command reply includes operationTime: yes ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-006.phpt0000644000175100001660000001045214760300421022120 0ustar --TEST-- Causal consistency: second read's afterClusterTime uses last reply's operationTime (even on error) --DESCRIPTION-- Causal consistency spec prose test #4 and #5 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query(['$unsupportedOperator' => 1]); throws(function() use ($manager, $query, $session) { $manager->executeQuery(NS, $query, ['session' => $session]); }, 'MongoDB\Driver\Exception\RuntimeException'); /* We cannot access the server reply if an exception is thrown for a * failed command (see: PHPC-1076). For the time being, just assert that * the operationTime is not null. */ printf("Session has non-null operationTime: %s\n", ($session->getOperationTime() !== null ? 'yes' : 'no')); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function executeReadAfterWriteError() { $this->lastSeenOperationTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 1]); throws(function() use ($manager, $bulk, $session) { $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); }, 'MongoDB\Driver\Exception\BulkWriteException'); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $hasAfterClusterTime = isset($command->readConcern->afterClusterTime); printf("%s command includes afterClusterTime: %s\n", $event->getCommandName(), ($hasAfterClusterTime ? 'yes' : 'no')); if ($hasAfterClusterTime && $this->lastSeenOperationTime !== null) { printf("%s command uses last seen operationTime: %s\n", $event->getCommandName(), ($command->readConcern->afterClusterTime == $this->lastSeenOperationTime) ? 'yes' : 'no'); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { $reply = $event->getReply(); $hasOperationTime = isset($reply->operationTime); printf("%s command reply includes operationTime: %s\n", $event->getCommandName(), $hasOperationTime ? 'yes' : 'no'); if ($hasOperationTime) { $this->lastSeenOperationTime = $reply->operationTime; } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } echo "\nTesting read after read error\n"; (new Test)->executeReadAfterReadError(); echo "\nTesting read after write error\n"; (new Test)->executeReadAfterWriteError(); ?> ===DONE=== --EXPECT-- Testing read after read error find command includes afterClusterTime: no OK: Got MongoDB\Driver\Exception\RuntimeException Session has non-null operationTime: yes find command includes afterClusterTime: yes find command reply includes operationTime: yes Testing read after write error insert command includes afterClusterTime: no insert command reply includes operationTime: yes OK: Got MongoDB\Driver\Exception\BulkWriteException find command includes afterClusterTime: yes find command uses last seen operationTime: yes find command reply includes operationTime: yes ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-007.phpt0000644000175100001660000000236114760300421022121 0ustar --TEST-- Causal consistency: reads in non-causally consistent session never include afterClusterTime --DESCRIPTION-- Causal consistency spec prose test #6 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- observe( function() { $manager = create_test_manager(); $session = $manager->startSession(['causalConsistency' => false]); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); $manager->executeQuery(NS, $query, ['session' => $session]); }, function(stdClass $command) { $hasAfterClusterTime = isset($command->readConcern->afterClusterTime); printf("Read includes afterClusterTime: %s\n", ($hasAfterClusterTime ? 'yes' : 'no')); } ); ?> ===DONE=== --EXPECT-- Read includes afterClusterTime: no Read includes afterClusterTime: no ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-008.phpt0000644000175100001660000000234214760300421022121 0ustar --TEST-- Causal consistency: reads in causally consistent session never include afterClusterTime for unsupported deployment --DESCRIPTION-- Causal consistency spec prose test #7 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- observe( function() { $manager = create_test_manager(); $session = $manager->startSession(['causalConsistency' => true]); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); $manager->executeQuery(NS, $query, ['session' => $session]); }, function(stdClass $command) { $hasAfterClusterTime = isset($command->readConcern->afterClusterTime); printf("Read includes afterClusterTime: %s\n", ($hasAfterClusterTime ? 'yes' : 'no')); } ); ?> ===DONE=== --EXPECT-- Read includes afterClusterTime: no Read includes afterClusterTime: no ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-009.phpt0000644000175100001660000000265414760300421022130 0ustar --TEST-- Causal consistency: default read concern includes afterClusterTime but not level --DESCRIPTION-- Causal consistency spec prose test #8 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- observe( function() { $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); $manager->executeQuery(NS, $query, ['session' => $session]); }, function(stdClass $command) { $hasAfterClusterTime = isset($command->readConcern->afterClusterTime); printf("Read concern includes afterClusterTime: %s\n", ($hasAfterClusterTime ? 'yes' : 'no')); $hasLevel = isset($command->readConcern->level); printf("Read concern includes level: %s\n", ($hasLevel ? 'yes' : 'no')); } ); ?> ===DONE=== --EXPECT-- Read concern includes afterClusterTime: no Read concern includes level: no Read concern includes afterClusterTime: yes Read concern includes level: no ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-010.phpt0000644000175100001660000000304514760300421022113 0ustar --TEST-- Causal consistency: custom read concern merges afterClusterTime and level --DESCRIPTION-- Causal consistency spec prose test #9 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- observe( function() { $manager = create_test_manager(); $session = $manager->startSession(); $readConcern = new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY); $query = new MongoDB\Driver\Query([], ['readConcern' => $readConcern]); $manager->executeQuery(NS, $query, ['session' => $session]); $manager->executeQuery(NS, $query, ['session' => $session]); }, function(stdClass $command) { $hasAfterClusterTime = isset($command->readConcern->afterClusterTime); printf("Read concern includes afterClusterTime: %s\n", ($hasAfterClusterTime ? 'yes' : 'no')); $hasLevel = isset($command->readConcern->level); printf("Read concern includes level: %s\n", ($hasLevel ? 'yes' : 'no')); } ); ?> ===DONE=== --EXPECT-- Read concern includes afterClusterTime: no Read concern includes level: yes Read concern includes afterClusterTime: yes Read concern includes level: yes ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-011.phpt0000644000175100001660000000225314760300421022114 0ustar --TEST-- Causal consistency: $clusterTime is not sent in commands to unsupported deployments --DESCRIPTION-- Causal consistency spec prose test #11 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- observe( function() { $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); $manager->executeQuery(NS, $query, ['session' => $session]); }, function(stdClass $command) { $hasClusterTime = isset($command->{'$clusterTime'}); printf("Command includes \$clusterTime: %s\n", ($hasClusterTime ? 'yes' : 'no')); } ); ?> ===DONE=== --EXPECT-- Command includes $clusterTime: no Command includes $clusterTime: no ===DONE=== mongodb-1.21.0/tests/causal-consistency/causal-consistency-012.phpt0000644000175100001660000000235214760300421022115 0ustar --TEST-- Causal consistency: $clusterTime is sent in commands to supported deployments --DESCRIPTION-- Causal consistency spec prose test #12 https://github.com/mongodb/specifications/blob/master/source/causal-consistency/causal-consistency.rst#test-plan --SKIPIF-- --FILE-- observe( function() { $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); $manager->executeQuery(NS, $query, ['session' => $session]); }, function(stdClass $command) { $hasClusterTime = isset($command->{'$clusterTime'}); printf("Command includes \$clusterTime: %s\n", ($hasClusterTime ? 'yes' : 'no')); } ); ?> ===DONE=== --EXPECT-- Command includes $clusterTime: yes Command includes $clusterTime: yes ===DONE=== mongodb-1.21.0/tests/clientEncryption/bug2149.phpt0000644000175100001660000000213014760300421016617 0ustar --TEST-- MongoDB\Driver\ClientEncryption::createDataKey() may leak "masterKey" option --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); /* The "local" provider does not support a "masterKey" option, but this is * sufficient to grow the stack-allocated bson_t and test for a possible leak. */ throws(function () use ($clientEncryption) { $clientEncryption->createDataKey('local', ['masterKey' => ['foo' => str_repeat('a', 4096)]]); }, MongoDB\Driver\Exception\EncryptionException::class); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\EncryptionException ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-addKeyAltName-001.phpt0000644000175100001660000000223714760300421024022 0ustar --TEST-- MongoDB\Driver\ClientEncryption::addKeyAltName() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); $keyBeforeUpdate = $clientEncryption->addKeyAltName($keyId, 'foo'); $keyAfterUpdate = $clientEncryption->getKey($keyId); var_dump($keyBeforeUpdate->_id == $keyId); var_dump(empty($keyBeforeUpdate->keyAltNames)); var_dump($keyAfterUpdate->_id == $keyId); var_dump(isset($keyAfterUpdate->keyAltNames) && is_array($keyAfterUpdate->keyAltNames)); var_dump(in_array('foo', $keyAfterUpdate->keyAltNames)); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-addKeyAltName-002.phpt0000644000175100001660000000151714760300421024023 0ustar --TEST-- MongoDB\Driver\ClientEncryption::addKeyAltName() when key does not exist --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = new MongoDB\BSON\Binary(random_bytes(16), MongoDB\BSON\Binary::TYPE_UUID); var_dump($clientEncryption->addKeyAltName($keyId, 'foo')); ?> ===DONE=== --EXPECT-- NULL ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-addKeyAltName_error-001.phpt0000644000175100001660000000166314760300421025235 0ustar --TEST-- MongoDB\Driver\ClientEncryption::addKeyAltName() with invalid keyId --SKIPIF-- --FILE-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $invalidKeyId = new MongoDB\BSON\Binary('', MongoDB\BSON\Binary::TYPE_GENERIC); echo throws(function () use ($clientEncryption, $invalidKeyId) { $clientEncryption->addKeyAltName($invalidKeyId, 'foo'); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected keyid to have UUID Binary subtype (4), 0 given ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-constants.phpt0000644000175100001660000000175214760300421023076 0ustar --TEST-- MongoDB\Driver\ClientEncryption constants --FILE-- ===DONE=== --EXPECTF-- string(43) "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" string(36) "AEAD_AES_256_CBC_HMAC_SHA_512-Random" string(7) "Indexed" string(9) "Unindexed" string(5) "Range" %Astring(12) "RangePreview" string(8) "equality" string(5) "range" %Astring(12) "rangePreview" ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-createDataKey-001.phpt0000644000175100001660000000163514760300421024066 0ustar --TEST-- MongoDB\Driver\ClientEncryption::createDataKey() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); var_dump($keyId); $key = $clientEncryption->getKey($keyId); var_dump($key->_id == $keyId); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%a" ["type"]=> int(4) } bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-createDataKey-002.phpt0000644000175100001660000000172514760300421024067 0ustar --TEST-- MongoDB\Driver\ClientEncryption::createDataKey() "keyAltNames" option --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local', ['keyAltNames' => ['foo', 'bar']]); $key = $clientEncryption->getKey($keyId); var_dump($key->_id == $keyId); var_dump(in_array('foo', $key->keyAltNames)); var_dump(in_array('bar', $key->keyAltNames)); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-createDataKey_error-001.phpt0000644000175100001660000000235214760300421025274 0ustar --TEST-- MongoDB\Driver\ClientEncryption::createDataKey() with invalid keyAltNames option --SKIPIF-- --FILE-- 'foo'], ['keyAltNames' => [0 => []]], ['keyAltNames' => ['foo' => []]], ]; $manager = create_test_manager(); $clientEncryption = $manager->createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); foreach ($tests as $opts) { echo throws(function () use ($clientEncryption, $opts) { $clientEncryption->createDataKey('local', $opts); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected keyAltNames to be array, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected keyAltName with index "0" to be string, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected keyAltName with index "foo" to be string, array given ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-createDataKey_error-002.phpt0000644000175100001660000000215114760300421025272 0ustar --TEST-- MongoDB\Driver\ClientEncryption::createDataKey() with invalid keyMaterial option --SKIPIF-- --FILE-- 0], ['keyMaterial' => new stdClass], ]; $manager = create_test_manager(); $clientEncryption = $manager->createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); foreach ($tests as $opts) { echo throws(function () use ($clientEncryption, $opts) { $clientEncryption->createDataKey('local', $opts); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "keyMaterial" option to be MongoDB\BSON\Binary, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "keyMaterial" option to be MongoDB\BSON\Binary, stdClass given ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-createDataKey_error-003.phpt0000644000175100001660000000233514760300421025277 0ustar --TEST-- MongoDB\Driver\ClientEncryption::createDataKey() masterKey option invalid type --SKIPIF-- --FILE-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); echo throws(function () use ($clientEncryption) { $clientEncryption->createDataKey('local', ['masterKey' => 'not-array-or-object']); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function () use ($clientEncryption) { $clientEncryption->createDataKey('local', ['masterKey' => MongoDB\BSON\PackedArray::fromPHP([])]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "masterKey" option to be array or object, string given OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-ctor-001.phpt0000644000175100001660000000114214760300421022320 0ustar --TEST-- MongoDB\Driver\ClientEncryption::__construct() --SKIPIF-- --FILE-- create_test_manager(), 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); var_dump($clientEncryption); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ClientEncryption)#%d (%d) { } ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-ctor-002.phpt0000644000175100001660000000134414760300421022325 0ustar --TEST-- MongoDB\Driver\ClientEncryption::__construct(): Drivers MUST NOT error if tlsDisableOCSPEndpointCheck is set --SKIPIF-- --FILE-- create_test_manager(), 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['aws' => ['accessKeyId' => 'foo', 'secretAccessKey' => 'bar']], 'tlsOptions' => ['aws' => ['tlsDisableOCSPEndpointCheck' => true]], ]); var_dump($clientEncryption); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ClientEncryption)#%d (%d) { } ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-ctor_error-001.phpt0000644000175100001660000000120114760300421023525 0ustar --TEST-- MongoDB\Driver\ClientEncryption::__construct() fails if compiled without FLE --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException Cannot configure clientEncryption object. Please recompile with support for libmongocrypt using the with-mongodb-client-side-encryption configure switch. ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-ctor_error-002.phpt0000644000175100001660000000474714760300421023550 0ustar --TEST-- MongoDB\Driver\ClientEncryption::__construct() with invalid option types --SKIPIF-- --FILE-- create_test_manager()]; $tests = [ [], ['keyVaultClient' => 'not_an_array_or_object'], [ 'keyVaultNamespace' => 'not_a_namespace', // keyVaultNamespace requires a valid kmsProviders option 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ] + $baseOptions, ['kmsProviders' => 'not_an_array_or_object'] + $baseOptions, ['tlsOptions' => 'not_an_array_or_object'] + $baseOptions, ]; foreach ($tests as $test) { echo throws(function () use ($test) { new MongoDB\Driver\ClientEncryption($test); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n\n"; } // PackedArray cannot be serialized as a root document $tests = [ ['kmsProviders' => MongoDB\BSON\PackedArray::fromPHP([])] + $baseOptions, ['tlsOptions' => MongoDB\BSON\PackedArray::fromPHP([])] + $baseOptions, ]; foreach ($tests as $test) { echo throws(function () use ($test) { new MongoDB\Driver\ClientEncryption($test); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException The "keyVaultClient" option is required when constructing a ClientEncryption object directly OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "keyVaultClient" option to be MongoDB\Driver\Manager, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "keyVaultNamespace" option to contain a full collection namespace OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "kmsProviders" option to be an array or object, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "tlsOptions" option to be an array or object, string given OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-decrypt-001.phpt0000644000175100001660000000200314760300421023020 0ustar --TEST-- MongoDB\Driver\ClientEncryption::decrypt() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); $encrypted = $clientEncryption->encrypt('top-secret', ['keyId' => $keyId, 'algorithm' => MongoDB\Driver\ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC]); var_dump($clientEncryption->decrypt($encrypted)); ?> ===DONE=== --EXPECTF-- string(10) "top-secret" ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-deleteKey-001.phpt0000644000175100001660000000147714760300421023277 0ustar --TEST-- MongoDB\Driver\ClientEncryption::deleteKey() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); var_dump($clientEncryption->deleteKey($keyId)); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["deletedCount"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-deleteKey-002.phpt0000644000175100001660000000156714760300421023300 0ustar --TEST-- MongoDB\Driver\ClientEncryption::deleteKey() when key does not exist --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = new MongoDB\BSON\Binary(random_bytes(16), MongoDB\BSON\Binary::TYPE_UUID); var_dump($clientEncryption->deleteKey($keyId)); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["deletedCount"]=> int(0) } ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-deleteKey_error-001.phpt0000644000175100001660000000177514760300421024511 0ustar --TEST-- MongoDB\Driver\ClientEncryption::deleteKey() with invalid keyId --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $invalidKeyId = new MongoDB\BSON\Binary('', MongoDB\BSON\Binary::TYPE_GENERIC); echo throws(function () use ($clientEncryption, $invalidKeyId) { $clientEncryption->deleteKey($invalidKeyId); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected keyid to have UUID Binary subtype (4), 0 given ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-encrypt-001.phpt0000644000175100001660000000202314760300421023034 0ustar --TEST-- MongoDB\Driver\ClientEncryption::encrypt() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); var_dump($clientEncryption->encrypt('top-secret', ['keyId' => $keyId, 'algorithm' => MongoDB\Driver\ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC])); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(82) "%a" ["type"]=> int(6) } ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-encryptExpression-001.phpt0000644000175100001660000000322014760300421025114 0ustar --TEST-- MongoDB\Driver\ClientEncryption::encryptExpression() encrypts $and operator --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); $encryptOpts = [ 'keyId' => $keyId, 'algorithm' => MongoDB\Driver\ClientEncryption::ALGORITHM_RANGE, 'queryType' => MongoDB\Driver\ClientEncryption::QUERY_TYPE_RANGE, 'contentionFactor' => 0, 'rangeOpts' => ['min' => 0, 'max' => 200], ]; $expr = [ '$and' => [ ['encryptedInt' => ['$gte' => 6]], ['encryptedInt' => ['$lte' => 200]], ], ]; $encryptedExpr = $clientEncryption->encryptExpression($expr, $encryptOpts); var_dump($encryptedExpr->{'$and'}[0]->encryptedInt->{'$gte'} instanceof MongoDB\BSON\Binary); var_dump($encryptedExpr->{'$and'}[0]->encryptedInt->{'$gte'}->getType() === MongoDB\BSON\Binary::TYPE_ENCRYPTED); var_dump($encryptedExpr->{'$and'}[1]->encryptedInt->{'$lte'} instanceof MongoDB\BSON\Binary); var_dump($encryptedExpr->{'$and'}[1]->encryptedInt->{'$lte'}->getType() === MongoDB\BSON\Binary::TYPE_ENCRYPTED); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-encryptExpression_error-001.phpt0000644000175100001660000000220714760300421026331 0ustar --TEST-- MongoDB\Driver\ClientEncryption::encryptExpression() BSON encoding errors --SKIPIF-- --FILE-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); class SerializableError implements MongoDB\BSON\Serializable { #[\ReturnTypeWillChange] public function bsonSerialize() { throw new RuntimeException('bsonSerialize() error'); } } echo throws(function() use ($clientEncryption) { $clientEncryption->encryptExpression(new SerializableError()); }, RuntimeException::class), "\n"; echo throws(function() use ($clientEncryption) { $clientEncryption->encryptExpression([], ['keyId' => new SerializableError()]); }, RuntimeException::class), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got RuntimeException bsonSerialize() error OK: Got RuntimeException bsonSerialize() error ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-encryptExpression_error-002.phpt0000644000175100001660000000241114760300421026327 0ustar --TEST-- MongoDB\Driver\ClientEncryption::encryptExpression() requires $and operator --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); $encryptOpts = [ 'keyId' => $keyId, 'algorithm' => MongoDB\Driver\ClientEncryption::ALGORITHM_RANGE, 'queryType' => MongoDB\Driver\ClientEncryption::QUERY_TYPE_RANGE, 'contentionFactor' => 0, 'rangeOpts' => ['min' => 0, 'max' => 200], ]; echo throws(function() use ($clientEncryption, $encryptOpts) { $clientEncryption->encryptExpression([], $encryptOpts); }, MongoDB\Driver\Exception\EncryptionException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\EncryptionException error unable to find '$and': { } ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-encrypt_error-001.phpt0000644000175100001660000000216314760300421024252 0ustar --TEST-- MongoDB\Driver\ClientEncryption::encrypt() BSON encoding errors --SKIPIF-- --FILE-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); class SerializableError implements MongoDB\BSON\Serializable { #[\ReturnTypeWillChange] public function bsonSerialize() { throw new RuntimeException('bsonSerialize() error'); } } echo throws(function() use ($clientEncryption) { $clientEncryption->encrypt(new SerializableError()); }, RuntimeException::class), "\n"; echo throws(function() use ($clientEncryption) { $clientEncryption->encrypt('top-secret', ['keyId' => new SerializableError()]); }, RuntimeException::class), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got RuntimeException bsonSerialize() error OK: Got RuntimeException bsonSerialize() error ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-getKey-001.phpt0000644000175100001660000000144414760300421022606 0ustar --TEST-- MongoDB\Driver\ClientEncryption::getKey() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); $key = $clientEncryption->getKey($keyId); var_dump($key->_id == $keyId); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-getKey-002.phpt0000644000175100001660000000147214760300421022610 0ustar --TEST-- MongoDB\Driver\ClientEncryption::getKey() when key does not exist --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = new MongoDB\BSON\Binary(random_bytes(16), MongoDB\BSON\Binary::TYPE_UUID); var_dump($clientEncryption->getKey($keyId)); ?> ===DONE=== --EXPECT-- NULL ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-getKeyByAltName-001.phpt0000644000175100001660000000166514760300421024350 0ustar --TEST-- MongoDB\Driver\ClientEncryption::getKeyByAltName() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local', ['keyAltNames' => ['foo', 'bar']]); $key = $clientEncryption->getKeyByAltName('foo'); var_dump($key->_id == $keyId); $key = $clientEncryption->getKeyByAltName('bar'); var_dump($key->_id == $keyId); ?> ===DONE=== --EXPECT-- bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-getKeyByAltName-002.phpt0000644000175100001660000000136614760300421024347 0ustar --TEST-- MongoDB\Driver\ClientEncryption::getKeyByAltName() when key does not exist --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); var_dump($clientEncryption->getKeyByAltName('foo')); ?> ===DONE=== --EXPECT-- NULL ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-getKey_error-001.phpt0000644000175100001660000000176714760300421024027 0ustar --TEST-- MongoDB\Driver\ClientEncryption::getKey() with invalid keyId --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $invalidKeyId = new MongoDB\BSON\Binary('', MongoDB\BSON\Binary::TYPE_GENERIC); echo throws(function () use ($clientEncryption, $invalidKeyId) { $clientEncryption->getKey($invalidKeyId); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected keyid to have UUID Binary subtype (4), 0 given ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-getKeys-001.phpt0000644000175100001660000000175014760300421022771 0ustar --TEST-- MongoDB\Driver\ClientEncryption::getKeys() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $key1Id = $clientEncryption->createDataKey('local'); $key2Id = $clientEncryption->createDataKey('local'); $keyIds = []; foreach ($clientEncryption->getKeys() as $key) { $keyIds[] = $key->_id; } var_dump(count($keyIds)); var_dump(in_array($key1Id, $keyIds)); var_dump(in_array($key2Id, $keyIds)); ?> ===DONE=== --EXPECT-- int(2) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-getKeys-002.phpt0000644000175100001660000000136014760300421022767 0ustar --TEST-- MongoDB\Driver\ClientEncryption::getKeys() with empty key vault --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); var_dump(iterator_count($clientEncryption->getKeys())); ?> ===DONE=== --EXPECT-- int(0) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-getKeys-003.phpt0000644000175100001660000000262714760300421022777 0ustar --TEST-- MongoDB\Driver\ClientEncryption::getKeys() cursor debug info --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); /* Note: the query reports a null readConcern property despite libmongoc using * a majority read concern internally (as it does for all key vault reads). */ var_dump($clientEncryption->getKeys()); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(%d) "%s" ["collection"]=> string(%d) "%s" ["query"]=> object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { } ["options"]=> object(stdClass)#%d (%d) { } ["readConcern"]=> NULL } ["command"]=> NULL ["readPreference"]=> NULL ["session"]=> NULL ["isDead"]=> bool(true) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-removeKeyAltName-001.phpt0000644000175100001660000000211014760300421024555 0ustar --TEST-- MongoDB\Driver\ClientEncryption::removeKeyAltName() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local', ['keyAltNames' => ['foo', 'bar']]); $key = $clientEncryption->removeKeyAltName($keyId, 'foo'); var_dump(in_array('foo', $key->keyAltNames)); var_dump(in_array('bar', $key->keyAltNames)); $key = $clientEncryption->getKey($keyId); var_dump(in_array('foo', $key->keyAltNames)); var_dump(in_array('bar', $key->keyAltNames)); ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(false) bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-removeKeyAltName-002.phpt0000644000175100001660000000152514760300421024567 0ustar --TEST-- MongoDB\Driver\ClientEncryption::removeKeyAltName() when key does not exist --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = new MongoDB\BSON\Binary(random_bytes(16), MongoDB\BSON\Binary::TYPE_UUID); var_dump($clientEncryption->removeKeyAltName($keyId, 'foo')); ?> ===DONE=== --EXPECT-- NULL ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-removeKeyAltName-003.phpt0000644000175100001660000000172714760300421024574 0ustar --TEST-- MongoDB\Driver\ClientEncryption::removeKeyAltName() when keyAltName does not exist --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local', ['keyAltNames' => ['foo', 'bar']]); $keyBeforeRemoval = $clientEncryption->removeKeyAltName($keyId, 'baz'); $keyAfterRemoval = $clientEncryption->getKey($keyId); var_dump($keyBeforeRemoval == $keyAfterRemoval); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-removeKeyAltName_error-001.phpt0000644000175100001660000000202214760300421025770 0ustar --TEST-- MongoDB\Driver\ClientEncryption::removeKeyAltName() with invalid keyId --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $invalidKeyId = new MongoDB\BSON\Binary('', MongoDB\BSON\Binary::TYPE_GENERIC); echo throws(function () use ($clientEncryption, $invalidKeyId) { $clientEncryption->removeKeyAltName($invalidKeyId, 'foo'); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected keyid to have UUID Binary subtype (4), 0 given ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-rewrapManyDataKey-001.phpt0000644000175100001660000000261414760300421024746 0ustar --TEST-- MongoDB\Driver\ClientEncryption::rewrapManyDataKey() --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); $orignalKey = $clientEncryption->getKey($keyId); var_dump($clientEncryption->rewrapManyDataKey([], ['provider' => 'local'])); $modifiedKey = $clientEncryption->getKey($keyId); var_dump($orignalKey->creationDate == $modifiedKey->creationDate); var_dump($orignalKey->updateDate < $modifiedKey->updateDate); var_dump($orignalKey->keyMaterial != $modifiedKey->keyMaterial); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["bulkWriteResult"]=> object(stdClass)#%d (%d) { ["nInserted"]=> int(0) ["nMatched"]=> int(1) ["nModified"]=> int(1) ["nRemoved"]=> int(0) ["nUpserted"]=> int(0) ["writeErrors"]=> array(0) { } } } bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-rewrapManyDataKey-002.phpt0000644000175100001660000000231414760300421024744 0ustar --TEST-- MongoDB\Driver\ClientEncryption::rewrapManyDataKey() when filter matches no keys --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); $keyId = $clientEncryption->createDataKey('local'); $orignalKey = $clientEncryption->getKey($keyId); var_dump($clientEncryption->rewrapManyDataKey(['_id' => 'no-matching-key'])); $modifiedKey = $clientEncryption->getKey($keyId); var_dump($orignalKey->creationDate == $modifiedKey->creationDate); var_dump($orignalKey->updateDate == $modifiedKey->updateDate); var_dump($orignalKey->keyMaterial == $modifiedKey->keyMaterial); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["bulkWriteResult"]=> NULL } bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-rewrapManyDataKey-003.phpt0000644000175100001660000000152114760300421024744 0ustar --TEST-- MongoDB\Driver\ClientEncryption::rewrapManyDataKey() accepts null for $options --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); var_dump($clientEncryption->rewrapManyDataKey(['_id' => 'no-matching-key'], null)); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["bulkWriteResult"]=> NULL } ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-rewrapManyDataKey_error-001.phpt0000644000175100001660000000173514760300421026162 0ustar --TEST-- MongoDB\Driver\ClientEncryption::rewrapManyDataKey() masterKey option invalid type --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); echo throws(function () use ($clientEncryption) { $clientEncryption->rewrapManyDataKey([], ['masterKey' => 'not-array-or-object']); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "masterKey" option to be array or object, string given ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-rewrapManyDataKey_error-002.phpt0000644000175100001660000000172114760300421026156 0ustar --TEST-- MongoDB\Driver\ClientEncryption::rewrapManyDataKey() masterKey option requires provider --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); echo throws(function () use ($clientEncryption) { $clientEncryption->rewrapManyDataKey([], ['masterKey' => []]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException The "masterKey" option should not be specified without "provider" ===DONE=== mongodb-1.21.0/tests/clientEncryption/clientEncryption-rewrapManyDataKey_error-003.phpt0000644000175100001660000000255114760300421026161 0ustar --TEST-- MongoDB\Driver\ClientEncryption::rewrapManyDataKey() prohibits PackedArray for document values --SKIPIF-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); echo throws(function() use ($clientEncryption) { $clientEncryption->rewrapManyDataKey(MongoDB\BSON\PackedArray::fromPHP([])); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; echo throws(function() use ($clientEncryption) { $clientEncryption->rewrapManyDataKey([], [ 'provider' => 'local', 'masterKey' => MongoDB\BSON\PackedArray::fromPHP([]), ]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/command/command-ctor-001.phpt0000644000175100001660000000426114760300421016477 0ustar --TEST-- MongoDB\Driver\Command construction should always encode __pclass for Persistable objects --SKIPIF-- --FILE-- id = $id; $this->child = $child; } #[\ReturnTypeWillChange] public function bsonSerialize() { return [ '_id' => $this->id, 'child' => $this->child, ]; } public function bsonUnserialize(array $data): void { $this->id = $data['_id']; $this->child = $data['child']; } } $manager = create_test_manager(); $document = new MyClass('foo', new MyClass('bar', new MyClass('baz'))); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['_id' => 'foo'], 'update' => $document, 'upsert' => true, 'new' => true, ])); var_dump($cursor->toArray()[0]->value); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$match' => $document], ], 'cursor' => new stdClass(), ])); var_dump($cursor->toArray()[0]); ?> ===DONE=== --EXPECTF-- object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "foo" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "bar" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "baz" ["child":"MyClass":private]=> NULL } } } object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "foo" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "bar" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "baz" ["child":"MyClass":private]=> NULL } } } ===DONE=== mongodb-1.21.0/tests/command/command-ctor-002.phpt0000644000175100001660000000137514760300421016503 0ustar --TEST-- MongoDB\Driver\Command::__construct() $document is MongoDB\Driver\Document --SKIPIF-- --FILE-- executeCommand(DATABASE_NAME, $command); var_dump($cursor->toArray()[0]); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Command)#%d (%d) { ["command"]=> object(stdClass)#%d (%d) { ["ping"]=> int(1) } } object(stdClass)#%d (%d) { ["ok"]=> float(1)%A } ===DONE=== mongodb-1.21.0/tests/command/command-ctor_error-001.phpt0000644000175100001660000000073714760300421017714 0ustar --TEST-- MongoDB\Driver\Command::__construct() does not allow PackedArray --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/command/command_error-001.phpt0000644000175100001660000000037214760300421016742 0ustar --TEST-- MongoDB\Driver\Command cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyCommand %s final class %SMongoDB\Driver\Command%S in %s on line %d mongodb-1.21.0/tests/command/cursor-batchsize-001.phpt0000644000175100001660000000472214760300421017405 0ustar --TEST-- MongoDB\Driver\Command non-zero batchSize applies to getMore --SKIPIF-- --FILE-- insert(['_id' => $i]); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$match' => new stdClass]], 'cursor' => ['batchSize' => 2] ]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $cursor->toArray(); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); if ($event->getCommandName() === 'aggregate') { printf("aggregate command specifies batchSize: %d\n", $command->cursor->batchSize); } if ($event->getCommandName() === 'getMore') { printf("getMore command specifies batchSize: %d\n", $command->batchSize); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { $reply = $event->getReply(); if ($event->getCommandName() === 'aggregate') { printf("aggregate response contains %d document(s)\n", count($reply->cursor->firstBatch)); } if ($event->getCommandName() === 'getMore') { printf("getMore response contains %d document(s)\n", count($reply->cursor->nextBatch)); } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } (new Test)->executeCommand(); ?> ===DONE=== --EXPECT-- Inserted: 5 aggregate command specifies batchSize: 2 aggregate response contains 2 document(s) getMore command specifies batchSize: 2 getMore response contains 2 document(s) getMore command specifies batchSize: 2 getMore response contains 1 document(s) ===DONE=== mongodb-1.21.0/tests/command/cursor-batchsize-002.phpt0000644000175100001660000000463414760300421017410 0ustar --TEST-- MongoDB\Driver\Command batchSize of zero is ignored for getMore --SKIPIF-- --FILE-- insert(['_id' => $i]); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$match' => new stdClass]], 'cursor' => ['batchSize' => 0] ]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $cursor->toArray(); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); if ($event->getCommandName() === 'aggregate') { printf("aggregate command specifies batchSize: %d\n", $command->cursor->batchSize); } if ($event->getCommandName() === 'getMore') { printf("getMore command specifies batchSize: %s\n", isset($command->batchSize) ? 'yes' : 'no'); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { $reply = $event->getReply(); if ($event->getCommandName() === 'aggregate') { printf("aggregate response contains %d document(s)\n", count($reply->cursor->firstBatch)); } if ($event->getCommandName() === 'getMore') { printf("getMore response contains %d document(s)\n", count($reply->cursor->nextBatch)); } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } (new Test)->executeCommand(); ?> ===DONE=== --EXPECT-- Inserted: 5 aggregate command specifies batchSize: 0 aggregate response contains 0 document(s) getMore command specifies batchSize: no getMore response contains 5 document(s) ===DONE=== mongodb-1.21.0/tests/command/cursor-comment-001.phpt0000644000175100001660000000374214760300421017074 0ustar --TEST-- MongoDB\Driver\Command comment applies to getMore --SKIPIF-- --FILE-- insert(['_id' => $i]); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$match' => new stdClass]], 'comment' => ['foo' => 1], 'cursor' => ['batchSize' => 2] ]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $cursor->toArray(); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); if ($event->getCommandName() === 'aggregate' || $event->getCommandName() === 'getMore') { printf("%s command includes comment: %s\n", $event->getCommandName(), json_encode($command->comment)); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } (new Test)->executeCommand(); ?> ===DONE=== --EXPECT-- Inserted: 5 aggregate command includes comment: {"foo":1} getMore command includes comment: {"foo":1} getMore command includes comment: {"foo":1} ===DONE=== mongodb-1.21.0/tests/command/cursor-tailable-001.phpt0000644000175100001660000000343214760300421017203 0ustar --TEST-- MongoDB\Driver\Command tailable cursor iteration with maxAwaitTimeMS option --SKIPIF-- --FILE-- executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'create' => COLLECTION_NAME, 'capped' => true, 'size' => 1048576, ])); $bulkWrite = new MongoDB\Driver\BulkWrite; $bulkWrite->insert(['_id' => 1]); $manager->executeBulkWrite(NS, $bulkWrite); $pipeline = [ [ '$changeStream' => [ 'fullDocument' => 'updateLookup' ] ] ]; $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => $pipeline, 'cursor' => ['batchSize' => 0], ], [ 'maxAwaitTimeMS' => 500, ]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $it = new IteratorIterator($cursor); $it->rewind(); $it->next(); $bulkWrite = new MongoDB\Driver\BulkWrite; $bulkWrite->insert(['_id' => "new-document"]); $manager->executeBulkWrite(NS, $bulkWrite); $startTime = microtime(true); echo "Awaiting results...\n"; $it->next(); var_dump($it->current()->operationType, $it->current()->documentKey); printf("Waited for %.6f seconds\n", microtime(true) - $startTime); $startTime = microtime(true); echo "Awaiting results...\n"; $it->next(); var_dump($it->current()); /* Should be NULL */ printf("Waited for %.6f seconds\n", microtime(true) - $startTime); ?> ===DONE=== --EXPECTF-- Awaiting results... string(6) "insert" object(stdClass)#%d (%d) { ["_id"]=> string(12) "new-document" } Waited for 0.%d seconds Awaiting results... NULL Waited for 0.%r(4|5)\d*%r seconds ===DONE=== mongodb-1.21.0/tests/command/findAndModify-001.phpt0000644000175100001660000000340514760300421016626 0ustar --TEST-- MongoDB\Driver\Command with findAndModify and arrayFilters --SKIPIF-- --FILE-- insert([ '_id' => 1, 'grades' => [ 95, 92, 90 ] ]); $bulk->insert([ '_id' => 2, 'grades' => [ 98, 100, 102 ] ]); $bulk->insert([ '_id' => 3, 'grades' => [ 95, 110, 100 ] ]); $manager->executeBulkWrite(DATABASE_NAME . '.' . COLLECTION_NAME, $bulk); $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['grades' => [ '$gt' => 100 ] ], 'update' => ['$set' => [ 'grades.$[element]' => 100 ] ], 'arrayFilters' => [ [ 'element' => [ '$gt' => 100 ] ] ], ]); // Running this twice, because findAndModify only updates the first document // it finds. $manager->executeCommand(DATABASE_NAME, $command); $manager->executeCommand(DATABASE_NAME, $command); $cursor = $manager->executeQuery( DATABASE_NAME . '.' . COLLECTION_NAME, new \MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- array(%d) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["grades"]=> array(%d) { [0]=> int(95) [1]=> int(92) [2]=> int(90) } } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["grades"]=> array(%d) { [0]=> int(98) [1]=> int(100) [2]=> int(100) } } [2]=> object(stdClass)#%d (%d) { ["_id"]=> int(3) ["grades"]=> array(%d) { [0]=> int(95) [1]=> int(100) [2]=> int(100) } } } ===DONE=== mongodb-1.21.0/tests/command/update-001.phpt0000644000175100001660000000324414760300421015376 0ustar --TEST-- MongoDB\Driver\Command with update and arrayFilters --SKIPIF-- --FILE-- insert([ '_id' => 1, 'grades' => [ 95, 92, 90 ] ]); $bulk->insert([ '_id' => 2, 'grades' => [ 98, 100, 102 ] ]); $bulk->insert([ '_id' => 3, 'grades' => [ 95, 110, 100 ] ]); $manager->executeBulkWrite(DATABASE_NAME . '.' . COLLECTION_NAME, $bulk); $command = new MongoDB\Driver\Command([ 'update' => COLLECTION_NAME, 'updates' => [[ 'q' => [ 'grades' => [ '$gte' => 100 ] ], 'u' => [ '$set' => [ 'grades.$[element]' => 100 ] ], 'arrayFilters' => [ [ 'element' => [ '$gte' => 100 ] ] ], 'multi' => true ]], ]); $manager->executeCommand(DATABASE_NAME, $command); $cursor = $manager->executeQuery( DATABASE_NAME . '.' . COLLECTION_NAME, new \MongoDB\Driver\Query([])); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- array(%d) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["grades"]=> array(%d) { [0]=> int(95) [1]=> int(92) [2]=> int(90) } } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["grades"]=> array(%d) { [0]=> int(98) [1]=> int(100) [2]=> int(100) } } [2]=> object(stdClass)#%d (%d) { ["_id"]=> int(3) ["grades"]=> array(%d) { [0]=> int(95) [1]=> int(100) [2]=> int(100) } } } ===DONE=== mongodb-1.21.0/tests/connect/bug0720.phpt0000644000175100001660000000246114760300421014717 0ustar --TEST-- PHPC-720: Do not persist SSL streams to avoid SSL reinitialization errors --SKIPIF-- --FILE-- true, 'ca_file' => SSL_DIR . '/ca.pem', ]; $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); unset($manager, $cursor); $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_invalid_hostname" driver option is deprecated. Please use the "tlsAllowInvalidHostnames" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "ca_file" driver option is deprecated. Please use the "tlsCAFile" URI option instead.%s ping: 1 ping: 1 ===DONE=== mongodb-1.21.0/tests/connect/bug1015.phpt0000644000175100001660000000171514760300421014716 0ustar --TEST-- PHPC-1015: Initial DNS Seedlist test --SKIPIF-- --FILE-- selectServer( new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::NEAREST ) ); $servers = $m->getServers(); foreach ( $servers as $server ) { echo $server->getHost(), ':', $server->getPort(), "\n"; } ?> ===DONE=== --EXPECTF-- %d.%d.%d.%d:27017 %d.%d.%d.%d:27018 %d.%d.%d.%d:27019 ===DONE=== mongodb-1.21.0/tests/connect/bug1045.phpt0000644000175100001660000000130714760300421014716 0ustar --TEST-- PHPC-1045: Segfault if username is not provided for SCRAM-SHA-1 authMechanism --SKIPIF-- --FILE-- 'SCRAM-SHA-1']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: 'SCRAM-SHA-1' authentication mechanism requires username ===DONE=== mongodb-1.21.0/tests/connect/compression_error-001.phpt0000644000175100001660000000071714760300421017703 0ustar --TEST-- MongoDB\Driver\Manager: Connecting with unsupported compressor --SKIPIF-- --FILE-- 'zli'] ); ini_set('mongodb.debug', null); ?> ===DONE=== --EXPECTF-- %AWARNING > Unsupported compressor: 'zli'%A ===DONE=== mongodb-1.21.0/tests/connect/compression_error-002.phpt0000644000175100001660000000106714760300421017703 0ustar --TEST-- MongoDB\Driver\Manager: Connecting with invalid compressor values --SKIPIF-- --FILE-- "foo\xFEbar"] ); }, 'MongoDB\Driver\Exception\UnexpectedValueException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException Detected invalid UTF-8 for field path "compressors": %s ===DONE=== mongodb-1.21.0/tests/connect/replicaset-seedlist-001.phpt0000644000175100001660000000211514760300421020070 0ustar --TEST-- MongoDB\Driver\Manager: Connecting to Replica Set with only secondary in seedlist --SKIPIF-- --FILE-- getInfo(); // As we're building our own URL here, we do need to extract username and password $url = parse_url(URI); if (array_key_exists('user', $url) && array_key_exists('pass', $url)) { $dsn = sprintf('mongodb://%s:%s@%s', $url['user'], $url['pass'], $info['me']); } else { $dsn = 'mongodb://' . $info['me']; } $manager = create_test_manager($dsn, ['replicaSet' => $info['setName']]); // load fixtures for test $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array("_id" => 1, "x" => 2, "y" => 3)); $bulk->insert(array("_id" => 2, "x" => 3, "y" => 4)); $bulk->insert(array("_id" => 3, "x" => 4, "y" => 5)); $manager->executeBulkWrite(NS, $bulk); ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/connect/replicaset-seedlist-002.phpt0000644000175100001660000000224414760300421020074 0ustar --TEST-- MongoDB\Driver\Manager: Connecting to Replica Set with only arbiter in seedlist --SKIPIF-- --FILE-- getInfo(); // As we're building our own URL here, we do need to extract username and password // We already checked whether there is an arbiter through `skip_if_no_arbiter` $url = parse_url(URI); if (array_key_exists('user', $url) && array_key_exists('pass', $url)) { $dsn = sprintf('mongodb://%s:%s@%s', $url['user'], $url['pass'], $info['arbiters'][0]); } else { $dsn = 'mongodb://' . $info['arbiters'][0]; } $manager = create_test_manager($dsn, ['replicaSet' => $info['setName']]); // load fixtures for test $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array("_id" => 1, "x" => 2, "y" => 3)); $bulk->insert(array("_id" => 2, "x" => 3, "y" => 4)); $bulk->insert(array("_id" => 3, "x" => 4, "y" => 5)); $manager->executeBulkWrite(NS, $bulk); ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/connect/standalone-auth-001.phpt0000644000175100001660000000220014760300421017205 0ustar --TEST-- Connect to MongoDB with using default auth mechanism --SKIPIF-- --FILE-- insert(array("my" => "value")); $bulk->insert(array("my" => "value", "foo" => "bar")); $bulk->insert(array("my" => "value", "foo" => "bar")); $bulk->delete(array("my" => "value", "foo" => "bar"), array("limit" => 1)); $bulk->update(array("foo" => "bar"), array('$set' => array("foo" => "baz")), array("limit" => 1, "upsert" => 0)); $retval = $manager->executeBulkWrite(NS, $bulk); printf("Inserted: %d\n", getInsertCount($retval)); printf("Deleted: %d\n", getDeletedCount($retval)); printf("Updated: %d\n", getModifiedCount($retval)); printf("Upserted: %d\n", getUpsertedCount($retval)); foreach(getWriteErrors($retval) as $error) { printf("WriteErrors: %", $error); } ?> ===DONE=== --EXPECT-- Inserted: 3 Deleted: 1 Updated: 1 Upserted: 0 ===DONE=== mongodb-1.21.0/tests/connect/standalone-auth_error-001.phpt0000644000175100001660000000175314760300421020432 0ustar --TEST-- Connect to MongoDB with using default auth mechanism and wrong password --SKIPIF-- --FILE-- insert(array("my" => "value")); echo throws(function() use($manager, $bulk) { $manager->executeBulkWrite(NS, $bulk); }, 'MongoDB\Driver\Exception\BulkWriteException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\BulkWriteException Bulk write failed due to previous MongoDB\Driver\Exception\AuthenticationException: Authentication failed. ===DONE=== mongodb-1.21.0/tests/connect/standalone-plain-0001.phpt0000644000175100001660000000403414760300421017436 0ustar --TEST-- Connect to MongoDB with using PLAIN auth mechanism --XFAIL-- authMechanism=PLAIN (LDAP) tests must be reimplemented (PHPC-1172) parse_url() tests must be reimplemented (PHPC-1177) --SKIPIF-- --FILE-- "bugs", "roles" => array(array("role" => "readWrite", "db" => DATABASE_NAME)), ); $command = new MongoDB\Driver\Command($cmd); try { $result = $adminmanager->executeCommand('$external', $command); echo "User Created\n"; } catch(Exception $e) { echo $e->getMessage(), "\n"; } $username = "bugs"; $password = "password"; $database = '$external'; $dsn = sprintf("mongodb://%s:%s@%s:%d/?authSource=%s&authMechanism=PLAIN", $username, $password, $parsed["host"], $parsed["port"], $database); $manager = create_test_manager($dsn); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array("very" => "important")); try { $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(array("very" => "important")); $cursor = $manager->executeQuery(NS, $query); foreach($cursor as $document) { var_dump($document->very); } $cmd = new MongoDB\Driver\Command(array("drop" => COLLECTION_NAME)); $result = $manager->executeCommand(DATABASE_NAME, $cmd); } catch(Exception $e) { printf("Caught %s: %s\n", get_class($e), $e->getMessage()); } $cmd = array( "dropUser" => "bugs", ); $command = new MongoDB\Driver\Command($cmd); try { $result = $adminmanager->executeCommand('$external', $command); echo "User deleted\n"; } catch(Exception $e) { echo $e->getMessage(), "\n"; } ?> ===DONE=== --EXPECT-- User Created string(9) "important" User deleted ===DONE=== mongodb-1.21.0/tests/connect/standalone-plain-0002.phpt0000644000175100001660000000341214760300421017436 0ustar --TEST-- Connect to MongoDB with using PLAIN auth mechanism #002 --XFAIL-- authMechanism=PLAIN (LDAP) tests must be reimplemented (PHPC-1172) parse_url() tests must be reimplemented (PHPC-1177) --SKIPIF-- --FILE-- "bugs", "roles" => array(array("role" => "readWrite", "db" => DATABASE_NAME)), ); $command = new MongoDB\Driver\Command($cmd); try { $result = $adminmanager->executeCommand('$external', $command); echo "User Created\n"; } catch(Exception $e) { echo $e->getMessage(), "\n"; } $username = "bugs"; $password = "wrong-password"; $database = '$external'; $dsn = sprintf("mongodb://%s:%s@%s:%d/?authSource=%s&authMechanism=PLAIN", $username, $password, $parsed["host"], $parsed["port"], $database); $manager = create_test_manager($dsn); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array("very" => "important")); throws(function() use($manager, $bulk) { $manager->executeBulkWrite(NS, $bulk); }, "MongoDB\Driver\Exception\AuthenticationException"); $cmd = array( "dropUser" => "bugs", ); $command = new MongoDB\Driver\Command($cmd); try { $result = $adminmanager->executeCommand('$external', $command); echo "User deleted\n"; } catch(Exception $e) { echo $e->getMessage(), "\n"; } ?> ===DONE=== --EXPECT-- User Created OK: Got MongoDB\Driver\Exception\AuthenticationException User deleted ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-no_verify-001.phpt0000644000175100001660000000177214760300421021060 0ustar --TEST-- Connect to MongoDB with SSL and no host/cert verification (driver options) --SKIPIF-- --FILE-- true, "weak_cert_validation" => true, ]; $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_invalid_hostname" driver option is deprecated. Please use the "tlsAllowInvalidHostnames" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "weak_cert_validation" driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s ping: 1 ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-no_verify-002.phpt0000644000175100001660000000233514760300421021055 0ustar --TEST-- Connect to MongoDB with SSL and no host/cert verification (context options) --SKIPIF-- --FILE-- stream_context_create([ 'ssl' => [ 'allow_invalid_hostname' => true, 'allow_self_signed' => true, // "weak_cert_validation" alias ], ]), ]; $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_invalid_hostname" driver option is deprecated. Please use the "tlsAllowInvalidHostnames" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_self_signed" context driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s ping: 1 ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-no_verify-003.phpt0000644000175100001660000000123114760300421021050 0ustar --TEST-- Connect to MongoDB with SSL and no host/cert verification (URI options) --SKIPIF-- --FILE-- true, 'tlsAllowInvalidCertificates' => true, ]; $manager = create_test_manager(URI, $uriOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); ?> ===DONE=== --EXPECT-- ping: 1 ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-verify_cert-001.phpt0000644000175100001660000000242214760300421021372 0ustar --TEST-- Connect to MongoDB with SSL and cert verification (driver options) --SKIPIF-- --FILE-- true, 'weak_cert_validation' => false, 'ca_file' => SSL_DIR . '/ca.pem', ]; $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_invalid_hostname" driver option is deprecated. Please use the "tlsAllowInvalidHostnames" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "weak_cert_validation" driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "ca_file" driver option is deprecated. Please use the "tlsCAFile" URI option instead.%s ping: 1 ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-verify_cert-002.phpt0000644000175100001660000000303614760300421021375 0ustar --TEST-- Connect to MongoDB with SSL and cert verification (context options) --SKIPIF-- --FILE-- stream_context_create([ 'ssl' => [ // libmongoc does not allow the hostname to be overridden as "server" 'allow_invalid_hostname' => true, 'allow_self_signed' => false, // "weak_cert_validation" alias 'cafile' => SSL_DIR . '/ca.pem', // "ca_file" alias ], ]), ]; $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_invalid_hostname" driver option is deprecated. Please use the "tlsAllowInvalidHostnames" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_self_signed" context driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "cafile" context driver option is deprecated. Please use the "tlsCAFile" URI option instead.%s ping: 1 ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-verify_cert-003.phpt0000644000175100001660000000144314760300421021376 0ustar --TEST-- Connect to MongoDB with SSL and cert verification (URI options) --SKIPIF-- --FILE-- true, 'tlsAllowInvalidCertificates' => false, 'tlsCAFile' => SSL_DIR . '/ca.pem', ]; $manager = create_test_manager(URI, $uriOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); ?> ===DONE=== --EXPECT-- ping: 1 ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-verify_cert-error-001.phpt0000644000175100001660000000240214760300421022517 0ustar --TEST-- Connect to MongoDB with SSL and cert verification error (driver options) --SKIPIF-- --FILE-- true, 'weak_cert_validation' => false, ]; echo throws(function() use ($driverOptions) { $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); }, MongoDB\Driver\Exception\ConnectionException::class, 'executeCommand'), "\n"; ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_invalid_hostname" driver option is deprecated. Please use the "tlsAllowInvalidHostnames" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "weak_cert_validation" driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s OK: Got MongoDB\Driver\Exception\ConnectionException thrown from executeCommand %sTLS handshake failed%s ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-verify_cert-error-002.phpt0000644000175100001660000000275514760300421022533 0ustar --TEST-- Connect to MongoDB with SSL and cert verification error (context options) --SKIPIF-- --FILE-- stream_context_create([ 'ssl' => [ // libmongoc does not allow the hostname to be overridden as "server" 'allow_invalid_hostname' => true, 'allow_self_signed' => false, // "weak_cert_validation" alias ], ]), ]; echo throws(function() use ($driverOptions) { $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); }, MongoDB\Driver\Exception\ConnectionException::class, 'executeCommand'), "\n"; ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_invalid_hostname" driver option is deprecated. Please use the "tlsAllowInvalidHostnames" URI option instead.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_self_signed" context driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s OK: Got MongoDB\Driver\Exception\ConnectionException thrown from executeCommand %sTLS handshake failed%s ===DONE=== mongodb-1.21.0/tests/connect/standalone-ssl-verify_cert-error-003.phpt0000644000175100001660000000163714760300421022532 0ustar --TEST-- Connect to MongoDB with SSL and cert verification error (URI options) --SKIPIF-- --FILE-- true, 'tlsAllowInvalidCertificates' => false, ]; echo throws(function() use ($uriOptions) { $manager = create_test_manager(URI, $uriOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); }, MongoDB\Driver\Exception\ConnectionException::class, 'executeCommand'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionException thrown from executeCommand %sTLS handshake failed%s ===DONE=== mongodb-1.21.0/tests/connect/standalone-x509-auth-001.phpt0000644000175100001660000000155314760300421017722 0ustar --TEST-- Connect to MongoDB with SSL and X509 auth --SKIPIF-- --FILE-- true, 'weak_cert_validation' => false, 'ca_file' => SSL_DIR . '/ca.pem', 'pem_file' => SSL_DIR . '/client.pem', ]; $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["ok"]=> float(1) } ===DONE=== mongodb-1.21.0/tests/connect/standalone-x509-auth-002.phpt0000644000175100001660000000207014760300421017716 0ustar --TEST-- Connect to MongoDB with SSL and X509 auth (stream context) --SKIPIF-- --FILE-- stream_context_create([ 'ssl' => [ // libmongoc does not allow the hostname to be overridden as "server" 'allow_invalid_hostname' => true, 'allow_self_signed' => false, // "weak_cert_validation" alias 'cafile' => SSL_DIR . '/ca.pem', // "ca_file" alias 'local_cert' => SSL_DIR . '/client.pem', // "pem_file" alias ], ]), ]; $manager = create_test_manager(URI, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["ok"]=> float(1) } ===DONE=== mongodb-1.21.0/tests/connect/standalone-x509-error-0001.phpt0000644000175100001660000000276514760300421020200 0ustar --TEST-- X509 connection should not reuse previous stream after an auth failure --XFAIL-- parse_url() tests must be reimplemented (PHPC-1177) --SKIPIF-- --FILE-- true, 'ca_file' => SSL_DIR . '/ca.pem', 'pem_file' => SSL_DIR . '/client.pem', ]; // Wrong username for X509 authentication $parsed = parse_url(URI); $dsn = sprintf('mongodb://username@%s:%d/?ssl=true&authMechanism=MONGODB-X509', $parsed['host'], $parsed['port']); // Both should fail with auth failure, without reusing the previous stream for ($i = 0; $i < 2; $i++) { echo throws(function() use ($dsn, $driverOptions) { $manager = create_test_manager($dsn, [], $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); }, 'MongoDB\Driver\Exception\AuthenticationException', 'executeCommand'), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\AuthenticationException thrown from executeCommand auth failed OK: Got MongoDB\Driver\Exception\AuthenticationException thrown from executeCommand auth failed ===DONE=== mongodb-1.21.0/tests/connect/standalone-x509-extract_username-001.phpt0000644000175100001660000000225014760300421022325 0ustar --TEST-- Connect to MongoDB with SSL and X509 auth and username retrieved from cert --XFAIL-- parse_url() tests must be reimplemented (PHPC-1177) --SKIPIF-- --FILE-- true, 'weak_cert_validation' => false, 'ca_file' => SSL_DIR . '/ca.pem', 'pem_file' => SSL_DIR . '/client.pem', ]; $uriOptions = ['authMechanism' => 'MONGODB-X509', 'ssl' => true]; $parsed = parse_url(URI); $uri = sprintf('mongodb://%s:%d', $parsed['host'], $parsed['port']); $manager = create_test_manager($uri, $uriOptions, $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["ok"]=> float(1) } ===DONE=== mongodb-1.21.0/tests/connect/standalone-x509-extract_username-002.phpt0000644000175100001660000000256514760300421022337 0ustar --TEST-- Connect to MongoDB with SSL and X509 auth and username retrieved from cert (stream context) --XFAIL-- parse_url() tests must be reimplemented (PHPC-1177) --SKIPIF-- --FILE-- stream_context_create([ 'ssl' => [ // libmongoc does not allow the hostname to be overridden as "server" 'allow_invalid_hostname' => true, 'allow_self_signed' => false, // "weak_cert_validation" alias 'cafile' => SSL_DIR . '/ca.pem', // "ca_file" alias 'local_cert' => SSL_DIR . '/client.pem', // "pem_file" alias ], ]), ]; $uriOptions = ['authMechanism' => 'MONGODB-X509', 'ssl' => true]; $parsed = parse_url(URI); $uri = sprintf('mongodb://%s:%d', $parsed['host'], $parsed['port']); $manager = create_test_manager($uri, $uriOptions, $driverOptions); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["ok"]=> float(1) } ===DONE=== mongodb-1.21.0/tests/cursor/bug0671-001.phpt0000644000175100001660000000121514760300421015102 0ustar --TEST-- PHPC-671: Segfault if Manager is already freed when destructing live Cursor --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); unset($manager); unset($cursor); ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/cursor/bug0732-001.phpt0000644000175100001660000000164614760300421015110 0ustar --TEST-- PHPC-732: Possible mongoc_client_t use-after-free with Cursor wrapped in generator --SKIPIF-- --FILE-- $value) { yield $key => $value; } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); $generator = wrapCursor($cursor); foreach ($generator as $value) { echo "Exiting during first iteration on generator\n"; exit(0); } ?> ===DONE=== --EXPECT-- Exiting during first iteration on generator mongodb-1.21.0/tests/cursor/bug0849-001.phpt0000644000175100001660000000176514760300421015123 0ustar --TEST-- PHPC-849: Cursor::setTypeMap() leaks current element if called during iteration --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); $cursor->setTypeMap(['root' => 'stdClass']); foreach ($cursor as $i => $document) { // Type map will apply to the next iteration, since current element is already converted $cursor->setTypeMap(['root' => ($i % 2 ? 'stdClass' : 'array')]); var_dump($document); } ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["_id"]=> int(1) } array(1) { ["_id"]=> int(2) } object(stdClass)#%d (%d) { ["_id"]=> int(3) } ===DONE=== mongodb-1.21.0/tests/cursor/bug0924-001.phpt0000644000175100001660000000273414760300421015112 0ustar --TEST-- PHPC-924: Cursor::setTypeMap() may unnecessarily convert first BSON document (type map) --SKIPIF-- --FILE-- data['_id'] = $id; } #[\ReturnTypeWillChange] public function bsonSerialize() { return (object) $this->data; } public function bsonUnserialize(array $data): void { printf("%s called for ID: %s\n", __METHOD__, $data['_id']); $this->data = $data; } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(new MyDocument('a')); $bulk->insert(new MyDocument('b')); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); $cursor->setTypeMap(['root' => 'MyDocument']); foreach ($cursor as $i => $document) { var_dump($document); } ?> ===DONE=== --EXPECTF-- MyDocument::bsonUnserialize called for ID: a object(MyDocument)#%d (%d) { ["data":"MyDocument":private]=> array(1) { ["_id"]=> string(1) "a" } } MyDocument::bsonUnserialize called for ID: b object(MyDocument)#%d (%d) { ["data":"MyDocument":private]=> array(1) { ["_id"]=> string(1) "b" } } ===DONE=== mongodb-1.21.0/tests/cursor/bug0924-002.phpt0000644000175100001660000000357314760300421015115 0ustar --TEST-- PHPC-924: Cursor::setTypeMap() may unnecessarily convert first BSON document (__pclass) --SKIPIF-- --FILE-- data['_id'] = $id; } #[\ReturnTypeWillChange] public function bsonSerialize() { return (object) $this->data; } public function bsonUnserialize(array $data): void { printf("%s called for ID: %s\n", __METHOD__, $data['_id']); $this->data = $data; } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(new MyDocument('a')); $bulk->insert(new MyDocument('b')); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); /* This type map will have no effect on the query result, since the document * only contains an ID, but it allows us to test for unnecessary conversion. */ $cursor->setTypeMap(['array' => 'array']); foreach ($cursor as $i => $document) { var_dump($document); } ?> ===DONE=== --EXPECTF-- MyDocument::bsonUnserialize called for ID: a object(MyDocument)#%d (%d) { ["data":"MyDocument":private]=> array(2) { ["_id"]=> string(1) "a" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } } } MyDocument::bsonUnserialize called for ID: b object(MyDocument)#%d (%d) { ["data":"MyDocument":private]=> array(2) { ["_id"]=> string(1) "b" ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(10) "MyDocument" ["type"]=> int(128) } } } ===DONE=== mongodb-1.21.0/tests/cursor/bug1050-001.phpt0000644000175100001660000000524114760300421015075 0ustar --TEST-- PHPC-1050: Command cursor should not invoke getMore at execution --SKIPIF-- --FILE-- getCommandName() !== 'aggregate' && $event->getCommandName() !== 'getMore') { return; } printf("Executing command: %s\n", $event->getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { if ($event->getCommandName() !== 'aggregate' && $event->getCommandName() !== 'getMore') { return; } printf("Executing command took %0.6f seconds\n", $event->getDurationMicros() / 1000000); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $cmd = new MongoDB\Driver\Command( [ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$changeStream' => (object) []], ], 'cursor' => (object) [], ], [ 'maxAwaitTimeMS' => 500, ] ); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $cursor = $manager->executeReadCommand(DATABASE_NAME, $cmd); $it = new IteratorIterator($cursor); printf("Current position is valid: %s\n\n", $it->valid() ? 'yes' : 'no'); echo "Rewinding cursor\n"; $it->rewind(); printf("Current position is valid: %s\n\n", $it->valid() ? 'yes' : 'no'); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk); echo "Advancing cursor\n"; $it->next(); printf("Current position is valid: %s\n\n", $it->valid() ? 'yes' : 'no'); $document = $it->current(); if (isset($document)) { printf("Operation type: %s\n", $document->operationType); var_dump($document->fullDocument); } ?> ===DONE=== --EXPECTF-- Executing command: aggregate Executing command took 0.%d seconds Current position is valid: no Rewinding cursor Executing command: getMore Executing command took 0.%r(4|5)%r%d seconds Current position is valid: no Advancing cursor Executing command: getMore Executing command took 0.%d seconds Current position is valid: yes Operation type: insert object(stdClass)#%d (%d) { ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } ["x"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/cursor/bug1050-002.phpt0000644000175100001660000000624114760300421015077 0ustar --TEST-- PHPC-1050: Command cursor should not invoke getMore at execution (rewind omitted) --SKIPIF-- ', '7.99'); ?> --FILE-- getCommandName() !== 'aggregate' && $event->getCommandName() !== 'getMore') { return; } printf("Executing command: %s\n", $event->getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { if ($event->getCommandName() !== 'aggregate' && $event->getCommandName() !== 'getMore') { return; } printf("Executing command took %0.6f seconds\n", $event->getDurationMicros() / 1000000); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $cmd = new MongoDB\Driver\Command( [ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$changeStream' => (object) []], ], 'cursor' => (object) [], ], [ 'maxAwaitTimeMS' => 500, ] ); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $cursor = $manager->executeReadCommand(DATABASE_NAME, $cmd); $it = new IteratorIterator($cursor); printf("Current position is valid: %s\n\n", $it->valid() ? 'yes' : 'no'); echo "Advancing cursor\n"; $it->next(); printf("Current position is valid: %s\n\n", $it->valid() ? 'yes' : 'no'); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk); echo "Advancing cursor\n"; $it->next(); printf("Current position is valid: %s\n\n", $it->valid() ? 'yes' : 'no'); $document = $it->current(); if (isset($document)) { printf("Operation type: %s\n", $document->operationType); var_dump($document->fullDocument); } ?> ===DONE=== --EXPECTF-- Executing command: aggregate Executing command took 0.%d seconds Current position is valid: no Advancing cursor Executing command: getMore Executing command took 0.%r(4|5)%r%d seconds Current position is valid: no Advancing cursor Executing command: getMore Executing command took 0.%d seconds Current position is valid: yes Operation type: insert object(stdClass)#%d (%d) { ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } ["x"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/cursor/bug1151-001.phpt0000644000175100001660000000146514760300421015103 0ustar --TEST-- PHPC-1151: Segfault if session unset before first getMore (find) --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $session = $manager->startSession(); $cursor = $manager->executeQuery(NS, $query, ['session' => $session]); foreach ($cursor as $document) { unset($session); echo $document->_id, "\n"; } ?> ===DONE=== --EXPECT-- 1 2 3 ===DONE=== mongodb-1.21.0/tests/cursor/bug1151-002.phpt0000644000175100001660000000163414760300421015102 0ustar --TEST-- PHPC-1151: Segfault if session unset before first getMore (aggregate) --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [], 'cursor' => ['batchSize' => 2], ]); $session = $manager->startSession(); $cursor = $manager->executeReadCommand(DATABASE_NAME, $command, ['session' => $session]); foreach ($cursor as $document) { unset($session); echo $document->_id, "\n"; } ?> ===DONE=== --EXPECT-- 1 2 3 ===DONE=== mongodb-1.21.0/tests/cursor/bug1151-003.phpt0000644000175100001660000000137314760300421015103 0ustar --TEST-- PHPC-1151: Segfault if session unset before cursor is killed (find) --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $session = $manager->startSession(); $cursor = $manager->executeQuery(NS, $query, ['session' => $session]); unset($session); unset($cursor); ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/cursor/bug1151-004.phpt0000644000175100001660000000154214760300421015102 0ustar --TEST-- PHPC-1151: Segfault if session unset before cursor is killed (aggregate) --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [], 'cursor' => ['batchSize' => 2], ]); $session = $manager->startSession(); $cursor = $manager->executeReadCommand(DATABASE_NAME, $command, ['session' => $session]); unset($session); unset($cursor); ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/cursor/bug1152-001.phpt0000644000175100001660000001130314760300421015074 0ustar --TEST-- PHPC-1152: Command cursors should use the same session for getMore and killCursors (implicit) --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$match' => new stdClass]], 'cursor' => ['batchSize' => 2], ]); MongoDB\Driver\Monitoring\addSubscriber($this); /* By creating two cursors with the same name, PHP's reference counting * will destroy the first after the second is created. Note that * mongoc_cursor_destroy also destroys implicit sessions and returns * them to the LIFO pool. This sequencing allows us to test that getMore * and killCursors use the session ID corresponding to the original * aggregate command. */ $cursor = $manager->executeCommand(DATABASE_NAME, $command); $cursor->toArray(); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $cursor->toArray(); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $cursor = $manager->executeCommand(DATABASE_NAME, $command); unset($cursor); MongoDB\Driver\Monitoring\removeSubscriber($this); /* We should expect two unique session IDs over the course of the test, * since at most two implicit sessions would have been in use at any * given time. */ printf("Unique session IDs used: %d\n", count(array_unique($this->lsidByRequestId))); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $requestId = $event->getRequestId(); $sessionId = bin2hex((string) $event->getCommand()->lsid->id); printf("%s session ID: %s\n", $event->getCommandName(), $sessionId); if ($event->getCommandName() === 'aggregate') { if (isset($this->lsidByRequestId[$requestId])) { throw new UnexpectedValueException('Previous command observed for request ID: ' . $requestId); } $this->lsidByRequestId[$requestId] = $sessionId; } if ($event->getCommandName() === 'getMore') { $cursorId = (string) $event->getCommand()->getMore; if ( ! isset($this->lsidByCursorId[$cursorId])) { throw new UnexpectedValueException('No previous command observed for cursor ID: ' . $cursorId); } printf("getMore used same session as aggregate: %s\n", $sessionId === $this->lsidByCursorId[$cursorId] ? 'yes' : 'no'); } if ($event->getCommandName() === 'killCursors') { $cursorId = (string) $event->getCommand()->cursors[0]; if ( ! isset($this->lsidByCursorId[$cursorId])) { throw new UnexpectedValueException('No previous command observed for cursor ID: ' . $cursorId); } printf("killCursors used same session as aggregate: %s\n", $sessionId === $this->lsidByCursorId[$cursorId] ? 'yes' : 'no'); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { /* Associate the aggregate's session ID with its cursor ID so it can be * looked up by the subsequent getMore or killCursors */ if ($event->getCommandName() === 'aggregate') { $cursorId = (string) $event->getReply()->cursor->id; $requestId = $event->getRequestId(); $this->lsidByCursorId[$cursorId] = $this->lsidByRequestId[$requestId]; } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } (new Test)->executeCommand(); ?> ===DONE=== --EXPECTF-- aggregate session ID: %x getMore session ID: %x getMore used same session as aggregate: yes aggregate session ID: %x getMore session ID: %x getMore used same session as aggregate: yes aggregate session ID: %x aggregate session ID: %x killCursors session ID: %x killCursors used same session as aggregate: yes killCursors session ID: %x killCursors used same session as aggregate: yes Unique session IDs used: 2 ===DONE=== mongodb-1.21.0/tests/cursor/bug1152-002.phpt0000644000175100001660000001113414760300421015077 0ustar --TEST-- PHPC-1152: Command cursors should use the same session for getMore and killCursors (explicit) --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$match' => new stdClass]], 'cursor' => ['batchSize' => 2], ]); $session = $manager->startSession(); MongoDB\Driver\Monitoring\addSubscriber($this); /* This uses the same sequencing as the implicit session test; however, * we should expect all commands (aggregate, getMore, and killCursors) * to use the same explicit session ID. */ $cursor = $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); $cursor->toArray(); $cursor = $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); $cursor->toArray(); $cursor = $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); $cursor = $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); unset($cursor); MongoDB\Driver\Monitoring\removeSubscriber($this); /* We should expect one unique session ID over the course of the test, * since all commands used the same explicit session. */ printf("Unique session IDs used: %d\n", count(array_unique($this->lsidByRequestId))); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $requestId = $event->getRequestId(); $sessionId = bin2hex((string) $event->getCommand()->lsid->id); printf("%s session ID: %s\n", $event->getCommandName(), $sessionId); if ($event->getCommandName() === 'aggregate') { if (isset($this->lsidByRequestId[$requestId])) { throw new UnexpectedValueException('Previous command observed for request ID: ' . $requestId); } $this->lsidByRequestId[$requestId] = $sessionId; } if ($event->getCommandName() === 'getMore') { $cursorId = (string) $event->getCommand()->getMore; if ( ! isset($this->lsidByCursorId[$cursorId])) { throw new UnexpectedValueException('No previous command observed for cursor ID: ' . $cursorId); } printf("getMore used same session as aggregate: %s\n", $sessionId === $this->lsidByCursorId[$cursorId] ? 'yes' : 'no'); } if ($event->getCommandName() === 'killCursors') { $cursorId = (string) $event->getCommand()->cursors[0]; if ( ! isset($this->lsidByCursorId[$cursorId])) { throw new UnexpectedValueException('No previous command observed for cursor ID: ' . $cursorId); } printf("killCursors used same session as aggregate: %s\n", $sessionId === $this->lsidByCursorId[$cursorId] ? 'yes' : 'no'); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { /* Associate the aggregate's session ID with its cursor ID so it can be * looked up by the subsequent getMore or killCursors */ if ($event->getCommandName() === 'aggregate') { $cursorId = (string) $event->getReply()->cursor->id; $requestId = $event->getRequestId(); $this->lsidByCursorId[$cursorId] = $this->lsidByRequestId[$requestId]; } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } (new Test)->executeCommand(); ?> ===DONE=== --EXPECTF-- aggregate session ID: %x getMore session ID: %x getMore used same session as aggregate: yes aggregate session ID: %x getMore session ID: %x getMore used same session as aggregate: yes aggregate session ID: %x aggregate session ID: %x killCursors session ID: %x killCursors used same session as aggregate: yes killCursors session ID: %x killCursors used same session as aggregate: yes Unique session IDs used: 1 ===DONE=== mongodb-1.21.0/tests/cursor/bug1162-001.phpt0000644000175100001660000000165614760300421015107 0ustar --TEST-- MongoDB\Driver\Cursor segfault dumping cursor while iterating with IteratorIterator --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); $iterator = new IteratorIterator($cursor); $iterator->rewind(); var_dump($cursor); $iterator->next(); var_dump($cursor); $iterator->next(); var_dump($cursor); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Cursor)#%d (%d) {%A } object(MongoDB\Driver\Cursor)#%d (%d) {%A } object(MongoDB\Driver\Cursor)#%d (%d) {%A } ===DONE=== mongodb-1.21.0/tests/cursor/bug1274-001.phpt0000644000175100001660000000424514760300421015110 0ustar --TEST-- PHPC-1274: Cursor destruct should not kill cursor from parent process --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); $childPid = pcntl_fork(); if ($childPid === 0) { echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } printf("Parent fully iterated cursor for %d documents\n", iterator_count($cursor)); } ?> ===DONE=== --EXPECT-- Parent executes find with batchSize: 2 Child exits Parent waited for child to exit Parent executes getMore with batchSize: 2 Parent fully iterated cursor for 3 documents ===DONE=== mongodb-1.21.0/tests/cursor/bug1274-002.phpt0000644000175100001660000000650414760300421015111 0ustar --TEST-- PHPC-1274: Child process can still iterate cursor from parent process --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $manager->executeBulkWrite(NS, $bulk); $subscriber = new CommandLogger; MongoDB\Driver\Monitoring\addSubscriber($subscriber); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); $childPid = pcntl_fork(); if ($childPid === 0) { /* This test asserts that mongoc_client_reset() does not prevent child * processes from actively interacting with a parent's cursor. Resetting the * client only prevents a child from inadvertently closing a parent cursor * via its php_phongo_cursor_free_object handler. * * Note: this test excludes SSL environments because we cannot interact with * the socket in a child without affecting the parent (and vice versa) due * to the SSL session. */ printf("Child fully iterated cursor for %d documents\n", iterator_count($cursor)); echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } echo throws(function() use ($cursor) { printf("Parent fully iterated cursor for %d documents\n", iterator_count($cursor)); }, 'MongoDB\Driver\Exception\RuntimeException'), "\n"; } /* This test doesn't need to assert that libmongoc may call killCursors when * destroying a cursor that previously encountered a CursorNotFound error. * See: https://jira.mongodb.org/browse/CDRIVER-3474 */ MongoDB\Driver\Monitoring\removeSubscriber($subscriber); ?> ===DONE=== --EXPECTF-- Parent executes find with batchSize: 2 Child executes getMore with batchSize: 2 Child fully iterated cursor for 3 documents Child exits Parent waited for child to exit Parent executes getMore with batchSize: 2 OK: Got MongoDB\Driver\Exception\RuntimeException %r(Cursor not found, cursor id: \d+|cursor id \d+ not found|Cursor not found \(.*id: \d+\)\.)%r ===DONE=== mongodb-1.21.0/tests/cursor/bug1274-003.phpt0000644000175100001660000000555114760300421015113 0ustar --TEST-- PHPC-1274: Child process should not reset parent client multiple times --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); $childPid = pcntl_fork(); if ($childPid === 0) { /* By having the child execute a query with the parent's client, unsetting * the parent's cursor, and then iterating the child's cursor, we test that * the parent's client is reset only once and prior to execution of the * child's find and getMore commands. If the client were reset multiple * times (i.e. between find and getMore), mongoc_cursor_next() would report * an error for advancing the cursor after resetting its client. */ $childCursor = $manager->executeQuery(NS, $query); // Unsetting the parent's cursor should not reset its client a second time unset($cursor); printf("Child fully iterated cursor for %d documents\n", iterator_count($childCursor)); echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } unset($cursor); } ?> ===DONE=== --EXPECT-- Parent executes find with batchSize: 2 Child executes find with batchSize: 2 Child executes getMore with batchSize: 2 Child fully iterated cursor for 3 documents Child exits Parent waited for child to exit Parent executes killCursors ===DONE=== mongodb-1.21.0/tests/cursor/bug1274-004.phpt0000644000175100001660000000436214760300421015113 0ustar --TEST-- PHPC-1274: Cursor destruct should not kill cursor from parent process (disableClientPersistence=true) --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); $childPid = pcntl_fork(); if ($childPid === 0) { echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } printf("Parent fully iterated cursor for %d documents\n", iterator_count($cursor)); } ?> ===DONE=== --EXPECT-- Parent executes find with batchSize: 2 Child exits Parent waited for child to exit Parent executes getMore with batchSize: 2 Parent fully iterated cursor for 3 documents ===DONE=== mongodb-1.21.0/tests/cursor/bug1274-005.phpt0000644000175100001660000000662114760300421015114 0ustar --TEST-- PHPC-1274: Child process can still iterate cursor from parent process (disableClientPersistence=true) --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $manager->executeBulkWrite(NS, $bulk); $subscriber = new CommandLogger; MongoDB\Driver\Monitoring\addSubscriber($subscriber); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); $childPid = pcntl_fork(); if ($childPid === 0) { /* This test asserts that mongoc_client_reset() does not prevent child * processes from actively interacting with a parent's cursor. Resetting the * client only prevents a child from inadvertently closing a parent cursor * via its php_phongo_cursor_free_object handler. * * Note: this test excludes SSL environments because we cannot interact with * the socket in a child without affecting the parent (and vice versa) due * to the SSL session. */ printf("Child fully iterated cursor for %d documents\n", iterator_count($cursor)); echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } echo throws(function() use ($cursor) { printf("Parent fully iterated cursor for %d documents\n", iterator_count($cursor)); }, 'MongoDB\Driver\Exception\RuntimeException'), "\n"; } /* This test doesn't need to assert that libmongoc may call killCursors when * destroying a cursor that previously encountered a CursorNotFound error. * See: https://jira.mongodb.org/browse/CDRIVER-3474 */ MongoDB\Driver\Monitoring\removeSubscriber($subscriber); ?> ===DONE=== --EXPECTF-- Parent executes find with batchSize: 2 Child executes getMore with batchSize: 2 Child fully iterated cursor for 3 documents Child exits Parent waited for child to exit Parent executes getMore with batchSize: 2 OK: Got MongoDB\Driver\Exception\RuntimeException %r(Cursor not found, cursor id: \d+|cursor id \d+ not found|Cursor not found \(.*id: \d+\)\.)%r ===DONE=== mongodb-1.21.0/tests/cursor/bug1274-006.phpt0000644000175100001660000000566614760300421015125 0ustar --TEST-- PHPC-1274: Child process should not reset parent client multiple times (disableClientPersistence=true) --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); $childPid = pcntl_fork(); if ($childPid === 0) { /* By having the child execute a query with the parent's client, unsetting * the parent's cursor, and then iterating the child's cursor, we test that * the parent's client is reset only once and prior to execution of the * child's find and getMore commands. If the client were reset multiple * times (i.e. between find and getMore), mongoc_cursor_next() would report * an error for advancing the cursor after resetting its client. */ $childCursor = $manager->executeQuery(NS, $query); // Unsetting the parent's cursor should not reset its client a second time unset($cursor); printf("Child fully iterated cursor for %d documents\n", iterator_count($childCursor)); echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } unset($cursor); } ?> ===DONE=== --EXPECT-- Parent executes find with batchSize: 2 Child executes find with batchSize: 2 Child executes getMore with batchSize: 2 Child fully iterated cursor for 3 documents Child exits Parent waited for child to exit Parent executes killCursors ===DONE=== mongodb-1.21.0/tests/cursor/bug1419-001.phpt0000644000175100001660000000227414760300421015111 0ustar --TEST-- PHPC-1419: error labels from getMore are not exposed --SKIPIF-- --FILE-- selectServer(new \MongoDB\Driver\ReadPreference('primary')); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $server->executeQuery(NS, new \MongoDB\Driver\Query([], ['batchSize' => 1])); $iterator = new IteratorIterator($cursor); configureTargetedFailPoint( $server, 'failCommand', [ 'times' => 1] , [ 'errorCode' => 280, 'failCommands' => ['getMore'] ] ); try { $iterator->next(); } catch (\MongoDB\Driver\Exception\ServerException $e) { var_dump($e->hasErrorLabel('NonResumableChangeStreamError')); } ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/cursor/bug1529-001.phpt0000644000175100001660000000627514760300421015120 0ustar --TEST-- PHPC-1529: Resetting a client should also reset the keyVaultClient --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $keyVaultClient = create_test_manager(URI, [], ['disableClientPersistence' => true]); $autoEncryptionOpts = [ 'keyVaultClient' => $keyVaultClient, 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]; $manager = create_test_manager(URI, [], ['autoEncryption' => $autoEncryptionOpts, 'disableClientPersistence' => true]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $keyVaultClient->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $keyVaultClient->executeQuery(NS, $query); $childPid = pcntl_fork(); if ($childPid === 0) { /* Executing any operation with the parent's client resets this client as well as * the keyVaultClient. Continuing iteration of the cursor opened on the * keyVaultClient before resetting it should then result in an error due to * the client having been reset. */ $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); echo throws( function () use ($cursor) { iterator_count($cursor); }, MongoDB\Driver\Exception\RuntimeException::class ), "\n"; echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } unset($cursor); } ?> ===DONE=== --EXPECT-- Parent executes find with batchSize: 2 Child executes ping OK: Got MongoDB\Driver\Exception\RuntimeException Cannot advance cursor after client reset Child exits Parent waited for child to exit Parent executes killCursors ===DONE=== mongodb-1.21.0/tests/cursor/bug1713-001.phpt0000644000175100001660000000073014760300421015101 0ustar --TEST-- PHPC-1713: MongoDB\Driver\Cursor::current() does not return anything --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query([])); var_dump($cursor->valid()); var_dump($cursor->current()); ?> ===DONE=== --EXPECTF-- bool(false) NULL ===DONE=== mongodb-1.21.0/tests/cursor/cursor-001.phpt0000644000175100001660000000054314760300421015327 0ustar --TEST-- MongoDB\Driver\Cursor implements MongoDB\Driver\CursorInterface and Traversable --FILE-- ===DONE=== --EXPECT-- bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/cursor/cursor-IteratorIterator-001.phpt0000644000175100001660000000147314760300421020633 0ustar --TEST-- MongoDB\Driver\Cursor query result iteration through IteratorIterator --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array("x" => 1))); foreach (new IteratorIterator($cursor) as $document) { var_dump($document); } ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-IteratorIterator-002.phpt0000644000175100001660000000175114760300421020633 0ustar --TEST-- MongoDB\Driver\Cursor command result iteration through IteratorIterator --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command(array( 'aggregate' => COLLECTION_NAME, 'pipeline' => array( array('$match' => array('x' => 1)), ), 'cursor' => new stdClass, )); $cursor = $manager->executeCommand(DATABASE_NAME, $command); foreach (new IteratorIterator($cursor) as $document) { var_dump($document); } ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-IteratorIterator-003.phpt0000644000175100001660000000177414760300421020641 0ustar --TEST-- MongoDB\Driver\Cursor iteration beyond last document --SKIPIF-- --FILE-- insert(['_id' => 1]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); $iterator = new IteratorIterator($cursor); $iterator->rewind(); var_dump($iterator->current()); $iterator->next(); var_dump($iterator->current()); // libmongoc throws on superfluous iteration of find command cursor (CDRIVER-1234) echo throws(function() use ($iterator) { $iterator->next(); }, 'MongoDB\Driver\Exception\RuntimeException'), "\n"; ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["_id"]=> int(1) } NULL OK: Got MongoDB\Driver\Exception\RuntimeException Cannot advance a completed or failed cursor. ===DONE=== mongodb-1.21.0/tests/cursor/cursor-NoRewindIterator-001.phpt0000644000175100001660000000313614760300421020565 0ustar --TEST-- MongoDB\Driver\Cursor query result iteration through NoRewindIterator --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array("x" => 1))); /* IteratorIterator requires either rewind() or next() to be called at least * once to populate its current.data pointer, which valid() checks. Since next() * would skip the first element and NoRewindIterator::rewind() is a NOP, we must * explicitly call IteratorIterator::rewind() before composing it. */ $iteratorIterator = new IteratorIterator($cursor); $iteratorIterator->rewind(); $noRewindIterator = new NoRewindIterator($iteratorIterator); foreach ($noRewindIterator as $document) { var_dump($document); } /* NoRewindIterator::rewind() is a NOP, so attempting to iterate a second time * or calling rewind() directly accomplishes nothing. That said, it does avoid * the exception one would otherwise get invoking the rewind handler after * iteration has started. */ foreach ($noRewindIterator as $document) { var_dump($document); } $noRewindIterator->rewind(); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-destruct-001.phpt0000644000175100001660000000310014760300421017152 0ustar --TEST-- MongoDB\Driver\Cursor destruct should kill a live cursor --SKIPIF-- --FILE-- executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(array('serverStatus' => 1))); $result = current($cursor->toArray()); if (isset($result->metrics->cursor->open->total)) { return $result->metrics->cursor->open->total; } if (isset($result->cursors->totalOpen)) { return $result->cursors->totalOpen; } throw new RuntimeException('Could not find number of open cursors in serverStatus'); } $manager = create_test_manager(); // Select a specific server for future operations to avoid mongos switching in sharded clusters $server = $manager->selectServer(new \MongoDB\Driver\ReadPreference('primary')); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1)); $bulk->insert(array('_id' => 2)); $bulk->insert(array('_id' => 3)); $server->executeBulkWrite(NS, $bulk); $numOpenCursorsBeforeQuery = getNumOpenCursors($server); $cursor = $server->executeQuery(NS, new MongoDB\Driver\Query(array(), array('batchSize' => 2))); var_dump($cursor->isDead()); var_dump(getNumOpenCursors($server) == $numOpenCursorsBeforeQuery + 1); unset($cursor); var_dump(getNumOpenCursors($server) == $numOpenCursorsBeforeQuery); ?> ===DONE=== --EXPECT-- bool(false) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/cursor/cursor-getmore-001.phpt0000644000175100001660000000162114760300421016765 0ustar --TEST-- MongoDB\Driver\Cursor query result iteration with batchSize requiring getmore with full batches --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array(), array('batchSize' => 2))); foreach ($cursor as $i => $document) { printf("%d => {_id: %d}\n", $i, $document->_id); } ?> ===DONE=== --EXPECT-- Inserted: 6 0 => {_id: 0} 1 => {_id: 1} 2 => {_id: 2} 3 => {_id: 3} 4 => {_id: 4} 5 => {_id: 5} ===DONE=== mongodb-1.21.0/tests/cursor/cursor-getmore-002.phpt0000644000175100001660000000160714760300421016772 0ustar --TEST-- MongoDB\Driver\Cursor query result iteration with batchSize requiring getmore with non-full batches --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array(), array('batchSize' => 2))); foreach ($cursor as $i => $document) { printf("%d => {_id: %d}\n", $i, $document->_id); } ?> ===DONE=== --EXPECT-- Inserted: 5 0 => {_id: 0} 1 => {_id: 1} 2 => {_id: 2} 3 => {_id: 3} 4 => {_id: 4} ===DONE=== mongodb-1.21.0/tests/cursor/cursor-getmore-003.phpt0000644000175100001660000000206614760300421016773 0ustar --TEST-- MongoDB\Driver\Cursor command result iteration with batchSize requiring getmore with full batches --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $command = new MongoDB\Driver\Command(array( 'aggregate' => COLLECTION_NAME, 'pipeline' => array( array('$match' => new stdClass), ), 'cursor' => array('batchSize' => 2), )); $cursor = $manager->executeCommand(DATABASE_NAME, $command); foreach ($cursor as $i => $document) { printf("%d => {_id: %d}\n", $i, $document->_id); } ?> ===DONE=== --EXPECT-- Inserted: 6 0 => {_id: 0} 1 => {_id: 1} 2 => {_id: 2} 3 => {_id: 3} 4 => {_id: 4} 5 => {_id: 5} ===DONE=== mongodb-1.21.0/tests/cursor/cursor-getmore-004.phpt0000644000175100001660000000205414760300421016771 0ustar --TEST-- MongoDB\Driver\Cursor command result iteration with batchSize requiring getmore with non-full batches --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $command = new MongoDB\Driver\Command(array( 'aggregate' => COLLECTION_NAME, 'pipeline' => array( array('$match' => new stdClass), ), 'cursor' => array('batchSize' => 2), )); $cursor = $manager->executeCommand(DATABASE_NAME, $command); foreach ($cursor as $i => $document) { printf("%d => {_id: %d}\n", $i, $document->_id); } ?> ===DONE=== --EXPECT-- Inserted: 5 0 => {_id: 0} 1 => {_id: 1} 2 => {_id: 2} 3 => {_id: 3} 4 => {_id: 4} ===DONE=== mongodb-1.21.0/tests/cursor/cursor-getmore-005.phpt0000644000175100001660000000301414760300421016767 0ustar --TEST-- MongoDB\Driver\Cursor query result iteration with getmore failure --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); failGetMore($manager); throws(function() use ($cursor) { foreach ($cursor as $i => $document) { printf("%d => {_id: %d}\n", $i, $document->_id); } }, MongoDB\Driver\Exception\ServerException::class); ?> ===DONE=== --CLEAN-- --EXPECT-- Inserted: 5 0 => {_id: 0} 1 => {_id: 1} OK: Got MongoDB\Driver\Exception\ServerException ===DONE=== mongodb-1.21.0/tests/cursor/cursor-getmore-006.phpt0000644000175100001660000000322714760300421016776 0ustar --TEST-- MongoDB\Driver\Cursor command result iteration with getmore failure --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$match' => new stdClass], ], 'cursor' => ['batchSize' => 2], ]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); failGetMore($manager); throws(function() use ($cursor) { foreach ($cursor as $i => $document) { printf("%d => {_id: %d}\n", $i, $document->_id); } }, MongoDB\Driver\Exception\ServerException::class); ?> ===DONE=== --CLEAN-- --EXPECT-- Inserted: 5 0 => {_id: 0} 1 => {_id: 1} OK: Got MongoDB\Driver\Exception\ServerException ===DONE=== mongodb-1.21.0/tests/cursor/cursor-isDead-001.phpt0000644000175100001660000000133714760300421016520 0ustar --TEST-- MongoDB\Driver\Cursor::isDead() with basic iteration --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); foreach ($cursor as $_) { var_dump($cursor->isDead()); } var_dump($cursor->isDead()); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(false) bool(true) ===DONE=== mongodb-1.21.0/tests/cursor/cursor-isDead-002.phpt0000644000175100001660000000147314760300421016522 0ustar --TEST-- MongoDB\Driver\Cursor::isDead() with IteratorIterator --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); $iterator = new IteratorIterator($cursor); $iterator->rewind(); for ($i = 0; $i < 3; $i++) { var_dump($cursor->isDead()); $iterator->next(); } var_dump($cursor->isDead()); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(false) bool(true) ===DONE=== mongodb-1.21.0/tests/cursor/cursor-iterator-001.phpt0000644000175100001660000000247014760300421017157 0ustar --TEST-- MongoDB\Driver\Cursor does not allow iterating multiple times (foreach) --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); echo "\nFirst foreach statement:\n"; foreach ($cursor as $document) { var_dump($document); } echo "\nSecond foreach statement:\n"; echo throws(function () use ($cursor) { foreach ($cursor as $document) { echo "FAILED: get_iterator should not yield multiple iterators\n"; } }, MongoDB\Driver\Exception\LogicException::class), "\n"; ?> ===DONE=== --EXPECTF-- Inserted: 3 First foreach statement: object(stdClass)#%d (1) { ["_id"]=> int(0) } object(stdClass)#%d (1) { ["_id"]=> int(1) } object(stdClass)#%d (1) { ["_id"]=> int(2) } Second foreach statement: OK: Got MongoDB\Driver\Exception\LogicException Cursors cannot rewind after starting iteration ===DONE=== mongodb-1.21.0/tests/cursor/cursor-iterator-002.phpt0000644000175100001660000000240514760300421017156 0ustar --TEST-- MongoDB\Driver\Cursor does not allow iterating multiple times (toArray()) --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); echo "\nFirst Cursor::toArray():\n"; var_dump($cursor->toArray()); echo "\nSecond Cursor::toArray():\n"; echo throws(function () use ($cursor) { var_dump($cursor->toArray()); }, MongoDB\Driver\Exception\LogicException::class), "\n"; ?> ===DONE=== --EXPECTF-- Inserted: 3 First Cursor::toArray(): array(3) { [0]=> object(stdClass)#%d (1) { ["_id"]=> int(0) } [1]=> object(stdClass)#%d (1) { ["_id"]=> int(1) } [2]=> object(stdClass)#%d (1) { ["_id"]=> int(2) } } Second Cursor::toArray(): OK: Got MongoDB\Driver\Exception\LogicException Cursors cannot rewind after starting iteration ===DONE=== mongodb-1.21.0/tests/cursor/cursor-iterator-003.phpt0000644000175100001660000000153314760300421017160 0ustar --TEST-- MongoDB\Driver\Cursor handles invalid positions gracefully --SKIPIF-- --FILE-- insert(array('_id' => 0)); $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); $cursor->rewind(); var_dump($cursor->valid()); var_dump($cursor->key()); var_dump($cursor->current()); $cursor->next(); var_dump($cursor->valid()); var_dump($cursor->key()); var_dump($cursor->current()); ?> ===DONE=== --EXPECTF-- bool(true) int(0) object(stdClass)#%d (1) { ["_id"]=> int(0) } bool(false) NULL NULL ===DONE=== mongodb-1.21.0/tests/cursor/cursor-iterator-004.phpt0000644000175100001660000000324614760300421017164 0ustar --TEST-- MongoDB\Driver\Cursor allows exposing raw BSON objects --SKIPIF-- --FILE-- insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); $cursor->setTypemap(['root' => 'bson']); echo "\nFirst foreach statement:\n"; foreach ($cursor as $document) { var_dump($document); } echo "\nSecond foreach statement:\n"; echo throws(function () use ($cursor) { foreach ($cursor as $document) { echo "FAILED: get_iterator should not yield multiple iterators\n"; } }, MongoDB\Driver\Exception\LogicException::class), "\n"; ?> ===DONE=== --EXPECTF-- Inserted: 3 First foreach statement: object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(20) "DgAAABBfaWQAAAAAAAA=" ["value"]=> object(stdClass)#%d (%d) { ["_id"]=> int(0) } } object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(20) "DgAAABBfaWQAAQAAAAA=" ["value"]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) } } object(MongoDB\BSON\Document)#%d (%d) { ["data"]=> string(20) "DgAAABBfaWQAAgAAAAA=" ["value"]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) } } Second foreach statement: OK: Got MongoDB\Driver\Exception\LogicException Cursors cannot rewind after starting iteration ===DONE=== mongodb-1.21.0/tests/cursor/cursor-iterator_handlers-001.phpt0000644000175100001660000000400414760300421021032 0ustar --TEST-- MongoDB\Driver\Cursor iterator handlers --SKIPIF-- --FILE-- name = (string) $name; } public function dump() { $key = parent::key(); $current = parent::current(); $position = is_int($key) ? (string) $key : 'null'; $document = is_object($current) ? sprintf("{_id: %d}", $current->_id) : 'null'; printf("%s: %s => %s\n", $this->name, $position, $document); } } $manager = create_test_manager(); $bulkWrite = new MongoDB\Driver\BulkWrite; for ($i = 0; $i < 5; $i++) { $bulkWrite->insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); $a = new MyIteratorIterator($cursor, 'A'); echo "\nBefore rewinding, position and current element are not populated:\n"; $a->dump(); echo "\nAfter rewinding, current element is populated:\n"; $a->rewind(); $a->dump(); echo "\nAfter advancing, next element is populated:\n"; $a->next(); $a->dump(); echo "\nAdvancing through remaining elements:\n"; $a->next(); $a->dump(); $a->next(); $a->dump(); $a->next(); $a->dump(); echo "\nAdvancing beyond the last element:\n"; $a->next(); $a->dump(); ?> ===DONE=== --EXPECT-- Inserted: 5 Before rewinding, position and current element are not populated: A: null => null After rewinding, current element is populated: A: 0 => {_id: 0} After advancing, next element is populated: A: 1 => {_id: 1} Advancing through remaining elements: A: 2 => {_id: 2} A: 3 => {_id: 3} A: 4 => {_id: 4} Advancing beyond the last element: A: null => null ===DONE=== mongodb-1.21.0/tests/cursor/cursor-rewind-001.phpt0000644000175100001660000000450514760300421016617 0ustar --TEST-- MongoDB\Driver\Cursor cannot rewind after starting iteration --SKIPIF-- --FILE-- name = (string) $name; } public function dump() { $key = parent::key(); $current = parent::current(); $position = is_int($key) ? (string) $key : 'null'; $document = is_object($current) ? sprintf("{_id: %d}", $current->_id) : 'null'; printf("%s: %s => %s\n", $this->name, $position, $document); } } $manager = create_test_manager(); $bulkWrite = new MongoDB\Driver\BulkWrite; for ($i = 0; $i < 5; $i++) { $bulkWrite->insert(array('_id' => $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); $a = new MyIteratorIterator($cursor, 'A'); echo "\nRewinding sets the current element:\n"; $a->rewind(); $a->dump(); echo "\nRewinding again is OK since we haven't advanced:\n"; $a->rewind(); $a->dump(); echo "\nAdvancing populates the next element:\n"; $a->next(); $a->dump(); echo "\nRewinding after advancing is not OK:\n"; try { $a->rewind(); echo "FAILED: rewind should throw if iteration has started\n"; } catch (MongoDB\Driver\Exception\LogicException $e) { printf("LogicException: %s\n", $e->getMessage()); } echo "\nAdvancing through remaining elements:\n"; $a->next(); $a->dump(); $a->next(); $a->dump(); $a->next(); $a->dump(); echo "\nAdvancing beyond the last element:\n"; $a->next(); $a->dump(); ?> ===DONE=== --EXPECT-- Inserted: 5 Rewinding sets the current element: A: 0 => {_id: 0} Rewinding again is OK since we haven't advanced: A: 0 => {_id: 0} Advancing populates the next element: A: 1 => {_id: 1} Rewinding after advancing is not OK: LogicException: Cursors cannot rewind after starting iteration Advancing through remaining elements: A: 2 => {_id: 2} A: 3 => {_id: 3} A: 4 => {_id: 4} Advancing beyond the last element: A: null => null ===DONE=== mongodb-1.21.0/tests/cursor/cursor-session-001.phpt0000644000175100001660000000300414760300421017003 0ustar --TEST-- MongoDB\Driver\Cursor debug output for query cursor includes explicit session --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $session = $manager->startSession(); $cursor = $manager->executeQuery(NS, $query, ['session' => $session]); $iterator = new IteratorIterator($cursor); $iterator->rewind(); $iterator->next(); printf("Cursor ID is zero: %s\n", $cursor->getId(true) == 0 ? 'yes' : 'no'); var_dump($cursor); $iterator->next(); /* Per PHPC-1161, the Cursor will free a reference to the Session as soon as it * is exhausted. While this is primarily done to ensure implicit sessions for * command cursors are returned to the pool ASAP, it also applies to explicit * sessions. */ printf("\nCursor ID is zero: %s\n", $cursor->getId(true) == 0 ? 'yes' : 'no'); var_dump($cursor); ?> ===DONE=== --EXPECTF-- Cursor ID is zero: no object(MongoDB\Driver\Cursor)#%d (%d) { %a ["session"]=> object(MongoDB\Driver\Session)#%d (%d) { %a } %a } Cursor ID is zero: yes object(MongoDB\Driver\Cursor)#%d (%d) { %a ["session"]=> NULL %a } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-session-002.phpt0000644000175100001660000000250614760300421017012 0ustar --TEST-- MongoDB\Driver\Cursor debug output for query cursor omits implicit session --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); $iterator = new IteratorIterator($cursor); $iterator->rewind(); $iterator->next(); /* Implicit sessions for query cursors are never exposed to PHPC, as they are * handled internally by libmongoc. Cursor debug ouput should never report such * sessions. */ printf("Cursor ID is zero: %s\n", $cursor->getId(true) == 0 ? 'yes' : 'no'); var_dump($cursor); $iterator->next(); printf("\nCursor ID is zero: %s\n", $cursor->getId(true) == 0 ? 'yes' : 'no'); var_dump($cursor); ?> ===DONE=== --EXPECTF-- Cursor ID is zero: no object(MongoDB\Driver\Cursor)#%d (%d) { %a ["session"]=> NULL %a } Cursor ID is zero: yes object(MongoDB\Driver\Cursor)#%d (%d) { %a ["session"]=> NULL %a } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-session-003.phpt0000644000175100001660000000317614760300421017017 0ustar --TEST-- MongoDB\Driver\Cursor debug output for command cursor includes explicit session --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$match' => new stdClass]], 'cursor' => ['batchSize' => 2], ]); $session = $manager->startSession(); $cursor = $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); $iterator = new IteratorIterator($cursor); $iterator->rewind(); $iterator->next(); printf("Cursor ID is zero: %s\n", $cursor->getId(true) == 0 ? 'yes' : 'no'); var_dump($cursor); $iterator->next(); /* Per PHPC-1161, the Cursor will free a reference to the Session as soon as it * is exhausted. While this is primarily done to ensure implicit sessions for * command cursors are returned to the pool ASAP, it also applies to explicit * sessions. */ printf("\nCursor ID is zero: %s\n", $cursor->getId(true) == 0 ? 'yes' : 'no'); var_dump($cursor); ?> ===DONE=== --EXPECTF-- Cursor ID is zero: no object(MongoDB\Driver\Cursor)#%d (%d) { %a ["session"]=> object(MongoDB\Driver\Session)#%d (%d) { %a } %a } Cursor ID is zero: yes object(MongoDB\Driver\Cursor)#%d (%d) { %a ["session"]=> NULL %a } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-session-004.phpt0000644000175100001660000000311514760300421017011 0ustar --TEST-- MongoDB\Driver\Cursor debug output for command cursor includes implicit session --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$match' => new stdClass]], 'cursor' => ['batchSize' => 2], ]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $iterator = new IteratorIterator($cursor); $iterator->rewind(); $iterator->next(); printf("Cursor ID is zero: %s\n", $cursor->getId(true) == 0 ? 'yes' : 'no'); var_dump($cursor); $iterator->next(); /* Unlike implicit sessions for query cursors, which are handled internally by * libmongoc, PHPC-1152 emulates its own implicit sessions for command cursors * in order to ensure that command cursors always share the same session as the * originating command. */ printf("\nCursor ID is zero: %s\n", $cursor->getId(true) == 0 ? 'yes' : 'no'); var_dump($cursor); ?> ===DONE=== --EXPECTF-- Cursor ID is zero: no object(MongoDB\Driver\Cursor)#%d (%d) { %a ["session"]=> object(MongoDB\Driver\Session)#%d (%d) { %a } %a } Cursor ID is zero: yes object(MongoDB\Driver\Cursor)#%d (%d) { %a ["session"]=> NULL %a } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-setTypeMap_error-001.phpt0000644000175100001660000000735414760300421020640 0ustar --TEST-- Cursor::setTypeMap(): Type map classes must be instantiatable and implement Unserializable --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query([])); foreach ($classes as $class) { $typeMaps = [ ['array' => $class], ['document' => $class], ['root' => $class], ['fieldPaths' => ['x' => $class]], ]; foreach ($typeMaps as $typeMap) { printf("Test typeMap: %s\n", json_encode($typeMap)); echo throws(function() use ($cursor, $typeMap) { $cursor->setTypeMap($typeMap); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n\n"; } } ?> ===DONE=== --EXPECT-- Test typeMap: {"array":"MissingClass"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist Test typeMap: {"document":"MissingClass"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist Test typeMap: {"root":"MissingClass"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist Test typeMap: {"fieldPaths":{"x":"MissingClass"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist Test typeMap: {"array":"MyAbstractDocument"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyAbstractDocument is not instantiatable Test typeMap: {"document":"MyAbstractDocument"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyAbstractDocument is not instantiatable Test typeMap: {"root":"MyAbstractDocument"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyAbstractDocument is not instantiatable Test typeMap: {"fieldPaths":{"x":"MyAbstractDocument"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyAbstractDocument is not instantiatable Test typeMap: {"array":"MyDocument"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyDocument does not implement MongoDB\BSON\Unserializable Test typeMap: {"document":"MyDocument"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyDocument does not implement MongoDB\BSON\Unserializable Test typeMap: {"root":"MyDocument"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyDocument does not implement MongoDB\BSON\Unserializable Test typeMap: {"fieldPaths":{"x":"MyDocument"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MyDocument does not implement MongoDB\BSON\Unserializable Test typeMap: {"array":"MongoDB\\BSON\\Unserializable"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Interface MongoDB\BSON\Unserializable is not instantiatable Test typeMap: {"document":"MongoDB\\BSON\\Unserializable"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Interface MongoDB\BSON\Unserializable is not instantiatable Test typeMap: {"root":"MongoDB\\BSON\\Unserializable"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Interface MongoDB\BSON\Unserializable is not instantiatable Test typeMap: {"fieldPaths":{"x":"MongoDB\\BSON\\Unserializable"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException Interface MongoDB\BSON\Unserializable is not instantiatable ===DONE=== mongodb-1.21.0/tests/cursor/cursor-setTypeMap_error-002.phpt0000644000175100001660000000231314760300421020627 0ustar --TEST-- Cursor::setTypeMap() error does not alter current element --SKIPIF-- --FILE-- insert(['_id' => 1]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); $iterator = new IteratorIterator($cursor); $iterator->rewind(); var_dump($iterator->current()); echo throws(function() use ($cursor) { $cursor->setTypeMap(['root' => 'MissingClass']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; /* IteratorIterator only invokes spl_dual_it_fetch() for rewind() and next(). * We rewind a second time to ensure that the Cursor iterator's current element * is fetched again is remains unchanged. */ $iterator->rewind(); var_dump($iterator->current()); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["_id"]=> int(1) } OK: Got MongoDB\Driver\Exception\InvalidArgumentException Class MissingClass does not exist object(stdClass)#%d (%d) { ["_id"]=> int(1) } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-setTypeMap_error-003.phpt0000644000175100001660000000210514760300421020627 0ustar --TEST-- Cursor::setTypeMap(): fieldPaths must be an array, with single key/string elements --SKIPIF-- --FILE-- 'notAnArray'], ['fieldPaths' => ['notAssociative']], ]; $manager = create_test_manager(); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); foreach ($typeMaps as $typeMap) { printf("Test typeMap: %s\n", json_encode($typeMap)); echo throws(function() use ($cursor, $typeMap) { $cursor->setTypeMap($typeMap); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; } ?> ===DONE=== --EXPECT-- Test typeMap: {"fieldPaths":"notAnArray"} OK: Got MongoDB\Driver\Exception\InvalidArgumentException The 'fieldPaths' element is not an array Test typeMap: {"fieldPaths":["notAssociative"]} OK: Got MongoDB\Driver\Exception\InvalidArgumentException The 'fieldPaths' element is not an associative array ===DONE=== mongodb-1.21.0/tests/cursor/cursor-setTypeMap_error-004.phpt0000644000175100001660000000353414760300421020637 0ustar --TEST-- Cursor::setTypeMap(): invalid fieldPaths keys --SKIPIF-- --FILE-- 'MyDocument'], ['.foo' => 'MyDocument'], ['...' => 'MyDocument'], ['foo.' => 'MyDocument'], ['foo..bar' => 'MyDocument'], ]; $manager = create_test_manager(); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); foreach ($fieldPaths as $fieldPath) { $typeMap = ['fieldPaths' => $fieldPath]; printf("Test typeMap: %s\n", json_encode($typeMap)); echo throws(function() use ($cursor, $typeMap) { $cursor->setTypeMap($typeMap); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo "\n"; } ?> ===DONE=== --EXPECT-- Test typeMap: {"fieldPaths":{"":"MyDocument"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException The 'fieldPaths' element may not be an empty string Test typeMap: {"fieldPaths":{".foo":"MyDocument"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException A 'fieldPaths' key may not start with a '.' Test typeMap: {"fieldPaths":{"...":"MyDocument"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException A 'fieldPaths' key may not start with a '.' Test typeMap: {"fieldPaths":{"foo.":"MyDocument"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException A 'fieldPaths' key may not end with a '.' Test typeMap: {"fieldPaths":{"foo..bar":"MyDocument"}} OK: Got MongoDB\Driver\Exception\InvalidArgumentException A 'fieldPaths' key may not have an empty segment ===DONE=== mongodb-1.21.0/tests/cursor/cursor-tailable-001.phpt0000644000175100001660000000350414760300421017102 0ustar --TEST-- MongoDB\Driver\Cursor tailable iteration --SKIPIF-- --FILE-- insert(['_id' => $i]); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted %d document(s): %s\n", $writeResult->getInsertedCount(), implode(', ', range($from, $to))); } $manager = create_test_manager(); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'create' => COLLECTION_NAME, 'capped' => true, 'size' => 1048576, ])); insert($manager, 1, 3); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['tailable' => true])); $it = new IteratorIterator($cursor); $numAwaitAttempts = 0; $maxAwaitAttempts = 7; for ($it->rewind(); $numAwaitAttempts < $maxAwaitAttempts; $it->next()) { $document = $it->current(); if ($document !== null) { printf("{_id: %d}\n", $document->_id); continue; } if ($numAwaitAttempts === 2) { insert($manager, 4, 6); } if ($numAwaitAttempts === 5) { insert($manager, 7, 9); } echo "Awaiting results...\n"; $numAwaitAttempts += 1; } ?> ===DONE=== --EXPECT-- Inserted 3 document(s): 1, 2, 3 {_id: 1} {_id: 2} {_id: 3} Awaiting results... Awaiting results... Inserted 3 document(s): 4, 5, 6 Awaiting results... {_id: 4} {_id: 5} {_id: 6} Awaiting results... Awaiting results... Inserted 3 document(s): 7, 8, 9 Awaiting results... {_id: 7} {_id: 8} {_id: 9} Awaiting results... ===DONE=== mongodb-1.21.0/tests/cursor/cursor-tailable-002.phpt0000644000175100001660000000360014760300421017100 0ustar --TEST-- MongoDB\Driver\Cursor tailable iteration with awaitData option --SKIPIF-- --FILE-- insert(['_id' => $i]); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted %d document(s): %s\n", $writeResult->getInsertedCount(), implode(', ', range($from, $to))); } $manager = create_test_manager(); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'create' => COLLECTION_NAME, 'capped' => true, 'size' => 1048576, ])); insert($manager, 1, 3); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['tailable' => true, 'awaitData' => true])); $it = new IteratorIterator($cursor); $numAwaitAttempts = 0; $maxAwaitAttempts = 7; for ($it->rewind(); $numAwaitAttempts < $maxAwaitAttempts; $it->next()) { $document = $it->current(); if ($document !== null) { printf("{_id: %d}\n", $document->_id); continue; } if ($numAwaitAttempts === 2) { insert($manager, 4, 6); } if ($numAwaitAttempts === 5) { insert($manager, 7, 9); } echo "Awaiting results...\n"; $numAwaitAttempts += 1; } ?> ===DONE=== --EXPECT-- Inserted 3 document(s): 1, 2, 3 {_id: 1} {_id: 2} {_id: 3} Awaiting results... Awaiting results... Inserted 3 document(s): 4, 5, 6 Awaiting results... {_id: 4} {_id: 5} {_id: 6} Awaiting results... Awaiting results... Inserted 3 document(s): 7, 8, 9 Awaiting results... {_id: 7} {_id: 8} {_id: 9} Awaiting results... ===DONE=== mongodb-1.21.0/tests/cursor/cursor-tailable-003.phpt0000644000175100001660000000224714760300421017107 0ustar --TEST-- MongoDB\Driver\Cursor tailable iteration with awaitData and maxAwaitTimeMS options --SKIPIF-- --FILE-- executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'create' => COLLECTION_NAME, 'capped' => true, 'size' => 1048576, ])); $bulkWrite = new MongoDB\Driver\BulkWrite; $bulkWrite->insert(['_id' => 1]); $manager->executeBulkWrite(NS, $bulkWrite); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], [ 'tailable' => true, 'awaitData' => true, 'maxAwaitTimeMS' => 10, ])); $it = new IteratorIterator($cursor); $it->rewind(); printf("{_id: %d}\n", $it->current()->_id); $it->next(); $startTime = microtime(true); echo "Awaiting results...\n"; $it->next(); printf("Waited for %.6f seconds\n", microtime(true) - $startTime); // Sometimes the cursor will wait for 0.0099 seconds and sometimes it will wait for 0.01. ?> ===DONE=== --EXPECTF-- {_id: 1} Awaiting results... Waited for 0.0%d seconds ===DONE=== mongodb-1.21.0/tests/cursor/cursor-tailable_error-001.phpt0000644000175100001660000000411614760300421020313 0ustar --TEST-- MongoDB\Driver\Cursor collection dropped during tailable iteration --SKIPIF-- --FILE-- insert(['_id' => $i]); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted %d document(s): %s\n", $writeResult->getInsertedCount(), implode(', ', range($from, $to))); } $manager = create_test_manager(); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'create' => COLLECTION_NAME, 'capped' => true, 'size' => 1048576, ])); insert($manager, 1, 3); echo throws(function() use ($manager) { $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['tailable' => true])); $it = new IteratorIterator($cursor); $numAwaitAttempts = 0; $maxAwaitAttempts = 7; for ($it->rewind(); $numAwaitAttempts < $maxAwaitAttempts; $it->next()) { $document = $it->current(); if ($document !== null) { printf("{_id: %d}\n", $document->_id); continue; } if ($numAwaitAttempts === 2) { insert($manager, 4, 6); } if ($numAwaitAttempts === 5) { $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['drop' => COLLECTION_NAME])); } echo "Awaiting results...\n"; $numAwaitAttempts += 1; } }, 'MongoDB\Driver\Exception\RuntimeException'), "\n"; ?> ===DONE=== --EXPECTF-- Inserted 3 document(s): 1, 2, 3 {_id: 1} {_id: 2} {_id: 3} Awaiting results... Awaiting results... Inserted 3 document(s): 4, 5, 6 Awaiting results... {_id: 4} {_id: 5} {_id: 6} Awaiting results... Awaiting results... Awaiting results... OK: Got MongoDB\Driver\Exception\RuntimeException %Scollection dropped%S ===DONE=== mongodb-1.21.0/tests/cursor/cursor-tailable_error-002.phpt0000644000175100001660000000437314760300421020321 0ustar --TEST-- MongoDB\Driver\Cursor cursor killed during tailable iteration --SKIPIF-- --FILE-- insert(['_id' => $i]); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted %d document(s): %s\n", $writeResult->getInsertedCount(), implode(', ', range($from, $to))); } $manager = create_test_manager(); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'create' => COLLECTION_NAME, 'capped' => true, 'size' => 1048576, ])); insert($manager, 1, 3); echo throws(function() use ($manager) { $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['tailable' => true])); $it = new IteratorIterator($cursor); $numAwaitAttempts = 0; $maxAwaitAttempts = 7; for ($it->rewind(); $numAwaitAttempts < $maxAwaitAttempts; $it->next()) { $document = $it->current(); if ($document !== null) { printf("{_id: %d}\n", $document->_id); continue; } if ($numAwaitAttempts === 2) { insert($manager, 4, 6); } if ($numAwaitAttempts === 5) { $cursor->getServer()->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'killCursors' => COLLECTION_NAME, 'cursors' => [ $cursor->getId(true) ], ])); } echo "Awaiting results...\n"; $numAwaitAttempts += 1; } }, 'MongoDB\Driver\Exception\RuntimeException'), "\n"; ?> ===DONE=== --EXPECTF-- Inserted 3 document(s): 1, 2, 3 {_id: 1} {_id: 2} {_id: 3} Awaiting results... Awaiting results... Inserted 3 document(s): 4, 5, 6 Awaiting results... {_id: 4} {_id: 5} {_id: 6} Awaiting results... Awaiting results... Awaiting results... OK: Got MongoDB\Driver\Exception\RuntimeException %r(Cursor not found, cursor id: \d+|cursor id \d+ not found|Cursor not found \(.*id: \d+\)\.)%r ===DONE=== mongodb-1.21.0/tests/cursor/cursor-toArray-001.phpt0000644000175100001660000000241614760300421016747 0ustar --TEST-- MongoDB\Driver\Cursor::toArray() --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array("x" => 1))); echo "Dumping Cursor::toArray():\n"; var_dump($cursor->toArray()); // Execute the query a second time, since we cannot iterate twice $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array("x" => 1))); echo "\nDumping iterated Cursor:\n"; var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- Dumping Cursor::toArray(): array(2) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(1) } } Dumping iterated Cursor: array(2) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/cursor/cursor-toArray-002.phpt0000644000175100001660000000167514760300421016756 0ustar --TEST-- MongoDB\Driver\Cursor::toArray() respects type map --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => array(1, 2, 3))); $bulk->insert(array('_id' => 2, 'x' => array(4, 5, 6))); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array('x' => 1))); $cursor->setTypeMap(array("array" => "MyArrayObject")); $documents = $cursor->toArray(); var_dump($documents[0]->x instanceof MyArrayObject); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/cursor/cursor_error-001.phpt0000644000175100001660000000036514760300421016542 0ustar --TEST-- MongoDB\Driver\Cursor cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyCursor %s final class %SMongoDB\Driver\Cursor%S in %s on line %d mongodb-1.21.0/tests/cursor/cursorid-getId-001.phpt0000644000175100001660000000267214760300421016703 0ustar --TEST-- MongoDB\Driver\Cursor::getId --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); var_dump($cursor->getId()); var_dump($cursor->getId(false)); var_dump($cursor->getId(true)); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Cursor::getId(): The method "MongoDB\Driver\Cursor::getId" will no longer return a "MongoDB\Driver\CursorId" instance in the future. Pass "true" as argument to change to the new behavior and receive a "MongoDB\BSON\Int64" instance instead. in %s object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> %rint\(%d\)|string\(%d\) "%d"%r } Deprecated: MongoDB\Driver\Cursor::getId(): The method "MongoDB\Driver\Cursor::getId" will no longer return a "MongoDB\Driver\CursorId" instance in the future. Pass "true" as argument to change to the new behavior and receive a "MongoDB\BSON\Int64" instance instead. in %s object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> %rint\(%d\)|string\(%d\) "%d"%r } object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(%d) "%d" } ===DONE=== mongodb-1.21.0/tests/cursor/cursorinterface-001.phpt0000644000175100001660000000125014760300421017204 0ustar --TEST-- MongoDB\Driver\CursorInterface is implemented by MongoDB\Driver\Cursor --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array("x" => 1))); var_dump($cursor instanceof MongoDB\Driver\CursorInterface); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/cursor/cursorinterface-002.phpt0000644000175100001660000000034314760300421017207 0ustar --TEST-- MongoDB\Driver\CursorInterface extends Traversable --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/cursor/cursorinterface-003.phpt0000644000175100001660000000034614760300421017213 0ustar --TEST-- MongoDB\Driver\CursorInterface does not extend Iterator --FILE-- ===DONE=== --EXPECT-- bool(false) ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-001.phpt0000644000175100001660000000205514760300421016161 0ustar --TEST-- MongoDB\Driver\CursorId BSON serialization --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); $cursorId = $cursor->getId(); hex_dump(fromPHP(['cid' => $cursorId])); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Cursor::getId(): The method "MongoDB\Driver\Cursor::getId" will no longer return a "MongoDB\Driver\CursorId" instance in the future. Pass "true" as argument to change to the new behavior and receive a "MongoDB\BSON\Int64" instance instead. in %s 0 : 12 00 00 00 12 63 69 64 00 %x %x %x %x %x %x %x [.....cid.%s] 10 : %x 00 [%s.] ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-002.phpt0000644000175100001660000000316614760300421016166 0ustar --TEST-- MongoDB\Driver\CursorId BSON serialization for killCursors command --SKIPIF-- --FILE-- selectServer(new \MongoDB\Driver\ReadPreference('primary')); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $server->executeBulkWrite(NS, $bulk); $cursor = $server->executeQuery(NS, new MongoDB\Driver\Query([], ['batchSize' => 2])); $cursorId = $cursor->getId(); $command = new MongoDB\Driver\Command([ 'killCursors' => COLLECTION_NAME, 'cursors' => [ $cursorId ], ]); /* Since the killCursors command result includes cursor IDs as 64-bit integers, * unserializing the result document requires a 64-bit platform. */ $result = $server->executeCommand(DATABASE_NAME, $command)->toArray()[0]; printf("Killed %d cursor(s)\n", count($result->cursorsKilled)); printf("Killed expected cursor: %s\n", (string) $cursorId === (string) $result->cursorsKilled[0] ? 'yes' : 'no'); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Cursor::getId(): The method "MongoDB\Driver\Cursor::getId" will no longer return a "MongoDB\Driver\CursorId" instance in the future. Pass "true" as argument to change to the new behavior and receive a "MongoDB\BSON\Int64" instance instead. in %s Killed 1 cursor(s) Killed expected cursor: yes ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-debug-001.phpt0000644000175100001660000000062414760300421017245 0ustar --TEST-- MongoDB\Driver\CursorId debug output --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> %rint\(|string\(19\) "|%r7250031947823432848%r"|\)%r } ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-debug-002.phpt0000644000175100001660000000075114760300421017247 0ustar --TEST-- MongoDB\Driver\CursorId debug output on 32-bit platform --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> string(19) "7250031947823432848" } ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-debug-003.phpt0000644000175100001660000000074114760300421017247 0ustar --TEST-- MongoDB\Driver\CursorId debug output on 64-bit platform --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> int(7250031947823432848) } ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-serialization-002.phpt0000644000175100001660000000176614760300421021045 0ustar --TEST-- MongoDB\Driver\CursorId serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> %rint\(7250031947823432848\)|string\(19\) "7250031947823432848"%r } O:23:"MongoDB\Driver\CursorId":1:{s:2:"id";s:19:"7250031947823432848";} object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> %rint\(7250031947823432848\)|string\(19\) "7250031947823432848"%r } object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> int(0) } O:23:"MongoDB\Driver\CursorId":1:{s:2:"id";s:1:"0";} object(MongoDB\Driver\CursorId)#%d (%d) { ["id"]=> int(0) } ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-serialization_error-001.phpt0000644000175100001660000000074714760300421022253 0ustar --TEST-- MongoDB\Driver\CursorId unserialization errors (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\CursorId initialization requires "id" string field ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-serialization_error-002.phpt0000644000175100001660000000074714760300421022254 0ustar --TEST-- MongoDB\Driver\CursorId unserialization errors (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\CursorId initialization requires "id" string field ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-set_state-001.phpt0000644000175100001660000000051714760300421020153 0ustar --TEST-- MongoDB\Driver\CursorId::__set_state() --FILE-- '7250031947823432848', ])); echo "\n"; ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\CursorId::__set_state(array( 'id' => %r(7250031947823432848|'7250031947823432848')%r, )) ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-set_state_error-001.phpt0000644000175100001660000000072114760300421021361 0ustar --TEST-- MongoDB\Driver\CursorId::__set_state() requires "id" string field --FILE-- 0]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\CursorId initialization requires "id" string field ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-tostring-001.phpt0000644000175100001660000000044114760300421020025 0ustar --TEST-- MongoDB\Driver\CursorId::__toString() --FILE-- ===DONE=== --EXPECT-- string(19) "7250031947823432848" ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid-var_export-001.phpt0000644000175100001660000000065414760300421020353 0ustar --TEST-- MongoDB\Driver\CursorId: var_export() --FILE-- ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\CursorId::__set_state(array( 'id' => %r(7250031947823432848|'7250031947823432848')%r, )) ===DONE=== mongodb-1.21.0/tests/cursorid/cursorid_error-001.phpt0000644000175100001660000000037714760300421017377 0ustar --TEST-- MongoDB\Driver\CursorId cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyCursorId %s final class %SMongoDB\Driver\CursorId%S in %s on line %d mongodb-1.21.0/tests/exception/bulkwriteexception-getwriteresult-001.phpt0000644000175100001660000000227214760300421023512 0ustar --TEST-- MongoDB\Driver\Exception\BulkWriteException::getWriteResult() --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> int(1) ["nMatched"]=> int(0) ["nModified"]=> int(0) ["nRemoved"]=> int(0) ["nUpserted"]=> int(0) ["upsertedIds"]=> array(0) { } ["writeErrors"]=> array(1) { [0]=> object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) %s ["code"]=> int(11000) ["index"]=> int(1) ["info"]=> NULL } } ["writeConcernError"]=> NULL ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { } ["errorReplies"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/exception/bulkwriteexception-haserrorlabel-001.phpt0000644000175100001660000000106214760300421023242 0ustar --TEST-- MongoDB\Driver\Exception\BulkWriteException::hasErrorLabel() --FILE-- getProperty('errorLabels'); $resultDocumentProperty->setAccessible(true); $resultDocumentProperty->setValue($exception, $labels); var_dump($exception->hasErrorLabel('foo')); var_dump($exception->hasErrorLabel('bar')); ?> ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/exception/bulkwriteexception-haserrorlabel-002.phpt0000644000175100001660000000230614760300421023245 0ustar --TEST-- MongoDB\Driver\Exception\BulkWriteException::hasErrorLabel() with writeConcernError --SKIPIF-- --FILE-- false]); // Select a specific server for future operations to avoid mongos switching in sharded clusters $server = $manager->selectServer(new \MongoDB\Driver\ReadPreference('primary')); configureTargetedFailPoint($server, 'failCommand', [ 'times' => 1 ], [ 'failCommands' => ['insert'], 'writeConcernError' => [ 'code' => 91, 'errmsg' => 'Replication is being shut down', 'errorLabels' => ['RetryableWriteError'], ], ]); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); try { $server->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->hasErrorLabel('RetryableWriteError')); } ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/exception/bulkwriteexception-haserrorlabel_error-001.phpt0000644000175100001660000000102314760300421024450 0ustar --TEST-- MongoDB\Driver\Exception\BulkWriteException::hasErrorLabel() with non-array values --FILE-- getProperty('errorLabels'); $resultDocumentProperty->setAccessible(true); $resultDocumentProperty->setValue($exception, $labels); var_dump($exception->hasErrorLabel('bar')); ?> ===DONE=== --EXPECT-- bool(false) ===DONE=== mongodb-1.21.0/tests/exception/commandexception-getresultdocument-001.phpt0000644000175100001660000000104414760300421023600 0ustar --TEST-- MongoDB\Driver\Exception\CommandException::getResultDocument() --FILE-- 1]; $reflection = new ReflectionClass($exception); $resultDocumentProperty = $reflection->getProperty('resultDocument'); $resultDocumentProperty->setAccessible(true); $resultDocumentProperty->setValue($exception, $resultDocument); var_dump($resultDocument === $exception->getResultDocument()); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/exception/commandexception-haserrorlabel-001.phpt0000644000175100001660000000105614760300421022653 0ustar --TEST-- MongoDB\Driver\Exception\CommandException::hasErrorLabel() --FILE-- getProperty('errorLabels'); $resultDocumentProperty->setAccessible(true); $resultDocumentProperty->setValue($exception, $labels); var_dump($exception->hasErrorLabel('foo')); var_dump($exception->hasErrorLabel('bar')); ?> ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/exception/commandexception-haserrorlabel_error-001.phpt0000644000175100001660000000101714760300421024061 0ustar --TEST-- MongoDB\Driver\Exception\CommandException::hasErrorLabel() with non-array values --FILE-- getProperty('errorLabels'); $resultDocumentProperty->setAccessible(true); $resultDocumentProperty->setValue($exception, $labels); var_dump($exception->hasErrorLabel('bar')); ?> ===DONE=== --EXPECT-- bool(false) ===DONE=== mongodb-1.21.0/tests/exception/exception-001.phpt0000644000175100001660000000051314760300421016466 0ustar --TEST-- MongoDB\Driver\Exception\Exception extends Throwable --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/exception/runtimeexception-haserrorlabel-001.phpt0000644000175100001660000000105614760300421022720 0ustar --TEST-- MongoDB\Driver\Exception\RuntimeException::hasErrorLabel() --FILE-- getProperty('errorLabels'); $resultDocumentProperty->setAccessible(true); $resultDocumentProperty->setValue($exception, $labels); var_dump($exception->hasErrorLabel('foo')); var_dump($exception->hasErrorLabel('bar')); ?> ===DONE=== --EXPECT-- bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/exception/runtimeexception-haserrorlabel_error-001.phpt0000644000175100001660000000101714760300421024126 0ustar --TEST-- MongoDB\Driver\Exception\RuntimeException::hasErrorLabel() with non-array values --FILE-- getProperty('errorLabels'); $resultDocumentProperty->setAccessible(true); $resultDocumentProperty->setValue($exception, $labels); var_dump($exception->hasErrorLabel('bar')); ?> ===DONE=== --EXPECT-- bool(false) ===DONE=== mongodb-1.21.0/tests/functional/cursor-001.phpt0000644000175100001660000000357214760300421016161 0ustar --TEST-- Sorting single field, ascending, using the Cursor Iterator --SKIPIF-- --FILE-- array('_id' => 0, 'username' => 1), 'sort' => array('username' => 1), 'limit' => 104, )); $cursor = $manager->executeQuery(NS, $query); foreach ($cursor as $document) { echo $document->username . "\n"; } ?> ===DONE=== --EXPECT-- aaliyah.kertzmann aaron89 abbott.alden abbott.flo abby76 abernathy.adrienne abernathy.audrey abner.kreiger aboehm abshire.icie abshire.jazlyn adams.delta adolph20 adonis.schamberger agleason ahartmann ahettinger akreiger al.cormier al97 albin95 alda.murray alden.blanda alessandra76 alex73 alexa01 alfred.ritchie alia07 alia72 alize.hegmann allie48 alta.sawayn alvena.pacocha alvis22 alycia48 amalia84 amely01 amos.corkery amos78 anahi95 anais.feest anais58 andreanne.steuber angela.dickinson angelina.bartoletti angelina31 aniyah.franecki annalise40 antoinette.gaylord antoinette.weissnat aoberbrunner apacocha apollich ara92 arch44 arely.ryan armstrong.clara armstrong.gordon arnold.kiehn arvel.hilll asatterfield aschuppe ashlynn71 ashlynn85 ashton.o'kon austen03 austen47 austin67 awintheiser awyman ayana.brakus bailey.mertz bailey.sarina balistreri.donald barrett.prohaska bartell.susie bashirian.lina bayer.ova baylee.maggio bbernier bblick beahan.oleta beatty.layne beatty.myrtis beau49 beaulah.mann bechtelar.nadia becker.theron beer.mossie beer.roselyn benedict.johnson berge.enoch bergnaum.roberto bernardo.mccullough bernardo52 bernhard.margaretta bernie.morissette bethel20 betty09 bins.aliyah bins.laisha bjori blanda.danielle blanda.irving ===DONE=== mongodb-1.21.0/tests/functional/cursorid-001.phpt0000644000175100001660000000141014760300421016463 0ustar --TEST-- Sorting single field, ascending, using the Cursor Iterator --SKIPIF-- --FILE-- array('_id' => 0, 'username' => 1), 'sort' => array('username' => 1), 'batchSize' => 11, 'limit' => 110, )); $cursor = $manager->executeQuery(NS, $query); $cursorid = $cursor->getId(true); var_dump($cursorid); var_dump($cursorid != 0); ?> ===DONE=== --EXPECTF-- object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(%d) "%d" } bool(true) ===DONE=== mongodb-1.21.0/tests/functional/query-sort-001.phpt0000644000175100001660000000345714760300421017000 0ustar --TEST-- Sorting single field, ascending --SKIPIF-- --FILE-- array('_id' => 0, 'username' => 1), 'sort' => array('username' => 1), "limit" => 100, )); $cursor = $manager->executeQuery(NS, $query); foreach ($cursor as $document) { echo $document->username . "\n"; } ?> ===DONE=== --EXPECT-- aaliyah.kertzmann aaron89 abbott.alden abbott.flo abby76 abernathy.adrienne abernathy.audrey abner.kreiger aboehm abshire.icie abshire.jazlyn adams.delta adolph20 adonis.schamberger agleason ahartmann ahettinger akreiger al.cormier al97 albin95 alda.murray alden.blanda alessandra76 alex73 alexa01 alfred.ritchie alia07 alia72 alize.hegmann allie48 alta.sawayn alvena.pacocha alvis22 alycia48 amalia84 amely01 amos.corkery amos78 anahi95 anais.feest anais58 andreanne.steuber angela.dickinson angelina.bartoletti angelina31 aniyah.franecki annalise40 antoinette.gaylord antoinette.weissnat aoberbrunner apacocha apollich ara92 arch44 arely.ryan armstrong.clara armstrong.gordon arnold.kiehn arvel.hilll asatterfield aschuppe ashlynn71 ashlynn85 ashton.o'kon austen03 austen47 austin67 awintheiser awyman ayana.brakus bailey.mertz bailey.sarina balistreri.donald barrett.prohaska bartell.susie bashirian.lina bayer.ova baylee.maggio bbernier bblick beahan.oleta beatty.layne beatty.myrtis beau49 beaulah.mann bechtelar.nadia becker.theron beer.mossie beer.roselyn benedict.johnson berge.enoch bergnaum.roberto bernardo.mccullough bernardo52 bernhard.margaretta bernie.morissette bethel20 betty09 bins.aliyah ===DONE=== mongodb-1.21.0/tests/functional/query-sort-002.phpt0000644000175100001660000000322314760300421016770 0ustar --TEST-- Sorting single field, descending --SKIPIF-- --FILE-- array('_id' => 0, 'username' => 1), 'sort' => array('username' => -1), 'limit' => 100, )); $cursor = $manager->executeQuery(NS, $query); foreach ($cursor as $document) { echo $document->username . "\n"; } ?> ===DONE=== --EXPECT-- zulauf.amaya zstanton zoe41 zieme.noemi ziemann.webster zheathcote zella78 zboyle zachery33 yyost ywyman ywiza ypredovic yost.magali yost.ari ylarkin yklein yhudson yfritsch ycole yasmine.lowe yasmin55 xrodriguez xkohler xhermann xgutmann xgibson xcassin wwilkinson wunsch.mose wschimmel wschaefer wpacocha wolff.caroline wkertzmann wiza.carmel witting.walker witting.chris wisozk.cortez winnifred08 wilson.white willms.amari will.lamont will.jerod will.edwina wilfred.feil wilderman.sophia wiegand.blanche west.jude west.cristobal weimann.tillman webster70 webster48 watson70 warren.feest walton33 walter.norval walter.lester walsh.vincenza walker.alec wade91 vwaters vvolkman vschulist vrolfson vpfeffer vorn von.britney vivianne.macejkovic veum.tyrell vesta.ritchie verda93 vena.schumm velma37 velda.wehner veffertz vdickinson vconn vbraun vborer vbins vandervort.ezekiel van.ruecker uzieme uwisoky usmith uschumm uschmeler urban24 upton.zackery unique.pagac una.larkin umraz ullrich.layne ulises44 ulises.beatty ulesch ukovacek ujenkins uhansen ===DONE=== mongodb-1.21.0/tests/functional/query-sort-003.phpt0000644000175100001660000003133514760300421016776 0ustar --TEST-- Sorting single field, ascending, using the Cursor Iterator --SKIPIF-- --FILE-- array('_id' => 0, 'username' => 1), 'sort' => array('username' => 1), )); var_dump($query); $cursor = $manager->executeQuery(NS, $query); var_dump(get_class($cursor)); foreach ($cursor as $document) { echo $document->username . "\n"; } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { } ["options"]=> object(stdClass)#%d (%d) { ["projection"]=> object(stdClass)#%d (%d) { ["_id"]=> int(0) ["username"]=> int(1) } ["sort"]=> object(stdClass)#%d (%d) { ["username"]=> int(1) } } ["readConcern"]=> NULL } string(21) "MongoDB\Driver\Cursor" aaliyah.kertzmann aaron89 abbott.alden abbott.flo abby76 abernathy.adrienne abernathy.audrey abner.kreiger aboehm abshire.icie abshire.jazlyn adams.delta adolph20 adonis.schamberger agleason ahartmann ahettinger akreiger al.cormier al97 albin95 alda.murray alden.blanda alessandra76 alex73 alexa01 alfred.ritchie alia07 alia72 alize.hegmann allie48 alta.sawayn alvena.pacocha alvis22 alycia48 amalia84 amely01 amos.corkery amos78 anahi95 anais.feest anais58 andreanne.steuber angela.dickinson angelina.bartoletti angelina31 aniyah.franecki annalise40 antoinette.gaylord antoinette.weissnat aoberbrunner apacocha apollich ara92 arch44 arely.ryan armstrong.clara armstrong.gordon arnold.kiehn arvel.hilll asatterfield aschuppe ashlynn71 ashlynn85 ashton.o'kon austen03 austen47 austin67 awintheiser awyman ayana.brakus bailey.mertz bailey.sarina balistreri.donald barrett.prohaska bartell.susie bashirian.lina bayer.ova baylee.maggio bbernier bblick beahan.oleta beatty.layne beatty.myrtis beau49 beaulah.mann bechtelar.nadia becker.theron beer.mossie beer.roselyn benedict.johnson berge.enoch bergnaum.roberto bernardo.mccullough bernardo52 bernhard.margaretta bernie.morissette bethel20 betty09 bins.aliyah bins.laisha bjori blanda.danielle blanda.irving blanda.ruthe blaze.miller block.kasandra block.toby bmccullough botsford.edwardo botsford.jennie boyd.balistreri boyer.khalid boyle.franco bpaucek bpurdy bradford.heidenreich brannon24 braun.adaline braun.jeanie breanne.schmeler breitenberg.demarco brennan.emmerich bret57 broderick53 brooklyn22 bruecker bstamm buckridge.julius buddy42 bwalker camilla20 cara.bechtelar carlotta.kreiger carolyn09 carolyne63 carroll.emmalee cartwright.garland casimir.keebler casper.eldred casper.juliana casper38 cassin.carmel cassin.krystel catherine.hilll cathrine.gislason cbartoletti cbecker cbednar cbreitenberg cecelia.schoen celestine97 cfriesen cgreenfelder chad.kuphal chance.conroy chasity63 chet.pacocha christina.simonis chyna05 citlalli41 ckertzmann clarabelle65 clementine.grimes clotilde39 cnikolaus cole.alice coleman55 collier.sage collins.skylar columbus78 connelly.josefina conner.doyle coralie47 cordelia25 corkery.arch cormier.adriana cormier.amy cormier.landen cormier.vida cory76 cpaucek cprice craig93 creola.emard creola88 crona.jaclyn cronin.clint crooks.josh crystel24 csipes cummings.frederic cwaelchi cwest cwhite cwolf cydney.hayes dahlia.white daisy.johns dakota.bednar dakota.wiza dallas.marquardt dante.shields darwin.howe dave46 davis.bennett davis.solon dayne.padberg dayton03 delaney91 delbert.auer delia.lindgren deontae36 dereck.ward derek.bahringer derek79 deven.spinka devon34 dgottlieb dhudson dickinson.ashleigh dillan66 djerde dock.bednar dolly.beer donnie.langosh dorothy67 dorthy.legros doyle.nelle drippin dubuque.brooklyn dubuque.cordia dvandervort dwiegand dwolf earlene.marvin earline.baumbach easter73 eauer ebert.cordie ebony.williamson ebony59 edgar33 edgardo.gorczany edibbert effertz.mateo effie.keeling efren31 egrimes ehirthe ehuel ehuels eino23 ekoelpin eldora.steuber eldred65 elenor33 elesch eli.mann elisabeth95 eliseo49 ella.roberts ellen.krajcik ellen12 elliot.kling elliot.weissnat ellis37 elsie.kuhic elva.baumbach elvis45 emelia.ortiz emerald.shanahan emerson07 emie.schneider emilio.crona emily91 emmalee.waters enid57 enid78 enoch.hilll enola.rath ephraim76 erdman.ethyl erdman.niko eriberto.russel erik04 erika74 ernser.addison ernser.geovany ervin.carter espinka ethan.daugherty ethel56 ethelyn46 ethyl68 ettie49 eulah49 fabian55 fadel.trevion fae00 fahey.rosalee farrell.asha farrell.lessie fbraun feeney.angelica feeney.elizabeth feeney.nathanial feil.rae ferdman ferry.eusebio fherman filomena18 finn.torphy flavie41 florida.o'hara ford85 fosinski frami.bulah franecki.rosetta fred35 freda25 frederik.stracke fsporer fstokes fturner gabriel.mccullough gardner.jacobson garnet.oberbrunner garry.windler gaylord.myrtis gblock gbrakus georgette.mueller geovanni.jones geovany07 german.leffler german40 ggislason gia15 gibson.amiya giovani.langworth giovanna.hickle giovanny.haley gislason.mae gisselle.jacobs gladyce88 glang gottlieb.jerry goyette.roman gparker gprosacco gracie.mcdermott graciela.jacobson grayson78 greenfelder.amya greenfelder.larry greenfelder.ozella gretchen19 gretchen38 greynolds greyson63 grimes.andreane gulgowski.allie gusikowski.aliyah gutkowski.laron gwunsch haag.alaina hackett.alycia hadley.abernathy hailee01 hal67 haley.grace haley.krystel haley.lauretta halvorson.bulah hammes.dimitri hand.lauren hand.tiana hansen.vanessa harber.larissa harber.vicenta harris.kailey hartmann.dedrick harvey.hillard haven13 hayes.delores hayley08 hazle21 hazle43 heathcote.ashly hegmann.sallie heidenreich.julia helene.o'connell henriette21 herman.sanford herzog.eileen hessel.barry hflatley hhackett hhyatt hickle.isabell hirthe.bryana hirthe.letitia hirthe.reymundo hmarvin hoeger.anastacio hollie29 howe.abagail howell.daugherty hquigley hrodriguez hspinka hstamm htowne hudson.bernie hudson.deion huels.alfred huels.enid hugh22 humberto98 hvandervort hyatt.astrid hyatt.soledad iabernathy idaugherty idella50 idonnelly ifeil ileuschke imuller ipredovic irwin.gutkowski irwin31 isabell95 isabella.parisian isac13 isac67 isaiah47 isaiah50 isaias90 isobel.mraz ivy73 izabella.hermann jacobs.carmela jada.romaguera jadon.reinger jailyn62 jalon90 jamaal.cassin jamarcus.weissnat janelle93 janice.walker jannie71 jaquan94 jaqueline.o'kon jarod94 jarrod.lindgren jasmin.ruecker javier.volkman javier13 javier62 jayda.d'amore jazmyne63 jborer jeanette45 jedidiah.hyatt jefferey02 jenkins.letha jerald.konopelski jeremy.o'keefe jessika.schmeler jessy16 jett00 jfeest jheaney jherzog jlebsack jlockman jo'hara jodie.casper johnnie66 johnston.brooklyn jonas97 jones.jazmyn jordan.turner joshua.mraz josiah59 joyce.casper jruecker jschamberger jschinner jthompson jtowne jude.jakubowski jude92 juliana.witting juliet55 june.runolfsson justina63 jwindler kadams kadin.mayer kaelyn05 kaelyn88 kamille.watsica kamron88 karson.mante kasey.abshire kassandra.reilly katheryn.walsh kathlyn02 kathryne.boehm kattie12 kaya24 kayleigh62 kbeahan kdicki keagan.hirthe keanu21 keanu42 keebler.rupert keeling.sydnee keira.dach kelly.konopelski kelvin.jakubowski kerluke.hiram kernser keshawn.boyle kessler.marisol keyon.gaylord keyon65 kherman khills khudson kiley63 kip12 kirk40 kirstin.cruickshank klarson kleuschke kling.laila klocko.filiberto kmohr ko'keefe koch.emmett koch.sophia koelpin.yoshiko krystel.stark kturcotte kub.marcel kuhic.hattie kuhlman.noel kuphal.ahmed kutch.chase kutch.madonna kutch.pasquale kuvalis.nicolette lane05 larkin.lawson larue.schuster laurel35 laurel72 laurence28 lauryn.beer lbode lbradtke leanne.cronin leannon.zander lebsack.harmony ledner.finn leif52 leilani73 lemke.ernestina lempi56 leopold69 lesch.delfina lesch.edna lesch.nyah leuschke.erika lexie.bernier lexie65 lgrady lillian50 lilliana.schaden lily.hansen lind.dane lloyd60 lmckenzie lnicolas london07 lonnie.little lonnie10 loraine.hammes lorna31 louisa76 lquitzon lubowitz.colleen lubowitz.jazmyne lucas.ferry luciano79 lucienne13 lucio.huel lucio20 luella.deckow lullrich luther.lesch mac.hermann macey95 macie.corwin macy.greenholt maddison66 madilyn.wyman madisyn51 madyson.johns maeve.raynor maggio.kayli maia14 mante.ashlee mante.maymie marc97 marcel56 marco.gerlach mariana.sipes marietta.swift marina.mayert marion15 marion35 marjolaine45 mark.casper marks.trace marlen34 marlene95 marley.sipes marvin.ivory maryjane.kutch maudie25 mayer.tanner mccullough.vella mcdermott.kaitlyn mckenzie.maximus mdare meaghan89 melisa61 metz.elmer metz.ima michaela.wolf miles.pollich milford39 milford40 mills.emmanuel mills.rickey miracle53 misty.boyer mitchell.delta mitchell.rafael mohammad.gorczany mohammed.lemke mohr.kylee mollie.deckow monroe.o'keefe monserrate.leannon monserrate.nikolaus monty.mills morar.aniya mosciski.alanis mraz.marcelina mrunte mtoy mueller.woodrow muller.akeem murazik.maximillia mwalter mylene.rogahn myra43 myron.bechtelar mzemlak mzieme nash88 nasir24 natalia66 nathanial37 nayeli.vandervort ndouglas neal.hand neichmann neil.gorczany nellie23 ngoldner nhaag nharber nharris nicolas.melyssa nicolas.wendy nikita.romaguera nikko.langosh nikolas.lang nikolas78 nikolaus.celestino njacobs nkshlerin noah.blick nolan.nora nolan.zachariah nolan56 norma46 novella67 npurdy nrath nrowe nstamm nward o'conner.arthur obie.weissnat oboyer octavia36 oda.robel odare odell96 ogulgowski ohaley ohowe okuneva.ebba olga.mertz olga.waelchi olin13 oliver.reichert olson.dedrick olynch omarvin omer.kirlin ondricka.alexzander ondricka.joy orion.quigley orn.katelyn orval95 oswaldo.kunze otreutel owehner owen82 pacocha.quentin pagac.coleman paige.murphy parisian.dena parker.ellie patience65 patricia.macejkovic pattie.waters pattie97 paul.hayes paula.fahey paxton73 pbotsford pconroy pcruickshank pdach perry63 pfannerstill.erna pframi phahn philpert phodkiewicz phoebe.crona phuel pierre.grant plesch pollich.danika polson powlowski.alfredo ppurdy price49 prohaska.ransom prudence76 prussel pschowalter pwaters pwatsica pwisozk qarmstrong qbatz qgislason qkunze qmayert qo'hara qpowlowski qromaguera qryan qschiller qschneider queen75 queenie33 quitzon.greyson quitzon.maxime rachel45 raphaelle55 ratke.aurelia rau.brent raven.walter raven.ziemann raymundo.ferry raynor.wilmer rdickens regan86 reginald.gulgowski reichert.margaretta reinger.johnathan remington.russel renner.lucius rey29 rice.ronaldo rico71 river66 rkoelpin rmayer robel.chance rocky.hoeger rodger.raynor rodolfo.effertz rohan.harmon rolando38 rolfson.jaren rosalee52 rosemarie.conn rosenbaum.elisa rosetta45 rowe.erik rschowalter rubie.hyatt russel64 rutherford.dawn sabina11 samara90 sarina.bednar savannah89 savion82 sawayn.catharine sawayn.pink sbailey schamberger.marcelle schiller.kameron schimmel.mavis schimmel.russell schmeler.dillon schmeler.flo schmidt.elwyn schmitt.magali schneider.rita schowalter.abbigail schroeder.zoey schulist.angelo schumm.carley schumm.danielle sebert selina.thiel sferry shaina.emard shanie.murazik sheathcote shegmann shields.bethany shoeger shyann28 sienna53 sigmund.schinner simeon.nader skihn skiles.darrin skye.jast skyla.friesen smith.nico so'kon soledad.connelly sonia05 sorn spencer.bessie spencer.darrel sschumm ssteuber stacy.leffler stark.vladimir stehr.odell stella.schowalter stracke.dakota streich.abdiel stroman.rae susanna55 swyman sylvia82 tabitha.mohr talon74 tanya65 tatum.harvey tbarrows tcole terry.corene terry.florian tessie.stroman tgrady thalia22 theo62 theodore55 theresia68 theron10 tkonopelski tlind tomas04 toni57 toy.deshawn trace03 tressa.price tressie47 treutel.evert treutel.minnie trolfson tromp.kaleigh trudie09 trutherford tsatterfield tstamm turcotte.armand turner.considine twila75 uabshire uchamplin udach ugusikowski uhansen ujenkins ukovacek ulesch ulises.beatty ulises44 ullrich.layne umraz una.larkin unique.pagac upton.zackery urban24 uschmeler uschumm usmith uwisoky uzieme van.ruecker vandervort.ezekiel vbins vborer vbraun vconn vdickinson veffertz velda.wehner velma37 vena.schumm verda93 vesta.ritchie veum.tyrell vivianne.macejkovic von.britney vorn vpfeffer vrolfson vschulist vvolkman vwaters wade91 walker.alec walsh.vincenza walter.lester walter.norval walton33 warren.feest watson70 webster48 webster70 weimann.tillman west.cristobal west.jude wiegand.blanche wilderman.sophia wilfred.feil will.edwina will.jerod will.lamont willms.amari wilson.white winnifred08 wisozk.cortez witting.chris witting.walker wiza.carmel wkertzmann wolff.caroline wpacocha wschaefer wschimmel wunsch.mose wwilkinson xcassin xgibson xgutmann xhermann xkohler xrodriguez yasmin55 yasmine.lowe ycole yfritsch yhudson yklein ylarkin yost.ari yost.magali ypredovic ywiza ywyman yyost zachery33 zboyle zella78 zheathcote ziemann.webster zieme.noemi zoe41 zstanton zulauf.amaya ===DONE=== mongodb-1.21.0/tests/functional/query-sort-004.phpt0000644000175100001660000000235314760300421016775 0ustar --TEST-- Sort query option is always serialized as a BSON document --SKIPIF-- --FILE-- insert(array('_id' => $i, '0' => 4 - $i)); } $writeResult = $manager->executeBulkWrite(NS, $bulkWrite); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $query = new MongoDB\Driver\Query(array(), array( 'sort' => array('0' => 1), )); var_dump($query); $cursor = $manager->executeQuery(NS, $query); /* Numeric keys of stdClass instances cannot be directly accessed, so ensure the * document is decoded as a PHP array. */ $cursor->setTypeMap(array('root' => 'array')); foreach ($cursor as $document) { echo $document['0'] . "\n"; } ?> ===DONE=== --EXPECTF-- Inserted: 5 object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { } ["options"]=> object(stdClass)#%d (%d) { ["sort"]=> object(stdClass)#%d (%d) { ["0"]=> int(1) } } ["readConcern"]=> NULL } 0 1 2 3 4 ===DONE=== mongodb-1.21.0/tests/ini/ini-debug-ini_get-001.phpt0000644000175100001660000000025314760300421016531 0ustar --TEST-- ini_get() reports mongodb.debug (default) --FILE-- ===DONE=== --EXPECT-- string(0) "" ===DONE=== mongodb-1.21.0/tests/ini/ini-debug-ini_get-002.phpt0000644000175100001660000000105714760300421016535 0ustar --TEST-- ini_get() reports mongodb.debug (master and local) --INI-- mongodb.debug=stderr --FILE-- ===DONE=== --EXPECTF-- %A string(6) "stderr" string(6) "stdout" ===DONE=== mongodb-1.21.0/tests/ini/ini-debug-phpinfo-001.phpt0000644000175100001660000000026214760300421016556 0ustar --TEST-- phpinfo() reports mongodb.debug (default) --FILE-- ===DONE=== --EXPECTF-- %a mongodb.debug => no value => no value %a ===DONE=== mongodb-1.21.0/tests/ini/ini-debug-phpinfo-002.phpt0000644000175100001660000000037214760300421016561 0ustar --TEST-- phpinfo() reports mongodb.debug (master and local) --INI-- mongodb.debug=stderr --FILE-- ===DONE=== --EXPECTF-- %a mongodb.debug => stdout => stderr %a ===DONE===%A mongodb-1.21.0/tests/logging/logging-addSubscriber-001.phpt0000644000175100001660000000203414760300421020320 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Adding one logger --FILE-- ===DONE=== --EXPECT-- 0: domain: error 1: domain: critical 2: domain: warning 3: domain: message 4: domain: info 5: domain: debug ===DONE=== mongodb-1.21.0/tests/logging/logging-addSubscriber-002.phpt0000644000175100001660000000247714760300421020334 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Adding two loggers --FILE-- name = $name; } public function log(int $level, string $domain, string $message): void { printf("%s: %d: %s: %s\n", $this->name, $level, $domain, $message); } } $logger1 = new MyLogger('ONE'); addSubscriber($logger1); mongoc_log(LogSubscriber::LEVEL_ERROR, 'domain', 'error'); mongoc_log(LogSubscriber::LEVEL_CRITICAL, 'domain', 'critical'); mongoc_log(LogSubscriber::LEVEL_WARNING, 'domain', 'warning'); $logger2 = new MyLogger('TWO'); addSubscriber($logger2); mongoc_log(LogSubscriber::LEVEL_MESSAGE, 'domain', 'message'); mongoc_log(LogSubscriber::LEVEL_INFO, 'domain', 'info'); mongoc_log(LogSubscriber::LEVEL_DEBUG, 'domain', 'debug'); ?> ===DONE=== --EXPECT-- ONE: 0: domain: error ONE: 1: domain: critical ONE: 2: domain: warning ONE: 3: domain: message TWO: 3: domain: message ONE: 4: domain: info TWO: 4: domain: info ONE: 5: domain: debug TWO: 5: domain: debug ===DONE=== mongodb-1.21.0/tests/logging/logging-addSubscriber-003.phpt0000644000175100001660000000212314760300421020321 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Adding the same logger multiple times is a NOP --FILE-- ===DONE=== --EXPECT-- 0: domain: error 1: domain: critical 2: domain: warning 3: domain: message 4: domain: info 5: domain: debug ===DONE=== mongodb-1.21.0/tests/logging/logging-addSubscriber-004.phpt0000644000175100001660000000203314760300421020322 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Trace logs are not reported to loggers --FILE-- ===DONE=== --EXPECTF-- [%s] domain: DEBUG > debug1 5: domain: debug1 [%s] domain: TRACE > trace [%s] domain: DEBUG > debug2 5: domain: debug2 ===DONE=== mongodb-1.21.0/tests/logging/logging-addSubscriber-005.phpt0000644000175100001660000000320514760300421020325 0ustar --TEST-- MongoDB\Driver\Monitoring\addSubscriber(): Adding a combined CommandSubscriber and LogSubscriber --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded($event): void {} public function commandFailed($event): void {} public function log(int $level, string $domain, string $message): void { printf("%d: %s: %s\n", $level, $domain, $message); } } $subscriber = new MySubscriber(); addSubscriber($subscriber); $manager = create_test_manager(); $manager->executeCommand(DATABASE_NAME, new Command(['ping' => 1])); mongoc_log(LogSubscriber::LEVEL_DEBUG, 'domain', 'debug'); removeSubscriber($subscriber); // Neither subscriber implementation should be notified after removal $manager->executeCommand(DATABASE_NAME, new Command(['ping' => 1])); mongoc_log(LogSubscriber::LEVEL_DEBUG, 'domain', 'debug'); ?> ===DONE=== --EXPECTF-- 5: PHONGO: Connection string: '%s' %a Observed commandStarted for ping 5: domain: debug ===DONE=== mongodb-1.21.0/tests/logging/logging-removeSubscriber-001.phpt0000644000175100001660000000211014760300421021060 0ustar --TEST-- MongoDB\Driver\Monitoring\removeSubscriber(): Removing the only logger --FILE-- ===DONE=== --EXPECT-- 0: domain: error 1: domain: critical 2: domain: warning ===DONE=== mongodb-1.21.0/tests/logging/logging-removeSubscriber-002.phpt0000644000175100001660000000262414760300421021073 0ustar --TEST-- MongoDB\Driver\Monitoring\removeSubscriber(): Removing one of multiple loggers --FILE-- name = $name; } public function log(int $level, string $domain, string $message): void { printf("%s: %d: %s: %s\n", $this->name, $level, $domain, $message); } } $logger1 = new MyLogger('ONE'); $logger2 = new MyLogger('TWO'); addSubscriber($logger1); mongoc_log(LogSubscriber::LEVEL_ERROR, 'domain', 'error'); mongoc_log(LogSubscriber::LEVEL_CRITICAL, 'domain', 'critical'); addSubscriber($logger2); mongoc_log(LogSubscriber::LEVEL_WARNING, 'domain', 'warning'); mongoc_log(LogSubscriber::LEVEL_MESSAGE, 'domain', 'message'); removeSubscriber($logger1); mongoc_log(LogSubscriber::LEVEL_INFO, 'domain', 'info'); mongoc_log(LogSubscriber::LEVEL_DEBUG, 'domain', 'debug'); ?> ===DONE=== --EXPECT-- ONE: 0: domain: error ONE: 1: domain: critical ONE: 2: domain: warning TWO: 2: domain: warning ONE: 3: domain: message TWO: 3: domain: message TWO: 4: domain: info TWO: 5: domain: debug ===DONE=== mongodb-1.21.0/tests/logging/logging-removeSubscriber-003.phpt0000644000175100001660000000225714760300421021076 0ustar --TEST-- MongoDB\Driver\mongoc_log(LogSubscriber(): Removing an unregistered logger is a NOP --FILE-- name = $name; } public function log(int $level, string $domain, string $message): void { printf("%s: %d: %s: %s\n", $this->name, $level, $domain, $message); } } $logger1 = new MyLogger('ONE'); $logger2 = new MyLogger('TWO'); addSubscriber($logger1); mongoc_log(LogSubscriber::LEVEL_ERROR, 'domain', 'error'); mongoc_log(LogSubscriber::LEVEL_CRITICAL, 'domain', 'critical'); removeSubscriber($logger2); mongoc_log(LogSubscriber::LEVEL_WARNING, 'domain', 'warning'); mongoc_log(LogSubscriber::LEVEL_MESSAGE, 'domain', 'message'); ?> ===DONE=== --EXPECT-- ONE: 0: domain: error ONE: 1: domain: critical ONE: 2: domain: warning ONE: 3: domain: message ===DONE=== mongodb-1.21.0/tests/logging/logsubscriber-constants.phpt0000644000175100001660000000070414760300421020503 0ustar --TEST-- MongoDB\Driver\Monitoring\LogSubscriber constants --FILE-- ===DONE=== --EXPECT-- int(0) int(1) int(2) int(3) int(4) int(5) ===DONE=== mongodb-1.21.0/tests/logging/mongoc_log_error-001.phpt0000644000175100001660000000155214760300421017460 0ustar --TEST-- MongoDB\Driver\Monitoring\mongoc_log(): Invalid level --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected level to be >= 0 and <= 6, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected level to be >= 0 and <= 6, 7 given ===DONE=== mongodb-1.21.0/tests/logging/mongoc_log_error-002.phpt0000644000175100001660000000110314760300421017451 0ustar --TEST-- MongoDB\Driver\Monitoring\mongoc_log(): Domain contains null bytes --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Domain cannot contain null bytes. Unexpected null byte after "domain". ===DONE=== mongodb-1.21.0/tests/logging/mongoc_log_error-003.phpt0000644000175100001660000000110614760300421017455 0ustar --TEST-- MongoDB\Driver\Monitoring\mongoc_log(): Message contains null bytes --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Message cannot contain null bytes. Unexpected null byte after "message". ===DONE=== mongodb-1.21.0/tests/manager/bug0572.phpt0000644000175100001660000000212114760300421014676 0ustar --TEST-- PHPC-572: Ensure stream context does not go out of scope before socket init --SKIPIF-- --FILE-- [ 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true, ], ]); return create_test_manager(URI, [], ['context' => $context]); }; $manager = $closure(); $cursor = $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); printf("ping: %d\n", $cursor->toArray()[0]->ok); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_self_signed" context driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s ping: 1 ===DONE=== mongodb-1.21.0/tests/manager/bug0851-001.phpt0000644000175100001660000000175014760300421015203 0ustar --TEST-- PHPC-851: Manager constructor should not modify options argument --FILE-- 'secondaryPreferred', 'readPreferenceTags' => [ ['dc' => 'ny'], [], ], ]; $manager = new MongoDB\Driver\Manager(null, $options); var_dump($options); /* Dump the Manager's ReadPreference to ensure that each element in the * readPreferenceTags option was converted to an object. */ var_dump($manager->getReadPreference()); ?> ===DONE=== --EXPECTF-- array(2) { ["readPreference"]=> string(18) "secondaryPreferred" ["readPreferenceTags"]=> array(2) { [0]=> array(1) { ["dc"]=> string(2) "ny" } [1]=> array(0) { } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" ["tags"]=> array(2) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } [1]=> object(stdClass)#%d (%d) { } } } ===DONE=== mongodb-1.21.0/tests/manager/bug0851-002.phpt0000644000175100001660000000144314760300421015203 0ustar --TEST-- PHPC-851: Manager constructor should not modify driverOptions argument --FILE-- true, 'context' => stream_context_create([ 'ssl' => [ 'allow_self_signed' => true, ], ]), ]; $manager = new MongoDB\Driver\Manager(null, [], $driverOptions); var_dump($driverOptions); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "weak_cert_validation" driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s array(2) { ["weak_cert_validation"]=> bool(true) ["context"]=> resource(4) of type (stream-context) } ===DONE=== mongodb-1.21.0/tests/manager/bug0912-001.phpt0000644000175100001660000000315014760300421015175 0ustar --TEST-- PHPC-912: Child process should not destroy mongoc_client_t objects from parent --SKIPIF-- --FILE-- 1]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $uri = $cursor->toArray()[0]->you; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['pid' => getmypid(), 'uri' => $uri]); $manager->executeBulkWrite(NS, $bulk); } $manager = create_test_manager(); logMyURI($manager); $parentPid = getmypid(); $childPid = pcntl_fork(); if ($childPid === 0) { $manager = create_test_manager(); logMyURI($manager); exit; } if ($childPid) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid > 0) { printf("Parent(%d) waited for child(%d) to exit\n", $parentPid, $waitPid); } $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); $results = $cursor->toArray(); printf("%d connections were logged\n", count($results)); printf("PIDs differ: %s\n", $results[0]->pid !== $results[1]->pid ? 'yes' : 'no'); printf("URIs differ: %s\n", $results[0]->uri !== $results[1]->uri ? 'yes' : 'no'); } ?> ===DONE=== --EXPECTF-- Parent(%d) waited for child(%d) to exit 2 connections were logged PIDs differ: yes URIs differ: yes ===DONE=== mongodb-1.21.0/tests/manager/bug0913-001.phpt0000644000175100001660000000411214760300421015175 0ustar --TEST-- PHPC-913: Child process should not re-use mongoc_client_t objects from parent --SKIPIF-- --FILE-- 1]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); $uri = $cursor->toArray()[0]->you; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['pid' => getmypid(), 'uri' => $uri]); $manager->executeBulkWrite(NS, $bulk); } $manager = create_test_manager(); logMyURI($manager); $parentPid = getmypid(); $childPid = pcntl_fork(); if ($childPid === 0) { $manager = create_test_manager(); logMyURI($manager); /* Due to PHPC-912, we cannot allow the child process to terminate before * the parent is done using its client, lest it destroy the mongoc_client_t * object and shutdown its socket(s). Sleep for 250ms to allow the parent * time to query for our logged URI. */ usleep(250000); exit; } if ($childPid) { /* Sleep for 100ms to allow the child time to log its URI. Ideally, we would * wait for the child to finish, but PHPC-912 prevents us from doing so. */ usleep(100000); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); $results = $cursor->toArray(); printf("%d connections were logged\n", count($results)); printf("PIDs differ: %s\n", $results[0]->pid !== $results[1]->pid ? 'yes' : 'no'); printf("URIs differ: %s\n", $results[0]->uri !== $results[1]->uri ? 'yes' : 'no'); $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid > 0) { printf("Parent(%d) waited for child(%d) to exit\n", $parentPid, $waitPid); } } ?> ===DONE=== --EXPECTF-- 2 connections were logged PIDs differ: yes URIs differ: yes Parent(%d) waited for child(%d) to exit ===DONE=== mongodb-1.21.0/tests/manager/bug0940-001.phpt0000644000175100001660000000120714760300421015177 0ustar --TEST-- PHPC-940: php_phongo_free_ssl_opt() attempts to free interned strings --SKIPIF-- --FILE-- false])); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "ca_file" driver option is deprecated. Please use the "tlsCAFile" URI option instead.%s object(MongoDB\Driver\Manager)#%d (%d) { ["uri"]=> string(20) "mongodb://127.0.0.1/" ["cluster"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/manager/bug0940-002.phpt0000644000175100001660000000150714760300421015203 0ustar --TEST-- PHPC-940: php_phongo_free_ssl_opt() attempts to free interned strings (context option) --SKIPIF-- --FILE-- ['cafile' => false]]); var_dump(new MongoDB\Driver\Manager(null, [], ['context' => $context])); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "cafile" context driver option is deprecated. Please use the "tlsCAFile" URI option instead.%s object(MongoDB\Driver\Manager)#%d (%d) { ["uri"]=> string(20) "mongodb://127.0.0.1/" ["cluster"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/manager/bug1163-001.phpt0000644000175100001660000000470314760300421015201 0ustar --TEST-- PHPC-1163: Unacknowledged write concern should omit implicit session --SKIPIF-- --FILE-- 0]); MongoDB\Driver\Monitoring\addSubscriber($this); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); echo "Testing executeBulkWrite\n"; $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command([ 'insert' => COLLECTION_NAME, 'documents' => [['x' => 1]], ]); /* Note: executeCommand() and executeReadCommand() are not tested * because they do not inherit the client-level write concern. */ echo "\nTesting executeWriteCommand\n"; $manager->executeWriteCommand(DATABASE_NAME, $command); /* We can safely re-use the insert command with executeReadWriteCommand * because there is no readConcern to inherit. */ echo "\nTesting executeReadWriteCommand\n"; $manager->executeReadWriteCommand(DATABASE_NAME, $command); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { if ($event->getCommandName() === 'insert') { $command = $event->getCommand(); $hasSession = isset($command->lsid); $writeConcern = isset($command->writeConcern) ? $command->writeConcern: null; printf("insert command write concern: %s\n", json_encode($writeConcern)); printf("insert command has session: %s\n", $hasSession ? 'yes' : 'no'); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } (new Test)->run(); ?> ===DONE=== --EXPECT-- Testing executeBulkWrite insert command write concern: {"w":0} insert command has session: no Testing executeWriteCommand insert command write concern: {"w":0} insert command has session: no Testing executeReadWriteCommand insert command write concern: {"w":0} insert command has session: no ===DONE=== mongodb-1.21.0/tests/manager/bug1701-001.phpt0000644000175100001660000000140014760300421015166 0ustar --TEST-- PHPC-1701: prep_authmechanismproperties may leak if Manager ctor errors --FILE-- 'username', 'authMechanism' => 'GSSAPI', 'authMechanismProperties' => ['canonicalize_host_name' => true]], ['context' => stream_context_create([])] ); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Stream-Context resource does not contain "ssl" options array ===DONE=== mongodb-1.21.0/tests/manager/manager-addSubscriber-001.phpt0000644000175100001660000000350514760300421020274 0ustar --TEST-- MongoDB\Driver\Manager::addSubscriber() with one Manager --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("commandSucceeded: %s\n", $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("commandFailed: %s\n", $event->getCommandName()); } } $m = create_test_manager(); $pingCommand = new MongoDB\Driver\Command(['ping' => 1]); $unsupportedCommand = new MongoDB\Driver\Command(['unsupportedCommand' => 1]); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); $subscriber = new MySubscriber; echo "adding subscriber\n"; $m->addSubscriber($subscriber); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); throws(function () use ($m, $unsupportedCommand) { $m->executeCommand(DATABASE_NAME, $unsupportedCommand); }, MongoDB\Driver\Exception\CommandException::class); echo "removing subscriber\n"; $m->removeSubscriber($subscriber); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); ?> --EXPECT-- ping: 1 adding subscriber commandStarted: ping commandSucceeded: ping ping: 1 commandStarted: unsupportedCommand commandFailed: unsupportedCommand OK: Got MongoDB\Driver\Exception\CommandException removing subscriber ping: 1 mongodb-1.21.0/tests/manager/manager-addSubscriber-002.phpt0000644000175100001660000000620514760300421020275 0ustar --TEST-- MongoDB\Driver\Manager::addSubscriber() with multiple Managers --SKIPIF-- --FILE-- id = $id; } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { printf("MySubscriber(%s) commandStarted: %s\n", $this->id, $event->getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("MySubscriber(%s) commandSucceeded: %s\n", $this->id, $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("MySubscriber(%s) commandFailed: %s\n", $this->id, $event->getCommandName()); } } /* The first two Managers will share the same libmongoc client. The third will * use a different client. */ $m1 = create_test_manager(); $m2 = create_test_manager(); $m3 = create_test_manager(null, [], ['disableClientPersistence' => true]); $s1 = new MySubscriber('s1_on_m1'); $s2 = new MySubscriber('s2_on_m3'); $m1->addSubscriber($s1); $m3->addSubscriber($s2); $pingCommand = new MongoDB\Driver\Command(['ping' => 1]); $unsupportedCommand = new MongoDB\Driver\Command(['unsupportedCommand' => 1]); printf("ping: %d\n", $m1->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); // s1_on_m1 will be notified because both Managers share the same client printf("ping: %d\n", $m2->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); printf("ping: %d\n", $m3->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); throws(function () use ($m1, $unsupportedCommand) { $m1->executeCommand(DATABASE_NAME, $unsupportedCommand); }, MongoDB\Driver\Exception\CommandException::class); throws(function () use ($m2, $unsupportedCommand) { $m2->executeCommand(DATABASE_NAME, $unsupportedCommand); }, MongoDB\Driver\Exception\CommandException::class); throws(function () use ($m3, $unsupportedCommand) { $m3->executeCommand(DATABASE_NAME, $unsupportedCommand); }, MongoDB\Driver\Exception\CommandException::class); ?> --EXPECT-- MySubscriber(s1_on_m1) commandStarted: ping MySubscriber(s1_on_m1) commandSucceeded: ping ping: 1 MySubscriber(s1_on_m1) commandStarted: ping MySubscriber(s1_on_m1) commandSucceeded: ping ping: 1 MySubscriber(s2_on_m3) commandStarted: ping MySubscriber(s2_on_m3) commandSucceeded: ping ping: 1 MySubscriber(s1_on_m1) commandStarted: unsupportedCommand MySubscriber(s1_on_m1) commandFailed: unsupportedCommand OK: Got MongoDB\Driver\Exception\CommandException MySubscriber(s1_on_m1) commandStarted: unsupportedCommand MySubscriber(s1_on_m1) commandFailed: unsupportedCommand OK: Got MongoDB\Driver\Exception\CommandException MySubscriber(s2_on_m3) commandStarted: unsupportedCommand MySubscriber(s2_on_m3) commandFailed: unsupportedCommand OK: Got MongoDB\Driver\Exception\CommandException mongodb-1.21.0/tests/manager/manager-addSubscriber-003.phpt0000644000175100001660000000311014760300421020266 0ustar --TEST-- MongoDB\Driver\Manager::addSubscriber() adds reference to subscriber --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("commandSucceeded: %s\n", $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("commandFailed: %s\n", $event->getCommandName()); } public function __destruct() { echo __METHOD__, "\n"; } } $m = create_test_manager(); $pingCommand = new MongoDB\Driver\Command(['ping' => 1]); $subscriber = new MySubscriber; echo "adding subscriber\n"; $m->addSubscriber($subscriber); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); echo "unsetting subscriber\n"; unset($subscriber); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); echo "unsetting manager\n"; unset($manager); ?> --EXPECT-- adding subscriber commandStarted: ping commandSucceeded: ping ping: 1 unsetting subscriber commandStarted: ping commandSucceeded: ping ping: 1 unsetting manager MySubscriber::__destruct mongodb-1.21.0/tests/manager/manager-addSubscriber-004.phpt0000644000175100001660000000237714760300421020305 0ustar --TEST-- MongoDB\Driver\Manager::addSubscriber() NOP if subscriber already registered --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("commandSucceeded: %s\n", $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("commandFailed: %s\n", $event->getCommandName()); } } $m = create_test_manager(); $pingCommand = new MongoDB\Driver\Command(['ping' => 1]); $subscriber = new MySubscriber; echo "adding subscriber twice\n"; $m->addSubscriber($subscriber); $m->addSubscriber($subscriber); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); ?> --EXPECT-- adding subscriber twice commandStarted: ping commandSucceeded: ping ping: 1 mongodb-1.21.0/tests/manager/manager-addSubscriber-005.phpt0000644000175100001660000000275614760300421020307 0ustar --TEST-- MongoDB\Driver\Manager::addSubscriber() subscriber is only notified once (Manager and global) --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("commandSucceeded: %s\n", $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("commandFailed: %s\n", $event->getCommandName()); } } $m = create_test_manager(); $pingCommand = new MongoDB\Driver\Command(['ping' => 1]); $subscriber = new MySubscriber; MongoDB\Driver\Monitoring\addSubscriber($subscriber); $m->addSubscriber($subscriber); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); // Global subscriber is still notified after Manager subscriber is unregistered $m->removeSubscriber($subscriber); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); ?> --EXPECT-- commandStarted: ping commandSucceeded: ping ping: 1 commandStarted: ping commandSucceeded: ping ping: 1 mongodb-1.21.0/tests/manager/manager-addSubscriber-006.phpt0000644000175100001660000000266314760300421020305 0ustar --TEST-- MongoDB\Driver\Manager::addSubscriber() subscriber is only notified once (two Managers) --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("commandSucceeded: %s\n", $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("commandFailed: %s\n", $event->getCommandName()); } } // Subscribers will share the same libmongoc client $m1 = create_test_manager(); $m2 = create_test_manager(); $pingCommand = new MongoDB\Driver\Command(['ping' => 1]); $subscriber = new MySubscriber; $m1->addSubscriber($subscriber); $m2->addSubscriber($subscriber); printf("ping: %d\n", $m1->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); printf("ping: %d\n", $m2->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); ?> --EXPECT-- commandStarted: ping commandSucceeded: ping ping: 1 commandStarted: ping commandSucceeded: ping ping: 1 mongodb-1.21.0/tests/manager/manager-addSubscriber_error-001.phpt0000644000175100001660000000235514760300421021507 0ustar --TEST-- MongoDB\Driver\Manager::addSubscriber() does not support LogSubscriber instances --FILE-- addSubscriber(new MyLogger); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function () use ($manager) { $manager->addSubscriber(new MySubscriber); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException LogSubscriber instances cannot be registered with a Manager OK: Got MongoDB\Driver\Exception\InvalidArgumentException LogSubscriber instances cannot be registered with a Manager ===DONE=== mongodb-1.21.0/tests/manager/manager-createClientEncryption-001.phpt0000644000175100001660000000112414760300421022170 0ustar --TEST-- MongoDB\Driver\Manager::createClientEncryption() --SKIPIF-- --FILE-- createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]] ]); var_dump($clientEncryption); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ClientEncryption)#%d (%d) { } ===DONE=== mongodb-1.21.0/tests/manager/manager-createClientEncryption-error-001.phpt0000644000175100001660000000127214760300421023323 0ustar --TEST-- MongoDB\Driver\Manager::createClientEncryption() fails if compiled without FLE --SKIPIF-- --FILE-- createClientEncryption([]); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException Cannot configure clientEncryption object. Please recompile with support for libmongocrypt using the with-mongodb-client-side-encryption configure switch. ===DONE=== mongodb-1.21.0/tests/manager/manager-createClientEncryption-error-002.phpt0000644000175100001660000000270714760300421023330 0ustar --TEST-- MongoDB\Driver\Manager::createClientEncryption() with invalid option types --SKIPIF-- --FILE-- 'not_an_array_or_object'], [ 'keyVaultNamespace' => 'not_a_namespace', // keyVaultNamespace requires a valid kmsProviders option 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ], ['kmsProviders' => 'not_an_array_or_object'], ['tlsOptions' => 'not_an_array_or_object'], ]; foreach ($tests as $test) { echo throws(function () use ($test) { $manager = create_test_manager(); $clientEncryption = $manager->createClientEncryption($test); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "keyVaultClient" option to be MongoDB\Driver\Manager, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "keyVaultNamespace" option to contain a full collection namespace OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "kmsProviders" option to be an array or object, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "tlsOptions" option to be an array or object, string given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-001.phpt0000644000175100001660000000026014760300421016462 0ustar --TEST-- MongoDB\Driver\Manager::__construct() with default URI --FILE-- ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-002.phpt0000644000175100001660000000027614760300421016472 0ustar --TEST-- MongoDB\Driver\Manager::__construct() with URI --FILE-- ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-003.phpt0000644000175100001660000000052114760300421016464 0ustar --TEST-- MongoDB\Driver\Manager::__construct() URI defaults to "mongodb://127.0.0.1/" --FILE-- ===DONE=== --EXPECTF-- [%s] PHONGO: DEBUG > Connection string: 'mongodb://127.0.0.1/' %A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-004.phpt0000644000175100001660000000116314760300421016470 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): Deprecated boolean options in URI string --FILE-- getWriteConcern()->getJournal()); } ?> ===DONE=== --EXPECTF-- bool(true) bool(true) bool(true) bool(true) bool(false) bool(false) bool(false) bool(false) bool(false) ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-005.phpt0000644000175100001660000000035314760300421016471 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): Ensure environmental URI is parsable --FILE-- ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-006.phpt0000644000175100001660000000077514760300421016502 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): Unparsable environmental URI --ENV-- MONGODB_URI=invalid --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'invalid'. Invalid URI Schema, expecting 'mongodb://' or 'mongodb+srv://'. ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-007.phpt0000644000175100001660000000060714760300421016475 0ustar --TEST-- MongoDB\Driver\Manager::__construct() reuses cached mongoc client --FILE-- ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s %A [%s] PHONGO: DEBUG > Found client for hash: %s %A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-008.phpt0000644000175100001660000000065014760300421016474 0ustar --TEST-- MongoDB\Driver\Manager::__construct() does not canonicalise options --FILE-- ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s %A [%s] PHONGO: DEBUG > Created client with hash: %s %A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-appname-001.phpt0000644000175100001660000000110114760300421020074 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): appname option --SKIPIF-- --FILE-- "2-{$name2}"]); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand("test", $command); ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-appname_error-001.phpt0000644000175100001660000000331614760300421021317 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid appname --FILE-- "2-{$name2}"]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Invalid appname value: '2-PHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGOPHONGO' ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auth_mechanism-001.phpt0000644000175100001660000000163014760300421021447 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): authMechanism option --FILE-- 'MONGODB-X509', 'username' => 'username']], [null, ['authMechanism' => 'MONGODB-X509']], [null, ['authMechanism' => 'GSSAPI', 'username' => 'username']], [null, ['authMechanism' => 'MONGODB-AWS']], ]; foreach ($tests as $test) { list($uri, $options) = $test; /* Note: the Manager's debug information does not include the auth mechanism * so we are merely testing that no exception is thrown. */ $manager = new MongoDB\Driver\Manager($uri, $options); } ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auth_mechanism-002.phpt0000644000175100001660000000260114760300421021447 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): authMechanismProperties option --FILE-- 'username', 'authMechanism' => 'GSSAPI', 'authMechanismProperties' => ['CANONICALIZE_HOST_NAME' => 'true', 'SERVICE_NAME' => 'foo', 'SERVICE_REALM' => 'bar']]], // Options are case-insensitive ['mongodb://username@127.0.0.1/?authMechanism=GSSAPI&authMechanismProperties=canonicalize_host_name:TRUE,service_name:foo,service_realm:bar', []], [null, ['username' => 'username', 'authMechanism' => 'GSSAPI', 'authMechanismProperties' => ['canonicalize_host_name' => 'TRUE', 'service_name' => 'foo', 'service_realm' => 'bar']]], // Boolean true "CANONICALIZE_HOST_NAME" value is converted to "true" [null, ['username' => 'username', 'authMechanism' => 'GSSAPI', 'authMechanismProperties' => ['canonicalize_host_name' => true]]], ]; foreach ($tests as $test) { list($uri, $options) = $test; /* Note: the Manager's debug information does not include the auth mechanism * so we are merely testing that no exception is thrown and that option * processing does not leak memory. */ $manager = new MongoDB\Driver\Manager($uri, $options); } ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auth_mechanism-error-001.phpt0000644000175100001660000000525614760300421022606 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): authentication options are validated --FILE-- 'GSSAPI', 'authSource' => 'admin']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://localhost:27017/?authMechanism=MONGODB-X509&authSource=admin'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://localhost:27017/', ['authMechanism' => 'MONGODB-X509', 'authSource' => 'admin']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://@localhost:27017/?authMechanism=SCRAM-SHA-1'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://localhost:27017/', ['username' => '', 'authMechanism' => 'SCRAM-SHA-1']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://localhost:27017/', ['password' => 'password', 'authMechanism' => 'MONGODB-X509']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?authMechanism=GSSAPI&authSource=admin'. GSSAPI and X509 require "$external" authSource. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: GSSAPI and X509 require "$external" authSource OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?authMechanism=MONGODB-X509&authSource=admin'. GSSAPI and X509 require "$external" authSource. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: GSSAPI and X509 require "$external" authSource OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://@localhost:27017/?authMechanism=SCRAM-SHA-1'. 'SCRAM-SHA-1' authentication mechanism requires username. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: 'SCRAM-SHA-1' authentication mechanism requires username OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: 'MONGODB-X509' authentication mechanism does not accept a password ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auth_source-001.phpt0000644000175100001660000000102014760300421020774 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): authSource option --FILE-- '$external']], ]; foreach ($tests as $test) { list($uri, $options) = $test; /* Note: the Manager's debug information does not include the auth mechanism * so we are merely testing that no exception is thrown. */ $manager = new MongoDB\Driver\Manager($uri, $options); } ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auto_encryption-001.phpt0000644000175100001660000000352514760300421021711 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): autoEncryption options --SKIPIF-- --FILE-- CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], /* Testing the schemaMap option requires either crypt_shared or mongocryptd * for automatic encryption. Disable mongocryptd spawning to avoid a test * failure if crypt_shared and mongocryptd are both unavailable. */ 'extraOptions' => ['mongocryptdBypassSpawn' => true], ]; $tests = [ [], ['bypassAutoEncryption' => true], ['bypassQueryAnalysis' => true], ['keyVaultClient' => create_test_manager()], ['schemaMap' => [ 'default.default' => [ 'properties' => [ 'encrypted_objectId' => [ 'encrypt' => [ 'keyId' => [ [ '$binary' => [ 'base64' => 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType' => '04', ], ], ], 'bsonType' => 'objectId', 'algorithm' => MongoDB\Driver\ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, ], ], ], 'bsonType' => 'object', ], ]], ]; foreach ($tests as $autoEncryptionOptions) { create_test_manager(null, [], ['autoEncryption' => $autoEncryptionOptions + $baseOptions]); } ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auto_encryption-002.phpt0000644000175100001660000000142014760300421021702 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): crypt_shared is required --SKIPIF-- --XFAIL-- crypt_shared log output breaks build (PHPC-2156) --FILE-- CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], 'extraOptions' => ['cryptSharedLibRequired' => true], ]; create_test_manager(null, [], ['autoEncryption' => $autoEncryptionOptions]); var_dump(get_module_info('crypt_shared library version')); ?> ===DONE=== --EXPECTF-- string(%d) "mongo_crypt%a" ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auto_encryption-error-001.phpt0000644000175100001660000000147114760300421023036 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): incomplete autoEncryption options --SKIPIF-- --FILE-- CSFLE_KEY_VAULT_NS], ]; foreach ($tests as $autoEncryptionOptions) { echo throws(function() use ($autoEncryptionOptions) { create_test_manager(null, [], ['autoEncryption' => $autoEncryptionOptions]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Key vault namespace option required OK: Got MongoDB\Driver\Exception\InvalidArgumentException KMS providers option required ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auto_encryption-error-002.phpt0000644000175100001660000000126514760300421023040 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): autoEncryption when compiling without libmongocrypt --SKIPIF-- --FILE-- []]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot enable automatic field-level encryption. Please recompile with support for libmongocrypt using the with-mongodb-client-side-encryption configure switch. ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auto_encryption-error-003.phpt0000644000175100001660000000674214760300421023046 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid types in autoEncryption options --SKIPIF-- --FILE-- 'not_an_array_or_object'], ['keyVaultClient' => 'not_an_array_or_object'], [ 'keyVaultNamespace' => 'not_a_namespace', // keyVaultNamespace requires a valid kmsProviders option 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ], ['kmsProviders' => 'not_an_array_or_object'], ['schemaMap' => 'not_an_array_or_object'], ['tlsOptions' => 'not_an_array_or_object'], ['extraOptions' => 'not_an_array_or_object'], ]; foreach ($tests as $autoEncryptionOptions) { echo throws(function() use ($autoEncryptionOptions) { create_test_manager(null, [], ['autoEncryption' => $autoEncryptionOptions]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n\n"; } // PackedArray cannot be serialized as a root document $tests = [ ['encryptedFieldsMap' => MongoDB\BSON\PackedArray::fromPHP([])], ['kmsProviders' => MongoDB\BSON\PackedArray::fromPHP([])], ['schemaMap' => MongoDB\BSON\PackedArray::fromPHP([])], ['tlsOptions' => MongoDB\BSON\PackedArray::fromPHP([])], ['extraOptions' => MongoDB\BSON\PackedArray::fromPHP([])], ]; foreach ($tests as $autoEncryptionOptions) { echo throws(function() use ($autoEncryptionOptions) { create_test_manager(null, [], ['autoEncryption' => $autoEncryptionOptions]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "autoEncryption" driver option to be array, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "encryptedFieldsMap" autoEncryption option to be an array or object, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "keyVaultClient" autoEncryption option to be MongoDB\Driver\Manager, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "keyVaultNamespace" autoEncryption option to contain a full collection namespace OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "kmsProviders" autoEncryption option to be an array or object, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "schemaMap" autoEncryption option to be an array or object, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "tlsOptions" autoEncryption option to be an array or object, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "extraOptions" autoEncryption option to be an array or object, string given OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-auto_encryption-error-004.phpt0000644000175100001660000000246414760300421023044 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): crypt_shared is required and unavailable --SKIPIF-- --FILE-- CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]; $tests = [ ['extraOptions' => ['cryptSharedLibPath' => '/not/found']], ['extraOptions' => ['cryptSharedLibRequired' => true]], ]; foreach ($tests as $autoEncryptionOptions) { echo throws(function() use ($autoEncryptionOptions, $baseOptions) { create_test_manager(null, [], ['autoEncryption' => $autoEncryptionOptions + $baseOptions]); }, MongoDB\Driver\Exception\EncryptionException::class), "\n\n"; } var_dump(get_module_info('crypt_shared library version')); ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\EncryptionException A crypt_shared override path was specified [/not/found], but we failed to open a dynamic library at that location%A OK: Got MongoDB\Driver\Exception\EncryptionException Option 'cryptSharedLibRequired' is 'true', but failed to load the crypt_shared runtime library string(7) "unknown" ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-directconnection-001.phpt0000644000175100001660000000235314760300421022017 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): directConnection option --SKIPIF-- --FILE-- false]); $server = $manager->selectServer(new \MongoDB\Driver\ReadPreference('primaryPreferred')); printf("Topology has multiple nodes when directConnection=false: %s\n", count($manager->getServers()) > 1 ? 'true' : 'false'); $uri = sprintf('mongodb://%s:%d', $server->getHost(), $server->getPort()); $manager2 = create_test_manager($uri, ['directConnection' => true]); $server2 = $manager2->selectServer(new \MongoDB\Driver\ReadPreference('primaryPreferred')); printf("Topology has single node when directConnection=true: %s\n", count($manager2->getServers()) == 1 ? 'true' : 'false'); printf("Single node in topology matches seed in URI: %s\n", ($server2 == $server) ? 'true' : 'false'); ?> ===DONE=== --EXPECT-- Topology has multiple nodes when directConnection=false: true Topology has single node when directConnection=true: true Single node in topology matches seed in URI: true ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-directconnection-error-001.phpt0000644000175100001660000000167414760300421023153 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): directConnection=true conflicts with multiple seeds --FILE-- true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://a.example.com,b.example.com/?directConnection=true'. Multiple seeds not allowed with directConnection option. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: Multiple seeds not allowed with directConnection option ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-directconnection-error-002.phpt0000644000175100001660000000160514760300421023146 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): directConnection=true conflicts with SRV --FILE-- true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb+srv://a.example.com/?directConnection=true'. SRV URI not allowed with directConnection option. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: SRV URI not allowed with directConnection option ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-001.phpt0000644000175100001660000000315314760300421023433 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): disableClientPersistence option --FILE-- false]); // Will reuse the previous client due to same options new MongoDB\Driver\Manager(null, [], ['disableClientPersistence' => false]); // Will create a non-persistent client new MongoDB\Driver\Manager(null, [], ['disableClientPersistence' => true]); // Will create another non-persistent client new MongoDB\Driver\Manager(null, [], ['disableClientPersistence' => true]); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored persistent client with hash: %s [%s] PHONGO: DEBUG > Not destroying persistent client for Manager%A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored persistent client with hash: %s [%s] PHONGO: DEBUG > Not destroying persistent client for Manager%A [%s] PHONGO: DEBUG > Found client for hash: %s [%s] PHONGO: DEBUG > Not destroying persistent client for Manager%A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-002.phpt0000644000175100001660000000335214760300421023435 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by Cursor --SKIPIF-- --FILE-- true]); ini_set('mongodb.debug', ''); echo "Inserting data\n"; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1, 'x' => 2, 'y' => 3]); $bulk->insert(['_id' => 2, 'x' => 3, 'y' => 4]); $bulk->insert(['_id' => 3, 'x' => 4, 'y' => 5]); $manager->executeBulkWrite(NS, $bulk); echo "Creating cursor\n"; $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Iterating cursor\n"; var_dump(iterator_to_array($cursor)); echo "Unsetting cursor\n"; ini_set('mongodb.debug', 'stderr'); unset($cursor); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Inserting data Creating cursor Unsetting manager Iterating cursor array(3) { [0]=> object(stdClass)#%d (3) { ["_id"]=> int(1) ["x"]=> int(2) ["y"]=> int(3) } [1]=> object(stdClass)#%d (3) { ["_id"]=> int(2) ["x"]=> int(3) ["y"]=> int(4) } [2]=> object(stdClass)#%d (3) { ["_id"]=> int(3) ["x"]=> int(4) ["y"]=> int(5) } } Unsetting cursor%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-003.phpt0000644000175100001660000000177714760300421023447 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by Session --SKIPIF-- --FILE-- true]); ini_set('mongodb.debug', ''); echo "Creating session\n"; $session = $manager->startSession(); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Unsetting session\n"; ini_set('mongodb.debug', 'stderr'); unset($session); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Creating session Unsetting manager Unsetting session%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-004.phpt0000644000175100001660000000177314760300421023444 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by Server --SKIPIF-- --FILE-- true]); ini_set('mongodb.debug', ''); echo "Creating server\n"; $server = $manager->selectServer(new MongoDB\Driver\ReadPreference('nearest')); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Unsetting server\n"; ini_set('mongodb.debug', 'stderr'); unset($server); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Creating server Unsetting manager Unsetting server%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-005.phpt0000644000175100001660000000231414760300421023435 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by WriteResult --SKIPIF-- --FILE-- true]); ini_set('mongodb.debug', ''); echo "Inserting data\n"; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1, 'x' => 2, 'y' => 3]); $bulk->insert(['_id' => 2, 'x' => 3, 'y' => 4]); $bulk->insert(['_id' => 3, 'x' => 4, 'y' => 5]); $writeResult = $manager->executeBulkWrite(NS, $bulk); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Unsetting writeResult\n"; ini_set('mongodb.debug', 'stderr'); unset($writeResult); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Inserting data Unsetting manager Unsetting writeResult%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-006.phpt0000644000175100001660000000232014760300421023433 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by ClientEncryption (implicit keyVaultClient) --SKIPIF-- --FILE-- true]); ini_set('mongodb.debug', ''); echo "Creating clientEncryption\n"; $clientEncryption = $manager->createClientEncryption([ 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Unsetting clientEncryption\n"; ini_set('mongodb.debug', 'stderr'); unset($clientEncryption); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Creating clientEncryption Unsetting manager Unsetting clientEncryption%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-007.phpt0000644000175100001660000000324414760300421023442 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by ClientEncryption (explicit keyVaultClient) --SKIPIF-- --FILE-- true]); $keyVaultClient = create_test_manager(null, [], ['disableClientPersistence' => true]); ini_set('mongodb.debug', ''); echo "Creating clientEncryption\n"; $clientEncryption = $manager->createClientEncryption([ 'keyVaultClient' => $keyVaultClient, 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ]); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Unsetting keyVaultClient\n"; ini_set('mongodb.debug', 'stderr'); unset($keyVaultClient); ini_set('mongodb.debug', ''); echo "Unsetting clientEncryption\n"; ini_set('mongodb.debug', 'stderr'); unset($clientEncryption); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Creating clientEncryption Unsetting manager [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A Unsetting keyVaultClient Unsetting clientEncryption%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-008.phpt0000644000175100001660000000363714760300421023451 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by CommandStartedEvent --SKIPIF-- --FILE-- getCommandName()); $this->events[] = $event; } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $subscriber = new MySubscriber; ini_set('mongodb.debug', 'stderr'); $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); ini_set('mongodb.debug', ''); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command); /* Remove the subscriber to ensure that the extension does not hold an internal * reference to it. This guarantees that the event object (and final Manager * reference) will be freed when the subscriber is later unset. */ MongoDB\Driver\Monitoring\removeSubscriber($subscriber); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Unsetting subscriber\n"; ini_set('mongodb.debug', 'stderr'); unset($subscriber); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Command started: ping Unsetting manager Unsetting subscriber%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-009.phpt0000644000175100001660000000364514760300421023451 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by CommandSucceededEvent --SKIPIF-- --FILE-- getCommandName()); $this->events[] = $event; } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $subscriber = new MySubscriber; ini_set('mongodb.debug', 'stderr'); $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); ini_set('mongodb.debug', ''); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command); /* Remove the subscriber to ensure that the extension does not hold an internal * reference to it. This guarantees that the event object (and final Manager * reference) will be freed when the subscriber is later unset. */ MongoDB\Driver\Monitoring\removeSubscriber($subscriber); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Unsetting subscriber\n"; ini_set('mongodb.debug', 'stderr'); unset($subscriber); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Command succeeded: ping Unsetting manager Unsetting subscriber%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-010.phpt0000644000175100001660000000412214760300421023430 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by CommandFailedEvent --SKIPIF-- --FILE-- getCommandName()); $this->events[] = $event; } } $subscriber = new MySubscriber; ini_set('mongodb.debug', 'stderr'); $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); ini_set('mongodb.debug', ''); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['unsupportedCommand' => 1]); throws(function () use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, MongoDB\Driver\Exception\CommandException::class); /* Remove the subscriber to ensure that the extension does not hold an internal * reference to it. This guarantees that the event object (and final Manager * reference) will be freed when the subscriber is later unset. */ MongoDB\Driver\Monitoring\removeSubscriber($subscriber); echo "Unsetting manager\n"; ini_set('mongodb.debug', 'stderr'); unset($manager); ini_set('mongodb.debug', ''); echo "Unsetting subscriber\n"; ini_set('mongodb.debug', 'stderr'); unset($subscriber); ini_set('mongodb.debug', ''); ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Command failed: unsupportedCommand OK: Got MongoDB\Driver\Exception\CommandException Unsetting manager Unsetting subscriber%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence-011.phpt0000644000175100001660000000326014760300421023433 0ustar --TEST-- MongoDB\Driver\Manager with disableClientPersistence=true referenced by APM subscriber freed in RSHUTDOWN --SKIPIF-- --FILE-- getCommandName()); $this->events[] = $event; } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $subscriber = new MySubscriber; ini_set('mongodb.debug', 'stderr'); $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); ini_set('mongodb.debug', ''); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command); ini_set('mongodb.debug', 'stderr'); echo "Unsetting manager\n"; unset($manager); echo "Unsetting subscriber\n"; unset($subscriber); /* Since the subscriber has not been removed, the remaining internal reference to * it will be freed during RSHUTDOWN. */ ?> ===DONE=== --EXPECTF-- %A [%s] PHONGO: DEBUG > Created client with hash: %s [%s] PHONGO: DEBUG > Stored non-persistent client Command started: ping Unsetting manager Unsetting subscriber ===DONE===%A [%s] PHONGO: DEBUG > Destroying non-persistent client for Manager%A mongodb-1.21.0/tests/manager/manager-ctor-disableClientPersistence_error-001.phpt0000644000175100001660000000272514760300421024650 0ustar --TEST-- MongoDB\Driver\Manager and keyVaultClient must have same disableClientPersistence option --SKIPIF-- --FILE-- [ 'keyVaultClient' => create_test_manager(null), 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ], 'disableClientPersistence' => true, ]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { create_test_manager(null, [], [ 'autoEncryption' => [ 'keyVaultClient' => create_test_manager(null, [], ['disableClientPersistence' => true]), 'keyVaultNamespace' => CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], ] ]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException The "disableClientPersistence" option for a Manager and its "keyVaultClient" must be the same OK: Got MongoDB\Driver\Exception\InvalidArgumentException The "disableClientPersistence" option for a Manager and its "keyVaultClient" must be the same ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-driver-metadata-001.phpt0000644000175100001660000000233014760300421021531 0ustar --TEST-- MongoDB\Driver\Manager: Pass custom handshake data --DESCRIPTION-- This test matches spaces at the end of the handshake data it appends. The only way to see final output is by checking against the binary socket communication: [2021-02-17T13:57:57.155166+00:00] socket: TRACE > 00100: 66 6f 72 6d 00 76 00 00 00 50 48 50 20 37 2e 34 f o r m . v . . . P H P 7 . 4 [2021-02-17T13:57:57.155182+00:00] socket: TRACE > 00110: 2e 31 35 20 2f 20 6d 69 6e 65 20 63 66 67 3d 30 . 1 5 / m i n e c f g = 0 Since matching this is not trivial, we're happy matching the trailing space at the end of each handshake data item. --INI-- mongodb.debug=stderr --FILE-- ['name' => 'test', 'version' => '0.1', 'platform' => 'mine']]); $manager = new MongoDB\Driver\Manager(null, [], ['driver' => ['name' => 'test']]); ?> ===DONE=== --EXPECTF-- %A[%s] PHONGO: DEBUG > Setting driver handshake data: { name: 'ext-mongodb:PHP / test ', version: '%s / 0.1 ', platform: 'PHP %s / mine ' } %A[%s] PHONGO: DEBUG > Setting driver handshake data: { name: 'ext-mongodb:PHP / test ', version: '%s ', platform: 'PHP %s ' } %A===DONE===%A mongodb-1.21.0/tests/manager/manager-ctor-duplicate-option-001.phpt0000644000175100001660000000052114760300421021740 0ustar --TEST-- MongoDB\Driver\Manager::__construct() with duplicate read preference option --FILE-- 'primary', 'readpreference' => 'secondary']); echo $manager->getReadPreference()->getModeString(), "\n"; ?> ===DONE=== --EXPECT-- secondary ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-duplicate-option-002.phpt0000644000175100001660000000050314760300421021741 0ustar --TEST-- MongoDB\Driver\Manager::__construct() with duplicate read concern option --FILE-- 'majority', 'readconcernlevel' => 'local']); echo $manager->getReadConcern()->getLevel(), "\n"; ?> ===DONE=== --EXPECT-- local ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-duplicate-option-003.phpt0000644000175100001660000000045714760300421021752 0ustar --TEST-- MongoDB\Driver\Manager::__construct() with duplicate write concern option --FILE-- 500, 'wTimeoutMs' => 200]); echo $manager->getWriteConcern()->getWtimeout(), "\n"; ?> ===DONE=== --EXPECT-- 200 ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-duplicate-option-004.phpt0000644000175100001660000000067414760300421021754 0ustar --TEST-- MongoDB\Driver\Manager::__construct() with duplicate read preference tags --FILE-- 'secondary', 'readPreferenceTags' => [['dc' => 'ny']], 'readpreferencetags' => [['dc' => 'ca']]]); var_dump($manager->getReadPreference()->getTagSets()); ?> ===DONE=== --EXPECT-- array(1) { [0]=> array(1) { ["dc"]=> string(2) "ca" } } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-loadBalanced_error-001.phpt0000644000175100001660000000464714760300421022237 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): loadBalanced option validation --FILE-- true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://localhost:27017/?loadBalanced=true&replicaSet=foo'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://localhost:27017', ['loadBalanced' => true, 'replicaSet' => 'foo']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://localhost:27017/?loadBalanced=true&directConnection=true'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://localhost:27017', ['loadBalanced' => true, 'directConnection' => true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017,localhost:27018/?loadBalanced=true'. URI with "loadbalanced" enabled must not contain more than one host. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: URI with "loadbalanced" enabled must not contain more than one host OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?loadBalanced=true&replicaSet=foo'. URI with "loadbalanced" enabled must not contain option "replicaset". OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: URI with "loadbalanced" enabled must not contain option "replicaset" OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?loadBalanced=true&directConnection=true'. URI with "loadbalanced" enabled must not contain option "directconnection" enabled. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: URI with "loadbalanced" enabled must not contain option "directconnection" enabled ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-read_concern-001.phpt0000644000175100001660000000143514760300421021107 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): read concern options --FILE-- 'local']], ]; foreach ($tests as $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getReadConcern()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(5) "local" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(1) "1" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(5) "local" } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-read_concern-error-001.phpt0000644000175100001660000000072014760300421022232 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid read concern --FILE-- 1]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "readConcernLevel" URI option, 32-bit integer given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-read_preference-001.phpt0000644000175100001660000000326314760300421021577 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): read preference options --FILE-- 'primary']], [null, ['readPreference' => 'secondary', 'readPreferenceTags' => [['tag' => 'one'], []]]], [null, ['readPreference' => 'secondary', 'maxStalenessSeconds' => 1000]], ]; foreach ($tests as $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getReadPreference()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(2) { [0]=> object(stdClass)#%d (%d) { ["tag"]=> string(3) "one" } [1]=> object(stdClass)#%d (%d) { } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(2) { [0]=> object(stdClass)#%d (%d) { ["tag"]=> string(3) "one" } [1]=> object(stdClass)#%d (%d) { } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-read_preference-002.phpt0000644000175100001660000000262014760300421021574 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): read preference options (maxStalenessSeconds) --FILE-- 1231]], ['mongodb://127.0.0.1/?readPreference=secondary&maxStalenessSeconds=1000', ['maxStalenessSeconds' => 2000]], ['mongodb://127.0.0.1/?readpreference=secondary&maxstalenessseconds=1231', []], ['mongodb://127.0.0.1/?readpreference=secondary', ['maxstalenessseconds' => 1231]], ]; foreach ($tests as $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getReadPreference()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1231) } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1231) } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(2000) } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1231) } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1231) } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-read_preference-error-001.phpt0000644000175100001660000000554114760300421022727 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid read preference (mode and tags) --FILE-- 1]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['readPreference' => 'primary', 'readPreferenceTags' => 'invalid']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; // Invalid values echo throws(function() { create_test_manager('mongodb://127.0.0.1/?readPreference=primary&readPreferenceTags=dc:ny'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['readPreference' => 'nothing']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://127.0.0.1/?readPreference=primary', ['readPreferenceTags' => [[]]]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://127.0.0.1/?readPreference=primary', ['readPreferenceTags' => ['invalid']]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?readPreference=1'. Error while assigning URI read preference: Unsupported readPreference value [readPreference=1]. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?readPreference=secondary&readPreferenceTags=invalid'. Unsupported value for "readPreferenceTags": "invalid". OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "readPreference" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected array for "readPreferenceTags" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?readPreference=primary&readPreferenceTags=dc:ny'. Invalid readPreferences. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Unsupported readPreference value: 'nothing' OK: Got MongoDB\Driver\Exception\InvalidArgumentException Primary read preference mode conflicts with tags OK: Got MongoDB\Driver\Exception\InvalidArgumentException Read preference tags must be an array of zero or more documents ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-read_preference-error-002.phpt0000644000175100001660000000667414760300421022740 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid read preference (maxStalenessSeconds) --FILE-- 'invalid']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; // Invalid range in URI string (array option is tested in 64-bit error test) echo throws(function() { create_test_manager('mongodb://127.0.0.1/?readPreference=secondary&maxStalenessSeconds=2147483648'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; // Invalid values echo throws(function() { create_test_manager('mongodb://127.0.0.1/?maxstalenessseconds=1231'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://127.0.0.1/?maxStalenessSeconds=1231'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['maxstalenessseconds' => 1231]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['maxStalenessSeconds' => 1231]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['readPreference' => 'secondary', 'maxStalenessSeconds' => -2]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['readPreference' => 'secondary', 'maxStalenessSeconds' => 0]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['readPreference' => 'secondary', 'maxStalenessSeconds' => 42]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?readPreference=secondary&maxStalenessSeconds=invalid'. Unsupported value for "maxstalenessseconds": "invalid". OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected integer for "maxStalenessSeconds" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?readPreference=secondary&maxStalenessSeconds=2147483648'. Unsupported value for "maxstalenessseconds": "2147483648". OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?maxstalenessseconds=1231'. Invalid readPreferences. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?maxStalenessSeconds=1231'. Invalid readPreferences. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Primary read preference mode conflicts with maxStalenessSeconds OK: Got MongoDB\Driver\Exception\InvalidArgumentException Primary read preference mode conflicts with maxStalenessSeconds OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected maxStalenessSeconds to be >= 90, -2 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected maxStalenessSeconds to be >= 90, 0 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected maxStalenessSeconds to be >= 90, 42 given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-read_preference-error-004.phpt0000644000175100001660000000115414760300421022726 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid read preference (maxStalenessSeconds range) --SKIPIF-- --FILE-- 'secondary', 'maxStalenessSeconds' => 2147483648]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected maxStalenessSeconds to be <= 2147483647, 2147483648 given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-server.phpt0000644000175100001660000000070314760300421017472 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): check if server is live --FILE-- 1]); try { $manager->executeCommand("test", $command); } catch (\MongoDB\Driver\Exception\ConnectionException $e) { echo "Could not connect to MongoDB server: ", $e->getMessage(), "\n"; } ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-serverApi-001.phpt0000644000175100001660000000231214760300421020420 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): serverApi driver option --SKIPIF-- --FILE-- getCommand(); var_dump($command->apiVersion); var_dump(isset($command->apiStrict)); var_dump(isset($command->apiDeprecationErrors)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $subscriber = new MySubscriber(); $manager = create_test_manager(URI, [], ['serverApi' => new MongoDB\Driver\ServerApi('1')]); MongoDB\Driver\Monitoring\addSubscriber($subscriber); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> ===DONE=== --EXPECT-- string(1) "1" bool(false) bool(false) ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-serverApi-error-001.phpt0000644000175100001660000000074614760300421021560 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): serverApi driver option (error) --FILE-- '1']); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "serverApi" driver option to be MongoDB\Driver\ServerApi, string given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-srvMaxHosts_error-001.phpt0000644000175100001660000000433214760300421022176 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): srvMaxHosts option validation --FILE-- 1]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb+srv://a.example.com/?srvMaxHosts=1&replicaSet=foo'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb+srv://a.example.com', ['srvMaxHosts' => 1, 'replicaSet' => 'foo']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb+srv://a.example.com/?srvMaxHosts=1&loadBalanced=true'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb+srv://a.example.com', ['srvMaxHosts' => 1, 'loadBalanced' => true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?srvMaxHosts=1'. srvmaxhosts must not be specified with a non-SRV URI. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: srvmaxhosts must not be specified with a non-SRV URI OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb+srv://a.example.com/?srvMaxHosts=1&replicaSet=foo'. srvmaxhosts must not be specified with replicaset. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: srvmaxhosts must not be specified with replicaset OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb+srv://a.example.com/?srvMaxHosts=1&loadBalanced=true'. srvmaxhosts must not be specified with loadbalanced=true. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: srvmaxhosts must not be specified with loadbalanced=true ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-srvServiceName_error-001.phpt0000644000175100001660000000154514760300421022634 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): srvServiceName option validation --FILE-- 'foo']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?srvServiceName=foo'. srvservicename must not be specified with a non-SRV URI. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: srvservicename must not be specified with a non-SRV URI ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-ssl-001.phpt0000644000175100001660000000146214760300421017266 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): ssl option does not require driverOptions --SKIPIF-- --FILE-- true])); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Manager)#%d (%d) { ["uri"]=> string(29) "mongodb://127.0.0.1/?ssl=true" ["cluster"]=> array(0) { } } object(MongoDB\Driver\Manager)#%d (%d) { ["uri"]=> string(20) "mongodb://127.0.0.1/" ["cluster"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-ssl-002.phpt0000644000175100001660000000063414760300421017267 0ustar --TEST-- PHPC-1239: Passing SSL driverOptions overrides SSL options from URI --SKIPIF-- --FILE-- executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-ssl-003.phpt0000644000175100001660000000175414760300421017274 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): Specifying a driver option implicitly enables TLS --SKIPIF-- --FILE-- executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager = create_test_manager(URI, [], ['ca_dir' => 'foo']); throws(function () use ($manager) { // Note that this command will not fail if the server was configured with allowSSL or preferSSL for net.ssl.mode. $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => true])); }, MongoDB\Driver\Exception\ConnectionException::class); ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionException ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-ssl-deprecated-001.phpt0000644000175100001660000000630414760300421021364 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): Test deprecated options --SKIPIF-- --FILE-- true], ['weak_cert_validation' => true], ['allow_self_signed' => true], ['pem_file' => 'foo'], ['local_cert' => 'foo'], ['pem_pwd' => 'foo'], ['passphrase' => 'foo'], ['ca_file' => 'foo'], ['cafile' => 'foo'], ['context' => stream_context_create(['ssl' => ['cafile' => 'foo']])], ['context' => stream_context_create(['ssl' => ['capath' => 'foo']])], ['context' => stream_context_create(['ssl' => ['local_cert' => 'foo']])], ['context' => stream_context_create(['ssl' => ['passphrase' => 'foo']])], ['context' => stream_context_create(['ssl' => ['allow_self_signed' => true]])], ]; foreach ($deprecatedDriverOptions as $driverOptions) { echo raises( function () use ($driverOptions) { create_test_manager('mongodb://127.0.0.1/', [], $driverOptions); }, E_DEPRECATED ), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "allow_invalid_hostname" driver option is deprecated. Please use the "tlsAllowInvalidHostnames" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "weak_cert_validation" driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "allow_self_signed" context driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "pem_file" driver option is deprecated. Please use the "tlsCertificateKeyFile" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "local_cert" context driver option is deprecated. Please use the "tlsCertificateKeyFile" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "pem_pwd" driver option is deprecated. Please use the "tlsCertificateKeyFilePassword" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "passphrase" context driver option is deprecated. Please use the "tlsCertificateKeyFilePassword" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "ca_file" driver option is deprecated. Please use the "tlsCAFile" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "cafile" context driver option is deprecated. Please use the "tlsCAFile" URI option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated. ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-ssl-deprecated-002.phpt0000644000175100001660000000160714760300421021366 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): Test deprecated options (capath) --SKIPIF-- --FILE-- 'foo']); }, E_DEPRECATED ), "\n"; echo raises( function () { create_test_manager('mongodb://127.0.0.1/', [], ['context' => stream_context_create(['ssl' => ['capath' => 'foo']])]); }, E_DEPRECATED ), "\n"; ?> ===DONE=== --EXPECT-- OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "capath" context driver option is deprecated. Please use the "ca_dir" driver option instead. OK: Got E_DEPRECATED MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated. ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-tls-error-001.phpt0000644000175100001660000003544014760300421020421 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): Test invalid URI option combinations --FILE-- $valueB ] ); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; } } echo "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=false&tlsAllowInvalidHostnames=false'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=false&tlsAllowInvalidHostnames=true'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=true&tlsAllowInvalidHostnames=false'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=true&tlsAllowInvalidHostnames=true'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=false&tlsAllowInvalidCertificates=false'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=false&tlsAllowInvalidCertificates=true'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=true&tlsAllowInvalidCertificates=false'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=true&tlsAllowInvalidCertificates=true'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=false&tlsDisableOCSPEndpointCheck=false'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=false&tlsDisableOCSPEndpointCheck=true'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=true&tlsDisableOCSPEndpointCheck=false'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=true&tlsDisableOCSPEndpointCheck=true'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=false&tlsDisableCertificateRevocationCheck=false'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=false&tlsDisableCertificateRevocationCheck=true'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=true&tlsDisableCertificateRevocationCheck=false'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsInsecure=true&tlsDisableCertificateRevocationCheck=true'. tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsinsecure may not be specified with tlsallowinvalidcertificates, tlsallowinvalidhostnames, tlsdisableocspendpointcheck, or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsAllowInvalidCertificates=false&tlsDisableOCSPEndpointCheck=false'. tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsAllowInvalidCertificates=false&tlsDisableOCSPEndpointCheck=true'. tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsAllowInvalidCertificates=true&tlsDisableOCSPEndpointCheck=false'. tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsAllowInvalidCertificates=true&tlsDisableOCSPEndpointCheck=true'. tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsAllowInvalidCertificates=false&tlsDisableCertificateRevocationCheck=false'. tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsAllowInvalidCertificates=false&tlsDisableCertificateRevocationCheck=true'. tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsAllowInvalidCertificates=true&tlsDisableCertificateRevocationCheck=false'. tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?tlsAllowInvalidCertificates=true&tlsDisableCertificateRevocationCheck=true'. tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse URI options: tlsallowinvalidcertificates may not be specified with tlsdisableocspendpointcheck or tlsdisablecertificaterevocationcheck ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-wireversion.phpt0000644000175100001660000000101014760300421020530 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): wire version support --FILE-- 1]); try { $manager->executeCommand("test", $command); } catch (\MongoDB\Driver\Exception\ConnectionException $e) { if ($e->getCode() == 15) { // MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION echo "Bad wire version detected: ", $e->getMessage(), "\n"; } } ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-001.phpt0000644000175100001660000000261314760300421021325 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): write concern options (w) --FILE-- -1]], [null, ['w' => -0]], [null, ['w' => 1]], [null, ['w' => 'majority']], [null, ['w' => 'customTagSet']], ]; foreach ($tests as $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getWriteConcern()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(-1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(12) "customTagSet" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(-1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(12) "customTagSet" } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-002.phpt0000644000175100001660000000337614760300421021335 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): write concern options (wtimeoutms) --FILE-- 1000]], [null, ['w' => 2, 'wtimeoutms' => 1000]], [null, ['w' => 'majority', 'wtimeoutms' => 1000]], [null, ['w' => 'customTagSet', 'wtimeoutms' => 1000]], ]; foreach ($tests as $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getWriteConcern()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["wtimeout"]=> %rint\(4294967296\)|string\(10\) "4294967296"%r } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(12) "customTagSet" ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(12) "customTagSet" ["wtimeout"]=> int(1000) } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-003.phpt0000644000175100001660000000141614760300421021327 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): write concern options (journal) --FILE-- true]], [null, ['journal' => false]], ]; foreach ($tests as $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getWriteConcern()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["j"]=> bool(true) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["j"]=> bool(false) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["j"]=> bool(true) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["j"]=> bool(false) } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-004.phpt0000644000175100001660000000301714760300421021327 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): write concern options (safe) --FILE-- true]], [null, ['safe' => false]], [null, ['w' => 1, 'safe' => false]], [null, ['w' => 0, 'safe' => true]], // safe in URI options array may override w in URI string ['mongodb://127.0.0.1/?w=0', ['safe' => true]], ['mongodb://127.0.0.1/?w=1', ['safe' => false]], ]; foreach ($tests as $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getWriteConcern()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-005.phpt0000644000175100001660000000162114760300421021327 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): write concern options (64-bit wtimeoutms) --FILE-- getWriteConcern()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> %rint\(4294967296\)|string\(10\) "4294967296"%r } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" ["wtimeout"]=> %rint\(4294967296\)|string\(10\) "4294967296"%r } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(12) "customTagSet" ["wtimeout"]=> %rint\(4294967296\)|string\(10\) "4294967296"%r } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-006.phpt0000644000175100001660000000166314760300421021336 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): write concern options (64-bit wtimeoutms) --SKIPIF-- --FILE-- 2, 'wtimeoutms' => 4294967296]], [null, ['w' => 'majority', 'wtimeoutms' => 4294967296]], [null, ['w' => 'customTagSet', 'wtimeoutms' => 4294967296]], ]; foreach ($tests as $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getWriteConcern()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> int(4294967296) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" ["wtimeout"]=> int(4294967296) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(12) "customTagSet" ["wtimeout"]=> int(4294967296) } ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-error-001.phpt0000644000175100001660000000175714760300421022464 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid write concern (w) --FILE-- 1.0]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; /* Note: Values of w < -1 are invalid, but libmongoc's URI string parsing only * logs a warning instead of raising an error (see: CDRIVER-2234), so we cannot * test for this. */ echo throws(function() { create_test_manager(null, ['w' => -2]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer or string for "w" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Unsupported w value: -2 ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-error-002.phpt0000644000175100001660000000124114760300421022451 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid write concern (w range) --SKIPIF-- --FILE-- 2147483648]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer or string for "w" URI option, 64-bit integer given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-error-003.phpt0000644000175100001660000000144114760300421022454 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid write concern (wtimeoutms) --FILE-- 'invalid']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?wtimeoutms=invalid'. Unsupported value for "wtimeoutms": "invalid". OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected integer for "wTimeoutMS" URI option, string given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-error-005.phpt0000644000175100001660000000604714760300421022465 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid write concern (journal) --FILE-- 'invalid']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; // Invalid values (journal conflicts with unacknowledged write concerns) echo throws(function() { create_test_manager('mongodb://127.0.0.1/?w=-1&journal=true'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://127.0.0.1/?w=0&journal=true'); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://127.0.0.1/?w=-1', ['journal' => true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://127.0.0.1/?w=0', ['journal' => true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://127.0.0.1/?journal=true', ['w' => -1]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager('mongodb://127.0.0.1/?journal=true', ['w' => 0]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['w' => -1, 'journal' => true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() { create_test_manager(null, ['w' => 0, 'journal' => true]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?journal=invalid'. Unsupported value for "journal": "invalid". OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected boolean for "journal" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?w=-1&journal=true'. Error while parsing the 'w' URI option: Journal conflicts with w value [w=-1]. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?w=0&journal=true'. Error while parsing the 'w' URI option: Journal conflicts with w value [w=0]. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Journal conflicts with w value: -1 OK: Got MongoDB\Driver\Exception\InvalidArgumentException Journal conflicts with w value: 0 OK: Got MongoDB\Driver\Exception\InvalidArgumentException Journal conflicts with w value: -1 OK: Got MongoDB\Driver\Exception\InvalidArgumentException Journal conflicts with w value: 0 OK: Got MongoDB\Driver\Exception\InvalidArgumentException Journal conflicts with w value: -1 OK: Got MongoDB\Driver\Exception\InvalidArgumentException Journal conflicts with w value: 0 ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-error-006.phpt0000644000175100001660000000141614760300421022461 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid write concern (safe) --FILE-- 'invalid']); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://127.0.0.1/?safe=invalid'. Unsupported value for "safe": "invalid". OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected boolean for "safe" URI option, string given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor-write_concern-error-007.phpt0000644000175100001660000000102514760300421022456 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid write concern (wtimeoutms range) --SKIPIF-- --FILE-- -1]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected wtimeoutMS to be >= 0, -1 given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor_error-001.phpt0000644000175100001660000000113014760300421017670 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): too many arguments --SKIPIF-- =', '7.99'); ?> --FILE-- ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Manager::__construct() expects at most 3 %r(argument|parameter)%rs, 4 given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor_error-002.phpt0000644000175100001660000000100714760300421017674 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid URI --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'not a valid connection string'. Invalid URI Schema, expecting 'mongodb://' or 'mongodb+srv://'. ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor_error-003.phpt0000644000175100001660000003075414760300421017710 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): invalid types in URI options arrays --FILE-- 1], ]; foreach ($integerOptions as $option) { foreach ($invalidIntegerValues as $value) { echo throws(function() use ($option, $value) { create_test_manager(null, [$option => $value]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; } } echo "\nTesting string options:\n"; $stringOptions = [ 'appname', 'authMechanism', 'authSource', 'gssapiServiceName', 'password', 'replicaSet', 'username', ]; $invalidStringValues = [ true, 1.0, 42, new MongoDB\BSON\ObjectId, [ 1, 2, 3 ], ['x' => 1], ]; foreach ($stringOptions as $option) { foreach ($invalidStringValues as $value) { echo throws(function() use ($option, $value) { create_test_manager(null, [$option => $value]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; } } echo "\nTesting document options:\n"; $invalidDocumentValues = [ true, 1.0, 42, 'string', new MongoDB\BSON\ObjectId, [ 1, 2, 3 ], ]; foreach ($invalidDocumentValues as $value) { echo throws(function() use ($value) { create_test_manager(null, ['authMechanismProperties' => $value]); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; } ?> ===DONE=== --EXPECT-- Testing 32-bit integer options: OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "connectTimeoutMS" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "connectTimeoutMS" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "connectTimeoutMS" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "connectTimeoutMS" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "connectTimeoutMS" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "connectTimeoutMS" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "heartbeatFrequencyMS" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "heartbeatFrequencyMS" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "heartbeatFrequencyMS" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "heartbeatFrequencyMS" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "heartbeatFrequencyMS" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "heartbeatFrequencyMS" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "localThresholdMS" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "localThresholdMS" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "localThresholdMS" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "localThresholdMS" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "localThresholdMS" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "localThresholdMS" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "serverSelectionTimeoutMS" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "serverSelectionTimeoutMS" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "serverSelectionTimeoutMS" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "serverSelectionTimeoutMS" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "serverSelectionTimeoutMS" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "serverSelectionTimeoutMS" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketCheckIntervalMS" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketCheckIntervalMS" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketCheckIntervalMS" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketCheckIntervalMS" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketCheckIntervalMS" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketCheckIntervalMS" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketTimeoutMS" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketTimeoutMS" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketTimeoutMS" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketTimeoutMS" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketTimeoutMS" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected 32-bit integer for "socketTimeoutMS" URI option, document given Testing string options: OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "appname" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "appname" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "appname" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "appname" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "appname" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "appname" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authMechanism" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authMechanism" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authMechanism" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authMechanism" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authMechanism" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authMechanism" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authSource" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authSource" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authSource" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authSource" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authSource" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "authSource" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "gssapiServiceName" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "gssapiServiceName" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "gssapiServiceName" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "gssapiServiceName" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "gssapiServiceName" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "gssapiServiceName" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "password" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "password" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "password" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "password" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "password" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "password" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "replicaSet" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "replicaSet" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "replicaSet" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "replicaSet" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "replicaSet" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "replicaSet" URI option, document given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "username" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "username" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "username" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "username" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "username" URI option, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected string for "username" URI option, document given Testing document options: OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected array or object for "authMechanismProperties" URI option, boolean given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected array or object for "authMechanismProperties" URI option, double given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected array or object for "authMechanismProperties" URI option, 32-bit integer given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected array or object for "authMechanismProperties" URI option, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected array or object for "authMechanismProperties" URI option, ObjectId given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected array or object for "authMechanismProperties" URI option, array given ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor_error-004.phpt0000644000175100001660000000171414760300421017703 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): empty replicaSet argument --FILE-- executeQuery(NS, new MongoDB\Driver\Query([])); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function () { $manager = create_test_manager('mongodb://localhost:27017', ['replicaSet' => '']); $manager->executeQuery(NS, new MongoDB\Driver\Query([])); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Failed to parse MongoDB URI: 'mongodb://localhost:27017/?replicaSet='. Value for URI option "replicaset" cannot be empty string. OK: Got MongoDB\Driver\Exception\InvalidArgumentException Value for URI option "replicaSet" cannot be empty string. ===DONE=== mongodb-1.21.0/tests/manager/manager-ctor_error-005.phpt0000644000175100001660000000214614760300421017704 0ustar --TEST-- MongoDB\Driver\Manager::__construct(): Invalid handshake data --FILE-- []], ['version' => []], ['platform' => []], ]; foreach ($tests as $driver) { echo throws(function () use ($driver) { $manager = create_test_manager(null, [], ['driver' => $driver]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "driver" driver option to be an array, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "driver" driver option to be an array, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "name" handshake option to be a string, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "version" handshake option to be a string, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "platform" handshake option to be a string, array given ===DONE=== mongodb-1.21.0/tests/manager/manager-debug-001.phpt0000644000175100001660000000111314760300421016577 0ustar --TEST-- MongoDB\Driver\Manager: Writing debug log files --FILE-- ===DONE=== --EXPECTF-- %A[%s] PHONGO: DEBUG > Connection string: '%s' [%s] PHONGO: DEBUG > Creating Manager, phongo-1.%d.%d%S[%s] - mongoc-1.%s(%s), libbson-1.%s(%s), php-%s %A===DONE===%A mongodb-1.21.0/tests/manager/manager-debug-002.phpt0000644000175100001660000000061114760300421016602 0ustar --TEST-- MongoDB\Driver\Manager: mongodb.debug=stderr (connection string and version) --INI-- mongodb.debug=stderr --FILE-- ===DONE=== --EXPECTF-- %A[%s] PHONGO: DEBUG > Connection string: '%s' [%s] PHONGO: DEBUG > Creating Manager, phongo-1.%d.%d%S[%s] - mongoc-1.%s(%s), libbson-1.%s(%s), php-%s %A===DONE===%A mongodb-1.21.0/tests/manager/manager-debug-003.phpt0000644000175100001660000000041314760300421016603 0ustar --TEST-- MongoDB\Driver\Manager: mongodb.debug=stderr (date format) --INI-- mongodb.debug=stderr --FILE-- ===DONE=== --EXPECTF-- [%r(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{6}\+00:00)%r]%A ===DONE===%A mongodb-1.21.0/tests/manager/manager-destruct-001.phpt0000644000175100001660000000204314760300421017351 0ustar --TEST-- MongoDB\Driver\Manager destruct should not free streams that are still in use --SKIPIF-- --INI-- ignore_repeated_errors=1 --FILE-- insert(array('_id' => 1)); $writeResult = $manager1->executeBulkWrite(NS, $bulk); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 2)); $writeResult = $manager2->executeBulkWrite(NS, $bulk); printf("Inserted: %d\n", $writeResult->getInsertedCount()); $manager2 = null; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 3)); $writeResult = $manager1->executeBulkWrite(NS, $bulk); printf("Inserted: %d\n", $writeResult->getInsertedCount()); ?> ===DONE=== --EXPECT-- Inserted: 1 Inserted: 1 Inserted: 1 ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-001.phpt0000644000175100001660000000244314760300421021013 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 2)); $bulk->update(array('x' => 2), array('$set' => array('x' => 1)), array("limit" => 1, "upsert" => false)); $bulk->update(array('_id' => 3), array('$set' => array('x' => 3)), array("limit" => 1, "upsert" => true)); $bulk->delete(array('x' => 1), array("limit" => 1)); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 2 matchedCount: 1 modifiedCount: 1 upsertedCount: 1 deletedCount: 1 upsertedId[3]: int(3) ===> Collection array(2) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(1) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(3) ["x"]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-002.phpt0000644000175100001660000000312314760300421021010 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() with upserted ids --SKIPIF-- --FILE-- false]); $bulk->update(array('x' => 'foo'), array('$set' => array('y' => 'foo')), array('upsert' => true)); $bulk->update(array('x' => 'bar'), array('$set' => array('y' => 'bar')), array('upsert' => true)); $bulk->update(array('x' => 'foo'), array('$set' => array('y' => 'bar'))); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 1 modifiedCount: 1 upsertedCount: 2 deletedCount: 0 upsertedId[0]: object(%s\ObjectId)#%d (%d) { ["oid"]=> string(24) "%s" } upsertedId[1]: object(%s\ObjectId)#%d (%d) { ["oid"]=> string(24) "%s" } ===> Collection array(2) { [0]=> object(stdClass)#%d (3) { ["_id"]=> object(%s\ObjectId)#%d (%d) { ["oid"]=> string(24) "%s" } ["x"]=> string(3) "foo" ["y"]=> string(3) "bar" } [1]=> object(stdClass)#%d (3) { ["_id"]=> object(%s\ObjectId)#%d (%d) { ["oid"]=> string(24) "%s" } ["x"]=> string(3) "bar" ["y"]=> string(3) "bar" } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-003.phpt0000644000175100001660000000213514760300421021013 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() delete one document --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->delete(array('x' => 1), array('limit' => 1)); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 1 ===> Collection array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-004.phpt0000644000175100001660000000201414760300421021010 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() delete multiple documents --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->delete(array('x' => 1), array('limit' => 0)); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 2 ===> Collection array(0) { } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-005.phpt0000644000175100001660000000162214760300421021015 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() insert one document --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 1 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 0 ===> Collection array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-006.phpt0000644000175100001660000000367514760300421021030 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() insert one document (with embedded) --SKIPIF-- --FILE-- addAddress($sunnyvale); $hannes->addAddress($kopavogur); $mikola = new Person("Jeremy", 21); $michigan = new Address(48169, "USA"); $hannes->addFriend($mikola); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert($hannes); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); foreach($cursor as $object) { var_dump($object); } ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 1 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 0 ===> Collection object(Person)#%d (5) { ["name":protected]=> string(6) "Hannes" ["age":protected]=> int(42) ["addresses":protected]=> array(2) { [0]=> object(Address)#%d (2) { ["zip":protected]=> int(94086) ["country":protected]=> string(3) "USA" } [1]=> object(Address)#%d (2) { ["zip":protected]=> int(200) ["country":protected]=> string(7) "Iceland" } } ["friends":protected]=> array(1) { [0]=> object(Person)#%d (5) { ["name":protected]=> string(6) "Jeremy" ["age":protected]=> int(21) ["addresses":protected]=> array(0) { } ["friends":protected]=> array(0) { } ["secret":protected]=> string(4) "none" } } ["secret":protected]=> string(4) "none" } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-007.phpt0000644000175100001660000000221114760300421021012 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() update one document with no upsert --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update( array('_id' => 1), array('$set' => array('x' => 2)), array('multi' => false, 'upsert' => false) ); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 1 modifiedCount: 1 upsertedCount: 0 deletedCount: 0 ===> Collection array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(2) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-008.phpt0000644000175100001660000000262414760300421021023 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() update multiple documents with no upsert --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $bulk->insert(array('_id' => 3, 'x' => 3)); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update( array('x' => 1), array('$set' => array('x' => 2)), array('multi' => true, 'upsert' => false) ); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 2 modifiedCount: 2 upsertedCount: 0 deletedCount: 0 ===> Collection array(3) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(2) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(2) } [2]=> object(stdClass)#%d (2) { ["_id"]=> int(3) ["x"]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-009.phpt0000644000175100001660000000200514760300421021015 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() update one document with upsert --SKIPIF-- --FILE-- update( array('_id' => 1), array('$set' => array('x' => 1)), array('multi' => false, 'upsert' => true) ); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 0 modifiedCount: 0 upsertedCount: 1 deletedCount: 0 upsertedId[0]: int(1) ===> Collection array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-010.phpt0000644000175100001660000000201214760300421021003 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() update multiple documents with upsert --SKIPIF-- --FILE-- update( array('_id' => 1), array('$set' => array('x' => 1)), array('multi' => true, 'upsert' => true) ); $result = $manager->executeBulkWrite(NS, $bulk); echo "\n===> WriteResult\n"; printWriteResult($result); echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 0 modifiedCount: 0 upsertedCount: 1 deletedCount: 0 upsertedId[0]: int(1) ===> Collection array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-011.phpt0000644000175100001660000000420714760300421021014 0ustar --TEST-- MongoDB\Driver\BulkWrite: bypassDocumentValidation option --SKIPIF-- --FILE-- COLLECTION_NAME, 'validator' => ['x' => ['$type' => 'number']], ]); $manager->executeCommand(DATABASE_NAME, $command); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1, 'x' => 1]); $bulk->insert(['_id' => 2, 'x' => 2]); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(['bypassDocumentValidation' => true]); $bulk->update(['_id' => 2], ['$set' => ['x' => 'two']]); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(['bypassDocumentValidation' => true]); $bulk->insert(['_id' => 3, 'x' => 'three']); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 4, 'x' => 'four']); echo throws(function() use($manager, $bulk) { $manager->executeBulkWrite(NS, $bulk); }, "MongoDB\Driver\Exception\BulkWriteException"), "\n"; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update(['_id' => 1], ['$set' => ['x' => 'one']]); echo throws(function() use($manager, $bulk) { $manager->executeBulkWrite(NS, $bulk); }, "MongoDB\Driver\Exception\BulkWriteException"), "\n"; $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update(['_id' => 2], ['$set' => ['x' => 2]]); $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\BulkWriteException Document failed validation OK: Got MongoDB\Driver\Exception\BulkWriteException %SDocument failed validation array(3) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(1) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(2) } [2]=> object(stdClass)#%d (2) { ["_id"]=> int(3) ["x"]=> string(5) "three" } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-012.phpt0000644000175100001660000000215314760300421021013 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() with legacy write concern (replica set primary) --SKIPIF-- --FILE-- insert(['wc' => $wc]); $options = [ 'writeConcern' => new MongoDB\Driver\WriteConcern($wc), ]; $result = $manager->executeBulkWrite(NS, $bulk, $options); var_dump($result->isAcknowledged()); var_dump($result->getInsertedCount()); } ?> ===DONE=== --EXPECTF-- bool(false) Deprecated: MongoDB\Driver\WriteResult::getInsertedCount(): Calling MongoDB\Driver\WriteResult::getInsertedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL bool(true) int(1) bool(true) int(1) bool(true) int(1) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-013.phpt0000644000175100001660000000307614760300421021021 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $pinnedServer = $session->getServer(); var_dump($pinnedServer instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $session->commitTransaction(); var_dump($session->getServer() == $pinnedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(true) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-014.phpt0000644000175100001660000000177214760300421021023 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() write concern inheritance --SKIPIF-- --FILE-- 2, 'wtimeoutms' => 1000]); (new CommandObserver)->observe( function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(1)]); }, function(stdClass $command) { echo json_encode($command->writeConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"w":2,"wtimeout":1000} {"w":1} ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite-015.phpt0000644000175100001660000000124414760300421021016 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() explicit WriteConcern argument is deprecated --SKIPIF-- --FILE-- insert(['_id' => 1]); $manager->executeBulkWrite(NS, $bulk, new MongoDB\Driver\WriteConcern(0)); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::executeBulkWrite(): Passing the "writeConcern" option directly is deprecated and will be removed in ext-mongodb 2.0%s ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-001.phpt0000644000175100001660000000275314760300421022230 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() with duplicate key errors (ordered) --SKIPIF-- --FILE-- true]); $bulk->insert(array('_id' => 1)); $bulk->insert(array('_id' => 1)); $bulk->insert(array('_id' => 2)); $bulk->insert(array('_id' => 2)); try { $result = $manager->executeBulkWrite(NS, $bulk); echo "FAILED\n"; } catch (MongoDB\Driver\Exception\BulkWriteException $e) { printf("BulkWriteException: %s\n", $e->getMessage()); echo "\n===> WriteResult\n"; printWriteResult($e->getWriteResult()); } echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- BulkWriteException:%S E11000 duplicate key error %s: phongo.manager_manager_executeBulkWrite_error_001%sdup key: { %S: 1 } ===> WriteResult server: %s:%d insertedCount: 1 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 0 object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "%s" ["code"]=> int(11000) ["index"]=> int(1) ["info"]=> NULL } writeError[1].message: %s writeError[1].code: 11000 ===> Collection array(1) { [0]=> object(stdClass)#%d (1) { ["_id"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-002.phpt0000644000175100001660000000357314760300421022232 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() with duplicate key errors (unordered) --SKIPIF-- --FILE-- false]); $bulk->insert(array('_id' => 1)); $bulk->insert(array('_id' => 1)); $bulk->insert(array('_id' => 2)); $bulk->insert(array('_id' => 2)); try { $result = $manager->executeBulkWrite(NS, $bulk); echo "FAILED\n"; } catch (MongoDB\Driver\Exception\BulkWriteException $e) { printf("BulkWriteException: %s\n", $e->getMessage()); echo "\n===> WriteResult\n"; printWriteResult($e->getWriteResult()); } echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- BulkWriteException: Multiple write errors: "%SE11000 duplicate key error %s: phongo.manager_manager_executeBulkWrite_error_002%sdup key: { %S: 1 }", "%SE11000 duplicate key error %s: phongo.manager_manager_executeBulkWrite_error_002%sdup key: { %S: 2 }" ===> WriteResult server: %s:%d insertedCount: 2 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 0 object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "%s" ["code"]=> int(11000) ["index"]=> int(1) ["info"]=> NULL } writeError[1].message: %s writeError[1].code: 11000 object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "%s" ["code"]=> int(11000) ["index"]=> int(3) ["info"]=> NULL } writeError[3].message: %s writeError[3].code: 11000 ===> Collection array(2) { [0]=> object(stdClass)#%d (1) { ["_id"]=> int(1) } [1]=> object(stdClass)#%d (1) { ["_id"]=> int(2) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-003.phpt0000644000175100001660000000263714760300421022233 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() write concern error --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); try { $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(30)]); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { printf("BulkWriteException: %s\n", $e->getMessage()); echo "\n===> WriteResult\n"; printWriteResult($e->getWriteResult()); } echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- BulkWriteException: Not enough data-bearing nodes ===> WriteResult server: %s:%d insertedCount: 1 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 0 object(MongoDB\Driver\WriteConcernError)#%d (%d) { ["message"]=> string(29) "Not enough data-bearing nodes" ["code"]=> int(100) ["info"]=> %a } writeConcernError.message: Not enough data-bearing nodes writeConcernError.code: 100 writeConcernError.info: %a ===> Collection array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-004.phpt0000644000175100001660000000301114760300421022217 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() delete write error --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->delete(['field' => ['$unsupportedOperator' => true]], ['limit' => 1]); try { $manager->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { printf("BulkWriteException: %s\n", $e->getMessage()); echo "\n===> WriteResult\n"; printWriteResult($e->getWriteResult()); } echo "\n===> Collection\n"; $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- BulkWriteException: unknown operator: $unsupportedOperator ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 0 object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(38) "unknown operator: $unsupportedOperator" ["code"]=> int(2) ["index"]=> int(0) ["info"]=> NULL } writeError[0].message: unknown operator: $unsupportedOperator writeError[0].code: 2 ===> Collection array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-005.phpt0000644000175100001660000000372614760300421022235 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() WriteResult accessible for network error --SKIPIF-- --FILE-- selectServer(new \MongoDB\Driver\ReadPreference('primary')); configureTargetedFailPoint($server, 'failCommand', [ 'times' => 1 ], [ 'failCommands' => ['delete'], 'closeConnection' => true, ]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 1]]); $bulk->delete(['x' => 1]); try { $server->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { printf("%s(%d): %s\n", get_class($e), $e->getCode(), $e->getMessage()); $prev = $e->getPrevious(); printf("%s(%d): %s\n", get_class($prev), $prev->getCode(), $prev->getMessage()); var_dump($e->getWriteResult()); } ?> ===DONE=== --EXPECTF-- MongoDB\Driver\Exception\BulkWriteException(0): Bulk write failed due to previous MongoDB\Driver\Exception\ConnectionTimeoutException: Failed to send "delete" command with database "%s": Failed to read 4 bytes: socket error or timeout MongoDB\Driver\Exception\ConnectionTimeoutException(%d): Failed to send "delete" command with database "%s": Failed to read 4 bytes: socket error or timeout object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> int(1) ["nMatched"]=> int(1) ["nModified"]=> int(1) ["nRemoved"]=> int(0) ["nUpserted"]=> int(0) ["upsertedIds"]=> array(0) { } ["writeErrors"]=> array(0) { } ["writeConcernError"]=> NULL ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { } ["errorReplies"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-006.phpt0000644000175100001660000000224514760300421022231 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() update write error --SKIPIF-- --FILE-- insert(array('x' => 1)); $manager->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->update(['x' => 1], ['$foo' => 1]); try { $manager->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { printf("BulkWriteException: %s\n", $e->getMessage()); echo "\n===> WriteResult\n"; printWriteResult($e->getWriteResult()); } ?> ===DONE=== --EXPECTF-- BulkWriteException: Unknown modifier: $foo%S ===> WriteResult server: %s:%d insertedCount: 0 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 0 object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "Unknown modifier: $foo%S" ["code"]=> int(9) ["index"]=> int(0) ["info"]=> NULL } writeError[0].message: Unknown modifier: $foo%S writeError[0].code: 9 ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-007.phpt0000644000175100001660000000221514760300421022227 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() should not issue warning before exception --FILE-- 1]); echo throws(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; // Valid host refuses connection $manager = create_test_manager('mongodb://localhost:54321', ['serverSelectionTimeoutMS' => 1]); echo throws(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-008.phpt0000644000175100001660000000114214760300421022226 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() with empty BulkWrite --SKIPIF-- --FILE-- executeBulkWrite(NS, new MongoDB\Driver\BulkWrite); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot do an empty bulk write ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-009.phpt0000644000175100001660000000347614760300421022243 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() with invalid options --SKIPIF-- --FILE-- insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-010.phpt0000644000175100001660000000242014760300421022217 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() cannot combine session with unacknowledged write concern --SKIPIF-- --FILE-- insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, [ 'session' => $manager->startSession(), 'writeConcern' => new MongoDB\Driver\WriteConcern(0), ]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { $manager = create_test_manager(URI, ['w' => 0]); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, [ 'session' => $manager->startSession(), ]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot combine "session" option with an unacknowledged write concern OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot combine "session" option with an unacknowledged write concern ===DONE=== mongodb-1.21.0/tests/manager/manager-executeBulkWrite_error-011.phpt0000644000175100001660000000422614760300421022226 0ustar --TEST-- MongoDB\Driver\Manager::executeBulkWrite() BulkWriteException inherits labels from previous exception --SKIPIF-- --FILE-- selectServer(new \MongoDB\Driver\ReadPreference('primary')); // Create collection since it can't be (automatically) done within the transaction $majority = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY); $server->executeWriteCommand( DATABASE_NAME, new MongoDB\Driver\Command(['create' => COLLECTION_NAME]), ['writeConcern' => $majority] ); configureTargetedFailPoint($server, 'failCommand', [ 'times' => 1 ], [ 'failCommands' => ['insert'], 'closeConnection' => true, ]); $session = $manager->startSession(); $session->startTransaction(); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); try { $server->executeBulkWrite(NS, $bulk, ['session' => $session]); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { printf("%s(%d): %s\n", get_class($e), $e->getCode(), $e->getMessage()); var_dump($e->hasErrorLabel('TransientTransactionError')); $prev = $e->getPrevious(); printf("%s(%d): %s\n", get_class($prev), $prev->getCode(), $prev->getMessage()); var_dump($prev->hasErrorLabel('TransientTransactionError')); } ?> ===DONE=== --EXPECTF-- MongoDB\Driver\Exception\BulkWriteException(0): Bulk write failed due to previous MongoDB\Driver\Exception\ConnectionTimeoutException: Failed to send "insert" command with database "%s": Failed to read 4 bytes: socket error or timeout bool(true) MongoDB\Driver\Exception\ConnectionTimeoutException(%d): Failed to send "insert" command with database "%s": Failed to read 4 bytes: socket error or timeout bool(true) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand-001.phpt0000644000175100001660000000272714760300421020466 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() --SKIPIF-- --FILE-- 1)); $result = $manager->executeCommand(DATABASE_NAME, $command); var_dump($command); var_dump($result instanceof MongoDB\Driver\Cursor); var_dump($result); echo "\nDumping response document:\n"; var_dump(current($result->toArray())); $server = $result->getServer(); var_dump($server instanceof MongoDB\Driver\Server); var_dump($server->getHost()); var_dump($server->getPort()); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Command)#%d (%d) { ["command"]=> object(stdClass)#%d (1) { ["ping"]=> int(1) } } bool(true) object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> NULL ["query"]=> NULL ["command"]=> object(MongoDB\Driver\Command)#%d (%d) { ["command"]=> object(stdClass)#%d (%d) { ["ping"]=> int(1) } } ["readPreference"]=> NULL ["session"]=> %a ["isDead"]=> bool(false) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } Dumping response document: object(stdClass)#%d (%d) { ["ok"]=> float(1)%A } bool(true) string(%d) "%s" int(%d) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand-002.phpt0000644000175100001660000000256014760300421020462 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() takes a read preference in options array --SKIPIF-- --FILE-- 1]); $cursor = $manager->executeCommand(DATABASE_NAME, $command, ['readPreference' => $primary]); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; echo "Testing secondary:\n"; $command = new MongoDB\Driver\Command(['ping' => 1]); $cursor = $manager->executeCommand(DATABASE_NAME, $command, ['readPreference' => $secondary]); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- Testing primary: is_primary: true is_secondary: false Testing secondary: is_primary: false is_secondary: true ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand-003.phpt0000644000175100001660000000317214760300421020463 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() takes a read preference as legacy option --SKIPIF-- --FILE-- 1]); $cursor = $manager->executeCommand(DATABASE_NAME, $command, $primary); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; echo "Testing secondary:\n"; $command = new MongoDB\Driver\Command(['ping' => 1]); $cursor = $manager->executeCommand(DATABASE_NAME, $command, $secondary); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- Testing primary: Deprecated: MongoDB\Driver\Manager::executeCommand(): Passing the "readPreference" option directly is deprecated and will be removed in ext-mongodb 2.0%s is_primary: true is_secondary: false Testing secondary: Deprecated: MongoDB\Driver\Manager::executeCommand(): Passing the "readPreference" option directly is deprecated and will be removed in ext-mongodb 2.0%s is_primary: false is_secondary: true ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand-004.phpt0000644000175100001660000000304114760300421020457 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() options (MONGOC_CMD_RAW) --SKIPIF-- --FILE-- observe( function() use ($manager) { $command = new MongoDB\Driver\Command([ 'ping' => true, ]); try { $manager->executeCommand( DATABASE_NAME, $command, [ 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::SECONDARY), 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::LOCAL), 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY), ] ); } catch ( Exception $e ) { // Ignore exception that ping doesn't support writeConcern } }, function(stdClass $command) { echo "Read Preference: ", $command->{'$readPreference'}->mode, "\n"; echo "Read Concern: ", $command->readConcern->level, "\n"; echo "Write Concern: ", $command->writeConcern->w, "\n"; } ); ?> ===DONE=== --EXPECTF-- Read Preference: secondary Read Concern: local Write Concern: majority ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand-005.phpt0000644000175100001660000000324114760300421020462 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [] ]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); $pinnedServer = $session->getServer(); var_dump($pinnedServer instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $session->commitTransaction(); var_dump($session->getServer() == $pinnedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(true) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand-006.phpt0000644000175100001660000000137214760300421020466 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() does not inherit read preference --SKIPIF-- --FILE-- 'secondary']); $command = new MongoDB\Driver\Command(['ping' => 1]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- is_primary: true is_secondary: false ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand-007.phpt0000644000175100001660000000251014760300421020462 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() does not inherit read or write concern --SKIPIF-- --FILE-- 'local', 'w' => 2, 'wtimeoutms' => 1000]); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$group' => ['_id' => 1]], ['$out' => COLLECTION_NAME . '.out'], ], 'cursor' => (object) [], ]); (new CommandObserver)->observe( function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); $manager->executeCommand(DATABASE_NAME, $command, [ 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::AVAILABLE), 'writeConcern' => new MongoDB\Driver\WriteConcern(1), ]); }, function(stdClass $command) { echo json_encode($command->readConcern ?? null), "\n"; echo json_encode($command->writeConcern ?? null), "\n"; } ); ?> ===DONE=== --EXPECT-- null null {"level":"available"} {"w":1} ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand_error-001.phpt0000644000175100001660000000213414760300421021667 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() should not issue warning before exception --FILE-- 1]); // Invalid host cannot be resolved $manager = create_test_manager('mongodb://example.invalid:27017', ['serverSelectionTimeoutMS' => 1]); echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; // Valid host refuses connection $manager = create_test_manager('mongodb://localhost:54321', ['serverSelectionTimeoutMS' => 1]); echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand_error-002.phpt0000644000175100001660000000604014760300421021670 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() with invalid options (MONGOC_CMD_RAW) --SKIPIF-- --FILE-- 1]); echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command, ['readConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command, ['readConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command, ['readPreference' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command, ['readPreference' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command, ['writeConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command, ['writeConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand_error-003.phpt0000644000175100001660000000114614760300421021673 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() connection error --FILE-- 1]); echo throws(function() use($manager, $command) { $manager->executeCommand('test', $command); }, "MongoDB\Driver\Exception\ConnectionTimeoutException"), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand_error-004.phpt0000644000175100001660000000115314760300421021672 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() with empty command document --SKIPIF-- --FILE-- executeCommand(DATABASE_NAME, $command); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Empty command document ===DONE=== mongodb-1.21.0/tests/manager/manager-executeCommand_error-005.phpt0000644000175100001660000000162014760300421021672 0ustar --TEST-- MongoDB\Driver\Manager::executeCommand() cannot combine session with unacknowledged write concern --SKIPIF-- --FILE-- COLLECTION_NAME, 'documents' => [['x' => 1]], ]); $manager->executeCommand(DATABASE_NAME, $command, [ 'session' => $manager->startSession(), 'writeConcern' => new MongoDB\Driver\WriteConcern(0), ]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot combine "session" option with an unacknowledged write concern ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery-002.phpt0000644000175100001660000000345114760300421020211 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() one document --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 2, 'y' => 3)); $bulk->insert(array('_id' => 2, 'x' => 3, 'y' => 4)); $bulk->insert(array('_id' => 3, 'x' => 4, 'y' => 5)); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(array('x' => 3), array('projection' => array('y' => 1))); $qr = $manager->executeQuery(NS, $query); var_dump($qr instanceof MongoDB\Driver\Cursor); var_dump($qr); $server = $qr->getServer(); var_dump($server instanceof MongoDB\Driver\Server); var_dump($server->getHost()); var_dump($server->getPort()); var_dump(iterator_to_array($qr)); ?> ===DONE=== --EXPECTF-- bool(true) object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> string(32) "manager_manager_executeQuery_002" ["query"]=> object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(3) } ["options"]=> object(stdClass)#%d (%d) { ["projection"]=> object(stdClass)#%d (%d) { ["y"]=> int(1) } } ["readConcern"]=> NULL } ["command"]=> NULL ["readPreference"]=> NULL ["session"]=> NULL ["isDead"]=> bool(false) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } bool(true) string(%d) "%s" int(%d) array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["y"]=> int(4) } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery-003.phpt0000644000175100001660000000303114760300421020204 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() takes a read preference in options array --SKIPIF-- --FILE-- insert(['_id' => 1, 'x' => 2, 'y' => 3]); $manager->executeBulkWrite(NS, $bulk); $primary = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY); $secondary = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY); echo "Testing primary:\n"; $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $manager->executeQuery(NS, $query, ['readPreference' => $primary]); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; echo "Testing secondary:\n"; $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $manager->executeQuery(NS, $query, ['readPreference' => $secondary]); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- Testing primary: is_primary: true is_secondary: false Testing secondary: is_primary: false is_secondary: true ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery-004.phpt0000644000175100001660000000343714760300421020217 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() takes a read preference as legacy option --SKIPIF-- --FILE-- insert(['_id' => 1, 'x' => 2, 'y' => 3]); $manager->executeBulkWrite(NS, $bulk); $primary = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY); $secondary = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY); echo "Testing primary:\n"; $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $manager->executeQuery(NS, $query, $primary); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; echo "Testing secondary:\n"; $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $manager->executeQuery(NS, $query, $secondary); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- Testing primary: Deprecated: MongoDB\Driver\Manager::executeQuery(): Passing the "readPreference" option directly is deprecated and will be removed in ext-mongodb 2.0%s is_primary: true is_secondary: false Testing secondary: Deprecated: MongoDB\Driver\Manager::executeQuery(): Passing the "readPreference" option directly is deprecated and will be removed in ext-mongodb 2.0%s is_primary: false is_secondary: true ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery-005.phpt0000644000175100001660000000332314760300421020212 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() with filter and projection --SKIPIF-- --FILE-- insert(array('_id' => 1, array('x' => 2, 'y' => 3))); $bulk->insert(array('_id' => 2, array('x' => 3, 'y' => 4))); $bulk->insert(array('_id' => 3, array('x' => 4, 'y' => 5))); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(array()); $qr = $manager->executeQuery(NS, $query); $qr->setTypeMap(array("root"=> "MyArrayObject", "document"=> "MyArrayObject", "array" => "MyArrayObject")); foreach($qr as $obj) { var_dump($obj); } ?> ===DONE=== --EXPECTF-- object(MyArrayObject)#%d (1) { [%s]=> array(2) { ["_id"]=> int(1) [0]=> object(MyArrayObject)#%d (1) { [%s]=> array(2) { ["x"]=> int(2) ["y"]=> int(3) } } } } object(MyArrayObject)#%d (1) { [%s]=> array(2) { ["_id"]=> int(2) [0]=> object(MyArrayObject)#%d (1) { [%s]=> array(2) { ["x"]=> int(3) ["y"]=> int(4) } } } } object(MyArrayObject)#%d (1) { [%s]=> array(2) { ["_id"]=> int(3) [0]=> object(MyArrayObject)#%d (1) { [%s]=> array(2) { ["x"]=> int(4) ["y"]=> int(5) } } } } ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery-006.phpt0000644000175100001660000000303314760300421020211 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); $pinnedServer = $session->getServer(); var_dump($pinnedServer instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $session->commitTransaction(); var_dump($session->getServer() == $pinnedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(true) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery-007.phpt0000644000175100001660000000160214760300421020212 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() read concern inheritance --SKIPIF-- --FILE-- 'local']); (new CommandObserver)->observe( function() use ($manager) { $manager->executeQuery(NS, new MongoDB\Driver\Query([])); $manager->executeQuery(NS, new MongoDB\Driver\Query([], [ 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::AVAILABLE), ])); }, function(stdClass $command) { echo json_encode($command->readConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"level":"local"} {"level":"available"} ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery_error-001.phpt0000644000175100001660000000205114760300421021414 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() should not issue warning before exception --FILE-- 1]); echo throws(function() use ($manager, $query) { $manager->executeQuery(NS, $query); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; // Valid host refuses connection $manager = create_test_manager('mongodb://localhost:54321', ['serverSelectionTimeoutMS' => 1]); echo throws(function() use ($manager, $query) { $manager->executeQuery(NS, $query); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery_error-002.phpt0000644000175100001660000000303214760300421021415 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() with invalid options --FILE-- 3], ['projection' => ['y' => 1]]); echo throws(function() use ($manager, $query) { $manager->executeQuery(NS, $query, ['readPreference' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $query) { $manager->executeQuery(NS, $query, ['readPreference' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $query) { $manager->executeQuery(NS, $query, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $query) { $manager->executeQuery(NS, $query, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given ===DONE=== mongodb-1.21.0/tests/manager/manager-executeQuery_error-003.phpt0000644000175100001660000000151114760300421021416 0ustar --TEST-- MongoDB\Driver\Manager::executeQuery() exposes error document via CommandException --SKIPIF-- --FILE-- ['$unsupportedOperator' => true]]); try { $manager->executeQuery(NS, $query); } catch (\MongoDB\Driver\Exception\CommandException $e) { printf("%s(%d): %s\n", get_class($e), $e->getCode(), $e->getMessage()); $doc = $e->getResultDocument(); var_dump($doc->errmsg === $e->getMessage()); var_dump($doc->code === $e->getCode()); } ?> ===DONE=== --EXPECT-- MongoDB\Driver\Exception\CommandException(2): unknown operator: $unsupportedOperator bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadCommand-001.phpt0000644000175100001660000000246014760300421021254 0ustar --TEST-- MongoDB\Driver\Manager::executeReadCommand() --SKIPIF-- --FILE-- observe( function() use ($manager) { $command = new MongoDB\Driver\Command( [ 'aggregate' => NS, 'pipeline' => [], 'cursor' => new stdClass(), ] ); $manager->executeReadCommand( DATABASE_NAME, $command, [ 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::SECONDARY), 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::MAJORITY), ] ); }, function(stdClass $command) { echo "Read Preference: ", $command->{'$readPreference'}->mode, "\n"; echo "Read Concern: ", $command->readConcern->level, "\n"; } ); ?> ===DONE=== --EXPECTF-- Read Preference: secondary Read Concern: majority ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadCommand-002.phpt0000644000175100001660000000325114760300421021254 0ustar --TEST-- MongoDB\Driver\Manager::executeReadCommand() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [] ]); $manager->executeReadCommand(DATABASE_NAME, $command, ['session' => $session]); $pinnedServer = $session->getServer(); var_dump($pinnedServer instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $session->commitTransaction(); var_dump($session->getServer() == $pinnedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(true) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadCommand-003.phpt0000644000175100001660000000205214760300421021253 0ustar --TEST-- MongoDB\Driver\Manager::executeReadCommand() read concern inheritance --SKIPIF-- --FILE-- 'local']); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [], ]); (new CommandObserver)->observe( function() use ($manager, $command) { $manager->executeReadCommand(DATABASE_NAME, $command); $manager->executeReadCommand(DATABASE_NAME, $command, [ 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::AVAILABLE), ]); }, function(stdClass $command) { echo json_encode($command->readConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"level":"local"} {"level":"available"} ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadCommand_error-001.phpt0000644000175100001660000000460114760300421022464 0ustar --TEST-- MongoDB\Driver\Manager::executeReadCommand() with invalid options --SKIPIF-- --FILE-- 1]); echo throws(function() use ($manager, $command) { $manager->executeReadCommand(DATABASE_NAME, $command, ['readConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadCommand(DATABASE_NAME, $command, ['readConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadCommand(DATABASE_NAME, $command, ['readPreference' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadCommand(DATABASE_NAME, $command, ['readPreference' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadCommand(DATABASE_NAME, $command, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadCommand(DATABASE_NAME, $command, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadWriteCommand-001.phpt0000644000175100001660000000234014760300421022264 0ustar --TEST-- MongoDB\Driver\Manager::executeReadWriteCommand() --SKIPIF-- --FILE-- COLLECTION_NAME, 'pipeline' => [ ['$group' => ['_id' => 1]], ['$out' => COLLECTION_NAME . '.out'], ], 'cursor' => (object) [], ]); (new CommandObserver)->observe( function() use ($manager, $command) { $manager->executeReadWriteCommand( DATABASE_NAME, $command, [ 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::LOCAL), 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY), ] ); }, function(stdClass $command) { echo "Read Concern: ", $command->readConcern->level, "\n"; echo "Write Concern: ", $command->writeConcern->w, "\n"; } ); ?> ===DONE=== --EXPECTF-- Read Concern: local Write Concern: majority ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadWriteCommand-002.phpt0000644000175100001660000000353414760300421022273 0ustar --TEST-- MongoDB\Driver\Manager::executeReadWriteCommand() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$group' => ['_id' => 1]], /* Note: $out cannot be used in a transaction. This is technically not a * write command, but it works for the purposes of this test. */ ], 'cursor' => (object) [] ]); $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => $session]); $pinnedServer = $session->getServer(); var_dump($pinnedServer instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $session->commitTransaction(); var_dump($session->getServer() == $pinnedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(true) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadWriteCommand-003.phpt0000644000175100001660000000255714760300421022300 0ustar --TEST-- MongoDB\Driver\Manager::executeReadWriteCommand() read and write concern inheritance --SKIPIF-- --FILE-- 'local', 'w' => 2, 'wtimeoutms' => 1000]); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$group' => ['_id' => 1]], ['$out' => COLLECTION_NAME . '.out'], ], 'cursor' => (object) [], ]); (new CommandObserver)->observe( function() use ($manager, $command) { $manager->executeReadWriteCommand(DATABASE_NAME, $command); $manager->executeReadWriteCommand(DATABASE_NAME, $command, [ 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::AVAILABLE), 'writeConcern' => new MongoDB\Driver\WriteConcern(1), ]); }, function(stdClass $command) { echo json_encode($command->readConcern), "\n"; echo json_encode($command->writeConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"level":"local"} {"w":2,"wtimeout":1000} {"level":"available"} {"w":1} ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadWriteCommand_error-001.phpt0000644000175100001660000000463014760300421023501 0ustar --TEST-- MongoDB\Driver\Manager::executeReadWriteCommand() with invalid options --SKIPIF-- --FILE-- 1]); echo throws(function() use ($manager, $command) { $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['readConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['readConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['writeConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['writeConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given ===DONE=== mongodb-1.21.0/tests/manager/manager-executeReadWriteCommand_error-002.phpt0000644000175100001660000000307614760300421023505 0ustar --TEST-- MongoDB\Driver\Manager::executeReadWriteCommand() cannot combine session with unacknowledged write concern --SKIPIF-- --FILE-- COLLECTION_NAME, 'documents' => [['x' => 1]], ]); $manager->executeReadWriteCommand(DATABASE_NAME, $command, [ 'session' => $manager->startSession(), 'writeConcern' => new MongoDB\Driver\WriteConcern(0), ]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { $manager = create_test_manager(URI, ['w' => 0]); $command = new MongoDB\Driver\Command([ 'insert' => COLLECTION_NAME, 'documents' => [['x' => 1]], ]); $manager->executeReadWriteCommand(DATABASE_NAME, $command, [ 'session' => $manager->startSession(), ]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot combine "session" option with an unacknowledged write concern OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot combine "session" option with an unacknowledged write concern ===DONE=== mongodb-1.21.0/tests/manager/manager-executeWriteCommand-001.phpt0000644000175100001660000000177614760300421021504 0ustar --TEST-- MongoDB\Driver\Manager::executeWriteCommand() --SKIPIF-- --FILE-- insert(['a' => 1]); $manager->executeBulkWrite(NS, $bw); (new CommandObserver)->observe( function() use ($manager) { $command = new MongoDB\Driver\Command([ 'drop' => COLLECTION_NAME, ]); $manager->executeWriteCommand( DATABASE_NAME, $command, [ 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY), ] ); }, function(stdClass $command) { echo "Write Concern: ", $command->writeConcern->w, "\n"; } ); ?> ===DONE=== --EXPECTF-- Write Concern: majority ===DONE=== mongodb-1.21.0/tests/manager/manager-executeWriteCommand-002.phpt0000644000175100001660000000331014760300421021467 0ustar --TEST-- MongoDB\Driver\Manager::executeWriteCommand() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['_id' => 'foo'], 'upsert' => true, 'new' => true, 'update' => ['x' => 1] ]); $manager->executeWriteCommand(DATABASE_NAME, $command, ['session' => $session]); $pinnedServer = $session->getServer(); var_dump($pinnedServer instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $session->commitTransaction(); var_dump($session->getServer() == $pinnedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(false) bool(false) bool(true) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/manager/manager-executeWriteCommand-003.phpt0000644000175100001660000000210714760300421021473 0ustar --TEST-- MongoDB\Driver\Manager::executeWriteCommand() write concern inheritance --SKIPIF-- --FILE-- 2, 'wtimeoutms' => 1000]); $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['x' => 1], 'upsert' => true, 'new' => true, 'update' => ['$inc' => ['x' => 1]], ]); (new CommandObserver)->observe( function() use ($manager, $command) { $manager->executeWriteCommand(DATABASE_NAME, $command); $manager->executeWriteCommand(DATABASE_NAME, $command, ['writeConcern' => new MongoDB\Driver\WriteConcern(1)]); }, function(stdClass $command) { echo json_encode($command->writeConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"w":2,"wtimeout":1000} {"w":1} ===DONE=== mongodb-1.21.0/tests/manager/manager-executeWriteCommand_error-001.phpt0000644000175100001660000000332514760300421022705 0ustar --TEST-- MongoDB\Driver\Manager::executeWriteCommand() with invalid options --SKIPIF-- --FILE-- 1]); echo throws(function() use ($manager, $command) { $manager->executeWriteCommand(DATABASE_NAME, $command, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeWriteCommand(DATABASE_NAME, $command, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeWriteCommand(DATABASE_NAME, $command, ['writeConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($manager, $command) { $manager->executeWriteCommand(DATABASE_NAME, $command, ['writeConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given ===DONE=== mongodb-1.21.0/tests/manager/manager-executeWriteCommand_error-002.phpt0000644000175100001660000000174314760300421022710 0ustar --TEST-- MongoDB\Driver\Manager::executeWriteCommand() throws CommandException for invalid writeConcern --SKIPIF-- --FILE-- COLLECTION_NAME, 'query' => ['_id' => 'foo'], 'update' => ['foo' => ['bar']], 'upsert' => true, 'new' => true, ]); try { $manager->executeWriteCommand(DATABASE_NAME, $command, ['writeConcern' => new MongoDB\Driver\WriteConcern("undefined")]); } catch (MongoDB\Driver\Exception\CommandException $e) { printf("%s(%d): %s\n", get_class($e), $e->getCode(), $e->getMessage()); } ?> ===DONE=== --EXPECT-- MongoDB\Driver\Exception\CommandException(79): Write Concern error: No write concern mode named 'undefined' found in replica set configuration ===DONE=== mongodb-1.21.0/tests/manager/manager-executeWriteCommand_error-003.phpt0000644000175100001660000000146014760300421022705 0ustar --TEST-- MongoDB\Driver\Manager::executeWriteCommand() throws CommandException for unsupported update operator --SKIPIF-- --FILE-- COLLECTION_NAME, 'query' => ['_id' => 'foo'], 'upsert' => true, 'new' => true, ]); try { $manager->executeWriteCommand(DATABASE_NAME, $command); } catch (MongoDB\Driver\Exception\CommandException $e) { printf("%s(%d): %s\n", get_class($e), $e->getCode(), $e->getMessage()); } ?> ===DONE=== --EXPECT-- MongoDB\Driver\Exception\CommandException(9): Either an update or remove=true must be specified ===DONE=== mongodb-1.21.0/tests/manager/manager-executeWriteCommand_error-004.phpt0000644000175100001660000000263714760300421022715 0ustar --TEST-- MongoDB\Driver\Manager::executeWriteCommand() cannot combine session with unacknowledged write concern --SKIPIF-- --FILE-- COLLECTION_NAME, 'documents' => [['x' => 1]], ]); $manager->executeWriteCommand(DATABASE_NAME, $command, [ 'session' => $manager->startSession(), 'writeConcern' => new MongoDB\Driver\WriteConcern(0), ]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { $manager = create_test_manager(URI, ['w' => 0]); $command = new MongoDB\Driver\Command([ 'insert' => COLLECTION_NAME, 'documents' => [['x' => 1]], ]); $manager->executeWriteCommand(DATABASE_NAME, $command, [ 'session' => $manager->startSession(), ]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot combine "session" option with an unacknowledged write concern OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot combine "session" option with an unacknowledged write concern ===DONE=== mongodb-1.21.0/tests/manager/manager-getencryptedfieldsmap-001.phpt0000644000175100001660000000422414760300421022101 0ustar --TEST-- MongoDB\Driver\Manager::getEncryptedFieldsMap() --SKIPIF-- --FILE-- CSFLE_KEY_VAULT_NS, 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary(CSFLE_LOCAL_KEY, 0)]], 'extraOptions' => ['mongocryptdBypassSpawn' => true], ]; $encryptedFields = [ 'escCollection' => 'escCollectionName', 'eccCollection' => 'eccCollectionName', 'ecocCollection' => 'ecocCollectionName', 'fields' => [ [ 'path' => 'foo', 'keyId' => new MongoDB\BSON\Binary(str_repeat('0', 16), MongoDB\BSON\Binary::TYPE_UUID), 'bsonType' => 'string', 'queries' => ['queryType' => 'equality'], ], ], ]; $tests = [ [], ['autoEncryption' => $baseOptions], ['autoEncryption' => ['encryptedFieldsMap' => []] + $baseOptions], ['autoEncryption' => ['encryptedFieldsMap' => ['db.coll' => $encryptedFields]] + $baseOptions], ]; foreach ($tests as $i => $driverOptions) { $manager = create_test_manager(null, [], $driverOptions); var_dump($manager->getEncryptedFieldsMap()); } ?> ===DONE=== --EXPECTF-- NULL NULL array(0) { } array(1) { ["db.coll"]=> array(4) { ["escCollection"]=> string(17) "escCollectionName" ["eccCollection"]=> string(17) "eccCollectionName" ["ecocCollection"]=> string(18) "ecocCollectionName" ["fields"]=> array(1) { [0]=> array(4) { ["path"]=> string(3) "foo" ["keyId"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "0000000000000000" ["type"]=> int(4) } ["bsonType"]=> string(6) "string" ["queries"]=> array(1) { ["queryType"]=> string(8) "equality" } } } } } ===DONE=== mongodb-1.21.0/tests/manager/manager-getreadconcern-001.phpt0000644000175100001660000000263014760300421020501 0ustar --TEST-- MongoDB\Driver\Manager::getReadConcern() --FILE-- 'local']], [null, ['readconcernlevel' => 'majority']], [null, ['readconcernlevel' => 'not-yet-supported']], ['mongodb://127.0.0.1/?readconcernlevel=local', ['readconcernlevel' => 'majority']], ]; foreach ($tests as $i => $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getReadConcern()); $manager->getReadConcern(); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadConcern)#%d (%d) { } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(5) "local" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(8) "majority" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(17) "not-yet-supported" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(5) "local" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(8) "majority" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(17) "not-yet-supported" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(8) "majority" } ===DONE=== mongodb-1.21.0/tests/manager/manager-getreadpreference-001.phpt0000644000175100001660000000422414760300421021171 0ustar --TEST-- MongoDB\Driver\Manager::getReadPreference() --FILE-- 'primaryPreferred')), array('mongodb://127.0.0.1/?readPreference=secondary', array('readPreference' => 'secondaryPreferred')), array('mongodb://127.0.0.1/?readPreference=secondary&readPreferenceTags=dc:ny,use:reports&readPreferenceTags=', array()), array('mongodb://127.0.0.1/?readPreference=secondary', array('readPreferenceTags' => array(array('dc' => 'ny', 'use' => 'reports'), array()))), array('mongodb://127.0.0.1/?readPreference=secondary&readPreferenceTags=dc:ny,use:reports', array('readPreferenceTags' => array(array('dc' => 'ca')))), ); foreach ($tests as $i => $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getReadPreference()); $manager->getReadPreference(); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(2) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" ["use"]=> string(7) "reports" } [1]=> object(stdClass)#%d (%d) { } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(2) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" ["use"]=> string(7) "reports" } [1]=> object(stdClass)#%d (%d) { } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ca" } } } ===DONE=== mongodb-1.21.0/tests/manager/manager-getservers-001.phpt0000644000175100001660000000217714760300421017715 0ustar --TEST-- MongoDB\Driver\Manager::getServers() (standalone) --SKIPIF-- --FILE-- getServers(); printf("Known servers: %d\n", count($servers)); echo "Pinging\n"; $command = new MongoDB\Driver\Command(array('ping' => 1)); $manager->executeCommand(DATABASE_NAME, $command); $servers = $manager->getServers(); printf("Known servers: %d\n", count($servers)); foreach ($servers as $server) { printf("Found server: %s:%d\n", $server->getHost(), $server->getPort()); assertServerType($server->getType()); } ?> ===DONE=== --EXPECTF-- Known servers: 0 Pinging Known servers: 1 Found server: %s:%d Found standalone server type: 1 ===DONE=== mongodb-1.21.0/tests/manager/manager-getservers-002.phpt0000644000175100001660000000266714760300421017722 0ustar --TEST-- MongoDB\Driver\Manager::getServers() (replica set) --SKIPIF-- --FILE-- getServers(); printf("Known servers: %d\n", count($servers)); echo "Pinging\n"; $command = new MongoDB\Driver\Command(array('ping' => 1)); $manager->executeCommand(DATABASE_NAME, $command); $servers = $manager->getServers(); printf("Known servers: %d\n", count($servers)); foreach ($servers as $server) { printf("Found server: %s:%d\n", $server->getHost(), $server->getPort()); assertServerType($server->getType()); } ?> ===DONE=== --EXPECTF-- Known servers: 0 Pinging Known servers: 3 Found server: %s:%d Found replica set server type: %r(4|5|6)%r Found server: %s:%d Found replica set server type: %r(4|5|6)%r Found server: %s:%d Found replica set server type: %r(4|5|6)%r ===DONE=== mongodb-1.21.0/tests/manager/manager-getwriteconcern-001.phpt0000644000175100001660000000366614760300421020732 0ustar --TEST-- MongoDB\Driver\Manager::getWriteConcern() --FILE-- 1, 'journal' => true)), array(null, array('w' => 'majority', 'journal' => true)), array('mongodb://127.0.0.1/?w=majority&journal=true', array('w' => 1, 'journal' => false)), array('mongodb://127.0.0.1/?wtimeoutms=1000', array()), array(null, array('wtimeoutms' => 1000)), array('mongodb://127.0.0.1/?w=2', array('wtimeoutms' => 1000)), array('mongodb://127.0.0.1/?w=majority', array('wtimeoutms' => 1000)), array('mongodb://127.0.0.1/?w=customTagSet', array('wtimeoutms' => 1000)), ); foreach ($tests as $i => $test) { list($uri, $options) = $test; $manager = new MongoDB\Driver\Manager($uri, $options); var_dump($manager->getWriteConcern()); $manager->getWriteConcern(); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(true) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" ["j"]=> bool(true) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(false) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(12) "customTagSet" ["wtimeout"]=> int(1000) } ===DONE=== mongodb-1.21.0/tests/manager/manager-invalidnamespace.phpt0000644000175100001660000000163014760300421020522 0ustar --TEST-- MongoDB\Driver\Manager: Invalid namespace --SKIPIF-- --FILE-- insert(array("my" => "value")); echo throws(function() use($manager, $bulk) { $manager->executeBulkWrite("database", $bulk); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() use($manager) { $manager->executeQuery("database", new MongoDB\Driver\Query(array("document "=> 1))); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Invalid namespace provided: database OK: Got MongoDB\Driver\Exception\InvalidArgumentException Invalid namespace provided: database ===DONE=== mongodb-1.21.0/tests/manager/manager-removeSubscriber-001.phpt0000644000175100001660000000347214760300421021044 0ustar --TEST-- MongoDB\Driver\Manager::removeSubscriber() unregisters a subscriber --SKIPIF-- --FILE-- id = $id; } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { printf("MySubscriber(%s) commandStarted: %s\n", $this->id, $event->getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("MySubscriber(%s) commandSucceeded: %s\n", $this->id, $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("MySubscriber(%s) commandFailed: %s\n", $this->id, $event->getCommandName()); } } $m = create_test_manager(); $pingCommand = new MongoDB\Driver\Command(['ping' => 1]); $s1 = new MySubscriber('s1'); $s2 = new MySubscriber('s2'); $m->addSubscriber($s1); $m->addSubscriber($s2); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); $m->removeSubscriber($s2); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); $m->removeSubscriber($s1); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); ?> --EXPECT-- MySubscriber(s1) commandStarted: ping MySubscriber(s2) commandStarted: ping MySubscriber(s1) commandSucceeded: ping MySubscriber(s2) commandSucceeded: ping ping: 1 MySubscriber(s1) commandStarted: ping MySubscriber(s1) commandSucceeded: ping ping: 1 ping: 1 mongodb-1.21.0/tests/manager/manager-removeSubscriber-002.phpt0000644000175100001660000000265514760300421021047 0ustar --TEST-- MongoDB\Driver\Manager::removeSubscriber() NOP if subscriber not registered --SKIPIF-- --FILE-- id = $id; } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { printf("MySubscriber(%s) commandStarted: %s\n", $this->id, $event->getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { printf("MySubscriber(%s) commandSucceeded: %s\n", $this->id, $event->getCommandName()); } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { printf("MySubscriber(%s) commandFailed: %s\n", $this->id, $event->getCommandName()); } } $m = create_test_manager(); $pingCommand = new MongoDB\Driver\Command(['ping' => 1]); $s1 = new MySubscriber('s1'); $s2 = new MySubscriber('s2'); $m->addSubscriber($s1); $m->removeSubscriber($s2); printf("ping: %d\n", $m->executeCommand(DATABASE_NAME, $pingCommand)->toArray()[0]->ok); ?> --EXPECT-- MySubscriber(s1) commandStarted: ping MySubscriber(s1) commandSucceeded: ping ping: 1 mongodb-1.21.0/tests/manager/manager-selectServer-001.phpt0000644000175100001660000000364414760300421020172 0ustar --TEST-- MongoDB\Driver\Manager::selectServer() select a server from SDAM based on ReadPreference --SKIPIF-- --FILE-- selectServer($rp); $rp2 = new MongoDB\Driver\ReadPreference('primary'); $server2 = $manager->selectServer($rp2); // load fixtures for test $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1, 'x' => 2, 'y' => 3]); $bulk->insert(['_id' => 2, 'x' => 3, 'y' => 4]); $bulk->insert(['_id' => 3, 'x' => 4, 'y' => 5]); $server->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $server->executeQuery(NS, $query); var_dump($cursor instanceof MongoDB\Driver\Cursor); var_dump($server == $cursor->getServer()); var_dump(iterator_to_array($cursor)); $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $server2->executeQuery(NS, $query); var_dump($cursor instanceof MongoDB\Driver\Cursor); var_dump($server2 == $cursor->getServer()); var_dump(iterator_to_array($cursor)); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1, 'x' => 2, 'y' => 3]); $bulk->insert(['_id' => 2, 'x' => 3, 'y' => 4]); $bulk->insert(['_id' => 3, 'x' => 4, 'y' => 5]); throws(function() use($server2, $bulk) { $server2->executeBulkWrite(NS, $bulk); }, "MongoDB\Driver\Exception\BulkWriteException"); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["y"]=> int(4) } } bool(true) bool(true) array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["y"]=> int(4) } } OK: Got MongoDB\Driver\Exception\BulkWriteException ===DONE=== mongodb-1.21.0/tests/manager/manager-selectServer-002.phpt0000644000175100001660000000150714760300421020167 0ustar --TEST-- MongoDB\Driver\Manager::selectServer() defaults to primary read preference --SKIPIF-- --FILE-- 'secondary']); function isPrimary(Server $server): bool { return in_array($server->getType(), [Server::TYPE_STANDALONE, Server::TYPE_MONGOS, Server::TYPE_RS_PRIMARY, Server::TYPE_LOAD_BALANCER]); } var_dump(isPrimary($manager->selectServer())); var_dump(isPrimary($manager->selectServer(null))); ?> ===DONE=== --EXPECT-- bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/manager/manager-selectserver_error-001.phpt0000644000175100001660000000207714760300421021442 0ustar --TEST-- MongoDB\Driver\Manager::selectServer() should not issue warning before exception --FILE-- 1]); echo throws(function() use ($manager, $rp) { $manager->selectServer($rp); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; // Valid host refuses connection $manager = create_test_manager('mongodb://localhost:54321', ['serverSelectionTimeoutMS' => 1]); echo throws(function() use ($manager, $rp) { $manager->selectServer($rp); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s ===DONE=== mongodb-1.21.0/tests/manager/manager-serialization_error-001.phpt0000644000175100001660000000134114760300421021602 0ustar --TEST-- MongoDB\Driver\Manager does not support serialization (PHP >= 8.1) --FILE-- ===DONE=== --EXPECT-- OK: Got Exception Serialization of 'MongoDB\Driver\Manager' is not allowed OK: Got Exception Unserialization of 'MongoDB\Driver\Manager' is not allowed OK: Got Exception Unserialization of 'MongoDB\Driver\Manager' is not allowed ===DONE=== mongodb-1.21.0/tests/manager/manager-set-uri-options-001.phpt0000644000175100001660000000252014760300421020575 0ustar --TEST-- MongoDB\Driver\Manager: Logging into MongoDB using credentials from $options --SKIPIF-- --FILE-- $url["user"], "password" => $url["pass"], ) + $args; $manager = create_test_manager($dsn, $options); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(array("my" => "value")); $inserted = $manager->executeBulkWrite(NS, $bulk)->getInsertedCount(); printf("Inserted: %d\n", $inserted); $options["username"] = "not-found-user"; $manager = create_test_manager($dsn, $options); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(array("my" => "value")); echo throws(function() use ($manager, $bulk) { $inserted = $manager->executeBulkWrite(NS, $bulk)->getInsertedCount(); printf("Incorrectly inserted: %d\n", $inserted); }, 'MongoDB\Driver\Exception\BulkWriteException'), "\n"; ?> ===DONE=== --EXPECTF-- Inserted: 1 OK: Got MongoDB\Driver\Exception\BulkWriteException Bulk write failed due to previous MongoDB\Driver\Exception\AuthenticationException: Authentication failed. ===DONE=== mongodb-1.21.0/tests/manager/manager-set-uri-options-002.phpt0000644000175100001660000000366114760300421020605 0ustar --TEST-- MongoDB\Driver\Manager: Connecting to MongoDB using "ssl" from $options --SKIPIF-- --FILE-- array( "verify_peer" => false, "verify_peer_name" => false, "allow_self_signed" => true, ), ); $context = stream_context_create($opts); $options = array( "ssl" => false, "serverselectiontimeoutms" => 100, ); /* The server requires SSL */ $manager = create_test_manager(URI, $options, array("context" => $context)); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(array("my" => "value")); throws(function() use ($manager, $bulk) { $inserted = $manager->executeBulkWrite(NS, $bulk)->getInsertedCount(); printf("Inserted incorrectly: %d\n", $inserted); }, MongoDB\Driver\Exception\ConnectionException::class); $options = array( "ssl" => true, ); $manager = create_test_manager(URI, $options, array("context" => $context)); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(array("my" => "value")); $inserted = $manager->executeBulkWrite(NS, $bulk)->getInsertedCount(); printf("Inserted: %d\n", $inserted); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_self_signed" context driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s OK: Got MongoDB\Driver\Exception\ConnectionException Deprecated: MongoDB\Driver\Manager::__construct(): The "context" driver option is deprecated.%s Deprecated: MongoDB\Driver\Manager::__construct(): The "allow_self_signed" context driver option is deprecated. Please use the "tlsAllowInvalidCertificates" URI option instead.%s Inserted: 1 ===DONE=== mongodb-1.21.0/tests/manager/manager-set-uri-options-003.phpt0000644000175100001660000000122214760300421020575 0ustar --TEST-- MongoDB\Driver\Manager: SSL options in URI and 'options' don't leak --SKIPIF-- --FILE-- "does-not-matter", ); $manager = create_test_manager(URI . '&sslclientcertificatekeypassword=does-also-not-matter', [], $options); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Manager::__construct(): The "pem_pwd" driver option is deprecated. Please use the "tlsCertificateKeyFilePassword" URI option instead.%s ===DONE=== mongodb-1.21.0/tests/manager/manager-startSession_error-001.phpt0000644000175100001660000001027614760300421021435 0ustar --TEST-- MongoDB\Driver\Manager::startSession() with wrong defaultTransactionOptions --SKIPIF-- --FILE-- -1 ], [ 'readConcern' => 42 ], [ 'readConcern' => new stdClass ], [ 'readConcern' => new \MongoDB\Driver\WriteConcern( 2 ) ], [ 'readPreference' => 42 ], [ 'readPreference' => new stdClass ], [ 'readPreference' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ) ], [ 'writeConcern' => 42 ], [ 'writeConcern' => new stdClass ], [ 'writeConcern' => new \MongoDB\Driver\ReadPreference( \MongoDB\Driver\ReadPreference::SECONDARY ) ], [ 'readConcern' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ), 'readPreference' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ), ], [ 'readConcern' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ), 'writeConcern' => new \MongoDB\Driver\ReadPreference( \MongoDB\Driver\ReadPreference::SECONDARY ), ], [ 'readPreference' => new \MongoDB\Driver\ReadPreference( \MongoDB\Driver\ReadPreference::SECONDARY ), 'writeConcern' => new \MongoDB\Driver\ReadPreference( \MongoDB\Driver\ReadPreference::SECONDARY ), ], 42, new stdClass, ]; foreach ($options as $txnOptions) { echo throws(function() use ($manager, $txnOptions) { $manager->startSession([ 'defaultTransactionOptions' => $txnOptions ]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } echo raises(function() use ($manager) { $manager->startSession([ 'defaultTransactionOptions' => [ 'maxCommitTimeMS' => new stdClass ] ]); }, E_NOTICE | E_WARNING), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "maxCommitTimeMS" option to be >= 0, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, MongoDB\Driver\WriteConcern given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, MongoDB\Driver\ReadConcern given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, MongoDB\Driver\ReadPreference given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, MongoDB\Driver\ReadConcern given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, MongoDB\Driver\ReadPreference given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, MongoDB\Driver\ReadPreference given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "defaultTransactionOptions" option to be an array, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "defaultTransactionOptions" option to be an array, stdClass given OK: Got %r(E_NOTICE|E_WARNING)%r Object of class stdClass could not be converted to int ===DONE=== mongodb-1.21.0/tests/manager/manager-startSession_error-002.phpt0000644000175100001660000000173014760300421021431 0ustar --TEST-- MongoDB\Driver\Manager::startSession() snapshot and causalConsistency cannot both be true --DESCRIPTION-- Session spec prose test #1: Setting both snapshot and causalConsistency to true is not allowed https://github.com/mongodb/specifications/blob/master/source/sessions/tests/README.rst#setting-both-snapshot-and-causalconsistency-to-true-is-not-allowed --SKIPIF-- --FILE-- startSession([ 'causalConsistency' => true, 'snapshot' => true, ]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Only one of "causalConsistency" and "snapshot" can be enabled ===DONE=== mongodb-1.21.0/tests/manager/manager-var-dump-001.phpt0000644000175100001660000000227014760300421017251 0ustar --TEST-- MongoDB\Driver\Manager debug output --SKIPIF-- --FILE-- insert(array("my" => "value")); $retval = $manager->executeBulkWrite(NS, $bulk); var_dump($manager); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Manager)#%d (%d) { ["uri"]=> string(%d) "mongodb://%s" ["cluster"]=> array(0) { } } object(MongoDB\Driver\Manager)#%d (%d) { ["uri"]=> string(%d) "mongodb://%s" ["cluster"]=> array(1) { [0]=> array(10) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["type"]=> int(1) ["is_primary"]=> bool(false) ["is_secondary"]=> bool(false) ["is_arbiter"]=> bool(false) ["is_hidden"]=> bool(false) ["is_passive"]=> bool(false) ["last_hello_response"]=> array(%d) { %a } ["round_trip_time"]=> int(%d) } } } ===DONE=== mongodb-1.21.0/tests/manager/manager_error-001.phpt0000644000175100001660000000037214760300421016732 0ustar --TEST-- MongoDB\Driver\Manager cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyManager %s final class %SMongoDB\Driver\Manager%S in %s on line %d mongodb-1.21.0/tests/query/bug0430-001.phpt0000644000175100001660000000054114760300421014724 0ustar --TEST-- PHPC-430: Query constructor arguments are modified --FILE-- ['x' => 1]]; $query = new MongoDB\Driver\Query($filter, $options); var_dump($filter); var_dump($options); ?> ===DONE=== --EXPECT-- array(0) { } array(1) { ["sort"]=> array(1) { ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/query/bug0430-002.phpt0000644000175100001660000000074114760300421014727 0ustar --TEST-- PHPC-430: Query constructor arguments are modified --FILE-- ['x' => 1]]; $optionsCopy = $options; $optionsCopy['cursorFlags'] = 0; $query = new MongoDB\Driver\Query([], $options); var_dump($options); var_dump($optionsCopy); ?> ===DONE=== --EXPECT-- array(1) { ["sort"]=> array(1) { ["x"]=> int(1) } } array(2) { ["sort"]=> array(1) { ["x"]=> int(1) } ["cursorFlags"]=> int(0) } ===DONE=== mongodb-1.21.0/tests/query/bug0430-003.phpt0000644000175100001660000000063114760300421014726 0ustar --TEST-- PHPC-430: Query constructor arguments are modified --FILE-- []]; $query = buildQuery($filter, $options); var_dump($options); ?> ===DONE=== --EXPECT-- array(1) { ["sort"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/query/bug2457-001.phpt0000644000175100001660000000144714760300421014745 0ustar --TEST-- PHPC-2457: Query options can be passed reference --FILE-- 'fr_FR', 'strength' => 2]; $let = ['x' => 1]; $sort = ['_id' => 1]; $query = new MongoDB\Driver\Query([], [ 'collation' => &$collation, 'let' => &$let, 'sort' => &$sort, ]); var_dump($query); ?> ===DONE=== --EXPECT-- object(MongoDB\Driver\Query)#1 (3) { ["filter"]=> object(stdClass)#2 (0) { } ["options"]=> object(stdClass)#6 (3) { ["collation"]=> object(stdClass)#3 (2) { ["locale"]=> string(5) "fr_FR" ["strength"]=> int(2) } ["let"]=> object(stdClass)#4 (1) { ["x"]=> int(1) } ["sort"]=> object(stdClass)#5 (1) { ["_id"]=> int(1) } } ["readConcern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/query/bug2457-002.phpt0000644000175100001660000000117514760300421014744 0ustar --TEST-- PHPC-2457: Query modifiers can be passed reference --FILE-- ['x' => 1]]; $query = new MongoDB\Driver\Query([], [ 'modifiers' => &$modifiers, ]); var_dump($query); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s object(MongoDB\Driver\Query)#1 (3) { ["filter"]=> object(stdClass)#2 (0) { } ["options"]=> object(stdClass)#4 (1) { ["sort"]=> object(stdClass)#3 (1) { ["x"]=> int(1) } } ["readConcern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-001.phpt0000644000175100001660000000334214760300421015754 0ustar --TEST-- MongoDB\Driver\Query construction should always encode __pclass for Persistable objects --SKIPIF-- --FILE-- id = $id; $this->child = $child; } #[\ReturnTypeWillChange] public function bsonSerialize() { return [ '_id' => $this->id, 'child' => $this->child, ]; } public function bsonUnserialize(array $data): void { $this->id = $data['_id']; $this->child = $data['child']; } } $manager = create_test_manager(); $document = new MyClass('foo', new MyClass('bar', new MyClass('baz'))); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(new MyClass('foo', new MyClass('bar', new MyClass('baz')))); $result = $manager->executeBulkWrite(NS, $bulk); printf("Inserted %d document(s)\n", $result->getInsertedCount()); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query($document)); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- Inserted 1 document(s) array(1) { [0]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "foo" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "bar" ["child":"MyClass":private]=> object(MyClass)#%d (%d) { ["id":"MyClass":private]=> string(3) "baz" ["child":"MyClass":private]=> NULL } } } } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-002.phpt0000644000175100001660000000700514760300421015755 0ustar --TEST-- MongoDB\Driver\Query construction with options --FILE-- 1], [ 'allowDiskUse' => false, 'allowPartialResults' => false, 'awaitData' => false, 'batchSize' => 10, 'collation' => ['locale' => 'en_US'], 'comment' => 'foo', 'exhaust' => false, 'limit' => 20, 'max' => ['y' => 100], 'maxScan' => 50, 'maxTimeMS' => 1000, 'min' => ['y' => 1], 'noCursorTimeout' => false, 'oplogReplay' => false, 'projection' => ['x' => 1, 'y' => 1], 'returnKey' => false, 'showRecordId' => false, 'singleBatch' => false, 'skip' => 5, 'sort' => ['y' => -1], 'snapshot' => false, 'tailable' => false, ] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], ['hint' => 'y_1'] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], ['hint' => ['y' => 1]] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], ['readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::LOCAL)] )); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): The "maxScan" option is deprecated and will be removed in a future release in %s on line %d Deprecated: MongoDB\Driver\Query::__construct(): The "oplogReplay" option is deprecated and will be removed in a future release in %s on line %d Deprecated: MongoDB\Driver\Query::__construct(): The "snapshot" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["allowDiskUse"]=> bool(false) ["allowPartialResults"]=> bool(false) ["awaitData"]=> bool(false) ["batchSize"]=> int(10) ["collation"]=> object(stdClass)#%d (%d) { ["locale"]=> string(5) "en_US" } ["comment"]=> string(3) "foo" ["exhaust"]=> bool(false) ["max"]=> object(stdClass)#%d (%d) { ["y"]=> int(100) } ["maxScan"]=> int(50) ["maxTimeMS"]=> int(1000) ["min"]=> object(stdClass)#%d (%d) { ["y"]=> int(1) } ["noCursorTimeout"]=> bool(false) ["oplogReplay"]=> bool(false) ["projection"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) ["y"]=> int(1) } ["returnKey"]=> bool(false) ["showRecordId"]=> bool(false) ["skip"]=> int(5) ["sort"]=> object(stdClass)#%d (%d) { ["y"]=> int(-1) } ["snapshot"]=> bool(false) ["tailable"]=> bool(false) ["limit"]=> int(20) ["singleBatch"]=> bool(false) } ["readConcern"]=> NULL } object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["hint"]=> string(3) "y_1" } ["readConcern"]=> NULL } object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["hint"]=> object(stdClass)#%d (%d) { ["y"]=> int(1) } } ["readConcern"]=> NULL } object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { } ["readConcern"]=> array(1) { ["level"]=> string(5) "local" } } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-003.phpt0000644000175100001660000000576214760300421015766 0ustar --TEST-- MongoDB\Driver\Query construction with modifier options --FILE-- 1], [ 'modifiers' => [ '$comment' => 'foo', '$max' => ['y' => 100], '$maxScan' => 50, '$maxTimeMS' => 1000, '$min' => ['y' => 1], '$orderby' => ['y' => -1], '$returnKey' => false, '$showDiskLoc' => false, '$snapshot' => false, ], ] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], ['modifiers' => ['$explain' => true]] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], ['modifiers' => ['$hint' => 'y_1']] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], ['modifiers' => ['$hint' => ['y' => 1]]] )); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d Deprecated: MongoDB\Driver\Query::__construct(): The "$maxScan" option is deprecated and will be removed in a future release in %s on line %d Deprecated: MongoDB\Driver\Query::__construct(): The "$snapshot" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["comment"]=> string(3) "foo" ["max"]=> object(stdClass)#%d (%d) { ["y"]=> int(100) } ["maxScan"]=> int(50) ["maxTimeMS"]=> int(1000) ["min"]=> object(stdClass)#%d (%d) { ["y"]=> int(1) } ["returnKey"]=> bool(false) ["showRecordId"]=> bool(false) ["sort"]=> object(stdClass)#%d (%d) { ["y"]=> int(-1) } ["snapshot"]=> bool(false) } ["readConcern"]=> NULL } Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["explain"]=> bool(true) } ["readConcern"]=> NULL } Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["hint"]=> string(3) "y_1" } ["readConcern"]=> NULL } Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["hint"]=> object(stdClass)#%d (%d) { ["y"]=> int(1) } } ["readConcern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-004.phpt0000644000175100001660000000561114760300421015760 0ustar --TEST-- MongoDB\Driver\Query construction with options overriding modifiers --FILE-- 1], [ 'comment' => 'foo', 'max' => ['y' => 100], 'maxScan' => 50, 'maxTimeMS' => 1000, 'min' => ['y' => 1], 'returnKey' => false, 'showRecordId' => false, 'sort' => ['y' => -1], 'snapshot' => false, 'modifiers' => [ '$comment' => 'bar', '$max' => ['y' => 200], '$maxScan' => 60, '$maxTimeMS' => 2000, '$min' => ['y' => 101], '$orderby' => ['y' => 1], '$returnKey' => true, '$showDiskLoc' => true, '$snapshot' => true, ], ] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], [ 'hint' => 'y_1', 'modifiers' => ['$hint' => 'x_1'], ] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], [ 'hint' => ['y' => 1], 'modifiers' => ['$hint' => ['x' => 1]], ] )); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d Deprecated: MongoDB\Driver\Query::__construct(): The "maxScan" option is deprecated and will be removed in a future release in %s on line %d Deprecated: MongoDB\Driver\Query::__construct(): The "snapshot" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["comment"]=> string(3) "foo" ["max"]=> object(stdClass)#%d (%d) { ["y"]=> int(100) } ["maxScan"]=> int(50) ["maxTimeMS"]=> int(1000) ["min"]=> object(stdClass)#%d (%d) { ["y"]=> int(1) } ["returnKey"]=> bool(false) ["showRecordId"]=> bool(false) ["sort"]=> object(stdClass)#%d (%d) { ["y"]=> int(-1) } ["snapshot"]=> bool(false) } ["readConcern"]=> NULL } Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["hint"]=> string(3) "y_1" } ["readConcern"]=> NULL } Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["hint"]=> object(stdClass)#%d (%d) { ["y"]=> int(1) } } ["readConcern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-005.phpt0000644000175100001660000000217214760300421015760 0ustar --TEST-- MongoDB\Driver\Query construction with negative limit --FILE-- 1], ['limit' => -5] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], [ 'limit' => -5, 'singleBatch' => true ] )); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): Support for negative "limit" values is deprecated and will be removed in ext-mongodb 2.0 in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["limit"]=> int(5) ["singleBatch"]=> bool(true) } ["readConcern"]=> NULL } Deprecated: MongoDB\Driver\Query::__construct(): Support for negative "limit" values is deprecated and will be removed in ext-mongodb 2.0 in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["limit"]=> int(5) ["singleBatch"]=> bool(true) } ["readConcern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-006.phpt0000644000175100001660000000151514760300421015761 0ustar --TEST-- MongoDB\Driver\Query construction "allowPartialResults" overrides "partial" option --FILE-- 1], ['partial' => true] )); var_dump(new MongoDB\Driver\Query( ['x' => 1], [ 'allowPartialResults' => false, 'partial' => true, ] )); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["allowPartialResults"]=> bool(true) } ["readConcern"]=> NULL } object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } ["options"]=> object(stdClass)#%d (%d) { ["allowPartialResults"]=> bool(false) } ["readConcern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-007.phpt0000644000175100001660000000201014760300421015751 0ustar --TEST-- MongoDB\Driver\Query::__construct() $filter is MongoDB\Driver\Document --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $manager->executeBulkWrite(NS, $bulk); $filter = MongoDB\BSON\Document::fromJSON('{ "_id": { "$gt": 1 } }'); $query = new MongoDB\Driver\Query($filter); var_dump($query); $cursor = $manager->executeQuery(NS, $query); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["_id"]=> object(stdClass)#%d (%d) { ["$gt"]=> int(1) } } ["options"]=> object(stdClass)#%d (%d) { } ["readConcern"]=> NULL } array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) } } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-comment-001.phpt0000644000175100001660000000302114760300421017406 0ustar --TEST-- MongoDB\Driver\Query::__construct(): comment option --SKIPIF-- --FILE-- getCommand(); if (!isset($command->comment)) { printf("%s does not include comment option\n", $event->getCommandName()); return; } printf("%s included comment: %s\n", $event->getCommandName(), json_encode($command->comment)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query( ['_id' => 1], ['comment' => ['foo' => 1]] ); $manager->addSubscriber(new CommandLogger); $cursor = $manager->executeQuery(NS, $query); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- find included comment: {"foo":1} array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-comment_error-001.phpt0000644000175100001660000000110014760300421020613 0ustar --TEST-- MongoDB\Driver\Query::__construct(): comment option bsonSerialize() exception --FILE-- new Comment()]); }, Exception::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got Exception phongo_zval_to_bson_value fails ===DONE=== mongodb-1.21.0/tests/query/query-ctor-let-001.phpt0000644000175100001660000000301714760300421016535 0ustar --TEST-- MongoDB\Driver\Query::__construct(): let option --SKIPIF-- --FILE-- getCommand(); if (!isset($command->let)) { printf("%s does not include let option\n", $event->getCommandName()); return; } printf("%s included let: %s\n", $event->getCommandName(), json_encode($command->let)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $manager->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query( ['$expr' => ['$eq' => ['$_id', '$$id']]], ['let' => ['id' => 1]] ); $manager->addSubscriber(new CommandLogger); $cursor = $manager->executeQuery(NS, $query); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- find included let: {"id":1} array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/query/query-ctor-let_error-001.phpt0000644000175100001660000000163114760300421017746 0ustar --TEST-- MongoDB\Driver\Query::__construct(): let option invalid type --FILE-- $invalidValue]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "let" option to be array or object, bool given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "let" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "let" option to be array or object, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "let" option to be array or object, null given ===DONE=== mongodb-1.21.0/tests/query/query-ctor_error-001.phpt0000644000175100001660000000261214760300421017164 0ustar --TEST-- MongoDB\Driver\Query construction (invalid readConcern type) --FILE-- $test]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; } ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, float given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, bool given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, null given ===DONE=== mongodb-1.21.0/tests/query/query-ctor_error-002.phpt0000644000175100001660000000500614760300421017165 0ustar --TEST-- MongoDB\Driver\Query construction (invalid option types) --FILE-- 0], ['collation' => 0], ['hint' => 0], ['max' => 0], ['min' => 0], ['projection' => 0], ['sort' => 0], ['modifiers' => ['$hint' => 0]], ['modifiers' => ['$max' => 0]], ['modifiers' => ['$min' => 0]], ['modifiers' => ['$orderby' => 0]], ]; foreach ($tests as $options) { echo throws(function() use ($options) { new MongoDB\Driver\Query([], $options); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "modifiers" option to be array, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "collation" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "hint" option to be string, array, or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "max" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "min" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "projection" option to be array or object, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "sort" option to be array or object, int given Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "$hint" modifier to be string, array, or object, int given Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "$max" modifier to be array or object, int given Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "$min" modifier to be array or object, int given Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "$orderby" modifier to be array or object, int given ===DONE=== mongodb-1.21.0/tests/query/query-ctor_error-003.phpt0000644000175100001660000000121614760300421017165 0ustar --TEST-- MongoDB\Driver\Query construction (negative limit conflicts with false singleBatch) --FILE-- -1, 'singleBatch' => false]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): Support for negative "limit" values is deprecated and will be removed in ext-mongodb 2.0 in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Negative "limit" option conflicts with false "singleBatch" option ===DONE=== mongodb-1.21.0/tests/query/query-ctor_error-004.phpt0000644000175100001660000000520014760300421017163 0ustar --TEST-- MongoDB\Driver\Query construction (cannot use empty keys in documents) --FILE-- '1'], []], [['x' => ['' => '1']], []], [[], ['collation' => ['' => 1]]], [[], ['hint' => ['' => 1]]], [[], ['max' => ['' => 1]]], [[], ['min' => ['' => 1]]], [[], ['projection' => ['' => 1]]], [[], ['sort' => ['' => 1]]], [[], ['modifiers' => ['$hint' => ['' => 1]]]], [[], ['modifiers' => ['$max' => ['' => 1]]]], [[], ['modifiers' => ['$min' => ['' => 1]]]], [[], ['modifiers' => ['$orderby' => ['' => 1]]]], ]; foreach ($tests as $test) { list($filter, $options) = $test; echo throws(function() use ($filter, $options) { new MongoDB\Driver\Query($filter, $options); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in filter document OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in filter document OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "collation" option OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "hint" option OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "max" option OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "min" option OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "projection" option OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "sort" option Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "$hint" modifier Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "$max" modifier Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "$min" modifier Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use empty keys in "$orderby" modifier ===DONE=== mongodb-1.21.0/tests/query/query-ctor_error-005.phpt0000644000175100001660000000070414760300421017170 0ustar --TEST-- MongoDB\Driver\Query construction (invalid maxAwaitTimeMS range) --FILE-- -1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "maxAwaitTimeMS" option to be >= 0, -1 given ===DONE=== mongodb-1.21.0/tests/query/query-ctor_error-006.phpt0000644000175100001660000000106314760300421017170 0ustar --TEST-- MongoDB\Driver\Query construction (invalid maxAwaitTimeMS range) --SKIPIF-- --FILE-- 4294967296]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "maxAwaitTimeMS" option to be <= 4294967295, 4294967296 given ===DONE=== mongodb-1.21.0/tests/query/query-ctor_error-007.phpt0000644000175100001660000000536114760300421017176 0ustar --TEST-- MongoDB\Driver\Query::__construct() prohibits PackedArray for document values --FILE-- MongoDB\BSON\PackedArray::fromPHP([])], ['let' => MongoDB\BSON\PackedArray::fromPHP([])], ['max' => MongoDB\BSON\PackedArray::fromPHP([])], ['min' => MongoDB\BSON\PackedArray::fromPHP([])], ['projection' => MongoDB\BSON\PackedArray::fromPHP([])], ['sort' => MongoDB\BSON\PackedArray::fromPHP([])], ['modifiers' => ['$max' => MongoDB\BSON\PackedArray::fromPHP([])]], ['modifiers' => ['$min' => MongoDB\BSON\PackedArray::fromPHP([])]], ['modifiers' => ['$orderby' => MongoDB\BSON\PackedArray::fromPHP([])]], ]; foreach ($tests as $options) { echo throws(function() use ($options) { new MongoDB\Driver\Query([], $options); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/query/query-debug-001.phpt0000644000175100001660000000221014760300421016064 0ustar --TEST-- MongoDB\Driver\Query debug output --FILE-- 123], [ 'limit' => 5, 'modifiers' => [ '$comment' => 'foo', '$maxTimeMS' => 500, ], 'projection' => ['c' => 1], 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::LOCAL), 'skip' => 10, 'sort' => ['b' => -1], ] )); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["a"]=> int(123) } ["options"]=> object(stdClass)#%d (%d) { ["comment"]=> string(3) "foo" ["maxTimeMS"]=> int(500) ["projection"]=> object(stdClass)#%d (%d) { ["c"]=> int(1) } ["skip"]=> int(10) ["sort"]=> object(stdClass)#%d (%d) { ["b"]=> int(-1) } ["limit"]=> int(5) } ["readConcern"]=> array(1) { ["level"]=> string(5) "local" } } ===DONE=== mongodb-1.21.0/tests/query/query-debug-002.phpt0000644000175100001660000000122314760300421016070 0ustar --TEST-- MongoDB\Driver\Query debug output with let option --FILE-- ['$eq' => ['$_id', '$$id']]], ['let' => ['id' => 1]] )); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["$expr"]=> object(stdClass)#%d (%d) { ["$eq"]=> array(2) { [0]=> string(4) "$_id" [1]=> string(4) "$$id" } } } ["options"]=> object(stdClass)#%d (%d) { ["let"]=> object(stdClass)#%d (%d) { ["id"]=> int(1) } } ["readConcern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/query/query-debug-003.phpt0000644000175100001660000000167014760300421016077 0ustar --TEST-- MongoDB\Driver\Query debug output with comment option --FILE-- ['foo' => 1]] )); var_dump(new MongoDB\Driver\Query( [], ['modifiers' => ['$comment' => ['foo' => 1]]] )); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (0) { } ["options"]=> object(stdClass)#%d (%d) { ["comment"]=> object(stdClass)#%d (%d) { ["foo"]=> int(1) } } ["readConcern"]=> NULL } Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (0) { } ["options"]=> object(stdClass)#%d (%d) { ["comment"]=> object(stdClass)#%d (%d) { ["foo"]=> int(1) } } ["readConcern"]=> NULL } ===DONE=== mongodb-1.21.0/tests/query/query_error-001.phpt0000644000175100001660000000036014760300421016215 0ustar --TEST-- MongoDB\Driver\Query cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyQuery %s final class %SMongoDB\Driver\Query%S in %s on line %d mongodb-1.21.0/tests/readConcern/bug1598-001.phpt0000644000175100001660000000067214760300421016027 0ustar --TEST-- PHPC-1598: ReadConcern get_gc should not invoke get_properties --FILE-- $rc]; $b = (object) ['rc' => $rc]; $a->b = $b; $b->a = $a; printf("Collected cycles: %d\n", gc_collect_cycles()); unset($a, $b); printf("Collected cycles: %d\n", gc_collect_cycles()); ?> ===DONE=== --EXPECT-- Collected cycles: 0 Collected cycles: 2 ===DONE=== mongodb-1.21.0/tests/readConcern/bug1598-002.phpt0000644000175100001660000000134214760300421016023 0ustar --TEST-- PHPC-1598: ReadConcern get_gc should delegate to zend_std_get_properties --SKIPIF-- =', '8.1.99'); ?> --FILE-- rc = new MongoDB\Driver\ReadConcern('local'); $a->rc->a = $a; printf("Collected cycles: %d\n", gc_collect_cycles()); unset($a); printf("Collected cycles: %d\n", gc_collect_cycles()); ?> ===DONE=== --EXPECT-- Collected cycles: 0 Collected cycles: 2 ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-bsonserialize-001.phpt0000644000175100001660000000060614760300421022052 0ustar --TEST-- MongoDB\Driver\ReadConcern::bsonSerialize() --FILE-- ===DONE=== --EXPECT-- { } { "level" : "local" } ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-bsonserialize-002.phpt0000644000175100001660000000073214760300421022053 0ustar --TEST-- MongoDB\Driver\ReadConcern::bsonSerialize() returns an object --FILE-- bsonSerialize()); } ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { } object(stdClass)#%d (%d) { ["level"]=> string(5) "local" } ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-constants.phpt0000644000175100001660000000072414760300421020720 0ustar --TEST-- MongoDB\Driver\ReadConcern constants --FILE-- ===DONE=== --EXPECTF-- string(12) "linearizable" string(5) "local" string(8) "majority" string(9) "available" string(8) "snapshot" ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-ctor-001.phpt0000644000175100001660000000115614760300421020151 0ustar --TEST-- MongoDB\Driver\ReadConcern construction --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadConcern)#%d (%d) { } object(MongoDB\Driver\ReadConcern)#%d (%d) { } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(5) "local" } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(17) "not-yet-supported" } ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-ctor_error-001.phpt0000644000175100001660000000112114760300421021352 0ustar --TEST-- MongoDB\Driver\ReadConcern construction (invalid arguments) --SKIPIF-- =', '7.99'); ?> --FILE-- ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadConcern::__construct() expects at most 1 %r(argument|parameter)%r, 2 given ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-ctor_error-002.phpt0000644000175100001660000000126114760300421021360 0ustar --TEST-- MongoDB\Driver\ReadConcern construction (invalid level type) --SKIPIF-- =', '7.99'); ?> --FILE-- ===DONE=== --EXPECTF-- OK: Got TypeError %SMongoDB\Driver\ReadConcern::__construct()%sstring or null, array given OK: Got TypeError %SMongoDB\Driver\ReadConcern::__construct()%sstring or null, %r(object|stdClass)%r given ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-debug-001.phpt0000644000175100001660000000072714760300421020273 0ustar --TEST-- MongoDB\Driver\ReadConcern debug output --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadConcern)#%d (%d) { } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(5) "local" } ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-getlevel-001.phpt0000644000175100001660000000056414760300421021013 0ustar --TEST-- MongoDB\Driver\ReadConcern::getLevel() --FILE-- getLevel()); } ?> ===DONE=== --EXPECT-- NULL string(5) "local" string(17) "not-yet-supported" ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-isdefault-001.phpt0000644000175100001660000000212314760300421021155 0ustar --TEST-- MongoDB\Driver\ReadConcern::isDefault() --FILE-- getReadConcern(), (new MongoDB\Driver\Manager('mongodb://127.0.0.1/?readconcernlevel='))->getReadConcern(), (new MongoDB\Driver\Manager(null, ['readconcernlevel' => 'local']))->getReadConcern(), (new MongoDB\Driver\Manager(null, ['readconcernlevel' => '']))->getReadConcern(), // Cannot test ['readconcernlevel' => null] since a string type is expected (PHPC-887) (new MongoDB\Driver\Manager)->getReadConcern(), ]; foreach ($tests as $rc) { var_dump($rc->isDefault()); } ?> ===DONE=== --EXPECT-- bool(true) bool(true) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(true) ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-serialization-002.phpt0000644000175100001660000000146414760300421022062 0ustar --TEST-- MongoDB\Driver\ReadConcern serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadConcern)#%d (%d) { } O:26:"MongoDB\Driver\ReadConcern":0:{} object(MongoDB\Driver\ReadConcern)#%d (%d) { } object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(5) "local" } O:26:"MongoDB\Driver\ReadConcern":1:{s:5:"level";s:5:"local";} object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(5) "local" } ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-serialization_error-001.phpt0000644000175100001660000000076514760300421023275 0ustar --TEST-- MongoDB\Driver\ReadConcern unserialization errors (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadConcern initialization requires "level" string field ===DONE===mongodb-1.21.0/tests/readConcern/readconcern-serialization_error-002.phpt0000644000175100001660000000076514760300421023276 0ustar --TEST-- MongoDB\Driver\ReadConcern unserialization errors (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadConcern initialization requires "level" string field ===DONE===mongodb-1.21.0/tests/readConcern/readconcern-set_state-001.phpt0000644000175100001660000000075214760300421021176 0ustar --TEST-- MongoDB\Driver\ReadConcern::__set_state() --FILE-- MongoDB\Driver\ReadConcern::AVAILABLE, ])); echo "\n\n"; /* Test with level unset */ var_export(MongoDB\Driver\ReadConcern::__set_state([ ])); echo "\n\n"; ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\ReadConcern::__set_state(array( %w'level' => 'available', )) %r\\?%rMongoDB\Driver\ReadConcern::__set_state(array( )) ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-set_state_error-001.phpt0000644000175100001660000000073614760300421022411 0ustar --TEST-- MongoDB\Driver\ReadConcern::__set_state() requires "level" string field --FILE-- 0]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadConcern initialization requires "level" string field ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern-var_export-001.phpt0000644000175100001660000000076414760300421021377 0ustar --TEST-- MongoDB\Driver\ReadConcern: var_export() --FILE-- ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\ReadConcern::__set_state(array( )) %r\\?%rMongoDB\Driver\ReadConcern::__set_state(array( 'level' => 'local', )) ===DONE=== mongodb-1.21.0/tests/readConcern/readconcern_error-001.phpt0000644000175100001660000000041614760300421020413 0ustar --TEST-- MongoDB\Driver\ReadConcern cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyReadConcern %s final class %SMongoDB\Driver\ReadConcern%S in %s on line %d mongodb-1.21.0/tests/readPreference/bug0146-001.phpt0000644000175100001660000001065514760300421016504 0ustar --TEST-- PHPC-146: ReadPreference primaryPreferred and secondary swapped --SKIPIF-- --FILE-- insert(array('my' => 'document')); $manager->executeBulkWrite(NS, $bulk); $rps = [ MongoDB\Driver\ReadPreference::PRIMARY, MongoDB\Driver\ReadPreference::PRIMARY_PREFERRED, MongoDB\Driver\ReadPreference::SECONDARY, MongoDB\Driver\ReadPreference::SECONDARY_PREFERRED, MongoDB\Driver\ReadPreference::NEAREST, ]; foreach($rps as $r) { $rp = new MongoDB\Driver\ReadPreference($r); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(['my' => 'query']), ['readPreference' => $rp]); var_dump($cursor); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> string(26) "readPreference_bug0146_001" ["query"]=> object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["my"]=> string(5) "query" } ["options"]=> object(stdClass)#%d (%d) { } ["readConcern"]=> NULL } ["command"]=> NULL ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } ["session"]=> NULL ["isDead"]=> bool(true) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> string(26) "readPreference_bug0146_001" ["query"]=> object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["my"]=> string(5) "query" } ["options"]=> object(stdClass)#%d (%d) { } ["readConcern"]=> NULL } ["command"]=> NULL ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } ["session"]=> NULL ["isDead"]=> bool(true) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> string(26) "readPreference_bug0146_001" ["query"]=> object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["my"]=> string(5) "query" } ["options"]=> object(stdClass)#%d (%d) { } ["readConcern"]=> NULL } ["command"]=> NULL ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } ["session"]=> NULL ["isDead"]=> bool(true) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> string(26) "readPreference_bug0146_001" ["query"]=> object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["my"]=> string(5) "query" } ["options"]=> object(stdClass)#%d (%d) { } ["readConcern"]=> NULL } ["command"]=> NULL ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } ["session"]=> NULL ["isDead"]=> bool(true) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> string(26) "readPreference_bug0146_001" ["query"]=> object(MongoDB\Driver\Query)#%d (%d) { ["filter"]=> object(stdClass)#%d (%d) { ["my"]=> string(5) "query" } ["options"]=> object(stdClass)#%d (%d) { } ["readConcern"]=> NULL } ["command"]=> NULL ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "nearest" } ["session"]=> NULL ["isDead"]=> bool(true) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } ===DONE=== mongodb-1.21.0/tests/readPreference/bug0851-001.phpt0000644000175100001660000000145514760300421016505 0ustar --TEST-- PHPC-851: ReadPreference constructor should not modify tagSets argument --FILE-- 'ny'], [], ]; $rp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY_PREFERRED, $tagSets); var_dump($tagSets); /* Dump the Manager's ReadPreference to ensure that each element in the $tagSets * argument was converted to an object. */ var_dump($rp); ?> ===DONE=== --EXPECTF-- array(2) { [0]=> array(1) { ["dc"]=> string(2) "ny" } [1]=> array(0) { } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" ["tags"]=> array(2) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } [1]=> object(stdClass)#%d (%d) { } } } ===DONE=== mongodb-1.21.0/tests/readPreference/bug1598-001.phpt0000644000175100001660000000070214760300421016510 0ustar --TEST-- PHPC-1598: ReadPreference get_gc should not invoke get_properties --FILE-- $rp]; $b = (object) ['rp' => $rp]; $a->b = $b; $b->a = $a; printf("Collected cycles: %d\n", gc_collect_cycles()); unset($a, $b); printf("Collected cycles: %d\n", gc_collect_cycles()); ?> ===DONE=== --EXPECT-- Collected cycles: 0 Collected cycles: 2 ===DONE=== mongodb-1.21.0/tests/readPreference/bug1598-002.phpt0000644000175100001660000000135514760300421016516 0ustar --TEST-- PHPC-1598: ReadPreference get_gc should delegate to zend_std_get_properties --SKIPIF-- =', '8.1.99'); ?> --FILE-- rp = new MongoDB\Driver\ReadPreference('primary'); $a->rp->a = $a; printf("Collected cycles: %d\n", gc_collect_cycles()); unset($a); printf("Collected cycles: %d\n", gc_collect_cycles()); ?> ===DONE=== --EXPECT-- Collected cycles: 0 Collected cycles: 2 ===DONE=== mongodb-1.21.0/tests/readPreference/bug1698-001.phpt0000644000175100001660000000277714760300421016527 0ustar --TEST-- PHPC-1698: php_phongo_read_preference_prep_tagsets may leak in convert_to_object --FILE-- 'secondary', 'tags' => [['dc' => 'ny']]]; var_dump(MongoDB\Driver\ReadPreference::__set_state($args)); var_dump($args); $tagSets = [['dc' => 'ny']]; var_dump(new MongoDB\Driver\ReadPreference('secondary', $tagSets)); var_dump($tagSets); $uriTagSets = [['dc' => 'ny']]; var_dump((create_test_manager(null, ['readPreference' => 'secondary', 'readPreferenceTags' => $uriTagSets]))->getReadPreference()); var_dump($uriTagSets); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadPreference)#%d (2) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (1) { ["dc"]=> string(2) "ny" } } } array(2) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> array(1) { ["dc"]=> string(2) "ny" } } } object(MongoDB\Driver\ReadPreference)#%d (2) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (1) { ["dc"]=> string(2) "ny" } } } array(1) { [0]=> array(1) { ["dc"]=> string(2) "ny" } } object(MongoDB\Driver\ReadPreference)#%d (2) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (1) { ["dc"]=> string(2) "ny" } } } array(1) { [0]=> array(1) { ["dc"]=> string(2) "ny" } } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-bsonserialize-001.phpt0000644000175100001660000000275014760300421023232 0ustar --TEST-- MongoDB\Driver\ReadPreference::bsonSerialize() --FILE-- 'ny']]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => 1000]), ]; foreach ($tests as $test) { echo toJSON(fromPHP($test)), "\n"; } ?> ===DONE=== --EXPECTF-- { "mode" : "primary" } { "mode" : "primaryPreferred" } { "mode" : "secondary" } { "mode" : "secondaryPreferred" } { "mode" : "nearest" } { "mode" : "primary" } { "mode" : "secondary", "tags" : [ { "dc" : "ny" } ] } { "mode" : "secondary", "tags" : [ { "dc" : "ny" }, { "dc" : "sf", "use" : "reporting" }, { %w} ] } { "mode" : "secondary", "maxStalenessSeconds" : { "$numberInt" : "1000" } } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-bsonserialize-002.phpt0000644000175100001660000000421014760300421023224 0ustar --TEST-- MongoDB\Driver\ReadPreference::bsonSerialize() returns an object --FILE-- 'ny']]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => 1000]), ]; foreach ($tests as $test) { var_dump($test->bsonSerialize()); } ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["mode"]=> string(7) "primary" } object(stdClass)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } object(stdClass)#%d (%d) { ["mode"]=> string(9) "secondary" } object(stdClass)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } object(stdClass)#%d (%d) { ["mode"]=> string(7) "nearest" } object(stdClass)#%d (%d) { ["mode"]=> string(7) "primary" } object(stdClass)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } } } object(stdClass)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(3) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } [1]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "sf" ["use"]=> string(9) "reporting" } [2]=> object(stdClass)#%d (%d) { } } } object(stdClass)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-constants-001.phpt0000644000175100001660000000123414760300421022371 0ustar --TEST-- MongoDB\Driver\ReadPreference constants --FILE-- ===DONE=== --EXPECTF-- string(7) "primary" string(16) "primaryPreferred" string(9) "secondary" string(18) "secondaryPreferred" string(7) "nearest" int(-1) int(90) ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-constants-002.phpt0000644000175100001660000000176414760300421022402 0ustar --TEST-- MongoDB\Driver\ReadPreference deprecated constants --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- Deprecated: Constant MongoDB\Driver\ReadPreference::RP_PRIMARY is deprecated in %s int(1) Deprecated: Constant MongoDB\Driver\ReadPreference::RP_PRIMARY_PREFERRED is deprecated in %s int(5) Deprecated: Constant MongoDB\Driver\ReadPreference::RP_SECONDARY is deprecated in %s int(2) Deprecated: Constant MongoDB\Driver\ReadPreference::RP_SECONDARY_PREFERRED is deprecated in %s int(6) Deprecated: Constant MongoDB\Driver\ReadPreference::RP_NEAREST is deprecated in %s int(10) ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor-001.phpt0000644000175100001660000000276114760300421021332 0ustar --TEST-- MongoDB\Driver\ReadPreference construction --FILE-- 'one']])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY, [])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => 1000])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['hedge' => ['enabled' => true]])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['hedge' => []])); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["tag"]=> string(3) "one" } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["hedge"]=> object(stdClass)#%d (%d) { ["enabled"]=> bool(true) } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor-002.phpt0000644000175100001660000000406614760300421021333 0ustar --TEST-- MongoDB\Driver\ReadPreference construction with strings --FILE-- getMessage(), "\n"; } var_dump( $rp ); } ?> --EXPECTF-- object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "nearest" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "nearest" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "nearest" } mongodb-1.21.0/tests/readPreference/readpreference-ctor-003.phpt0000644000175100001660000000542614760300421021335 0ustar --TEST-- MongoDB\Driver\ReadPreference construction with integer constants (PHP < 8.3) --SKIPIF-- =', '8.3.0'); ?> --FILE-- 'one']])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY, [])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['maxStalenessSeconds' => 1000])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => ['enabled' => true]])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => []])); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["tag"]=> string(3) "one" } } } Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["hedge"]=> object(stdClass)#%d (%d) { ["enabled"]=> bool(true) } } Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor-004.phpt0000644000175100001660000000642414760300421021335 0ustar --TEST-- MongoDB\Driver\ReadPreference construction with integer constants (PHP 8.3+) --SKIPIF-- --FILE-- 'one']])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY, [])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['maxStalenessSeconds' => 1000])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => ['enabled' => true]])); var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => []])); ?> ===DONE=== --EXPECTF-- Deprecated: Constant MongoDB\Driver\ReadPreference::RP_PRIMARY is deprecated in %s Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } Deprecated: Constant MongoDB\Driver\ReadPreference::RP_SECONDARY is deprecated in %s Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["tag"]=> string(3) "one" } } } Deprecated: Constant MongoDB\Driver\ReadPreference::RP_PRIMARY is deprecated in %s Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } Deprecated: Constant MongoDB\Driver\ReadPreference::RP_SECONDARY is deprecated in %s Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } Deprecated: Constant MongoDB\Driver\ReadPreference::RP_SECONDARY is deprecated in %s Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["hedge"]=> object(stdClass)#%d (%d) { ["enabled"]=> bool(true) } } Deprecated: Constant MongoDB\Driver\ReadPreference::RP_SECONDARY is deprecated in %s Deprecated: MongoDB\Driver\ReadPreference::__construct(): Passing an integer mode to "MongoDB\Driver\ReadPreference::__construct" is deprecated and will be removed in a future release. in %s object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor_error-001.phpt0000644000175100001660000000061514760300421022537 0ustar --TEST-- MongoDB\Driver\ReadPreference construction (invalid mode) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Invalid mode: 'foo' ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor_error-002.phpt0000644000175100001660000000325514760300421022543 0ustar --TEST-- MongoDB\Driver\ReadPreference construction (invalid tagSets) --FILE-- 'one']]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { new MongoDB\Driver\ReadPreference("primary", [['tag' => 'one']]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY, ['invalid']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, ['invalid']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; // Ensure that tagSets is validated before maxStalenessSeconds option echo throws(function() { new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, ['invalid'], ['maxStalenessSeconds' => -2]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException tagSets may not be used with primary mode OK: Got MongoDB\Driver\Exception\InvalidArgumentException tagSets may not be used with primary mode OK: Got MongoDB\Driver\Exception\InvalidArgumentException tagSets must be an array of zero or more documents OK: Got MongoDB\Driver\Exception\InvalidArgumentException tagSets must be an array of zero or more documents OK: Got MongoDB\Driver\Exception\InvalidArgumentException tagSets must be an array of zero or more documents ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor_error-003.phpt0000644000175100001660000000333214760300421022540 0ustar --TEST-- MongoDB\Driver\ReadPreference construction (invalid maxStalenessSeconds) --FILE-- 1000]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { new MongoDB\Driver\ReadPreference("primary", null, ['maxStalenessSeconds' => 1000]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => -2]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => 0]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => 42]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException maxStalenessSeconds may not be used with primary mode OK: Got MongoDB\Driver\Exception\InvalidArgumentException maxStalenessSeconds may not be used with primary mode OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected maxStalenessSeconds to be >= 90, -2 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected maxStalenessSeconds to be >= 90, 0 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected maxStalenessSeconds to be >= 90, 42 given ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor_error-004.phpt0000644000175100001660000000116714760300421022545 0ustar --TEST-- MongoDB\Driver\ReadPreference construction (invalid maxStalenessSeconds range) --SKIPIF-- --FILE-- 2147483648]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected maxStalenessSeconds to be <= 2147483647, 2147483648 given ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor_error-005.phpt0000644000175100001660000000064214760300421022543 0ustar --TEST-- MongoDB\Driver\ReadPreference construction (invalid string mode) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Invalid mode: 'hocuspocus' ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor_error-006.phpt0000644000175100001660000000066414760300421022550 0ustar --TEST-- MongoDB\Driver\ReadPreference construction (invalid type for mode) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected mode to be integer or string, float given ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor_error-007.phpt0000644000175100001660000000101314760300421022536 0ustar --TEST-- MongoDB\Driver\ReadPreference construction (combining hedge with primary read preference) --FILE-- ['enabled' => true]]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException hedge may not be used with primary mode ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-ctor_error-008.phpt0000644000175100001660000000113614760300421022545 0ustar --TEST-- MongoDB\Driver\ReadPreference::__construct() prohibits PackedArray for hedge document --FILE-- MongoDB\BSON\PackedArray::fromPHP([])] ); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-debug-001.phpt0000644000175100001660000000507614760300421021453 0ustar --TEST-- MongoDB\Driver\ReadPreference debug output --FILE-- 'ny']]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => 1000]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['hedge' => ['enabled' => true]]), ]; foreach ($tests as $test) { var_dump($test); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "nearest" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(3) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } [1]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "sf" ["use"]=> string(9) "reporting" } [2]=> object(stdClass)#%d (%d) { } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["hedge"]=> object(stdClass)#%d (%d) { ["enabled"]=> bool(true) } } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-getHedge-001.phpt0000644000175100001660000000116414760300421022073 0ustar --TEST-- MongoDB\Driver\ReadPreference::getHedge() --FILE-- true], (object) ['enabled' => true], ['foo' => 'bar'], ]; foreach ($tests as $test) { $rp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['hedge' => $test]); var_dump($rp->getHedge()); } ?> ===DONE=== --EXPECTF-- NULL object(stdClass)#%d (%d) { ["enabled"]=> bool(true) } object(stdClass)#%d (%d) { ["enabled"]=> bool(true) } object(stdClass)#%d (%d) { ["foo"]=> string(3) "bar" } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-getMaxStalenessMS-001.phpt0000644000175100001660000000113414760300421023723 0ustar --TEST-- MongoDB\Driver\ReadPreference::getMaxStalenessSeconds() --FILE-- $test]); var_dump($rp->getMaxStalenessSeconds()); } ?> ===DONE=== --EXPECT-- int(-1) int(90) int(90) int(1000) int(2147483647) ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-getMaxStalenessMS-002.phpt0000644000175100001660000000112014760300421023717 0ustar --TEST-- MongoDB\Driver\ReadPreference::getMaxStalenessSeconds() with string mode --FILE-- $test]); var_dump($rp->getMaxStalenessSeconds()); } ?> ===DONE=== --EXPECT-- int(-1) int(90) int(90) int(1000) int(2147483647) ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-getMode-001.phpt0000644000175100001660000000162114760300421021741 0ustar --TEST-- MongoDB\Driver\ReadPreference::getMode() --FILE-- getMode()); } ?> ===DONE=== --EXPECTF-- Deprecated: %s MongoDB\Driver\ReadPreference::getMode() is deprecated in %s int(1) Deprecated: %s MongoDB\Driver\ReadPreference::getMode() is deprecated in %s int(5) Deprecated: %s MongoDB\Driver\ReadPreference::getMode() is deprecated in %s int(2) Deprecated: %s MongoDB\Driver\ReadPreference::getMode() is deprecated in %s int(6) Deprecated: %s MongoDB\Driver\ReadPreference::getMode() is deprecated in %s int(10) ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-getModeString-001.phpt0000644000175100001660000000116414760300421023132 0ustar --TEST-- MongoDB\Driver\ReadPreference::getModeString() --FILE-- getModeString()); } ?> ===DONE=== --EXPECT-- string(7) "primary" string(16) "primaryPreferred" string(9) "secondary" string(18) "secondaryPreferred" string(7) "nearest" ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-getTagSets-001.phpt0000644000175100001660000000132714760300421022432 0ustar --TEST-- MongoDB\Driver\ReadPreference::getTagSets() --FILE-- 'ny'], []], [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []], ]; foreach ($tests as $test) { $rp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY_PREFERRED, $test); var_dump($rp->getTagSets()); } ?> ===DONE=== --EXPECT-- array(0) { } array(0) { } array(2) { [0]=> array(1) { ["dc"]=> string(2) "ny" } [1]=> array(0) { } } array(3) { [0]=> array(1) { ["dc"]=> string(2) "ny" } [1]=> array(2) { ["dc"]=> string(2) "sf" ["use"]=> string(9) "reporting" } [2]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-getTagSets-002.phpt0000644000175100001660000000131214760300421022425 0ustar --TEST-- MongoDB\Driver\ReadPreference::getTagSets() with string mode --FILE-- 'ny'], []], [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []], ]; foreach ($tests as $test) { $rp = new MongoDB\Driver\ReadPreference("secondaryPreferred", $test); var_dump($rp->getTagSets()); } ?> ===DONE=== --EXPECT-- array(0) { } array(0) { } array(2) { [0]=> array(1) { ["dc"]=> string(2) "ny" } [1]=> array(0) { } } array(3) { [0]=> array(1) { ["dc"]=> string(2) "ny" } [1]=> array(2) { ["dc"]=> string(2) "sf" ["use"]=> string(9) "reporting" } [2]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-serialization-002.phpt0000644000175100001660000001203614760300421023235 0ustar --TEST-- MongoDB\Driver\ReadPreference serialization (__serialize and __unserialize) --FILE-- 'ny']]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => 1000]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['hedge' => ['enabled' => true]]), ]; foreach ($tests as $test) { var_dump($test); echo $s = serialize($test), "\n"; var_dump(unserialize($s)); echo "\n"; } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } O:29:"MongoDB\Driver\ReadPreference":1:{s:4:"mode";s:7:"primary";} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } O:29:"MongoDB\Driver\ReadPreference":1:{s:4:"mode";s:16:"primaryPreferred";} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } O:29:"MongoDB\Driver\ReadPreference":1:{s:4:"mode";s:9:"secondary";} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } O:29:"MongoDB\Driver\ReadPreference":1:{s:4:"mode";s:18:"secondaryPreferred";} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(18) "secondaryPreferred" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "nearest" } O:29:"MongoDB\Driver\ReadPreference":1:{s:4:"mode";s:7:"nearest";} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "nearest" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } O:29:"MongoDB\Driver\ReadPreference":1:{s:4:"mode";s:9:"secondary";} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } } } O:29:"MongoDB\Driver\ReadPreference":2:{s:4:"mode";s:9:"secondary";s:4:"tags";a:1:{i:0;O:8:"stdClass":1:{s:2:"dc";s:2:"ny";}}} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(3) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } [1]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "sf" ["use"]=> string(9) "reporting" } [2]=> object(stdClass)#%d (%d) { } } } O:29:"MongoDB\Driver\ReadPreference":2:{s:4:"mode";s:9:"secondary";s:4:"tags";a:3:{i:0;O:8:"stdClass":1:{s:2:"dc";s:2:"ny";}i:1;O:8:"stdClass":2:{s:2:"dc";s:2:"sf";s:3:"use";s:9:"reporting";}i:2;O:8:"stdClass":0:{}}} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["tags"]=> array(3) { [0]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "ny" } [1]=> object(stdClass)#%d (%d) { ["dc"]=> string(2) "sf" ["use"]=> string(9) "reporting" } [2]=> object(stdClass)#%d (%d) { } } } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } O:29:"MongoDB\Driver\ReadPreference":2:{s:4:"mode";s:9:"secondary";s:19:"maxStalenessSeconds";i:1000;} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["maxStalenessSeconds"]=> int(1000) } object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["hedge"]=> object(stdClass)#%d (%d) { ["enabled"]=> bool(true) } } O:29:"MongoDB\Driver\ReadPreference":2:{s:4:"mode";s:9:"secondary";s:5:"hedge";O:8:"stdClass":1:{s:7:"enabled";b:1;}} object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(9) "secondary" ["hedge"]=> object(stdClass)#%d (%d) { ["enabled"]=> bool(true) } } ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-serialization_error-001.phpt0000644000175100001660000000202014760300421024435 0ustar --TEST-- MongoDB\Driver\ReadPreference unserialization errors (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires specific values for "mode" string field OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "mode" field to be string ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-serialization_error-002.phpt0000644000175100001660000000201114760300421024436 0ustar --TEST-- MongoDB\Driver\ReadPreference unserialization errors (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires specific values for "mode" string field OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "mode" field to be string ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-set_state-001.phpt0000644000175100001660000000332214760300421022350 0ustar --TEST-- MongoDB\Driver\ReadPreference::__set_state() --FILE-- 'primary' ], [ 'mode' => 'primaryPreferred' ], [ 'mode' => 'secondary' ], [ 'mode' => 'secondaryPreferred' ], [ 'mode' => 'nearest' ], [ 'mode' => 'secondary', 'tags' => [['dc' => 'ny']] ], [ 'mode' => 'secondary', 'tags' => [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []] ], [ 'mode' => 'secondary', 'maxStalenessSeconds' => 1000 ], ]; foreach ($tests as $fields) { var_export(MongoDB\Driver\ReadPreference::__set_state($fields)); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'primary', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'primaryPreferred', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondary', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondaryPreferred', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'nearest', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondary', 'tags' =>%w array ( 0 =>%w (object) array( 'dc' => 'ny', ), ), )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondary', 'tags' =>%w array ( 0 =>%w (object) array( 'dc' => 'ny', ), 1 =>%w (object) array( 'dc' => 'sf', 'use' => 'reporting', ), 2 =>%w (object) array( ), ), )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondary', 'maxStalenessSeconds' => 1000, )) ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-set_state_error-001.phpt0000644000175100001660000000703414760300421023565 0ustar --TEST-- MongoDB\Driver\ReadPreference::__set_state() requires correct data types and values --FILE-- 'furthest']); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => M_PI]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => 'secondary', 'tags' => -1]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => 'secondary', 'tags' => [ 42 ] ]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => 'primary', 'tags' => [['dc' => 'ny']]]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => 'secondary', 'maxStalenessSeconds' => 1]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => 'primary', 'maxStalenessSeconds' => 100]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => 'secondary', 'hedge' => 'foo']); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => 'primary', 'hedge' => []]); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; echo throws(function() { MongoDB\Driver\ReadPreference::__set_state(['mode' => 'primaryPreferred', 'hedge' => MongoDB\BSON\PackedArray::fromPHP([])]); }, MongoDB\Driver\Exception\UnexpectedValueException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires specific values for "mode" string field OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "mode" field to be string OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "tags" field to be array OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "tags" array field to have zero or more documents OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "tags" array field to not be present with "primary" mode OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "maxStalenessSeconds" integer field to be >= 90 OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "maxStalenessSeconds" field to not be present with "primary" mode OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "hedge" field to be an array or object OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "hedge" field to not be present with "primary" mode OK: Got MongoDB\Driver\Exception\UnexpectedValueException MongoDB\BSON\PackedArray cannot be serialized as a root document ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-set_state_error-002.phpt0000644000175100001660000000122714760300421023564 0ustar --TEST-- MongoDB\Driver\ReadPreference::__set_state() requires correct data types and values --SKIPIF-- --FILE-- 'secondary', 'maxStalenessSeconds' => 2147483648]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ReadPreference initialization requires "maxStalenessSeconds" integer field to be <= 2147483647 ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference-var_export-001.phpt0000644000175100001660000000430114760300421022544 0ustar --TEST-- MongoDB\Driver\ReadPreference: var_export() --FILE-- 'ny']]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []]), new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY, null, ['maxStalenessSeconds' => 1000]), ]; foreach ($tests as $test) { echo var_export($test, true), "\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'primary', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'primaryPreferred', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondary', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondaryPreferred', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'nearest', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'primary', )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondary', 'tags' =>%w array ( 0 =>%w (object) array( 'dc' => 'ny', ), ), )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondary', 'tags' =>%w array ( 0 =>%w (object) array( 'dc' => 'ny', ), 1 =>%w (object) array( 'dc' => 'sf', 'use' => 'reporting', ), 2 =>%w (object) array( ), ), )) %r\\?%rMongoDB\Driver\ReadPreference::__set_state(array( 'mode' => 'secondary', 'maxStalenessSeconds' => 1000, )) ===DONE=== mongodb-1.21.0/tests/readPreference/readpreference_error-001.phpt0000644000175100001660000000043514760300421021572 0ustar --TEST-- MongoDB\Driver\ReadPreference cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyReadPreference %s final class %SMongoDB\Driver\ReadPreference%S in %s on line %d mongodb-1.21.0/tests/replicaset/bug0155.phpt0000644000175100001660000000142414760300421015421 0ustar --TEST-- PHPC-155: WriteConcernError->getInfo() can be scalar --SKIPIF-- --FILE-- insert(array('example' => 'document')); try { $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $wc]); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteConcernError()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcernError)#%d (%d) { ["message"]=> string(%d) "%s" ["code"]=> int(79) ["info"]=> %a } ===DONE=== mongodb-1.21.0/tests/replicaset/bug0898-001.phpt0000644000175100001660000000174514760300421015743 0ustar --TEST-- PHPC-898: readConcern option should not be included in getMore commands (URI option) --SKIPIF-- --FILE-- 'local']); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $result = $manager->executeBulkWrite(NS, $bulk); printf("Inserted %d document(s)\n", $result->getInsertedCount()); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query); foreach ($cursor as $document) { var_dump($document); } ?> ===DONE=== --EXPECTF-- Inserted 3 document(s) object(stdClass)#%d (1) { ["_id"]=> int(1) } object(stdClass)#%d (1) { ["_id"]=> int(2) } object(stdClass)#%d (1) { ["_id"]=> int(3) } ===DONE=== mongodb-1.21.0/tests/replicaset/bug0898-002.phpt0000644000175100001660000000204214760300421015733 0ustar --TEST-- PHPC-898: readConcern option should not be included in getMore commands (query option) --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $result = $manager->executeBulkWrite(NS, $bulk); printf("Inserted %d document(s)\n", $result->getInsertedCount()); $rc = new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::LOCAL); $query = new MongoDB\Driver\Query([], ['batchSize' => 2, 'readConcern' => $rc]); $cursor = $manager->executeQuery(NS, $query); foreach ($cursor as $document) { var_dump($document); } ?> ===DONE=== --EXPECTF-- Inserted 3 document(s) object(stdClass)#%d (1) { ["_id"]=> int(1) } object(stdClass)#%d (1) { ["_id"]=> int(2) } object(stdClass)#%d (1) { ["_id"]=> int(3) } ===DONE=== mongodb-1.21.0/tests/replicaset/manager-selectserver-001.phpt0000644000175100001660000000514414760300421020750 0ustar --TEST-- MongoDB\Driver\Manager::selectServer() select a server from SDAM based on ReadPreference --SKIPIF-- --FILE-- false, 'w' => 1]); $rp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY); $server = $manager->selectServer($rp); $rp2 = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY); $server2 = $manager->selectServer($rp2); // load fixtures for test $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1, 'x' => 2, 'y' => 3)); $bulk->insert(array('_id' => 2, 'x' => 3, 'y' => 4)); $bulk->insert(array('_id' => 3, 'x' => 4, 'y' => 5)); $server->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(array('x' => 3), array('projection' => array('y' => 1))); $cursor = $server->executeQuery(NS, $query); var_dump($cursor instanceof MongoDB\Driver\Cursor); var_dump($server == $cursor->getServer()); var_dump(iterator_to_array($cursor)); $query = new MongoDB\Driver\Query(array('x' => 3), array('projection' => array('y' => 1))); $cursor = $server2->executeQuery(NS, $query); var_dump($cursor instanceof MongoDB\Driver\Cursor); var_dump($server2 == $cursor->getServer()); var_dump(iterator_to_array($cursor)); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1, 'x' => 2, 'y' => 3)); $bulk->insert(array('_id' => 2, 'x' => 3, 'y' => 4)); $bulk->insert(array('_id' => 3, 'x' => 4, 'y' => 5)); throws(function() use($server2, $bulk) { $server2->executeBulkWrite(NS, $bulk); }, "MongoDB\Driver\Exception\BulkWriteException"); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1, 'x' => 2, 'y' => 3)); $bulk->insert(array('_id' => 2, 'x' => 3, 'y' => 4)); $bulk->insert(array('_id' => 3, 'x' => 4, 'y' => 5)); $result = $server2->executeBulkWrite('local.' . COLLECTION_NAME, $bulk); var_dump($result->getInsertedCount()); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["y"]=> int(4) } } bool(true) bool(true) array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["y"]=> int(4) } } OK: Got MongoDB\Driver\Exception\BulkWriteException int(3) ===DONE=== mongodb-1.21.0/tests/replicaset/readconcern-001.phpt0000644000175100001660000000242414760300421017113 0ustar --TEST-- ReadConcern: MongoDB\Driver\Manager::executeQuery() with readConcern option --SKIPIF-- --FILE-- insert(['_id' => 1, 'x' => 1]); $bulk->insert(['_id' => 2, 'x' => 2]); $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $wc]); $rc = new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::LOCAL); $query = new MongoDB\Driver\Query(['x' => 2], ['readConcern' => $rc]); $cursor = $manager->executeQuery(NS, $query); var_dump(iterator_to_array($cursor)); $rc = new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY); $query = new MongoDB\Driver\Query(['x' => 2], ['readConcern' => $rc]); $cursor = $manager->executeQuery(NS, $query); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["x"]=> int(2) } } array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["x"]=> int(2) } } ===DONE=== mongodb-1.21.0/tests/replicaset/writeconcernerror-001.phpt0000644000175100001660000000152314760300421020403 0ustar --TEST-- WriteConcernError: Populate WriteConcernError on WriteConcern errors --SKIPIF-- --FILE-- insert(array("my" => "value")); $w = new MongoDB\Driver\WriteConcern(30, 100); try { $retval = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $w]); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { $server = $e->getWriteResult()->getServer(); $server->getPort(); printWriteResult($e->getWriteResult(), false); } ?> ===DONE=== --EXPECTF-- server: %s:%d insertedCount: 1 matchedCount: 0 modifiedCount: 0 upsertedCount: 0 deletedCount: 0 writeConcernError: %s (%d) ===DONE=== mongodb-1.21.0/tests/replicaset/writeconcernerror-002.phpt0000644000175100001660000000205514760300421020405 0ustar --TEST-- WriteConcernError: Access write counts and WriteConcern reason --SKIPIF-- --FILE-- insert(array("my" => "value")); $bulk->insert(array("my" => "value", "foo" => "bar")); $bulk->insert(array("my" => "value", "foo" => "bar")); $bulk->delete(array("my" => "value", "foo" => "bar"), array("limit" => 1)); $bulk->update(array("foo" => "bar"), array('$set' => array("foo" => "baz")), array("limit" => 1, "upsert" => 0)); $w = new MongoDB\Driver\WriteConcern(30); try { $retval = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $w]); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { printWriteResult($e->getWriteResult(), false); } ?> ===DONE=== --EXPECTF-- server: %s:%d insertedCount: 3 matchedCount: 1 modifiedCount: 1 upsertedCount: 0 deletedCount: 1 writeConcernError: %s (%d) ===DONE=== mongodb-1.21.0/tests/replicaset/writeresult-getserver-001.phpt0000644000175100001660000000221014760300421021216 0ustar --TEST-- MongoDB\Driver\Server: Manager->getServer() returning correct server --SKIPIF-- --FILE-- "document"); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert($doc); $wresult = $manager->executeBulkWrite(NS, $bulk); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert($doc); /* writes go to the primary */ $server = $wresult->getServer(); /* This is the same server */ $server2 = $server->executeBulkWrite(NS, $bulk)->getServer(); /* Both are the primary, e.g. the same server */ var_dump($server == $server2); $rp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY); /* Fetch a secondary */ $server3 = $manager->executeQuery(NS, new MongoDB\Driver\Query([]), ['readPreference' => $rp])->getServer(); var_dump($server == $server3); var_dump($server->getPort(), $server3->getPort()); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) int(%d) int(%d) ===DONE=== mongodb-1.21.0/tests/replicaset/writeresult-getserver-002.phpt0000644000175100001660000000473614760300421021236 0ustar --TEST-- MongoDB\Driver\Server: Manager->getServer() returning correct server --SKIPIF-- --FILE-- false, 'w' => 1]); $doc = array("example" => "document"); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert($doc); $wresult = $manager->executeBulkWrite(NS, $bulk); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert($doc); /* writes go to the primary */ $server = $wresult->getServer(); /* This is the same server */ $server2 = $server->executeBulkWrite(NS, $bulk)->getServer(); /* Both are the primary, e.g. the same server */ var_dump($server == $server2); $rp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY); /* Fetch a secondary */ $server3 = $manager->executeQuery(NS, new MongoDB\Driver\Query([]), ['readPreference' => $rp])->getServer(); var_dump($server == $server3); var_dump($server->getPort(), $server3->getPort()); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert($doc); $result = $server3->executeBulkWrite('local.' . COLLECTION_NAME, $bulk); var_dump($result, $result->getServer()->getHost(), $result->getServer()->getPort()); $result = $server3->executeQuery('local.' . COLLECTION_NAME, new MongoDB\Driver\Query(array())); foreach($result as $document) { var_dump($document); } $cmd = new MongoDB\Driver\Command(['drop' => COLLECTION_NAME]); $server3->executeCommand("local", $cmd); ?> ===DONE=== --EXPECTF-- bool(true) bool(false) int(%d) int(%d) object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> int(1) ["nMatched"]=> int(0) ["nModified"]=> int(0) ["nRemoved"]=> int(0) ["nUpserted"]=> int(0) ["upsertedIds"]=> array(0) { } ["writeErrors"]=> array(0) { } ["writeConcernError"]=> NULL ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } ["errorReplies"]=> array(0) { } } string(%d) "%s" int(%d) object(stdClass)#%d (2) { ["_id"]=> object(%s\ObjectId)#%d (1) { ["oid"]=> string(24) "%s" } ["example"]=> string(8) "document" } ===DONE=== mongodb-1.21.0/tests/retryable-reads/retryable-reads-001.phpt0000644000175100001660000000357714760300421020661 0ustar --TEST-- Retryable reads: executeReadCommand is retried once --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, ['retryReads' => true]); // Select a specific server for future operations to avoid mongos switching in sharded clusters $server = $manager->selectServer(new \MongoDB\Driver\ReadPreference('primary')); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $server->executeBulkWrite(NS, $bulk); configureTargetedFailPoint($server, 'failCommand', ['times' => 1], ['failCommands' => ['aggregate'], 'closeConnection' => true]); $observer = new Observer; MongoDB\Driver\Monitoring\addSubscriber($observer); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$group' => ['_id' => 1, 'n' => ['$sum' => 1]]], ], 'cursor' => (object) [], ]); $cursor = $server->executeReadCommand(DATABASE_NAME, $command); var_dump(iterator_to_array($cursor)); MongoDB\Driver\Monitoring\removeSubscriber($observer); ?> ===DONE=== --EXPECTF-- Command started: aggregate Command started: aggregate array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["n"]=> int(2) } } ===DONE=== mongodb-1.21.0/tests/retryable-reads/retryable-reads-002.phpt0000644000175100001660000000312214760300421020644 0ustar --TEST-- Retryable reads: executeQuery is retried once --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, ['retryReads' => true]); // Select a specific server for future operations to avoid mongos switching in sharded clusters $server = $manager->selectServer(new \MongoDB\Driver\ReadPreference('primary')); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $server->executeBulkWrite(NS, $bulk); configureTargetedFailPoint($server, 'failCommand', ['times' => 1], ['failCommands' => ['find'], 'closeConnection' => true]); $observer = new Observer; MongoDB\Driver\Monitoring\addSubscriber($observer); $cursor = $server->executeQuery(NS, new \MongoDB\Driver\Query(['x' => 1])); var_dump(iterator_count($cursor)); MongoDB\Driver\Monitoring\removeSubscriber($observer); ?> ===DONE=== --EXPECT-- Command started: find Command started: find int(1) ===DONE=== mongodb-1.21.0/tests/retryable-reads/retryable-reads_error-001.phpt0000644000175100001660000000340314760300421022056 0ustar --TEST-- Retryable reads: executeReadCommand is not retried when retryable reads are disabled --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, ['retryReads' => false]); // Select a specific server for future operations to avoid mongos switching in sharded clusters $server = $manager->selectServer(new \MongoDB\Driver\ReadPreference('primary')); configureTargetedFailPoint($server, 'failCommand', ['times' => 1], ['failCommands' => ['aggregate'], 'closeConnection' => true]); $observer = new Observer; MongoDB\Driver\Monitoring\addSubscriber($observer); throws( function() use ($server) { $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$group' => ['_id' => 1, 'n' => ['$sum' => 1]]], ], 'cursor' => (object) [], ]); $server->executeReadCommand(DATABASE_NAME, $command); }, \MongoDB\Driver\Exception\ConnectionTimeoutException::class ); ?> ===DONE=== --EXPECT-- Command started: aggregate OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException ===DONE=== mongodb-1.21.0/tests/retryable-reads/retryable-reads_error-002.phpt0000644000175100001660000000300514760300421022055 0ustar --TEST-- Retryable reads: executeQuery is not retried when retryable reads are disabled --SKIPIF-- --FILE-- getCommandName()); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, ['retryReads' => false]); // Select a specific server for future operations to avoid mongos switching in sharded clusters $server = $manager->selectServer(new \MongoDB\Driver\ReadPreference('primary')); configureTargetedFailPoint($server, 'failCommand', ['times' => 1], ['failCommands' => ['find'], 'closeConnection' => true]); $observer = new Observer; MongoDB\Driver\Monitoring\addSubscriber($observer); throws( function() use ($server) { $server->executeQuery(NS, new \MongoDB\Driver\Query(['x' => 1])); }, \MongoDB\Driver\Exception\ConnectionTimeoutException::class ); ?> ===DONE=== --EXPECT-- Command started: find OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException ===DONE=== mongodb-1.21.0/tests/retryable-writes/retryable-writes-001.phpt0000644000175100001660000000456214760300421021312 0ustar --TEST-- Retryable writes: supported single-statement operations include transaction IDs --SKIPIF-- --FILE-- getCommand(); $hasTransactionId = isset($command->lsid) && isset($command->txnNumber); printf("%s command includes transaction ID: %s\n", $event->getCommandName(), $hasTransactionId ? 'yes' : 'no'); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $observer = new TransactionIdObserver; MongoDB\Driver\Monitoring\addSubscriber($observer); $manager = create_test_manager(); echo "Testing deleteOne\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->delete(['x' => 1], ['limit' => 1]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting insertOne\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting replaceOne\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['x' => 1], ['x' => 2]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting updateOne\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['x' => 1], ['$inc' => ['x' => 1]]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting findAndModify\n"; $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['x' => 1], 'update' => ['$inc' => ['x' => 1]], ]); $manager->executeReadWriteCommand(DATABASE_NAME, $command); MongoDB\Driver\Monitoring\removeSubscriber($observer); ?> ===DONE=== --EXPECT-- Testing deleteOne delete command includes transaction ID: yes Testing insertOne insert command includes transaction ID: yes Testing replaceOne update command includes transaction ID: yes Testing updateOne update command includes transaction ID: yes Testing findAndModify findAndModify command includes transaction ID: yes ===DONE=== mongodb-1.21.0/tests/retryable-writes/retryable-writes-002.phpt0000644000175100001660000000540514760300421021310 0ustar --TEST-- Retryable writes: supported multi-statement operations include transaction IDs --SKIPIF-- --FILE-- getCommand(); $hasTransactionId = isset($command->lsid) && isset($command->txnNumber); printf("%s command includes transaction ID: %s\n", $event->getCommandName(), $hasTransactionId ? 'yes' : 'no'); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $observer = new TransactionIdObserver; MongoDB\Driver\Monitoring\addSubscriber($observer); $manager = create_test_manager(); echo "Testing multi-statement bulk write (ordered=true)\n"; $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]); $bulk->delete(['x' => 1], ['limit' => 1]); $bulk->insert(['x' => 1]); $bulk->update(['x' => 1], ['$inc' => ['x' => 1]]); $bulk->update(['x' => 1], ['x' => 2]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting multi-statement bulk write (ordered=false)\n"; $bulk = new MongoDB\Driver\BulkWrite(['ordered' => false]); $bulk->delete(['x' => 1], ['limit' => 1]); $bulk->insert(['x' => 1]); $bulk->update(['x' => 1], ['$inc' => ['x' => 1]]); $bulk->update(['x' => 1], ['x' => 2]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting insertMany (ordered=true)\n"; $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting insertMany (ordered=false)\n"; $bulk = new MongoDB\Driver\BulkWrite(['ordered' => false]); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $manager->executeBulkWrite(NS, $bulk); MongoDB\Driver\Monitoring\removeSubscriber($observer); ?> ===DONE=== --EXPECT-- Testing multi-statement bulk write (ordered=true) delete command includes transaction ID: yes insert command includes transaction ID: yes update command includes transaction ID: yes Testing multi-statement bulk write (ordered=false) delete command includes transaction ID: yes insert command includes transaction ID: yes update command includes transaction ID: yes Testing insertMany (ordered=true) insert command includes transaction ID: yes Testing insertMany (ordered=false) insert command includes transaction ID: yes ===DONE=== mongodb-1.21.0/tests/retryable-writes/retryable-writes-003.phpt0000644000175100001660000000642314760300421021312 0ustar --TEST-- Retryable writes: unsupported operations do not include transaction IDs --SKIPIF-- --FILE-- getCommand(); $hasTransactionId = isset($command->lsid) && isset($command->txnNumber); printf("%s command includes transaction ID: %s\n", $event->getCommandName(), $hasTransactionId ? 'yes' : 'no'); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $observer = new TransactionIdObserver; MongoDB\Driver\Monitoring\addSubscriber($observer); $manager = create_test_manager(); echo "Testing deleteMany\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->delete(['x' => 1], ['limit' => 0]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting updateMany\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['x' => 1], ['$inc' => ['x' => 1]], ['multi' => true]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting multi-statement bulk write with one unsupported operation (ordered=true)\n"; $bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]); $bulk->delete(['x' => 1], ['limit' => 1]); $bulk->insert(['x' => 1]); $bulk->update(['x' => 1], ['$inc' => ['x' => 1]]); $bulk->update(['x' => 1], ['x' => 2]); $bulk->update(['x' => 1], ['$inc' => ['x' => 1]], ['multi' => true]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting multi-statement bulk write with one unsupported operation (ordered=false)\n"; $bulk = new MongoDB\Driver\BulkWrite(['ordered' => false]); $bulk->delete(['x' => 1], ['limit' => 1]); $bulk->insert(['x' => 1]); $bulk->update(['x' => 1], ['$inc' => ['x' => 1]]); $bulk->update(['x' => 1], ['x' => 2]); $bulk->update(['x' => 1], ['$inc' => ['x' => 1]], ['multi' => true]); $manager->executeBulkWrite(NS, $bulk); echo "\nTesting aggregate\n"; $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$match' => ['x' => 1]], ['$out' => COLLECTION_NAME . '.out'], ], 'cursor' => new stdClass, ]); $manager->executeReadWriteCommand(DATABASE_NAME, $command); MongoDB\Driver\Monitoring\removeSubscriber($observer); ?> ===DONE=== --EXPECT-- Testing deleteMany delete command includes transaction ID: no Testing updateMany update command includes transaction ID: no Testing multi-statement bulk write with one unsupported operation (ordered=true) delete command includes transaction ID: yes insert command includes transaction ID: yes update command includes transaction ID: no Testing multi-statement bulk write with one unsupported operation (ordered=false) delete command includes transaction ID: yes insert command includes transaction ID: yes update command includes transaction ID: no Testing aggregate aggregate command includes transaction ID: no ===DONE=== mongodb-1.21.0/tests/retryable-writes/retryable-writes-004.phpt0000644000175100001660000000572214760300421021314 0ustar --TEST-- Retryable writes: unacknowledged write operations do not include transaction IDs --SKIPIF-- --FILE-- getCommand(); $hasTransactionId = isset($command->lsid) && isset($command->txnNumber); printf("%s command includes transaction ID: %s\n", $event->getCommandName(), $hasTransactionId ? 'yes' : 'no'); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $observer = new TransactionIdObserver; MongoDB\Driver\Monitoring\addSubscriber($observer); $manager = create_test_manager(); $writeConcern = new MongoDB\Driver\WriteConcern(0); echo "Testing unacknowledged deleteOne\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->delete(['x' => 1], ['limit' => 1]); $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $writeConcern]); echo "\nTesting unacknowledged insertOne\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $writeConcern]); echo "\nTesting unacknowledged replaceOne\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['x' => 1], ['x' => 2]); $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $writeConcern]); echo "\nTesting unacknowledged updateOne\n"; $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['x' => 1], ['$inc' => ['x' => 1]]); $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $writeConcern]); /* Note: the server does not actually support unacknowledged write concerns for * findAndModify. This is just testing that mongoc_cmd_parts_set_write_concern() * in libmongoc detects w:0 and refrains from adding a transaction ID. */ echo "\nTesting unacknowledged findAndModify\n"; $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['x' => 1], 'update' => ['$inc' => ['x' => 1]], ]); $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['writeConcern' => $writeConcern]); MongoDB\Driver\Monitoring\removeSubscriber($observer); ?> ===DONE=== --EXPECT-- Testing unacknowledged deleteOne delete command includes transaction ID: no Testing unacknowledged insertOne insert command includes transaction ID: no Testing unacknowledged replaceOne update command includes transaction ID: no Testing unacknowledged updateOne update command includes transaction ID: no Testing unacknowledged findAndModify findAndModify command includes transaction ID: no ===DONE=== mongodb-1.21.0/tests/retryable-writes/retryable-writes-005.phpt0000644000175100001660000000421214760300421021306 0ustar --TEST-- Retryable writes: non-write command methods do not include transaction IDs --SKIPIF-- --FILE-- getCommand(); $hasTransactionId = isset($command->lsid) && isset($command->txnNumber); printf("%s command includes transaction ID: %s\n", $event->getCommandName(), $hasTransactionId ? 'yes' : 'no'); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $observer = new TransactionIdObserver; MongoDB\Driver\Monitoring\addSubscriber($observer); $manager = create_test_manager(); $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['x' => 1], 'update' => ['$inc' => ['x' => 1]], ]); echo "Testing Manager::executeCommand()\n"; $manager->executeCommand(DATABASE_NAME, $command); echo "\nTesting Manager::executeReadCommand()\n"; $manager->executeReadCommand(DATABASE_NAME, $command); echo "\nTesting Manager::executeReadWriteCommand()\n"; $manager->executeReadWriteCommand(DATABASE_NAME, $command); echo "\nTesting Manager::executeWriteCommand()\n"; $manager->executeWriteCommand(DATABASE_NAME, $command); MongoDB\Driver\Monitoring\removeSubscriber($observer); ?> ===DONE=== --EXPECT-- Testing Manager::executeCommand() findAndModify command includes transaction ID: no Testing Manager::executeReadCommand() findAndModify command includes transaction ID: no Testing Manager::executeReadWriteCommand() findAndModify command includes transaction ID: yes Testing Manager::executeWriteCommand() findAndModify command includes transaction ID: yes ===DONE=== mongodb-1.21.0/tests/retryable-writes/retryable-writes_error-001.phpt0000644000175100001660000000217014760300421022514 0ustar --TEST-- Retryable writes: actionable error message when using retryable writes on unsupported storage engines --SKIPIF-- --FILE-- startSession(); echo throws( function() use ($manager, $session) { $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['x' => 1], 'update' => ['$inc' => ['x' => 1]], ]); $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => $session]); }, \MongoDB\Driver\Exception\CommandException::class ); echo "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\CommandException This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string. ===DONE=== mongodb-1.21.0/tests/server/bug0671-002.phpt0000644000175100001660000000123514760300421015076 0ustar --TEST-- PHPC-671: Segfault if Manager is already freed when using selected Server --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); unset($manager); $cursor = $server->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["ok"]=> float(1)%A } ===DONE=== mongodb-1.21.0/tests/server/server-constants.phpt0000644000175100001660000000125214760300421017023 0ustar --TEST-- MongoDB\Driver\Server constants --FILE-- ===DONE=== --EXPECT-- int(0) int(1) int(2) int(3) int(4) int(5) int(6) int(7) int(8) int(9) ===DONE=== mongodb-1.21.0/tests/server/server-construct-001.phpt0000644000175100001660000000161414760300421017333 0ustar --TEST-- MongoDB\Driver\Server::__construct() --SKIPIF-- --FILE-- getInfo()['me'] : URI; $parsed = parse_url($uri); $manager = create_test_manager(); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array('foo' => 'bar')); $server = $manager->executeBulkWrite(NS, $bulk)->getServer(); $expectedHost = $parsed['host']; $expectedPort = (integer) (isset($parsed['port']) ? $parsed['port'] : 27017); var_dump($server->getHost() == $expectedHost); var_dump($server->getPort() == $expectedPort); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/server/server-debug.phpt0000644000175100001660000000141514760300421016076 0ustar --TEST-- MongoDB\Driver\Server debug output --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); var_dump($server); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Server)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["type"]=> int(%d) ["is_primary"]=> bool(%s) ["is_secondary"]=> bool(%s) ["is_arbiter"]=> bool(false) ["is_hidden"]=> bool(false) ["is_passive"]=> bool(false)%A ["last_hello_response"]=> array(%d) { %a } ["round_trip_time"]=> %r(NULL|int\(\d+\))%r } ===DONE=== mongodb-1.21.0/tests/server/server-errors.phpt0000644000175100001660000000462114760300421016326 0ustar --TEST-- MongoDB\Driver\Server argument count errors --SKIPIF-- =', '7.99'); ?> --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); $methods = [ 'getHost', 'getTags', 'getInfo', 'getLatency', 'getPort', 'getType', 'isPrimary', 'isSecondary', 'isArbiter', 'isHidden', 'isPassive', ]; foreach ($methods as $method) { echo throws(function() use ($server, $method) { $server->{$method}(true); }, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::getHost() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::getTags() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::getInfo() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::getLatency() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::getPort() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::getType() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::isPrimary() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::isSecondary() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::isArbiter() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::isHidden() expects exactly 0 %r(argument|parameter)%rs, 1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\Server::isPassive() expects exactly 0 %r(argument|parameter)%rs, 1 given ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-001.phpt0000644000175100001660000000377314760300421020612 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 2)); $bulk->update(array('x' => 2), array('$set' => array('x' => 1)), array("limit" => 1, "upsert" => false)); $bulk->update(array('_id' => 3), array('$set' => array('x' => 3)), array("limit" => 1, "upsert" => true)); $bulk->delete(array('x' => 1), array("limit" => 1)); $result = $server->executeBulkWrite(NS, $bulk); printf("WriteResult.server is the same: %s\n", $server == $result->getServer() ? 'yes' : 'no'); echo "\n===> WriteResult\n"; printWriteResult($result); var_dump($result); echo "\n===> Collection\n"; $cursor = $server->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- WriteResult.server is the same: yes ===> WriteResult server: %s:%d insertedCount: 2 matchedCount: 1 modifiedCount: 1 upsertedCount: 1 deletedCount: 1 upsertedId[3]: int(3) object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> int(2) ["nMatched"]=> int(1) ["nModified"]=> int(1) ["nRemoved"]=> int(1) ["nUpserted"]=> int(1) ["upsertedIds"]=> array(1) { [0]=> array(%d) { ["index"]=> int(3) ["_id"]=> int(3) } } ["writeErrors"]=> array(0) { } ["writeConcernError"]=> NULL ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { } ["errorReplies"]=> array(0) { } } ===> Collection array(2) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) ["x"]=> int(1) } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(3) ["x"]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-002.phpt0000644000175100001660000000210714760300421020601 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() with write concern (standalone) --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); $writeConcerns = array(0, 1); foreach ($writeConcerns as $writeConcern) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array('wc' => $writeConcern)); $result = $primary->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern($writeConcern)]); var_dump($result->isAcknowledged()); var_dump($result->getInsertedCount()); } ?> ===DONE=== --EXPECTF-- bool(false) Deprecated: MongoDB\Driver\WriteResult::getInsertedCount(): Calling MongoDB\Driver\WriteResult::getInsertedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL bool(true) int(1) ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-003.phpt0000644000175100001660000000226714760300421020611 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() with legacy write concern (replica set primary) --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); $writeConcerns = array(0, 1, 2, MongoDB\Driver\WriteConcern::MAJORITY); foreach ($writeConcerns as $wc) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array('wc' => $wc)); $result = $server->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern($wc)]); var_dump($result->isAcknowledged()); var_dump($result->getInsertedCount()); } ?> ===DONE=== --EXPECTF-- bool(false) Deprecated: MongoDB\Driver\WriteResult::getInsertedCount(): Calling MongoDB\Driver\WriteResult::getInsertedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL bool(true) int(1) bool(true) int(1) bool(true) int(1) ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-004.phpt0000644000175100001660000000252314760300421020605 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() with legacy write concern (replica set secondary) --SKIPIF-- --FILE-- false]); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY)); $writeConcerns = array(1, 2, MongoDB\Driver\WriteConcern::MAJORITY); foreach ($writeConcerns as $wc) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array('wc' => $wc)); echo throws(function() use ($server, $bulk, $wc) { $server->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern($wc)]); }, "MongoDB\Driver\Exception\RuntimeException"), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\RuntimeException not %r(primary|master)%r OK: Got MongoDB\Driver\Exception\RuntimeException not %r(primary|master)%r OK: Got MongoDB\Driver\Exception\RuntimeException not %r(primary|master)%r ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-005.phpt0000644000175100001660000000332014760300421020602 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() with write concern (replica set secondary, local DB) --SKIPIF-- =', '6.2'); /* TODO: Remove this when addressing PHPC-2121 */ ?> --FILE-- false, 'w' => 1]); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY)); /* The server ignores write concerns with w>2 for writes to the local database, * so we won't test behavior for w=2 and w=majority. */ $writeConcerns = array(0, 1); foreach ($writeConcerns as $wc) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(array('wc' => $wc)); $result = $server->executeBulkWrite('local.' . COLLECTION_NAME, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern($wc)]); var_dump($result->isAcknowledged()); var_dump($result->getInsertedCount()); } $bulk = new MongoDB\Driver\BulkWrite(); $bulk->delete( (object) [] ); $server->executeBulkWrite('local.' . COLLECTION_NAME, $bulk); ?> ===DONE=== --EXPECTF-- bool(false) Deprecated: MongoDB\Driver\WriteResult::getInsertedCount(): Calling MongoDB\Driver\WriteResult::getInsertedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL bool(true) int(1) ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-006.phpt0000644000175100001660000000232614760300421020610 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() with legacy write concern (replica set primary) --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); $writeConcerns = [0, 1, 2, MongoDB\Driver\WriteConcern::MAJORITY]; foreach ($writeConcerns as $wc) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['wc' => $wc]); $options = [ 'writeConcern' => new MongoDB\Driver\WriteConcern($wc), ]; $result = $server->executeBulkWrite(NS, $bulk, $options); var_dump($result->isAcknowledged()); var_dump($result->getInsertedCount()); } ?> ===DONE=== --EXPECTF-- bool(false) Deprecated: MongoDB\Driver\WriteResult::getInsertedCount(): Calling MongoDB\Driver\WriteResult::getInsertedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL bool(true) int(1) bool(true) int(1) bool(true) int(1) ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-007.phpt0000644000175100001660000000256014760300421020611 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() with write concern (replica set secondary) --SKIPIF-- --FILE-- false]); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY)); $writeConcerns = [1, 2, MongoDB\Driver\WriteConcern::MAJORITY]; foreach ($writeConcerns as $wc) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['wc' => $wc]); $options = [ 'writeConcern' => new MongoDB\Driver\WriteConcern($wc), ]; echo throws(function() use ($server, $bulk, $options) { $server->executeBulkWrite(NS, $bulk, $options); }, "MongoDB\Driver\Exception\RuntimeException"), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\RuntimeException not %r(primary|master)%r OK: Got MongoDB\Driver\Exception\RuntimeException not %r(primary|master)%r OK: Got MongoDB\Driver\Exception\RuntimeException not %r(primary|master)%r ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-008.phpt0000644000175100001660000000421414760300421020610 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $servers = $manager->getServers(); $selectedServer = array_pop($servers); $wrongServer = array_pop($servers); var_dump($selectedServer != $wrongServer); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() == $selectedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); echo throws(function () use ($wrongServer, $session) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $wrongServer->executeBulkWrite(NS, $bulk, ['session' => $session]); }, \MongoDB\Driver\Exception\BulkWriteException::class), "\n"; $session->commitTransaction(); var_dump($session->getServer() == $selectedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) OK: Got MongoDB\Driver\Exception\BulkWriteException Bulk write failed due to previous MongoDB\Driver\Exception\RuntimeException: Requested server id does not matched pinned server id bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-009.phpt0000644000175100001660000000210614760300421020607 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() write concern inheritance --SKIPIF-- --FILE-- 2, 'wtimeoutms' => 1000]); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference('primary')); (new CommandObserver)->observe( function() use ($server) { $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $server->executeBulkWrite(NS, $bulk); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $server->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(1)]); }, function(stdClass $command) { echo json_encode($command->writeConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"w":2,"wtimeout":1000} {"w":1} ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite-010.phpt0000644000175100001660000000130514760300421020577 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() explicit WriteConcern argument is deprecated --SKIPIF-- --FILE-- selectServer(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1]); $server->executeBulkWrite(NS, $bulk, new MongoDB\Driver\WriteConcern(0)); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Server::executeBulkWrite(): Passing the "writeConcern" option directly is deprecated and will be removed in ext-mongodb 2.0%s ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite_error-001.phpt0000644000175100001660000000131414760300421022010 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() with empty BulkWrite --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); echo throws(function() use ($server) { $server->executeBulkWrite(NS, new MongoDB\Driver\BulkWrite); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot do an empty bulk write ===DONE=== mongodb-1.21.0/tests/server/server-executeBulkWrite_error-002.phpt0000644000175100001660000000364214760300421022017 0ustar --TEST-- MongoDB\Driver\Server::executeBulkWrite() with invalid options --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); echo throws(function() use ($server) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $server->executeBulkWrite(NS, $bulk, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $server->executeBulkWrite(NS, $bulk, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $server->executeBulkWrite(NS, $bulk, ['writeConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $server->executeBulkWrite(NS, $bulk, ['writeConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-001.phpt0000644000175100001660000000244414760300421020252 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); $command = new MongoDB\Driver\Command(array('ping' => 1)); $result = $server->executeCommand(DATABASE_NAME, $command); var_dump($result instanceof MongoDB\Driver\Cursor); var_dump($result); echo "\nDumping response document:\n"; var_dump(current($result->toArray())); var_dump($server == $result->getServer()); ?> ===DONE=== --EXPECTF-- bool(true) object(MongoDB\Driver\Cursor)#%d (%d) { ["database"]=> string(6) "phongo" ["collection"]=> NULL ["query"]=> NULL ["command"]=> object(MongoDB\Driver\Command)#%d (%d) { ["command"]=> object(stdClass)#%d (%d) { ["ping"]=> int(1) } } ["readPreference"]=> NULL ["session"]=> %a ["isDead"]=> bool(false) ["currentIndex"]=> int(0) ["currentDocument"]=> NULL ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } } Dumping response document: object(stdClass)#%d (%d) { ["ok"]=> float(1)%A } bool(true) ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-002.phpt0000644000175100001660000000406714760300421020256 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() takes a read preference --SKIPIF-- --FILE-- selectServer($rp); $command = new MongoDB\Driver\Command(array('profile' => 2)); $cursor = $secondary->executeCommand(DATABASE_NAME, $command); $result = current($cursor->toArray()); printf("Set profile level to 2 successfully: %s\n", (empty($result->ok) ? 'no' : 'yes')); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ [ '$match' => [ 'x' => 1 ] ] ], 'cursor' => (object) [], ]); $secondary->executeCommand(DATABASE_NAME, $command, ['readPreference' => $rp]); $query = new MongoDB\Driver\Query( array( 'op' => 'command', 'ns' => DATABASE_NAME . '.' . COLLECTION_NAME, ), array( 'sort' => array('ts' => -1), 'limit' => 1, ) ); $cursor = $secondary->executeQuery(DATABASE_NAME . '.system.profile', $query, ['readPreference' => $rp]); $profileEntry = current($cursor->toArray()); var_dump($profileEntry->command); $command = new MongoDB\Driver\Command(array('profile' => 0)); $cursor = $secondary->executeCommand(DATABASE_NAME, $command); $result = current($cursor->toArray()); printf("Set profile level to 0 successfully: %s\n", (empty($result->ok) ? 'no' : 'yes')); ?> ===DONE=== --EXPECTF-- Set profile level to 2 successfully: yes object(stdClass)#%d (%d) { ["aggregate"]=> string(32) "server_server_executeCommand_002" ["pipeline"]=> array(1) { [0]=> object(stdClass)#%d (%d) { ["$match"]=> object(stdClass)#%d (%d) { ["x"]=> int(1) } } } ["cursor"]=> object(stdClass)#%d (%d) { }%A } Set profile level to 0 successfully: yes ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-003.phpt0000644000175100001660000000204314760300421020247 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() with conflicting read preference for secondary --SKIPIF-- --FILE-- selectServer($secondaryRp); /* Note: this is testing that the read preference (even a conflicting one) has * no effect when directly querying a server, since the secondaryOk flag is always * set for hinted commands. */ $primaryRp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY); $cursor = $secondary->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(array('ping' => 1)), ['readPreference' => $primaryRp]); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- array(1) { [0]=> object(stdClass)#%d (%d) { ["ok"]=> float(1)%A } } ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-004.phpt0000644000175100001660000000273614760300421020261 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() takes a read preference in options array --SKIPIF-- --FILE-- selectServer($primaryRp); $secondary = $manager->selectServer($secondaryRp); echo "Testing primary:\n"; $command = new MongoDB\Driver\Command(['ping' => 1]); $cursor = $primary->executeCommand(DATABASE_NAME, $command, ['readPreference' => $primaryRp]); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; echo "Testing secondary:\n"; $command = new MongoDB\Driver\Command(['ping' => 1]); $cursor = $secondary->executeCommand(DATABASE_NAME, $command, ['readPreference' => $secondaryRp]); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- Testing primary: is_primary: true is_secondary: false Testing secondary: is_primary: false is_secondary: true ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-005.phpt0000644000175100001660000000334614760300421020260 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() takes a read preference as legacy option --SKIPIF-- --FILE-- selectServer($primaryRp); $secondary = $manager->selectServer($secondaryRp); echo "Testing primary:\n"; $command = new MongoDB\Driver\Command(['ping' => 1]); $cursor = $primary->executeCommand(DATABASE_NAME, $command, $primaryRp); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; echo "Testing secondary:\n"; $command = new MongoDB\Driver\Command(['ping' => 1]); $cursor = $secondary->executeCommand(DATABASE_NAME, $command, $secondaryRp); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- Testing primary: Deprecated: MongoDB\Driver\Server::executeCommand(): Passing the "readPreference" option directly is deprecated and will be removed in ext-mongodb 2.0%s is_primary: true is_secondary: false Testing secondary: Deprecated: MongoDB\Driver\Server::executeCommand(): Passing the "readPreference" option directly is deprecated and will be removed in ext-mongodb 2.0%s is_primary: false is_secondary: true ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-006.phpt0000644000175100001660000000314414760300421020255 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() options (MONGO_CMD_RAW) --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); (new CommandObserver)->observe( function() use ($server) { $command = new MongoDB\Driver\Command([ 'ping' => true, ]); try { $server->executeCommand( DATABASE_NAME, $command, [ 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::SECONDARY), 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::LOCAL), 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY), ] ); } catch ( Exception $e ) { // Ignore exception that ping doesn't support writeConcern } }, function(stdClass $command) { echo "Read Preference: ", $command->{'$readPreference'}->mode, "\n"; echo "Read Concern: ", $command->readConcern->level, "\n"; echo "Write Concern: ", $command->writeConcern->w, "\n"; } ); ?> ===DONE=== --EXPECTF-- Read Preference: secondary Read Concern: local Write Concern: majority ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-007.phpt0000644000175100001660000000172014760300421020254 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() sends read preference to mongos --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); (new CommandObserver)->observe( function() use ($server) { $server->executeCommand( DATABASE_NAME, new MongoDB\Driver\Command(['ping' => true]), [ 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::NEAREST), ] ); }, function(stdClass $command) { echo "Read Preference: ", $command->{'$readPreference'}->mode, "\n"; } ); ?> ===DONE=== --EXPECTF-- Read Preference: nearest ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-008.phpt0000644000175100001660000000322714760300421020261 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() does not send read preference to standalone --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); (new CommandObserver)->observe( function() use ($server) { $command = new MongoDB\Driver\Command([ 'ping' => true, ]); try { $server->executeCommand( DATABASE_NAME, $command, [ 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::SECONDARY), 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::LOCAL), 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY), ] ); } catch ( Exception $e ) { // Ignore exception that ping doesn't support writeConcern } }, function(stdClass $command) { echo isset($command->{'$readPreference'}) ? 'Read preference set' : 'No read preference set', "\n"; echo "Read Concern: ", $command->readConcern->level, "\n"; echo "Write Concern: ", $command->writeConcern->w, "\n"; } ); ?> ===DONE=== --EXPECTF-- No read preference set Read Concern: local Write Concern: majority ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-009.phpt0000644000175100001660000000441714760300421020264 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $servers = $manager->getServers(); $selectedServer = array_pop($servers); $wrongServer = array_pop($servers); var_dump($selectedServer != $wrongServer); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [] ]); $selectedServer->executeCommand(DATABASE_NAME, $command, ['session' => $session]); var_dump($session->getServer() == $selectedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); echo throws(function () use ($wrongServer, $session) { $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [] ]); $wrongServer->executeCommand(DATABASE_NAME, $command, ['session' => $session]); }, \MongoDB\Driver\Exception\RuntimeException::class), "\n"; $session->commitTransaction(); var_dump($session->getServer() == $selectedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) OK: Got MongoDB\Driver\Exception\RuntimeException Requested server id does not matched pinned server id bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand-010.phpt0000644000175100001660000000262414760300421020252 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() does not inherit read or write concern --SKIPIF-- --FILE-- 'local', 'w' => 2, 'wtimeoutms' => 1000]); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference('primary')); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$group' => ['_id' => 1]], ['$out' => COLLECTION_NAME . '.out'], ], 'cursor' => (object) [], ]); (new CommandObserver)->observe( function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command); $server->executeCommand(DATABASE_NAME, $command, [ 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::AVAILABLE), 'writeConcern' => new MongoDB\Driver\WriteConcern(1), ]); }, function(stdClass $command) { echo json_encode($command->readConcern ?? null), "\n"; echo json_encode($command->writeConcern ?? null), "\n"; } ); ?> ===DONE=== --EXPECT-- null null {"level":"available"} {"w":1} ===DONE=== mongodb-1.21.0/tests/server/server-executeCommand_error-001.phpt0000644000175100001660000000613014760300421021457 0ustar --TEST-- MongoDB\Driver\Server::executeCommand() with invalid options (MONGOC_CMD_RAW) --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); $command = new MongoDB\Driver\Command(['ping' => 1]); echo throws(function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command, ['readConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command, ['readConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command, ['readPreference' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command, ['readPreference' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command, ['writeConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeCommand(DATABASE_NAME, $command, ['writeConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-001.phpt0000644000175100001660000000211614760300421017775 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() with filter and projection --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); // load fixtures for test $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1, 'x' => 2, 'y' => 3)); $bulk->insert(array('_id' => 2, 'x' => 3, 'y' => 4)); $bulk->insert(array('_id' => 3, 'x' => 4, 'y' => 5)); $server->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(array('x' => 3), array('projection' => array('y' => 1))); $cursor = $server->executeQuery(NS, $query); var_dump($cursor instanceof MongoDB\Driver\Cursor); var_dump($server == $cursor->getServer()); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) array(1) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["y"]=> int(4) } } ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-002.phpt0000644000175100001660000000247014760300421020001 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() with sort and empty filter --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); // load fixtures for test $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1, 'x' => 2, 'y' => 3)); $bulk->insert(array('_id' => 2, 'x' => 3, 'y' => 4)); $bulk->insert(array('_id' => 3, 'x' => 4, 'y' => 5)); $server->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(array(), array('sort' => array('_id' => -1))); $cursor = $server->executeQuery(NS, $query); var_dump($cursor instanceof MongoDB\Driver\Cursor); var_dump($server == $cursor->getServer()); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) array(3) { [0]=> object(stdClass)#%d (3) { ["_id"]=> int(3) ["x"]=> int(4) ["y"]=> int(5) } [1]=> object(stdClass)#%d (3) { ["_id"]=> int(2) ["x"]=> int(3) ["y"]=> int(4) } [2]=> object(stdClass)#%d (3) { ["_id"]=> int(1) ["x"]=> int(2) ["y"]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-003.phpt0000644000175100001660000000273114760300421020002 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() with modifiers and empty filter --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); // load fixtures for test $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1, 'x' => 2, 'y' => 3)); $bulk->insert(array('_id' => 2, 'x' => 3, 'y' => 4)); $bulk->insert(array('_id' => 3, 'x' => 4, 'y' => 5)); $server->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query(array(), array('modifiers' => array('$comment' => 'foo'))); $cursor = $server->executeQuery(NS, $query); var_dump($cursor instanceof MongoDB\Driver\Cursor); var_dump($server == $cursor->getServer()); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): The "modifiers" option is deprecated and will be removed in a future release in %s on line %d bool(true) bool(true) array(3) { [0]=> object(stdClass)#%d (3) { ["_id"]=> int(1) ["x"]=> int(2) ["y"]=> int(3) } [1]=> object(stdClass)#%d (3) { ["_id"]=> int(2) ["x"]=> int(3) ["y"]=> int(4) } [2]=> object(stdClass)#%d (3) { ["_id"]=> int(3) ["x"]=> int(4) ["y"]=> int(5) } } ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-004.phpt0000644000175100001660000000134414760300421020002 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() finds no matching documents --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 1)); $server->executeBulkWrite(NS, $bulk); $cursor = $server->executeQuery(NS, new MongoDB\Driver\Query(array("x" => 2))); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECT-- array(0) { } ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-006.phpt0000644000175100001660000000350014760300421020000 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() takes a read preference --SKIPIF-- --FILE-- selectServer($rp); $command = new MongoDB\Driver\Command(array('profile' => 2)); $cursor = $secondary->executeCommand(DATABASE_NAME, $command); $result = current($cursor->toArray()); printf("Set profile level to 2 successfully: %s\n", (empty($result->ok) ? 'no' : 'yes')); if (empty($result->ok)) { exit("Could not set profile level\n"); } $secondary->executeQuery(NS, new MongoDB\Driver\Query(['x' => 1]), ['readPreference' => $rp]); $query = new MongoDB\Driver\Query( array( 'op' => 'query', 'ns' => NS, ), array( 'sort' => array('ts' => -1), 'limit' => 1, ) ); $cursor = $secondary->executeQuery(DATABASE_NAME . '.system.profile', $query, ['readPreference' => $rp]); $profileEntry = current($cursor->toArray()); if (! isset( $profileEntry->command )) { var_dump($profileEntry); } var_dump($profileEntry->command->find); var_dump($profileEntry->command->filter); $command = new MongoDB\Driver\Command(array('profile' => 0)); $cursor = $secondary->executeCommand(DATABASE_NAME, $command); $result = current($cursor->toArray()); printf("Set profile level to 0 successfully: %s\n", (empty($result->ok) ? 'no' : 'yes')); ?> ===DONE=== --EXPECTF-- Set profile level to 2 successfully: yes string(%d) "%s" object(stdClass)#%d (1) { ["x"]=> int(1) } Set profile level to 0 successfully: yes ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-007.phpt0000644000175100001660000000251414760300421020005 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() with negative limit returns a single batch --SKIPIF-- --FILE-- executeQuery(NS, new MongoDB\Driver\Query(array()))->getServer(); // load fixtures for test $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert(['_id' => 1, 'x' => 2, 'y' => 3]); $bulk->insert(['_id' => 2, 'x' => 3, 'y' => 4]); $bulk->insert(['_id' => 3, 'x' => 4, 'y' => 5]); $server->executeBulkWrite(NS, $bulk); $query = new MongoDB\Driver\Query([], ['limit' => -2]); $cursor = $server->executeQuery(NS, $query); var_dump($cursor instanceof MongoDB\Driver\Cursor); var_dump($server == $cursor->getServer()); var_dump(iterator_to_array($cursor)); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\Query::__construct(): Support for negative "limit" values is deprecated and will be removed in ext-mongodb 2.0 in %s on line %d bool(true) bool(true) array(2) { [0]=> object(stdClass)#%d (3) { ["_id"]=> int(1) ["x"]=> int(2) ["y"]=> int(3) } [1]=> object(stdClass)#%d (3) { ["_id"]=> int(2) ["x"]=> int(3) ["y"]=> int(4) } } ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-008.phpt0000644000175100001660000000302614760300421020005 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() with conflicting read preference for secondary --SKIPIF-- --FILE-- selectServer($primaryRp); // Count all data-bearing members to use for the write concern $dataBearingNodes = count(array_filter($manager->getServers(), function (MongoDB\Driver\Server $server) { return ($server->isPrimary() || $server->isSecondary()); })); $bulk = new \MongoDB\Driver\BulkWrite; $bulk->insert(['_id' => 1, 'x' => 1]); $primary->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern($dataBearingNodes)]); $secondaryRp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY); $secondary = $manager->selectServer($secondaryRp); /* Note: this is testing that the read preference (even a conflicting one) has * no effect when directly querying a server, since the secondaryOk flag is always * set for hinted queries. */ $cursor = $secondary->executeQuery(NS, new MongoDB\Driver\Query(['x' => 1]), ['readPreference' => $primaryRp]); var_dump($cursor->toArray()); ?> ===DONE=== ( --EXPECTF-- array(1) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(1) ["x"]=> int(1) } } ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-009.phpt0000644000175100001660000000320514760300421020005 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() takes a read preference in options array --SKIPIF-- --FILE-- insert(['_id' => 1, 'x' => 2, 'y' => 3]); $manager->executeBulkWrite(NS, $bulk); $primaryRp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY); $secondaryRp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY); $primary = $manager->selectServer($primaryRp); $secondary = $manager->selectServer($secondaryRp); echo "Testing primary:\n"; $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $manager->executeQuery(NS, $query, ['readPreference' => $primaryRp]); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; echo "Testing secondary:\n"; $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $manager->executeQuery(NS, $query, ['readPreference' => $secondaryRp]); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- Testing primary: is_primary: true is_secondary: false Testing secondary: is_primary: false is_secondary: true ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-010.phpt0000644000175100001660000000361314760300421020000 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() takes a read preference as legacy option --SKIPIF-- --FILE-- insert(['_id' => 1, 'x' => 2, 'y' => 3]); $manager->executeBulkWrite(NS, $bulk); $primaryRp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY); $secondaryRp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY); $primary = $manager->selectServer($primaryRp); $secondary = $manager->selectServer($secondaryRp); echo "Testing primary:\n"; $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $primary->executeQuery(NS, $query, $primaryRp); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; echo "Testing secondary:\n"; $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); $cursor = $secondary->executeQuery(NS, $query, $secondaryRp); echo "is_primary: ", $cursor->getServer()->isPrimary() ? 'true' : 'false', "\n"; echo "is_secondary: ", $cursor->getServer()->isSecondary() ? 'true' : 'false', "\n\n"; ?> ===DONE=== --EXPECTF-- Testing primary: Deprecated: MongoDB\Driver\Server::executeQuery(): Passing the "readPreference" option directly is deprecated and will be removed in ext-mongodb 2.0%s is_primary: true is_secondary: false Testing secondary: Deprecated: MongoDB\Driver\Server::executeQuery(): Passing the "readPreference" option directly is deprecated and will be removed in ext-mongodb 2.0%s is_primary: false is_secondary: true ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-011.phpt0000644000175100001660000000167114760300421020003 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() sends read preference to mongos --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); (new CommandObserver)->observe( function() use ($server) { $server->executeQuery( NS, new MongoDB\Driver\Query(['x' => 1]), [ 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::NEAREST), ] ); }, function(stdClass $command) { echo "Read Preference: ", $command->{'$readPreference'}->mode, "\n"; } ); ?> ===DONE=== --EXPECTF-- Read Preference: nearest ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-012.phpt0000644000175100001660000000376514760300421020012 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $servers = $manager->getServers(); $selectedServer = array_pop($servers); $wrongServer = array_pop($servers); var_dump($selectedServer != $wrongServer); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $query = new MongoDB\Driver\Query([]); $selectedServer->executeQuery(NS, $query, ['session' => $session]); var_dump($session->getServer() == $selectedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); echo throws(function () use ($wrongServer, $session) { $query = new MongoDB\Driver\Query([]); $wrongServer->executeQuery(NS, $query, ['session' => $session]); }, \MongoDB\Driver\Exception\RuntimeException::class), "\n"; $session->commitTransaction(); var_dump($session->getServer() == $selectedServer); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) OK: Got MongoDB\Driver\Exception\RuntimeException Requested server id does not matched pinned server id bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery-013.phpt0000644000175100001660000000171614760300421020005 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() read concern inheritance --SKIPIF-- --FILE-- 'local']); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference('primary')); (new CommandObserver)->observe( function() use ($server) { $server->executeQuery(NS, new MongoDB\Driver\Query([])); $server->executeQuery(NS, new MongoDB\Driver\Query([], [ 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::AVAILABLE), ])); }, function(stdClass $command) { echo json_encode($command->readConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"level":"local"} {"level":"available"} ===DONE=== mongodb-1.21.0/tests/server/server-executeQuery_error-001.phpt0000644000175100001660000000333714760300421021214 0ustar --TEST-- MongoDB\Driver\Server::executeQuery() with invalid options --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); $query = new MongoDB\Driver\Query(['x' => 3], ['projection' => ['y' => 1]]); echo throws(function() use ($server, $query) { $server->executeQuery(NS, $query, ['readPreference' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $query) { $server->executeQuery(NS, $query, ['readPreference' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $query) { $server->executeQuery(NS, $query, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $query) { $server->executeQuery(NS, $query, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given ===DONE=== mongodb-1.21.0/tests/server/server-executeReadCommand-001.phpt0000644000175100001660000000263414760300421021047 0ustar --TEST-- MongoDB\Driver\Server::executeReadCommand() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY)); (new CommandObserver)->observe( function() use ($server) { $command = new MongoDB\Driver\Command( [ 'aggregate' => NS, 'pipeline' => [], 'cursor' => new stdClass(), ] ); $server->executeReadCommand( DATABASE_NAME, $command, [ 'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::SECONDARY), 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::MAJORITY), ] ); }, function(stdClass $command) { echo "Read Preference: ", $command->{'$readPreference'}->mode, "\n"; echo "Read Concern: ", $command->readConcern->level, "\n"; } ); ?> ===DONE=== --EXPECTF-- Read Preference: secondary Read Concern: majority ===DONE=== mongodb-1.21.0/tests/server/server-executeReadCommand-002.phpt0000644000175100001660000000447114760300421021051 0ustar --TEST-- MongoDB\Driver\Server::executeReadCommand() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $servers = $manager->getServers(); $selectedServer = array_pop($servers); $wrongServer = array_pop($servers); var_dump($selectedServer != $wrongServer); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [] ]); $selectedServer->executeReadCommand(DATABASE_NAME, $command, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); echo throws(function () use ($wrongServer, $session) { $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [] ]); $wrongServer->executeReadCommand(DATABASE_NAME, $command, ['session' => $session]); }, \MongoDB\Driver\Exception\RuntimeException::class), "\n"; $session->commitTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) OK: Got MongoDB\Driver\Exception\RuntimeException Requested server id does not matched pinned server id bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/server/server-executeReadCommand-003.phpt0000644000175100001660000000216614760300421021051 0ustar --TEST-- MongoDB\Driver\Server::executeReadCommand() read concern inheritance --SKIPIF-- --FILE-- 'local']); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference('primary')); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [], ]); (new CommandObserver)->observe( function() use ($server, $command) { $server->executeReadCommand(DATABASE_NAME, $command); $server->executeReadCommand(DATABASE_NAME, $command, [ 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::AVAILABLE), ]); }, function(stdClass $command) { echo json_encode($command->readConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"level":"local"} {"level":"available"} ===DONE=== mongodb-1.21.0/tests/server/server-executeReadCommand_error-001.phpt0000644000175100001660000000505014760300421022253 0ustar --TEST-- MongoDB\Driver\Server::executeReadCommand() with invalid options --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY)); $command = new MongoDB\Driver\Command(['ping' => 1]); echo throws(function() use ($server, $command) { $server->executeReadCommand(DATABASE_NAME, $command, ['readConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadCommand(DATABASE_NAME, $command, ['readConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadCommand(DATABASE_NAME, $command, ['readPreference' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadCommand(DATABASE_NAME, $command, ['readPreference' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadCommand(DATABASE_NAME, $command, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadCommand(DATABASE_NAME, $command, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given ===DONE=== mongodb-1.21.0/tests/server/server-executeReadWriteCommand-001.phpt0000644000175100001660000000240014760300421022051 0ustar --TEST-- MongoDB\Driver\Server::executeReadWriteCommand() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); (new CommandObserver)->observe( function() use ($server) { $command = new MongoDB\Driver\Command( [ 'findAndModify' => NS, 'update' => [ '$set' => [ 'foo' => 'bar' ] ], ] ); $server->executeReadWriteCommand( DATABASE_NAME, $command, [ 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::LOCAL), 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY), ] ); }, function(stdClass $command) { echo "Read Concern: ", $command->readConcern->level, "\n"; echo "Write Concern: ", $command->writeConcern->w, "\n"; } ); ?> ===DONE=== --EXPECTF-- Read Concern: local Write Concern: majority ===DONE=== mongodb-1.21.0/tests/server/server-executeReadWriteCommand-002.phpt0000644000175100001660000000451414760300421022062 0ustar --TEST-- MongoDB\Driver\Server::executeReadWriteCommand() pins transaction to server --SKIPIF-- --FILE-- executeReadWriteCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $servers = $manager->getServers(); $selectedServer = array_pop($servers); $wrongServer = array_pop($servers); var_dump($selectedServer != $wrongServer); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [] ]); $selectedServer->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); echo throws(function () use ($wrongServer, $session) { $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [['$group' => ['_id' => 1]]], 'cursor' => (object) [] ]); $wrongServer->executeReadCommand(DATABASE_NAME, $command, ['session' => $session]); }, \MongoDB\Driver\Exception\RuntimeException::class), "\n"; $session->commitTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) OK: Got MongoDB\Driver\Exception\RuntimeException Requested server id does not matched pinned server id bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/server/server-executeReadWriteCommand-003.phpt0000644000175100001660000000267314760300421022067 0ustar --TEST-- MongoDB\Driver\Server::executeReadWriteCommand() read and write concern inheritance --SKIPIF-- --FILE-- 'local', 'w' => 2, 'wtimeoutms' => 1000]); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference('primary')); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ ['$group' => ['_id' => 1]], ['$out' => COLLECTION_NAME . '.out'], ], 'cursor' => (object) [], ]); (new CommandObserver)->observe( function() use ($server, $command) { $server->executeReadWriteCommand(DATABASE_NAME, $command); $server->executeReadWriteCommand(DATABASE_NAME, $command, [ 'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::AVAILABLE), 'writeConcern' => new MongoDB\Driver\WriteConcern(1), ]); }, function(stdClass $command) { echo json_encode($command->readConcern), "\n"; echo json_encode($command->writeConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"level":"local"} {"w":2,"wtimeout":1000} {"level":"available"} {"w":1} ===DONE=== mongodb-1.21.0/tests/server/server-executeReadWriteCommand_error-001.phpt0000644000175100001660000000507714760300421023277 0ustar --TEST-- MongoDB\Driver\Server::executeReadWriteCommand() with invalid options --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY)); $command = new MongoDB\Driver\Command(['ping' => 1]); echo throws(function() use ($server, $command) { $server->executeReadWriteCommand(DATABASE_NAME, $command, ['readConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadWriteCommand(DATABASE_NAME, $command, ['readConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadWriteCommand(DATABASE_NAME, $command, ['writeConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeReadWriteCommand(DATABASE_NAME, $command, ['writeConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given ===DONE=== mongodb-1.21.0/tests/server/server-executeWriteCommand-001.phpt0000644000175100001660000000215014760300421021257 0ustar --TEST-- MongoDB\Driver\Server::executeWriteCommand() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); $bw = new MongoDB\Driver\BulkWrite(); $bw->insert(['a' => 1]); $manager->executeBulkWrite(NS, $bw); (new CommandObserver)->observe( function() use ($server) { $command = new MongoDB\Driver\Command([ 'drop' => COLLECTION_NAME, ]); $server->executeWriteCommand( DATABASE_NAME, $command, [ 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY), ] ); }, function(stdClass $command) { echo "Write Concern: ", $command->writeConcern->w, "\n"; } ); ?> ===DONE=== --EXPECTF-- Write Concern: majority ===DONE=== mongodb-1.21.0/tests/server/server-executeWriteCommand-002.phpt0000644000175100001660000000457614760300421021276 0ustar --TEST-- MongoDB\Driver\Server::executeWriteCommand() pins transaction to server --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $servers = $manager->getServers(); $selectedServer = array_pop($servers); $wrongServer = array_pop($servers); var_dump($selectedServer != $wrongServer); $session = $manager->startSession(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $session->startTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['_id' => 'foo'], 'upsert' => true, 'new' => true, 'update' => ['x' => 1] ]); $selectedServer->executeWriteCommand(DATABASE_NAME, $command, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); echo throws(function () use ($wrongServer, $session) { $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['_id' => 'foo'], 'upsert' => true, 'new' => true, 'update' => ['x' => 1] ]); $wrongServer->executeWriteCommand(DATABASE_NAME, $command, ['session' => $session]); }, \MongoDB\Driver\Exception\RuntimeException::class), "\n"; $session->commitTransaction(); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $selectedServer->executeBulkWrite(NS, $bulk, ['session' => $session]); var_dump($session->getServer() instanceof \MongoDB\Driver\Server); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(false) bool(true) OK: Got MongoDB\Driver\Exception\RuntimeException Requested server id does not matched pinned server id bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/server/server-executeWriteCommand-003.phpt0000644000175100001660000000222314760300421021262 0ustar --TEST-- MongoDB\Driver\Server::executeWriteCommand() write concern inheritance --SKIPIF-- --FILE-- 2, 'wtimeoutms' => 1000]); $server = $manager->selectServer(new MongoDB\Driver\ReadPreference('primary')); $command = new MongoDB\Driver\Command([ 'findAndModify' => COLLECTION_NAME, 'query' => ['x' => 1], 'upsert' => true, 'new' => true, 'update' => ['$inc' => ['x' => 1]], ]); (new CommandObserver)->observe( function() use ($server, $command) { $server->executeWriteCommand(DATABASE_NAME, $command); $server->executeWriteCommand(DATABASE_NAME, $command, ['writeConcern' => new MongoDB\Driver\WriteConcern(1)]); }, function(stdClass $command) { echo json_encode($command->writeConcern), "\n"; } ); ?> ===DONE=== --EXPECT-- {"w":2,"wtimeout":1000} {"w":1} ===DONE=== mongodb-1.21.0/tests/server/server-executeWriteCommand_error-001.phpt0000644000175100001660000000364614760300421022503 0ustar --TEST-- MongoDB\Driver\Server::executeWriteCommand() with invalid options --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::SECONDARY)); $command = new MongoDB\Driver\Command([]); echo throws(function() use ($server, $command) { $server->executeWriteCommand(DATABASE_NAME, $command, ['session' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeWriteCommand(DATABASE_NAME, $command, ['session' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeWriteCommand(DATABASE_NAME, $command, ['writeConcern' => 'foo']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() use ($server, $command) { $server->executeWriteCommand(DATABASE_NAME, $command, ['writeConcern' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "session" option to be MongoDB\Driver\Session, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, string given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given ===DONE=== mongodb-1.21.0/tests/server/server-getInfo-001.phpt0000644000175100001660000000071514760300421016703 0ustar --TEST-- MongoDB\Driver\Server::getInfo() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY))->getInfo()); } catch (Exception $e) {} ?> ===DONE=== --EXPECTF-- array(%d) { %a } ===DONE=== mongodb-1.21.0/tests/server/server-getLatency-001.phpt0000644000175100001660000000075114760300421017407 0ustar --TEST-- MongoDB\Driver\Server::getLatency() returns a non-negative integer when set --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getLatency()); ?> ===DONE=== --EXPECTF-- int(%d) ===DONE=== mongodb-1.21.0/tests/server/server-getLatency-002.phpt0000644000175100001660000000072114760300421017405 0ustar --TEST-- MongoDB\Driver\Server::getLatency() returns null when unset (e.g. load balancer) --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getLatency()); ?> ===DONE=== --EXPECT-- NULL ===DONE=== mongodb-1.21.0/tests/server/server-getServerDescription-001.phpt0000644000175100001660000000074114760300421021461 0ustar --TEST-- MongoDB\Driver\Server::getServerDescription() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getServerDescription() instanceof MongoDB\Driver\ServerDescription); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/server/server-getTags-001.phpt0000644000175100001660000000077214760300421016711 0ustar --TEST-- MongoDB\Driver\Server::getTags() with standalone --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY))->getTags()); ?> ===DONE=== --EXPECTF-- array(0) { } ===DONE=== mongodb-1.21.0/tests/server/server-getTags-002.phpt0000644000175100001660000000237114760300421016707 0ustar --TEST-- MongoDB\Driver\Server::getTags() with replica set --SKIPIF-- --FILE-- 1]); $manager->executeCommand(DATABASE_NAME, $command); function assertSomeServerHasTags(array $servers, array $expectedTags) { foreach ($servers as $server) { /* Using a non-strict comparison guards against tags being returned in * a different order than expected. */ if ($expectedTags == $server->getTags()) { printf("Found server with tags: %s\n", json_encode($expectedTags)); return; } } printf("No server has tags: %s\n", json_encode($expectedTags)); } $servers = $manager->getServers(); assertSomeServerHasTags($servers, ['dc' => 'ny', 'ordinal' => 'one']); assertSomeServerHasTags($servers, ['dc' => 'pa', 'ordinal' => 'two']); assertSomeServerHasTags($servers, []); ?> ===DONE=== --EXPECT-- Found server with tags: {"dc":"ny","ordinal":"one"} Found server with tags: {"dc":"pa","ordinal":"two"} Found server with tags: [] ===DONE=== mongodb-1.21.0/tests/server/server_error-001.phpt0000644000175100001660000000036514760300421016524 0ustar --TEST-- MongoDB\Driver\Server cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyServer %s final class %SMongoDB\Driver\Server%S in %s on line %d mongodb-1.21.0/tests/serverApi/serverApi-bsonserialize-001.phpt0000644000175100001660000000114514760300421021243 0ustar --TEST-- MongoDB\Driver\ServerApi::bsonSerialize() --FILE-- ===DONE=== --EXPECT-- { "version" : "1" } { "version" : "1", "strict" : true } { "version" : "1", "deprecationErrors" : true } { "version" : "1", "strict" : false, "deprecationErrors" : false } ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-bsonserialize-002.phpt0000644000175100001660000000150714760300421021246 0ustar --TEST-- MongoDB\Driver\ServerApi::bsonSerialize() returns an object --FILE-- bsonSerialize()); } ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["version"]=> string(1) "1" } object(stdClass)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> bool(true) } object(stdClass)#%d (%d) { ["version"]=> string(1) "1" ["deprecationErrors"]=> bool(true) } object(stdClass)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> bool(false) ["deprecationErrors"]=> bool(false) } ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-construct-001.phpt0000644000175100001660000000073014760300421020415 0ustar --TEST-- MongoDB\Driver\ServerApi::__construct() --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Server API version "no way" is not supported in this driver version ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-debug.phpt0000644000175100001660000000156514760300421017170 0ustar --TEST-- MongoDB\Driver\ServerApi debug output --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> NULL ["deprecationErrors"]=> NULL } object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> bool(true) ["deprecationErrors"]=> NULL } object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> NULL ["deprecationErrors"]=> bool(true) } object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> bool(false) ["deprecationErrors"]=> bool(false) } ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-serialization-002.phpt0000644000175100001660000000401514760300421021247 0ustar --TEST-- MongoDB\Driver\ServerApi serialization (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> NULL ["deprecationErrors"]=> NULL } O:24:"MongoDB\Driver\ServerApi":3:{s:7:"version";s:1:"1";s:6:"strict";N;s:17:"deprecationErrors";N;} object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> NULL ["deprecationErrors"]=> NULL } object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> bool(true) ["deprecationErrors"]=> NULL } O:24:"MongoDB\Driver\ServerApi":3:{s:7:"version";s:1:"1";s:6:"strict";b:1;s:17:"deprecationErrors";N;} object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> bool(true) ["deprecationErrors"]=> NULL } object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> NULL ["deprecationErrors"]=> bool(true) } O:24:"MongoDB\Driver\ServerApi":3:{s:7:"version";s:1:"1";s:6:"strict";N;s:17:"deprecationErrors";b:1;} object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> NULL ["deprecationErrors"]=> bool(true) } object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> bool(false) ["deprecationErrors"]=> bool(false) } O:24:"MongoDB\Driver\ServerApi":3:{s:7:"version";s:1:"1";s:6:"strict";b:0;s:17:"deprecationErrors";b:0;} object(MongoDB\Driver\ServerApi)#%d (%d) { ["version"]=> string(1) "1" ["strict"]=> bool(false) ["deprecationErrors"]=> bool(false) } ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-serialization_error-001.phpt0000644000175100001660000000225314760300421022461 0ustar --TEST-- MongoDB\Driver\ServerApi unserialization errors (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "version" field to be string OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "strict" field to be bool or null OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "deprecationErrors" field to be bool or null ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-serialization_error-002.phpt0000644000175100001660000000226214760300421022462 0ustar --TEST-- MongoDB\Driver\ServerApi unserialization errors (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "version" field to be string OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "strict" field to be bool or null OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "deprecationErrors" field to be bool or null ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-set_state-001.phpt0000644000175100001660000000227314760300421020370 0ustar --TEST-- MongoDB\Driver\ServerApi::__set_state() --FILE-- '1'], ['version' => '1', 'strict' => true], ['version' => '1', 'deprecationErrors' => true], ['version' => '1', 'strict' => false, 'deprecationErrors' => false], ['version' => '1', 'strict' => null, 'deprecationErrors' => null], ]; foreach ($tests as $fields) { var_export(MongoDB\Driver\ServerApi::__set_state($fields)); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => NULL, 'deprecationErrors' => NULL, )) %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => true, 'deprecationErrors' => NULL, )) %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => NULL, 'deprecationErrors' => true, )) %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => false, 'deprecationErrors' => false, )) %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => NULL, 'deprecationErrors' => NULL, )) ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-set_state_error-001.phpt0000644000175100001660000000322614760300421021600 0ustar --TEST-- MongoDB\Driver\ServerApi::__set_state() requires correct data types and values --FILE-- 1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\Driver\ServerApi::__set_state(['version' => '2']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\Driver\ServerApi::__set_state(['version' => '1', 'strict' => 'true']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\Driver\ServerApi::__set_state(['version' => '1', 'deprecationErrors' => 'true']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "version" field to be string OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "version" field to be string OK: Got MongoDB\Driver\Exception\InvalidArgumentException Server API version "2" is not supported in this driver version OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "strict" field to be bool or null OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\ServerApi initialization requires "deprecationErrors" field to be bool or null ===DONE=== mongodb-1.21.0/tests/serverApi/serverApi-var_export-001.phpt0000644000175100001660000000167614760300421020574 0ustar --TEST-- MongoDB\Driver\ServerApi: var_export() --FILE-- ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => NULL, 'deprecationErrors' => NULL, )) %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => true, 'deprecationErrors' => NULL, )) %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => NULL, 'deprecationErrors' => true, )) %r\\?%rMongoDB\Driver\ServerApi::__set_state(array( 'version' => '1', 'strict' => false, 'deprecationErrors' => false, )) ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-constants.phpt0000644000175100001660000000170014760300421023431 0ustar --TEST-- MongoDB\Driver\ServerDescription constants --FILE-- ===DONE=== --EXPECT-- string(7) "Unknown" string(10) "Standalone" string(6) "Mongos" string(15) "PossiblePrimary" string(9) "RSPrimary" string(11) "RSSecondary" string(9) "RSArbiter" string(7) "RSOther" string(7) "RSGhost" string(12) "LoadBalancer" ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-debug-001.phpt0000644000175100001660000000137414760300421023010 0ustar --TEST-- MongoDB\Driver\ServerDescription debug output --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getServerDescription()); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\ServerDescription)#%d (%d) { ["host"]=> string(%d) "%s" ["port"]=> int(%d) ["type"]=> string(%d) "%r(Standalone|Mongos|RSPrimary|LoadBalancer)%r" ["hello_response"]=> array(%d) {%A } ["last_update_time"]=> %r(string\(\d+\) "\d+"|int\(\d+\))%r ["round_trip_time"]=> %r(NULL|int\(\d+\))%r } ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-getHelloResponse-001.phpt0000644000175100001660000000072714760300421025205 0ustar --TEST-- MongoDB\Driver\ServerDescription::getHelloResponse() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getServerDescription()->getHelloResponse()); ?> ===DONE=== --EXPECTF-- array(%d) {%A } ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-getHost-001.phpt0000644000175100001660000000070314760300421023332 0ustar --TEST-- MongoDB\Driver\ServerDescription::getHost() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getServerDescription()->getHost()); ?> ===DONE=== --EXPECTF-- string(%s) %s ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-getLastUpdateTime-001.phpt0000644000175100001660000000103414760300421025300 0ustar --TEST-- MongoDB\Driver\ServerDescription::getLastUpdateTime() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getServerDescription()->getLastUpdateTime()); ?> ===DONE=== --EXPECTF-- int(%d) ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-getLastUpdateTime-002.phpt0000644000175100001660000000200414760300421025277 0ustar --TEST-- MongoDB\Driver\ServerDescription::getLastUpdateTime() emits warning on truncation of 64-bit value --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); /* The return value of mongoc_server_description_last_update_time() originates * from bson_get_monotonic_time(), which has an unspecified starting point and * may or may not exceed the range of a 32-bit integer. As such, EXPECTF allows * for a possible warning message. Depending on how the value is truncated, it * may also be reported as negative. */ var_dump($server->getServerDescription()->getLastUpdateTime()); ?> ===DONE=== --EXPECTF-- %r(Warning: Truncating 64-bit value for lastUpdateTime in .+ on line \d+\R)?%rint(%r(-?\d+)%r) ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-getPort-001.phpt0000644000175100001660000000067514760300421023351 0ustar --TEST-- MongoDB\Driver\ServerDescription::getPort() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getServerDescription()->getPort()); ?> ===DONE=== --EXPECTF-- int(%d) ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-getRoundTripTime-001.phpt0000644000175100001660000000073514760300421025167 0ustar --TEST-- MongoDB\Driver\ServerDescription::getRoundTripTime() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getServerDescription()->getRoundTripTime()); ?> ===DONE=== --EXPECTF-- %r(NULL|int\(\d+\))%r ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-getType-001.phpt0000644000175100001660000000076114760300421023342 0ustar --TEST-- MongoDB\Driver\ServerDescription::getType() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); var_dump($server->getServerDescription()->getType()); ?> ===DONE=== --EXPECTF-- string(%d) "%r(Standalone|Mongos|RSPrimary|LoadBalancer)%r" ===DONE=== mongodb-1.21.0/tests/serverDescription/serverDescription-var_export-001.phpt0000644000175100001660000000137414760300421024113 0ustar --TEST-- MongoDB\Driver\ServerDescription: var_export() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); echo var_export($server->getServerDescription(), true), "\n"; ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\ServerDescription::__set_state(array( 'host' => '%s', 'port' => %d, 'type' => '%r(Standalone|Mongos|RSPrimary|LoadBalancer)%r', 'hello_response' =>%w array (%A ), 'last_update_time' => %r('\d+'|\d+)%r, 'round_trip_time' => %r(NULL|\d+)%r, )) ===DONE=== mongodb-1.21.0/tests/session/bug1274-001.phpt0000644000175100001660000000370414760300421015255 0ustar --TEST-- PHPC-1274: Session destruct should not abort transaction from parent process --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new MongoDB\Driver\Command(['create' => COLLECTION_NAME]), ['writeConcern' => new MongoDB\Driver\WriteConcern('majority')] ); $session = $manager->startSession(); $session->startTransaction(['writeConcern' => new MongoDB\Driver\WriteConcern('majority')]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $result = $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); printf("Parent inserted %d documents\n", $result->getInsertedCount()); $childPid = pcntl_fork(); if ($childPid === 0) { echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 3]); $bulk->insert(['x' => 4]); $result = $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); printf("Parent inserted %d documents\n", $result->getInsertedCount()); $session->commitTransaction(); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); printf("Parent fully iterated cursor for %d documents\n", iterator_count($cursor)); } ?> ===DONE=== --EXPECT-- Parent inserted 2 documents Child exits Parent waited for child to exit Parent inserted 2 documents Parent fully iterated cursor for 4 documents ===DONE=== mongodb-1.21.0/tests/session/bug1274-002.phpt0000644000175100001660000000615014760300421015254 0ustar --TEST-- PHPC-1274: Session destruct should not end session from parent process --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $session = $manager->startSession(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query, ['session' => $session]); $childPid = pcntl_fork(); if ($childPid === 0) { echo "Child exits\n"; exit; } function isSessionOnServer($manager, $session) { /* Note: use $listLocalSessions since sessions are only synced to the config * database's system.sessions collection every 30 minutes. Alternatively, we * could run the refreshLogicalSessionCacheNow command on the primary. */ $command = new MongoDB\Driver\Command([ 'aggregate' => 1, 'pipeline' => [ ['$listLocalSessions' => new stdClass], ['$match' => ['_id.id' => $session->getLogicalSessionId()->id]], ], 'cursor' => new stdClass, ]); $cursor = $manager->executeReadCommand(DATABASE_NAME, $command); return iterator_count($cursor) > 0; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } printf("Session is on server: %s\n", isSessionOnServer($manager, $session) ? 'yes' : 'no'); printf("Parent fully iterated cursor for %d documents\n", iterator_count($cursor)); } ?> ===DONE=== --EXPECT-- Parent executes find with batchSize: 2 Child exits Parent waited for child to exit Parent executes aggregate Session is on server: yes Parent executes getMore with batchSize: 2 Parent fully iterated cursor for 3 documents ===DONE=== mongodb-1.21.0/tests/session/bug1274-003.phpt0000644000175100001660000000651014760300421015255 0ustar --TEST-- PHPC-1274: Implicit sessions are not reused from parent process --SKIPIF-- --FILE-- logNamespace = $logNamespace; $this->manager = $manager; $this->pid = getmypid(); } public function executeAndLogSessions(callable $callable) { $this->lsids = []; MongoDB\Driver\Monitoring\addSubscriber($this); call_user_func($callable); MongoDB\Driver\Monitoring\removeSubscriber($this); if (empty($this->lsids)) { return; } $bulk = new MongoDB\Driver\BulkWrite(); foreach ($this->lsids as $lsid) { $bulk->update(['lsid' => $lsid], ['$inc' => ['count' => 1]], ['upsert' => true]); } $this->manager->executeBulkWrite($this->logNamespace, $bulk); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); if (isset($command->lsid)) { $this->lsids[] = $command->lsid; } $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(); $logNamespace = NS . '_sessions'; $sessionLogger = new SessionLogger($manager, $logNamespace); /* This test uses executeBulkWrite() as it's the only execute method that does * not create a cursor. The original patch for PHPC-1274 covered those methods * that return a cursor but omitted executeBulkWrite(). */ $sessionLogger->executeAndLogSessions(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk); }); $childPid = pcntl_fork(); if ($childPid === 0) { $sessionLogger->executeAndLogSessions(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 2]); $manager->executeBulkWrite(NS, $bulk); }); echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } $query = new MongoDB\Driver\Query([]); $cursor = $manager->executeQuery($logNamespace, $query); printf("Sessions used: %d\n", iterator_count($cursor)); } ?> ===DONE=== --EXPECT-- Parent executes insert Child executes insert Child exits Parent waited for child to exit Sessions used: 2 ===DONE=== mongodb-1.21.0/tests/session/bug1274-004.phpt0000644000175100001660000000402114760300421015251 0ustar --TEST-- PHPC-1274: Session destruct should not abort transaction from parent process (disableClientPersistence=true) --SKIPIF-- --FILE-- true]); /* Create collections as that can't be (automatically) done in a transaction */ $manager->executeCommand( DATABASE_NAME, new MongoDB\Driver\Command(['create' => COLLECTION_NAME]), ['writeConcern' => new MongoDB\Driver\WriteConcern('majority')] ); $session = $manager->startSession(); $session->startTransaction(['writeConcern' => new MongoDB\Driver\WriteConcern('majority')]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $result = $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); printf("Parent inserted %d documents\n", $result->getInsertedCount()); $childPid = pcntl_fork(); if ($childPid === 0) { echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 3]); $bulk->insert(['x' => 4]); $result = $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); printf("Parent inserted %d documents\n", $result->getInsertedCount()); $session->commitTransaction(); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query([])); printf("Parent fully iterated cursor for %d documents\n", iterator_count($cursor)); } ?> ===DONE=== --EXPECT-- Parent inserted 2 documents Child exits Parent waited for child to exit Parent inserted 2 documents Parent fully iterated cursor for 4 documents ===DONE=== mongodb-1.21.0/tests/session/bug1274-005.phpt0000644000175100001660000000626514760300421015266 0ustar --TEST-- PHPC-1274: Session destruct should not end session from parent process (disableClientPersistence=true) --SKIPIF-- --FILE-- pid = getmypid(); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; if ($commandName === 'find' || $commandName === 'getMore') { printf("%s executes %s with batchSize: %d\n", $process, $commandName, $command->batchSize); return; } printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); $session = $manager->startSession(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $bulk->insert(['x' => 2]); $bulk->insert(['x' => 3]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); MongoDB\Driver\Monitoring\addSubscriber(new CommandLogger); $query = new MongoDB\Driver\Query([], ['batchSize' => 2]); $cursor = $manager->executeQuery(NS, $query, ['session' => $session]); $childPid = pcntl_fork(); if ($childPid === 0) { echo "Child exits\n"; exit; } function isSessionOnServer($manager, $session) { /* Note: use $listLocalSessions since sessions are only synced to the config * database's system.sessions collection every 30 minutes. Alternatively, we * could run the refreshLogicalSessionCacheNow command on the primary. */ $command = new MongoDB\Driver\Command([ 'aggregate' => 1, 'pipeline' => [ ['$listLocalSessions' => new stdClass], ['$match' => ['_id.id' => $session->getLogicalSessionId()->id]], ], 'cursor' => new stdClass, ]); $cursor = $manager->executeReadCommand(DATABASE_NAME, $command); return iterator_count($cursor) > 0; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } printf("Session is on server: %s\n", isSessionOnServer($manager, $session) ? 'yes' : 'no'); printf("Parent fully iterated cursor for %d documents\n", iterator_count($cursor)); } ?> ===DONE=== --EXPECT-- Parent executes find with batchSize: 2 Child exits Parent waited for child to exit Parent executes aggregate Session is on server: yes Parent executes getMore with batchSize: 2 Parent fully iterated cursor for 3 documents ===DONE=== mongodb-1.21.0/tests/session/bug1274-006.phpt0000644000175100001660000000662514760300421015267 0ustar --TEST-- PHPC-1274: Implicit sessions are not reused from parent process (disableClientPersistence=true) --SKIPIF-- --FILE-- logNamespace = $logNamespace; $this->manager = $manager; $this->pid = getmypid(); } public function executeAndLogSessions(callable $callable) { $this->lsids = []; MongoDB\Driver\Monitoring\addSubscriber($this); call_user_func($callable); MongoDB\Driver\Monitoring\removeSubscriber($this); if (empty($this->lsids)) { return; } $bulk = new MongoDB\Driver\BulkWrite(); foreach ($this->lsids as $lsid) { $bulk->update(['lsid' => $lsid], ['$inc' => ['count' => 1]], ['upsert' => true]); } $this->manager->executeBulkWrite($this->logNamespace, $bulk); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); if (isset($command->lsid)) { $this->lsids[] = $command->lsid; } $commandName = $event->getCommandName(); $process = $this->pid === getmypid() ? 'Parent' : 'Child'; printf("%s executes %s\n", $process, $commandName); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $manager = create_test_manager(URI, [], ['disableClientPersistence' => true]); $logNamespace = NS . '_sessions'; $sessionLogger = new SessionLogger($manager, $logNamespace); /* This test uses executeBulkWrite() as it's the only execute method that does * not create a cursor. The original patch for PHPC-1274 covered those methods * that return a cursor but omitted executeBulkWrite(). */ $sessionLogger->executeAndLogSessions(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk); }); $childPid = pcntl_fork(); if ($childPid === 0) { $sessionLogger->executeAndLogSessions(function() use ($manager) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 2]); $manager->executeBulkWrite(NS, $bulk); }); echo "Child exits\n"; exit; } if ($childPid > 0) { $waitPid = pcntl_waitpid($childPid, $status); if ($waitPid === $childPid) { echo "Parent waited for child to exit\n"; } $query = new MongoDB\Driver\Query([]); $cursor = $manager->executeQuery($logNamespace, $query); printf("Sessions used: %d\n", iterator_count($cursor)); } ?> ===DONE=== --EXPECT-- Parent executes insert Child executes insert Child exits Parent waited for child to exit Sessions used: 2 ===DONE=== mongodb-1.21.0/tests/session/session-001.phpt0000644000175100001660000000204314760300421015640 0ustar --TEST-- MongoDB\Driver\Session spec test: Pool is LIFO --DESCRIPTION-- Session spec prose test #2: Pool is LIFO https://github.com/mongodb/specifications/blob/master/source/sessions/tests/README.rst#pool-is-lifo --SKIPIF-- --FILE-- startSession(); $firstSessionId = $firstSession->getLogicalSessionId(); /* libmongoc does not pool unused sessions (CDRIVER-3322), so we must use this * session with a command to ensure it enters the pool. */ $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $firstSession]); unset($firstSession); $secondSession = $manager->startSession(); $secondSessionId = $secondSession->getLogicalSessionId(); var_dump($firstSessionId == $secondSessionId); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/session/session-002.phpt0000644000175100001660000001370514760300421015650 0ustar --TEST-- MongoDB\Driver\Session spec test: $clusterTime in commands --DESCRIPTION-- Session spec prose test #3: $clusterTime in commands https://github.com/mongodb/specifications/blob/master/source/sessions/tests/README.rst#clustertime-in-commands --SKIPIF-- --FILE-- lastSeenClusterTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [], 'cursor' => new stdClass(), ]); $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => $session]); $manager->executeReadWriteCommand(DATABASE_NAME, $command, ['session' => $session]); printf("Session reports last seen \$clusterTime: %s\n", ($session->getClusterTime() == $this->lastSeenClusterTime) ? 'yes' : 'no'); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function find() { $this->lastSeenClusterTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); $manager->executeQuery(NS, $query, ['session' => $session]); printf("Session reports last seen \$clusterTime: %s\n", ($session->getClusterTime() == $this->lastSeenClusterTime) ? 'yes' : 'no'); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function insert() { $this->lastSeenClusterTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 2]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); printf("Session reports last seen \$clusterTime: %s\n", ($session->getClusterTime() == $this->lastSeenClusterTime) ? 'yes' : 'no'); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function ping() { $this->lastSeenClusterTime = null; MongoDB\Driver\Monitoring\addSubscriber($this); $manager = create_test_manager(); $session = $manager->startSession(); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); printf("Session reports last seen \$clusterTime: %s\n", ($session->getClusterTime() == $this->lastSeenClusterTime) ? 'yes' : 'no'); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { $command = $event->getCommand(); $hasClusterTime = isset($command->{'$clusterTime'}); printf("%s command includes \$clusterTime: %s\n", $event->getCommandName(), $hasClusterTime ? 'yes' : 'no'); if ($hasClusterTime && $this->lastSeenClusterTime !== null) { printf("%s command uses last seen \$clusterTime: %s\n", $event->getCommandName(), ($command->{'$clusterTime'} == $this->lastSeenClusterTime) ? 'yes' : 'no'); } } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { $reply = $event->getReply(); $hasClusterTime = isset($reply->{'$clusterTime'}); printf("%s command reply includes \$clusterTime: %s\n", $event->getCommandName(), $hasClusterTime ? 'yes' : 'no'); if ($hasClusterTime) { $this->lastSeenClusterTime = $reply->{'$clusterTime'}; } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } echo "\nTesting aggregate command\n"; (new Test)->aggregate(); echo "\nTesting find command\n"; (new Test)->find(); echo "\nTesting insert command\n"; (new Test)->insert(); echo "\nTesting ping command\n"; (new Test)->ping(); ?> ===DONE=== --EXPECT-- Testing aggregate command aggregate command includes $clusterTime: yes aggregate command reply includes $clusterTime: yes aggregate command includes $clusterTime: yes aggregate command uses last seen $clusterTime: yes aggregate command reply includes $clusterTime: yes Session reports last seen $clusterTime: yes Testing find command find command includes $clusterTime: yes find command reply includes $clusterTime: yes find command includes $clusterTime: yes find command uses last seen $clusterTime: yes find command reply includes $clusterTime: yes Session reports last seen $clusterTime: yes Testing insert command insert command includes $clusterTime: yes insert command reply includes $clusterTime: yes insert command includes $clusterTime: yes insert command uses last seen $clusterTime: yes insert command reply includes $clusterTime: yes Session reports last seen $clusterTime: yes Testing ping command ping command includes $clusterTime: yes ping command reply includes $clusterTime: yes ping command includes $clusterTime: yes ping command uses last seen $clusterTime: yes ping command reply includes $clusterTime: yes Session reports last seen $clusterTime: yes ===DONE=== mongodb-1.21.0/tests/session/session-003.phpt0000644000175100001660000000405214760300421015644 0ustar --TEST-- MongoDB\Driver\Session spec test: session cannot be used for different clients --DESCRIPTION-- Session spec prose test #5: Session argument is for the right client https://github.com/mongodb/specifications/blob/master/source/sessions/tests/README.rst#session-argument-is-for-the-right-client --SKIPIF-- --FILE-- true]); $otherManager = create_test_manager(URI, [], ['disableClientPersistence' => true]); // Create a session with the second Manager (associated with different client) $session = $otherManager->startSession(); echo "\nTesting executeBulkWrite()\n"; echo throws(function() use ($manager, $session) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo "\nTesting executeCommand()\n"; echo throws(function() use ($manager, $session) { $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo "\nTesting executeQuery()\n"; echo throws(function() use ($manager, $session) { $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- Testing executeBulkWrite() OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use Session started from a different Manager Testing executeCommand() OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use Session started from a different Manager Testing executeQuery() OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot use Session started from a different Manager ===DONE=== mongodb-1.21.0/tests/session/session-004.phpt0000644000175100001660000000206014760300421015642 0ustar --TEST-- MongoDB\Driver\Session spec test: snapshot option is incompatible with writes --DESCRIPTION-- PHPC-1875: Disable writes on snapshot sessions --SKIPIF-- --FILE-- startSession(['snapshot' => true]); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); try { $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { /* Note: we intentionally do not assert the server's error message for the * client specifying a read concern on a write command. It is sufficient to * assert that the error code is InvalidOptions(72). */ var_dump($e->getCode() === 72); } ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/session/session-005.phpt0000644000175100001660000000370114760300421015646 0ustar --TEST-- MongoDB\Driver\Session spec test: snapshot option requires MongoDB 5.0+ --DESCRIPTION-- PHPC-1876: Raise client error for snapshot sessions on <5.0 servers --SKIPIF-- =', '5.0'); ?> --FILE-- startSession(['snapshot' => true]); /* Note: executeBulkWrite() always throws a BulkWriteException. Any previous * exception's message will be included in the BulkWriteException message. */ echo "\nTesting executeBulkWrite()\n"; echo throws(function() use ($manager, $session) { $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['x' => 1]); $manager->executeBulkWrite(NS, $bulk, ['session' => $session]); }, MongoDB\Driver\Exception\BulkWriteException::class), "\n"; echo "\nTesting executeCommand()\n"; echo throws(function() use ($manager, $session) { $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; echo "\nTesting executeQuery()\n"; echo throws(function() use ($manager, $session) { $query = new MongoDB\Driver\Query([]); $manager->executeQuery(NS, $query, ['session' => $session]); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECT-- Testing executeBulkWrite() OK: Got MongoDB\Driver\Exception\BulkWriteException Bulk write failed due to previous MongoDB\Driver\Exception\RuntimeException: Snapshot reads require MongoDB 5.0 or later Testing executeCommand() OK: Got MongoDB\Driver\Exception\RuntimeException Snapshot reads require MongoDB 5.0 or later Testing executeQuery() OK: Got MongoDB\Driver\Exception\RuntimeException Snapshot reads require MongoDB 5.0 or later ===DONE=== mongodb-1.21.0/tests/session/session-advanceClusterTime-001.phpt0000644000175100001660000000243014760300421021420 0ustar --TEST-- MongoDB\Driver\Session::advanceClusterTime() --SKIPIF-- --FILE-- startSession(); $sessionB = $manager->startSession(); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $sessionA]); echo "Initial cluster time of session B:\n"; var_dump($sessionB->getClusterTime()); $sessionB->advanceClusterTime($sessionA->getClusterTime()); echo "\nCluster time after advancing session B:\n"; var_dump($sessionB->getClusterTime()); echo "\nSessions A and B have equivalent cluster times:\n"; var_dump($sessionA->getClusterTime() == $sessionB->getClusterTime()); ?> ===DONE=== --EXPECTF-- Initial cluster time of session B: NULL Cluster time after advancing session B: object(stdClass)#%d (%d) { ["clusterTime"]=> object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(%d) "%d" ["timestamp"]=> string(%d) "%d" } ["signature"]=> %a } Sessions A and B have equivalent cluster times: bool(true) ===DONE=== mongodb-1.21.0/tests/session/session-advanceOperationTime-001.phpt0000644000175100001660000000233614760300421021744 0ustar --TEST-- MongoDB\Driver\Session::advanceOperationTime() --SKIPIF-- --FILE-- startSession(); $sessionB = $manager->startSession(); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $sessionA]); echo "Initial operation time of session B:\n"; var_dump($sessionB->getOperationTime()); $sessionB->advanceOperationTime($sessionA->getOperationTime()); echo "\nOperation time after advancing session B:\n"; var_dump($sessionB->getOperationTime()); echo "\nSessions A and B have equivalent operation times:\n"; var_dump($sessionA->getOperationTime() == $sessionB->getOperationTime()); ?> ===DONE=== --EXPECTF-- Initial operation time of session B: NULL Operation time after advancing session B: object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(%d) "%d" ["timestamp"]=> string(%d) "%d" } Sessions A and B have equivalent operation times: bool(true) ===DONE=== mongodb-1.21.0/tests/session/session-advanceOperationTime-002.phpt0000644000175100001660000000157314760300421021747 0ustar --TEST-- MongoDB\Driver\Session::advanceOperationTime() with Timestamp --SKIPIF-- --FILE-- startSession(); echo "Initial operation time of session:\n"; var_dump($session->getOperationTime()); $session->advanceOperationTime(new MongoDB\BSON\Timestamp(5678, 1234)); echo "\nOperation time after advancing session:\n"; var_dump($session->getOperationTime()); ?> ===DONE=== --EXPECTF-- Initial operation time of session: NULL Operation time after advancing session: object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(4) "5678" ["timestamp"]=> string(4) "1234" } ===DONE=== mongodb-1.21.0/tests/session/session-advanceOperationTime-003.phpt0000644000175100001660000000231114760300421021737 0ustar --TEST-- MongoDB\Driver\Session::advanceOperationTime() with TimestampInterface --SKIPIF-- --FILE-- getIncrement(), $this->getTimestamp()); } } $manager = create_test_manager(); $session = $manager->startSession(); echo "Initial operation time of session:\n"; var_dump($session->getOperationTime()); $session->advanceOperationTime(new MyTimestamp); echo "\nOperation time after advancing session:\n"; var_dump($session->getOperationTime()); ?> ===DONE=== --EXPECTF-- Initial operation time of session: NULL Operation time after advancing session: object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(4) "5678" ["timestamp"]=> string(4) "1234" } ===DONE=== mongodb-1.21.0/tests/session/session-advanceOperationTime_error-001.phpt0000644000175100001660000000401514760300421023151 0ustar --TEST-- MongoDB\Driver\Session::advanceOperationTime() with TimestampInterface exceptions --SKIPIF-- --FILE-- failIncrement = $failIncrement; $this->failTimestamp = $failTimestamp; } public function getIncrement(): int { if ($this->failIncrement) { throw new Exception('getIncrement() failed'); } return 5678; } public function getTimestamp(): int { if ($this->failTimestamp) { throw new Exception('getTimestamp() failed'); } return 1234; } public function __toString(): string { return sprintf('[%d:%d]', $this->getIncrement(), $this->getTimestamp()); } } $manager = create_test_manager(); $session = $manager->startSession(); echo "Initial operation time of session:\n"; var_dump($session->getOperationTime()); $timestamps = [ new MyTimestamp(true, false), new MyTimestamp(false, true), new MyTimestamp(true, true), ]; foreach ($timestamps as $timestamp) { echo "\n", throws(function() use ($session, $timestamp) { $session->advanceOperationTime($timestamp); }, 'Exception'), "\n"; echo "\nOperation time after advancing session fails:\n"; var_dump($session->getOperationTime()); } ?> ===DONE=== --EXPECT-- Initial operation time of session: NULL OK: Got Exception getIncrement() failed Operation time after advancing session fails: NULL OK: Got Exception getTimestamp() failed Operation time after advancing session fails: NULL OK: Got Exception getTimestamp() failed Operation time after advancing session fails: NULL ===DONE=== mongodb-1.21.0/tests/session/session-commitTransaction-001.phpt0000644000175100001660000000505714760300421021344 0ustar --TEST-- MongoDB\Driver\Session::commitTransaction() applies w:majority when retrying --SKIPIF-- --FILE-- manager = create_test_manager(); $this->manager->executeCommand( DATABASE_NAME, new MongoDB\Driver\Command(['create' => COLLECTION_NAME]), ['writeConcern' => new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY)] ); } public function run(array $startTransactionOptions) { $session = $this->manager->startSession(); $session->startTransaction($startTransactionOptions); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $this->manager->executeBulkWrite(NS, $bulk, ['session' => $session]); MongoDB\Driver\Monitoring\addSubscriber($this); $session->commitTransaction(); $session->commitTransaction(); MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { if ($event->getCommandName() !== 'commitTransaction') { return; } printf("commitTransaction included write concern: %s\n", json_encode($event->getCommand()->writeConcern)); } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } $test = new Test; echo "Applies w:majority and default wtimeout when retrying commitTransaction\n"; $test->run(['writeConcern' => new MongoDB\Driver\WriteConcern(1)]); echo "\nPreserves other WC options when retrying commitTransaction\n"; $test->run(['writeConcern' => new MongoDB\Driver\WriteConcern(1, 5000)]); ?> ===DONE=== --EXPECT-- Applies w:majority and default wtimeout when retrying commitTransaction commitTransaction included write concern: {"w":1} commitTransaction included write concern: {"w":"majority","wtimeout":10000} Preserves other WC options when retrying commitTransaction commitTransaction included write concern: {"w":1,"wtimeout":5000} commitTransaction included write concern: {"w":"majority","wtimeout":5000} ===DONE=== mongodb-1.21.0/tests/session/session-constants.phpt0000644000175100001660000000076214760300421017362 0ustar --TEST-- MongoDB\Driver\Session constants --FILE-- ===DONE=== --EXPECTF-- string(4) "none" string(8) "starting" string(11) "in_progress" string(9) "committed" string(7) "aborted" ===DONE=== mongodb-1.21.0/tests/session/session-debug-001.phpt0000644000175100001660000000163014760300421016725 0ustar --TEST-- MongoDB\Driver\Session debug output (before an operation) --SKIPIF-- --FILE-- startSession(); var_dump($session); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Session)#%d (%d) { ["logicalSessionId"]=> array(1) { ["id"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%a" ["type"]=> int(4) } } ["clusterTime"]=> NULL ["causalConsistency"]=> bool(true) ["snapshot"]=> bool(false) ["operationTime"]=> NULL ["server"]=> NULL ["dirty"]=> bool(false) ["inTransaction"]=> bool(false) ["transactionState"]=> string(4) "none" ["transactionOptions"]=> NULL } ===DONE=== mongodb-1.21.0/tests/session/session-debug-002.phpt0000644000175100001660000000260314760300421016727 0ustar --TEST-- MongoDB\Driver\Session debug output (after an operation) --SKIPIF-- --FILE-- startSession(); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); var_dump($session); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Session)#%d (%d) { ["logicalSessionId"]=> array(1) { ["id"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%a" ["type"]=> int(4) } } ["clusterTime"]=> array(2) { ["clusterTime"]=> object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(%d) "%d" ["timestamp"]=> string(%d) "%d" } ["signature"]=> %a } ["causalConsistency"]=> bool(true) ["snapshot"]=> bool(false) ["operationTime"]=> object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(%d) "%d" ["timestamp"]=> string(%d) "%d" } ["server"]=> NULL ["dirty"]=> bool(false) ["inTransaction"]=> bool(false) ["transactionState"]=> string(4) "none" ["transactionOptions"]=> NULL } ===DONE=== mongodb-1.21.0/tests/session/session-debug-003.phpt0000644000175100001660000000167314760300421016736 0ustar --TEST-- MongoDB\Driver\Session debug output (causalConsistency=false) --SKIPIF-- --FILE-- startSession(['causalConsistency' => false]); var_dump($session); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Session)#%d (%d) { ["logicalSessionId"]=> array(1) { ["id"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%a" ["type"]=> int(4) } } ["clusterTime"]=> NULL ["causalConsistency"]=> bool(false) ["snapshot"]=> bool(false) ["operationTime"]=> NULL ["server"]=> NULL ["dirty"]=> bool(false) ["inTransaction"]=> bool(false) ["transactionState"]=> string(4) "none" ["transactionOptions"]=> NULL } ===DONE=== mongodb-1.21.0/tests/session/session-debug-004.phpt0000644000175100001660000000120214760300421016723 0ustar --TEST-- MongoDB\Driver\Session debug output (after ending session) --SKIPIF-- --FILE-- startSession(); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); $session->endSession(); var_dump($session); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Session)#%d (%d) { ["ended"]=> bool(true) } ===DONE=== mongodb-1.21.0/tests/session/session-debug-005.phpt0000644000175100001660000000335214760300421016734 0ustar --TEST-- MongoDB\Driver\Session debug output (during a pinned transaction) --SKIPIF-- --FILE-- selectServer(new \MongoDB\Driver\ReadPreference('primary')); $session = $manager->startSession(); $session->startTransaction(); $query = new MongoDB\Driver\Query([]); $server->executeQuery(NS, $query, ['session' => $session]); var_dump($session); $session->abortTransaction(); $session->endSession(); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Session)#%d (%d) { ["logicalSessionId"]=> array(1) { ["id"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%a" ["type"]=> int(4) } } ["clusterTime"]=> array(2) { ["clusterTime"]=> object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(%d) "%d" ["timestamp"]=> string(%d) "%d" } ["signature"]=> %a } ["causalConsistency"]=> bool(true) ["snapshot"]=> bool(false) ["operationTime"]=> object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(%d) "%d" ["timestamp"]=> string(%d) "%d" } ["server"]=> object(MongoDB\Driver\Server)#%d (%d) { %a } ["dirty"]=> bool(false) ["inTransaction"]=> bool(true) ["transactionState"]=> string(11) "in_progress" ["transactionOptions"]=> array(1) { ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(7) "primary" } } } ===DONE=== mongodb-1.21.0/tests/session/session-debug-006.phpt0000644000175100001660000000317214760300421016735 0ustar --TEST-- MongoDB\Driver\Session debug output (with transaction options) --SKIPIF-- --FILE-- startSession(); $options = [ 'maxCommitTimeMS' => 1, 'readConcern' => new \MongoDB\Driver\ReadConcern('majority'), 'readPreference' => new \MongoDB\Driver\ReadPreference('primaryPreferred'), 'writeConcern' => new \MongoDB\Driver\WriteConcern('majority'), ]; $session->startTransaction($options); var_dump($session); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Session)#%d (%d) { ["logicalSessionId"]=> array(1) { ["id"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%a" ["type"]=> int(4) } } ["clusterTime"]=> NULL ["causalConsistency"]=> bool(true) ["snapshot"]=> bool(false) ["operationTime"]=> NULL ["server"]=> NULL ["dirty"]=> bool(false) ["inTransaction"]=> bool(true) ["transactionState"]=> string(8) "starting" ["transactionOptions"]=> array(4) { ["maxCommitTimeMS"]=> int(1) ["readConcern"]=> object(MongoDB\Driver\ReadConcern)#%d (%d) { ["level"]=> string(8) "majority" } ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (%d) { ["mode"]=> string(16) "primaryPreferred" } ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } } } ===DONE=== mongodb-1.21.0/tests/session/session-debug-007.phpt0000644000175100001660000000164614760300421016742 0ustar --TEST-- MongoDB\Driver\Session debug output (snapshot=true) --SKIPIF-- --FILE-- startSession(['snapshot' => true]); var_dump($session); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\Session)#%d (%d) { ["logicalSessionId"]=> array(1) { ["id"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(16) "%a" ["type"]=> int(4) } } ["clusterTime"]=> NULL ["causalConsistency"]=> bool(false) ["snapshot"]=> bool(true) ["operationTime"]=> NULL ["server"]=> NULL ["dirty"]=> bool(false) ["inTransaction"]=> bool(false) ["transactionState"]=> string(4) "none" ["transactionOptions"]=> NULL } ===DONE=== mongodb-1.21.0/tests/session/session-endSession-001.phpt0000644000175100001660000000615614760300421017761 0ustar --TEST-- MongoDB\Driver\Session::endSession() Calling methods after session has been ended --SKIPIF-- --FILE-- startSession(); $sessionA->endSession(); echo throws(function() use ($sessionA) { $sessionA->startTransaction(); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; echo throws(function() use ($sessionA) { $sessionA->abortTransaction(); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; /* The reason that startTransaction is in here twice is that this script can run without exception * if the endSession() call is taken out. */ echo throws(function() use ($sessionA) { $sessionA->startTransaction(); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; echo throws(function() use ($sessionA) { $sessionA->commitTransaction(); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; echo throws(function() use ($sessionA) { $sessionA->advanceOperationTime(new \MongoDB\BSON\Timestamp(1900123000, 1900123000)); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; echo throws(function() use ($sessionA) { $sessionA->advanceClusterTime([]); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; echo throws(function() use ($sessionA) { var_dump($sessionA->getClusterTime()); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; echo throws(function() use ($sessionA) { var_dump($sessionA->getLogicalSessionId()); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; echo throws(function() use ($sessionA) { var_dump($sessionA->getOperationTime()); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; echo throws(function() use ($sessionA) { $sessionA->isInTransaction(); }, 'MongoDB\Driver\Exception\LogicException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'startTransaction', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'abortTransaction', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'startTransaction', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'commitTransaction', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'advanceOperationTime', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'advanceClusterTime', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'getClusterTime', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'getLogicalSessionId', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'getOperationTime', as the session has already been ended. OK: Got MongoDB\Driver\Exception\LogicException Cannot call 'isInTransaction', as the session has already been ended. ===DONE=== mongodb-1.21.0/tests/session/session-endSession-002.phpt0000644000175100001660000000073614760300421017760 0ustar --TEST-- MongoDB\Driver\Session::endSession() Calling method multiple times --SKIPIF-- --FILE-- startSession(); $sessionA->endSession(); $sessionA->endSession(); $sessionA->endSession(); ?> ===DONE=== --EXPECT-- ===DONE=== mongodb-1.21.0/tests/session/session-getClusterTime-001.phpt0000644000175100001660000000167414760300421020607 0ustar --TEST-- MongoDB\Driver\Session::getClusterTime() --SKIPIF-- --FILE-- startSession(); echo "Initial cluster time:\n"; var_dump($session->getClusterTime()); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); echo "\nCluster time after command:\n"; var_dump($session->getClusterTime()); ?> ===DONE=== --EXPECTF-- Initial cluster time: NULL Cluster time after command: object(stdClass)#%d (%d) { ["clusterTime"]=> object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(%d) "%d" ["timestamp"]=> string(%d) "%d" } ["signature"]=> %a } ===DONE=== mongodb-1.21.0/tests/session/session-getLogicalSessionId-001.phpt0000644000175100001660000000137014760300421021533 0ustar --TEST-- MongoDB\Driver\Session::getLogicalSessionId() --SKIPIF-- --FILE-- startSession(); $lsid = $session->getLogicalSessionId(); /* Note: we avoid dumping the Binary object as it may contain bytes that * intefere with the test suite's ability to compare expected output. */ var_dump($lsid instanceof stdClass); var_dump($lsid->id instanceof MongoDB\BSON\Binary); var_dump($lsid->id->getType() === MongoDB\BSON\Binary::TYPE_UUID); ?> ===DONE=== --EXPECTF-- bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/session/session-getOperationTime-001.phpt0000644000175100001660000000156614760300421021126 0ustar --TEST-- MongoDB\Driver\Session::getOperationTime() --SKIPIF-- --FILE-- startSession(); echo "Initial operation time:\n"; var_dump($session->getOperationTime()); $command = new MongoDB\Driver\Command(['ping' => 1]); $manager->executeCommand(DATABASE_NAME, $command, ['session' => $session]); echo "\nOperation time after command:\n"; var_dump($session->getOperationTime()); ?> ===DONE=== --EXPECTF-- Initial operation time: NULL Operation time after command: object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(%d) "%d" ["timestamp"]=> string(%d) "%d" } ===DONE=== mongodb-1.21.0/tests/session/session-getTransactionOptions-001.phpt0000644000175100001660000000353014760300421022201 0ustar --TEST-- MongoDB\Driver\Session::getTransactionOptions() --SKIPIF-- --FILE-- startSession(); var_dump($session->getTransactionOptions()); $options = [ ['maxCommitTimeMS' => 0], ['maxCommitTimeMS' => 1], ['readConcern' => new \MongoDB\Driver\ReadConcern('majority')], ['readPreference' => new \MongoDB\Driver\ReadPreference('primaryPreferred')], ['writeConcern' => new \MongoDB\Driver\WriteConcern('majority')], ]; foreach ($options as $test) { // Session no longer needs to be restarted once CDRIVER-3366 is fixed $session = $manager->startSession(); $session->startTransaction($test); var_dump($session->getTransactionOptions()); } ?> ===DONE=== --EXPECTF-- NULL array(1) { ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (1) { ["mode"]=> string(7) "primary" } } array(2) { ["maxCommitTimeMS"]=> int(1) ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (1) { ["mode"]=> string(7) "primary" } } array(2) { ["readConcern"]=> object(MongoDB\Driver\ReadConcern)#%d (1) { ["level"]=> string(8) "majority" } ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (1) { ["mode"]=> string(7) "primary" } } array(1) { ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (1) { ["mode"]=> string(16) "primaryPreferred" } } array(2) { ["readPreference"]=> object(MongoDB\Driver\ReadPreference)#%d (1) { ["mode"]=> string(7) "primary" } ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (1) { ["w"]=> string(8) "majority" } } ===DONE=== mongodb-1.21.0/tests/session/session-getTransactionState-001.phpt0000644000175100001660000000460514760300421021632 0ustar --TEST-- MongoDB\Driver\Session::getTransactionState() --SKIPIF-- --FILE-- COLLECTION_NAME, ]); $manager->executeCommand(DATABASE_NAME, $cmd); /* Start a session */ $session = $manager->startSession(); echo "Test case: Empty transaction, and aborted empty transaction\n"; var_dump($session->getTransactionState()); $session->startTransaction(); var_dump($session->getTransactionState()); $session->abortTransaction(); var_dump($session->getTransactionState()); echo "\n"; echo "Test case: Empty transaction, and committed empty transaction\n"; $session->startTransaction(); var_dump($session->getTransactionState()); $session->commitTransaction(); var_dump($session->getTransactionState()); echo "\n"; echo "Test case: Aborted transaction with one operation\n"; $session->startTransaction(); var_dump($session->getTransactionState()); $bw = new \MongoDB\Driver\BulkWrite(); $bw->insert( [ '_id' => 0, 'msg' => 'Initial Value' ] ); $manager->executeBulkWrite(NS, $bw, ['session' => $session]); var_dump($session->getTransactionState()); $session->abortTransaction(); var_dump($session->getTransactionState()); echo "\n"; echo "Test case: Committed transaction with one operation\n"; $session->startTransaction(); var_dump($session->getTransactionState()); $bw = new \MongoDB\Driver\BulkWrite(); $bw->insert( [ '_id' => 0, 'msg' => 'Initial Value' ] ); $manager->executeBulkWrite(NS, $bw, ['session' => $session]); var_dump($session->getTransactionState()); $session->commitTransaction(); var_dump($session->getTransactionState()); ?> ===DONE=== --EXPECTF-- Test case: Empty transaction, and aborted empty transaction string(4) "none" string(8) "starting" string(7) "aborted" Test case: Empty transaction, and committed empty transaction string(8) "starting" string(9) "committed" Test case: Aborted transaction with one operation string(8) "starting" string(11) "in_progress" string(7) "aborted" Test case: Committed transaction with one operation string(8) "starting" string(11) "in_progress" string(9) "committed" ===DONE=== mongodb-1.21.0/tests/session/session-isDirty-001.phpt0000644000175100001660000000245114760300421017270 0ustar --TEST-- MongoDB\Driver\Session::isDirty() --SKIPIF-- --FILE-- selectServer(); $session = $manager->startSession(); printf("New session is dirty: %s\n", $session->isDirty() ? 'yes' : 'no'); $command = new MongoDB\Driver\Command(['ping' => 1]); $server->executeCommand(DATABASE_NAME, $command, ['session' => $session]); printf("Session after successful command is dirty: %s\n", $session->isDirty() ? 'yes' : 'no'); configureTargetedFailPoint($server, 'failCommand', [ 'times' => 1 ], [ 'failCommands' => ['ping'], 'closeConnection' => true ]); throws(function() use ($server, $command, $session) { $server->executeCommand(DATABASE_NAME, $command, ['session' => $session]); }, MongoDB\Driver\Exception\ConnectionTimeoutException::class); printf("Session after network error is dirty: %s\n", $session->isDirty() ? 'yes' : 'no'); ?> ===DONE=== --EXPECT-- New session is dirty: no Session after successful command is dirty: no OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException Session after network error is dirty: yes ===DONE=== mongodb-1.21.0/tests/session/session-isInTransaction-001.phpt0000644000175100001660000000373514760300421020757 0ustar --TEST-- MongoDB\Driver\Session::isInTransaction() --SKIPIF-- --FILE-- COLLECTION_NAME, ]); $manager->executeCommand(DATABASE_NAME, $cmd); /* Start a session */ $session = $manager->startSession(); /* Empty transaction, and aborted empty transaction */ var_dump($session->isInTransaction()); $session->startTransaction(); var_dump($session->isInTransaction()); $session->abortTransaction(); var_dump($session->isInTransaction()); /* Empty transaction, and committed empty transaction */ var_dump($session->isInTransaction()); $session->startTransaction(); var_dump($session->isInTransaction()); $session->commitTransaction(); var_dump($session->isInTransaction()); /* Aborted transaction with one operation */ var_dump($session->isInTransaction()); $session->startTransaction(); $bw = new \MongoDB\Driver\BulkWrite(); $bw->insert( [ '_id' => 0, 'msg' => 'Initial Value' ] ); $manager->executeBulkWrite(NS, $bw, ['session' => $session]); var_dump($session->isInTransaction()); $session->abortTransaction(); var_dump($session->isInTransaction()); /* Committed transaction with one operation */ var_dump($session->isInTransaction()); $session->startTransaction(); $bw = new \MongoDB\Driver\BulkWrite(); $bw->insert( [ '_id' => 0, 'msg' => 'Initial Value' ] ); $manager->executeBulkWrite(NS, $bw, ['session' => $session]); var_dump($session->isInTransaction()); $session->commitTransaction(); var_dump($session->isInTransaction()); ?> ===DONE=== --EXPECTF-- bool(false) bool(true) bool(false) bool(false) bool(true) bool(false) bool(false) bool(true) bool(false) bool(false) bool(true) bool(false) ===DONE=== mongodb-1.21.0/tests/session/session-startTransaction-001.phpt0000644000175100001660000000103614760300421021202 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() ensure that methods can be called --SKIPIF-- --FILE-- startSession(); $session->startTransaction(); $session->abortTransaction(); $session->startTransaction(); $session->commitTransaction(); ?> ===DONE=== --EXPECTF-- ===DONE=== mongodb-1.21.0/tests/session/session-startTransaction_error-001.phpt0000644000175100001660000000117214760300421022414 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() twice --SKIPIF-- --FILE-- startSession(); $session->startTransaction(); echo throws(function() use ($session) { $session->startTransaction(); }, 'MongoDB\Driver\Exception\RuntimeException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\RuntimeException Transaction already in progress ===DONE=== mongodb-1.21.0/tests/session/session-startTransaction_error-002.phpt0000644000175100001660000000755014760300421022423 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() with wrong values in options array --SKIPIF-- --FILE-- startSession(); $options = [ [ 'maxCommitTimeMS' => -1 ], [ 'readConcern' => 42 ], [ 'readConcern' => new stdClass ], [ 'readConcern' => new \MongoDB\Driver\WriteConcern( 2 ) ], [ 'readPreference' => 42 ], [ 'readPreference' => new stdClass ], [ 'readPreference' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ) ], [ 'writeConcern' => 42 ], [ 'writeConcern' => new stdClass ], [ 'writeConcern' => new \MongoDB\Driver\ReadPreference( \MongoDB\Driver\ReadPreference::SECONDARY ) ], [ 'readConcern' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ), 'readPreference' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ), ], [ 'readConcern' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ), 'writeConcern' => new \MongoDB\Driver\ReadPreference( \MongoDB\Driver\ReadPreference::SECONDARY ), ], [ 'readPreference' => new \MongoDB\Driver\ReadPreference( \MongoDB\Driver\ReadPreference::SECONDARY ), 'writeConcern' => new \MongoDB\Driver\ReadPreference( \MongoDB\Driver\ReadPreference::SECONDARY ), ], ]; foreach ($options as $txnOptions) { echo throws(function() use ($session, $txnOptions) { $session->startTransaction($txnOptions); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; } echo raises(function() use ($session) { $session->startTransaction([ 'maxCommitTimeMS' => new stdClass ]); }, E_NOTICE | E_WARNING), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "maxCommitTimeMS" option to be >= 0, -1 given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readConcern" option to be MongoDB\Driver\ReadConcern, MongoDB\Driver\WriteConcern given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, MongoDB\Driver\ReadConcern given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, int given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, MongoDB\Driver\ReadPreference given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "readPreference" option to be MongoDB\Driver\ReadPreference, MongoDB\Driver\ReadConcern given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, MongoDB\Driver\ReadPreference given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected "writeConcern" option to be MongoDB\Driver\WriteConcern, MongoDB\Driver\ReadPreference given OK: Got %r(E_NOTICE|E_WARNING)%r Object of class stdClass could not be converted to int ===DONE=== mongodb-1.21.0/tests/session/session-startTransaction_error-004.phpt0000644000175100001660000000213614760300421022420 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() with wrong argument for options array (PHP 7) --SKIPIF-- ', '7.99'); ?> --FILE-- startSession(); $options = [ 2, new stdClass, ]; foreach ($options as $txnOptions) { echo throws(function () use ($session, $txnOptions) { $session->startTransaction($txnOptions); }, TypeError::class), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got TypeError Argument 1 passed to MongoDB\Driver\Session::startTransaction() must be of the type array%r( or null)?%r, int given OK: Got TypeError Argument 1 passed to MongoDB\Driver\Session::startTransaction() must be of the type array%r( or null)?%r, object given ===DONE=== mongodb-1.21.0/tests/session/session-startTransaction_error-005.phpt0000644000175100001660000000167414760300421022427 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() with wrong argument for options array (PHP 8) --SKIPIF-- --FILE-- startSession(); $options = [ 2, new stdClass, ]; foreach ($options as $txnOptions) { echo throws(function () use ($session, $txnOptions) { $session->startTransaction($txnOptions); }, TypeError::class), "\n"; } ?> ===DONE=== --EXPECTF-- OK: Got TypeError %r\\?%rMongoDB\Driver\Session::startTransaction()%sarray, int given OK: Got TypeError %r\\?%rMongoDB\Driver\Session::startTransaction()%sarray, %r(object|stdClass)%r given ===DONE=== mongodb-1.21.0/tests/session/session-startTransaction_error-006.phpt0000644000175100001660000000132214760300421022416 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() throws an error on replicasets < 4.0 --SKIPIF-- =', '4.0'); ?> --FILE-- startSession(); echo throws(function () use ($session) { $session->startTransaction(); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException Multi-document transactions are not supported by this server version ===DONE=== mongodb-1.21.0/tests/session/session-startTransaction_error-007.phpt0000644000175100001660000000135414760300421022424 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() throws an error on sharded clusters < 4.2 --SKIPIF-- =', '4.2'); ?> --FILE-- startSession(); echo throws(function () use ($session) { $session->startTransaction(); }, MongoDB\Driver\Exception\RuntimeException::class), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\RuntimeException Multi-document transactions are not supported by this server version ===DONE=== mongodb-1.21.0/tests/session/transaction-integration-001.phpt0000644000175100001660000000520614760300421021027 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() Committing a transaction with example for how to handle failures --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => $EMPLOYEES_COL ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $manager->executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => $EVENTS_COL ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); /* Do the transaction */ $session = $manager->startSession(); $session->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); while (true) { try { $cmd = new \MongoDB\Driver\Command( [ 'update' => $EMPLOYEES_COL, 'updates' => [ [ 'q' => [ 'employee' => 3 ], 'u' => [ '$set' => [ 'status' => 'Inactive' ] ], ] ] ] ); $manager->executeCommand(DATABASE_NAME, $cmd, ['session' => $session]); $cmd = new \MongoDB\Driver\Command( [ 'insert' => $EVENTS_COL, 'documents' => [ [ 'employee' => 3, 'status' => [ 'new' => 'Inactive', 'old' => 'Active' ] ] ] ] ); $manager->executeCommand(DATABASE_NAME, $cmd, ['session' => $session]); $session->commitTransaction(); echo "Transaction committed.\n";break; } catch (\MongoDB\Driver\Exception\CommandException $e) { $rd = $e->getResultDocument(); if (isset($rd->errorLabels) && in_array('TransientTransactionError', $rd->errorLabels)) { echo "Temporary error: ", $e->getMessage(), ", retrying...\n"; $rd = $e->getResultDocument(); var_dump($rd); continue; } else { var_dump($e); } break; } } ?> ===DONE=== --EXPECTF-- Transaction committed. ===DONE=== mongodb-1.21.0/tests/session/transaction-integration-002.phpt0000644000175100001660000000463214760300421021032 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() Transient Error Test --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); /* Insert Data */ $bw = new \MongoDB\Driver\BulkWrite(); $bw->insert( [ '_id' => 0, 'msg' => 'Initial Value' ] ); $manager->executeBulkWrite(NS, $bw); /* First 'thread', try to update document, but don't close transaction */ $sessionA = $manager->startSession(); $sessionA->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $cmd = new \MongoDB\Driver\Command( [ 'update' => COLLECTION_NAME, 'updates' => [ [ 'q' => [ '_id' => 0 ], 'u' => [ '$set' => [ 'msg' => 'Update from session A' ] ], ] ] ] ); $manager->executeCommand(DATABASE_NAME, $cmd, ['session' => $sessionA]); /* Second 'thread', try to update the same document, should trigger exception. In handler, commit * first settion, verify result, and redo this transaction. */ $sessionB = $manager->startSession(); $sessionB->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); try { $cmd = new \MongoDB\Driver\Command( [ 'update' => COLLECTION_NAME, 'updates' => [ [ 'q' => [ '_id' => 0 ], 'u' => [ '$set' => [ 'msg' => 'Update from session B' ] ], ] ] ] ); $manager->executeCommand(DATABASE_NAME, $cmd, ['session' => $sessionB]); } catch (MongoDB\Driver\Exception\CommandException $e) { echo $e->hasErrorLabel('TransientTransactionError') ? "found a TransientTransactionError" : "did NOT get a TransientTransactionError", "\n"; } ?> ===DONE=== --EXPECTF-- found a TransientTransactionError ===DONE=== mongodb-1.21.0/tests/session/transaction-integration-003.phpt0000644000175100001660000000407414760300421021033 0ustar --TEST-- MongoDB\Driver\Session::startTransaction() Transient Error Test --SKIPIF-- --FILE-- COLLECTION_NAME, ]); $manager->executeCommand(DATABASE_NAME, $cmd); /* Insert Data */ $bw = new \MongoDB\Driver\BulkWrite(); $bw->insert( [ '_id' => 0, 'msg' => 'Initial Value' ] ); $manager->executeBulkWrite(NS, $bw); /* First 'thread', try to update document, but don't close transaction */ $sessionA = $manager->startSession(); $sessionA->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); $bw = new \MongoDB\Driver\BulkWrite(); $bw->update( [ '_id' => 0 ], [ '$set' => [ 'msg' => 'Update from session A' ] ] ); $manager->executeBulkWrite(NS, $bw, ['session' => $sessionA]); /* Second 'thread', try to update the same document, should trigger exception. In handler, commit * first settion, verify result, and redo this transaction. */ $sessionB = $manager->startSession(); $sessionB->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); try { $bw = new \MongoDB\Driver\BulkWrite(); $bw->update( [ '_id' => 0 ], [ '$set' => [ 'msg' => 'Update from session B' ] ] ); $manager->executeBulkWrite(NS, $bw, ['session' => $sessionB]); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { echo $e->hasErrorLabel('TransientTransactionError') ? "found a TransientTransactionError" : "did NOT get a TransientTransactionError", "\n"; } ?> ===DONE=== --EXPECTF-- found a TransientTransactionError ===DONE=== mongodb-1.21.0/tests/session/transaction-integration_error-001.phpt0000644000175100001660000000436214760300421022242 0ustar --TEST-- MongoDB\Driver\Session: Setting per-op readConcern or writeConcern in transaction (executeCommand) --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); /* Do the transaction */ $session = $manager->startSession(); $session->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); echo throws(function() use ($manager, $session) { $cmd = new \MongoDB\Driver\Command( [ 'update' => COLLECTION_NAME, 'updates' => [ [ 'q' => [ 'employee' => 3 ], 'u' => [ '$set' => [ 'status' => 'Inactive' ] ] ] ] ] ); $manager->executeCommand( DATABASE_NAME, $cmd, [ 'session' => $session, 'readConcern' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ) ] ); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() use ($manager, $session) { $cmd = new \MongoDB\Driver\Command( [ 'update' => COLLECTION_NAME, 'updates' => [ [ 'q' => [ 'employee' => 3 ], 'u' => [ '$set' => [ 'status' => 'Inactive' ] ] ] ] ] ); $manager->executeCommand( DATABASE_NAME, $cmd, [ 'session' => $session, 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot set read concern after starting transaction OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot set write concern after starting transaction ===DONE=== mongodb-1.21.0/tests/session/transaction-integration_error-002.phpt0000644000175100001660000000304714760300421022242 0ustar --TEST-- MongoDB\Driver\Session: Setting per-op readConcern in transaction (executeReadCommand) --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); /* Do the transaction */ $session = $manager->startSession(); $session->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); echo throws(function() use ($manager, $session) { $cmd = new \MongoDB\Driver\Command( [ 'count' => COLLECTION_NAME, 'query' => [ 'q' => [ 'employee' => 3 ] ] ] ); $manager->executeReadCommand( DATABASE_NAME, $cmd, [ 'session' => $session, 'readConcern' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ) ] ); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot set read concern after starting transaction ===DONE=== mongodb-1.21.0/tests/session/transaction-integration_error-003.phpt0000644000175100001660000000315114760300421022237 0ustar --TEST-- MongoDB\Driver\Session: Setting per-op writeConcern in transaction (executeWriteCommand) --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); /* Do the transaction */ $session = $manager->startSession(); $session->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); echo throws(function() use ($manager, $session) { $cmd = new \MongoDB\Driver\Command( [ 'update' => COLLECTION_NAME, 'updates' => [ [ 'q' => [ 'employee' => 3 ], 'u' => [ '$set' => [ 'status' => 'Inactive' ] ] ] ] ] ); $manager->executeWriteCommand( DATABASE_NAME, $cmd, [ 'session' => $session, 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot set write concern after starting transaction ===DONE=== mongodb-1.21.0/tests/session/transaction-integration_error-004.phpt0000644000175100001660000000432514760300421022244 0ustar --TEST-- MongoDB\Driver\Session: Setting per-op readConcern or writeConcern in transaction (executeReadWriteCommand) --SKIPIF-- --FILE-- executeCommand( DATABASE_NAME, new \MongoDB\Driver\Command([ 'create' => COLLECTION_NAME ]), [ 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); /* Do the transaction */ $session = $manager->startSession(); $session->startTransaction( [ 'readConcern' => new \MongoDB\Driver\ReadConcern( "snapshot" ), 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); echo throws(function() use ($manager, $session) { $cmd = new \MongoDB\Driver\Command( [ 'count' => COLLECTION_NAME, 'query' => [ 'q' => [ 'employee' => 3 ] ] ] ); $manager->executeReadWriteCommand( DATABASE_NAME, $cmd, [ 'session' => $session, 'readConcern' => new \MongoDB\Driver\ReadConcern( \MongoDB\Driver\ReadConcern::LOCAL ) ] ); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; echo throws(function() use ($manager, $session) { $cmd = new \MongoDB\Driver\Command( [ 'update' => COLLECTION_NAME, 'updates' => [ [ 'q' => [ 'employee' => 3 ], 'u' => [ '$set' => [ 'status' => 'Inactive' ] ] ] ] ] ); $manager->executeReadWriteCommand( DATABASE_NAME, $cmd, [ 'session' => $session, 'writeConcern' => new \MongoDB\Driver\WriteConcern( \MongoDB\Driver\WriteConcern::MAJORITY ) ] ); }, "MongoDB\Driver\Exception\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot set read concern after starting transaction OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot set write concern after starting transaction ===DONE=== mongodb-1.21.0/tests/standalone/bug0231.phpt0000644000175100001660000000142214760300421015407 0ustar --TEST-- Multiple managers sharing streams: Using stream after closing manager --SKIPIF-- --FILE-- 1)); $retval = $manager->executeCommand("admin", $listdatabases); $retval = $manager2->executeCommand("admin", $listdatabases); foreach($retval as $database) { } $manager = null; $retval = $manager2->executeCommand("admin", $listdatabases); foreach($retval as $database) { } echo "All Good!\n"; ?> ===DONE=== --EXPECT-- All Good! ===DONE=== mongodb-1.21.0/tests/standalone/bug0357.phpt0000644000175100001660000000113014760300421015414 0ustar --TEST-- PHPC-357: The exception for "invalid namespace" does not list the broken name --SKIPIF-- --FILE-- executeQuery( 'demo', $c ); }, "MongoDB\\Driver\\Exception\\InvalidArgumentException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Invalid namespace provided: demo ===DONE=== mongodb-1.21.0/tests/standalone/bug0545.phpt0000644000175100001660000000626214760300421015426 0ustar --TEST-- PHPC-545: Update does not serialize embedded Persistable's __pclass field --SKIPIF-- --FILE-- $value) { $this->{$name} = $value; } } } #[\AllowDynamicProperties] class Page implements MongoDB\BSON\Persistable { #[\ReturnTypeWillChange] public function bsonSerialize() { $data = get_object_vars($this); return $data; } public function bsonUnserialize(array $data): void { foreach ($data as $name => $value) { $this->{$name} = $value; } } } // Aux $manager = create_test_manager(); $wc = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY); // Create $book = new Book(); $book->title = 'Unnameable'; $book->pages = []; $page1 = new Page(); $page1->content = 'Lorem ipsum'; $book->pages[] = $page1; $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert($book); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $wc]); printf("Inserted %d document(s)\n", $result->getInsertedCount()); // Read $query = new MongoDB\Driver\Query(['title' => $book->title]); $cursor = $manager->executeQuery(NS, $query); $bookAfterInsert = $cursor->toArray()[0]; // Update $bookAfterInsert->description = 'An interesting document'; $page2 = new Page(); $page2->content = 'Dolor sit amet'; $bookAfterInsert->pages[] = $page2; $bulk = new MongoDB\Driver\BulkWrite; $bulk->update(['title' => $bookAfterInsert->title], $bookAfterInsert); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $wc]); printf("Modified %d document(s)\n", $result->getModifiedCount()); // Read (again) $query = new MongoDB\Driver\Query(['title' => $bookAfterInsert->title]); $cursor = $manager->executeQuery(NS, $query); $bookAfterUpdate = $cursor->toArray()[0]; var_dump($bookAfterUpdate); ?> ===DONE=== --EXPECTF-- Inserted 1 document(s) Modified 1 document(s) object(Book)#%d (%d) { ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%s" } ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(4) "Book" ["type"]=> int(%d) } ["title"]=> string(10) "Unnameable" ["pages"]=> array(2) { [0]=> object(Page)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(4) "Page" ["type"]=> int(%d) } ["content"]=> string(11) "Lorem ipsum" } [1]=> object(Page)#%d (%d) { ["__pclass"]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(4) "Page" ["type"]=> int(%d) } ["content"]=> string(14) "Dolor sit amet" } } ["description"]=> string(23) "An interesting document" } ===DONE=== mongodb-1.21.0/tests/standalone/bug0655.phpt0000644000175100001660000000211214760300421015416 0ustar --TEST-- PHPC-655: Use case insensitive parsing for Manager connectTimeoutMS array option --FILE-- 1]); // Invalid host cannot be resolved $manager = create_test_manager('mongodb://example.invalid:27017', ['connectTimeoutMS' => 1]); echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; // Valid host refuses connection $manager = create_test_manager('mongodb://localhost:54321', ['CONNECTTIMEOUTMS' => 1]); echo throws(function() use ($manager, $command) { $manager->executeCommand(DATABASE_NAME, $command); }, 'MongoDB\Driver\Exception\ConnectionTimeoutException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException No suitable servers found (`serverSelectionTryOnce` set): %s ===DONE=== mongodb-1.21.0/tests/standalone/command-aggregate-001.phpt0000644000175100001660000000170014760300421020163 0ustar --TEST-- DRIVERS-289: Test iteration on live command cursor with empty first batch --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $manager->executeBulkWrite(NS, $bulk); $command = new MongoDB\Driver\Command([ 'aggregate' => COLLECTION_NAME, 'pipeline' => [ [ '$match' => [ '_id' => [ '$gt' => 1 ]]], ], 'cursor' => ['batchSize' => 0], ]); $cursor = $manager->executeCommand(DATABASE_NAME, $command); var_dump($cursor->toArray()); ?> ===DONE=== --EXPECTF-- array(2) { [0]=> object(stdClass)#%d (%d) { ["_id"]=> int(2) } [1]=> object(stdClass)#%d (%d) { ["_id"]=> int(3) } } ===DONE=== mongodb-1.21.0/tests/standalone/connectiontimeoutexception-001.phpt0000644000175100001660000000177314760300421022320 0ustar --TEST-- ConnectionTimeoutException: exceeding sockettimeoutms --SKIPIF-- --FILE-- 1, 'secs' => 1, 'w' => false, ]); echo throws(function() use ($manager, $command) { $manager->executeCommand('admin', $command); }, 'MongoDB\Driver\Exception\\ConnectionTimeoutException'), "\n"; ?> ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\ConnectionTimeoutException Failed to send "sleep" command with database "admin": %Ssocket error or timeout ===DONE=== mongodb-1.21.0/tests/standalone/executiontimeoutexception-001.phpt0000644000175100001660000000173214760300421022157 0ustar --TEST-- ExecutionTimeoutException: exceeding $maxTimeMS (queries) --SKIPIF-- --FILE-- selectServer(new \MongoDB\Driver\ReadPreference('primary')); $query = new MongoDB\Driver\Query(array("company" => "Smith, Carter and Buckridge"), array( 'projection' => array('_id' => 0, 'username' => 1), 'sort' => array('phoneNumber' => 1), 'maxTimeMS' => 1, )); failMaxTimeMS($server); throws(function() use ($server, $query) { $result = $server->executeQuery(NS, $query); }, "MongoDB\Driver\Exception\ExecutionTimeoutException"); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\ExecutionTimeoutException ===DONE=== mongodb-1.21.0/tests/standalone/executiontimeoutexception-002.phpt0000644000175100001660000000170414760300421022157 0ustar --TEST-- ExecutionTimeoutException: exceeding maxTimeMS (commands) --SKIPIF-- --FILE-- selectServer(new \MongoDB\Driver\ReadPreference('primary')); $cmd = array( "count" => "collection", "query" => array("a" => 1), "maxTimeMS" => 100, ); $command = new MongoDB\Driver\Command($cmd); failMaxTimeMS($server); throws(function() use ($server, $command) { $result = $server->executeCommand(DATABASE_NAME, $command); }, "MongoDB\Driver\Exception\ExecutionTimeoutException"); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\ExecutionTimeoutException ===DONE=== mongodb-1.21.0/tests/standalone/manager-as-singleton.phpt0000644000175100001660000000272414760300421020345 0ustar --TEST-- PHPC-431: Segfault when using Manager through singleton class --SKIPIF-- --FILE-- Database = $Manager; } public static function getInstance() { if (static::$Instance == null) { static::$Instance = new Database(); } return static::$Instance; } public function query($scheme, $query) { return $this->Database->executeQuery($scheme, $query, ['readPreference' => new ReadPreference(ReadPreference::PRIMARY)]); } } class App { public function run() { $db = Database::getInstance(); $query = new Query(array()); $cursor = $db->query(DATABASE_NAME . ".scheme_info", $query); foreach ($cursor as $document) { echo $document->value; } $query = new Query(array()); $cursor = $db->query(DATABASE_NAME . ".domain", $query); foreach ($cursor as $document) { echo $document->hostname; } } } $App = new App(); $App->run(); echo "All done\n"; ?> ===DONE=== --EXPECT-- All done ===DONE=== mongodb-1.21.0/tests/standalone/query-errors.phpt0000644000175100001660000000233514760300421017007 0ustar --TEST-- MongoDB\Driver\Query: Invalid types --FILE-- "Smith, Carter and Buckridge"), array( "projection" => array("_id" => 0, "username" => 1), "sort" => array("phoneNumber" => 1), "modifiers" => "string", )); }, "MongoDB\Driver\Exception\InvalidArgumentException"); throws(function() { $query = new MongoDB\Driver\Query(array("company" => "Smith, Carter and Buckridge"), array( "projection" => array("_id" => 0, "username" => 1), "sort" => array("phoneNumber" => 1), "projection" => "string", )); }, "MongoDB\Driver\Exception\InvalidArgumentException"); throws(function() { $query = new MongoDB\Driver\Query(array("company" => "Smith, Carter and Buckridge"), array( "projection" => array("_id" => 0, "username" => 1), "sort" => "string" )); }, "MongoDB\Driver\Exception\InvalidArgumentException"); ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException OK: Got MongoDB\Driver\Exception\InvalidArgumentException OK: Got MongoDB\Driver\Exception\InvalidArgumentException ===DONE=== mongodb-1.21.0/tests/standalone/update-multi-001.phpt0000644000175100001660000001163714760300421017245 0ustar --TEST-- PHPC-243: Manager::executeUpdate() & Bulk->update() w/o multi --SKIPIF-- --FILE-- insert(array('_id' => 1, 'x' => 1)); $bulk->insert(array('_id' => 2, 'x' => 2)); $bulk->insert(array('_id' => 3, 'x' => 2)); $bulk->insert(array('_id' => 4, 'x' => 2)); $bulk->insert(array('_id' => 5, 'x' => 1)); $bulk->insert(array('_id' => 6, 'x' => 1)); $manager->executeBulkWrite(NS, $bulk); $bulk = new \MongoDB\Driver\BulkWrite; $bulk->update( array('x' => 1), array('$set' => array('x' => 3)), array('multi' => false, 'upsert' => false) ); $result = $manager->executeBulkWrite(NS, $bulk); printf("Changed %d out of expected 1 (_id=1)\n", $result->getModifiedCount()); $bulk = new \MongoDB\Driver\BulkWrite; $bulk->update( array('x' => 1), array('$set' => array('x' => 2)), array('multi' => true, 'upsert' => false) ); $result = $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); printf("Changed %d out of expected 2, (_id=5, _id=6)\n", $result->getModifiedCount()); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update( array('x' => 2), array('$set' => array('x' => 4)), array('multi' => false, 'upsert' => false) ); $result = $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); printf("Changed %d out of expected 1, (_id=2)\n", $result->getModifiedCount()); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update( array('x' => 2), array('$set' => array('x' => 41)), array('multi' => false, 'upsert' => false) ); $result = $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); printf("Changed %d out of expected 1 (id_=3)\n", $result->getModifiedCount()); $bulk = new MongoDB\Driver\BulkWrite; $bulk->update( array('x' => 2), array('$set' => array('x' => 42)), array('multi' => true, 'upsert' => false) ); $result = $manager->executeBulkWrite(NS, $bulk); $cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); var_dump(iterator_to_array($cursor)); printf("Changed %d out of expected 3 (_id=4, _id=5, _id=6)\n", $result->getModifiedCount()); ?> ===DONE=== --EXPECTF-- Changed 1 out of expected 1 (_id=1) array(6) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(3) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(2) } [2]=> object(stdClass)#%d (2) { ["_id"]=> int(3) ["x"]=> int(2) } [3]=> object(stdClass)#%d (2) { ["_id"]=> int(4) ["x"]=> int(2) } [4]=> object(stdClass)#%d (2) { ["_id"]=> int(5) ["x"]=> int(2) } [5]=> object(stdClass)#%d (2) { ["_id"]=> int(6) ["x"]=> int(2) } } Changed 2 out of expected 2, (_id=5, _id=6) array(6) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(3) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(4) } [2]=> object(stdClass)#%d (2) { ["_id"]=> int(3) ["x"]=> int(2) } [3]=> object(stdClass)#%d (2) { ["_id"]=> int(4) ["x"]=> int(2) } [4]=> object(stdClass)#%d (2) { ["_id"]=> int(5) ["x"]=> int(2) } [5]=> object(stdClass)#%d (2) { ["_id"]=> int(6) ["x"]=> int(2) } } Changed 1 out of expected 1, (_id=2) array(6) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(3) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(4) } [2]=> object(stdClass)#%d (2) { ["_id"]=> int(3) ["x"]=> int(41) } [3]=> object(stdClass)#%d (2) { ["_id"]=> int(4) ["x"]=> int(2) } [4]=> object(stdClass)#%d (2) { ["_id"]=> int(5) ["x"]=> int(2) } [5]=> object(stdClass)#%d (2) { ["_id"]=> int(6) ["x"]=> int(2) } } Changed 1 out of expected 1 (id_=3) array(6) { [0]=> object(stdClass)#%d (2) { ["_id"]=> int(1) ["x"]=> int(3) } [1]=> object(stdClass)#%d (2) { ["_id"]=> int(2) ["x"]=> int(4) } [2]=> object(stdClass)#%d (2) { ["_id"]=> int(3) ["x"]=> int(41) } [3]=> object(stdClass)#%d (2) { ["_id"]=> int(4) ["x"]=> int(42) } [4]=> object(stdClass)#%d (2) { ["_id"]=> int(5) ["x"]=> int(42) } [5]=> object(stdClass)#%d (2) { ["_id"]=> int(6) ["x"]=> int(42) } } Changed 3 out of expected 3 (_id=4, _id=5, _id=6) ===DONE=== mongodb-1.21.0/tests/standalone/write-error-001.phpt0000644000175100001660000000165214760300421017110 0ustar --TEST-- MongoDB\Driver\Manager::executeInsert() --SKIPIF-- --FILE-- "Hannes", "country" => "USA", "gender" => "male"); $bulk = new \MongoDB\Driver\BulkWrite(['ordered' => true]); $hannes_id = $bulk->insert($hannes); $w = 2; $wtimeout = 1000; $writeConcern = new \MongoDB\Driver\WriteConcern($w, $wtimeout); echo throws(function() use($bulk, $writeConcern, $manager) { $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $writeConcern]); }, "MongoDB\Driver\Exception\BulkWriteException"), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\BulkWriteException cannot use 'w' > 1 when a host is not replicated ===DONE=== mongodb-1.21.0/tests/standalone/writeresult-isacknowledged-001.phpt0000644000175100001660000000200314760300421022170 0ustar --TEST-- MongoDB\Driver\WriteResult::isAcknowledged() with default WriteConcern --SKIPIF-- --FILE-- insert(array('x' => 1)); $result = $manager->executeBulkWrite(NS, $bulk); printf("WriteResult::isAcknowledged(): %s\n", $result->isAcknowledged() ? 'true' : 'false'); var_dump($result); ?> ===DONE=== --EXPECTF-- WriteResult::isAcknowledged(): true object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> int(1) ["nMatched"]=> int(0) ["nModified"]=> int(0) ["nRemoved"]=> int(0) ["nUpserted"]=> int(0) ["upsertedIds"]=> array(0) { } ["writeErrors"]=> array(0) { } ["writeConcernError"]=> NULL ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { } ["errorReplies"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/standalone/writeresult-isacknowledged-002.phpt0000644000175100001660000000224414760300421022200 0ustar --TEST-- MongoDB\Driver\WriteResult::isAcknowledged() with inherited WriteConcern --SKIPIF-- --FILE-- insert(array('x' => 1)); $result = $manager->executeBulkWrite(NS, $bulk); printf("WriteResult::isAcknowledged(): %s\n", $result->isAcknowledged() ? 'true' : 'false'); var_dump($result); ?> ===DONE=== --EXPECTF-- WriteResult::isAcknowledged(): false object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> int(0) ["nMatched"]=> int(0) ["nModified"]=> int(0) ["nRemoved"]=> int(0) ["nUpserted"]=> int(0) ["upsertedIds"]=> array(0) { } ["writeErrors"]=> array(0) { } ["writeConcernError"]=> NULL ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } ["errorReplies"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/standalone/writeresult-isacknowledged-003.phpt0000644000175100001660000000211014760300421022171 0ustar --TEST-- MongoDB\Driver\WriteResult::isAcknowledged() with custom WriteConcern --SKIPIF-- --FILE-- insert(array('x' => 2)); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(0)]); printf("WriteResult::isAcknowledged(): %s\n", $result->isAcknowledged() ? 'true' : 'false'); var_dump($result); ?> ===DONE=== --EXPECTF-- WriteResult::isAcknowledged(): false object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> NULL ["nMatched"]=> NULL ["nModified"]=> NULL ["nRemoved"]=> NULL ["nUpserted"]=> NULL ["upsertedIds"]=> array(0) { } ["writeErrors"]=> array(0) { } ["writeConcernError"]=> NULL ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } ["errorReplies"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/topologyDescription/topologyDescription-constants.phpt0000644000175100001660000000124314760300421024347 0ustar --TEST-- MongoDB\Driver\TopologyDescription constants --FILE-- ===DONE=== --EXPECT-- string(7) "Unknown" string(6) "Single" string(7) "Sharded" string(19) "ReplicaSetNoPrimary" string(21) "ReplicaSetWithPrimary" string(12) "LoadBalanced" ===DONE=== mongodb-1.21.0/tests/topologyDescription/topologyDescription-debug-001.phpt0000644000175100001660000000410514760300421023717 0ustar --TEST-- MongoDB\Driver\TopologyDescription debug output --SKIPIF-- --FILE-- topologyDescription = $event->getNewDescription(); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} public function getTopologyDescription() { $manager = create_test_manager(); $manager->addSubscriber($this); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager->removeSubscriber($this); return $this->topologyDescription; } } $subscriber = new TopologyDescriptionProvider; $topologyDescription = $subscriber->getTopologyDescription(); var_dump($topologyDescription); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\TopologyDescription)#%d (%d) { ["servers"]=> array(%d) { [0]=> object(MongoDB\Driver\ServerDescription)#%d (%d) {%A }%A } ["type"]=> string(%d) "%r(Single|Sharded|ReplicaSetWithPrimary|LoadBalanced)%r" } ===DONE=== mongodb-1.21.0/tests/topologyDescription/topologyDescription-getServers-001.phpt0000644000175100001660000000427214760300421024767 0ustar --TEST-- MongoDB\Driver\TopologyDescription::getServers() --SKIPIF-- --FILE-- topologyDescription = $event->getNewDescription(); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} public function getTopologyDescription() { $manager = create_test_manager(); $manager->addSubscriber($this); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager->removeSubscriber($this); return $this->topologyDescription; } } function isArrayOfServerDescriptions(array $sds) { if (count($sds) < 1) { return false; } foreach ($sds as $sd) { if (! $sd instanceof MongoDB\Driver\ServerDescription) { return false; } } return true; } $subscriber = new TopologyDescriptionProvider; $topologyDescription = $subscriber->getTopologyDescription(); $serverDescriptions = $topologyDescription->getServers(); var_dump(isArrayOfServerDescriptions($serverDescriptions)); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/topologyDescription/topologyDescription-getType-001.phpt0000644000175100001660000000363314760300421024257 0ustar --TEST-- MongoDB\Driver\TopologyDescription::getType() --SKIPIF-- --FILE-- topologyDescription = $event->getNewDescription(); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} public function getTopologyDescription() { $manager = create_test_manager(); $manager->addSubscriber($this); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager->removeSubscriber($this); return $this->topologyDescription; } } $subscriber = new TopologyDescriptionProvider; $topologyDescription = $subscriber->getTopologyDescription(); var_dump($topologyDescription->getType()); ?> ===DONE=== --EXPECTF-- string(%d) "%r(Single|Sharded|ReplicaSetWithPrimary|LoadBalanced)%r" ===DONE=== mongodb-1.21.0/tests/topologyDescription/topologyDescription-hasReadableServer-001.phpt0000644000175100001660000000356414760300421026223 0ustar --TEST-- MongoDB\Driver\TopologyDescription::hasReadableServer() --SKIPIF-- --FILE-- topologyDescription = $event->getNewDescription(); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} public function getTopologyDescription() { $manager = create_test_manager(); $manager->addSubscriber($this); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager->removeSubscriber($this); return $this->topologyDescription; } } $subscriber = new TopologyDescriptionProvider; $topologyDescription = $subscriber->getTopologyDescription(); var_dump($topologyDescription->hasReadableServer()); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/topologyDescription/topologyDescription-hasReadableServer-002.phpt0000644000175100001660000000371014760300421026215 0ustar --TEST-- MongoDB\Driver\TopologyDescription::hasReadableServer() with ReadPreference argument --SKIPIF-- --FILE-- topologyDescription = $event->getNewDescription(); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} public function getTopologyDescription() { $manager = create_test_manager(); $manager->addSubscriber($this); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager->removeSubscriber($this); return $this->topologyDescription; } } $subscriber = new TopologyDescriptionProvider; $topologyDescription = $subscriber->getTopologyDescription(); $rp = new MongoDB\Driver\ReadPreference('primary'); var_dump($topologyDescription->hasReadableServer($rp)); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/topologyDescription/topologyDescription-hasReadableServer_error-001.phpt0000644000175100001660000000407214760300421027427 0ustar --TEST-- MongoDB\Driver\TopologyDescription::hasReadableServer() (argument with bad type) --SKIPIF-- --FILE-- topologyDescription = $event->getNewDescription(); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} public function getTopologyDescription() { $manager = create_test_manager(); $manager->addSubscriber($this); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager->removeSubscriber($this); return $this->topologyDescription; } } $tests = [ 1, [], ]; $subscriber = new TopologyDescriptionProvider; $topologyDescription = $subscriber->getTopologyDescription(); foreach ($tests as $test) { throws(function() use ($topologyDescription, $test) { $topologyDescription->hasReadableServer($test); }, TypeError::class); } ?> ===DONE=== --EXPECT-- OK: Got TypeError OK: Got TypeError ===DONE=== mongodb-1.21.0/tests/topologyDescription/topologyDescription-hasWritableServer-001.phpt0000644000175100001660000000356414760300421026275 0ustar --TEST-- MongoDB\Driver\TopologyDescription::hasWritableServer() --SKIPIF-- --FILE-- topologyDescription = $event->getNewDescription(); } public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} public function getTopologyDescription() { $manager = create_test_manager(); $manager->addSubscriber($this); $manager->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); $manager->removeSubscriber($this); return $this->topologyDescription; } } $subscriber = new TopologyDescriptionProvider; $topologyDescription = $subscriber->getTopologyDescription(); var_dump($topologyDescription->hasWritableServer()); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/utils/PHONGO-FIXTURES.json.gz0000644000175100001660000022370114760300421016220 0ustar ‹ch9UFIXTURES.jsonÄœ[oÛH²Çß÷S4‚Î ñôý²OãØÉ$;ã3Î$Ø]œ‡&Ù”z̋‹my±ßýTS²,y(Z1|ä ° ±%R¬îúÕ¿ªšÿú‚ÿºÆÕ¥-Ü«¿£WñŸUí_½¾?8·Ms]Õi8ø]ü@ðÿ8úõê<úïtʯnõQüAŠöÃ…ûçŸf¶xáó_N¾YU¾éêsýù´œ~yëÞ¤—ÑægºÂú|}¶Ÿç³yTºvsDæë¦ý´º¦÷¶,]³y8·÷GÏì´ìš¦*7$U1·å¢?^•ÓêäÍæÑØWáÈE•µ×¶vèm9õ¥s5ú ŒNjg[—µð©ÑT0%7Ø4­]ÓÀ%þýkýòöM^nÚÚ¹öhù–åõ—6®m×"¾qÖû³û¶ÿ«¹½ª¦]=4¨iá 5¯`\~\¥ýPŠñР¼Jàè_/¼?Ø.æý{Ï+_¶ï^^qÓÅ—pE½![%VÚ ]ÇzЄ’ÈCˆy58èÿòê¶^ùÏëï¶ÈÉ¢t—>ŸÚÖ""ÆŒò[“W£öØ5`ÛXHó¶&2 ÁÆlAp¤”4JÌÇ3[ç®A> ó|̧U™n¹€Ï\Ùb÷mk\|eˆúå¥ B"®5¡rtqàˆH.ÁjO3Èß¶G® ´ ß.»òÖíbC ìç’j§™L)§2¶2!Úrn†?cxQJ chÌœ&$Ét–1ø?ȇ$·¾vJýìnl1ÏÝ(&>Ù:ñMµ‹ÇU}í· 1ŸU¥ûÔ±«Ã€•Q?f&FPzƒ)ßôK¯lÞžo/»<&ÎEáÛÙktlë˜b˽é’ËÚ§S7@¡“*¯`º£¢‚‰ÞzÛ ?olßFèÂ¥(ë¦Ùf,Ñv5 ?älÝ:ñÓÒ7/ªÁˆÌÕ®L}ƒ®ª¼›ÃÌ÷1ŒõeâÓ®lQ Þ†¾uÞ"˜õ𾮉Ї98èXuþîMp7g¾uI[¡§¤*÷­ë¯ u±o}í¤$%T` ^ûÙ(ÉUèc5ËáŽ^ÀeµæpƒZ k·ðÞç¹­Ó™½rãÎáÌ÷Ú=ܦ’Ò‰ j ôkpÇŒŒûlM#Ê4•ü`>[aNÑ»ÚùÔ¢‹yíËi3f¢óºK]™¸¢êÚÙ#¼ó‡péq#®ñKÛgB„ޏÔRÓQ™ÊäS}ø÷s…ÞÛ¢§sœwñr!™áù|g¥/>qeëÀõMŸi1j¤œh·¦ïAídXd„ÂjtMHDaBµ­;³QQÍê]Àe'N`šRJãYbcGŽ5àWeƆcÀo[• Ç´¢)æÎXf³AàÚÔF@Évæ<\λՖշ±{â¬mí.잺Yéêìb©'Xó‰"æ©Àý<ó..`êåù ¹ŸkWĹ] ÷‹ËÒ\ Ë] (C8`"`/µÕ·€ÈÚÍ|X™~æy…ÒÀi8PÜ­Ã[¬-=\D„>§BU–ùÄ÷£Ã;}Šà¤s ýú-.`#,唂'ÁêÙXª¤ÁÚ@ç0¡ÆUgYÁm.aYCtâÆÕçQnc[ìឥ‘ÊLWä¥%¨Ž8_1äûÖƒ…¥ƒôÁ<´ÐLB´ãò¹/AøØ[»tÒjjwÖz ëØ:^Ä]=‡é‰‡³ú¤…IŠŽa6±ßÇpŒ)~”|y¸2)Ž RÎëa X©!pÍ3f ]\ÛÒÛkX5謂¸Û‚{ûa1˜s¹³ßEЯ. aüâQÖ~rqm›Ë=ÌF4¼O‡µ¦Q†È8gØ”ƒ>hg Ñ [–QêRX —»`ëI4qL:—IÉS“1Là»hÊS–b™XÎpª*“D%,±ÊÅ2QÌ)NIâAØÂ @Éäν@û¦ÑNuûÆCVIPJDP1ÎØWd¢¸žpM'FIrC¶Eðs¿za^ 2·OÒ#÷ÜÖ}|>€Ü·¹ŸaŠÉð« PÜT”W ;]¡+i‰|”,ì/\„þtaXù­«»™ç‚ø«ùºTÐ@…Ãé¦X†?š9@؆íŸR†ëõ…ß ]Æ`©j.ž/ÍKA'.‡ÛÜ¢ JtѼF@ŸÑ¼– Éשׂ‡à“¤¥˜ jæƒújÀ1SmÔc¹_Ƙ8`‘(†‡µ+:‚o±tÜšŽ‚÷½Í¯ªº©ÊçL4­±~iCQ1Ã4¥ìD±ˆ`¡øáì$¤ÐÙú²A_lo¨åz’j±}ˆtlð+ã±ì’ÅǶ®r¿Ï²ÒÜ6Á˜ ‰ýCšL3i™¬(¬M4‰ SBCP¶¨ímTØ:qîåc1V:Ö²—; V¹Ž³8f4á6N˜5œÄ$îb@¬Î9ìlšIB“8sd±®´QcË Î±Wù]íÓZö÷Î%—ãœÕV˜âì†Aä)Fq»[Ò~tÌÐÉ©k’ÙO›·¾Ú"h k™›]IÚ‡éÜ!uÓå°b NW|ëÆ',Û'“ƒÒ ²9öÂ¥ð½Ï,_$]c 8sÿ Ká®d7tÁ´\ Êù³A—I!!ž.=Ôèwy:æ>¹kt a{UÂ¥ŽóöÌ7MÕmUÊï§Ävè-Ù‹Z'ŒE˜aömYÈ'cAäá2‘Š`tZ];ÔÑ•Èe{ˆ¤w¾çìï30úЄ ¾k1×ú²áSV×òHH‰õhJBD„KI‡Kê3….Úº±„Îýåªú"Ë“÷©}XFwËïYak¸b¶Kt뱇¬Á(jÖÌPïÆzÔD«sL4>mд׵ŸÎÚhjëó‹¸2V a¥…É@¸ó §Vð \EÌR«yÌ…K“Ðõ"g€Y»ÌR•ªØ îþ%Ì’¨Ê§v/ä–s»»,¢ŽUm%“?a%& Ðq£éSsÈ'ÿuTã^£7•›Ë2È´bPΞ­kµKQ Ø—I ²»IÜ0ìN…KI›»¤íë¬ó¦ 2µqKt'í6²Cu+™œú¤µúŸ@ÐÍêî†nAÏ>÷Àæu¾yD×jÃ5£úù’Éé†>‚ñCó®Í'÷á÷{W¾N7®]­L`>³Aí îaŠåh§°UjÃÈᑆÁ½Aï}ÝÎúÜÕåÜö˜m¾†üÉiÈá4ã¦ùìB?^ã?í!WÉ`ºï >ZªÐg¦ä¸&#iÁÈTΰ4èÂvœ~vum·±Â ÿu  \¡3w9óÍÌ׃v¸/ÊÔþ¶ÚªLÊ&j¸ì ã:"ÕGÂU-"CÔÓÃÕï‚jÓ´®‹ÝÎjl’­b`#Él,w[GƆ&*‘©Lã„i–§Df 'ÖÊ” @é®ñ­Kf°íLȽ2ÄǶÐ],=³åXÿcî)›P%åÊÈ'¢ô"™€´XÚëå¦ï« ·a¿ëÙéBtÞ¥ÆÚú(àòÆÕI/cáìÊzµCÎöbô¼®®@‚t¨—t›PÎ%ë#tÔWWúµY`;TÞ5YýÊ7I¬KlÍU ®Ð—WðÁádËóÚ‚ð-[º®Þ4¶@^ŸTu  øŽÃßAæ6«Ã#,6”(*˜~¾Â®&ýîèx“ÅÚ—Œ&˜ûýnÐ|Ö5êÞ½+¼\óÒ5Be"úÐÉ„©ˆk.Øár—Šr…~± ˜“):ñaYèMnoÝã‰å¯‹ ¢ªÁŠáƒ.Çæ¥ëî PDtÔ4 GDƒŸ<\>BsÃÀ2½hBaeŒ³ÇU Þm±OgÄ÷ \&è ýi#J#)‰\ÆëAa" -;H¹öO{[,J'Ù. ™& ¥ˆ5Ë ‹1¥”¥)7*8]"2ëb nš ngðZ¢´Œ‰²bß»&úÓ.ÒªÜKÑþn˦*vbØ·0eò|Åd¢Ÿ`0–ŒÞPEõYüÛeWº+;ùØÍѲ®Ï!Çî{ƒÃö¿Ùœœ®RÉ=S#ôÅÕj¬›o@» uYÔtMâçÀv †’k<ÒäD9L4¦Ÿ…\tºLE ãÜgÙ ‡z0±¶^Óg]=Ÿ-®„Q§Y-èã 4Hþ¤æÃÕ d~é hH´4ƒZÖ£ 5¿|¸nTcŒÙy ¾~•ðe¦w‘迾ݴ ›Ãl³¡÷û¢`EÚAg¾m)e¸bɆc¦ƒæ¥ˆ°‰8Ú< Ázd#¬c ˆ¬í ¢çG+*Gå´k_Lg>$ªv/02I'œÊ—Îüö9]ÊùàL¹Å¡šÓ§šç»è‡\ižGàxýÎ}:VR¡@šZ«0UVK,•Ñ [±J51’ —š”d2ÓI–’H‹3ǸÒ*M i»¸v‹¨If¾é·$Ý¢èÊtgGSȈ,Fù£4æ',ð.Œ"Õ¸\¦JÉ'‚ò‰ÑÌÜÀ²«·étªκu7ñQ M·Ãëµ|íU`ŸªÝn dt6BÊ>ìËU¼¶[2Ðk˜™ç!|OtÔÌÚªDg>ÝD÷{ZüÿŸZG&/¾Ë‘€¤0’Ðñ-3"â/';B›>úèê¼»tè‹·+*>xöx§à†³Ç”{(nÿêêÆ-7hw<¸ù¦",¢ÔÀ÷¯$¢¡¤q8cQ¦újóØú½²éÊVŒ–BûÂÇ?}k5Ô8k›ÌÀ±·ÃòóÁ²¢éN$Ö/ DÂtDWãš~"D$`^ãƒÑ‘ºù|' •‹Á€@™gv,qBZ ƒƒ0GÉ4s w6U‚†^)IiŒc@lÊÓ4¡ÃYÛËEîÁ{AÞ­¹EÀ·¡¼½a —<‚(9â’ªQú4uó™Í_ÃÜt¡º§ÝjçÁëŽRPt ëúäi_®tyÈÞnçh‹ C—¨¾%òîj ¨J}…àbàíËž_P–ð àò\H¹Ú¨:}‹µ0ÝÈ']èBBðÖðkæ“MÉ EIŸ¯H”BDÛÊßÙû^1Xû{à§ ñLûÈõ¾÷Å×Ó]õÑ©

xøC¼1ÚØ¹›¶ƒò •HtŸê]Sׯë-7½À¡«Én·"}ëªÕJ8fTül¨¥‹uþö󬮺éìÚj—rLá]ýxº)H¡Tõåã>!´¨ —Ã|?hp-##Œo‰¾jiŒ>\òVºµ\ØæÛ›nxÃâ}ƒQØ ¾O¹ì½½¶~æjŒ1}é-2„Ë(<îÄŒêÞ‹#rH¼rŒÎ«®ßð%<e:ZdþX%³Ç3?aå¼7¼³ëèA²– *' â_zùL¦eôø>ï‰4‘Q†‹§&¾ ©×} !‚ &Ù…TÆ›HË™“DH‘¦Î¨vFX®…uILyl²„Cì-3l±©L…‰…44£ƒH­sàà^íD_F¶Â¼¯ÒKˆ§}2&O”\ý„1›@0#n¨’[U°ï¡ê/>nªrò±öÍUÿ¥éƳ’nîS¿zÂô®  ,ì!Û“s¾~wiÚ%ýˆÜÇ}æ6 ¸{`R ñÏJÏÞ7û­h{ÙÚC;8×îžçAÉÙ;¹ê¡Ëܰ]b}D¶s0LBö|²UôTxÿ@ž¥H4¾¾X¤ëµÕõ#z¾]U6~Ÿç&Iõò…ŠF‚‘ímYE"ŰP‡Ã(ÕõÉwt {µôÑh¸ýŵïyj’áô¥»N&&bŒP2èM57ôÉ»¿ßBB‰ÿ#îÚšÛ6’î_A}Oq}&jî—GÇvœÄ²“u.[µoÌ@DD^^d)¿~»g^„T*Ò®rÉLI¦OŸîÓ§·%²_ë&¬Ò=‚Ìw<%õhÅ1˜¶>Ò½s7“ ‚èá¯yÎ{ÇH.Ækó轡`Ï•¼? MË(}u‡ãÓ¥ª4Ç_.'$žŸ!]™PÊñŠÀï2POdá ^Ha-ñ•÷Î béÐû!_}Eÿ²å$†ú¾C«ÚC³¤ªZœpK"3-ê‚Ì=äWÏ¥©?”Í.C]Î_gê|m*þ¦ÖÆÊ¾Û!_ÒÓFجD»P@Àz±£Ÿ€(ÐÝÊf÷D¶‘Ó¦iÓØ †‡[äìgIÓ€)×XdaŸLàÜ"yA³@’ý^£¶$û}éÊ›~º\ V‡Ä´W~|~âßòçæúH-ø¥œ›—ôÒ4r¸< MF«R‚ç³þ3úí]µMSœOD•즟¢rÂÅïðÔ ÷D·÷ëϰ¼mßÂDZY‹h 9Ø;ïÍ’h*Håh9^åBP­ž[@|ƽÒ<» !ûy±[ô(Ã×Ý‘B {2ýä–ÓF}•äp“—î™Ì¨b9!F³QlÎsʈ<„èa¾ñ¬ÔäµÂY¯µ×ŽˆPâȨ2Á8%*4uª ®rP•VŠùÊRGU%KˆAÛ*amÖùÍ"ÔÓĵ£ (ËAO¬ï,H̤µòÞZÆù3µ4«×Ù'‡Y;âæ‡¥;x(¦[K&À$žm¶/÷j¶yöeoü‡Wö<Q=”ü&óÂP£>wß8iÒg÷LƒÛk¡Ž0O FZJñr8Ê­b:û!ŒG­`˜Å Ë8@Ñÿ¸fœ×<Ù …;ÍŸ½‡,kܲWD×#z>Ë^8½Æ e&<: à w=¿áfBc©à ÜÞÅ8‚~íòzJC›f/ÝÔÌeŠŒ‹Ä€¡§ÆùÆE5Ùg·ž•‡›ôaïR?ã5Š¡¨g Íìj"¹”—.êZ™Cî`-·É\ Àž…ƒ~ûV/nêf?}A¬*TŘ¢•·¬®öé<&¦k&TÊ Ã¹Sž0õÀIáÀH­ÄÏuçt›ÿ÷8LÑÎtþŒî ,Ǫ»ð³¼Ø §ÏO¹ª 8û°¬oÃPm÷SçF´i|ØÎqöEاÜ@˜zÕ@øe\’ÚnàaGuŠp£.iµ y´*Œ¶IGCïË›tçØð~ç瀮 ½ð2Ä×:œT#¨FAí?õ4‘(·v° zfÏGK¢Ôx£k‹Ô¦Îè”Á1ÙUofˆ2±Ñã„“»á´ïÂS,9¥¼¼êÈÚœ*uHˆþyƒ3Ç ÚÈžPWó×4‡³ò]gJQJ–ÒF ©µ…Õˆ±ÚZo¯XQ*©l! gŠ’{[rCª$ ©hh•œ¶r&…CÑÜr9>çù$úQv”à¹n ]r÷ºÊJN¼þ‘{t§WhŸ°‰Æ¨¥ÝsÚ7ÄÞeW… DòŠî€¾ïybݙ箊þCµO2¥¹K_ )Ù2¸ Šò´úSÒdh‚œ½EÉÓ ¼d;㉜ý¤Ês !Õ¥Û1ÀÞr!äÄ(šV8*hΨ"èö}rÙGmksìn”Rìt÷\ pCg„_Ü…bFðy«é¸£Ÿá¹âDðs’~–½i ÖBÀ ɨ~[’·õë|¾_P| B/^œQ9ƒ(28dz½­Ž*ñÎbœûßU·ÒäY¦´ EFÀµ =3¦òNÊÀeI(nƒ)eE ·>¼.Ë $0ÎÊ"àMl Nã|Žû µ ÒX=–H4»$9“ô¹Ê _Ûo‹™ê må9ýîoÏÈ:ée ±ÛmGËРîÖm5Aˆ@6óìÍmt*Úþ×XÙÝÊ|öH£bYf-×/'–…WTÙUhv…ðñ…N¿µ_çõéi´·ÈxŸ‚„(ïš©amÍYýødn¹'ÖL™ã*K~> ‰6Têävû1<ôŒP ÚÒmo`â×ùi ÉOÞÍ'qwcšï_úáÌÐ j£þö2£sŠæ'g\^Ô2Ü;Jˆ¾I ™ÌÉ:ø›^Å5áXòYýE)c3£†¿þY5?p/$P«q:HÍϤù©Z k”ž|¢´*TeU)”qÜpf=©to«6Z3_ˆRií=ñ¤0Õ€¥´âÜUâ8Þ]cŸo; #f|ïÜÝ¡–õŸöúÃÑ^sˆïÿ¾о’B£î1KƒÎ«jöë²]¹²lPò_8u’v6á¶ù¤Ýgݸeúdgߣe\DšFVRosÝ®]¿&­LŠÓ iÚ+µY¿L´kNb 7¢hüc«ÓŸ7_){1…×’ N|X@Ƶ?‘–Î?ðÕq0Å^äûÍu8ekûÓbQ7m=¡f§ŒÐlÆÕÅ w”™\s&IÁöª'¹¢ÄÈóÕí„b,qþÎ=u”avÈôp–è¥Jw‰÷Œ±‹û%ĺ)Å£b‰%ØsÇ+”Rgï( |»YÞuÎñRŽŠ›ß,õ'’¡YoÊ› –Œs~é[„ {‡¼üÄ`'‡ãfµ= †Þ„P¿Ì— FëcH*K4~/(Î4 Gƒ‘œ•TW–PR8oü\Á²’žÒÝá+ë¤óÙf¶Õ[|«WíÍÃJËC˼GñpÕÑneêo©‘敵r¸¾×êÔ´ÿ'ä;öŠcëÕPýµŠ«ú°¿ù:€¨ïm¢l?É·ËeÛý¹?6’gŸwc'V¸ëä{›ümQÛz4°ýµÍ}\MÖ´»šîn!ËΤ>õÍÎãÅZÆ ©SæåÐVh›Å[ )sÝ Eþº ÃÞ¤û;Z¾´í*Ü…Å8s}žK‘As¨‘ââù6Ž|2ˆÕãZ!ÉÐN圛·µèàÿw{·Çºë^nË娪ë PÔ“å†_CÓ¬wn’ý…0ÆÏ´Õ—Žì¸´’+ÍN¬I“&gJ[uÆ;DR\gçNQ‹_c©7³qÏ’ÿmSº›ÓãE“K¼\+AgDû$õdÑÜH5싽»Ša?Ôˆg·KžÃß¿êæ:/ç&ø,•…!÷*Á*åyYîJSÎ+˜3Œ!~‚ÐÊ #à9ÄóÙ¯]1?vËv±…ã|á÷ UÞ#<Ö:®Ê›18Á÷FXý\÷¢Kç^gWM9ÏO`CK¿¿ìj¶»9”ÔËŒ¦·] x¯¶‹K¼cqÅJô·mª¬wîD¾N$‰ðöµ;?$¤²µïÇGóì Ö“fiÏHþд¡wkH:á}ó…±Z²!ÜZM_š9£Ù;8ÑÙ—z ÊVOR(CxŸäA7Íx EFæâæ9Qµ"”àb¹Å¢=QI~’±1ä/OÌ€ÓÂ9`ƒÒÝUšäè¦k·½ d?»²-êì ·qu’jÍF þðNè­N+ùs´­ƒÇóò%Ià #Ç µÉ•`Ä<÷ = v®câ ?ÁQÀªUUp_XôÇâÀz¥­lUЂê²Ôº \J&dI¬”Pa" ÑžT–ªbÕ êÞ¶sw{¼â“èï'”øü]-&w.ïc XöÊ¢©¼}¶X÷˃kPf„JÝ4ò²hïGEc)Éeª=šÁ‡Q¯»e Û…)·ÇVªE¦¼'×ͳ?·ƒ1è‘Ô[¶q%*Ž“~F@—ö÷Ša$Ê™CvcB]¢¹TT¼œû.IM²7¸âéݲ¾/Q¢æ]øæNŒ¾L§ÀÉØ‹ )EÝ'eã:]A€í uFµ@²´g7ûe‰›–úù$98äº7Õ > ¼Œ¦O&£/îfde®·§¶G SAøù¤dTP–}i‹°H‡±ûM4ßBPY·_ç'îÎt}—fø±8ëYÊ9'dp™Äî"®ràÚJœE£Û\· ßW(Už9W:ã‚)¥«Jb°ÿªœ— €P)¼c>ÖÊ|ëU¼ ð|„Âç_î¦-rªe]Χ¯›ãã.ۿØÕtÝ,Ç ‹´`^NËK¼ZW nzibªZ ÷ÙvÊÞ2üuÓÞÕåiyïÍòç)«Ìc_Z›8áDHùø¬¸´¹—àžä Ü¥eï27>Š<Ù›“™§÷2mÎ ¹’„hî)–saà¯^o‡~¬—ðF¢CFp·c7ècêž\¨óD£jÂÍ pè¬ëuŽóºƒ;÷áÎ3‚à3@ç<ÝÕÈ´¨¦žZ ôÓ.šÂUÌhYHZal!)•÷†±"@¸t^¥«œcŒ–ÀM+6Üu½õ¸Üdf¾]¸ ¼³GYçc7¾.1ãlF Ÿ } }’n*Œ¿ÎNFÚùs;Çaæ!¥ïq“è>neõí×€äiå Ý›Ûì×yöd5./KFq %ÜG»û°\â³Ou³Ye¨!^%ÕSR:ű_Û1Î1›ɬšùbx©‰ÍÞëuöÃÂNZDs´l=áD?™cZª.oHF¥A3:ž –CþÆŸm÷¤Óý­ß†tìxsˉt¥±„éÊ«ŠW¢´¡Þœ—ÆéB‰¢"\«ª°ÀU¬â¡`LzYTÃíœ%R¤¼¾n Ík'¹|þ',Žû©¼Ãjð¡»Ã?*KÖšWðC´q}OÅA3v Aö’Ü+¢É½†¿(ÿ÷Ž~<æmó:û\¯ÿ†73Ù¬|ÜܹŠ èÛ¾””(á>ž{w°Wø¿´Ié—Q$Ëν‚RÒ1ÆâV¯âß<»‚0Ø9¯DGî~b›7ßbPˆÛéïÖÙ½z² Did`×r~$V`Ij_° Å¥êRë¤BOiõ¸! öm~rMµyÑî½’‚\:'°<·ZêA/‹íEØ; ¸«ý,¾À¾}ˆí×GÚáýÈ90K™ ÁŠÙÂÁ9¡¢FeŒ+ œléC{% ü‚¡¬ŠPi?¼¶'~VuÈ—íÜ5“"Ç›ÕѸñ öb¹i¥%}ß׌kî'§bÇw c ·3)©¸§R,>yÔž»ÛÙ÷øfÄŠ7ÛÕÖïßºw~ÀpN¾‡£é’ü*âÿžĦïw›Éßìù5}Ýn)ßÛv{ÌûäÛ]:yÖí“ë&¢÷Óvj ÷­.𻎔¿ªê²[cV_ Nsb•²/çD¡ $oS´3¥ %igY•8Qæ~ÊœD5w7\ºÜ›p¨Dl )X¢3Öž§D÷f"ÿ8Š{ñ$ÈRi á˜8n*´¦E%„ F;ÉKªV ªƒ …)%ÄoKÅt!½§bxu‡Çuäu™/6¡^|Ÿ$-ù NÓÑ…XÿÚÀË´ãoÀ­g˜H÷Ô°Ñ€rœwü†ö~5‹6äý*Ïú?ãùëðûõ.x¤2Û®¤0‰hòìõ~¬Ivp{{=04¡„3V÷ì힘3ò¼(‘\-k’ÎîyOŸzt¾9c 00ÑõÅâƒPŠóì}³¬Ë6éÌxq2Å™¥x³÷–°ƒšú~TøÞÍ—uÑçuvU¯×‹ÔØøwœ†ªUFW…G+¶±G™¢FùT"ø²çK»5¾Ý*d·EƒŽŒt=ÎTFDû†T… ƒWwHð/ðÒ>m+…ìí v£¤±¸Ívñb€ú|PµØ½Šë¥cáÄ&_²ö@¥È>A`ƒ7y‚- v9ޅؼ==ööÉÕÃÕËÇö-Ú˜™ÔæâA¨â¹VÆ£þ-\äĪç[Ï?)‚t…ò&ÿæ–þX1Ìù *YVG0^åy(ÕèëR \¨JÆ*VhÁte}¸ Š^ "Ýp"ኢ]¯ó"¸Í4â€yÇ‚Èõj>žG(Á^Qò?â®®¹m#ÙþÖ}Y»®‰šïGÄ«TìÄk;›ª} "ŠðB¤lù×ßîe¤U¼ÔCÉ‚ŠD÷œî>}ŽŠVàßМu~İè9Ë•˜Ü;ÞË7õö^ÉHƸp7È|†lÑ&”;@õCÔS…„ÚC,bäÏú F Ý#µA2ìQèÏJu W†BØúëúë¹ ³Ó‡‹¶ƒêÊ?çȦ…±r)Ù¸¢ÅyWÆi¦™çü÷—A"€:A?Z`ù§b¼qÛ,@9)-A9ÀÇÑw„ ó¬š@%೚åŠR¸ÆÐÂSçµ$Ü]*RŒ¯×|q÷›zÍÌQáM¨áh˜ì ¤AÀ\€ž3%–B€3{¬q“fÂ4}­ÊMš;By;ÊQx¹Ý³+ïëüvégg~ŽÓ¤uG‰m­ÛŒ B`lÙ ßlûñäûžÓ€ÊD?›Ýœ2’';pðkì@&‰ˆøß6s$†d箞@H‡3özœs [Í4=aRHpqUe׆ŒLI2/O•ØÕðX4èÕ?ã‚^d¨"ÿÔ8`X†œžO%2³V}žTRc?0JYO%ÎJa¥/œ <m fdá­—F S^„Aùá·”. @\;'¹!Âz1šD¢l¶ªÖÅQ“ˆ7«=-Ã}Ûg×Ì'gL¨ç\ë%Õ‚“TÑÇòš^mýuƒÂ.ËwHÀ…ï£`k[bİ•w}Å›½’J¶ø%uR:HN °Ml0|›3áÆIN'Œn©¤í¬.þ¸ë=gõü 1ÕÿïªÕYâñò“ØõxòQ¢ð%|ü…ì®:„1%Ï hnàC«×—ÙåÆè{}@O!f©†Ê_»€|E¥YÉ‚aªpšÒZ0¥¥ÌKj%ã¥Ì­%¬,òÒÊ=šù.ˆ×í^Aæð„< |ÜÂã¸ï곯ë¼~À|ËVñ%¥ri§ßûÛdžò›í«-ë/­ÏPë: é_oá©ï\ó†=ƒ~pè·«/®ó¨í6þ½sÏ[¡4GUìÔ°béåsKdÊ´{Pä9ݰ JI‡ã(E‚‰Úº§;Ó%å@Æ4Í„ÜXTM-À´þrpñá%<×Ç´ ‰ O­hA”iÀÔ£RýUK¡2 §Î£W‰* \¹U¸Ï®›ûÛÍô¾”£b!°U¤Ìs͵÷¹bPfñ „D…Zçï'z)´kÝâ1.¸dÛ_º¦_{®¿Ž‡}"ùn7 f” A†õ&Í 6;a¬Òqx8 Þ¡:”‚žL¨eŠéM”ˆ>,]ZôŸ¯Ü€Ç!ƒcÏl ¥ìSŸÙ(郔u6¿§hHF …Zã,Â?_¶M1Iù ·v²Ì™ eO7𳄰Å;lÏB3.ß³ë¯Â]hV÷‡}íëõæ8jø…ä’YõÔ]{i3‰l¸Ùxˆ.ˆ´ç‘3¸‡7*ƒ3e*à |öÎIi(‡Yf gÂ*¨¾EArŒæ :ü‹?ø. # Ÿ»ñ#½þ€W—Ýá¡tœPf-LÅý…»šu#ÆRT18ÀÑ™ú·»©^¤Ù[Œ÷—«MX Íž–kò­ìH\ ì´ÖçöÏÝNr¤ïßïúæ‡Ç=T7‰ `s ;Ȳ–ô„„L,vê[Ië²ÕWÙIvm›Ê‡clypHwÏÀ¤÷öC%%Ñ@iôÐÕ×ê#†Y¾Œùä1¯3Tþ³b× "âI¥ G="Ê¥Nf7Ô9SòœqVÂË7ZF·”*§cÁ´¦67%ÖEŽh+”ïL¼ÛíwÔyPú¨Þú_ðrÃ$Õö·úê¡òƒ¢œ“gæ9*<)Àpü±d¼÷®Áq±YöLý‘Ç*;6űÀÆã7rá±Ï^­Vý¼¸€Ó°Z4ƒR;nøÞ×Ý·É‘…õDR~ åCõ¥ÚôÛ|}˾é&¯«Û¶þEÄWÄ:å¾?E^Ý üÎé¸o¡F_³±ó8/'8qG·eϺ¸£2Mä< l¦àz´œòOåÐ ùÆ»æáªëpa×F×§¤`%sܪÂ)ŠÒ›œÚ—P«È…)sK…ÅI/h@¦®—&»qͽ»Éò:\Ýœ€˜û2ˆD¡…OFÄ£·u?U75Ò/ÿ©BŽêÿ³]¹m9’Þôš=n 0ø e×MáZ¢n¤½ÄÍœí&ÏÖõº+ß㟴Ú>í"KíºNÖ>ö:1£/­óî\å"¯…{Zß\q (7†œNÏ÷¿íâ×Â->T×mY Æ›æ]jxªÐv'‡ gf5ê<©*2º Ô_# Ô Öšó Þ˜BþçIçdBÐ…Ê ÆÜ¸àà¸×Y_Bôç,¸²€¯=À8tµb†p'D^²BèÜøäÖÏÝ4aL¼¤¢qdR˜Ìo<÷sm=!És¨\–Ú ùM r@Ë{®Îm¼‹OWníàŸ˜^AN­WHëßöpcKãó6NÍ"I‹ÿ}Ú|KK©`ÝŽì Ìk¤ö+†å; ²nÖçÀ"æš–´‹ßÇ|ó©ÿ±ëÇ Œ˜ïüNä€O¨ÿM¢Hy—·kÝ\²¸€7³óÁÅž—Mõ½>ªPX, 3O-*M%Vr>ËÍW,ÓSöYl×Ý$s·W“¤;ÏK‹ª„Ú;O­wZU2EÐí}\°’ª  àp¦(-a.¤¥€k¸›ØÛ dÝÕ_£Ü…û›ízzpáîüz1µj©,[ ®KÑéüÄßmŠ‘”ð¯N²ç¶õ‰uÖðibUÛÿ¿)|{ä¯M½`Ç #ãÅ- á > aÇ1îú´ …O±ºXGÛØ¶ÿô’·s¬[x4¹RútíÎ4J*EÑÜ#þ‚:ë® _ÿ* Ü}êÈ'$ƒ³ÔR ƒô`)=Ï2Ê·5Yãî×õdí =“Œ.õý‚-‚Ž+?8j;µÑÛ•>íÖ·>X½lõõ]‚håH÷^öR¢‰èS´#¿ŽÝ)3àôN’Xᦦ’§›û)¡xdé~¿† ½ë …mÎÅÿLJkwupúw¼K£bÜÃø¬$ûLZnG—û‹ÐK2«ÅYF¾xùU5½Æ«µâ$°Òj«$ÑRyáJICp9@Òº2·Ž—PûX[Š\h^æ4ÀÑJIYr¯F£þ¿ßÃÍʧîõ*¬×ÓyïÝåeUÏ>*SLe@Ä7ÈHt~h0ù/·%”2PÜ¿HT±2ø¼m|½ÙŒñzPÏw¨æÕw÷ºó¼Óèؼ›‡is·ãØc+12xS› ¿¦“ÎÞàÀlÃç …Ÿ®%H4ådñª ×H¼kà·hj×y­©Q¡ÜÝxп^m›påîÂ|”ÿî\qŒ]7ô©AýÏv›EõhØÔì,‡{}UT·9dýÜ0®u©Yª´˜`´)HàœˆRà< ¦Ðw¹Ï!¸J)ÅáDý=HeŽÂóoê›°®ü$ž?¬ ü¿Ü>cÏ¡üÐ]È;ã¿pëÄåù¸z4 áøNLœÝ–>ò½ËÀm¿3Û÷çºZ¿¨Úfà¾øoú³$ñ‰Ã„vʘ¡Š`Z­¿ÛÝ[ -E¨¿?Æëv0øÃ!u‹ªx#"©oCÓÜ·Ý¿Q£Ž]Ô×WÍ1Œ€¿îQdúòpÔKn©Z ÞšØCÍ>éQ+Áþ*¦3*„&g1Á]á.RàW!LîàP¼aÎXzâT\Y')¡¥2¸€Ë•fJk.‚aeaè;Š;*ˆïþtW!ûo à#ù«iÁ\ñ˜cù¾ÔJ/ù¾YÌO¥x¾/_A ? 6壎wo ´+Ò«¶Ç¸D–_ò Ú´ª­ÜFÂíýh?¸¾V?Ê‘‡Ý.~¤ðG"àt´Ï¡5§ãà3c£dïâ½Û/w/  ïÏWð^ÞÖëƒÕûñ†ñBPýÔ,|”þ·‚‰Q|Ñ_¥Zßèó ýý•[{{Ë e J™/•dŠ€˜Â)¬â9ÇÝà¡b'¶(=6ócdœºçnr@z³£jö÷®š6!ºpÍݼ?'Â)b3"ìc;ú~ÙÔëå4=÷s×ÃÑú@k'‡K2ÙâÏ«­¸Í°O2yÞN‡â»-œžÏ›-~OgwŠõN_/5æ=|93 '‹i(2éâw€]ðyàbÍ{Ç‹ÝÚBsؾþÂ}uUuD`#~êÀ–(™ÅŸâ•i¦Ñÿê _Áw|ºÕœƒ œÃ$îJâ¡× Êð¼VèP2©tid<+J -ƒ.‰ 2÷ÄA5o÷ÙÇ»Èn»ðÙ T¦«ûã–fßn‘±7à[=ßKKèž„¥Ø7Mø©uÙâë~‰ƒü±:<é_tGnh—bêÛ†þÒ8L1˜C}›-Þ´‡ù¶3‰2q_. ÚÚ™{ìÛ'Î}œÝÁ±Í}·£ÓŸô -$f~ª!š¹-Y¨e™FvºZ«Å»ß,[|D€Ùxÿ>ÄEۇ˷Í´~ìÆäFðåƒd¾{pÎ÷‚g–ð}úÈWI›q*?ËQ´ 8z[…Éb…@HÐ*v§JˆjæE {Ε”žbD XAEI . ¯¥Ä©~ÉhÉÇíÁBG<  ¿¼¹Ÿ<Î*fJA3CEÆ 5ßyô~|ÒÇ|±H+ù;ëÐQÑ‹ÎnÛåýœpwÜÈézgÉe»“ÑOÛ±ÃC~¯ÛÞ¯ÅÆÚY»;æ~Ó1þBëû•ï7ɇ$SAÞÀ¾æ–¼ÝÎm)†ˆn£ã2âæPœÜ'^bz­iž×y”º9_RB­•‚œ®±O¤"‹×ͶòרÙ|}%¸³'Ú;³ÙäÏM7–"Ò~êvŸÀQžUb¾Ý§UF >†Ž.šð5UVÔk·š”àÍiŽ<åEî%+Hn4‘ììôŒ².§žzÉ=„lNä…+ ç¾°ãeÿú:Ù`§¸ŒŸÞÕÝ®og·ù’e\ˆLIþQeÝùëÎÅqëŽ×{¦Ã]_n°†‹óü¤¼[µö>1dï†æ£­ÏGkã‘Vø{ö¢âü¯uñH·sÅÞæ=Þ}è3w÷±¯8;ÕãðØiCøé¶ù„àŽ¶Í€ºPOô:uþ˜•Þù¥ÂÔa,ñ›[ߺ#$øŒ’,µ~r šÌ}À¿‡ã<ŸÛóu³Î®á¥ŠŸlúx(¡¢´L¨ðÔx€CZp]0o˜w¼äÄû‚0#% åË\\ø-li‹‰Mý¼Í}–7÷Göû>ฯ¦;pX¬f©ÀKÔRPöØÁoûÛϹytÁ` 7”ÛÝqðÐKôMÏש÷ Dë^ŒÇ}oÃÓ•ÍÞáÄwŒô¾©ÿF¤÷v`ø…=ãg Ò.Å…ÔÄ8Êÿ‹X…uÈéÖ !`àM†7¦NuÈì¸À5>¬Ú¾Ý1MjžÜHTÈŒq*é|¾Ð,ã8z?‹ß×ßîÆ¹UæáÁ¬&3†Ã)¡pð€g€r™+¥¹Ç½F™p¥cÁ jgQhBµV$)KmJªËq3Ñëj}‰; 5¤ªpܼ099LeŒW+6×s)ãSì¹&ji‰!ß8j ?v\pén‚„ëA‰ëmÁó¤€;;‹—~^(zêÏïq¢Øšü$î~H^­¼g{«˜j:ÀðÌ]YsÛF¶þ+|›¸®‰ê}y”OœXN2v®]•·ºa2¢H [ʯŸsºæ°¨©JRŽÄ(”„³K0Ä#¹Ù#j`á˜vNŒÔêóí‰Ô“hÔœhÕ'9Q½¾ý³Š#ÂAôÏûÄôäç ¦á#@–q1%ýB:öýâhù#A2DOÉ‹ˆõýåpß×Ãv¶0A:˜Í)qâ OÃNåºÔœ³À©¶„o‹Ašà ‡*t!HÐý“Âç€[çí„ùíjáv›# ëàUm\8ÿŠªLY™)%O ü›¼ñÏ!juÝÏú´ºžèì·a­=Bœj,O6yW©ñã.±é3öÍBø•§pÚà.rÔ¿“3IÎhÊ!A=€õ_ðCõžýð»®ÚÞ/¯ÃHŸïsç0Dh;eF?7è‡j—ÿ~¼Só*•qÂôE˜€ó gÎý†X–ž{Æ4 N¨äš–ÄçV–Z–Š(b‹¢0¤¤~IÐØÂ˜0u<úwµ:ÿ±2ž:ÿÛ¡@~¿[¢Ð¾_m·ó±•"1袽’!ú{*5øGWÌ\:š¶¼vßLw»ÊÚ/ªâV•9-ÿ_ïZ7¾¬¾½ë«H}É4 9~ÐÁãq'ƒz™}û VöFosLºGsèÖµ:[¼E'WqtŸÜ¬úw ßðÆ÷{ñŠØwOk¶$LO©|v•.›¥é]ME¡¬+c/²äûŠà_;?x*P¤ðŽå%Ës¡œ×LFÚ¢ÔNÍC°0òë`rZhî”ÌK¨ò–—ÓÚû~LÏu]–ÿ‡Ç£ÊõÃÐÛ…9ªãÝßvëT‘ŒÙ©µÜ<(}2º/¸exœ¾Z­oú¯bŒËúˆigæUMÂÿؙȑp»©vûõdîò/nüöÛ€ÐqsÀëmǨ'ÊtUbýó+}.¥Š³óQó¸ÌNzs·™¼™w£û÷PÃvè¹wÅ{<+JÌsåSJ(¢Ä™ååpÞ5að=º Œ‚rÐZk^!@4ÒÍ ÒÎxx{¶p\•†ÚÂ"ÐC@W¦`ž™àµ. ž,ô€Æ2¸E¶¨-VŽç‚_#”ÄÁ‘ÜAxºÑU¾PÂa0‚^êÔ«àÛU¸¿9ù32 m7n#{B=éà7÷ÿ´«¼3[Ô›;hÄ»A‹MúÇŽ@OZêu…âžH:•†v›©3Óð›ÔVòóo¦Õäm$þܬ\y°vÿˆ(%H’Hnë$Òwl£ŽªqjJºîÏû傎NWÂp1.¶©e†rqpþ½+VÅÌeðè-·Ã»7fx‘Ãìå<“FÇqƒ !ÂTx¨öBc5db¸+µ2^Ó\@Z šñ~ÓÝ-<òwX¥Ž³Ü}Ö(01hv‘x^#AŽHmfìTÓ“ùùŸæèÍåvnIý¶&Ú5|9èΣŽ^6ù5-Åâ?;š±Ž·šô§ª{i~l‡F©ÔÔž¯,C>˜ü¶Û„Ñ aô¬X-®ÍŽFÖ+­íÿ€ñ¥ÈÐhyËy¦4.±›û°,Â:ó‘-?XšyÉPÞÚ óÚGö¬²ÜðFó’),Õ‚Ð’–0YV)&s/lîú‡ìb±ú2ßP~T¸Â˜5›»nP£Ç5#ùÔ 1ÕŒ±AÈ©¢¹R§ÀþPS\+¹zìëY»eVר^ãq½ÞË&5€7žÂ÷Ò¹¾æÒPÊÓ6Åù`vTQ5ùÝíŠp;ùìð¡H{o*Æ}îï ·º»A Ìv>_‡·ƒ§I=÷¾ÛèŒp˜ž\« †R¢/ÒVßÎÐfy(r uyî© \”N£ìUz›¹f”>ð¼ð,w¼`BCðz%‚v®`$PÕ_jÃÚß¹e¶Z§vû'düÁ›øõb> ªý?¡/¢büÔùÓjQ–c|¸ßÃzsÇ{ ÊPÙÊU;êÒ0×Î0×j”»ˆ>ôõiz[ëJ +õâ‰Ñ†ýuJ{Å›¹ïÞÆÁŒjs–Mj=ý´™ÃÂ^)l5·°=Êìò- [~>•‚ã¶ïËÜMþ˜E ÜW×{×îøY|p‹ÅühÝã85T‰ÿÒNlf`r•£¥}ªMF`„½ vžö5º§…l³ »|DR“”Ðp;Ï©£yYäL•¥/¡ý6%V÷@½"P`³Ì!¥pé ü;gK- ÛoYƒ™8¹–þ¸Qíb3Êo·U̼͒€iaj¬5ZèŽÑ÷¤ŠWj]nÆñs,‡;³z%ÞøW"£ 7eû4ÅûðûNžA¦L„ÙÝT«ò}ɯÅöjo"àìÐ(È>[ˆ+e™¼›/JxL&oæ1Â+:wLZ”P%4;…ñZ0'ƒ‚ qD %ŠXhá„-Õð§~V\‰e9[»ÝQS÷ŸPv]÷¾Ô¸_Œ+]C“˜1Ë3Ëõ©ÕøÍ|%sûròÛ:ÉWÆÍxOüþ ꢗû.ÆhÍ=O®Q›yŸõ€ÝÞ%š Þ©j°i[Œ®M¨k<‰Úîš)¡ÝÄ/˜>^ÉeÄS\åƒÆdmÔ]eøù€kV³J 8½«T@doÏ\§‚+Ô£ó‡ù±ÇƒU!=Uϯu=$ƒvI÷Jçí_%¡€k(‹Éð¨Ìp¢^„í X¥õŽÃð^(maœwÊ‹B›¢ä\‡@‹ÜÊBÁ„‡Rñ`œ3–[šÓ~î”ëþ»²Â•® ¨îg»A¸j<ÏŒä­0ÉŠLRf §f…·«¿ÃãØ8ÿ¯Ý &ãX»‘mRÆ&‰:Ù«%]úDëpåñaÎÏ&íN?9l÷NO±¸&q©Èn2I7¦½~‰of%ª¿œÁ¢‰Q“ŠÐ3ùçÂ{@âÍëŸî‰vë‹ÿWs3Ì¡·+¶ï¤|QxÉ·ßë.ѼH2T†ü"Zˆ=0ƒ”h¬=õ…Õª4áÎJ¯ÓÔ"s¯e‘—Ž]2“Û¼Ð^:cK“û@r˜´ûWâ_!ƒ»µÏ¶³yXÕV¿u‹0¸UK‚Ž£qN9™R¥§Ôrú@:ÌÛïŠõ⦚ ^Vl‘ó»åmOÈ_å•{ V\Tcnjr[¦©¥öŠêmm¶w┹tss;l¯çËzi;ôJÔ=Îä{`KÕËcäŽaY©Ñ¸æ8[¼+®íäÝãz;Gw‡®ßþ=´;íŸà+6k{…ß°óG,Î¥´ ùÏnì ¡šÃt<æSÍ3©RÙ‘¡y‹ËþrňȓcŽ@‹Ç•d” å1Þ*K ¶3¦½-˜3¥àò—^á$dÍi`hÿØíwñœ² Š'鑿ƒ5ý·¼qk7ìFÒ©‚€×Ô’ªÉ©ª ïVÑÒqú­gL-Ú‰!¸ß -Z§QßY„]µìÛPÈþ¸uiçíoâ)¢1î!ÎßU½‰k´„~mmԲɯa¼á©¥Œµ] VÓè=jç$-Ñò|ªšk6yù ~@•ycuLc½æJN`>@íÜÅñ¯ûû#NãÔHöÜ9Aë Ê&Ï 7Pÿ"•ÿñ~.ù¥ZÙÇ—I2Ç»§'9üXY0Äd°·uKÊ.mlLsì®<k#ˆ›ýŽ<2Ò’?d}C+v•,$Â^–˜&>„æN–D&[p™ÖÀÿ°N5Ľfºá{­c¢ÜH¶°FPbéùª…}Þ…¿G2ÆZ«èýÈ P=@ƒs*%æzõy¾™³—“¹]_5YãG×{d«SB`Òš½#³wllÈ+c­ý¹¤3“l¤ëû}•LÂS7©.·®½âöͤ·ŠB“>™ÞOäì`ÃÓ¨L¤!„êŒxyÉ S“«Ü#70ÎUNöÓÖÚ ÅhAݬܘ5¾ª®”PÏž/„È8J?Žžã)ÍŒ„†ý"÷ºÊE~9øaîÓ+uAK­ÉóÒP ó°¦zwÈhN¡lœ¡£T¡ È(Ü1+•ôª4:ôs^$©õ*ë"ÿ Úï»áîâý úì]8~ T½€ùhÊsÇÌ©ØùOó¿Ý¼Î{·í?ÆÇ#ݼ+úèÚT–†¼ÐÖ5ãÍ/UøE-!xÅ6Ôœvü{éwi¸Ú†×C©‚zuFÍW(FO®¡ ¸u“·hoÑ{â'èâaà0 öènuž;º)™ÐÜŒ³Þ$Ï(ºÄ]„»ùúøÄÂ¥³BP–i–’‡œR ԓ2Ö1å +…–V±À”,‰"…– Æ êSI{ƒ:‡`õu“A451üâ}ìn¸N–ßs$Œ Éü"N ~߆—“h5•¸øÀöæ‚yŒØ'ýy# ¹KQÜnó7Û'jñ Î6âyZÁ®–•‹Ðûçi\!ÚÙ :4– ·óÕWïô®jsšúÙ>gÔk®œ0m•_ƨ9Ñqšiu¾›'B*”©»£ß4<»õ¦ö•—:µƒ÷fîÇ’G·Uyn¨•$Ctk¯îþU4³¸_¸Èmb;C( ”¶Â³Ò±Âiar¯P£†J‚W6ŠËs’{]ZhÀm€´ãÊ’­$E-±'q­»„wwljH¿\Ãæ îçm2±í)eSaäTÁ\ü`:uLx“À4zÊ÷d’Ѷ%UUËNVv°°ûäWäËUÇÅ/‘ºFŒò· Õ‡f.pÕD]§P“¾æè˜Ï4Ð…¸»lí8SÆb ~BFËóí…jr )|Û¿}q‹Îßßâw†‹×›þ®¡8Úl\1ƒGzÛrx²6€ÊgáA Ï=]LÏÚ6õ”Í$ç/r•p ï²»Ýzí}j ÇF!h.´¦Dyå&Vohμх”š¢ ž1)¹*…ÎZSÊ2 Hí³Ûék÷a†á8®Oˆ`ßHîhùyÁ¡Ö =Þ©3ƵCõ§¹‹h„y…à¿ ~Ù{HÆÒéà¸å.Sx²û‹{>ønZh¥xjüs׶ܶµd…u^’Ô„¨}¿<&¶ã“Øš8Ç>Iͼm"LŠÈðbKþúéÞ7ÒkXÔä!–-êRú²ºW¯5^¹¶FÒ êßC¢i<¢ú]÷ÕÓ¾áæ¼½±¯§Ôqƒ Àîo½q«jÖ^@i4 §ƒ W X´yÁ;ûGÖ$p¸¼ ws—­ýöK9ª-M¸H .˜sZÛÔ¤.“”er IIVð‚ãêÐÃûTj¸É]Î,TîÜÁ3ª¨FwåÎe¤ktÀÜ•óDäsÙúŒþÐÛÀ7g æ«*®ÉÒp¶„lÃïO ¾¿‰ZíÂÇ5î^G¨¼ýÁ\DöýN=´%¢öÈø‹tÆô½QŒoêry¸¿ý"ßÝßœÔ–Ûæô¦a wEøîƒÀmkt=U¼%1ª÷Å’ÕR,Þ@ ­«š*Üœã‰A|Üw„*ÝêÑ áM¹Ýúý¬á`”g§™HÍÔôÞ’‹ð´$Wa Gu™ds>‹9ã¥iŠÝyJln”s\ŽFr©ÓœX¨è<ð G„. ð”R‹¶0ZøŒ/³¶ÂNòyÚÓî!õ§ò“ð§?ÞMdŽZV'VZyÏåS›xL߆~ÍßÁÞºS¥Å›œê=\?kÿÈ`3-¨kš?öøqÑßêå!8¶Kþ €À8:h#ºQ@óV~h~9ü.(etñê“ÛÞ…ÅÛòv5I,|sü„ ²Ç#ÿBüòg¹»-·³(Äœ Ó–® ÝM$—ŠNBw­B×înSmO¥/N">ˬ, Û,|j 4èDÁ·”a -cN•%"O)³ÎB±/ jP^X'Aý[7"9ÿÝ›g!÷—ÿÇ'€_+¾Ÿá;SÏ“·zo«Ï~ùûnÈiúö€Iƒñ'Jc56/¾qŒ¨…³bð×®oýÐÉÛ¾:a…jÞ øra'7êþ ÒÃaAÜ"@¬£´u—ŽÑܾ›6N@•@Ž‹%)ÕâÕ¦üèV‹÷ïFT©OÆ/Ý~ßsÔ0瓌•ÁffPãšÙ€‰„ ˆ§éd`ÎŒåWÙù?§ía\p‹ZïŒWN(‰<æˆË `\Á2n8$”f*ÏŒ¡:Ë än2‘CùÃHàcµübFç)ìÀ“³K7ð LÚG!OIh´Èø¿cö7ðׯx8!~¯‹}½è†j§eâ>€öî   ­­D÷ÎÎD®ËB>Îùâ„°"ï­'£ãt¼èí8‰½vb ]©ºaÀZ#Êl6‹wî°ª±>·mçû›ƒûTúÏ“ya®¿´ÕÚ­¶rT7Ó(Ŧž1øfÐ>B3PœMùœX+…gÂÛ ¾Åœ+4Ï4²pÚ3Űnfæ7Ñš$Iñ ~.x yp°í*¿šBßsnT€WfO ¼üî§;ˆÃåëj32Ä‹’Á:*(S÷Ó@Øû«)äøæÿp@ÚŒ·…Í;Švx¶.ÒËÖ¢2ž!@¢)üî‰l®%êuèËöCóht[ÈÚÍX`*àêzôÜè‡ù–™ÿs|‹4ú1Oy•Xtí½isë.B³ž  ñL> ª?Þsß³\Sg!/@rÈ3ç(g™-$ÉD–Aíà9-¸HmFO ]üï|êrP=ÏrnS=Œ ç¾Þø2[ÅâWSA-äRrêi-ž|/$ÿ@òµÕî…:!®öSÁo~—û¯«ô¼Úa)¹R̃é”Õá¶ÎY(:ù”A¥V9¹„3®¼bŒyFDZÐ"ç¹pÝT¬Ç« ’îý°lÀºÜ¡ççr¥ž^?+ö_ïü¸”ÈOÛõ:áI9NIé’ ƒ´âÕež,È]„éØ_Ý7Ò¸qWïùÂÿ¡‡Q;òô:Sœ>®Æ÷t|¾¬“íDŽž’u°ÇOzŒ(?Ä O ô¢á]½%8!Oÿ „T—ëÕ2Ø—à¼(Tú†â3lhqBÑý>UîíýZ}žÑ¯35L­¹*Ň¡þ¾-¶/"‰ Ò^Gà~DÉ»…„;øˆ¿3K-Òjnáé°ÔÇÐàÎÉB잦Rz<ôµÐ¤H&Íã’ªázÿ±Ú"2ßJ; ˜ÿ{WúÑõÞ;·[OŽòP(DI¹D Ú{c ì?µÚÃ#½™ôÂjhµ‡ºè©/dî¹(ãwΕ/ˆ3{nxñU§ßþº. l‹'…vQ@Ü\n/¬!‹·Ç´ú\¾ Üþâb7Þrýûüw’Ñ£*ÚóâW;ìžw]¨­¡rK­&×óKèé ž:\e‡¸¥“ýç²mÛ©J­†n7GöAgÛ4˨ϡñKS͵w"3"“6'i&¸.Ò4ƒšrÿEfÈ0KïsºsÇyz?/ OÝŒ[Q¿p»ÃçÝ 쫺míR»$Z`Ó.åS5òßGFÃâí!ãqõv‚\WŸræf§§55‹'gÍ ^\Ûù»Zû~¼n;éøÆi~0Ãêø¸Ñù¶ííÛ7°ˆc“ZŸšPrA‚.Q¹úÇ¿ÿöÐÇiãã£õ.fï+4!Ÿ»ÕVŽQöÙê"ᦕ{¸M$TFr•[}Tîy8ñÒ>UÖfD¾˜…²lð©w©eÛ¹á<çÂP0¾ùÞ)*þQn=ÏÇz…ëèl¬é¬xÿ«ÜL|½ö»UµÉ'bå=ã½>ΟZ°wîcV®\¼<þ| uzpÈ€w£¡¤wºCÚÞin?â÷ÍäA‹é¶Ýî÷ð(ÉÑ‘mcôFfNÿ¨®™â{׿Íõá¥U<×i†úá/=@§ñF€€9Œ_޵K…â%wüâ€g-YŸòéc;üD›Í,<ÿ+ZWåŒ=¡úù-mM Ǽ;Ù M¿¾c¿ÜW_ÖÐLïgrX},Ï‘“Ÿæ,³Båiæ…-ˆƒ7iÆòÔBgM=cŽ[¼ãñŠSš 7yÂH=&Oþ¾òaž¤×O‰|GÉ)bŽdâh–BYy-ïSÆ)ÿÐÒ—w~òë¢ð»Ã—ìðŸA„¿ç<±z÷ú=e¯é8±÷÷5£.Šô‡1`ÿ67\èE¹ïèÅÑðõ±Â¤&äsI¹\ïùC“x_»³\}NèEêÈ·“ `x¨è¥T=NÝ¿)¡ ºu³ÆöB·‘Ò‰ÑÄÈISú¥á ü„¼Já…FySûƒ?žAÞ›JS"¬‡P€ÐsDÜÐuK ÕÚ,¨ ‚Ö;ƒ">P¢SášRZäÆH¯†ýìvU pŸ­\îçÍá>”‡q#ê·n]n'âõ?´ýžü?XH-ŒËéhýäC´@š°{2¸Ù¿¦Ùm‚.%zzGg íçJ‹«ÜÐÞútnÉÆÅ„Ô~nѪ)4Nm-ªëKê¸NŸ¤òl,÷8ô*”Î º;Úä,#N Sáï¼»…/]}·ö¾˜G°Ac®t,'ü¼;ú©Á ™”4P‚Þ›óªÿ ! lŽ í–QååmöýÙãádºöêМã×,™‡¾¸k8ÑØ¾Ì×z»íyK3ˆ¼‘`;奡µæT^hµˆ'ïW•Û4ãw2ìJžýP壹¾àå~=´£›ZžIœuÏÊuu´‰Lòˆ#—L(Uê:ç.Ñ`3´yØŒâvë%Þ‡ú—$76OU–R• æSâ\æ‰ç©+‚…F.ŠTä|*3šfJ[Ö£ò%á³ëÖ¶ÌFÇïµÜÊ ü{ùƒ‘’)¡É“ݸ^ºOåþÇÅ_%¶+å¾V»{ï(å¥ß Íê¾™¿uaÿuc_ËáwÇ/-:À¹}#} õP‡·ù”qW_Ãüޤ¹§óUÐ^^®¨HX¼?ø¿W>çêQ“ú¶A!ãÆïQÀ“O]¤†óçæÍRÂfrLg¹‚C¯ïùê˜ïÇÅ1£è“+Œ-hNÒ´(\nRg3hðMJsž+”Aƒßµ,Df¸að /]31?¼Œ?ì‹yG.î“ß¶½*³ÞÊMïâ%[JÁ—†{O…~ò­Ëcº?"Á½^™•ýPÇêYñïݵ ¾°Y³×÷«‡–û²àÕ4¼Öóæ®ÄèSy¦0;þF„½;^ ‚fXkH1=R,dÒ©Ø~½©à7ùèÍ‹j7+´¥‚-Ïݳ/-M¬âdÐô§}•M”2–\å†-Å‹ÏäP¥ã’µß¥óÜæE&¼Ê|¦ ¥tÎra”Ñðv;QÞz§R¨ì9)¸. ËG_m?<Ò» êäyR·ëyW«wwgwc'ĺ#¼zÜiwMKm,<Tßsùˆ0|tùKFè’+#ïõŸ€­©,·½­ö«Ñ€‡ö¼aÀÔ‡+û“û6œ¸õÛ¯Qš¦-èaKÞÑuÂ\kqætøá«2k½²‚2F‰ßÓͪÕõ:¯ yÌ5ç8Aœ‡„qMߘrL™ñJ&¸—3Ò°Â,Þ oø·~W·ŠLbü ²[@3p1@µ¶jiõ³›o£54÷VNÐ1–pkqd}…Ìñ÷ßÇ]>š5,Ërƒ O¥åF^p%…DŸ^jS¡3™JÀ9õŠå>GÅëÔsCsGÓ” £ü õ•¥3å2ó »8–3>ìüñ0I¿Ñ¾á‰>½a:Qà }Ñ×qVX!ç³KÊÉÁ§\¼ÁÞfSãäG»åŸò0›>2ù %¾¶·‡a ì¹l5Ï­* -›N šR2½)Ã+3%˜¾ÎP< ÊŽsTòBAÒ„.S“”¼"ÄCÍyª¹)8×vx˜;*±(Š"•¢È†yið¤ï}eجÈ cañ—È“&S„0´¦ ìdMzBBÙ¹/Ë÷·[Ç„VRZzÁ{kJÙâCµÛù‡ÈÜœŠˆ_07|zT+áÛŒš­R]UFM$jÈ4}5U†_%·;7^' Sæà{Îs@9a)c)€_)0z­¼ðÒd^Hcð~Ã@ʲúOo¤rjxHtwDnþ.µC ¢yõâÔ¶ûÌLqï·©›ÔW¦„% ;ÞÝ31Ö*¾ôÙºú|ÎÐ:;S6Å/çH` 5‹VwÐóeëÅMPñA‘8Q½©¾ÀOò‚øŸ,• ÏͲ`$Ѻ’!8Ú¾ˆÛ$ŒU¯²AùX=dð”öûXİT q!xo ˹E&´[þ(¨qèZ [(*T&-¼–©TQÅSÊüpÄìŽðlm’G¦35E>•cÑòæ¸:sf?+ Ê2 9ŠžšôñT,/CO?&j¨0ürÃH¡ˆX¼À©ñvñ¿ìÁ§å8‘Jð'\øÇC_û_ÕIeì~N§S Kþ—¹+knÛj²…ocU™¨»/^¾8‰íÄc»ÆõÍÛ]EX áÉØô¯Ÿn’²D „¦XÔ<$•²qn÷éåä£_æê²}¤"L«^Ù¯»«¤­´B·ì‹ ®:”’©â±1âa¯19NMäŽQm5g†¸ Q`<!bæÑ}Ø*}|$ÑA;JY4ø¨ûív¾¯Ë0«Rƒ‚—ã,w6qQ–ò¸›<ÀŒÐºVWz!;<\ï=tîÆé¹Ã9£#Æ®…e~¯ˆÏ““—¨ <9ž†¼»‡C©* Ð'ÝéÆOíIéSã„â$¼àz0û˜0Áùe6eæðÅÖÀPUq‘S¬Ì‘,rlËCvŸ Hñ ’¬”œÐ$œÉF{žB´4¢ýS6AûþòÞ×”3§£°ñ·ÞËÃ9/“›¹¡²ý3„Wï)çåáP|‡Ó"qõ|òWЂsÛûÜÁ%åð¯j~œ¯°…³²fòª©·k¹Ÿ×( uëåÖ?^v°dò²qRs|\ÓËu†Ggz·».kíH+m­UƒÉØT ë›–ü"®„EÈóÜ»#N|¿B7¯1aÇå1Lnx¢>i³uvËÐÎx˜éïªË!s¥!#Ó U£µÌ½òõbYÍ]‚Ó|T·ûO (ߊÐ׫Yê2ÞpJÆà…º2’cŒ9hÓÀ)¼i6‹ÅóÉoëÅÍIÚu×.ËGr‹5ôóejš(`ûõªÝ9-ߎ‰X2Ø6Þ‘š×¸n6"So°"DAíé²¥°JÈr»Æp‘ R«‹,x¬Ñ÷¸8â¨dD‹àpì#JM ÌHÀG”2IÍmNÂgŸ å* C’6QšΆ9nû–«”ަø­1ÁÈÎqt]]žàWú ±d¤œÂÉy2$gB³Rúе3lã(À0õL^Á-Q"8¥%—O«¶Y¥îT=ŸlçÛ·yÕµíM¹ÀŒaPϧöù8|ü¬©Ý./».f°_ói«àþºh*MÜR±‹ÌŒC66w¢XwVÌD>'Áéà"GOh¶]K&*“ü)Xg,áRq£ 7*EàÆV¹ ýî_Û­Îr3_ެ=¯fë¢|®f ŒI¦\Ò)á¬4 óHÚK/ü–oa²/  ”ž)aðeò³á„Y1ù«^ý„ض6ð%ÿ¤ß ô)Ÿ;œ¡ÈëscdþpH;UÌ>ù<6VO€ysœ—Á¿Ë¸¡Ð¾a×å`` H •ž-îUÉyšbC|NJ9‘R2¥È!îd+T–[£réxî—Dïn5KÕ?õ"¤ÅÏv‚þL‹Å&—%®6·o @^ixàú„–„Іi±œ¾©ýÑ*ÊÑÞ1~Î9BqEÉ-°z>ùâzk`wŲE:‰–ÇLYJbzex/»‰–„#d$LTŠ¥/\¾cµ »òI±Ä²Ñì|·¼Â…$)R†¢½ä¨îíŒqÄAÔ±°”B².KJµ &}é‡Iû-ñqŠÞ/0S,ô}ÙªlX´^bzÊ(#?0chü纾nÒfÇòÛÅ@#>“öŒ„…Z6ùïuãÖyòÇ¢I½/þ©ÇÉËÍðjÏǼü{é®1Íõä“dÓí’®Ô„ —Å*f\F?·]ÎÖ®šw®¨I‚¶É[…jê(»±&´¨¢ÊZËrähP5ÅcéØ&Î|¢Â» Iê¯"D¦jÂ^ábPÞ­cY5ûwYGÃ#¨0^Iøm)bXqürçS‹ö”]ø ¸M˜ÍëÃõ¢#Áy8‡­¡ç[#\ÓÉ>¤M>À6Èô?98HV`Õøœ¾fõÔ‚6À.+x°ýnô¿®‚4±2ŒÊËXºÍÛEצ[‰bëReÏ„'!Âvo ‰¡î¤W:*ë,$fŽ ä ppã"|–º´ú ë½·Üâ꯮úîVË:Œsrü3¡ˆë¦„›·íBU³¼š+ƒÔwʵr¥Kű·ÝžÝ‡ iVRu>n·d&»q¶Ò ÷ ïá¥ÑÒd)ŒYNŸ:ù¾£`ÔšA¡^¡!Q½È@ÿº íj•*÷ ½9H¾˜‘p /”ËÁ'Ï)H*¨R‘C>c‰Ž[¡YŒ9Jf$âŒç4ìývx»‡»+Î(¿^w×Ã…0®Ÿñ+y¯0Û'ÛŽ?]hýrz¿¹>E¸²LÙ3J"Y+€œì¹ š„ïíûUKnÑò¢Ù„Ó4åQCýBôï&^vI²RŠž’D¢ ÈŒÒâ"YØ Ð“ëª··8£Lm„{žÙÈLQÈgõœäaÏfgᜇ·Æ`»r/'•7.Â&‰‚çØ×ut³ ^—¹oÜfT—å_MÙoìßí‰ È'¦L)d±RÙø-šwM߸Ms4‰v4ØS œž¥0ùÛämÝxnîœúN‘•WÛEŒ“ÂaáóF‘§W!‚[¡CÔ0[™*S)¸æ2ÃbÎ{*•kb*ëŒPƒŒ^JsæÒ¹h‘'›"ŠW8—˜Œ@áqàŸŒÕNXÜ1&FËÒR1zЇª]Ö‹åHcÎÝbÝäbÿ¯:-ÚïCU/Mì•TlŠc£¬üW»ø¸Nð4žï§å÷M|7Ÿ—#ŒÖÌªÏØ`šòfÛ¾¿ó·ÜõX¬oS­ðËöôœÿcB „PöÔ JÜ Ç‰ßÁu|e3…ÝÔ à§Ì(®nÊj\ å9[)œ"!<´æÞ:¯|¬gâ½¥Y8ª<‘ ÞPmÄûû’?±ÙR»ù}í!Ü|îÚ"]yÝp5LØŠpVQy`ªx°¿q«ÕtÌA"ˆRRLÎ!ÑëHzÝXÇÇÈò—ƒº>AVV8•}…%ONWpŸP‘‚†$8cíEB˼n0?>Tm=ØÑRKO².ŠR®„¥ÚÓh“’‘F©° -¡Êz@M:A$Ê®0±¿¿§&Œ,•QñáÈÆ*¬­n} *~Y)‘ø7{¹ûÁÍ0A~÷3Kü䣃7gW¾õEíWO½EÈ.ï 3!U¿{Ÿs/p´ënDÔÀ©«'/+VÁY!z‹ wW SY`Šú" eÓ¸îXý4¸v8lï=¼è”9­Ð'I»¬•¥Î¯‡,GmUŒ5qóEñ*Ò‚ÏZó?»†Å8µŠÙ¦9’i<袤c9ú£½c«Ã¥LëåvWàùäï²Í²ŽM&a‚Âð¨{z¾. Æ÷.Ôiò¾]µÝw·¹uîÏp×.œv?g>*˜èe—„ˆ&×VšÁUc&*-¹ŒœË7à%Ë›S÷½ƒe ÄqÈ•dLŒP ÄY{HÿT–” ¤!7&™É.g×(D>›ÂÄ×¶q^Í÷çÛ¸‰ü™û^”üÍ …l4ò©áb* þZ•F‹ÿ†ÿÃw¸»ØMß9À=0 ¿%—ÔžoŽ…ÎéäU·®ÃÍræ7“wh§ºßd±ý>š‡ó’Ý·™Cõ—ô}3ñ0¾ô© ½¥§ S{l„Až<(ˆ$ Là2ÁšvU­/ç_Vj.C *'³ÃͰäE4ð 5Óp⪬XH\)ÃH0! ¯ 7‹šÀû‘ËügÇå(è¼rÄ£v>íĆªÅR>3WÖ* ¦pE‚²N͈^ Ó†rÎÏèOÏ(Cñü.Ý pî^ÿåvZ’õ.Ýð•—­÷›ÓÝÇÇ:cqóô:úS¦+Eµ:a%X…â"d~—7EÑ$GX,;Ÿ„0‚8\×·<Ç,‰áL’]"D†¤’øÇز§P/d¿±Æ7±ÒYá±ZoÆu _øúÚmÊÛûÜ:¤›Ü(¦¦@ƧŠkúÃ[{+ëé§y}ð>˜n1–ZsFuj% î ¯P¦îB“~  ÚÁ¾NM†wo ƒyL˜¡êðÝ=óKö#Y¥à¸Îи¨¨1ÚÓÿšbk7«fXÿ)†(m’±Ñ:o‰¦<É26à1ÙR\ˆLAz&r–\(ï}JÎsŸªõõ3™°éꆙq«_i“Š4æ÷Ôýl¯ˆ­¨U•óƒ«ÆÛk\Rñ=Ee‘–õÍäÓ·®^ô¶L4`ÞÕ?{CÄcY $;O=Ê2•²R–k2,ϺõbÑ©ymWï«E›æu œ{ŸÉŠG#p?A¢‰6:Ku„‡ªÓÖ^‹yâÂiö´?ŠÌ1‘‚Þ»4jÔ¿ê\}]ÆÞôp»HH¾¥S*ŠäcÛd`÷Û ¯´L{š¿ê°ëSÎÃ,°!£íùÚ)LH3Ù*cN>4˜‚ ¡äï›´B9Õb,3Ožta™˜qÁø°¦ådÔš_d¨89|Ôº¸u"ðîCÀHššÄ%q$*Á9i˽b)2—’¤máj ޾°s²ýú õ ¹á?|T ùw»œ¾JˆÙ)L‘-ŸÉ+e­!œ0YÒ6F×\…WÁFÑÙ0¢ ““/Ûx”Tån•þµƒ£§^žæ(·—éÆÝ=¬Ãù{Í$ZÖë¾sé¼ }qÊHU‚P).3…ƒòCÛò'“ õ¤†˜b KÜ%à(šJçˆ6*CäÉ$Q™”ápêzËp­6ðþó>¶Yߌ³ùBCî"±¸KòPÛÅÒ)Üû”ñ ¥(í‚…Øç“·í?Ï6õ·44Š/8Î)ŸoÕÞ0ÈÊ©›¼jÖ~3¯ºñy„mîh»zå2SjŸÜ'¨|Åq-x°Ébd%%V'/2ÛrÝ$7àŸ˜á0´KÔÑå© ){§©Ï ¢  .sJT^gîN…ê˜ê·­wÍ&@déZÔ¦—ˆýéº.÷U^v©Þïü æ™aêJR>•––Ê`ïÃ;·¾ž5õât|ÓŒpÉÏh1‡ ªU¶ß¸d28¶›b9”¹¹÷“oQÒBSï2„>ùè jPÀûvBÌðÁ"Ò‹Tˆ›¦ÝDUÔ TÓhDˆ$@A«à4Î<9E]L&zƒ²áQÆ`•Ê’Hž³V`¤'©¿Áâ»´2ãŠÃoê˜Úbcå® õVUŠ s-‘“ßÛïiú¾uåh¡9Du ˜gCUzòf½UQBy[Öýònµ8¹Õ¢wu?|Ž6R{ò-z”06ÜR6Hã)V‚µ¼Œ¸‘kïúmÅ$ b‡Ò–@ªªe0ÞN#1*I‚uΤ`£0^J#U„¨¢½…L&Ó@”‹¼_IÏ¡VÝ8-ð?šT–œx·N«Õõ ™ê3Hk¯à ŸªrÈøû?ÞâFÎó d.ó}Üx 3~¤¢gâì|]zBÄäãØUê&Ÿ¾­»Aòþ›ó5¤XgßIÀÛÔ” óÔ¾¤ÀÍeE-7½vnw—) ‘„± ío\¸jî6‡V7‡…/Ê-žAve˜ç‰xA·ÌyK½vW¡ Õ:ˬ) ^ø5]ô„3Èîûy|ß(äPPùjUá¾€Ä×ÏÊ–À´¨]*"’q E­¬™kåÎ\ùr,ç· ö¿•ëaÜ䙂—äBH ㇃bÚÒ ×~Ü!àø~º–Ÿßyýz=äð ],\ ¡: ‰Iñ¤Ç¤ðÂöÌ)>9aðù©N³^qœÏGi£Ž¡Ý‰Æ)GA^`‰"J!XZ™ãR:%¼J± $”Xb(ܸ:#àfI$[jC`2EòñÃnÙüÖ°¥U¯MVVw!ä©Ûh¼{kU§­õWRá¿[9  ‰­Hy†O×)ÿ;#ËrLSZ<`+SÜž=§`ðiWËœ·ü;Œ—ë² ƒåüE#¨ÓÖà§h‘ªwÊØI!çÏOuÂôÂã¡G!.7ÛÕû.Юæ­JÒ ïªhÖnb­"d 3nke^к 8óEh)‹u1³,#ìj×Äká°?WëýÐnýzEûqÇ·oê¬×LÙ+cš‹"©l¿¿çb^0éœÕòáŠ]HÊ\Ý…Ü®ßÏW»@ÕÇ{ç‚¿MžÅ)ee§ÄÓ7ß#s÷L3ÏW„îIE[ÈGa÷¼&˜qlS(/ED–•¬ÁWEI$†š ÕÛ+®ª¤'BR„Ìt0“¦Ô`+ÚV>Ýy›Xú¸Åñ^&6Aµáöæ7k*mæÖ©òNqÞy':pÆ–Ÿ¼ÀO¾º"i¿ºn»Š`ž!d<ä0½•g_¬>û³Ü#ÀzÜ Ç-éÜ<Ð5Št\©¿=9“àíVèIþôù)5Dgù8›$·c7uì²'û¶¬QqReïS¨J¤j˜wIÊòl«ñ9SK¾÷ «L¯ªûä.Á­Âý˹¿ßk üßYù䌅P`o•ÃÙšsÅzäwÏåÖ1ÅÆ…ÝIr.§`l¬þدJ;fŠõÖŠ”¢ÓÁ¥à­öžÉ”j M“,p=}ó8nB¥Ž–±,Ü%¹>æÀöJbjìXϪµyqÆt Iካ–†ä u™õEyB=à²n­€<>‰®¾ÇwŸ½e~r;á^í‰oq"Ôiýä­,€ËŠTg[YŒ"µ<£Etõ#õjo¯e³÷ËKQ -¬á:z4D‘Ig4Ã÷Š-ἪÀkRñu2Üë"¢VÓŽicb¿ú¤o·(µ<ŸÇa? @.ó=-ÙÅx×YfZ…±ãåx÷ËÅa(ïCÓU„´üeеÓîìŪ\“šÒÙËòÅlW£óý“·—O6Få?;Ë/›°/‰àGw–?ùn"Zpo ·÷\×+Û3+ {Öò÷»ñÃìá¢ÙZì˜` |¸Ò8Tå2;’õ)À]È/µF›{SKá!e+ƒ+5 °úhUc#bá—ýe ¹Èe[ñæ%ò¾ÚùU)ÙógÞ±NhÓÊ)oíévv‰ú*н`î!U$åÙOÈh‡²¹Ebó›‰hä›°¡Êñý÷,¯Â°[¢%©h ½3\<ùhŠ¢ý…ÈyÎW¤ìâøãˆà¯ÂÇM9i'8ñ¥K•Œ µç*&É‚eQ—àL²pÍrH,ˤCL ÅzW«O"8& ŸžHÔòµY„¼~ÙnfŠÓŠsÞáàÀ¼’V]ß”îþc³Ù®o·ªÌ7{-Uö!Å»½ðgoÃ~_¶u òÅôã1¯˜ùÕÞÇÛyd¤Íîµ*ÿŒÔ[&õÁï|jÕY5Ùgò¸´…¤í-ÀÍlMŒzŠ…Ò’\Ò*ì`{ÓîÂw5À-”•º¨x­ÖÔ2+—£ÉR'&c`´#Ò¨œ*XŠqQE¯DR›®‡Õ‚÷ÜÃbËôZJn^O¾} ?wÏÂ;%hí!#ÑèæÀ#’ÊQókŽª8 óŠ?àx=òÉ[ÚÌÎ^ŒÛáž;•›Núår~/äû0Y»Ó@,h‹³SO¾á®ó½ãœÛÙ&0ð(УܣГݾ¬¶ý˜ïXOVݯ&ga²ð‘–ëŠ_¥^]¤…w9ùÚ&/Xõ!yQ˜ŽŒ+¦ ÊöâfaÐ2½ÕÎéϵXü¶äñýiÃÖ×`ðΡ…PWZ¶jÄ7.ÖMQ;þ!€ ¸±aîìçÃf}Øý“Fî÷×L~›ñ©PpUX/D‡ØýÔ÷*‚æR`é{´$Aù­eÓv¾iÿypsþ$ šNc‹ä®€qðœŒÆd-´ª¤£=i&x¤pxŸœ‹Æ›G& w,N:M¸ø,¼½ˆ£¼¾ÛC{*½zò¼öª¾“àóR5§S~ Ûröz?'¹Ê<èÙîKõB³³·+ùq8û- €G¼¥õä=¡(/ËpϪáoXü(iÔS³x+z€>;ù³~ª³¬· ÿQ„¿VuöwDONÄV}6Î\!²$YµôÔCL6Áé¤E¶T­,‘o¢¯Ø†ì×ÍZzÅ—JO|¸«íw²¿î€Ã:×Ôò/&¿SÏâ¨t4V׺PÁ¹énöØÏ”‡©BŒPòpt…6Iž½^ï?^ãlŸTºÿù_Žu½ 1ÐxØÞÓÎrã-KGèÎë4ðò“ge€¬˜lØüü˜Ö½UxBU.h†©_…ý~Ýìd‰äXej±2Á‰c) ‹¦8³³ á” F¤‚‘ÁàiN ¦ŒªÕ›i?Ù¯p:È©AsYØO›ãäS6u2 ùECð\ÙØýŒ[ÞáUø+úkyuˆÝq±OÛeŒcÖˆÜÁ”3‰ Ÿ6€²¼9Ýçòϧø´ïq\ 4'–Î@"eºÎKùÔœ¾ó¢7šÝÛPL¤ÞØÇ¸ÿrñÍ›AM¨¬ÅXæB¦R<Ë®æRyMºèP…ÒÁ(-BŒ1„-‹ª$åeMNMÏt­/Ç!,‚üe»nÎÿÒ˜VaÆ)p©y¥“Ì·F +—ïÊæû“ËŒã6á»Ípw´$¥´n‰oðgŸ¿9©™ðÈ€Ö¯:$r7”’ºTµ¯R&F‹9²r))fk‡¬Äs£f²]'©•K~ ã¦Ù*2J¯¿ñ*Ë:DOå¹j¥ìßÇëïÏ^/Îo4;ß¶á㺽X(aW¶ÀÔÃúb½'u†Ëp~(Ûæv äü ¯5©ƒ”•óbtˆN׺]ÀH…åJ«ÂsôI;çs•±d•uiú\»a“ûp[@]t¼it{^ñf«âN’ì;ñ Á^#ÁÃF¿™\pQhœetv©wã¦ä‘Û€ ïn#>Ù.c£5Y™4mYòÚ¦ÊËŠÖÅ“¸ò5U$YRÀk6º2Ò ¬ˆÖÂ2ü4Ãu¿½™^t¾_á3–f$y.׳]Ö†ËÞzÙ{Éý•Ôͦç4ì·]Ó.Ì1¸ªþñžžqí=§-† ÿŸð÷! ^µ îDÎ ”v×UiØUØPtõµ(¤ƒÐD{5*å(¤sQähs£§êï]Z ejiý°ÛQ¿Oöä¡sh†i©$Ž‚nJ2¾:¬h‡Oؾ¿51‘sj2“b÷Ó+¿¬SðÄm®¡fV©ŒUA¼J Z%Uä&û¨€¹MÎá횤K˜Ö©LÚxSŽeÝþkCýÇKåɯۋׇ²Þ|Xßië¾£åËŒíäÔ³ª•)ÿ瀿‡ÄþžßJ·ßžìý ysvó˜$Ùe)ôã¿ûbå_Oßn½Å=K^ hŽTée8ṡˆžxEæd{-¼®Ü8gj,›½ ‰iø¾w$o½.Ž- ß?ŽÛñÎ8Åé.êÝøqnÞœIEúÇ= 7^i«š-é_Îv¥;¸²_ÁCjåMðÇ”2JÅB’Ñ”`¹ô"éœ ¾UŽŒ²¹Ð­¢—ÎX'Ñ$F.XÅô>ÖMA$éoÖ(¯ÙøÏ2ܽ¡ý¶$©”è¶;Æš­4¿ÓÒð0t/ÁÚ6sÄH€È€ê.A}#¾”Mãjk8ºø¤Çñuf8¸¾Ô@–@€%qVr'"3È‹¡€¶fK×®7a°rïÄ»o^Ñôùvžo ©žY+¨õ™]iß ?—á‚ú‚æ/Êð‚€_–ÀéíHÝUã©>ýI+KP¹š”Cäñ§4YE­÷R"Óù" Ó »f_é¢Eh…0*­PUœOŸÛÝŠ˜ÁŽ´_—Õ‘×9´Çøa~®KIÕqÆ;Pv…sך¾½¶6í³+$7–ÅûëT³WÈR€% ÈœLÎÒ|ñÙ^9>jñÖ"5Ö¢4“GTÇ £w`¦¹Êùí*¥þÃÍ^©e-Cáº-ipÜ…tÞ÷^!öz+®„ã-ÇÑ€4¨drÌx/Ë=XQÓ ¹$_^oñÇ’Vû² m)"0ÍÊ'8þn”¢»t¤1|ŽrΣÆk—ÉFø‘×ÊrO¼½•ˆIƒ¯2‚ݲ(on^IÓÐäs4ü;'ø3£dç”l!ç?Ëú¨š5Ûšå€Á=sfi?µB^7as´.qâ%0ÍxxI`F$jI(ÚØh^µG T4Ýxl‡OcÌ4ÌGƒ³°ø¾½‰irfó. Tö;{å$w¼Eÿ‹Úñ¾?{õI^ôFî©PgÚyÛæ†úP [rœu›Çþ2¥Ãfsg€ó”¥Òˆ¨†Î³v ñ ¡–˜HrŽ•ˆÜ3¢q<Ÿ¹´ø-fäÅéùô Þwÿî¸a|tnJ;ÜŠŽÎgÍ:8dÐå®tó–âõqØ÷g7 Â7F_—U»ÃŠüxÀÛ%ÇüöV( çx©}Ì“ Ñ¢€i²#7Ñ¡xIøÍ0Qh¾™s`òB½B³ìŠÍ … ”%MG÷«›ñûEü·ñ:4AÜkdùâR'´ïœƒ¹qº¯Ìéõú‰­ËåEé~úz”õÔÀŠÖy€.,ʅἤ*Þ6®åŠÖµ1k’gHqJG¢¤ÝDq6[UÌÆ×œ’¡…nL#…Ý´qó©Rܬiê”Ë–m.ÛÙ<ø/m¿ÓÏh«rÖéÿ©ÔÂuÙu•ËM˜©Õ‘øµ]F?Ò¸½nÏç#9Ò{Q%°P4P c*bIyW|ŒICb/€¡™'-kñžyqr'mŠ$Fã‚ý-Ì^!þrý©‚Ü)û :Ü3ÆEVÖÓXý•6Íe’Ï·á0tGû9*m ãK¢ñ-MïÿS†¡}¢\eä5Fpª9'LW4Äà`{ÙNš„€ ´ÁjŠT–Q$‘V$‚Åt-#FDáÕ¢Ó{ÛÍÖ<¾t4k_Æ4,â¥nʼ-4Øýµ.wUµ¿‚FM-An#¸øv‹?üy+C³X”­s z¥† H¥ à' VÁÄP ×…jœvÕÓä£ñ,+§ rç‚ÊùnØ-ëøú9l®›v~~;6 ã´xæ•ê<@Ò•e­jÅóñÖ¾Wò‹¤—¹”z‘¹áv׃nòéTŒÅIn@„õ4 §‘¶råC\SÖVZ3%3õCÄ$SPB'—œt«N—™7ácØŽÌ/²îínºßÇí»YGNuø$R Hü€ç22‘R,‰¿«°1M¹º¨UBv<è\™òAs†7ïE0ÀdR$#«—ñO2Zp<¾QªAŒzž.O„¯í2c¾Aò»¼œQÍž¤L_„X€3.;ª#_éö°ás’#šsŸz©;ßNœü“Ü&"I÷Sžr)eÚÀç‚-6F°<gªôÈbŠ3 ñÂà_ö6Åb¿Êezg"bQÙìò‹§16Ë–oÂöïpü¬ gâ^~§@î¯D3©½ š·¬&g¹èê# a½ëSE-Ûz)A)¬qÀlÓoEÃKÊÜÍ”êlͺ¨ª† M fåÀ›´…*ÊÓ¸a=t«(€¼v¹ì „4Ö-ÿîH«}e_iųÿ§ìÚ–ÛÆ‘è¯ø-“*‹… q{Ì¥âìÄIv3©IÕ¾h1"E)Ù–¿~»IÙ–iƾ:Ž,ܺOwŸ>ãÝ•A¡ÅwûÊù~CvÇA SoS7‘ LìJ¥ˆaìYÊvë¿êt¿½´„·/Qò…°Ü@¸¦÷¹…à"geIÀ¯QÇ @¾V du ç¼öÂä`œ—ïrÕÛ¶Î&\&†C¤}ó% 4® âsAù048Ѹóë6¥Š ;Œó¶ïÔngà ˆ¤õ5°eŒ8QU"|ï8ÂåL±u€Ñà'•ƒ@ƒ@ˆWQgJ‡Yd¸ÚU@§ª?”~KiÒEàï•Ӌ¿Ëü-Sb%™NúÀ‰ìÈÂØ{¾¿<µ1³ð®IÛáá [ €¹Äã’(BT:‚:œ–­Bñ8=ˆÚx©sl‹CQø’cDŽ˖,ïn= Ôª‘I÷ö_Ã`ËÈæ¾p1KA(³‚WŽbí.½MuÒÕ¥¯ª&B.æ‚7Aò”Àx³¿‘ÙõÌM?+þs p ®¦-dî+ˆu™±®Àæk]ñÊBA Å%j¯•BºŠ ÷V¯’é€ðá`™5‰38îÛ0öýÒÛßeTZà>k½(Dï º»>âõ­Î…T¨¢›„~ñô²ú¦ëƒ<‹œ)Æ+A•(ò(ËBV•` -¹(´*iîrãdŹ…ý‹|ø²è¶,q[owk_ÃWɺ[Ÿ&ýøq?ì‚Ðâû›ãP„¿…G wÚ„¬Å¥íDZsŸmãGÒ|¿1ëðŽÆ“³×÷ç^•û!»…Õ[´ Ná(e×` ¯4%%–·iú./ˆÊ«³š@ô¯ü–5€QJ´! ‚©i»íëpìü×i#†’‰ÉŒ™äÁÓ§©¥éüì³í‘´ÕùHM4„R¤0¶nü¾Ív‡>Òƒ+Á¡Šœ(%™Ëa¸ëA‹B€Y®,|}¹N ðÞK«àh¹Úµ8¹:iæcïl ;æc;¬TFhžI¦øayJS.P²gñ3Ï“yž°Ë#o:Û,DH§M6àÕ;eqH6.œâÆÃQr/ ñ½>Lá J>ÀoƒõÎY¡©Ä>’åj~=tmÖbóÄ ë8&¾¼è÷zLOtì¨ÇË3Æhބܸìô/ë›r]¿’/6†`2a‡!ÐXçA:7ÕÚè§![¡1²(-쯎!›)ì㬴¸N–zª´Wà •õ*0ÅÒ,Èž‚»´LE3S†˜Ù °(Ql.~,¶½ÍƒffÞj$ÌYX ƒÚÕÑÏE|œÄ‰"… 3,Ò³T„tk àÜ‚•HTU©`×´¦ž'9WV„``µØé`VH¸æàíò4Úß76›^LšpAcûqNZðæ~‹sÌÙTLÿ¡Þ'¯1‡±Ý`&:SíÌ™‚7’‡Ø´³1·ÏØÃŽš¼®ƒÛ [ç 8v2×½õ•—ðg$u9X[ì;•»|®4~ƒeѶYWšˆ]ƒÛ41ð—±–O Ó·9Õ+œ_v'Ãlø¶Þ­ã2ÊäšøM¹µ¯ÌÄ RZã•àWØýÌ‘+i$à®~qÌ87VUp¡i)5ÄvRo(y€ø7¾”Ý}Ö ¯·iÕü?±@Ör²Û9}{^Fʧî] ¸ò‚ŒàLå‡üýØy·™Bº¥œþ,õ“sðè"Åþîz[zl=ÀQ; ÚŒ¶€t©[Åmn¼-iéŒá˜vÈ-3„q̘RزÜÌ ¾Œ#îv½o‹Æ¦±¨~X¸«>He]hg~Ñ”NW°Å+ÀX!Õ—I r5Ö7Âûª ™”}-ßú-\(Ÿ] » !έ4´È ϨÍK*|P 02))DЊҗ²ð`Nd%Ç•„ÑÂTc‚s7l§ÁÖ]†SËS—£ºcÄb¬£¢—¥€õ„Š‘žòu±ã­IÚàP(…ûMç›ë°9-æ—€»ÀxQðY,‡@ŠY« ÌšA@ ‘1`¤P…¼dN&–íEPðÚfv‹¬V€žIÛûw¹‚Ðæ¾ïý&^ÒXaSC‹ALˆžr¼Äç(ÕCxxìöãù°y&8EŠî»ïëU‘Fh×•Ò °ðR0pnp[ —bïáÂ`ˆRÖZPm…rÆU¡),oúÑØe½/|iÓ˜†kQ¾nžª­XNÀù1qŸÇN¥”!_R2ìˆK©ÏíS$¸ÇØ @;ë`£® °H €ºÃŠàþÊJ(; „¸â½² æ˜ uáÞ‚•Úi®Ïû°çÛuÍÒ¬žy­äȵ2’‡²™_íÕUÝESÄ .’: £“oÛ¬´}D+µ=œ<ì bÜWl½è4ðj9+ˆÁ%€6lp.]¨ YÞÜßS;fæÀm}|ƒ VÐÿiË®¨£æBçf^{…¹À;I¨ y¾‘þ¾údcÉK&@«”Û;ÔW˜ƱIã4‰ÐNsp^Œë‚­ŠŠ–8Š9˜QÆŸË-xJxSåÞvY+ÍØð"ØuœØmšCZ¦ø¢÷W]_G&6]Ù˜Ïê8ãð"ƒ¼ x?œŸýi‡M‡£MF9ˆŸë5ÌúsA–ÐÜ싲ß#ç&ÐÐØ À…Ġ̇¥$Ʀ‰Àjt]¬mM…ßQÓý+qÊÆÊÀ—kà%Zâlsê£}h½Ý„#ÎI-)”ö)«o°ápÉ#­ëhš Ds +û-¨&ûp{×h±©„ë¤^‚ÏŒ°aáÝnÖ»|RœÛ£f~<+Ì ï˜t?k0Î.æ£oö%J¦‰p¼k|8-ó½Þ#±æ‘¨s¤>nï#ÜÈ¿ð$ÖºÝ k@[uà›±àºý|ߤ…~êíö>xŒÝ\¸ôÔ"û"˜çƦÓìz¹în-¸ö>³EQÏòŸbiÔó‰ (¼¢Ÿí:tŠS¹tõ¾ßÇ8Q &'&×¹ܩeŸòϰƒ¿U§ù“Û Â¿¨‹¹Æÿ Ž|ðçgSk÷T3x™!ŸÙN£1NJ:¿ ÿ,.qƒÂ!{^`—÷±|ݤ'ûçŠÃ IäWn&àýLŠí¬›cÙ{Ù/Xç·/jšñ²ÅÁ‡ m!«ùµüplÁ>ŸÚ'ˆÄÂH¬Kr¦iC²u¶_^änÓ iÖäÛ¨eï/îÈ‚bË÷&6«‚'€;S2$ÎÖÃ!}ßòÓ›Oíˆ'‰*ëÃÒŸ}ß]–öÙ_½ª„À%19Jz$-¬¿­·ÙzÆ’yêr;нd ªi$=¹¿áÓô½—–ðy¾üÝm]í&ì9å"ÞN‚_ȓҵåÄ»Ê{µ¼Òu×zf—×§\>€œ©W§:ˆepxâ âÿm,—+lG)Kœ8j™mía9?aGºÆ-öÍô©#f>4uÓ÷øk×ûYm? y÷~€þ¶Ûz©Ê)BÈ“4Z¬ºd;;áN¦nEšÀ;6¤íºëH>æ—i™Í™¤(,3)ÁÌžÔÂzÂLZñ¥½ÿ‚ÌòieW§­ò_ad:iF‡ Ì-ŽgÀ9¾ø·WÎpŒ3"Þ"gŠÈ¤ÎýªnÈXHŸãœg€{nSûÛºLãëüDi”`ÛÖE×—÷¸¾@ÀØïU €å7«Kðù‘u2ÎPÄ,IÛhg±ˆåHø¨?|"Ôí·®b8ÄAt³îÇ1âçgï*lÇ$Íœ²0G7àI±¬öú%yòäÒvÈjÍz{Øv‰LÍ!nS?O²M!Œó¨~{~öë!súÒPÍl,§ÔÐ$×~1péU€Æ>vöeEwhSom}ì/mæÕÆ“—:¶Ê¯F.NÄ¡Ì;K…Ùo^j†=^F¸ÅZ‚D˜s(¾‹”}ÂNù ÒU–&hK@©¨F•ò&ר„•¡Jî²ÆÒ?mçÓ ìGøž›0!Óº ‰=r,Î.ún^–Ѐnà&,kgsekÛß<7‚Oϰš(³Ið=&ŽÃ^ÿѦ–7¹—Õ¯G~vørRõ©$fc3öe£ïâ/ºÞ®¥J£tõ‘‚à\rìôìüîþµ¡‰B™§¶~3d#ghqI÷\~_Û5Æ·‰èÆöWA[Ø],êƒ?Ï*ŽO›§–Î)Õ1\ÇÎ’S£¨Ñ)£€ÿ‡M[‡~W/g«°øx[Ý&øø=FØŠâç„bŽo­5cfë“4W&‰uP`U/³3/œ‡`#0šK‹ªª]8cuÑ{¿­|ã‚o=am[ðM«Ð@žy³¹`(†—°Ú[Ô:o,6â-?LìÊpžéMbFç¯È<¡Ï³Ò×É"Z £¥¶\Êœñ4ºñû9üÄÛã“ÀtUs"ä×J sø_êÐÎ2ýãìï(…Õ½ˤØS¿ÞûåªSÑhËZ¿Y§ªý±®£x‹ý\'UDûJë"£ðø´H.±3xqOrŒn‡®MZÜŸ¶m#­†£Xk`a£¨Wcëv$E¬Æõ”¢ý¶Þlºq‚q7,{AÛ` em³Í”FJ„iaˆ¶ )*)t… 9Ì+NÓbEf¤ÔTV·û9Ïîi‰zÌMó“‹G&¬NcC; u¼§‹c£Iž¯©tHcÅç¼üþš±»$ÃM¥÷b®f.´½”=}fYömmd <;@Ñ” ð/Ù¢5ùÍþŸ†ß¯u°ˆÓ/æ§ tÄt F”LRsômÝÌ2~-M+ÙÇËg‹¬ãàË{h†‹ÆF9‘ŒrôæZ€¡hEqG#žt\˜±Û2¸2L_# T=NF{-@USEFA:ŒÝvj¹U·ê;À‰­çáW ùt–to_a-˜$U{¯<|Iùþ¡¿lIÀˆb%%äTpú`TôÉ®}0ƒÖm{œŒ6͉:Öy˜ I*#(§IŠF>ãe{‚M3™Å(*ñ~~;„­Éq¬q¬ŒJ ñ{É$áDšâÐ!B¸_0•Ì—ÑØ&•ÿ3’]Ð-8*}‹¯; b8 Üœ4y’tÏ~<“å;9F"S")]Áè[f#ü½8—ûÔ ªâÐÙ0"~šðØ\kµ¬ÃRŽ€ü_Ÿ:ëÄÚ˜[ ²Œ²+½½?lbJ¨ë"CT“$Žè>3»ZHž?­¶Å¹"IGˆ³êÃUëË—˜öÙt œüV°lÔQ2mŽ0æd lHŠ× œ[v¡·©}ŸXÊþpŒ´ƒ‹ö/§å²ÄùÙÃÏ×Úpe;'‚JT’°îáXÖÉúÑn/ÃÑQ… {øÕ´b çãžÁˆ=R¾ØÜÏURnô‘L’ Ýõº^æÜ4¤“ýϾޖAkûóØXäå‘b7HRjf„IYâf=NÈ\ö{— 5½¤ãû8ò/6¡Õ-ŠW?ãtÑÝH žH㑾+Š.ƨ!’`±4ÿüÓ½@cù,KxÂ(p•ÝÖÂS—d>û¦«‡Ò¤FH°úŒüçíK¢Ñ,ÆÀºšL9Ò«§”^fÛ[ªlüǬeiy5زpUoCUÄ‘…±zEš™s¢•DÆØƒ›Ì*ܹŅå8²k…õ].|ï‚ᢥÝ.dt> E¡_MÝ%›C¥ÁÎ4ÊýQ3‡³Jæ çËmÇñN×]ãÿGÚµ5¹ë¿¢·ó"±x¿<ÚžñNvìרYWòID‹"µ¤¨YͯO7@( öžSµNm%Û@÷×ß…ÉþO µÓ‡×ý¦j+VóÙcÉ]äèð>\$q˜°:âc= ˆ½±Q>¸ª U9]à1{evü´­ð¹lÄŠ‚3Þ#C¯ˆ—¥I–±o­X6»œ  ×Õîå‚qb’Û­xþƒA,²CºÏR.írÔ,BŸÕþ«Ð/l„ë“y&ó«j$F&ð¢í°´!¯SëHæ£8½MÐ÷ü,ÉbÏg‘sEÞ¶§}5ü‰¾/투4絪 ÿå92RÀáÿ±xR-û|†eí;¿Æª+ö½ÔË\žoêÕ`Ú7C9'±††Sô=E¬ k)€ø/±Èç¼XÂ1]XСFÓÐg@e Í›€øåþ Çô®ÊuM~£Ñ‹FM;É“½«Ì’$á1Kt ×1ë{«òBôÔ@VjbU®äqeqW~ªŽGju]c2Ÿ½ˆÓ^·[ߪ×bt€†€ï¡º‹±Ø¥ˆ¹é (yšvmÁ=ž+y<‹|Q·¶ÝÏCFÆ2«Nãç·oú~@nÿžÁÚÀGÄEùFñ ˆvŸ„¡àû`- Ã4e1NXª9›¢ªíloðt†Ó'œ¿ERü.éæø7X=…è|T‚in©—E^˜°æ¿Z KAép<=·I¶¨á@e k§"t_DK6Á— Á¨ï%pµ¤¬$Q¬s—q­lWWÁkÏ^ªÕžuðö"œ¬R´¶˜Ž¼y[9ˆ†¼»P£°Ðõ˜í!O¼ˆ'Ì®¥â+%óH_}{êà"CÙ¾¦`ÂȆœu½*Ym*“Óå3ðþB|0à€-K)ÚÐ|ârÝÔyQ“¢,èþç \¾t“ЭMfº¡ÚX[9èðâšZN‡·­•í}´f>ƒðx4¹ yðõ‡Bþõ¦†½Ôr>2#ñdµÍN„_|ÎI¬ÅY–ÎÛ8š÷F©Ô4!ã3›Éº…Ýøöö–6NÓ勃Wëg8s3FD1EBL2ÞÒ2 5Åžß–÷GU¾´X¬2 =X#üâ<Geºï¼Ž-{µÙAžê¼m†¨™¾F÷SòTL6ú;YèmoÎ-”µ L}7æ ïûã¤ê ¡^âZE³)¼X¹(…À6Ž ¾{9”Š îžë|@m¬‰~3´ÙñÕ+Õ8þKÍw ϧa,jæ¢]Ó1.~•»ûwÄBƒN–Ê Ø8ËSR§Hæ~·jäqKÈÃ+„Å»ÍfÕ¢ÁüÅãÒ*…E‡x7M9HïJ+#¤YÆõá7êtǼúM´xžè Ê:3 ÆP) C7Ë2N­SJQ@Wš¥hËF+àx콪&ÍŸ:%Uˆ=òà,ÆNˆC§ÌXc¼è”ëˆ"'”M¿óÕù{Îô€wüñõ¡oò²0•x÷†ç¡ÙK‚òNgƒ×ʸ¼rÕÙðžFüÍòfE®Ð>Žè‹zì °›¥>öÀŒeŠCÕ$f‘öîþÑ·ò¾šÓð½áîÜw“ËÂa™ŠâVB´q>ÙˆE>‹yµÉóÌ*í-Rýòï-üˆþ äåò8”œöEhÚÂnñy >¨ÜÐ`.fQEN]Ë‘¢¨7²†bé¼Ê†wö>¡å}unƒ!Û¡Ûõ³ØÍf…Bz˜×H?®x£@tƒ'`‚ÙÓë%ÕãÜßÚ&O›‡¶ÐêÇ,ˆ¦„ß jÆYuLQó¥Sì‘e¶Ãå:§ÝÉí®%]Tâ|¦Ò „Žÿ"·ƒÐµ¡VeYÊ„^`kTù俇ñMeö°6ö+‹øÇfÐö¢aˆi BG˸óUæØ#:§qøá°×h¼”Y}Ë‚lý¿k§þ«çÅs[®-µvêzišð¦×•DÔF”ð7€Æßü…æÍ½xÍ#OÝ8,øJBDå ÑÃ(å‘ÖJ¸ÂÌœö£TÄàjǵEü$jK€áü¼§·Ñø|(s "§¬ß˜WšõLËjLýµû™o6–yüGÔ±KûŠ•<Ü*7Mž¾L ˜ñàY ?` yËWÊ÷A GNë·_ª×BÐ8þبòîjQžžóÙ—:àmih‹vË2ƒÀ<–ßܯjFP#9R/´©– "7èÅ;¡{•6ü‹µ59-|nÏȰæòR4Hg%•âU5À8ª¾ÇJÈ›`vÀߥ8Ðfü?%­ÆûÐn ‘Ù‰zaÀ<î‘ð(taœÚ´³ÕQ,Ò½¹ŠS<¯ˆ7šù·W}¡g½“RX­^¼ã5–>1ô1À—sù@ï‰QA+‚7³-ªs7 à-²½o&îVxJÈîW…}ð5F{pî™ü|!÷ù!xaQ]h“@Úòé–qô¹-÷]q6Ö™ ÅO)üã“ÔZ¾•‰ÙÓž“Æ)ª6gªÏÕ¤Àâ6;TJ÷Ÿyôjµ³œÒÐØνyDŠ´ ù¡ ´¿N;øÃfvîƒòi¥×eQÖ£àmban_¤Ëª-k´"+•GçÐZóÖ?ȲªEì³–öÃâ); 7º3Eè\Èàó—+ùUS)éïso2žþ\d´VË\¬)%)/òTYŒ,üI-%XL•.>õR×ÍX:}ö° ¿mªr´VV<Ûj § ³ÍÛÓp|>">5òC¿jM]c,q+–5\)ÎaµêBÌ)Žõy“í—ªilyÁ† 졎Ý%ŠÑå•¿¡/DVäæ:fpv7X“·ÂË(!û®;jËaºFï¾ÉO§Bâ¨Wq«;î¯Á“àþqLÒØwÙd‰,C󗺂?e»C°ûpo›oHäÝjúûã4DÂq\¡n`-|휠,pM”ù±ËkîÕÌS^\sž¢ v#¦ºzºŽ³…S©ÿÍþÉÆhí³B·áãÀ fóˆ“4÷•§ ÙjÃRjqµ!UÀih{>ëâ«´î>/޶w ×9`‰¿ÄŸ­‚StR ñ¬œUÄÀîʺê‚„ŸáŽ¢QEuÏg8ÚÔæÖv[ò3˜YõÝ›—Ýp¹u4ç]óÎågY“ÆSKj_•Ã|¦ønzqZN®/t½“!YÜš\™'Hç—‚¤ ÕNž—8`íâïâ è*Öðöº=ºAl±3P_.ŽTèÍôcôz Yí¿ö®…zè¯ü *óÆjÖ÷ªbRk¥…3¬ ªMîFcóÙoWq‡Ç˜a”•Çúz·¹ðˆK© apNµlžZíãHÝwÁ)’‰ë˜f¿)Ôz¼[H»r£åè–•¿‹#ý(ï‰HE''—8%mV–ÐówÇy­=ܨ7ÏRÔÇ*…xÆ í Õ•¤Rôz5ƒ\.y ÿÞ–%yõ~Òò?jcÕK4Ÿ}«åº:ç+=öÀwÜj&Ýu²n¨NÓ†¨ÈžÊ/èÕÕ+&Ê]QÐX2zQëûþs¾ä¡I–Ë 4,y™ûë«rX*& o7GV1÷Фí¯;?E+”ì»Q.§Ü«öm)ÏB}ˆf<«¼rSK&í"rB“ÕüfV¯‹ ; ]M•ñu´ðoá"¯œ.™œG8ji,ùE“BHØNUZ‹oã@ƒ!™}LYíô¹ªÍÕݲë’9 TØ,µ¨o5ÇÕ=|v¿*ìò泎`Ýå?LøafT²1 ]F£ƒä3óz@ÞšKYõË<+›qŠªi @ /ÕAl[yo4r’€²ÁB»vnFQæÅÞ[IZ7õŽô°F´t±÷Íɺl[õ)çùaÄÊ¢ƒÖÄ¡- ñÈx>ûU½ôLŽ#åJØã]1¦Æ‰@µÎ*a·GÃyé¹Ó˜W´Bed‘*ZB®v™ˆáº™¸%*ÜÓ6=7öý€³>¹ËëÓÎ\Ù¬Që2ƒ«+›*¬¶AvßuK71˜ |ø‡ÅDý³1͈n“« j/g¯&‰$šõ¿ÿó,å†Ú¾¥L÷ÕÞMѦƒ(Ž7ä\¥{ÑÈ‹có:ï”™gþ½¥¯P;¡¸¹Ž#ÛåÕ0JØ £ " £ äůÂzÁ˜bGßs¬¡ªÙÉ‚7y’œí®.Åf†ê;t@Ê|ö£›ð2oUh´P»Ïºy )ÝDfØîmÐb/Î’~;pþN¬òÙ¢-Ÿ®sôž¹Ÿb¤Ç—ìñ¯-Óêæ[i\êªÈÑü*âN*­Ã §’ƒ®ÎìÌnÑãÁ¯es¶§´=òZÃÝòåŸÅÅ"Úœ 6>‹¨f”v™4V2–Ð} _8j5®È7Ò›%þ0¤cßá²iè4«'%=›ë7í ­oêF¼xÒ|w‰ae¬PÖîô“ñI[¤“èØ#Nõ±–ûîè™^™{*\EËú4;vž€ú´>UZÌÝT±®Ê8b-ø=JÈASszœ8ƒ/á=µÑKR^IV¯Q@G¥Œ² Í3¯:ÀDÏIxùA?ÂöÑøí-ôßUsšbŽÅÏn¢”.aÜV¡æ¿ÓÇó¾Øu­Ô-äå9æû¢†k’.§ ƒÐƒÏ”ÅDÂqºÝ,ABj7y³cvÅ_ÚU^Òš°ï§\®Gºìû2\ûIÏg˜û™s2L¼X9œ­<Þ2,ÍGQ·ã˜Å#7"¬Æ_Uëñ wÝ•,0%úƒ"©XköÚ®qXw•½šam´ãìdYóü¦ìa.¦c¿ÛBg»p3së:Î#©~X¾Ù_äcîñŠ€/âLŸÃçŠD‰—%vN‹£¢OaàûHà\1k,/¯þfæmkñ«Úáƒ9ËXѺ÷÷"†<„è85%kLâ(J\Ú_êø$s±×ç÷Váê?c¿’Qªy7+Ò€ýe&I. —ÅKÔö°ÄESWQ8ëkßÍ»CGZÁ»®„Zôz)TåÎgWµŸ6ÚMß|7 áQdÙ£-«Sƒ¶#×(<2Žh®âxÊx£ M@©¿%+D¢Àê\M1°Œ÷RV:Ypý¦Räx¨É;õ«\ïÚº¡,ÿÒÓZ¸€d·}c=äýõãzÐ%³`Gxíwæêm/•7}°vîcÓéfióÝnawß÷ƒÀ‹áߦ¤à›%<)Pè8kDyêÇBX¤·ßÇmHHU ÜÂDyØLfhŸÉ¹G_峃ˆÄ%Q ‰1á•3ø.Ò’i(TFÅJ¯%Æ$ø.»ç‹5G ‚'©,lc U üuH6àµ`uà_ñø€â=<=ƱŽl¯IÓ£†|V¼@ï]ó•¹iNP;³ÃtìÎ0O¤ÿôi_ÔùìºÇº«¸:SØpTØ<—ï7HÛ™ù+…Úþ`¦VÓFs|G4Üͦ–²À7^”§.‡o˜Ì1ü>1#‚ýûˆ3Û‹ù@Ù5@‚éç³¶hO‹jñµ4aJ„”Ä¡‡· ë­ŽU±ŽÍ=Ó~'Šüï9+ÿ ¡bô&ömƒ¬œ£Åâwc‹:¨FÃØ bÖç¹_Êáåv› Â¹’…Èñ„¶Hú(h'ÆŸ#Þh,³ø6näõgä'o†Q¢^22{½É•sŽÖsýª‚dŒÈ¥ƒ†p>ûªS9ßçÛÚ¶î†nÀ‡ÊX'>u¼Í¡ù–Ù©?Ö)öÂ:„ÏðÛÑu¶ ÄàÅ®Ö=“íÝÎ`ÀÒ4¶Ì×]Õ·n·go-ÒÆãÑúݦzP5d:Ùf,¦EõØ©ÊÙŸ2|À½ÂàÖó÷U©ÐrZ÷g7aТ ›æÏ}?ŒÒŒghÓœœ2ë«¥0Ïת¿á‰ò½µ(¨tD—ý5€S·zÐvrzfqšˆc 3ßc:¾5‹¯ÍNÙ𞼯á½e&™Š¤.ïi?"7õ<Ö‹·C¡4á{Ö–Âãõ°ß‡þÄW‰2ì‡-ÓÔ YfŸBÉ}b":@¡a°3§üõ1>žmj¾=yýw¤{_»ðbs úh‘š‡*ï¤(§è²›Y[†O3 é> Içƒ\’ù쪹ÐЊ¦'[@ˆ(ðÒ˜%"îtyè[n­^GðqVpà™zèÙ¨µv¸ÉË¿¾q‹OØBÛ‚f\7Ê\—%ß(dbNV…ÓIlXËûÊæ,îŠ_éüí7—¦¨÷z/ŸEÓ´ÅÞBHÈâ0 3Ö wƒ:ËþDù‡RpÐÂlÞÔB5½‚z Ði1…c±ç‡ʲä;¿gN;òMîs¾æp}¯}—;3SÙ]‡òÔB»æv>ÓYô]Ì£F¡-a =`ÀzôåvÔ—õÜÜu,Ž£LÝ™L¶*·ZÚbô¾Š•üµWÌØ9 ‘ïûiê²l¥´K³”CQ÷­_º¦bsõ|ÒBKü"Fâà¾[2Áç3•d¦•A…‚Dƒ¶×ƒn"ryß"¯NΫ̛¦æK÷Ïûp»û›eXˆÚ·m‚ªº*kZ ïÂsâòº‰WE­v‘1x;€^H†• •¯èäܧQú²é™Ï~^îôþ_ZÖšDðµ²pËh¨$.Ì•tØ–ùID<´/mÑRKU øÕ V{¸QÌŒ@Þ+F òæG^ û½”ÂÙ·§Þ´w"ä`ñš2س÷ 4õaûÂòB&1J£Y.{‰OÃÖi0Ì…"*›U!²ä10_à‡V“ïGgÝjßÀùìßm¹>uÔv‹!1Š‚4f¹\ÅÁ< ,óÕÞÙuªÀv©óARÀ}åcƒò¯wÑB\Zú©(ðÝ”Õ"ò¯\Ææ²n¥DCÂyÝå'n]N¥¿A‹ ýÌ’XÜÆ- ©¡ÙræÇ,^ü>Ul&=¯EÞ\æ%* ²§Aµaàoß`YÏEOWö§ 3L'­”Í1/ gE¡¼mú|n멃'’¶n×¹dÔfÉú­Ú* ‚reÎ%‚ÄCOßi…hæ¥tÍØ6\ýû4©¦Ÿw«¿vÿ\hš¥å¸ÅHyfÅUkwÓÀ ­íµY³×Äÿß“éÛpà{çA Â¸í©;©‡Cj—SºTEŽž—u÷A˜å©ÁSàY¼Æ·_ŸF©ü£û– #là~è‡ÈQãTØ _·Í%öÕ4ÉÑ–“%×<ŒÜDUQWŒ¸R®/3ô؇nØ y.EÚs©¤gæm=u)NÝ–¨T^ÃEŸóàÓŸy¹AÑ 641èª@6&ê"UÀÒEÁ»g¬=>Š¿NUIØ ^m4ºº¬˜­b[‹þâæ‡F¬±S!L%–"› *8ƱB*eãü¢(3pJ×ܯviƒ…¿aÐ$9öM¤í"Yä!„oÖ‹ÿZ¯+B®Vcð'zLïä…}4|Ô cß–7‹oÇd‚DèA󛲸@[•Úi~1—;P¥l#ÎLŠþ£‹ëÏvI JÀÌ5ݹã_Ó†ï#‡’$ ¼Œ¥jPÁV&f{¸#V=<Ó^izYBׯîÄv—Fß Ý0áeÐvÂI§ Ñš=þ…œ\xÛøOELÿ ¯\ÚˆAhÊiÊw¡*}V/”ÀF> ƒ{Å7ÎAD5g:Žø!ƒ1~Côÿs"nW…$'œyÒÔð¸ëj'¢,ïá®Xð–øX@OL<‘ûGrÅ;TAÐ$¯ÒÄŸrÂÞãä>¼#p"ËÞas ]óyÜklO:ÑûW´!Á–U¹”R;hÀ›æêË|µ?¥7Ø÷â åÑÛH/†ḩt§“f豕&UK:Þ'ËlG‡‚Ý23-ˆUæ&iÆrÍØä˜ï2Jè‰/Q·ít OÓ^ÙxühygzÌ;…ç«õ¡oö¡±du_KÌ43Áò+íõ|΋ê`ñѰY„Ür–&êè¼"øžë¯ºù¯S8ó%«B®Óâá9CÝHb:Eõžâº¹iËdK(¥ÍP[vÃâþKÛ•4·,é¿â[_DöåhÙîñ´ä×ýì{âÝŠD‰„jLýúɬE¨LfwÄÜîÅJªrû”˜@X‡Œ‘ð‡ê÷ôе)áq½|Í/¤lŽU»‘|pL6‚7œäÍ˲^Ø\¶xl¦ÎSáõ×YõbÄ}³ãÖ•HÏÅ\.‰´ Xý"Šso¯\«." 'tƒâªéúÿ 5còòÁt ½°™ ¶"D‡ùØÂ n÷º±ž-ùyQ…ÃŽ¼qïß @"´ãhg1“†ŸÀ²¸E&®÷&\|jý\Y8¼¬ïUƈ~IŠ~†¯¶®6C0ƒ7([üX¶IÝèîÝ ò.5GT¢·7 jÙÄmßÓ“ÑÖn1€™—JÏÐÏDC~Õu("8ã*²žÕ©ðV‡n‰ÓBwÓ”¤Ë §1ˆüûÅX…2åKâ§E Ú±ýo!ºÜ6n5Œ×±˜“= ZÑÄXTC)©dð;Âêù9p˜%qG’Ôý/.!½ñ9r†µ›:b°”¿“7í{Û|4͘1I}1nø™yo–EQ’IG[·MDH|YimϺ³‹âûÚî5£"`ÙØÔ÷¸ú0ú-~̤á'ˆQ?• ò·Pœ ±{o¨_ä„lº‹ Ú…AND\o&ƒá`D$¦"crk*8’ëœáH½Df¿ó¿F}~&{²úµV= ϰӈ¨@Í ‘)¶ýe;•"<¶ªk‘(2A«_SäD—³Šú°!{Ý,þk¨×WàïCå%Ò¸Øà°Üƒú˜0PÄZÌ{^”Ðà sš#4÷$¾ZÎW„Hn{éªõ†±J!+²A„ÞAaÙB)Ò‚ìÏ3GoÖ A d*gõŒ%ßóÄQ&c/[ð̾­ yhÑuÒª²¦‡*U—Ž€ÁE Øb, Ò¬eë@m¨ÑÞZãxÐÝá­!5®Ú¾—¿êi¯xA÷n‡ Šv‚¹¨šn5;„0N‰Èd·Ö˽²`ß]K„øýj…sÏ;TnÈÓü1GO Ý‚$‘ ãC,Rð:óÕóPÑ}Ñ`¦Ô‘ ]z_½2ZåNzù¹ÝQDà Ìj»ÛýñdŸ’HÐĵ­°!yFB '†h¥±Þ;3§eG-õœ­4ÌlY§2Â’¼2žy*‚yµõ°[ûŒàqã 3J奛ËF/‡=çoñï¡ê_iŸ³_âÍ[‹¨@úˆHû¢™×·gÊ]ÖWvrðwA?5RþH º7±T>®8Jü8 $q!è™P™[\SÙfehz¦N£që·ð ôºA ÅbæØ~Uåšls¤ê‡N—ÞˆÀsg³\ª¼-d2YOûѺº“WÎf="Ì?ÛÃbt\¡ß“" R_6dY½X¥ZglÛC§Ÿ*YYv¾™†ð´„" ÊMÀÝšÖ|çk¾]Õ ²Á3À(ÁÇðÒh.Ó›¢ŸŸ%a‰4Èì2Ö=¡8REe+T}pŒÒ(±ø2LÑT“4— Ë¼èØžŸ-ÊÝýd¢N€gHéB§C¨Ê^“r\P©N#pÒ^v»±ƒ˜6û—åuçy.Úñµ5¢šKm`7ÎP÷ø%JŽ© Q¬·s΂˜[𡃆´YŒzÀÌ dqˆD–WŒ»µa•Ã]ʪø×%­©£à¹ífäŠ Ó¾}ÝÞ¶¤-=qóÎgça!“r6ß º:tî·tφ§'ÆÈÿÜÚðÖ¡Í{ŽùUÚV½*)H+,ò8ICQecÄ›EHcì-É+«¦•=©ö2“‘rþϦœY|hªoX`JÌek##™B5pÀºQsöë]“#)0g)Oc;ª¸0R&¡Œ²ö—mW¬+0á[õwì¹Þ0?Ç™»]ˆ —Ç«d‘4áɽ8§JÞÃ/¾#ÜãŽÒÖž)Xdok7±®—|ÿ°+»k[ø8Žƒ, É®¡¬nt7Yƒ¶‘7Ó«Fê^ùÞ,ì™Ã¤I?wÖ÷óÚIèæœ‹”[~næ20grqöþ†Úñ&СK„V["FßÔ‹:påw’E~ âQ@æ«Ô&v aíöúÂ=†û0på+Ò,ŸK»¸Ä§/L-a"9¶ÈZu[Â|c§êj«’@t^·VíThÎ1‹?ƒKènÓÖåânh^™ä¤i’±dù²ÃNLzPHÒ ×ï¹m:³®”)$´œ#…ã“;«hŒTÉ•[‡Öið¶HÄÖú»»¥¡T›¹e¦oÊ=Íóe  _ÚNu‹Ï3“… [ Í?!ù.FZ×µ{rúù<öìo«bƒÅ~_ª•,”îÆ [dGÊœH³¤iœÊ’–3IƒÔŠ{uÛ”ÂH¿M·:bo9‡#ŸCÑ 4^ܵMû¹’Û¦˜%|Ñ÷ .’ ¤ä8ŸòTmð[¢çxAìân:aG'-ÂR¡Úa´ï³pÉ÷µ}©™™ût #s7´q×Qó…hÞÞí¦ÅùÌthXm»ªãü4yŽ'J]lÕõaT›è-ñtîèp™ù² N}ÞÚzËéþí„}A'y gmµöE1¿oàÿ¯È»éò`8'CXÏ„Åý´Óœjoúq!kìJµm{å10?gñ±z%—åY¾Àûå²íûÅ19rÃ?cQ/à5K¼ÇÖ=â\]‰óܨ]Æ{3¼§…'àSìZM¯3G øõ¬ÍyîÇ2Mß-:Å{[çØôlÐi/fõ.ûT¿2õQÒºö•Ž»[:ÆÐý4åý*«úÐx/SáÏ“¶½±îé…>ÃÿSW+zÚye¾b®ßÍIúݼ<óþ%îÜOáDE´9µlõfç ²74æ™{›¤ïã(æKõêoŠ>¶_dI âÍ‚)ʳœF÷½¼t*1‘A²¼¹Ö4º}±•ÀW5Ð!†YaŠÄn–CYâÜO»:ÆÖoô ÙLðd^æ,Fmúp ‹@HÓj òÿÞšU{¥ÚW2ÌݯuËqTÛÎuð¶DÝ“ŸÃ7d"F`õª¼•±p'{«#©jk&|f¾ 7„ óûÄxÞÐcm´~kNà¬1mˆù"…YCP>»™s»¡ëÔÁ+Q¬YÆ4êö 90û÷˜ˆÐ¬œàþAÃøõ\$yóyiXÄv”àVEòÜtjw@ñX˜ŸªV俱dOÂêó\Íï­‰^ 16“3"8W?—IúX…[UVQéõd;,q’ ‘Ô8pïVsês–öÂ/vOƒa~S{¨ÌèÃû4®[ùiTûQš‹xÿp³§æð§7§Õ;´ˆ>Àå(e 㣹¹Lë?ƒxÎ 7ž‹ä~–'"šncå&Ü•L­¨¢„mÓý+b6d¥vÛîWíD þ½KhaR|C”Y(‚ü,;Ý'Äx™q$ë k½¢¼ŽZ6Vµ‹}érÈ–Ça˜‰–EÊtbÞCíFF¢è™¯êFíD±}ꦈˆË™¢ʦÐÊØß¼»×ð᎕èçãjŽŽ6 Ò ‰E,Ö'Εh¹9_ز:hpÿ¡}ŽpW=N£°H“"’tK8z­tèf)!¼©At«7*ÃËÂk H¤4¶ÞQhžWlªì·ú*¹, ˆ2 ¬OAF|«K®Km¼"ÏíhO×# ±Väu„jÍ•‹/!½Q‚¾¨"§ ì¹½'Ô!vÖºÆmM©þŽù·^ÑIž· ~{GŽïeEݯ­µ²{ƒ:1臊=Pe‰ë¯¶Ú ² hÛ(ÆÒîû›9;m¼Þtľ¥„ˆl‹¬‹‚·y_îÞ }À<«z+Ë%Ö€ŠÔ4OTÛhDaq´ÑõÇõÍ}Õ÷y"Šü(E+*ÝY™4¯›IÕŸ²‹Ióç?ûv ÅbÌ)LoŒœÙbj=[y;¾õ¨¥ž}±<ÌÂTµ4ТªŸèE·5ƒåJ¹°Èò Š„‹û•öS6Ôé+µðo ý£pMe™ÊTtœfá9JoqEkuíó@Ö× î†a{î{¢nU†>§ ™ÞÃJ6“Ñ^2ú*6êLÈ÷nhJúF1îŠeþÚÏHQÚÆ¢ûKµ”óä=ÊXõº¡ý¶¸òü˜5æceú)¨^£(”÷°™!Œ/¤m»>É…-+ëðù(¬N—äÖßN2;ÅY"|_C»±Úè†pKÛ›u¶·å»e²cúò.“¢Òôû%*ùÚoÔ)Y—Ǽ¨"õþ¥FÃŒU¸9>lŽÏré×jŠîÿG*÷<& õ¦³0i®´/ÚSKµV•;#‹ڴHåê:-ƒ°Ýuxfil¤nÞ䋿ž7\ÎâŠ8‹"ÑÓ!©ÀÓé±%$W'#Û‘+£ŽaÜÚð3 ýÔ—é7>ëz§"÷ ¾”‡7Fy²f˃ÐnÃÃ&Ïo ÞµùT‘e¹È“i×n:M [Û£S¸¬»:ÔÏzšZ/ø>zî¥ì9„¼·µEGí™*îDi¦ý\¤x;ºjånˆ¢®¡dl;HŸ¶Û•aRá\˜dÊpb}{á ÍÈ’/ô Ðì™Ý© Ÿjÿ.3e’á¼Dºíš¨QÄ ‡ÿ†fd«#¨ÌUY‚kÉIvp'½ üîgõ°Å±” P…#£Þ]KM>Fw¯}õ8(É{õ\µMN,—ÇÅ´è?´K²xûÐ"=‚¤†âØñæÝÑ5Up~1âüòBô½nb÷ppõH$"´K¬_᤾ XS ëþ;VãóÍùD(0- N™M‘yK<ä¿PJÝÐo’B6èPtËÈf ˆctÄ1&bn!É+E‰à4¼‰ÂýºÏÃö™!¢¦:Û×Iw q&‘m@0)Vðq(x@·–í.ŠìS‰"Xd%s;'ž1&‡f»¸«:ÎS2Ì“$("Ñ»µ% %w«5&FdÚU{ÙÜ¿fTª§'Zgƾ:¼µqU*d‚£ºÓÛÌ-bÿ|$P ‡üŒ“äqËDfGÔ7«£ ”Ó"ç¶5ú*;ƒÂ-ÿnïõjYI÷øŸêÉsvÑAß¼ìÆ„oÔ1¼&`Qä‰pHñ´™˜(Õ-ÛžPÏ[* 4ÔŒüôtIy¡¹i17ïPõÏ<ý·z:ªlí³$M#Ñ¢mÓOQgQâ‚]E2rÅýÌ1õÒ‡Çɨž‹PóMC’Dq*JÝO†Uéé)Mì }ïâk/n#cø‚Ô˜ðoÎ÷ê!Rå…zqƒõñLdñRðL7œ;·«î´œ…Y&½#e&E“¶kûÍ!uWdêyòŒ¤Æo¹×ºfÚõãz’Jñ_sóî Lc¿UËÔŸÁw+“w:¾CÈ !85ÊH'È1œ^åýÜjöž1¬Ðqb.Ì=zgi–g’vÝiTCKÝØ‹¡P(S‡G6[Õ™ÿ SÍl«Õ5»ÖÈÏü( "Éþsƒ3‰ƒ™ILêij ¾mqÊ,„éÓ7wräpI7 W{ypQVĹFƒ(žÊìÆ¼Ãìl»´ßxýûþ…“tü€!r‰öû/PÝ©ÅÝHaaž›8„.I´ 5Fs©{>ب§¶ÖȳT—[†FúeõÊ—¶'× CWNæ/#^ŠþZ³¢ˆ># Ô k{»j*Ù{Êh „ŠI†é!œm/iÆOÈŽ!WG‘œand¾/ƒº ŒÃ¥õvpﵡ×ÞÞÈöHõU¹Ótø=Õ•á+Õ<ŽÒ4 «>­ÌÐÊ–%<2^OL¢R-ÙÆ÷ŠÒ(/QÔáÉx)+2_Ôü£ä²õÖm·z¥¦fñ »T8:ÃZœŸ9&-gS ûMRÿLlç2`?OóHÄ,Õûšˆ˜Í¨®nLµeŸÉf¬‹rO߯?Û™bóÙãc†ÞWé¥Ð22Î̶z"Êð7ŸuÆ¢¸¾¨g=ULž^Ú|c «ûæÝ Mw|RÇi:“&ó4K#Q”-|@»¸©·íFº!¼r#Yc ;{»b¼ /h,ÓôØMlˆ+™Aìë ¥™eëk "oáíìµ¾8?CcO±Ÿ&Q–D¢zÔ‡z»C×Wîq,J·^ßDŸ(Î’è&cLsT4Ë2\F öµƒ?Ø2×ÚõÔ|r£4EüÃÕ©Gº. t* EGùkMVnw'Ô<±×Ãô 루$O®´k˜ø¹¤_vý3P/ãì.n ˜=ø©TÕŠÑ~zä¢S¿±fžžˆê¶ x¼$>ó£»'Þäöy&k Ú†Önþcn4z¡#aÜ+÷Ö$Š+½ƒ¨Aeêe[ºŸ¸FaÓ³’^²ÉâÀ‚dŽ"¾ÑQxáò¹¼y(ŒÈ @ð* ¼ÓöÏOÊàfUG¯ì+Æ—•Ë·¶¨l°¶ã\b®‘eG˜ðâÈÔa’>š|"˜å#šÎÀ§øº;¸Opk†ÿÞò-K ÷»³^1þÙÁ¯(>ÄÜÃ4Œ‹Hä{£68ùÖ|§ztèÖªñÕ­ª}+DÑÊ^œÃȨqónü…@qú{8ÊD¤-W)Cê7îêÉzãÈ@š©aYÀGF+b)S·¯Iùà¨T¤Yƒþ˜X {[øŽ‘>Í@lìT»’nòyÛHBã #j±$W´#H E’óìL ·Íísl– ó«’mO?«ýžSY5Ö3T]c ²ùw‘„y\ˆ^ê%ô"ëe ›º ŒzåZø×gwÖü‚¹}q&Hr|œ›!´—˜âzoiæF2Å–©høíÅmÛï­¥ØGu¼ˆWŠ·(?‰EÃoÄú7£W¨ûë´"ÞÎèHË’f:)²Íÿ`wzTžû~XˆÄÛRyÈ1pã 7óñ Úg5Ý^6OÆT‹¿w‹ï\–€7%IÓÿãìJšÛF’õ_Ñm.ûrl·ÛÖ³,·ŸíÇ›[‘,‘A€Æ"5õë_f(‚@e!=‡‰ž·ÝNU¡rûÖwW‰¶h3nû¥P`åÚ}QÖI¬Tñ?PùíŠÜR»¤moþ³ª«µ°4‰Ÿ$©°”€û¶Ðò™.,'aƬÄ:çÊ(–ÏbS“8çEo %Éz{s_ž­Ïµ¯å4“(ñS–…!Š7ˆzÚw¯j"Þó^Ó’,¼?S¹Q„ÃñÝÞ ¥âåYš ž×˜%2„w24/iÊ^z+68Æ-¦P¨‘`ì‡ÆÈrhì6õV['M † t‹¼ä^[ŒaLº3ãùï`Õ¸ œAK‘²tÌ´ˆ qh/¿!8€^…•­µ7PÇ–S§no~èí×ùã«-ü4?σ² 'åÃs‰ÿeWS4EKxÓ™Ïý^˜=+ÔW;5-œÂ(F¶ÚÓ¬ ê'Å`æƒ,û­šÌÐ-ïtJ2Šl`¬9ô΀-ñ¢Ðã­í÷:Ùºø8¶µ9»?öÕÞ=J·gêëý‰¥]}ÜÑl˜¿”ƒ<5º i¿›® ±4aì¥qƳ$n‹ƒ¬±µ%g¿#Y·›¯‹ø!ÙÒè{žÂÉí¶Pߤ½Ù‡ï1‰³„2òêê] ö‹ÈÇ-~.,’5&<˜…ÅÏÕàÍ ·t=ºI#h”„‘Çb® Þ½CN4W;²|†4‘¬ýØ­œ<—×XÔ)‰yÕpΪ|ô9B£‘C7ÌÚ$¾HŠ“’)õ™–ê%z¤"»¶Ëà´r{ƒÿGϧþeà}M!Ø;ò$•›½»í‘z‘N› AUZö™§E¿±€¥-|õ;Ù¼Ö[ça W[®išdðærÂÛÉ-fFxKI´tÙCA׸í ^é·Ù'ø”ÈâÜ®>xiPœ™µóõC›AùÃ# þjN1ÒXq~Èû íÕE MÔôNì ¸CHŠº©ŸÑXK}Çi’³8ÀÕN3!c…—˜w7ÿØèAê7E'BûÐ@å|’E'"ˆ#è‰yž1kZí£üLô{ùLcL¾kåPr$¥ôÛΖÃjAÑ4Ó4…›ÉÚtÃ8Î7™—±­ËMÅ„e|«i!Œï]½'E“DÕIT9;Àµµ¥¦óó €(9Aꑆ»Ghé‡u56Æëüm„Ê?zËn_¹3ç>_ïk æK|§§C_mj÷qê 5R¨íáI›‰·ZSÒ-ˆ…—¡©PJ–^a ÎJ`â€ëT¦ßKâ ˆxh°²Eéùi®ºlêB2…N¾+y*Ð7H;íFœa J•YîGYž±Ðí+8*å³iÖ2oP¬—×v ,àdQq™)PR©œ; ãNÇÆèäÄÂdâš¶®Bóämõ[K¨÷5íïg‘ÔŠ¬·7?ÈÖÀe^Ñw2ÄqÀF7Š…Fø+(´çuO5°¯tˆ›85°ïôqC¬™~K?)O}5ö °Ëì•ô®èDNª• g•c"+\·ð~d “,ÏyNxp{íÕI´Fº2t7¢âïeU‘5Úížž•®ì¦š¨¨—³ÆŠ>,6+ËDs榣öu'_™ðçŠ=:Õ¨<" Ûùû ­ª‹i‡?'yœç x P t cÄùŒ•p£=ßÛ:‹xÛð-N€5Š/diÃÌ󓀓 îì+Ïœìƒð»Åƒ§ÑomõèThݤšäü9ÞZ‚L²$çÙ¶û[3ÕëRÆ!åíÀ+Ùà :µ–º[)Ï‹ì,A¡}?Î3Ïã´Àƒc¯»*EµÞ\ö¢®<æ}EºwcYL}’Õ~ZE_5N¸)]”Šs/ üŒ% ÿ(Ož™V ŠE»Ç}•)ÍVXäËîçïùi_ûÝ“‡ã°~û±ƒ_¶* '^‚#E–•1ü¹Elž~—XuŠ$f]Ô/ЃQ!ÿÆã‰©BM9FFصŽ`’EiÆrÁ€.šˆ›³<îjè~™ÛÅo}G–8Ú‘Do. ¥@à#‘¥æµ/š}d¦°CÉ‚P™Rßv7ì¤EXo²WáÊbÃY¹ôÓ,Ë–̉X­N©ù2ÊN‹^~h;› ÒB6Ôp…Aô‘~X’0„vÐcyY6¸®²´4ÇÙû‡’R‹Äa¶è³…dð/Ö´¢Ø‚v':[æKº ù3yÕÖ­|לhW¹ TtTLeÖ!̯3»—ø¾Ç*½¡>) ”Éu‹¡Ÿ‚dž‰aWâÑTtf1ˆ1˜m[ÞÞ|ìË­Æœh!»…xi>‰òœ5ëFÅTY7(+«"&ÅùÔZhÝ ¬NõH’}‘JBbØŸ¾9 Ì…'8¢ªS§íŸmß‘s`m¦àñrà°‹!ûE«ë})‹Êùþ¶Õ²Tl)3kÜÊé_è26”+á¾ñhx‹B»øÀ,6²šc£ ¹Spﳑ¾¸¶”ï!#b­/d ·EârsvSÀÔÀûV¿Ðzå3%ÒqëB Ï*t‰!4Œ¸žlKû~„ÈbæD£·ìzÏúãDTg^;£j黎–ÅÚ²^‹‚ ‰à¾rR?œNÑ"Ñ´“-Q£C{Ó1ýŸ¡u'ïì²–Û¡²Ï9‚4RÀ"F Ø.Ð! žå|Äk2º/P½·“ÁÁ(<äŽU˱" š\Ö¦éW…tw'Ñ™óànkÐâàmi¨þ7e©@j|#g€ÑáÅÐé† KùãµP»÷E®H—Žm+¯ô­€ ÕPllüí{Óæüê <-‹_Bö‹Ò„%»÷|Ô3IóìPBN¯2Íx}aYÐÀË¿*¤+GÎ[m +ÑcQÙšß•r©Iðü<šÅ…?®’n3Ûv_.åï¸Mþ½––µŠ]˜S÷ÖQˆÝ—°M»ÁÍž¸ŠÒZ[ jLúM¼^ó=­Ýˆ"Ö< XËv¨ýD)¥û2S2/W¸k5Hšù±Á¤#§ðæg gqͤyžx9‹g~›“R·ÀÌc>Kmmdz)²Ê®(2%ùáé›bhÆhÿÂ3CUælù¥|ªQ¸jßbcËÄòþ{¦¯;hÎ$ê®`LÚ+eYÈ"Ë/Mxòx«r" y™>œißî¶)™7ôƒ°Ì¿)~¤Bý, >D^”FPtrŽð×afqÙ€µÂ]Ÿ‰û¬ð~U—‚|b”´ÜÐ),¨Åðåy,ô|]n…{˜¾Ö#!9|` á²ýS¬>½?{l-ÉoOkYÞÞ .ÍnØ™~Ëõ<:”‘ã<2¨¾÷ZHD–BĹUÞQ®¶ÅaÅüMT“³ ¥kŸœiÓ%Ÿuöï}µŒ`¼Â»Uº]#ÑÞ\Ûˆ~)à¡dïì0îÓ9Ã]k@6CyÎY:MØf/‹“ÀO9GyÜÍwéã8q Âäá?àÏͲþ^R»x'7•hnoQv0^1~O¢ áן%š¢¿Ì{6·ú%…àNñztv®-ÛûRõœCno´ù•®^§ ×€FQ8éäGß8ñ2sW©ÇpÊFžg P÷¸Û;…D&_[ÝdÙ±pe=&eíl.ã>–f7ˆ®oð4WW“X+LÒeê_8°¶´È¼³¨žEAæñ:Éݳ‘sti#¯=ºíæ}ZÉæÑJŒuíæ™ïñ¨k;¤ü*5Z#tº¹eÝóH‡…°X¬~ª§Rãs;·ÍÎÜÎs¢gyâ³¼:Ï ?ed-+ƒ\i}Æ<×µûšö·ø±›jWÎ!Š#söyj,ëV/‚šó\r¡b+*Íœ 4ÙáŸÍÛuÍl5Ö4Ó¬ö<–L†§é$oֲР„¸K¼1´Æqι·[‹åSÛAÃÁ:Ê÷²|´qÔMâ%S]Ïýô_ËX)q½;UòÕòÅîSÝl¸õ8.³,NAjŠ£ú,¬qŠ¡a¼—r6‹Ø‘Å~æóU¨„æb§0s¤ºÌÊßh²îAl7(qÍ{z H¤…èmþòcØù0+ÿ&e«ŸA‹Å鮚z½?¹»ZRc*¥8èë1[ͺ֑ôbò»†´Ñi©“ÅUUË8UªV(u!¹R{õ¢ˆ´ÒØaßÖ•Åxu@6ئ(°X²ÁŽt¦£:‘ ƒ—5ÍXfePgak”›¿ÍúØÔ­X3ŸÕoÅÝ\©8ï&ºšãü¡)ëv« ?‚w4a­«Žë¦‡—ލ2ï¬.5+Î̦ؾ°!‹ ‹ôнè»Wxx¬« “$dÕÝ¢¹Y:ø—.J™:Xðà ©ß‹É4Q¿TŽÑ‘æ:¨ÎÍcIëŠF¬K›%wê=4¹bÍK/«eþ¤šdÜÞü¥XæœðÆqƼ·ofs”Ã5;¿¤{µø’dÙ6¸ÎÕ’'îÐþ¼µ8Žòܶ.åF{q±ZÕLŽÂƒÜZ€Ä3öoŠ|Å¡X*VÊkþ|—Y©j3Ö2ÊYqýÔ y ª—7'y;E;ÈâŠMN\P€ÀÜ=˜´#ñ¹žé0þU¬h§Ø÷³ y4îq6ñ÷¿ {ÔC¶E",dâ(caT@´VÂ^OÝ#ª»ó†1ðÈð¾®':Wƒ¶Wau5qãí,$;®DÝC=ÍG—ÉÄ MÇÆ‡‘g÷Gµï« ½_Rn+ÎÛÑRŠ…Q‡9+»Ùôœw¼¡LÌéîìÑA¶|ZEŽºœ—­™}ô„ò.X¨Ze„Hâª'ºÚ­¬yJyÞÅ?DדßûEóJÝbW9Ð<6”~€j:qÂÒˆß`éOoìß$‘Ü•êÜy«l¹îèè½\ïI¢ÅYóIÃéáM‰s…_k?Wa•µlb^×? Þ¦°hì, Ͼ·7oÖkêÒþ¯ÆÐqg)|˜q¾#m"2[RïêV¤_1Á5 "OÅj¢…ަ¼ƒ2›½”N³þÇÛa×bçÒxi¸±]·••‹ízÌ0yPmAÞXÌDtÚ&fÁ‘ËËÜ—äÿÑ4c`'4;à­@¸KäþÁ¥UÕ¥£M,—ЋÓ$e­’„í£{R²¾î¨äÁÙеŒN€ïûwý¯ž*_þ’ãôÛË|?ÌY„ú²®6u噹Ùkkã:Bk_ðƒ*)[X½<åäã\ÐЖ'„—Å,á(Ç ÿrŸ‹µ¬:s‚/ÚFÈÒÝ©ÜËÓ'Û-ZqÙŠë‰T‡¾ÒƒÝ¯s‡IÁæ%YÈ :=6EGA¡ øè«ú…Ç„²‚ù?L°Æm„°9wszÖt×+#°7ÄS^ÕlÅÜJÀØÝ‹g& ÿ¡†0IÛÙO„ Sbœ1à Ó2?ëÚDJ®=£¼ÓïÈtß‹¢³€fzöÔÆÈž#´õåÌú§¹jí%M´Z¬–Ø÷- @Í$>ˆÓíØhcØ®´ëÚòôD~ŽÂyœÜÑš]ê®×eÝ)åYÄj*7½fyGëÐoÁíÍà 0(æ7S“õë,‰Òd^Â&ï:Ü3ˆ’°à€Š ® ÛÕ¼¾÷“z éõK±¯KÑSßÕ/òöæ«J\¯°åúqæ{1§€SÄÉÆ˜B‰6ùÈd>ÿ(2Ì&´Õ•Ö%ê T°FZ™ŠG;Þ}L Ї~âg¼ñÚ£²Ï&F† ‚8«˜«_Ù¬møÃÖC~n8¶X¶ùõákË2@v#k(¼ehÖ¬^ÌÞfÚÆ FÜ™eÇòòÓ¢šB˜@ëä'®#&¡2v7’XÀŸŽ¾Á:·~2½£RÖ0ð×p~¨U}#s?Îó”5=íQl××?{í›Àëå…mÌôSl‰¨Æ†ÅïõbA¡ÁÑ%¡çs6b( #óu|)*è ø—Ý'qbÒ?‰ç‚ÎoKÑ?•ž£¢¶/.ðSå •Z½Íá&—׿>©L:È{Yèçó•‚WYžÖy–!H’SRoÄ¡…/®$Zy¤©Áã—¦¼6¾.åÁ’¿­vÄ £¶Ô0S‡,Yÿù`®ò³/Ì¡½¢ä "ñ ¶[‹>Ä 8V¾ØHÇ(r|Ý@g¥,ͧQ¶;ZÙõԞ풲ϞLLe–›Aß·mQ{6ðÆzæ²l˜å(°Í*MÞ¼h™Màì_g8«R%ßUD+òéÐÕÚo'òyÓ(dmÿ,ä¤3¦E*U/æ<ÞF@ÿÞÉ~Ú˜Ž,Èm±½'PIB÷Xzèb‡,Gœ´KsÃs€¸Ë~Ïà þhpÞDw:ÍTSñš1Hû.¤‚ ‚oχdÀˆïÌËÝB'Ýò×YnŽ á±È"˜ì@Ƙ‚3Í|y=æÅú¾±^Î#ŠÊ•26ãʶV LBÒ]Ýšz5ã]——P8£‘Ý* Y,«'ÐÀ@B_ ¾TÎ`.úR`îˆù€Áv Ò0IcVû=Ìã¹ó‰=¢/5ov‚¢ä yvo!‚;ï8oo.Pì’]V…i’°L–6.¼p_vÀÚêoÆZä€×‰—bSè…ßgÑì-Ùrw°+”…aÅ)ϵNßÜbM CžÛ7·Rž± yew3 ðøE­~«6s’û~–Äœa/º]e†»ÂŸ–ù”ZâŽãÙliËäAi“Êå€Äzçw×S°4ÌŸßc7kG‚ÓpXÝÿsv%ÍmYø¯è–‹ˆÂ¾½ÄÖXö8±=qMnM°EB ÄP¿~ÞëI,ýš/sH•®X-t¿õ[6gÛE¦&ú‹…jdðƒj1S¶çœr¥­!Ø ~íP꙲jaªü~-å<Ÿm%Ý+ÈBiv¨ÑW­Ïl€¥]ã Ͳ(ð91g¤’@Jl!5×ó¦[wŠ'HÓ°àjÚ7[4¿69qOÒøYR¥¢ç†gð,N¯ÕûC7 äÒ]£û‰“½‡;´@¡ci» p?/K8cöZF8Iæ¢l÷òû'año½e–õSéwí°îìÅÄmñª—Ð眞üÈNmÆ> JêÈAôqÌM˜Ø(re }³Æž3ÌÆ#‰4òÜ”ÅëjjFHQõj«¼ytcYîe,ŸñæøýNàóqNµDA†òTùfÐÿi‹6UÜ)»&aE°>œi“÷wŸåº49g®Rã°$èë—ðwôK£ ´‡l.ñ›²´M“,'E +¡.[]RœñÆK “`o±œ‘(m¤Æ1æ)L#«˜·8yWwÍ¡¢§º½ðqØG”‘ºÁ½u¡ Y3—½èJg#NÒ 'ÀsCKæEÌAg Å,­½aS¡þ£®¾uPéV·‹üjIà¥,õ-­÷žšÓ{qQqâÙïi Vê|&ß©m#ÁûYDQÀbÁõ”öü,{a<år/œ¬•ÞCü l¹o3D×Ûñû»¡ýµÞÏ «4<¤ÿ8‹X ‚:?ˆ—Bk±Ué0uY‡ý.^l\ñKÙI·‡È,Þ"†>Z…~à³à=‡ú„‚q$vÏè-œu}b{¸^>-Ê=³_ ~áøÂŽq ã S#K̹UÂæa(B¯&ý\Én£HÓÈPéÃ8´=÷¯æÊÒJb à€Q–²²¿,eU7™‡pô0äÍ)nTÝï”ì9.TŠw‹³ž¥5ÌÒ ö}&ëüea@dÂÓ}ÕE+[Ã4×ðÊüa3u÷+t©+ŽSVèú1´À.'+BӔǬkEé,•&&Sï®ÝXšßwf8dë¥ÿ¬|[$| ˜1g¡´TÜ)sÔT`v§”%ÏŠïSÝÊ=‰ù|@{ª`Ókíû»‡nÕöLéÏunoŸ ;¸a¢J?«–˜Õ¨”i»(²¥DÈ7]€\PŒe1_àO nÄCF¬Åô¶–%\qçTCØÚš%nÎBøêårå ¡É%o§Ý±UÙ¡÷RiÙFø^”¦K]\tíAV„ÙYßö‹ ò¯y*O­e¡Ì&Èæ 1ÉS'aBTuN7cî—–â„r(;\8›¿ç®G´9h¦Ìs›ª-Îæ^*•OJYìAñ,µ8L¡H –6ÊÍ¢0fÆWòEVN; ÓCW­]Qù+ü¼¯iÙæ÷ÂRÍ\è&‹‡‰Ë9Ÿ‡à}.çÑëÚdh6] #Ëš¯¿¼ÓËFêlý*òþMõ¥5õ“1|”Ùb½P-l»žîùøs-xÅ€Z¤ïi7Â~$¼˜ý• qž,‡­À~ÆÙM»“!Ü¥’9³ß¼ØóCwÎÔùlMŸÕσÈÖµÈ5ÌbfŸ;iø½ÐËxª =üº ¥|ó$e¥Öúù–¹ÔîÅ©³Þ›«$§}8°>¥=ï§î{SÅæ8Œ–”ã¥pq0Ïn–M½dúFÿ‡“¥ø&-JÜÔ”%êÃÈM¯idU4‚rþsYNÏènI‚V¤þ{©­A˜ ¸¨ÜGòƒ êºÇF<çÅÖ¾uƒ ˆyì%ºÆ8õ‹ù¢B†Æ±&oèfƒ™™ÌÓTŸ}Óý4€ç¸K©>ß5ž ]FPƒ±éÝ;y-Æædá þè÷ÔÅÔ ø—ìÒcéÏX~úÈ‘†‰qb욦y¼‘ë‚ÐP}ÀÙí# ‹ZºÖ¿¿; ái™¦¥t-­£ëFÐfñ\¸A™S¢T@&KRâ7%ïlï¹Hó;þºæéÕxtí¿ç±(å§cA`/‹¨¼®r¹Ï‹š©?—Ÿëƨ¼KT‘ã·˜‹ÁiœArdí¢PàŽ¸¤½¥‘vÐfÊ 4ôÊû­ Ù½%CÅ"óÃ8ô]– Bƒ|#Gî&ZשM®áuÜ9ÿ¡°(Qõü­Ûâf“1F¿¤2ŠYxàÕ|Ý|9ªDæ\05Vsªú$hM8(ͨ^÷R‹ëŠØR¬z<áy‡V†jê`z@SnZYIÃNöuCBz«Æ ii⇬”¨Êf^WWØïR3XçzS.ébÔ†ßþú 4ø‹G Yµ„L7ÉÜŒ…-¹ôï *ÂKZÏÝ„öm<0É<Ê$ŽlždÛÒ*2½Êˆ}åQ˜òT´ŸÅi%œÕ/bW7H©()o¬ÿoI¿µ/Ðu>o-€Ë¥Ä±ÿâçLl‚#õâ4㩡éZ'ŸcÍááp’z‡ÊÓ´•”³%1ôèØ…Qv\ŠF ùqÊ•íf¦u &í¦„>P™NS(¹BO܉Œz{ JÚ#³¦'ÏÆÇãŠ,†teœ‘ÅZ¢nbUÀ«ˆÅÓ³}Ò¿aVRø­°°ru‘Iœô œ]Ø¡©›ÅHdœp_Ok kp‘P#%ÿ¶;A+Ƚϋ³Íýòs¯àli1ŠÕañ¶žNØÆÃˆ„<´è¡×¨&† -qáL•¶¬¥«Øo,Ÿ_§Ç=I¤Ü ÉÐâû (?Õ4ò¢Ì9-ÆN¹“z„Ä›¡…ÖÜdÝj UjT5$Dµ CËÂËÜ,Y`&)PæÜ!÷FE^7»‚9ŠùMÔ´)Æ7Œ”ä,FSëí$‰8Îâ8aáÏKHRD›@o‹6¬ÏöÓ¦øcš Éfû(‘@¸lEo §,$,­b’¸>(qMýÄ*W›£Ê?ÙJ“§]WÑ®V¦ÿÌ8ªtåáÕÚÓ#R; SÊ®¹‰-ù%߉æp„½¡ù:ê b_¾o„ú“ÆÌ•Ç»éÄË¢€å«·ÃËY÷àsDÅQo“ûk‰&SÔÿc £XG‘Æ^ì‡,7 â³Ì7b*x}ÅO–µ²ŠyCvÛ\ôk¯åm'ƒ¦®—¥ ‹zv„È‘«#… =>AEÁ4ô*è-®•&yÆ0/n`²|([ NcMo”ýN/¡l.¸Ë—Bì[¬Õ‹hv5-â4޳… ôbb½˜4vÆÕ6Vh!Ëd^“u ›ûÄÈ ‡ýßÛ’Æ|3€÷Èf%Ç.ˆ·ahjËD<«ùý ‹¯ƒf2‘„‡‚عs£U%áyÞ’EMc /,tOm1#ÆM}QÉ”'xþ©kt|Ë'êŒÙf„O/I¡ eÝöj–Å‘Qj¾£‚Ç,×:ÚÀ¼ù3ŒÜ”ˆ½Êþ,"¨ïºA”òèLÕqñ"0/œN8øâUÞjï˜[;×’6µî1Dç8Ù9¥žÏë|ë• ?Íp(íˆÞãM3öŒ¾æUÍ–*Áe±’•Zu€…vv4úI¦¬4"ÕÿÔ©(òÝÕ ÒiÇ:ôc¯-AÏ«,å9\ܦ–Êuö¡¨úü³«ZÛ†æ8â¢òPÇ Þ˜³6ª(” €»À«Ó?ŠõÿE‹9“ºUni¶g­¹éÔp¢¥àBq±š®\¯6•×¥g™7¢X3}Þ¾6¶nr'Ö$Õ TD‚Ët3µDäM–ⶆA·¢gEìâ!ôjI;. ?$éA‹xR{ÀÇò˜þ Wµiã‰ö-òl¸¢yÍÄ`gÌ9ä’)Ú›ô|m‹ÊX¡ÂAMÂ’Ï+ÅTacÐ]ˆ¸À÷wUA#Ñ ^¹#¡„ÃÍ=j%qìz,¸!z°DæX*t £òXÁk{†eØ&·ÔÙd{¸¿ûÖ³lzÎKmcøAÅqp.ç.ƒSŠ¢%\1Ï nRhsâUä¿wE•ÓZðÁºØ®§(òÈÂíÑë$6k\hg·ó¬¤xyûEˆ…Gr O2ì­V•h4©Î&=/6ö}„MGq¶6ù~ÆÁ$þŽkáÝY؃F`Uò5ÐCUÎZѬĶ>‡¤öl»,kèuÚšW˜UAsпïq8b©hÐ;ã†Ñ5ôa’EL¿‚üN]óM]¾vð ™5xCccßZ,“{cöû»!³çÒ}X$ðܘeÓ­!äd§þe‹¶ÌÆ“n ÊÃWC^'S¥¬¢M\­F„_w©À‰ô c×Ïxì{¨¸¤³›E0YUb d»›ÿÅÞŠfNèÛN½@è÷oˆ§C]ù,ý¼­r?ê}kg’é¿WÈÔpžÒONöîïÔèF]φî¤áGY˜°ú¦}”V ¨ÌcþÝ îSÀã‡ük] àùœÏ©,òk•]ç8qS·¢œØrÔ`ó Þ䲨€ˆ&dêEŒìœ#N§¤ïï´~µN÷¢zš‚9Æ"Pm{¼ö·Ã̳/ [›‹òL«ã;oLliÌÅ⮽ ?° ±¼Ç ƒ0ÊÖôX0§ÅæÒüA‹§'øœ]^öË&Vø™¶Æ´õKZ]ç§°}?¸©è±ÁÂ0Êë3³¢¹ÖßugÛj?ëªÚiØïf^ÆM¹¢ºé”åG^âAMÊ™-ªb³Å9D3s-ó×ÉšLi’R’mÅOœÛ'ûÑ¿ú[M“›†¨ðÀY«!aÕ7×/ç‘¿sTCÞžtSÓ ÐŠþ$¶¨¢è†7Jây¯Ðô3§Ç©kåÒá«Üà>‚GcB  mÕè8ë]->ÖÐri‰œÐ-ùk¯¦ôE4„&TsÖ×馃’ã’éè†2¯{G;45Öš‚g/îltÌ‹™@«Èyˆ9ÖLUë´ÛS)ÌcQ>ù.o¥Ö›°åöê± Ã˜ŒÔ좀 Y¦bè*Ö“_þ€cqhŠ•ÓŽÖhVYA/Bo#…~ë-díÙ ÒÀMYò¿ÊÄÕ5ƒ¼–ÍêÁúh?Å ­6.h-±ËíMoêÆè®Ì ™OBºf©JÈO./ÿý[Ö4ÎòQë¸P/rÔQ%ÇI3 Çó$X¶8áSûwb¢­:}át{®&×\=’ó®ÃA¨5LY³‹ç„‘’kä„M(ž&²)tå:tÒ+wÞ<“rxq¥@5%ò˜ÓjJs!uß–øiì%)gFÚj— !< B‹ƒ–b¼éiE‹;õ 4*ùiíû3ÇPÝZÃTuâ€Ry g<³¹£‡¦„R^]Hg_wCa\»r¬eœaª§gÂÍj÷}¦’(Ôšå q”y<íß-4~(Ê}"öÈ ÉKø¬‚æSW–}¶ö6'Îù .óâF ]oè¹~Æ9ÛFù^8+YP¬C¼®MÁ…ä}ÉqÄE«J‹ŠêEçwñ0µ›¤ ¸£±›q^ã_ˉŒÝ°iŸ4Û'û\ÓÔŸ³œu(5[ÔÀîÝ®72\f*¸ “»ÙLAeë›ÊЉ·èý,ë}]Ò'%å1Îë‰Åoõ±´#ºßS/vYnàj7â`“DŒ¾Êr'^ÎÿÓD“â/›z4”0êÅ~F'ã7ò䛳êÌ<ó>høþŸWÖ«‡/ š'ãøDAè³tJµåwJq¤Æ½/ë÷\8OE»anä‘Ó’Ó"sXÖÞ+7H¦@U4ð‰þxXbgoà$P×Ê §¤Øi­Ò@—.v÷ ÚÖ¢!^Ð]ûR+ ¯G0}#8‘7Ÿ\SßËÂ,fáäl‡p-Ù4Zˆ©æXƒ‰úŽx%e†.ð4hÔMžÛë¡5‹¨\ñõEw`îyÿ¦•ó K7€ç ‰ñÒËéìâyÐ-¡‚'¿­€°™»¦Ýu„†C1Ýö´ØFv’3ñ£>- b¤Súkd¬Ó“œÉn †ÐIµÎsÇÖ0~DÚ%1yZ6/ Û£}Ë—zfM9Áq쳨¾ëî ¹Rb"¾Ê>Ã¥o¥Ô‰íVp+j…šimúÆQ‘µKƒ2‚À¯å'(@3v4ÝN£`3hšHšÁ´â*“8s]Ÿe…‚ µÍmI9K ôó¨n‰Æ¾Í‰)ø+Ú\”dÀyDKgûìpñAll] »^š±˜öµZÀ˜ï¤ÞŽòUÄéöO9ÕP噬Pöf¡åGé/çÐÅ'ó­ê|ë,ŽßœýºbU§<½²ÏÝ<àóXO—Ñ׆”˜[É I ˜°¸»ËÐÌÊÆŠâֿ产áuí6KÉwœæˆ))oñöÂV´ÜÈ0Ü8䤆²g²;¨Køõ d’£ãmswSUâÑh¢Ù¯+sÉQ}FM…ÇQ&ŠÂ,ãé­âÒ!4·UpÕç\E@xnyº‘\Òc ˆc_A‹S¨õ$= •mIJ(l è"b³›Í¾‘+ãÇ`»âQ|ßaØ¥Î÷q Û†Pm+·x«]¬,ß03t aœ-—9îÔv¦€2W¬á™Ä¼=ö[5Ô$o¬[ðuÛUòE,~ŸïI&o2È<7b­°óºÄÝTdÞ_oåI¹L3õ~Ô;Aï:¯ºUÔÄB‰æB{¨–žZÍó¶TºÔ§¬¡Ú²©I~™÷ØÛº‘'g£´Þ™ ÆR’%a8úX+Ü _ž§£7¿lž³<7*íèìgÑZ ÊÉÙ²§ˆošú¼m ÈŒ©@g÷w¥,x²BiìB e1€r¥…h>c´r Î@B¶0ûˆÑ™æÛè*ª)Æâb&â:É ÚÞ°Z: |æ­r–[ôæ„–´…ðYWòYW¿N)Ãw»AohÞ6» )?,çÒ3Žû»‹Ò‰«Šâd©[¡&w}žbœÞÑÕ\½J%-ø¿Ö®¥¹m# ß÷Wè– ‰ÂÄÑ–¹")›’·œÚTíaHŒˆñЂ ´Ô¯ßî@"ÁéA{k“ªø—5Æ<º¿þ^q[oЇLaÇ.:² prhM†ŒÛ{= Ð6)`íS]ÇÙÑSÕ·£+-ÏfOS“÷§k"ŠÑ*©-Åðü4&A²ŠY¤à­1o&üƒÇt[y(Z&KáFU. O›+Ç„j9çÍÏà*ÏY±„HŒÜ‹”ðØûÁ­Òà¢R=íŽ<’ˆµÝbtëÎ?Ma{2pzí çÑ›T”H×åÉД¨[:Ôõ‹Z;lI?6õz”+“.—`Å’,ë¼,LT†ªÌ~·Œ&‚çVnn³ë‰°µgš^.ï.âN.DHÀà<rSqÔÀ¢;ìû£wÆÉwRHåã#}k~¿¼¥'fË_'¦|²t„yÈâÎÈ粪Îìm!öTÍO¼ì·r’Èw®4k'kÏqTáÎ"ôW <|,WY:«v#ºJJf?ø]ÉnI’Ä’îávå Z)N2–°uðP…™ÀC÷:èÑ32mfÖ"ZdÍ" Ç@ⵑËq ÏX”¢Ø…íִбT"µ;ʬ±8ƒûƒ¿¯[dƒÑ•´¦ú™WÎ{“Û/—®b^LE«çñÅÔ]â£ÿ)q˜ÄKçCÿ˜žÖEêy;õ¬š79ÃTN£ÌY®ÍZˆ<±]<ÁC_›1^‹‡ôJWVù-T*´òP§ Þ´î‘ oôUÒm©RDY†¼-¤ ,˜f/N,·ó8 X̬ZlŽÞv;Y\>Ÿêc?UaûGoÌ®V.G#l‘Wí«8Z—­óñmžEp>¸j£¿Š°¿åÿYc§ |¯X‹ýÜ©ÞáêïÖ—8lq¥ß?swS‹Kõ$b‰ZöâU]¾ì_T¢<4@!MúCùQOå«ÔsµÍœ´Ü÷ÑA†•¶m.½·–¼ÁgiÌúÐg‹FÛÞSk¼ŸvÞgqFH]^„˱¾¬YœÞ§WÕT‚Q ¿Jé½ x³$¹+I¢Ú×i üÙ§Ûïg8èA Ç5÷쮽:aIo§˜Ëu{è\GÐf'r2a1ssݨ3ò°5fÝÙß…·rÍK¼3#jqwdžýÝI|¢–ƒ¿¸zÈáUŒYóÜnl«<9Õ¸(U×&kq9ؼ—æ§\--#?Ë9ýóÂ${Ò1š5²*ìC]£Ú¢]7Ö…Šm#÷ïòtg|×W5±VP±¸ú4òS†ô©›êè£ökÈóßìM7?{û^C}ò(Úr-7šhas·ÿXî?á³÷¨0ÉL«ø0Êâ$\å,˜^Tm“Ûixÿ©Œšç ªQЂÛIþÑòô,Ö-ÍàйR™òû˜Õc¥æu:)ÓîI-1JŽÞ‰fÐ=,`Ì B5ÀPÔ›C²X8·_IóÚGΓ2„Ùzb](BûC&–§M2ybŸ)V}öa‡Ø0 |’õ³¬WºyjØÊÄ9– -dîGœr]TJdv×’Z³'O„®“z#è@ŽÏm¿wLîµ+àòæPmg„PìdiÈ¢•¬µ £§pBM„S"‘/ª¾d]»×%ͼ¸D­O±¶¶›¢Å¾6`a‡rgíïHStí$½a€È~•ÃãØKƺhàŠ½×Tã…tiuŽN%P ð¬c+4Ú‚.7´@'\oïY )h‡÷èïKµ”觇O(V˃øN«ÕBFÈ fÇãF (0ÎsžÑа–úÅÕ<ßÑ·/cä Vh;dMyìgyÀ²²4Êh«^Ù˽µlNØ—Î+UÑùƃ‹Õ'#=6¬ö¸2ól§é%ú9ü›f¬àØJæv°÷24vÞÀ¦ÏÒ”(Û÷´Öëºãâê¶ ŸÛöELü¥'øÜj…6VP”Ìmïí*êr…ZäUÏ”žóÞ¶M ÏmHúM Uç:.è'ƒ4[q ؆ÍÔP`;ÉZ”Å„ú¬J¿Äf.¼+oå~ïÒ‹Dq†qÈÚ™k­óBG( :Q=—1Ïãø^<Ñ•êìÊ–Œ0 ÇûVš×b`%:Ð?ÊÓˆå‰ÿ$º¶Èc;È*Æ<"ž"†6°üÖÖ²Q$â¯{†¨)ðÓ•ÏóU݈½‚–ÏÛI¹¦@œÇNIè§=(çxC W·Ü’8À¯æY¾+ì]Ô*N|ž•€èØ1Þnªp8!<ãÔ,æ©B?a(’ãóMGøg,„[þ&*st—ÉáRá¢ÿîlI,§‡Å¶“<™È½s4:ZP ìÚW$âÝj2•£ÒŽÒ]e8§–†ÏzUÔ.‡®x¶•Ðà8ø1?H°ÿ¶2ñè§0ÎÚb¦ iÂÓ¤l2;K´ÐÚ>Ø¡UÅ Imæéú‡'ÏÞ×.ï¼Þ$L²(eeÚ´@zƒ­°Ãn/¢’MMn0ÏžÜÒ­¼½ƒý_"ïb(8ÑŸç=Š:㢃Vö"KðCƒ CïÒ)Èy' þ„€'i¡ÈXc<Ùâê‹Âøœ¡`Ç“˜Fðb°ÜXLLjÓ·jÓÂ9üiß™k‡úÎöߢ4ø7?c~µš³ÆßÚ!Þ{©à/Þ};ìÖ5rßk~s»c†uò•ZÞŸGšN9ÐÚܫ˲ÇQ¬i¸v÷0¯Þ^ª½ëba“1Ì_‹ã$ä✠~¨×Ó÷)ù¤¬æ‘²0x›¦Êì¨ð«B‰ú­>‰ÍŽË½÷ФÖx)ý<5óh1sw9^@ôgôÓ0ö}–kW[m…÷zÙk oÆ| ÞÕz€]ÿH–m†eB­Ïhq—3ûïÕ6*cu/hˆk<5¬‹SúŒ2ã;Þtw€ËãU‘ž¸™šK‹£õ¹8$â€Çi¿‚MøFe«âQ·LÂñjxm™ÉD-y/²"¿oádgçð8Ÿ š¤ÑÊ_Å,ó1øaPM†_„07\’~ÏÔתáµJwèì:‚ N›ÉKY\Ý©Æ8 ŒQ1®¶/˜Ql-y3—J˜'&QjfÛ~“[Çdb´Ÿù²Y’×eñ÷¶º¢Ží÷(?Ó¤—±„JF½ÓˆuyÞb¾]£Á&©ãœsùÝn?<½\ò QÆÒ¶ãHÙ»`}œâ…¨ò6•`Nv t´y£5$ÄcS:ÉX͹­Óã`u7‹%sèÖ¢ íÈS×¶k¯€Æ§eÞ ÖŽm>ÙN\"fS%CÎ Mn‚‘’œ ªú ¿_l·Š .nuØ{Ïâ°‘;Ö*?A­K»‹c…¾ )ÆÍoŠò8ÎW Ëel#+ ”Q´×Bjè´õJqj7“Ë»“$‘ }G½ïÚšÓ½-Wqšf žx‚’ÚëLòÕ1uízm þ2÷›/²«iß¿/¢›ó¦ 1 sÅÊ+h÷ð·%ûäåq’ñâ„%Ž4›ðOI>{ÆIŒqÖBX‘ûœ’ó©mĞ؋eÛõ šŒG2ÿGvO? S‘Ó‰&ã¥Å"þü‰‹¡»åÙÝi¶ t¬PŠמèàÿjº›]ûÊÜBeF›Š YÄ:ßÇ„‹«Í÷’¢ŸKá(Íü$…ÿ°{Ýzõ{„ŒuÑÏëm¼í:WøáëÁÆp2tjÑ¡ûÍ“¤l䞌eü{S`À‰˜˜&}V.)s×lâ'¬l[Q×èÊ­jÕwö޾³Ò¦´ø‚uLí=:Ó™¶ouÒPIìHW'p$Â޲ÀOVqÈ"z÷¥l‹¶“DDN­L eÈÞ_˪hÜʹ9˜+ ^BÃBoŒù¨« ó,ÊX4E¬XfjX,ãe“ó>wZjrð0iÈΙ7Û*ùåß¹ugUpÕ²V·}Ö:ûå#^Tq¢!uZ 8t¿\ü§37#ÿ_ÞMò§NBp}–‹ÇF\°á ¿­¤à^<¿ÉýÔR÷ Ö@Š ©2ü48ˆ.¯[—]œÀGËcλñâ&ëכ͡ªZجÞs=tô¤Eã`úzuÑÁ>òÓúF5ƒ#p±QÅ>K¤Pž! »þ uúw8ÁΣTû=œeªzÕþ‰stÓ8ðã—mongodb-1.21.0/tests/utils/basic-skipif.inc0000644000175100001660000000143314760300421015500 0ustar getCode(), $e->getMessage(), $e->getFile(), $e->getLine())); }); register_shutdown_function(function() { $lastError = error_get_last(); if ($lastError !== null) { exit(sprintf('skip %s: %s', errno_as_string($lastError['type']), $lastError['message'])); } }); mongodb-1.21.0/tests/utils/basic.inc0000644000175100001660000000152714760300421014221 0ustar name = $name; $this->age = $age; $this->addresses = array(); $this->secret = "$name confidential info"; } public function addAddress(Address $address) { $this->addresses[] = $address; } public function addFriend(Person $friend) { $this->friends[] = $friend; } #[\ReturnTypeWillChange] public function bsonSerialize() { return array( "name" => $this->name, "age" => $this->age, "addresses" => $this->addresses, "friends" => $this->friends, ); } public function bsonUnserialize(array $data): void { $this->name = $data["name"]; $this->age = $data["age"]; $this->addresses = $data["addresses"]; $this->friends = $data["friends"]; } } class Address implements MongoDB\BSON\Persistable { protected $zip; protected $country; public function __construct($zip, $country) { $this->zip = $zip; $this->country = $country; } #[\ReturnTypeWillChange] public function bsonSerialize() { return array( "zip" => $this->zip, "country" => $this->country, ); } public function bsonUnserialize(array $data): void { $this->zip = $data["zip"]; $this->country = $data["country"]; } } mongodb-1.21.0/tests/utils/observer.php0000644000175100001660000000213014760300421014774 0ustar commands = []; \MongoDB\Driver\Monitoring\addSubscriber($this); try { call_user_func($execution); } finally { \MongoDB\Driver\Monitoring\removeSubscriber($this); foreach ($this->commands as $command) { call_user_func($commandCallback, $command); } } } public function commandStarted(CommandStartedEvent $event): void { $this->commands[] = $event->getCommand(); } public function commandSucceeded(CommandSucceededEvent $event): void { } public function commandFailed(CommandFailedEvent $event): void { } } ?> mongodb-1.21.0/tests/utils/skipif.php0000644000175100001660000003223014760300421014436 0ustar selectServer(new ReadPreference('nearest')); $mongosNodes = array_filter($manager->getServers(), function(Server $server) { return $server->getType() === Server::TYPE_MONGOS; }); if (count($mongosNodes) > 1) { exit('skip topology contains multiple mongos nodes'); } } /** * Skips the test if the topology is not a shard cluster. */ function skip_if_not_mongos() { is_mongos(URI) or exit('skip topology is not a sharded cluster'); } function skip_if_not_sharded_cluster_with_replica_set() { is_sharded_cluster_with_replica_set(URI) or exit('skip topology is not a sharded cluster with replica set'); } /** * Skips the test if the topology is a replica set. */ function skip_if_replica_set() { is_replica_set(URI) and exit('skip topology is a replica set'); } /** * Skips the test if the topology is not a replica set. */ function skip_if_not_replica_set() { is_replica_set(URI) or exit('skip topology is not a replica set'); } /** * Skips the test if the topology is not a replica set or sharded cluster backed by replica sets */ function skip_if_not_replica_set_or_sharded_cluster_with_replica_set() { is_replica_set(URI) or is_sharded_cluster_with_replica_set(URI) or exit('skip topology is not a replica set or sharded cluster with replica set'); } function skip_if_no_transactions() { if (is_sharded_cluster_with_replica_set(URI)) { skip_if_server_version('<', '4.2'); } elseif (is_replica_set(URI)) { skip_if_server_version('<', '4.0'); } else { exit('skip topology does not support transactions'); } } /** * Skips the test if the topology has no arbiter. */ function skip_if_no_arbiter() { try { $primary = get_primary_server(URI); } catch (ConnectionException $e) { exit('skip primary server is not accessible: ' . $e->getMessage()); } $info = $primary->getInfo(); if (!isset($info['arbiters']) || count($info['arbiters']) < 1) { exit('skip no arbiters available'); } } /** * Skips the test if the topology has no secondary. */ function skip_if_no_secondary() { try { $primary = get_primary_server(URI); } catch (ConnectionException $e) { exit('skip primary server is not accessible: ' . $e->getMessage()); } $info = $primary->getInfo(); if (!isset($info['hosts']) || count($info['hosts']) < 2) { exit('skip no secondaries available'); } } /** * Skips the test if the topology does not have enough data carrying nodes */ function skip_if_not_enough_data_nodes($requiredNodes, $maxNodeCount = null) { try { $primary = get_primary_server(URI); } catch (ConnectionException $e) { exit('skip primary server is not accessible: ' . $e->getMessage()); } $info = $primary->getInfo(); $dataNodeCount = isset($info['hosts']) ? count($info['hosts']) : 0; if ($dataNodeCount < $requiredNodes) { exit("skip not enough nodes available (wanted: {$requiredNodes}, available: " . count($info['hosts']) . ')'); } if ($maxNodeCount !== null && $dataNodeCount > $requiredNodes) { exit("skip too many nodes available (wanted: {$requiredNodes}, available: " . count($info['hosts']) . ')'); } } /** * Skips the test if the topology does not have enough nodes */ function skip_if_not_enough_nodes($requiredNodes, $maxNodeCount = null) { try { $primary = get_primary_server(URI); } catch (ConnectionException $e) { exit('skip primary server is not accessible: ' . $e->getMessage()); } $info = $primary->getInfo(); $nodeCount = (isset($info['hosts']) ? count($info['hosts']) : 0) + (isset($info['arbiters']) ? count($info['arbiters']) : 0); if ($nodeCount < $requiredNodes) { exit("skip not enough nodes available (wanted: {$requiredNodes}, available: " . count($info['hosts']) . ')'); } if ($maxNodeCount !== null && $nodeCount > $requiredNodes) { exit("skip too many nodes available (wanted: {$requiredNodes}, available: " . count($info['hosts']) . ')'); } } /** * Skips the test if the topology is a standalone. */ function skip_if_standalone() { is_standalone(URI) and exit('skip topology is a standalone'); } /** * Skips the test if the topology is not a standalone. */ function skip_if_not_standalone() { is_standalone(URI) or exit('skip topology is not a standalone'); } /** * Skips the test if the connection string uses SSL. */ function skip_if_ssl() { is_ssl(URI) and exit('skip URI is using SSL'); } /** * Skips the test if the connection string uses SSL. */ function skip_if_not_ssl() { is_ssl(URI) or exit('skip URI is not using SSL'); } /** * Skips the test if no SSL directory has been defined. */ function skip_if_no_ssl_dir() { $sslDir = getenv('SSL_DIR'); $sslDir !== false or exit('skip SSL_DIR environment variable not set'); $sslDir = realpath($sslDir); ($sslDir !== false && is_dir($sslDir)) or exit('skip SSL_DIR is not a valid directory'); } /** * Skips the test if the connection string is using auth. */ function skip_if_auth() { is_auth(URI) and exit('skip URI is using auth'); } /** * Skips the test if the connection string is not using auth. */ function skip_if_not_auth() { is_auth(URI) or exit('skip URI is not using auth'); } /** * Skips the test if the connection string is not using a particular * authMechanism. * * @param string $authMechanism */ function skip_if_not_auth_mechanism($authMechanism) { $uriAuthMechanism = get_uri_option(URI, 'authMechanism'); if ($uriAuthMechanism === null && $authMechanism !== null) { exit('skip URI is not using authMechanism'); } if ($uriAuthMechanism !== $authMechanism) { exit("skip URI authMechanism is '$uriAuthMechanism' (needed: '$authMechanism')"); } } /** * Skips the test if the server is not accessible. */ function skip_if_not_live() { try { get_primary_server(URI); } catch (ConnectionException $e) { exit('skip server is not accessible: ' . $e->getMessage()); } } /** * Skips the test if the server version satisfies a comparison. * * @see http://php.net/version_compare * @param string $operator Comparison operator * @param string $version Version to compare against */ function skip_if_server_version($operator, $version) { $serverVersion = get_server_version(URI); if (version_compare($serverVersion, $version, $operator)) { exit("skip Server version '$serverVersion' $operator '$version'"); } } /** * Skips the test if the PHP version satisfies a comparison. * * @see http://php.net/version_compare * @param string $operator Comparison operator * @param string $version Version to compare against */ function skip_if_php_version($operator, $version) { if (version_compare(PHP_VERSION, $version, $operator)) { exit("skip PHP version '" . PHP_VERSION . "' $operator '$version'"); } } /** * Skips the test if the server not using a particular storage engine. * * @param string $storageEngine Storage engine name */ function skip_if_not_server_storage_engine($storageEngine) { $serverStorageEngine = get_server_storage_engine(URI); if ($serverStorageEngine !== $storageEngine) { exit("skip Server storage engine is '$serverStorageEngine' (needed '$storageEngine')"); } } /** * Skips the test if the server does not support the sleep command. */ function skip_if_sleep_command_unavailable() { if (!command_works(URI, ['sleep' => 1, 'secs' => 1, 'w' => false])) { exit('skip sleep command not available'); } } /** * Skips the test if the server does not support test commands. */ function skip_if_test_commands_disabled() { if (!get_server_parameter(URI, 'enableTestCommands')) { exit('skip test commands are disabled'); } } /** * Skips the test if libmongoc does not support crypto. * * If one or more libaries are provided, additionally check that the reported * library is in that array. Possible values are "libcrypto", "Common Crypto", * and "CNG". * * @param array $libs Optional list of crypto libraries to require */ function skip_if_not_libmongoc_crypto(array $libs = []) { $lib = get_module_info('libmongoc crypto library'); if ($lib === null) { exit('skip libmongoc crypto is not enabled'); } if (!empty($libs) && !in_array($lib, $libs)) { exit('skip Needs libmongoc crypto library ' . implode(', ', $libs) . ', but found ' . $lib); } } /** * Skips the test if libmongoc does not support SSL. * * If one or more libaries are provided, additionally check that the reported * library is in that array. Possible values are "OpenSSL", "LibreSSL", * "Secure Transport", and "Secure Channel". * * @param array $libs Optional list of SSL libraries to require */ function skip_if_not_libmongoc_ssl(array $libs = []) { $lib = get_module_info('libmongoc SSL library'); if ($lib === null) { exit('skip libmongoc SSL is not enabled'); } if (!empty($libs) && !in_array($lib, $libs)) { exit('skip Needs libmongoc SSL library ' . implode(', ', $libs) . ', but found ' . $lib); } } /** * Skips the test if the driver was not compiled with support for FLE */ function skip_if_not_libmongocrypt() { $lib = get_module_info('libmongocrypt'); if ($lib === 'disabled') { exit('skip libmongocrypt is not enabled'); } } /** * Skips the test if the driver was compiled with support for FLE */ function skip_if_libmongocrypt() { $lib = get_module_info('libmongocrypt'); if ($lib !== 'disabled') { exit('skip libmongocrypt is enabled'); } } /** * Skips the test if the collection cannot be dropped. * * @param string $databaseName Database name * @param string $collectionName Collection name */ function skip_if_not_clean($databaseName = DATABASE_NAME, $collectionName = COLLECTION_NAME) { try { drop_collection(URI, $databaseName, $collectionName); } catch (RuntimeException $e) { exit("skip Could not drop '$databaseName.$collectionName': " . $e->getMessage()); } /* Since this function modifies the state of the database, we need it to run * each time before a test. */ disable_skipif_caching(); } function skip_if_no_getmore_failpoint() { $serverVersion = get_server_version(URI); if (version_compare($serverVersion, '4.0', '<')) { exit("skip Server version '$serverVersion' does not support a getMore failpoint'"); } } function skip_if_no_failcommand_failpoint() { skip_if_test_commands_disabled(); $serverVersion = get_server_version(URI); if (is_mongos(URI) && version_compare($serverVersion, '4.1.8', '<')) { exit("skip mongos version '$serverVersion' does not support 'failCommand' failpoint'"); } elseif (version_compare($serverVersion, '4.0', '<')) { exit("skip mongod version '$serverVersion' does not support 'failCommand' failpoint'"); } } function skip_if_no_mongo_orchestration() { $ctx = stream_context_create(['http' => ['timeout' => 0.5]]); $result = @file_get_contents(MONGO_ORCHESTRATION_URI, false, $ctx); /* Note: file_get_contents emits an E_WARNING on failure, which will be * caught by the error handler in basic-skipif.inc. In that case, this may * never be reached. */ if ($result === false) { exit("skip mongo-orchestration is not accessible: '" . MONGO_ORCHESTRATION_URI . "'"); } } function skip_if_crypt_shared() { // Intentionally ignore empty values for CRYPT_SHARED_LIB_PATH if (getenv('CRYPT_SHARED_LIB_PATH')) { exit('skip crypt_shared is available'); } } function skip_if_no_crypt_shared() { // Intentionally consider empty values for CRYPT_SHARED_LIB_PATH if ( ! getenv('CRYPT_SHARED_LIB_PATH')) { exit('skip crypt_shared is not available'); } } mongodb-1.21.0/tests/utils/tools.php0000644000175100001660000005775714760300421014336 0ustar $collectionName]); try { /* Unless we are dropping a collection within the "local" database, * which does not support a write concern, we need to use w:majority due * to the issue explained in SERVER-35613: "drop" uses a two phase * commit, and due to that, it is possible that a lock can't be acquired * for a transaction that gets quickly started as the "drop" reaper * hasn't completed yet. */ $wc = $databaseName === 'local' ? new WriteConcern(1) : new WriteConcern(WriteConcern::MAJORITY); $server->executeCommand( $databaseName, $command, ['writeConcern' => $wc] ); } catch (RuntimeException $e) { if ($e->getMessage() !== 'ns not found') { throw $e; } } } /** * Returns the value of a module row from phpinfo(), or null if it's not found. * * @param string $row * @return string|null */ function get_module_info($row) { ob_start(); phpinfo(INFO_MODULES); $info = ob_get_clean(); $pattern = sprintf('/^%s(.*)$/m', preg_quote($row . ' => ')); if (preg_match($pattern, $info, $matches) !== 1) { return null; } return $matches[1]; } function create_test_manager(?string $uri = null, array $options = [], array $driverOptions = []) { if (getenv('API_VERSION') && ! isset($driverOptions['serverApi'])) { $driverOptions['serverApi'] = new ServerApi(getenv('API_VERSION')); } if (getenv('CRYPT_SHARED_LIB_PATH') && isset($driverOptions['autoEncryption'])) { if (is_array($driverOptions['autoEncryption']) && (! isset($driverOptions['autoEncryption']['extraOptions']) || is_array($driverOptions['autoEncryption']['extraOptions'])) && ! isset($driverOptions['autoEncryption']['extraOptions']['cryptSharedLibPath'])) { $driverOptions['autoEncryption']['extraOptions']['cryptSharedLibPath'] = getenv('CRYPT_SHARED_LIB_PATH'); } } return new Manager($uri ?? URI, $options, $driverOptions); } /** * Returns the primary server. * * @param string $uri Connection string * @return Server * @throws ConnectionException */ function get_primary_server($uri) { return create_test_manager($uri)->selectServer(new ReadPreference('primary')); } /** * Returns a secondary server. * * @param string $uri Connection string * @return Server * @throws ConnectionException */ function get_secondary_server($uri) { return create_test_manager($uri)->selectServer(new ReadPreference('secondary')); } /** * Runs a command and returns whether an exception was thrown or not * * @param string $uri Connection string * @param array|object $commandSpec * @return bool * @throws RuntimeException */ function command_works($uri, $commandSpec) { $command = new Command($commandSpec); $server = get_primary_server($uri); try { $cursor = $server->executeCommand('admin', $command); return true; } catch (Exception $e) { return false; } } /** * Returns a parameter of the primary server. * * @param string $uri Connection string * @return mixed * @throws RuntimeException */ function get_server_parameter($uri, $parameter) { $server = get_primary_server($uri); $command = new Command(['getParameter' => 1, $parameter => 1]); $cursor = $server->executeCommand('admin', $command); return current($cursor->toArray())->$parameter; } /** * Returns the storage engine of the primary server. * * @param string $uri Connection string * @return string * @throws RuntimeException */ function get_server_storage_engine($uri) { $server = get_primary_server($uri); $command = new Command(['serverStatus' => 1]); $cursor = $server->executeCommand('admin', $command); return current($cursor->toArray())->storageEngine->name; } /** * Helper to return the version of a specific server. * * @param Server $server * @return string * @throws RuntimeException */ function get_server_version_from_server(Server $server) { $command = new Command(['buildInfo' => 1]); $cursor = $server->executeCommand('admin', $command); return current($cursor->toArray())->version; } /** * Returns the version of the primary server. * * @param string $uri Connection string * @return string * @throws RuntimeException */ function get_server_version($uri) { $server = get_primary_server($uri); return get_server_version_from_server($server); } /** * Returns the value of a URI option, or null if it's not found. * * @param string $uri * @return string|null */ function get_uri_option($uri, $option) { $pattern = sprintf('/[?&]%s=([^&]+)/i', preg_quote($option)); if (preg_match($pattern, $uri, $matches) !== 1) { return null; } return $matches[1]; } /** * Checks that the topology is load balanced. * * @param string $uri * @return boolean */ function is_load_balanced($uri) { return get_primary_server($uri)->getType() === Server::TYPE_LOAD_BALANCER; } /** * Checks that the topology is a sharded cluster. * * @param string $uri * @return boolean */ function is_mongos($uri) { return get_primary_server($uri)->getType() === Server::TYPE_MONGOS; } /** * Checks that the topology is a sharded cluster using a replica set. * * Note: only the first shard is checked. */ function is_sharded_cluster_with_replica_set($uri) { $server = get_primary_server($uri); if ($server->getType() !== Server::TYPE_MONGOS && $server->getType() !== Server::TYPE_LOAD_BALANCER) { return false; } $cursor = $server->executeQuery('config.shards', new \MongoDB\Driver\Query([], ['limit' => 1])); $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); $document = current($cursor->toArray()); if (! $document) { return false; } /** * Use regular expression to distinguish between standalone or replicaset: * Without a replicaset: "host" : "localhost:4100" * With a replicaset: "host" : "dec6d8a7-9bc1-4c0e-960c-615f860b956f/localhost:4400,localhost:4401" */ return preg_match('@^.*/.*:\d+@', $document['host']); } /** * Checks that the topology is a replica set. * * @param string $uri * @return boolean */ function is_replica_set($uri) { if (get_primary_server($uri)->getType() !== Server::TYPE_RS_PRIMARY) { return false; } /* Note: this may return a false negative if replicaSet is specified through * a TXT record for a mongodb+srv connection string. */ if (get_uri_option($uri, 'replicaSet') === NULL) { return false; } return true; } /** * Checks if the connection string uses authentication. * * @param string $uri * @return boolean */ function is_auth($uri) { if (stripos($uri, 'authmechanism=') !== false) { return true; } if (strpos($uri, ':') !== false && strpos($uri, '@') !== false) { return true; } return false; } /** * Checks if the connection string uses SSL. * * @param string $uri * @return boolean */ function is_ssl($uri) { return stripos($uri, 'ssl=true') !== false || stripos($uri, 'tls=true') !== false; } /** * Checks that the topology is a standalone. * * @param string $uri * @return boolean */ function is_standalone($uri) { return get_primary_server($uri)->getType() === Server::TYPE_STANDALONE; } /** * Converts the server type constant to a string. * * @see http://php.net/manual/en/class.mongodb-driver-server.php * @param integer $type * @return string */ function server_type_as_string($type) { switch ($type) { case Server::TYPE_STANDALONE: return 'Standalone'; case Server::TYPE_MONGOS: return 'Mongos'; case Server::TYPE_POSSIBLE_PRIMARY: return 'PossiblePrimary'; case Server::TYPE_RS_PRIMARY: return 'RSPrimary'; case Server::TYPE_RS_SECONDARY: return 'RSSecondary'; case Server::TYPE_RS_ARBITER: return 'RSArbiter'; case Server::TYPE_RS_OTHER: return 'RSOther'; case Server::TYPE_RS_GHOST: return 'RSGhost'; default: return 'Unknown'; } } /** * Converts an errno number to a string. * * @see http://php.net/manual/en/errorfunc.constants.php * @param integer $errno * @param string */ function errno_as_string($errno) { $errors = [ 'E_ERROR', 'E_WARNING', 'E_PARSE', 'E_NOTICE', 'E_CORE_ERROR', 'E_CORE_WARNING', 'E_COMPILE_ERROR', 'E_COMPILE_WARNING', 'E_USER_ERROR', 'E_USER_WARNING', 'E_USER_NOTICE', 'E_STRICT', 'E_RECOVERABLE_ERROR', 'E_DEPRECATED', 'E_USER_DEPRECATED', 'E_ALL', ]; foreach ($errors as $error) { if ($errno === constant($error)) { return $error; } } return 'Unknown'; } /** * Prints a traditional hex dump of byte values and printable characters. * * @see http://stackoverflow.com/a/4225813/162228 * @param string $data Binary data * @param integer $width Bytes displayed per line */ function hex_dump($data, $width = 16) { static $pad = '.'; // Placeholder for non-printable characters static $from = ''; static $to = ''; if ($from === '') { for ($i = 0; $i <= 0xFF; $i++) { $from .= chr($i); $to .= ($i >= 0x20 && $i <= 0x7E) ? chr($i) : $pad; } } $hex = str_split(bin2hex($data), $width * 2); $chars = str_split(strtr($data, $from, $to), $width); $offset = 0; $length = $width * 3; foreach ($hex as $i => $line) { printf("%6X : %-{$length}s [%s]\n", $offset, implode(' ', str_split($line, 2)), $chars[$i]); $offset += $width; } } /** * Canonicalizes a JSON string. * * @param string $json * @return string */ function json_canonicalize($json) { $json = json_encode(json_decode($json)); /* Canonicalize string values for $numberDouble to ensure they are converted * the same as number literals in legacy and relaxed output. This is needed * because the printf format in _bson_as_json_visit_double uses a high level * of precision and may not produce the exponent notation expected by the * BSON corpus tests. */ $json = preg_replace_callback( '/{"\$numberDouble":"(-?\d+(\.\d+([eE]\+\d+)?)?)"}/', function ($matches) { return '{"$numberDouble":"' . json_encode(json_decode($matches[1])) . '"}'; }, $json ); return $json; } /** * Return a collection name to use for the test file. * * The filename will be stripped of the base path to the test suite (prefix) as * well as the PHP file extension (suffix). Special characters (including hyphen * for shell compatibility) will be replaced with underscores. * * @param string $filename * @return string */ function makeCollectionNameFromFilename($filename) { $filename = realpath($filename); $prefix = realpath(dirname(__FILE__) . '/..') . DIRECTORY_SEPARATOR; $replacements = array( // Strip test path prefix sprintf('/^%s/', preg_quote($prefix, '/')) => '', // Strip file extension suffix '/\.php$/' => '', // SKIPIFs add ".skip" between base name and extension '/\.skip$/' => '', // Replace special characters with underscores sprintf('/[%s]/', preg_quote('-$/\\', '/')) => '_', ); return preg_replace(array_keys($replacements), array_values($replacements), $filename); } function NEEDS($configuration) { if (!constant($configuration)) { exit("skip -- need '$configuration' defined"); } } function SLOW() { if (getenv("SKIP_SLOW_TESTS")) { exit("skip SKIP_SLOW_TESTS"); } } function loadFixtures(Manager $manager, $dbname = DATABASE_NAME, $collname = COLLECTION_NAME, $filename = null) { if (!$filename) { $filename = "compress.zlib://" . __DIR__ . "/" . "PHONGO-FIXTURES.json.gz"; } $bulk = new BulkWrite(['ordered' => false]); $server = $manager->selectServer(new ReadPreference(ReadPreference::PRIMARY)); $data = file_get_contents($filename); $array = json_decode($data); foreach($array as $document) { $bulk->insert($document); } $retval = $server->executeBulkWrite("$dbname.$collname", $bulk); if ($retval->getInsertedCount() !== count($array)) { exit(sprintf('skip Fixtures were not loaded (expected: %d, actual: %d)', $total, $retval->getInsertedCount())); } } function createTemporaryMongoInstance(array $options = []) { $id = 'mo_' . COLLECTION_NAME; $options += [ "name" => "mongod", "id" => $id, 'procParams' => [ 'logpath' => "/tmp/MO/phongo/{$id}.log", 'ipv6' => true, 'setParameter' => [ 'enableTestCommands' => 1 ], ], ]; $opts = array( "http" => array( "timeout" => 60, "method" => "PUT", "header" => "Accept: application/json\r\n" . "Content-type: application/x-www-form-urlencoded", "content" => json_encode($options), "ignore_errors" => true, ), ); $ctx = stream_context_create($opts); $json = file_get_contents(MONGO_ORCHESTRATION_URI . "/servers/$id", false, $ctx); $result = json_decode($json, true); /* Failed -- or was already started */ if (!isset($result["mongodb_uri"])) { destroyTemporaryMongoInstance($id); throw new Exception("Could not start temporary server instance\n"); } else { return $result['mongodb_uri']; } } function destroyTemporaryMongoInstance($id = NULL) { if ($id == NULL) { $id = 'mo_' . COLLECTION_NAME; } $opts = array( "http" => array( "timeout" => 60, "method" => "DELETE", "header" => "Accept: application/json\r\n", "ignore_errors" => true, ), ); $ctx = stream_context_create($opts); $json = file_get_contents(MONGO_ORCHESTRATION_URI . "/servers/$id", false, $ctx); } /** * Converts an error level (constant or bitmask) to a string description. */ function severityToString(int $severity): string { static $constants = [ 'E_ERROR' => E_ERROR, 'E_WARNING' => E_WARNING, 'E_PARSE' => E_PARSE, 'E_NOTICE' => E_NOTICE, 'E_CORE_ERROR' => E_CORE_ERROR, 'E_CORE_WARNING' => E_CORE_WARNING, 'E_COMPILE_ERROR' => E_COMPILE_ERROR, 'E_COMPILE_WARNING' => E_COMPILE_WARNING, 'E_USER_ERROR' => E_USER_ERROR, 'E_USER_WARNING' => E_USER_WARNING, 'E_USER_NOTICE' => E_USER_NOTICE, 'E_STRICT' => 2048, // E_STRICT was deprecated in PHP 8.4 'E_RECOVERABLE_ERROR' => E_RECOVERABLE_ERROR, 'E_DEPRECATED' => E_DEPRECATED, 'E_USER_DEPRECATED' => E_USER_DEPRECATED, // E_ALL is handled separately ]; if ($severity === E_ALL) { return 'E_ALL'; } foreach ($constants as $constant => $value) { if ($severity & $value) { $matches[] = $constant; } } return empty($matches) ? 'UNKNOWN' : implode('|', $matches); } /** * Expects the callable to raise an error matching the expected severity, which * may be a constant or bitmask. May optionally expect the error to be raised * from a particular function. Returns the message from the raised error or * exception, or an empty string if neither was thrown. */ function raises(callable $callable, int $expectedSeverity, ?string $expectedFromFunction = null): string { set_error_handler(function(int $severity, string $message, string $file, int $line) { throw new ErrorException($message, 0, $severity, $file, $line); }); try { call_user_func($callable); } catch (ErrorException $e) { if (!($e->getSeverity() & $expectedSeverity)) { printf("ALMOST: Got %s - expected %s\n", severityToString($e->getSeverity()), severityToString($expectedSeverity)); return $e->getMessage(); } if ($expectedFromFunction === null) { printf("OK: Got %s\n", severityToString($e->getSeverity())); return $e->getMessage(); } $fromFunction = $e->getTrace()[0]['function']; if (strcasecmp($fromFunction, $expectedFromFunction) !== 0) { printf("ALMOST: Got %s - but was raised from %s, not %s\n", errorLevelToString($e->getSeverity()), $fromFunction, $expectedFromFunction); return $e->getMessage(); } printf("OK: Got %s raised from %s\n", severityToString($e->getSeverity()), $fromFunction); return $e->getMessage(); } catch (Throwable $e) { printf("ALMOST: Got %s - expected %s\n", get_class($e), ErrorException::class); return $e->getMessage(); } finally { restore_error_handler(); } printf("FAILED: Expected %s, but no error raised!\n", ErrorException::class); return ''; } /** * Expects the callable to throw an expected exception. May optionally expect * the exception to be thrown from a particular function. Returns the message * from the thrown exception, or an empty string if one was not thrown. */ function throws(callable $callable, string $expectedException, ?string $expectedFromFunction = null): string { try { call_user_func($callable); } catch (Throwable $e) { if (!($e instanceof $expectedException)) { printf("ALMOST: Got %s - expected %s\n", get_class($e), $expectedException); return $e->getMessage(); } if ($expectedFromFunction === null) { printf("OK: Got %s\n", $expectedException); return $e->getMessage(); } $fromFunction = $e->getTrace()[0]['function']; if (strcasecmp($fromFunction, $expectedFromFunction) !== 0) { printf("ALMOST: Got %s - but was thrown from %s, not %s\n", $expectedException, $fromFunction, $expectedFromFunction); return $e->getMessage(); } printf("OK: Got %s thrown from %s\n", $expectedException, $fromFunction); return $e->getMessage(); } printf("FAILED: Expected %s, but no exception thrown!\n", $expectedException); return ''; } function printServer(Server $server) { printf("server: %s:%d\n", $server->getHost(), $server->getPort()); } function printWriteResult(WriteResult $result, $details = true) { printServer($result->getServer()); printf("insertedCount: %d\n", $result->getInsertedCount()); printf("matchedCount: %d\n", $result->getMatchedCount()); printf("modifiedCount: %d\n", $result->getModifiedCount()); printf("upsertedCount: %d\n", $result->getUpsertedCount()); printf("deletedCount: %d\n", $result->getDeletedCount()); foreach ($result->getUpsertedIds() as $index => $id) { printf("upsertedId[%d]: ", $index); var_dump($id); } $writeConcernError = $result->getWriteConcernError(); printWriteConcernError($writeConcernError ? $writeConcernError : null, $details); foreach ($result->getWriteErrors() as $writeError) { printWriteError($writeError); } } function printWriteConcernError(?WriteConcernError $error = null, $details = null) { if ($error) { /* This stuff is generated by the server, no need for us to test it */ if (!$details) { printf("writeConcernError: %s (%d)\n", $error->getMessage(), $error->getCode()); return; } var_dump($error); printf("writeConcernError.message: %s\n", $error->getMessage()); printf("writeConcernError.code: %d\n", $error->getCode()); printf("writeConcernError.info: "); var_dump($error->getInfo()); } } function printWriteError(WriteError $error) { var_dump($error); printf("writeError[%d].message: %s\n", $error->getIndex(), $error->getMessage()); printf("writeError[%d].code: %d\n", $error->getIndex(), $error->getCode()); } function getInsertCount($retval) { return $retval->getInsertedCount(); } function getModifiedCount($retval) { return $retval->getModifiedCount(); } function getDeletedCount($retval) { return $retval->getDeletedCount(); } function getUpsertedCount($retval) { return $retval->getUpsertedCount(); } function getWriteErrors($retval) { return (array)$retval->getWriteErrors(); } function def($arr) { foreach($arr as $const => $value) { define($const, getenv("PHONGO_TEST_$const") ?: $value); } } function configureFailPoint(Manager $manager, $failPoint, $mode, array $data = []) { $doc = [ 'configureFailPoint' => $failPoint, 'mode' => $mode, ]; if ($data) { $doc['data'] = $data; } $cmd = new Command($doc); $manager->executeCommand('admin', $cmd); } function configureTargetedFailPoint(Server $server, $failPoint, $mode, array $data = []) { $doc = array( 'configureFailPoint' => $failPoint, 'mode' => $mode, ); if ($data) { $doc['data'] = $data; } $cmd = new Command($doc); $server->executeCommand('admin', $cmd); } function failMaxTimeMS(Server $server) { configureTargetedFailPoint($server, 'maxTimeAlwaysTimeOut', [ 'times' => 1 ]); } function toPHP($var, $typemap = array()) { return MongoDB\BSON\Document::fromBSON($var)->toPHP($typemap); } function fromPHP($var) { return (string) MongoDB\BSON\Document::fromPHP($var); } function toJSON($var) { return MongoDB\BSON\Document::fromBSON($var)->toCanonicalExtendedJSON(); } function toCanonicalExtendedJSON($var) { return MongoDB\BSON\Document::fromBSON($var)->toCanonicalExtendedJSON(); } function toRelaxedExtendedJSON($var) { return MongoDB\BSON\Document::fromBSON($var)->toRelaxedExtendedJSON(); } function fromJSON($var) { return (string) MongoDB\BSON\Document::fromJSON($var); } /* Note: this fail point may terminate the mongod process, so you may want to * use this in conjunction with a throwaway server. */ function failGetMore(Manager $manager) { /* We need to do version detection here */ $primary = $manager->selectServer(new ReadPreference('primary')); $version = get_server_version_from_server($primary); if (version_compare($version, "4.0", ">=")) { /* We use 237 here, as that's the same original code that MongoD would * throw if a cursor had already gone by the time we call getMore. This * allows us to make things consistent with the getMore OP behaviour * from previous mongod versions. An errorCode is required here for the * failPoint to work. */ configureFailPoint($manager, 'failCommand', 'alwaysOn', [ 'errorCode' => 237, 'failCommands' => ['getMore'] ]); return; } throw new Exception("Trying to configure a getMore fail point for a server version ($version) that doesn't support it"); } mongodb-1.21.0/tests/writeConcern/bug1598-001.phpt0000644000175100001660000000112114760300421016234 0ustar --TEST-- PHPC-1598: WriteConcern get_gc should not invoke get_properties --FILE-- $wc]; $b = (object) ['wc' => $wc]; $a->b = $b; $b->a = $a; printf("Collected cycles: %d\n", gc_collect_cycles()); unset($a, $b); printf("Collected cycles: %d\n", gc_collect_cycles()); ?> ===DONE=== --EXPECT-- Collected cycles: 0 Collected cycles: 2 ===DONE=== mongodb-1.21.0/tests/writeConcern/bug1598-002.phpt0000644000175100001660000000154714760300421016251 0ustar --TEST-- PHPC-1598: WriteConcern get_gc should delegate to zend_std_get_properties --SKIPIF-- =', '8.1.99'); ?> --FILE-- wc = new MongoDB\Driver\WriteConcern('string'); $a->wc->a = $a; printf("Collected cycles: %d\n", gc_collect_cycles()); unset($a); printf("Collected cycles: %d\n", gc_collect_cycles()); ?> ===DONE=== --EXPECT-- Collected cycles: 0 Collected cycles: 2 ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-bsonserialize-001.phpt0000644000175100001660000000264414760300421022514 0ustar --TEST-- MongoDB\Driver\WriteConcern::bsonSerialize() --FILE-- 1 new MongoDB\Driver\WriteConcern(-2, 1000), ]; foreach ($tests as $test) { echo toJSON(fromPHP($test)), "\n"; } ?> ===DONE=== --EXPECT-- { "w" : "majority" } { } { "w" : { "$numberInt" : "-1" } } { "w" : { "$numberInt" : "0" } } { "w" : { "$numberInt" : "1" } } { "w" : "majority" } { "w" : "tag" } { "w" : { "$numberInt" : "1" } } { "w" : { "$numberInt" : "1" }, "j" : false } { "w" : { "$numberInt" : "1" }, "wtimeout" : { "$numberInt" : "1000" } } { "w" : { "$numberInt" : "1" }, "j" : true, "wtimeout" : { "$numberInt" : "1000" } } { "j" : true } { "wtimeout" : { "$numberInt" : "1000" } } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-bsonserialize-002.phpt0000644000175100001660000000327014760300421022511 0ustar --TEST-- MongoDB\Driver\WriteConcern::bsonSerialize() returns an object --FILE-- 1 new MongoDB\Driver\WriteConcern(-2, 1000), ]; foreach ($tests as $test) { var_dump($test->bsonSerialize()); } ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["w"]=> string(8) "majority" } object(stdClass)#%d (%d) { } object(stdClass)#%d (%d) { ["w"]=> int(-1) } object(stdClass)#%d (%d) { ["w"]=> int(0) } object(stdClass)#%d (%d) { ["w"]=> int(1) } object(stdClass)#%d (%d) { ["w"]=> string(8) "majority" } object(stdClass)#%d (%d) { ["w"]=> string(3) "tag" } object(stdClass)#%d (%d) { ["w"]=> int(1) } object(stdClass)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(false) } object(stdClass)#%d (%d) { ["w"]=> int(1) ["wtimeout"]=> int(1000) } object(stdClass)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(true) ["wtimeout"]=> int(1000) } object(stdClass)#%d (%d) { ["j"]=> bool(true) } object(stdClass)#%d (%d) { ["wtimeout"]=> int(1000) } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-bsonserialize-003.phpt0000644000175100001660000000065314760300421022514 0ustar --TEST-- MongoDB\Driver\WriteConcern::bsonSerialize() encodes 64-bit wtimeoutms as integer (64-bit) --SKIPIF-- --FILE-- bsonSerialize()); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> int(2147483648) } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-bsonserialize-004.phpt0000644000175100001660000000102214760300421022504 0ustar --TEST-- MongoDB\Driver\WriteConcern::bsonSerialize() encodes 64-bit wtimeoutms as Int64 (32-bit) --SKIPIF-- --FILE-- 2, 'wtimeout' => '2147483648']); var_dump($wc->bsonSerialize()); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> object(MongoDB\BSON\Int64)#%d (%d) { ["integer"]=> string(10) "2147483648" } } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-constants.phpt0000644000175100001660000000027514760300421021357 0ustar --TEST-- MongoDB\Driver\WriteConcern constants --FILE-- ===DONE=== --EXPECTF-- string(8) "majority" ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-ctor-001.phpt0000644000175100001660000000311714760300421020606 0ustar --TEST-- MongoDB\Driver\WriteConcern construction --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> int(2000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(7) "tagname" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(6) "string" ["wtimeout"]=> int(3000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(6) "string" ["j"]=> bool(true) ["wtimeout"]=> int(4000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(6) "string" ["j"]=> bool(false) ["wtimeout"]=> int(5000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(6) "string" ["wtimeout"]=> int(6000) } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-ctor-002.phpt0000644000175100001660000000060714760300421020610 0ustar --TEST-- MongoDB\Driver\WriteConcern construction with 64-bit wtimeoutms --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["wtimeout"]=> int(2147483648) } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-ctor_error-001.phpt0000644000175100001660000000114414760300421022015 0ustar --TEST-- MongoDB\Driver\WriteConcern construction (invalid arguments) --SKIPIF-- =', '7.99'); ?> --FILE-- ===DONE=== --EXPECTF-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\WriteConcern::__construct() expects at most 3 %r(argument|parameter)%rs, 4 given ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-ctor_error-002.phpt0000644000175100001660000000172614760300421022024 0ustar --TEST-- MongoDB\Driver\WriteConcern construction (invalid w type) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected w to be integer or string, float given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected w to be integer or string, bool given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected w to be integer or string, array given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected w to be integer or string, stdClass given OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected w to be integer or string, null given ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-ctor_error-003.phpt0000644000175100001660000000062614760300421022023 0ustar --TEST-- MongoDB\Driver\WriteConcern construction (invalid w range) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected w to be >= -3, -4 given ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-ctor_error-004.phpt0000644000175100001660000000064614760300421022026 0ustar --TEST-- MongoDB\Driver\WriteConcern construction (invalid wtimeout range) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Expected wtimeout to be >= 0, -1 given ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-ctor_error-005.phpt0000644000175100001660000000067014760300421022024 0ustar --TEST-- MongoDB\Driver\WriteConcern construction (journaling with unacknowledged w) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot enable journaling when using w = 0 ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-debug-001.phpt0000644000175100001660000000105714760300421020726 0ustar --TEST-- MongoDB\Driver\WriteConcern debug output should include all fields for w default --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["j"]=> bool(true) ["wtimeout"]=> int(1000) } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-debug-002.phpt0000644000175100001660000000121414760300421020722 0ustar --TEST-- MongoDB\Driver\WriteConcern debug output --FILE-- ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(3) "tag" ["j"]=> bool(false) ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" ["j"]=> bool(true) ["wtimeout"]=> int(500) } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-debug-003.phpt0000644000175100001660000000424014760300421020725 0ustar --TEST-- MongoDB\Driver\WriteConcern debug output --FILE-- 1 new MongoDB\Driver\WriteConcern(-2, 1000), // 64-bit wtimeout may be reported as integer or string MongoDB\Driver\WriteConcern::__set_state(['w' => 2, 'wtimeout' => '2147483648']), ]; foreach ($tests as $test) { var_dump($test); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } object(MongoDB\Driver\WriteConcern)#%d (%d) { } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(-1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(3) "tag" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(false) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(true) ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["j"]=> bool(true) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> %rint\(2147483648\)|string\(10\) "2147483648"%r } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-getjournal-001.phpt0000644000175100001660000000072014760300421022006 0ustar --TEST-- MongoDB\Driver\WriteConcern::getJournal() --FILE-- getJournal()); } // Test with default value $wc = new MongoDB\Driver\WriteConcern(1, 0); var_dump($wc->getJournal()); ?> ===DONE=== --EXPECT-- bool(true) bool(false) bool(true) bool(false) NULL NULL ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-getw-001.phpt0000644000175100001660000000071114760300421020602 0ustar --TEST-- MongoDB\Driver\WriteConcern::getW() --FILE-- getW()); } ?> ===DONE=== --EXPECT-- string(8) "majority" string(8) "majority" NULL int(-1) int(0) int(1) int(2) string(3) "tag" string(1) "2" ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-getwtimeout-001.phpt0000644000175100001660000000061314760300421022212 0ustar --TEST-- MongoDB\Driver\WriteConcern::getWtimeout() --FILE-- getWtimeout()); } // Test with default value $wc = new MongoDB\Driver\WriteConcern(1); var_dump($wc->getWtimeout()); ?> ===DONE=== --EXPECT-- int(0) int(1) int(0) ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-getwtimeout-002.phpt0000644000175100001660000000105714760300421022216 0ustar --TEST-- MongoDB\Driver\WriteConcern::getWtimeout() emits warning on truncation of 64-bit value --SKIPIF-- --FILE-- getWriteConcern()->getWtimeout()); }, E_WARNING), "\n"; ?> ===DONE=== --EXPECT-- OK: Got E_WARNING Truncating 64-bit value for wTimeoutMS ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-isdefault-001.phpt0000644000175100001660000000466614760300421021631 0ustar --TEST-- MongoDB\Driver\WriteConcern::isDefault() --FILE-- getWriteConcern(), // Cannot test "w=-3" since libmongoc URI parsing expects integers >= -1 // Cannot test "w=-2" since libmongoc URI parsing expects integers >= -1, and throws an error otherwise (new MongoDB\Driver\Manager('mongodb://127.0.0.1/?w=-1'))->getWriteConcern(), (new MongoDB\Driver\Manager('mongodb://127.0.0.1/?w=0'))->getWriteConcern(), (new MongoDB\Driver\Manager('mongodb://127.0.0.1/?w=1'))->getWriteConcern(), (new MongoDB\Driver\Manager('mongodb://127.0.0.1/?w=2'))->getWriteConcern(), (new MongoDB\Driver\Manager('mongodb://127.0.0.1/?w=tag'))->getWriteConcern(), (new MongoDB\Driver\Manager('mongodb://127.0.0.1/?w=majority'))->getWriteConcern(), // Cannot test ['w' => null] since an integer or string type is expected (PHPC-887) // Cannot test ['w' => -3] or ['w' => -2] since php_phongo_apply_wc_options_to_uri() expects integers >= -1 (new MongoDB\Driver\Manager(null, ['w' => -1]))->getWriteConcern(), (new MongoDB\Driver\Manager(null, ['w' => 0]))->getWriteConcern(), (new MongoDB\Driver\Manager(null, ['w' => 1]))->getWriteConcern(), (new MongoDB\Driver\Manager(null, ['w' => 2]))->getWriteConcern(), (new MongoDB\Driver\Manager(null, ['w' => 'tag']))->getWriteConcern(), (new MongoDB\Driver\Manager(null, ['w' => 'majority']))->getWriteConcern(), (new MongoDB\Driver\Manager)->getWriteConcern(), ]; foreach ($tests as $wc) { var_dump($wc->isDefault()); } ?> ===DONE=== --EXPECT-- bool(false) bool(true) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(true) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(false) bool(true) ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-serialization-002.phpt0000644000175100001660000001043314760300421022514 0ustar --TEST-- MongoDB\Driver\WriteConcern serialization (__serialize and __unserialize) --FILE-- 1 new MongoDB\Driver\WriteConcern(-2, 1000), // 64-bit wtimeout is always encoded as as string MongoDB\Driver\WriteConcern::__set_state(['w' => 2, 'wtimeout' => '2147483648']), ]; foreach ($tests as $test) { var_dump($test); echo $s = serialize($test), "\n"; var_dump(unserialize($s)); echo "\n"; } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } O:27:"MongoDB\Driver\WriteConcern":1:{s:1:"w";s:8:"majority";} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } object(MongoDB\Driver\WriteConcern)#%d (%d) { } O:27:"MongoDB\Driver\WriteConcern":0:{} object(MongoDB\Driver\WriteConcern)#%d (%d) { } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(-1) } O:27:"MongoDB\Driver\WriteConcern":1:{s:1:"w";i:-1;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(-1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } O:27:"MongoDB\Driver\WriteConcern":1:{s:1:"w";i:0;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(0) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } O:27:"MongoDB\Driver\WriteConcern":1:{s:1:"w";i:1;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } O:27:"MongoDB\Driver\WriteConcern":1:{s:1:"w";s:8:"majority";} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(8) "majority" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(3) "tag" } O:27:"MongoDB\Driver\WriteConcern":1:{s:1:"w";s:3:"tag";} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> string(3) "tag" } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } O:27:"MongoDB\Driver\WriteConcern":1:{s:1:"w";i:1;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(false) } O:27:"MongoDB\Driver\WriteConcern":2:{s:1:"w";i:1;s:1:"j";b:0;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(false) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["wtimeout"]=> int(1000) } O:27:"MongoDB\Driver\WriteConcern":2:{s:1:"w";i:1;s:8:"wtimeout";i:1000;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(true) ["wtimeout"]=> int(1000) } O:27:"MongoDB\Driver\WriteConcern":3:{s:1:"w";i:1;s:1:"j";b:1;s:8:"wtimeout";i:1000;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(1) ["j"]=> bool(true) ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["j"]=> bool(true) } O:27:"MongoDB\Driver\WriteConcern":1:{s:1:"j";b:1;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["j"]=> bool(true) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["wtimeout"]=> int(1000) } O:27:"MongoDB\Driver\WriteConcern":1:{s:8:"wtimeout";i:1000;} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["wtimeout"]=> int(1000) } object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> %rint\(2147483648\)|string\(10\) "2147483648"%r } O:27:"MongoDB\Driver\WriteConcern":2:{s:1:"w";i:2;s:8:"wtimeout";s:10:"2147483648";} object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> %rint\(2147483648\)|string\(10\) "2147483648"%r } ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-serialization_error-001.phpt0000644000175100001660000000124014760300421023720 0ustar --TEST-- MongoDB\Driver\WriteConcern unserialization errors (Serializable interface) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot enable journaling when using w = 0 ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-serialization_error-002.phpt0000644000175100001660000000124014760300421023721 0ustar --TEST-- MongoDB\Driver\WriteConcern unserialization errors (__serialize and __unserialize) --FILE-- ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException Cannot enable journaling when using w = 0 ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-set_state-001.phpt0000644000175100001660000000331514760300421021632 0ustar --TEST-- MongoDB\Driver\WriteConcern::__set_state() --FILE-- -3 ], [ 'w' => -2 ], // -2 is default [ 'w' => -1 ], [ 'w' => 0 ], [ 'w' => 1 ], [ 'w' => 'majority' ], [ 'w' => 'tag' ], [ 'w' => 1, 'j' => false ], [ 'w' => 1, 'wtimeout' => 1000 ], [ 'w' => 1, 'j' => true, 'wtimeout' => 1000 ], [ 'j' => true ], [ 'wtimeout' => 1000 ], // wtimeout accepts 64-bit integers as strings [ 'wtimeout' => '2147483648'], ]; foreach ($tests as $fields) { var_export(MongoDB\Driver\WriteConcern::__set_state($fields)); echo "\n\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 'majority', )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => -1, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 0, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 'majority', )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 'tag', )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, 'j' => false, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, 'wtimeout' => 1000, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, 'j' => true, 'wtimeout' => 1000, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'j' => true, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'wtimeout' => 1000, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'wtimeout' => %r2147483648|'2147483648'%r, )) ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-set_state_error-001.phpt0000644000175100001660000000372514760300421023050 0ustar --TEST-- MongoDB\Driver\WriteConcern::__set_state() requires correct data types and values --FILE-- -4]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\Driver\WriteConcern::__set_state(['w' => M_PI]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\Driver\WriteConcern::__set_state(['wtimeout' => -1]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\Driver\WriteConcern::__set_state(['wtimeout' => 'failure']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\Driver\WriteConcern::__set_state(['wtimeout' => new stdClass]); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; echo throws(function() { MongoDB\Driver\WriteConcern::__set_state(['j' => 'failure']); }, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; ?> ===DONE=== --EXPECT-- OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\WriteConcern initialization requires "w" integer field to be >= -3 OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\WriteConcern initialization requires "w" field to be integer or string OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\WriteConcern initialization requires "wtimeout" integer field to be >= 0 OK: Got MongoDB\Driver\Exception\InvalidArgumentException Error parsing "failure" as 64-bit value for MongoDB\Driver\WriteConcern initialization OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\WriteConcern initialization requires "wtimeout" field to be integer or string OK: Got MongoDB\Driver\Exception\InvalidArgumentException MongoDB\Driver\WriteConcern initialization requires "j" field to be boolean ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern-var_export-001.phpt0000644000175100001660000000426314760300421022033 0ustar --TEST-- MongoDB\Driver\WriteConcern: var_export() --FILE-- 1 new MongoDB\Driver\WriteConcern(-2, 1000), // 64-bit wtimeout may be reported as integer or string MongoDB\Driver\WriteConcern::__set_state(['w' => 2, 'wtimeout' => '2147483648']), ]; foreach ($tests as $test) { echo var_export($test, true), "\n"; } ?> ===DONE=== --EXPECTF-- %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 'majority', )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => -1, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 0, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 'majority', )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 'tag', )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, 'j' => false, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, 'wtimeout' => 1000, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 1, 'j' => true, 'wtimeout' => 1000, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'j' => true, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'wtimeout' => 1000, )) %r\\?%rMongoDB\Driver\WriteConcern::__set_state(array( 'w' => 2, 'wtimeout' => %r2147483648|'2147483648'%r, )) ===DONE=== mongodb-1.21.0/tests/writeConcern/writeconcern_error-001.phpt0000644000175100001660000000042314760300421021047 0ustar --TEST-- MongoDB\Driver\WriteConcern cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyWriteConcern %s final class %SMongoDB\Driver\WriteConcern%S in %s on line %d mongodb-1.21.0/tests/writeConcernError/writeconcernerror-debug-001.phpt0000644000175100001660000000152614760300421023013 0ustar --TEST-- MongoDB\Driver\WriteConcernError debug output --SKIPIF-- --FILE-- insert(['x' => 1]); try { /* We assume that the replica set does not have 12 nodes */ $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(12)]); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteConcernError()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcernError)#%d (%d) { ["message"]=> string(29) "Not enough data-bearing nodes" ["code"]=> int(100) ["info"]=> %A } ===DONE=== mongodb-1.21.0/tests/writeConcernError/writeconcernerror-getcode-001.phpt0000644000175100001660000000131314760300421023331 0ustar --TEST-- MongoDB\Driver\WriteConcernError::getCode() --SKIPIF-- --FILE-- insert(['x' => 1]); try { /* We assume that the replica set does not have 12 nodes */ $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(12)]); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteConcernError()->getCode()); } ?> ===DONE=== --EXPECT-- int(100) ===DONE=== mongodb-1.21.0/tests/writeConcernError/writeconcernerror-getinfo-001.phpt0000644000175100001660000000330614760300421023356 0ustar --TEST-- MongoDB\Driver\WriteConcernError::getInfo() exposes writeConcernError.errInfo --DESCRIPTION-- CRUD spec prose test #1 https://github.com/mongodb/specifications/blob/master/source/crud/tests/README.rst#writeconcernerror-details-exposes-writeconcernerror-errinfo --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference('primary')); configureTargetedFailPoint( $server, 'failCommand', [ 'times' => 1], [ 'failCommands' => ['insert'], 'writeConcernError' => [ 'code' => 100, 'codeName' => 'UnsatisfiableWriteConcern', 'errmsg' => 'Not enough data-bearing nodes', 'errInfo' => [ 'writeConcern' => [ 'w' => 2, 'wtimeout' => 0, 'provenance' => 'clientSupplied', ], ], ], ] ); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['_id' => 1]); try { $server->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteConcernError()->getInfo()); } ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["writeConcern"]=> object(stdClass)#%d (%d) { ["w"]=> int(2) ["wtimeout"]=> int(0) ["provenance"]=> string(14) "clientSupplied" } } ===DONE=== mongodb-1.21.0/tests/writeConcernError/writeconcernerror-getmessage-001.phpt0000644000175100001660000000136314760300421024050 0ustar --TEST-- MongoDB\Driver\WriteConcernError::getMessage() --SKIPIF-- --FILE-- insert(['x' => 1]); try { /* We assume that the replica set does not have 12 nodes */ $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(12)]); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteConcernError()->getMessage()); } ?> ===DONE=== --EXPECT-- string(29) "Not enough data-bearing nodes" ===DONE=== mongodb-1.21.0/tests/writeConcernError/writeconcernerror_error-001.phpt0000644000175100001660000000045414760300421023137 0ustar --TEST-- MongoDB\Driver\WriteConcernError cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyWriteConcernError %s final class %SMongoDB\Driver\WriteConcernError%S in %s on line %d mongodb-1.21.0/tests/writeError/writeerror-debug-001.phpt0000644000175100001660000000153314760300421020131 0ustar --TEST-- MongoDB\Driver\WriteError debug output --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 1]); try { $manager->executeBulkWrite(NS, $bulk); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteErrors()[0]); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "%SE11000 duplicate key error %s: phongo.writeError_writeerror_debug_001%s dup key: { %S: 1 }" ["code"]=> int(11000) ["index"]=> int(1) ["info"]=> NULL } ===DONE=== mongodb-1.21.0/tests/writeError/writeerror-getCode-001.phpt0000644000175100001660000000117714760300421020421 0ustar --TEST-- MongoDB\Driver\WriteError::getCode() --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 1]); try { $manager->executeBulkWrite(NS, $bulk); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteErrors()[0]->getCode()); } ?> ===DONE=== --EXPECT-- int(11000) ===DONE=== mongodb-1.21.0/tests/writeError/writeerror-getIndex-001.phpt0000644000175100001660000000117514760300421020614 0ustar --TEST-- MongoDB\Driver\WriteError::getIndex() --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 1]); try { $manager->executeBulkWrite(NS, $bulk); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteErrors()[0]->getIndex()); } ?> ===DONE=== --EXPECT-- int(1) ===DONE=== mongodb-1.21.0/tests/writeError/writeerror-getInfo-001.phpt0000644000175100001660000000131114760300421020430 0ustar --TEST-- MongoDB\Driver\WriteError::getInfo() --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 1]); try { $manager->executeBulkWrite(NS, $bulk); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { // "errInfo" is rarely populated on a WriteError (e.g. shard version error) var_dump($e->getWriteResult()->getWriteErrors()[0]->getInfo()); } ?> ===DONE=== --EXPECT-- NULL ===DONE=== mongodb-1.21.0/tests/writeError/writeerror-getInfo-002.phpt0000644000175100001660000000426014760300421020437 0ustar --TEST-- MongoDB\Driver\WriteError::getInfo() exposes writeError.errInfo --DESCRIPTION-- CRUD spec prose test #2 https://github.com/mongodb/specifications/blob/master/source/crud/tests/README.rst#writeerror-details-exposes-writeerrors-errinfo --SKIPIF-- --FILE-- executeCommand(DATABASE_NAME, new MongoDB\Driver\Command([ 'create' => COLLECTION_NAME, 'validator' => ['x' => ['$type' => 'string']], ])); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); MongoDB\Driver\Monitoring\addSubscriber($this); try { $manager->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { $writeError = $e->getWriteResult()->getWriteErrors()[0]; var_dump($writeError->getCode()); // DocumentValidationFailure(121) /* Note: we intentionally do not assert the contents of errInfo * since its structure could change between server versions. */ var_dump($writeError->getInfo() instanceof stdClass); var_dump($this->errInfo instanceof stdClass); var_dump($writeError->getInfo() == $this->errInfo); } MongoDB\Driver\Monitoring\removeSubscriber($this); } public function commandStarted(MongoDB\Driver\Monitoring\CommandStartedEvent $event): void { } public function commandSucceeded(MongoDB\Driver\Monitoring\CommandSucceededEvent $event): void { if ($event->getCommandName() === 'insert') { $this->errInfo = $event->getReply()->writeErrors[0]->errInfo ?? null; } } public function commandFailed(MongoDB\Driver\Monitoring\CommandFailedEvent $event): void { } } (new Test)->execute(); ?> ===DONE=== --EXPECTF-- int(121) bool(true) bool(true) bool(true) ===DONE=== mongodb-1.21.0/tests/writeError/writeerror-getMessage-001.phpt0000644000175100001660000000135214760300421021126 0ustar --TEST-- MongoDB\Driver\WriteError::getMessage() --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 1]); try { $manager->executeBulkWrite(NS, $bulk); } catch(MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteErrors()[0]->getMessage()); } ?> ===DONE=== --EXPECTF-- string(%d) "%SE11000 duplicate key error %s: phongo.writeError_writeerror_getMessage_001%s dup key: { %S: 1 }" ===DONE=== mongodb-1.21.0/tests/writeError/writeerror_error-001.phpt0000644000175100001660000000041114760300421020250 0ustar --TEST-- MongoDB\Driver\WriteError cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyWriteError %s final class %SMongoDB\Driver\WriteError%S in %s on line %d mongodb-1.21.0/tests/writeResult/bug0671-003.phpt0000644000175100001660000000153314760300421016123 0ustar --TEST-- PHPC-671: Segfault if Manager is already freed when using WriteResult's Server --SKIPIF-- --FILE-- insert(['_id' => 1]); $writeResult = $manager->executeBulkWrite(NS, $bulk); unset($manager); $server = $writeResult->getServer(); /* WriteResult only uses the client to construct a Server. We need to interact * with the Server to test for a user-after-free. */ $cursor = $server->executeCommand(DATABASE_NAME, new MongoDB\Driver\Command(['ping' => 1])); var_dump($cursor->toArray()[0]); ?> ===DONE=== --EXPECTF-- object(stdClass)#%d (%d) { ["ok"]=> float(1)%A } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-debug-001.phpt0000644000175100001660000000264514760300421020510 0ustar --TEST-- MongoDB\Driver\WriteResult debug output without errors --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> int(1) ["nMatched"]=> int(1) ["nModified"]=> int(1) ["nRemoved"]=> int(1) ["nUpserted"]=> int(2) ["upsertedIds"]=> array(2) { [0]=> array(2) { ["index"]=> int(2) ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } [1]=> array(2) { ["index"]=> int(3) ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } } ["writeErrors"]=> array(0) { } ["writeConcernError"]=> NULL ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { } ["errorReplies"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-debug-002.phpt0000644000175100001660000000533714760300421020512 0ustar --TEST-- MongoDB\Driver\WriteResult debug output with errors --SKIPIF-- --FILE-- false]); $bulk->update(['x' => 1], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 2], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $bulk->insert(['_id' => 3]); try { /* We assume that the replica set does not have 30 nodes */ $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(30)]); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteResult)#%d (%d) { ["nInserted"]=> int(3) ["nMatched"]=> int(0) ["nModified"]=> int(0) ["nRemoved"]=> int(0) ["nUpserted"]=> int(2) ["upsertedIds"]=> array(2) { [0]=> array(2) { ["index"]=> int(0) ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } [1]=> array(2) { ["index"]=> int(1) ["_id"]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } } ["writeErrors"]=> array(3) { [0]=> object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "E11000 duplicate key %S phongo.writeResult_writeresult_debug_002%s dup key: { %S: 1 }" ["code"]=> int(11000) ["index"]=> int(3) ["info"]=> NULL } [1]=> object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "E11000 duplicate key %S phongo.writeResult_writeresult_debug_002%s dup key: { %S: 2 }" ["code"]=> int(11000) ["index"]=> int(5) ["info"]=> NULL } [2]=> object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "E11000 duplicate key %S phongo.writeResult_writeresult_debug_002%s dup key: { %S: 3 }" ["code"]=> int(11000) ["index"]=> int(7) ["info"]=> NULL } } ["writeConcernError"]=> object(MongoDB\Driver\WriteConcernError)#%d (%d) { ["message"]=> string(29) "Not enough data-bearing nodes" ["code"]=> int(100) ["info"]=> %a } ["writeConcern"]=> object(MongoDB\Driver\WriteConcern)#%d (%d) { ["w"]=> int(30) } ["errorReplies"]=> array(0) { } } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getErrorReplies-001.phpt0000644000175100001660000000157114760300421022534 0ustar --TEST-- MongoDB\Driver\WriteResult::getErrorReplies() --SKIPIF-- --FILE-- selectServer(); configureTargetedFailPoint( $server, 'failCommand', ['times' => 1] , ['errorCode' => 8, 'failCommands' => ['insert']] ); $errors = []; try { $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['_id' => 1, 'x' => 'bar']); $server->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { $errors = $e->getWriteResult()->getErrorReplies(); } var_dump(count($errors)); var_dump($errors[0]->code); ?> ===DONE=== --EXPECT-- int(1) int(8) ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getdeletedcount-001.phpt0000644000175100001660000000134314760300421022573 0ustar --TEST-- MongoDB\Driver\WriteResult::getDeletedCount() with acknowledged write --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getDeletedCount()); ?> ===DONE=== --EXPECT-- int(1) ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getdeletedcount-002.phpt0000644000175100001660000000175414760300421022602 0ustar --TEST-- MongoDB\Driver\WriteResult::getDeletedCount() with unacknowledged write --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(0)]); var_dump($result->getDeletedCount()); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\WriteResult::getDeletedCount(): Calling MongoDB\Driver\WriteResult::getDeletedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getinsertedcount-001.phpt0000644000175100001660000000131514760300421023001 0ustar --TEST-- MongoDB\Driver\WriteResult::getInsertedCount() --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getInsertedCount()); ?> ===DONE=== --EXPECT-- int(1) ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getinsertedcount-002.phpt0000644000175100001660000000176014760300421023006 0ustar --TEST-- MongoDB\Driver\WriteResult::getInsertedCount() with unacknowledged write --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(0)]); var_dump($result->getInsertedCount()); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\WriteResult::getInsertedCount(): Calling MongoDB\Driver\WriteResult::getInsertedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getmatchedcount-001.phpt0000644000175100001660000000131314760300421022567 0ustar --TEST-- MongoDB\Driver\WriteResult::getMatchedCount() --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getMatchedCount()); ?> ===DONE=== --EXPECT-- int(1) ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getmatchedcount-002.phpt0000644000175100001660000000173114760300421022574 0ustar --TEST-- MongoDB\Driver\WriteResult::getMatchedCount() with unacknowledged write --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(0)]); var_dump($result->getMatchedCount()); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\WriteResult::getMatchedCount(): Calling MongoDB\Driver\WriteResult::getMatchedCount() for an unacknowledged write is deprecated and will throw an exception in %s NULL ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getmodifiedcount-001.phpt0000644000175100001660000000134514760300421022747 0ustar --TEST-- MongoDB\Driver\WriteResult::getModifiedCount() with acknowledged write --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getModifiedCount()); ?> ===DONE=== --EXPECT-- int(1) ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getmodifiedcount-002.phpt0000644000175100001660000000176014760300421022751 0ustar --TEST-- MongoDB\Driver\WriteResult::getModifiedCount() with unacknowledged write --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(0)]); var_dump($result->getModifiedCount()); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\WriteResult::getModifiedCount(): Calling MongoDB\Driver\WriteResult::getModifiedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getserver-001.phpt0000644000175100001660000000114314760300421021420 0ustar --TEST-- MongoDB\Driver\WriteResult::getUpsertedIds() --SKIPIF-- --FILE-- selectServer(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::PRIMARY)); $bulk = new MongoDB\Driver\BulkWrite; $bulk->insert(['x' => 1]); $result = $server->executeBulkWrite(NS, $bulk); var_dump($result->getServer() == $server); ?> ===DONE=== --EXPECT-- bool(true) ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getupsertedcount-001.phpt0000644000175100001660000000134514760300421023022 0ustar --TEST-- MongoDB\Driver\WriteResult::getUpsertedCount() with acknowledged write --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getUpsertedCount()); ?> ===DONE=== --EXPECT-- int(2) ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getupsertedcount-002.phpt0000644000175100001660000000176014760300421023024 0ustar --TEST-- MongoDB\Driver\WriteResult::getUpsertedCount() with unacknowledged write --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(0)]); var_dump($result->getUpsertedCount()); ?> ===DONE=== --EXPECTF-- Deprecated: MongoDB\Driver\WriteResult::getUpsertedCount(): Calling MongoDB\Driver\WriteResult::getUpsertedCount() for an unacknowledged write is deprecated and will throw an exception in ext-mongodb 2.0 in %s NULL ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getupsertedids-001.phpt0000644000175100001660000000163514760300421022453 0ustar --TEST-- MongoDB\Driver\WriteResult::getUpsertedIds() with server-generated values --SKIPIF-- --FILE-- insert(['x' => 1]); $bulk->update(['x' => 1], ['$set' => ['y' => 3]]); $bulk->update(['x' => 2], ['$set' => ['y' => 1]], ['upsert' => true]); $bulk->update(['x' => 3], ['$set' => ['y' => 2]], ['upsert' => true]); $bulk->delete(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getUpsertedIds()); ?> ===DONE=== --EXPECTF-- array(2) { [2]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } [3]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "%x" } } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getupsertedids-002.phpt0000644000175100001660000000433014760300421022447 0ustar --TEST-- MongoDB\Driver\WriteResult::getUpsertedIds() with client-generated values --SKIPIF-- --FILE-- update(['_id' => $value], ['$set' => ['x' => 1]], ['upsert' => true]); } $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getUpsertedIds()); ?> ===DONE=== --EXPECTF-- array(14) { [0]=> NULL [1]=> bool(true) [2]=> int(1) [3]=> float(4.125) [4]=> string(3) "foo" [5]=> object(stdClass)#%d (%d) { } [6]=> object(MongoDB\BSON\Binary)#%d (%d) { ["data"]=> string(3) "foo" ["type"]=> int(0) } [7]=> object(MongoDB\BSON\Decimal128)#%d (%d) { ["dec"]=> string(9) "1234.5678" } [8]=> object(MongoDB\BSON\Javascript)#%d (%d) { ["code"]=> string(12) "function(){}" ["scope"]=> NULL } [9]=> object(MongoDB\BSON\MaxKey)#%d (%d) { } [10]=> object(MongoDB\BSON\MinKey)#%d (%d) { } [11]=> object(MongoDB\BSON\ObjectId)#%d (%d) { ["oid"]=> string(24) "586c18d86118fd6c9012dec1" } [12]=> object(MongoDB\BSON\Timestamp)#%d (%d) { ["increment"]=> string(4) "1234" ["timestamp"]=> string(4) "5678" } [13]=> object(MongoDB\BSON\UTCDateTime)#%d (%d) { ["milliseconds"]=> string(13) "1483479256924" } } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getwriteconcernerror-001.phpt0000644000175100001660000000154614760300421023675 0ustar --TEST-- MongoDB\Driver\WriteResult::getWriteConcernError() --SKIPIF-- --FILE-- insert(['x' => 1]); try { /* We assume that the replica set does not have 12 nodes */ $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => new MongoDB\Driver\WriteConcern(12)]); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteConcernError()); } ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcernError)#%d (%d) { ["message"]=> string(29) "Not enough data-bearing nodes" ["code"]=> int(100) ["info"]=> %a } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getwriteconcernerror-002.phpt0000644000175100001660000000202114760300421023663 0ustar --TEST-- MongoDB\Driver\WriteResult::getWriteConcernError() works for errors without a message --SKIPIF-- --FILE-- false]); // Configure a fail point triggering a write concern error without message configureFailPoint( $manager, 'failCommand', ['times' => 1], [ 'failCommands' => ['insert'], 'writeConcernError' => ['code' => 91], ] ); $bulk = new MongoDB\Driver\BulkWrite(); $bulk->insert(['write' => 1]); $result = $manager->executeBulkWrite(NS, $bulk); var_dump($result->getWriteConcernError()); configureFailPoint($manager, 'failCommand', 'off'); ?> ===DONE=== --EXPECTF-- object(MongoDB\Driver\WriteConcernError)#%d (%d) { ["message"]=> string(0) "" ["code"]=> int(91) ["info"]=> NULL } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getwriteerrors-001.phpt0000644000175100001660000000201214760300421022475 0ustar --TEST-- MongoDB\Driver\WriteResult::getWriteErrors() with ordered execution --SKIPIF-- --FILE-- insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $bulk->insert(['_id' => 4]); $bulk->insert(['_id' => 4]); try { $result = $manager->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteErrors()); } ?> ===DONE=== --EXPECTF-- array(1) { [0]=> object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "%SE11000 duplicate key error %s: phongo.writeResult_writeresult_getwriteerrors_001%sdup key: { %S: 2 }" ["code"]=> int(11000) ["index"]=> int(2) ["info"]=> NULL } } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-getwriteerrors-002.phpt0000644000175100001660000000246714760300421022514 0ustar --TEST-- MongoDB\Driver\WriteResult::getWriteErrors() with unordered execution --SKIPIF-- --FILE-- false]); $bulk->insert(['_id' => 1]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 2]); $bulk->insert(['_id' => 3]); $bulk->insert(['_id' => 4]); $bulk->insert(['_id' => 4]); try { $result = $manager->executeBulkWrite(NS, $bulk); } catch (MongoDB\Driver\Exception\BulkWriteException $e) { var_dump($e->getWriteResult()->getWriteErrors()); } ?> ===DONE=== --EXPECTF-- array(2) { [0]=> object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "%SE11000 duplicate key error %s: phongo.writeResult_writeresult_getwriteerrors_002%sdup key: { %S: 2 }" ["code"]=> int(11000) ["index"]=> int(2) ["info"]=> NULL } [1]=> object(MongoDB\Driver\WriteError)#%d (%d) { ["message"]=> string(%d) "%SE11000 duplicate key error %s: phongo.writeResult_writeresult_getwriteerrors_002%sdup key: { %S: 4 }" ["code"]=> int(11000) ["index"]=> int(5) ["info"]=> NULL } } ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult-isacknowledged-001.phpt0000644000175100001660000000123514760300421022377 0ustar --TEST-- MongoDB\Driver\WriteResult::isAcknowledged() --SKIPIF-- --FILE-- insert(['x' => 1]); $result = $manager->executeBulkWrite(NS, $bulk, ['writeConcern' => $wc]); var_dump($result->isAcknowledged()); } ?> ===DONE=== --EXPECT-- bool(false) bool(true) ===DONE=== mongodb-1.21.0/tests/writeResult/writeresult_error-001.phpt0000644000175100001660000000041614760300421020627 0ustar --TEST-- MongoDB\Driver\WriteResult cannot be extended --FILE-- ===DONE=== --EXPECTF-- Fatal error: Class MyWriteResult %s final class %SMongoDB\Driver\WriteResult%S in %s on line %d mongodb-1.21.0/CONTRIBUTING.md0000644000175100001660000003145214760300421012374 0ustar # Contributing to the PHP Driver for MongoDB ## Building from Source Developers who would like to contribute to the driver will need to build it from source. The repository may be initialized with: ``` $ git clone https://github.com/mongodb/mongo-php-driver.git $ cd mongo-php-driver $ git submodule update --init ``` The following script may be used to build the driver: ``` #!/bin/sh phpize > /dev/null && \ ./configure --enable-mongodb-developer-flags > /dev/null && \ make clean > /dev/null && make all > /dev/null && make install ``` To verify that the installation was successful, run the following command, which will report `phpinfo()` output for the extension: ``` $ php --ri mongodb ``` ## Generating arginfo from stub files Arginfo structures are generated from stub files using the `gen_stub.php` file. Note that this requires `phpize` to be run for **PHP 8.2** to make use of all features. After changing a stub file, run `./build/gen_stub.php` to regenerate the corresponding arginfo files and commit the results. ## Generating function maps for static analysis tools PHPStan and Psalm use function maps to provide users with correct type analysis when using this extension. To generate the function map, run the `generate-function-map` make target. The generated map will be stored in `scripts/functionMap.php`. ## Testing The driver includes a test suite that can be run with `make test`. To run a single test file, define the `TESTS` variable with the file path: ``` make test TESTS=tests/.phpt ``` ### File format The extension's test use the PHPT format from PHP internals. This format is documented in the following links: * [Introduction to PHPT Files](https://qa.php.net/write-test.php) * [PHPT - Test File Layout](https://qa.php.net/phpt_details.php) Generally, most tests will be based on the following template: ``` --TEST-- Description of API or JIRA issue being tested --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- ===DONE=== ``` The `basic-skipif.inc` and `basic.inc` files contain utility functions for the `SKIPIF` and `FILE` sections, respectively. If those functions are not needed (e.g. skip logic only depends on checking the `PHP_INT_SIZE` constant), the test should not include the file. When it doubt, keep it simple. ### Best Practices for `SKIPIF` The [`skipif.php`](tests/utils/skipif.php) file defines various helper functions for use within a test's [`SKIPIF`](https://qa.php.net/phpt_details.php#skipif_section) section. When multiple functions are used in a single `SKIPIF` section, they should be logically ordered: * Any PHP environment requirements should be checked first. For example, if a test requires a 64-bit architecture, start by checking `PHP_INT_SIZE` before anything else. * Any extension build requirements (e.g. `skip_if_not_libmongoc_crypto()`) or test environment requirements (e.g. `skip_if_auth()`) should then be checked. These functions only examine local information, such as `phpinfo()` output or the structure of the `URI` constant, and do not interact with a remote MongoDB server. * Any remote server requirements should then be checked. A general integration test that requires any type of remote server to be accessible might use `skip_if_not_live()` while a test requiring a replica set would prefer `skip_if_not_replica_set()`. * After requiring a remote server to be accessible (optionally with a specific type), you can enforce requirements about that server. This includes checking its server version, storage engine, availability of test commands, etc. * Finally, use `skip_if_not_clean()` if needed to ensure that the collection(s) under test are dropped before the test runs. As a rule of thumb, your `SKIPIF` logic should be written to allow the test to run in as many environments as possible. To paraphrase the [robustness principal](https://en.wikipedia.org/wiki/Robustness_principle): > Be conservative in what/how you test, and liberal in what environment you require Consider that a well-crafted `EXPECTF` section may allow a `SKIPIF` section to be less restrictive. ### Environment Variables The test suite references the following environment variables: * `MONGODB_DATABASE`: Default database to use in tests. Defaults to `phongo`. * `MONGO_ORCHESTRATION_URI`: API endpoint for [Mongo Orchestration](https://github.com/10gen/mongo-orchestration). Defaults to `http://localhost:8889/v1`. This is only used by a few tests that start temporary servers, and those tests will be skipped if Mongo Orchestration is inaccessible. * `MONGODB_URI`: Connection string. Defaults to `mongodb://127.0.0.1/`, which assumes a MongoDB server is listening on localhost port 27017. * `SSL_DIR`: Path to directory containing certificate files. On Evergreen, this will be set to the [.evergreen/x509gen](https://github.com/mongodb-labs/drivers-evergreen-tools/tree/master/.evergreen/x509gen) directory within [drivers-evergreen-tools](https://github.com/mongodb-labs/drivers-evergreen-tools). If undefined or inaccessible, tests requiring certificates will be skipped. The following environment variable is used for [stable API testing](https://github.com/mongodb/specifications/blob/master/source/versioned-api/tests/README.rst): * `API_VERSION`: If defined, this value will be used to construct a [`MongoDB\Driver\ServerApi`](https://www.php.net/manual/en/mongodb-driver-serverapi.construct.php), which will then be specified as the `serverApi` driver option for [`MongoDB\Driver\Manager`](https://www.php.net/manual/en/class.mongodb-driver-manager.php) objects created by the test suite. The following environment variables are used for [CSFLE testing](https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst): * `CRYPT_SHARED_LIB_PATH`: If defined, this value will be used to set the `cryptSharedLibPath` autoEncryption driver option for [`MongoDB\Driver\Manager`](https://www.php.net/manual/en/class.mongodb-driver-manager.php) objects created by the test suite. ### Mongo Orchestration [Mongo Orchestration](https://github.com/10gen/mongo-orchestration) is an HTTP server that provides a REST API for managing MongoDB servers and clusters. Evergreen CI and GitHub Actions use configurations provided by the [drivers-evergreen-tools](https://github.com/mongodb-labs/drivers-evergreen-tools) repository. These configurations are loaded by Mongo Orchestration, which then provides a connection string to assign to `MONGODB_URI` and run the test suite. Additionally, some tests start temporary servers and interact directly with Mongo Orchestration (via `MONGO_ORCHESTRATION_URI`). For local development, running Mongo Orchestration is not required and it is generally sufficient to test against a single-node replica set. ## Updating libmongoc, libbson, and libmongocrypt The PHP driver can use either system libraries or bundled versions of libmongoc, libbson, and libmongocrypt. If a new version of either library is available, the submodule and build configuration will need to be updated to reflect the new sources and/or package version. ### Resolving Submodule Conflicts When Merging Maintenance Branches When merging a maintenance branch up to master, it is quite possible for there to be a submodule conflict (and in related files). Resolving a merge conflict should never result in downgrading a submodule to an older version. Rather, the submodule should be conservatively advanced and satisfy any requirements for incoming changes from the maintenance branch. For example, the 1.14.2 release bumped libmongoc from 1.22.1 to 1.22.2. When merging v1.14 into master (1.15-dev), a conflict arose because the libmongoc submodule in master pointed to a 1.23-dev commit (before the 1.23.0 release). In this case, there were no particular requirements for incoming changes from the v1.14 branch and the libmongoc submodule was bumped to 1.23.0 even though a 1.23.1 tag also existed at the time. The bump to libmongoc 1.23.1 was left to another PHPC ticket in the 1.15.0 milestone, which actually depended on the libmongoc changes therein. ### Updating bundled libraries The following steps are the same for libmongoc and libmongocrypt. When updating libmongocrypt, follow the same steps but replace `libmongoc` with `libmongocrypt`, retaining the same capitalization. The following examples always refer to libmongoc. #### Update submodule ```shell cd src/libmongoc git fetch git checkout 1.20.0 ``` During development, it may be necessary to temporarily point the submodule to a commit on the developer's fork. For instance, the developer may be working on a PHP driver feature that depends on unmerged or unreleased changes. In this case, the submodule path can be updated using the `git submodules set-url` command can be used to change the URL, and `git submodules set-branch` can be used to point the submodule to a development branch: ```shell git submodules set-url src/libmongoc https://github.com//.git git submodules set-branch -b src/libmongoc ``` #### Ensure version information is correct Various build processes and tools rely on the version files to infer version information. This file can be regenerated using Makefile targets: ```shell make libmongoc-version-current ``` Alternatively, the `build/calc_release_version.py` script in the submodule can be executed directly. Note: If the submodule points to a non-release, non-master branch, the script may fail to correctly detect the version. This issue is being tracked in [CDRIVER-3315](https://jira.mongodb.org/browse/CDRIVER-3315) and can be safely ignored since this should only happen during development (any PHP driver release should point to a tagged submodule version). #### Update sources in build configurations The Autotools and Windows build configurations (`config.m4` and `config.w32`, respectively) define several variables (e.g. `PHP_MONGODB_MONGOC_SOURCES`) that collectively enumerate all of the sources within the submodules to include in a bundled build. These variables should each have a shell command in a preceding comment, which should be run to regenerate that particular list of source files. Each command may be run manually or `scripts/update-submodule-sources.php` may be used to update all variables. In the event that a new source directory is introduced, this directory will need to be manually added following prior art. #### Update package dependencies The Autotools configuration additionally includes some `pkg-config` commands for using libmongoc, libbson, and libmongocrypt as system libraries (in lieu of a bundled build). When bumping the bundled version, be sure to update the version check _and_ error message in the `pkg-config` blocks for the submodule being updated. When updating libmongoc, be sure to update both version checks for libmongoc and libbson. For example, the following lines might be updated for libmongoc: ``` if $PKG_CONFIG libmongoc-1.0 --atleast-version 1.20.0; then ... AC_MSG_ERROR(system libmongoc must be upgraded to version >= 1.20.0) ``` #### Update tested versions in Evergreen configuration (libmongoc only) Evergreen tests against multiple versions of libmongoc. When updating to a newer libmongoc version, make sure to update the libmongoc build tasks in `.evergreen/config/templates/build/build-libmongoc.yml` and regenerate the build configuration. The template file contains additional information about the build tasks and where they are used. In general, we test against two additional versions of libmongoc: - The upcoming patch release of the current libmongoc minor version (e.g. the `r1.x` branch) - The upcoming minor release of libmongoc (e.g. the `master` branch) #### Update sources in PECL package generation script If a new version of a submodule introduces a new source directory, that may also require updating the glob patterns in the `bin/prep-release.php` script to ensure new source files will be included in any generated PECL package. #### Update SBOM file After updating dependencies, the SBOM file needs to be updated. There is a script to automate this process: ```shell ./scripts/update-sbom.sh ``` This script will generate a temporary purl file with our dependencies, then run the internal silkbomb tool to update the SBOM. Note that you need to have docker installed in order to run this. #### Test and commit your changes Verify that the upgrade was successful by ensuring that the driver can compile using both the bundled sources and system libraries, and by ensuring that the test suite passes. Once done, commit the changes to all of the above files/paths. For example: ```shell git commit -m "Bump libmongoc to 1.20.0" config.m4 config.w32 src/libmongoc src/LIBMONGOC_VERSION_CURRENT sbom.json ``` mongodb-1.21.0/CREDITS0000644000175100001660000000006414760300421011156 0ustar MongoDB Driver for PHP Andreas Braun, Jeremy Mikola mongodb-1.21.0/LICENSE0000644000175100001660000002613714760300421011154 0ustar Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mongodb-1.21.0/Makefile.frag0000644000175100001660000001221014760300421012510 0ustar .PHONY: mv-coverage lcov-coveralls lcov-local coverage coveralls format format-changed format-check test-clean package package.xml libmongoc-version-current libmongocrypt-version-current generate-function-map ifneq (,$(realpath $(EXTENSION_DIR)/json.so)) PHP_TEST_SHARED_EXTENSIONS := "-d" "extension=$(EXTENSION_DIR)/json.so" $(PHP_TEST_SHARED_EXTENSIONS) PHP_TEST_SETTINGS := "-d" "extension=$(EXTENSION_DIR)/json.so" $(PHP_TEST_SETTINGS) endif DATE=`date +%Y-%m-%d--%H-%M-%S` MONGODB_VERSION=$(shell php -n -dextension=modules/mongodb.so -r 'echo MONGODB_VERSION;') MONGODB_MINOR=$(shell echo $(MONGODB_VERSION) | cut -d. -f1,2) MONGODB_STABILITY=$(shell php -n -dextension=modules/mongodb.so -r 'echo MONGODB_STABILITY;') help: @echo "" @echo -e "\t$$ make coveralls" @echo -e "\t - Creates code coverage report using coveralls" @echo -e "\t$$ make coverage" @echo -e "\t - Creates code coverage report using gcov" @echo "" @echo -e "\t$$ make package.xml" @echo -e "\t - Creates a package.xml file with empty release notes" @echo -e "\t$$ make package.xml RELEASE_NOTES_FILE=changelog" @echo -e "\t - Creates a package.xml file with release notes read from the indicated file" @echo -e "\t$$ make package" @echo -e "\t - Creates the pecl archive to use for provisioning" mv-coverage: @if test -e $(top_srcdir)/coverage; then \ echo "Moving previous coverage run to coverage-$(DATE)"; \ mv coverage coverage-$(DATE); \ fi lcov-coveralls: lcov --gcov-tool $(top_srcdir)/.llvm-cov.sh --capture --directory . --output-file .coverage.lcov --no-external lcov-local: lcov --gcov-tool $(top_srcdir)/.llvm-cov.sh --capture --derive-func-data --directory . --output-file .coverage.lcov --no-external coverage: mv-coverage lcov-local genhtml .coverage.lcov --legend --title "mongodb code coverage" --output-directory coverage coveralls: mv-coverage lcov-coveralls coveralls --exclude src/libbson --exclude src/libmongoc --exclude src/contrib --exclude lib --exclude tests format: $(top_srcdir)/scripts/clang-format.sh format-changed: $(top_srcdir)/scripts/clang-format.sh changed format-check: $(top_srcdir)/scripts/clang-format.sh check test-clean: find $(top_srcdir)/tests -not \( -path $(top_srcdir)/tests/utils -prune \) -type f -name "*.diff" -o -name "*.exp" -o -name "*.log" -o -name "*.mem" -o -name "*.out" -o -name "*.php" -o -name "*.sh" | xargs -r rm package: pecl package package.xml package.xml: php bin/prep-release.php $(MONGODB_VERSION) $(MONGODB_STABILITY) $(RELEASE_NOTES_FILE) libmongoc-version-current: cd src/libmongoc/ && python build/calc_release_version.py > ../LIBMONGOC_VERSION_CURRENT libmongocrypt-version-current: cd src/libmongocrypt/ && python etc/calc_release_version.py > ../LIBMONGOCRYPT_VERSION_CURRENT generate-function-map: all @if test ! -z "$(PHP_EXECUTABLE)" && test -x "$(PHP_EXECUTABLE)"; then \ INI_FILE=`$(PHP_EXECUTABLE) -d 'display_errors=stderr' -r 'echo php_ini_loaded_file();' 2> /dev/null`; \ if test "$$INI_FILE"; then \ $(EGREP) -h -v $(PHP_DEPRECATED_DIRECTIVES_REGEX) "$$INI_FILE" > $(top_builddir)/tmp-php.ini; \ else \ echo > $(top_builddir)/tmp-php.ini; \ fi; \ INI_SCANNED_PATH=`$(PHP_EXECUTABLE) -d 'display_errors=stderr' -r '$$a = explode(",\n", trim(php_ini_scanned_files())); echo $$a[0];' 2> /dev/null`; \ if test "$$INI_SCANNED_PATH"; then \ INI_SCANNED_PATH=`$(top_srcdir)/build/shtool path -d $$INI_SCANNED_PATH`; \ $(EGREP) -h -v $(PHP_DEPRECATED_DIRECTIVES_REGEX) "$$INI_SCANNED_PATH"/*.ini >> $(top_builddir)/tmp-php.ini; \ fi; \ CC="$(CC)" \ $(PHP_EXECUTABLE) -n -c $(top_builddir)/tmp-php.ini -n -c $(top_builddir)/tmp-php.ini -d extension_dir=$(top_builddir)/modules/ $(PHP_TEST_SHARED_EXTENSIONS) $(top_srcdir)/scripts/generate-functionmap.php; \ RESULT_EXIT_CODE=$$?; \ rm $(top_builddir)/tmp-php.ini; \ exit $$RESULT_EXIT_CODE; \ else \ echo "ERROR: Cannot generate function maps without CLI sapi."; \ fi test-no-build: @if test ! -z "$(PHP_EXECUTABLE)" && test -x "$(PHP_EXECUTABLE)"; then \ INI_FILE=`$(PHP_EXECUTABLE) -d 'display_errors=stderr' -r 'echo php_ini_loaded_file();' 2> /dev/null`; \ if test "$$INI_FILE"; then \ $(EGREP) -h -v $(PHP_DEPRECATED_DIRECTIVES_REGEX) "$$INI_FILE" > $(top_builddir)/tmp-php.ini; \ else \ echo > $(top_builddir)/tmp-php.ini; \ fi; \ INI_SCANNED_PATH=`$(PHP_EXECUTABLE) -d 'display_errors=stderr' -r '$$a = explode(",\n", trim(php_ini_scanned_files())); echo $$a[0];' 2> /dev/null`; \ if test "$$INI_SCANNED_PATH"; then \ INI_SCANNED_PATH=`$(top_srcdir)/build/shtool path -d $$INI_SCANNED_PATH`; \ $(EGREP) -h -v $(PHP_DEPRECATED_DIRECTIVES_REGEX) "$$INI_SCANNED_PATH"/*.ini >> $(top_builddir)/tmp-php.ini; \ fi; \ TEST_PHP_EXECUTABLE=$(PHP_EXECUTABLE) \ TEST_PHP_SRCDIR=$(top_srcdir) \ CC="$(CC)" \ $(PHP_EXECUTABLE) -n -c $(top_builddir)/tmp-php.ini $(PHP_TEST_SETTINGS) $(top_srcdir)/run-tests.php -n -c $(top_builddir)/tmp-php.ini -d extension_dir=$(top_builddir)/modules/ $(PHP_TEST_SHARED_EXTENSIONS) $(TESTS); \ TEST_RESULT_EXIT_CODE=$$?; \ rm $(top_builddir)/tmp-php.ini; \ exit $$TEST_RESULT_EXIT_CODE; \ else \ echo "ERROR: Cannot run tests without CLI sapi."; \ fi mongodb-1.21.0/README.md0000644000175100001660000001071014760300421011414 0ustar # MongoDB PHP Driver [![Tests](https://github.com/mongodb/mongo-php-driver/actions/workflows/tests.yml/badge.svg)](https://github.com/mongodb/mongo-php-driver/actions/workflows/tests.yml) [![Coverage Status](https://coveralls.io/repos/github/mongodb/mongo-php-driver/badge.svg?branch=master)](https://coveralls.io/github/mongodb/mongo-php-driver?branch=master) [![Coding Standards](https://github.com/mongodb/mongo-php-driver/actions/workflows/clang-format.yml/badge.svg)](https://github.com/mongodb/mongo-php-driver/actions/workflows/clang-format.yml) This extension is developed atop the [libmongoc](https://github.com/mongodb/mongo-c-driver) and [libbson](https://github.com/mongodb/libbson) libraries. It provides a minimal API for core driver functionality: commands, queries, writes, connection management, and BSON serialization. Userland PHP libraries that depend on this extension may provide higher level APIs, such as query builders, individual command helper methods, and GridFS. Application developers should consider using this extension in conjunction with the [MongoDB PHP library](https://github.com/mongodb/mongo-php-library), which implements the same higher level APIs found in MongoDB drivers for other languages. ## Documentation - https://www.php.net/mongodb - https://www.mongodb.com/docs/drivers/php-drivers/ ## Installation To build and install the driver: $ pecl install mongodb $ echo "extension=mongodb.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` Additional installation instructions may be found in the [PHP.net documentation](https://php.net/manual/en/mongodb.installation.php). This extension is intended to be used alongside the [MongoDB PHP Library](https://github.com/mongodb/mongo-php-library), which is distributed as the [`mongodb/mongodb`](https://packagist.org/packages/mongodb/mongodb) package for [Composer](https://getcomposer.org). ## Release Integrity Releases are created automatically and signed using the [PHP team's GPG key](https://pgp.mongodb.com/php-driver.asc). This applies to the git tag as well as all release packages provided as part of a [GitHub release](https://github.com/mongodb/mongo-php-library/releases). To verify the provided packages, download the key and import it using `gpg`: ```shell gpg --import php-driver.asc ``` ### PECL package PECL packages are made available as release artifacts on GitHub, as well as on the [PECL homepage](https://pecl.php.net/mongodb). The GitHub release will also contain a detached signature file for the PECL package (named `mongodb-X.Y.Z.tgz.sig`). To verify the integrity of the downloaded package, run the following command: ```shell gpg --verify mongodb-X.Y.Z.tgz.sig mongodb-X.Y.Z.tgz ``` > [!NOTE] > No verification is done when using `pecl` to install the package. To ensure > release integrity when using `pecl`, download the tarball manually from the > GitHub release, verify the signature, then install the package from the > downloaded tarball using `pecl install mongodb-X.Y.Z.tgz`. ### Windows Windows binaries distributed through GitHub releases contain a detached signature for the `php_mongodb.dll` file named `php_mongodb.dll.sig`. To verify the integrity of the DLL, run the following command: ```shell gpg --verify php_mongodb.dll.sig php_mongodb.dll.tgz ``` > [!NOTE] > Windows binaries distributed directly through PECL are not signed by MongoDB > and cannot be verified. If you need to verify the integrity of the downloaded > binary, always download them from the GitHub release. ## Reporting Issues Issues pertaining to the extension should be reported in the [PHPC](https://jira.mongodb.org/secure/CreateIssue!default.jspa?project-field=PHPC) project in MongoDB's JIRA. Library-related issues should be reported in the [PHPLIB](https://jira.mongodb.org/secure/CreateIssue!default.jspa?project-field=PHPLIB) project. For general questions and support requests, please use one of MongoDB's [Technical Support](https://docs.mongodb.com/manual/support/) channels. ### Security Vulnerabilities If you've identified a security vulnerability in a driver or any other MongoDB project, please report it according to the instructions in [Create a Vulnerability Report](https://docs.mongodb.org/manual/tutorial/create-a-vulnerability-report). ## Development Development is tracked in the [PHPC](https://jira.mongodb.org/projects/PHPC/summary) project in MongoDB's JIRA. Documentation for contributing to this project may be found in [CONTRIBUTING.md](CONTRIBUTING.md). mongodb-1.21.0/THIRD_PARTY_NOTICES0000644000175100001660000000707414760300421013106 0ustar The MongoDB PHP Driver uses third-party code distributed under different licenses. The MongoDB PHP Driver uses libbson and libmongoc, which also use third-party code distributed under difference licenses. See src/libbson/THIRD_PARTY_NOTICES and src/libmongoc/THIRD_PARTY_NOTICES for additional information. License notice for php_array_api.h ------------------------------------------------------------------------------- -------------------------------------------------------------------- The PHP License, version 3.01 Copyright (c) 1999 - 2014 The PHP Group. All rights reserved. -------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name "PHP" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact group@php.net. 4. Products derived from this software may not be called "PHP", nor may "PHP" appear in their name, without prior written permission from group@php.net. You may indicate that your software works in conjunction with PHP by saying "Foo for PHP" instead of calling it "PHP Foo" or "phpfoo" 5. The PHP Group may publish revised and/or new versions of the license from time to time. Each version will be given a distinguishing version number. Once covered code has been published under a particular version of the license, you may always continue to use it under the terms of that version. You may also choose to use such covered code under the terms of any subsequent version of the license published by the PHP Group. No one other than the PHP Group has the right to modify the terms applicable to covered code created under this License. 6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes PHP software, freely available from ". THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND ANY EXPRESSED 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 PHP DEVELOPMENT TEAM OR ITS 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. -------------------------------------------------------------------- This software consists of voluntary contributions made by many individuals on behalf of the PHP Group. The PHP Group can be contacted via Email at group@php.net. For more information on the PHP Group and the PHP project, please see . PHP includes the Zend Engine, freely available at . mongodb-1.21.0/Vagrantfile0000644000175100001660000000322714760300421012327 0ustar # -*- mode: ruby -*- # vi: set ft=ruby et sw=2 : Vagrant.configure(2) do |config| config.vm.synced_folder ".", "/phongo" config.vm.provider "vmware_workstation" do |vmware, override| vmware.vmx["memsize"] = "8192" vmware.vmx["numvcpus"] = "2" end config.vm.provider "virtualbox" do |virtualbox| virtualbox.memory = 2048 virtualbox.cpus = 2 end config.vm.define "mo", primary: true do |mo| mo.vm.network "private_network", ip: "192.168.112.10" mo.vm.box = "ubuntu/trusty64" mo.vm.provision "shell", path: "scripts/ubuntu/essentials.sh", privileged: true mo.vm.provision "file", source: "scripts/ubuntu/get-pip.py", destination: "get-pip.py" mo.vm.provision "file", source: "scripts/ubuntu/mongo-orchestration-config.json", destination: "mongo-orchestration-config.json" mo.vm.provision "shell", path: "scripts/ubuntu/mongo-orchestration.sh", privileged: true mo.vm.provision "shell", path: "scripts/ubuntu/ldap/install.sh", privileged: true end config.vm.define "ldap", autostart: false do |ldap| ldap.vm.network "private_network", ip: "192.168.112.20" ldap.vm.box = "http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box" ldap.vm.provider "vmware_workstation" do |vmware, override| override.vm.box_url = "https://dl.dropbox.com/u/5721940/vagrant-boxes/vagrant-centos-6.4-x86_64-vmware_fusion.box" override.vm.provision "shell", path: "scripts/vmware/kernel.sh", privileged: true end ldap.vm.provision "shell", path: "scripts/centos/essentials.sh", privileged: true ldap.vm.provision "shell", path: "scripts/centos/ldap/install.sh", privileged: true end end mongodb-1.21.0/config.m40000644000175100001660000007770414760300421011664 0ustar dnl Determine the base directory used for subsequent m4_include calls m4_define(PHP_MONGODB_BASEDIR, esyscmd(printf %s "$(dirname "__file__")")) PHP_ARG_ENABLE([mongodb], [whether to enable MongoDB support], [AS_HELP_STRING([--enable-mongodb], [Enable MongoDB support])]) if test "$PHP_MONGODB" != "no"; then dnl Common includes for both bundled and system builds m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/m4/php_mongodb.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/m4/pkg.m4) PKG_PROG_PKG_CONFIG dnl Enable C99 (required for libmongoc 1.24+). On Autoconf 2.70+, this will dnl already have been done when AC_PROG_CC is called from configure.ac. m4_version_prereq([2.70],,[AC_PROG_CC_C99]) if test "$ac_cv_prog_cc_c99" = no; then AC_MSG_ERROR([Compiler does not support C99]) fi dnl Check PHP version is compatible with this extension AC_MSG_CHECKING([PHP version]) if test -z "${PHP_VERSION_ID}"; then if test -z "$PHP_CONFIG"; then AC_MSG_ERROR([php-config not found]) fi PHP_MONGODB_PHP_VERSION=`${PHP_CONFIG} --version` PHP_MONGODB_PHP_VERSION_ID=`${PHP_CONFIG} --vernum` else PHP_MONGODB_PHP_VERSION="${PHP_VERSION}" PHP_MONGODB_PHP_VERSION_ID="${PHP_VERSION_ID}" fi AC_MSG_RESULT($PHP_MONGODB_PHP_VERSION) if test "$PHP_MONGODB_PHP_VERSION_ID" -lt "80100"; then AC_MSG_ERROR([not supported. Need a PHP version >= 8.1.0 (found $PHP_MONGODB_PHP_VERSION)]) fi PHP_MONGODB_STD_CFLAGS="" PHP_MONGODB_DEV_CFLAGS="" PHP_MONGODB_COVERAGE_CFLAGS="" PHP_ARG_ENABLE([mongodb-developer-flags], [whether to enable developer build flags], [AS_HELP_STRING([--enable-mongodb-developer-flags], [MongoDB: Enable developer flags [default=no]])], [no], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_DEVELOPER_FLAGS], [yes no]) if test "$PHP_MONGODB_DEVELOPER_FLAGS" = "yes"; then PHP_MONGODB_STD_CFLAGS="-g -O0 -Wall" dnl Warn about functions which might be candidates for format attributes AX_CHECK_COMPILE_FLAG(-Wmissing-format-attribute, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wmissing-format-attribute" ,, -Werror) dnl Avoid duplicating values for an enum AX_CHECK_COMPILE_FLAG(-Wduplicate-enum, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wduplicate-enum" ,, -Werror) dnl Warns on mismatches between #ifndef and #define header guards AX_CHECK_COMPILE_FLAG(-Wheader-guard, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wheader-guard" ,, -Werror) dnl logical not of a non-boolean expression AX_CHECK_COMPILE_FLAG(-Wlogical-not-parentheses, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wlogical-not-parentheses" ,, -Werror) dnl Warn about suspicious uses of logical operators in expressions AX_CHECK_COMPILE_FLAG(-Wlogical-op, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wlogical-op" ,, -Werror) dnl memory error detector. dnl FIXME: -fsanitize=address,undefined for clang. The AX_CHECK_COMPILE_FLAG macro isn't happy about that string :( AX_CHECK_COMPILE_FLAG(-fsanitize-address, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -fsanitize-address" ,, -Werror) dnl Enable frame debugging AX_CHECK_COMPILE_FLAG(-fno-omit-frame-pointer, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -fno-omit-frame-pointer" ,, -Werror) dnl Make sure we don't optimize calls AX_CHECK_COMPILE_FLAG(-fno-optimize-sibling-calls, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -fno-optimize-sibling-calls" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wlogical-op-parentheses, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wlogical-op-parentheses" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wpointer-bool-conversion, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wpointer-bool-conversion" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wbool-conversion, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wbool-conversion" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wloop-analysis, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wloop-analysis" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wsizeof-array-argument, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wsizeof-array-argument" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wstring-conversion, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wstring-conversion" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wno-variadic-macros, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wno-variadic-macros" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wno-sign-compare, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wno-sign-compare" ,, -Werror) AX_CHECK_COMPILE_FLAG(-fstack-protector, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -fstack-protector" ,, -Werror) AX_CHECK_COMPILE_FLAG(-fno-exceptions, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -fno-exceptions" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wformat-security, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wformat-security" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wformat-nonliteral, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wformat-nonliteral" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Winit-self, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Winit-self" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wwrite-strings, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wwrite-strings" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wenum-compare, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wenum-compare" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wempty-body, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wempty-body" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wparentheses, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wparentheses" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wmaybe-uninitialized, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wmaybe-uninitialized" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wimplicit-fallthrough, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wimplicit-fallthrough" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Werror, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Werror" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wextra, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wextra" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wno-unused-parameter, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wno-unused-parameter" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wno-unused-but-set-variable, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wno-unused-but-set-variable" ,, -Werror) AX_CHECK_COMPILE_FLAG(-Wno-missing-field-initializers, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wno-missing-field-initializers",, -Werror) if test "$PHP_MONGODB_PHP_VERSION_ID" -ge "80108"; then AX_CHECK_COMPILE_FLAG(-Wstrict-prototypes, PHP_MONGODB_DEV_CFLAGS="$PHP_MONGODB_DEV_CFLAGS -Wstrict-prototypes",, -Werror) fi fi PHP_ARG_ENABLE([mongodb-coverage], [whether to enable code coverage], [AS_HELP_STRING([--enable-mongodb-coverage], [MongoDB: Enable developer code coverage information [default=no]])], [no], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_COVERAGE], [yes no]) if test "$PHP_MONGODB_COVERAGE" = "yes"; then if test "$ext_shared" != "yes"; then AC_MSG_ERROR(code coverage is not supported for static builds) fi PHP_MONGODB_COVERAGE_CFLAGS="--coverage -g" MONGODB_SHARED_LIBADD="$MONGODB_SHARED_LIBADD --coverage" fi PHP_MONGODB_CFLAGS="$PHP_MONGODB_STD_CFLAGS $PHP_MONGODB_DEV_CFLAGS $PHP_MONGODB_COVERAGE_CFLAGS" PHP_MONGODB_SOURCES="\ php_phongo.c \ src/phongo_apm.c \ src/phongo_atomic.c \ src/phongo_bson.c \ src/phongo_bson_encode.c \ src/phongo_client.c \ src/phongo_compat.c \ src/phongo_error.c \ src/phongo_execute.c \ src/phongo_ini.c \ src/phongo_log.c \ src/phongo_util.c \ src/BSON/Binary.c \ src/BSON/BinaryInterface.c \ src/BSON/Document.c \ src/BSON/Iterator.c \ src/BSON/DBPointer.c \ src/BSON/Decimal128.c \ src/BSON/Decimal128Interface.c \ src/BSON/Int64.c \ src/BSON/Javascript.c \ src/BSON/JavascriptInterface.c \ src/BSON/MaxKey.c \ src/BSON/MaxKeyInterface.c \ src/BSON/MinKey.c \ src/BSON/MinKeyInterface.c \ src/BSON/ObjectId.c \ src/BSON/ObjectIdInterface.c \ src/BSON/PackedArray.c \ src/BSON/Persistable.c \ src/BSON/Regex.c \ src/BSON/RegexInterface.c \ src/BSON/Serializable.c \ src/BSON/Symbol.c \ src/BSON/Timestamp.c \ src/BSON/TimestampInterface.c \ src/BSON/Type.c \ src/BSON/Undefined.c \ src/BSON/Unserializable.c \ src/BSON/UTCDateTime.c \ src/BSON/UTCDateTimeInterface.c \ src/BSON/functions.c \ src/MongoDB/BulkWrite.c \ src/MongoDB/ClientEncryption.c \ src/MongoDB/Command.c \ src/MongoDB/Cursor.c \ src/MongoDB/CursorId.c \ src/MongoDB/CursorInterface.c \ src/MongoDB/Manager.c \ src/MongoDB/Query.c \ src/MongoDB/ReadConcern.c \ src/MongoDB/ReadPreference.c \ src/MongoDB/Server.c \ src/MongoDB/ServerApi.c \ src/MongoDB/ServerDescription.c \ src/MongoDB/Session.c \ src/MongoDB/TopologyDescription.c \ src/MongoDB/WriteConcern.c \ src/MongoDB/WriteConcernError.c \ src/MongoDB/WriteError.c \ src/MongoDB/WriteResult.c \ src/MongoDB/Exception/AuthenticationException.c \ src/MongoDB/Exception/BulkWriteException.c \ src/MongoDB/Exception/CommandException.c \ src/MongoDB/Exception/ConnectionException.c \ src/MongoDB/Exception/ConnectionTimeoutException.c \ src/MongoDB/Exception/EncryptionException.c \ src/MongoDB/Exception/Exception.c \ src/MongoDB/Exception/ExecutionTimeoutException.c \ src/MongoDB/Exception/InvalidArgumentException.c \ src/MongoDB/Exception/LogicException.c \ src/MongoDB/Exception/RuntimeException.c \ src/MongoDB/Exception/ServerException.c \ src/MongoDB/Exception/SSLConnectionException.c \ src/MongoDB/Exception/UnexpectedValueException.c \ src/MongoDB/Exception/WriteException.c \ src/MongoDB/Monitoring/CommandFailedEvent.c \ src/MongoDB/Monitoring/CommandStartedEvent.c \ src/MongoDB/Monitoring/CommandSubscriber.c \ src/MongoDB/Monitoring/CommandSucceededEvent.c \ src/MongoDB/Monitoring/LogSubscriber.c \ src/MongoDB/Monitoring/SDAMSubscriber.c \ src/MongoDB/Monitoring/Subscriber.c \ src/MongoDB/Monitoring/ServerChangedEvent.c \ src/MongoDB/Monitoring/ServerClosedEvent.c \ src/MongoDB/Monitoring/ServerHeartbeatFailedEvent.c \ src/MongoDB/Monitoring/ServerHeartbeatStartedEvent.c \ src/MongoDB/Monitoring/ServerHeartbeatSucceededEvent.c \ src/MongoDB/Monitoring/ServerOpeningEvent.c \ src/MongoDB/Monitoring/TopologyChangedEvent.c \ src/MongoDB/Monitoring/TopologyClosedEvent.c \ src/MongoDB/Monitoring/TopologyOpeningEvent.c \ src/MongoDB/Monitoring/functions.c \ " PHP_ARG_WITH([mongodb-system-libs], [whether to compile against system libraries instead of bundled], [AS_HELP_STRING([--with-mongodb-system-libs=@<:@yes/no@:>@], [MongoDB: Use system libraries for libbson, libmongoc, and libmongocrypt [default=no]])], [no], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_SYSTEM_LIBS], [yes no]) PHP_ARG_WITH([libbson], [whether to use system libbson], [AS_HELP_STRING([--with-libbson=@<:@yes/no@:>@], [MongoDB: Use system libbson (deprecated for --with-mongodb-system-libs) [default=no]])], [no], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_LIBBSON], [yes no]) PHP_ARG_WITH([libmongoc], [whether to use system libmongoc], [AS_HELP_STRING([--with-libmongoc=@<:@yes/no@:>@], [MongoDB: Use system libmongoc (deprecated for --with-mongodb-system-libs) [default=no]])], [no], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_LIBMONGOC], [yes no]) PHP_ARG_WITH([mongodb-client-side-encryption], [whether to enable client-side encryption], [AS_HELP_STRING([--with-mongodb-client-side-encryption=@<:@auto/yes/no@:>@], [MongoDB: Enable client-side encryption [default=auto]])], [auto], [no]) PHP_MONGODB_VALIDATE_ARG([PHP_MONGODB_CLIENT_SIDE_ENCRYPTION], [auto yes no]) if test "$PHP_LIBBSON" != "no"; then AC_MSG_WARN(Using --with-libbson is deprecated and will be removed in a future version. Please use --with-system-libs instead) if test "$PHP_LIBMONGOC" = "no"; then AC_MSG_ERROR(Cannot use system libbson and bundled libmongoc) fi PHP_MONGODB_SYSTEM_LIBS="yes" fi if test "$PHP_LIBMONGOC" != "no"; then AC_MSG_WARN(Using --with-libmongoc is deprecated and will be removed in a future version. Please use --with-system-libs instead) if test "$PHP_LIBBSON" = "no"; then AC_MSG_ERROR(Cannot use system libmongoc and bundled libbson) fi PHP_MONGODB_SYSTEM_LIBS="yes" fi PHP_MONGODB_BSON_VERSION_STRING="None" PHP_MONGODB_MONGOC_VERSION_STRING="None" PHP_MONGODB_MONGOCRYPT_VERSION_STRING="None" if test "$PHP_MONGODB_SYSTEM_LIBS" != "no"; then PKG_CHECK_MODULES([PHP_MONGODB_BSON], [libbson-1.0 >= 1.30.1], [ PHP_MONGODB_BSON_VERSION=`$PKG_CONFIG libbson-1.0 --modversion` PHP_MONGODB_BSON_VERSION_STRING="System ($PHP_MONGODB_BSON_VERSION)" PHP_MONGODB_CFLAGS="$PHP_MONGODB_CFLAGS $PHP_MONGODB_BSON_CFLAGS" PHP_EVAL_LIBLINE($PHP_MONGODB_BSON_LIBS, MONGODB_SHARED_LIBADD) AC_DEFINE(HAVE_SYSTEM_LIBBSON, 1, [Use system libbson]) ],[ AC_MSG_ERROR([Could not find system library for libbson >= 1.30.1]) ]) PKG_CHECK_MODULES([PHP_MONGODB_MONGOC], [libmongoc-1.0 >= 1.30.1], [ PHP_MONGODB_BSON_VERSION=`$PKG_CONFIG libbson-1.0 --modversion` PHP_MONGODB_BSON_VERSION_STRING="System ($PHP_MONGODB_BSON_VERSION)" PHP_MONGODB_CFLAGS="$PHP_MONGODB_CFLAGS $PHP_MONGODB_MONGOC_CFLAGS" PHP_EVAL_LIBLINE($PHP_MONGODB_MONGOC_LIBS, MONGODB_SHARED_LIBADD) AC_DEFINE(HAVE_SYSTEM_LIBMONGOC, 1, [Use system libmongoc]) ],[ AC_MSG_ERROR(Could not find system library for libmongoc >= 1.30.1) ]) if test "$PHP_MONGODB_CLIENT_SIDE_ENCRYPTION" != "no"; then PKG_CHECK_MODULES([PHP_MONGODB_MONGOCRYPT], [libmongocrypt >= 1.12.0], [ PHP_MONGODB_MONGOCRYPT_VERSION=`$PKG_CONFIG libmongocrypt --modversion` PHP_MONGODB_MONGOCRYPT_VERSION_STRING="System ($PHP_MONGODB_MONGOCRYPT_VERSION)" PHP_MONGODB_CFLAGS="$PHP_MONGODB_CFLAGS $PHP_MONGODB_MONGOCRYPT_CFLAGS" PHP_EVAL_LIBLINE($PHP_MONGODB_MONGOCRYPT_LIBS, MONGODB_SHARED_LIBADD) AC_DEFINE(HAVE_SYSTEM_LIBMONGOCRYPT, 1, [Use system libmongocrypt]) ],[ AC_MSG_ERROR(Could not find system library for libmongocrypt >= 1.12.0) ]) fi fi if test "$PHP_MONGODB_SYSTEM_LIBS" = "no"; then PHP_MONGODB_BUNDLED_CFLAGS="$PHP_MONGODB_STD_CFLAGS -DBSON_COMPILATION -DMONGOC_COMPILATION" dnl CheckUtf8Proc.m4 will modify this when using bundled utf8proc PHP_MONGODB_UTF8PROC_CFLAGS="" dnl CheckCompression.m4 will modify this when using bundled zlib PHP_MONGODB_ZLIB_CFLAGS="" dnl Endian.m4 will modify this when using bundled libmongocrypt PHP_MONGODB_LIBMONGOCRYPT_CFLAGS="" dnl Save CPPFLAGS, which PlatformFlags.m4 modifies for subsequent M4 scripts old_CPPFLAGS="$CPPFLAGS" dnl Avoid using AC_CONFIG_MACRO_DIR, which might conflict with PHP m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/m4/ax_check_compile_flag.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/m4/ax_prototype.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/m4/ax_prototype_accept.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/m4/ax_pthread.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/CheckCompiler.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/CheckHost.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/PlatformFlags.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libbson/CheckHeaders.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libbson/Endian.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libbson/FindDependencies.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libbson/Versions.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongoc/CheckCompression.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongoc/CheckResolv.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongoc/CheckSasl.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongoc/CheckSSL.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongoc/CheckUtf8Proc.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongoc/Endian.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongoc/FindDependencies.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongoc/Versions.m4) dnl This include modifies the value of $PHP_MONGODB_CLIENT_SIDE_ENCRYPTION to "yes" dnl or "no" depending on whether dependencies for libmongocrypt are fulfilled m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongocrypt/CheckSSL.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongocrypt/Endian.m4) m4_include(PHP_MONGODB_BASEDIR/scripts/autotools/libmongocrypt/Version.m4) dnl Restore CPPFLAGS once all M4 scripts have executed CPPFLAGS="$old_CPPFLAGS" PHP_MONGODB_BSON_VERSION_STRING="Bundled ($libbson_VERSION_FULL)" PHP_MONGODB_MONGOC_VERSION_STRING="Bundled ($libmongoc_VERSION_FULL)" AC_SUBST(BSON_EXTRA_ALIGN, 0) AC_SUBST(BSON_OS, 1) AC_SUBST(MONGOC_NO_AUTOMATIC_GLOBALS, 1) AC_SUBST(MONGOC_ENABLE_MONGODB_AWS_AUTH, 0) AC_SUBST(MONGOC_ENABLE_RDTSCP, 0) AC_SUBST(MONGOC_ENABLE_SHM_COUNTERS, 0) AC_SUBST(MONGOC_TRACE, 1) dnl Assignments for metadata handshake. Leave CFLAGS/LDFLAGS empty as they dnl would likely cause platform info (PHP version) to be truncated. We can dnl consider restoring CFLAGS/LDFLAGS once CDRIVER-3134 is resolved. AC_SUBST(MONGOC_CC, [$CC]) AC_SUBST(MONGOC_USER_SET_CFLAGS, []) AC_SUBST(MONGOC_USER_SET_LDFLAGS, []) if test "$PHP_MONGODB_CLIENT_SIDE_ENCRYPTION" = "yes"; then AC_SUBST(MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION, 1) else AC_SUBST(MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION, 0) fi if test "$PHP_MONGODB_DEVELOPER_FLAGS" = "yes"; then AC_SUBST(MONGOC_ENABLE_DEBUG_ASSERTIONS, 1) else AC_SUBST(MONGOC_ENABLE_DEBUG_ASSERTIONS, 0) fi dnl Sources below are updated by scripts/update-submodule-sources.php PHP_MONGODB_COMMON_SOURCES="common-atomic.c common-b64.c common-json.c common-md5.c common-oid.c common-string.c common-thread.c" PHP_MONGODB_KMS_MESSAGE_SOURCES="hexlify.c kms_azure_request.c kms_b64.c kms_caller_identity_request.c kms_crypto_apple.c kms_crypto_libcrypto.c kms_crypto_none.c kms_crypto_windows.c kms_decrypt_request.c kms_encrypt_request.c kms_gcp_request.c kms_kmip_reader_writer.c kms_kmip_request.c kms_kmip_response.c kms_kmip_response_parser.c kms_kv_list.c kms_message.c kms_port.c kms_request.c kms_request_opt.c kms_request_str.c kms_response.c kms_response_parser.c sort.c" PHP_MONGODB_BSON_SOURCES="bcon.c bson-atomic.c bson.c bson-clock.c bson-context.c bson-decimal128.c bson-error.c bson-iso8601.c bson-iter.c bson-json.c bson-keys.c bson-md5.c bson-memory.c bson-oid.c bson-reader.c bson-string.c bson-timegm.c bson-utf8.c bson-value.c bson-version-functions.c bson-writer.c" PHP_MONGODB_JSONSL_SOURCES="jsonsl.c" PHP_MONGODB_MONGOC_SOURCES="mcd-azure.c mcd-nsinfo.c mcd-rpc.c mongoc-aggregate.c mongoc-apm.c mongoc-array.c mongoc-async.c mongoc-async-cmd.c mongoc-buffer.c mongoc-bulk-operation.c mongoc-bulkwrite.c mongoc-change-stream.c mongoc-client.c mongoc-client-pool.c mongoc-client-session.c mongoc-client-side-encryption.c mongoc-cluster-aws.c mongoc-cluster.c mongoc-cluster-cyrus.c mongoc-cluster-sasl.c mongoc-cluster-sspi.c mongoc-cmd.c mongoc-collection.c mongoc-compression.c mongoc-counters.c mongoc-crypt.c mongoc-crypto.c mongoc-crypto-cng.c mongoc-crypto-common-crypto.c mongoc-crypto-openssl.c mongoc-cursor-array.c mongoc-cursor.c mongoc-cursor-change-stream.c mongoc-cursor-cmd.c mongoc-cursor-cmd-deprecated.c mongoc-cursor-find.c mongoc-cursor-find-cmd.c mongoc-cursor-find-opquery.c mongoc-cursor-legacy.c mongoc-cyrus.c mongoc-database.c mongoc-deprioritized-servers.c mongoc-error.c mongoc-find-and-modify.c mongoc-flags.c mongoc-generation-map.c mongoc-gridfs-bucket.c mongoc-gridfs-bucket-file.c mongoc-gridfs.c mongoc-gridfs-file.c mongoc-gridfs-file-list.c mongoc-gridfs-file-page.c mongoc-handshake.c mongoc-host-list.c mongoc-http.c mongoc-index.c mongoc-init.c mongoc-interrupt.c mongoc-libressl.c mongoc-linux-distro-scanner.c mongoc-list.c mongoc-log-and-monitor-private.c mongoc-log.c mongoc-matcher.c mongoc-matcher-op.c mongoc-memcmp.c mongoc-ocsp-cache.c mongoc-opcode.c mongoc-openssl.c mongoc-optional.c mongoc-opts.c mongoc-opts-helpers.c mongoc-queue.c mongoc-rand-cng.c mongoc-rand-common-crypto.c mongoc-rand-openssl.c mongoc-read-concern.c mongoc-read-prefs.c mongoc-rpc.c mongoc-sasl.c mongoc-scram.c mongoc-secure-channel.c mongoc-secure-transport.c mongoc-server-api.c mongoc-server-description.c mongoc-server-monitor.c mongoc-server-stream.c mongoc-set.c mongoc-shared.c mongoc-socket.c mongoc-ssl.c mongoc-sspi.c mongoc-stream-buffered.c mongoc-stream.c mongoc-stream-file.c mongoc-stream-gridfs.c mongoc-stream-gridfs-download.c mongoc-stream-gridfs-upload.c mongoc-stream-socket.c mongoc-stream-tls.c mongoc-stream-tls-libressl.c mongoc-stream-tls-openssl-bio.c mongoc-stream-tls-openssl.c mongoc-stream-tls-secure-channel.c mongoc-stream-tls-secure-transport.c mongoc-structured-log.c mongoc-timeout.c mongoc-topology-background-monitoring.c mongoc-topology.c mongoc-topology-description-apm.c mongoc-topology-description.c mongoc-topology-scanner.c mongoc-ts-pool.c mongoc-uri.c mongoc-util.c mongoc-version-functions.c mongoc-write-command.c mongoc-write-concern.c service-gcp.c" PHP_MONGODB_UTF8PROC_SOURCES="utf8proc.c" PHP_MONGODB_ZLIB_SOURCES="adler32.c compress.c crc32.c deflate.c gzclose.c gzlib.c gzread.c gzwrite.c infback.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c" PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/common/src/], $PHP_MONGODB_COMMON_SOURCES, $PHP_MONGODB_BUNDLED_CFLAGS) PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/libbson/src/bson/], $PHP_MONGODB_BSON_SOURCES, $PHP_MONGODB_BUNDLED_CFLAGS) PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/libbson/src/jsonsl/], $PHP_MONGODB_JSONSL_SOURCES, $PHP_MONGODB_BUNDLED_CFLAGS) PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/libmongoc/src/mongoc/], $PHP_MONGODB_MONGOC_SOURCES, $PHP_MONGODB_BUNDLED_CFLAGS) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/common/src/]) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/uthash/]) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/libbson/src/]) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/libbson/src/jsonsl/]) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/libmongoc/src/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/common/src/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/libbson/src/bson/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/libbson/src/jsonsl/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/libmongoc/src/mongoc/]) dnl If compiling without libmongocrypt, use kms_message sources bundled with libmongoc. dnl If compiling with libmongocrypt, kms_message bundled with libmongocrypt is used as it is most likely newer. if test "$PHP_MONGODB_CLIENT_SIDE_ENCRYPTION" != "yes" && test "$PHP_MONGODB_SSL" != "no"; then AC_SUBST(MONGOC_ENABLE_MONGODB_AWS_AUTH, 1) PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/kms-message/src/], $PHP_MONGODB_KMS_MESSAGE_SOURCES, $PHP_MONGODB_BUNDLED_CFLAGS) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/kms-message/src/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/kms-message/src/]) fi dnl TODO: Use $ext_srcdir if we can move this after PHP_NEW_EXTENSION ac_config_dir=PHP_EXT_SRCDIR(mongodb) AC_CONFIG_FILES([ ${ac_config_dir}/src/libmongoc/src/common/src/common-config.h ${ac_config_dir}/src/libmongoc/src/libbson/src/bson/bson-config.h ${ac_config_dir}/src/libmongoc/src/libbson/src/bson/bson-version.h ${ac_config_dir}/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config.h ${ac_config_dir}/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version.h ]) if test "x$bundled_utf8proc" = "xyes"; then PHP_MONGODB_UTF8PROC_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_UTF8PROC_CFLAGS" PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/utf8proc-2.8.0/], $PHP_MONGODB_UTF8PROC_SOURCES, $PHP_MONGODB_UTF8PROC_CFLAGS) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/utf8proc-2.8.0/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/utf8proc-2.8.0/]) fi if test "x$bundled_zlib" = "xyes"; then PHP_MONGODB_ZLIB_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_ZLIB_CFLAGS" PHP_MONGODB_ADD_SOURCES([src/libmongoc/src/zlib-1.3.1/], $PHP_MONGODB_ZLIB_SOURCES, $PHP_MONGODB_ZLIB_CFLAGS) PHP_MONGODB_ADD_INCLUDE([src/libmongoc/src/zlib-1.3.1/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongoc/src/zlib-1.3.1/]) AC_CONFIG_FILES([${ac_config_dir}/src/libmongoc/src/zlib-1.3.1/zconf.h]) fi if test "$PHP_MONGODB_CLIENT_SIDE_ENCRYPTION" = "yes"; then PHP_MONGODB_LIBMONGOCRYPT_CFLAGS="$PHP_MONGODB_BUNDLED_CFLAGS $PHP_MONGODB_LIBMONGOCRYPT_CFLAGS -DKMS_MSG_STATIC -DMLIB_USER" PHP_MONGODB_MONGOCRYPT_VERSION_STRING="Bundled ($MONGOCRYPT_BUILD_VERSION)" dnl Since libmongocrypt adds kms-message, we can enable AWS auth in this case AC_SUBST(MONGOC_ENABLE_MONGODB_AWS_AUTH, 1) AC_SUBST(MONGOCRYPT_ENABLE_TRACE, 1) dnl Sources below are updated by scripts/update-submodule-sources.php PHP_MONGODB_MONGOCRYPT_SOURCES="mc-array.c mc-efc.c mc-fle2-encryption-placeholder.c mc-fle2-find-equality-payload.c mc-fle2-find-equality-payload-v2.c mc-fle2-find-range-payload.c mc-fle2-find-range-payload-v2.c mc-fle2-insert-update-payload.c mc-fle2-insert-update-payload-v2.c mc-fle2-payload-iev.c mc-fle2-payload-iev-v2.c mc-fle2-payload-uev.c mc-fle2-payload-uev-common.c mc-fle2-payload-uev-v2.c mc-fle2-rfds.c mc-fle2-tag-and-encrypted-metadata-block.c mc-range-edge-generation.c mc-range-encoding.c mc-range-mincover.c mc-rangeopts.c mc-reader.c mc-tokens.c mc-writer.c mongocrypt-binary.c mongocrypt-buffer.c mongocrypt.c mongocrypt-cache.c mongocrypt-cache-collinfo.c mongocrypt-cache-key.c mongocrypt-cache-oauth.c mongocrypt-ciphertext.c mongocrypt-crypto.c mongocrypt-ctx.c mongocrypt-ctx-datakey.c mongocrypt-ctx-decrypt.c mongocrypt-ctx-encrypt.c mongocrypt-ctx-rewrap-many-datakey.c mongocrypt-endpoint.c mongocrypt-kek.c mongocrypt-key-broker.c mongocrypt-key.c mongocrypt-kms-ctx.c mongocrypt-log.c mongocrypt-marking.c mongocrypt-opts.c mongocrypt-status.c mongocrypt-traverse-util.c mongocrypt-util.c" PHP_MONGODB_MONGOCRYPT_CRYPTO_SOURCES="cng.c commoncrypto.c libcrypto.c none.c" PHP_MONGODB_MONGOCRYPT_OS_POSIX_SOURCES="os_dll.c os_mutex.c" PHP_MONGODB_MONGOCRYPT_OS_WIN_SOURCES="os_dll.c os_mutex.c" PHP_MONGODB_MONGOCRYPT_KMS_MESSAGE_SOURCES="hexlify.c kms_azure_request.c kms_b64.c kms_caller_identity_request.c kms_crypto_apple.c kms_crypto_libcrypto.c kms_crypto_none.c kms_crypto_windows.c kms_decrypt_request.c kms_encrypt_request.c kms_gcp_request.c kms_kmip_reader_writer.c kms_kmip_request.c kms_kmip_response.c kms_kmip_response_parser.c kms_kv_list.c kms_message.c kms_port.c kms_request.c kms_request_opt.c kms_request_str.c kms_response.c kms_response_parser.c sort.c" PHP_MONGODB_ADD_SOURCES([src/libmongocrypt/src/], $PHP_MONGODB_MONGOCRYPT_SOURCES, $PHP_MONGODB_LIBMONGOCRYPT_CFLAGS) PHP_MONGODB_ADD_SOURCES([src/libmongocrypt/src/crypto/], $PHP_MONGODB_MONGOCRYPT_CRYPTO_SOURCES, $PHP_MONGODB_LIBMONGOCRYPT_CFLAGS) PHP_MONGODB_ADD_SOURCES([src/libmongocrypt/src/os_posix/], $PHP_MONGODB_MONGOCRYPT_OS_POSIX_SOURCES, $PHP_MONGODB_LIBMONGOCRYPT_CFLAGS) PHP_MONGODB_ADD_SOURCES([src/libmongocrypt/src/os_win/], $PHP_MONGODB_MONGOCRYPT_OS_WIN_SOURCES, $PHP_MONGODB_LIBMONGOCRYPT_CFLAGS) PHP_MONGODB_ADD_SOURCES([src/libmongocrypt/kms-message/src/], $PHP_MONGODB_MONGOCRYPT_KMS_MESSAGE_SOURCES, $PHP_MONGODB_LIBMONGOCRYPT_CFLAGS) PHP_MONGODB_ADD_INCLUDE([src/libmongocrypt/src/]) PHP_MONGODB_ADD_INCLUDE([src/libmongocrypt/kms-message/src/]) PHP_MONGODB_ADD_INCLUDE([src/libmongocrypt-compat/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongocrypt/src/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongocrypt/src/crypto/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongocrypt/src/os_posix/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongocrypt/src/os_win/]) PHP_MONGODB_ADD_BUILD_DIR([src/libmongocrypt/kms-message/src/]) AC_CONFIG_FILES([ ${ac_config_dir}/src/libmongocrypt/src/mongocrypt-config.h ]) fi fi PHP_NEW_EXTENSION(mongodb, $PHP_MONGODB_SOURCES, $ext_shared,, $PHP_MONGODB_CFLAGS) PHP_SUBST(MONGODB_SHARED_LIBADD) PHP_ADD_EXTENSION_DEP(mongodb, date) PHP_ADD_EXTENSION_DEP(mongodb, json) PHP_ADD_EXTENSION_DEP(mongodb, spl) PHP_ADD_EXTENSION_DEP(mongodb, standard) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(mongodb)[/src/]) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(mongodb)[/src/BSON/]) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(mongodb)[/src/MongoDB/]) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(mongodb)[/src/MongoDB/Exception/]) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(mongodb)[/src/MongoDB/Monitoring/]) PHP_ADD_INCLUDE(PHP_EXT_SRCDIR(mongodb)[/src/contrib/]) PHP_ADD_BUILD_DIR(PHP_EXT_BUILDDIR(mongodb)[/src/]) PHP_ADD_BUILD_DIR(PHP_EXT_BUILDDIR(mongodb)[/src/BSON/]) PHP_ADD_BUILD_DIR(PHP_EXT_BUILDDIR(mongodb)[/src/MongoDB/]) PHP_ADD_BUILD_DIR(PHP_EXT_BUILDDIR(mongodb)[/src/MongoDB/Exception/]) PHP_ADD_BUILD_DIR(PHP_EXT_BUILDDIR(mongodb)[/src/MongoDB/Monitoring/]) PHP_ADD_BUILD_DIR(PHP_EXT_BUILDDIR(mongodb)[/src/contrib/]) dnl Necessary to ensure that static builds include "-pthread" when linking if test "$ext_shared" != "yes"; then EXTRA_LDFLAGS_PROGRAM="$EXTRA_LDFLAGS_PROGRAM $EXTRA_LDFLAGS" fi dnl This must come after PHP_NEW_EXTENSION, otherwise the srcdir won't be set PHP_ADD_MAKEFILE_FRAGMENT AC_CONFIG_COMMANDS_POST([ if test "$enable_static" = "no"; then echo " mongodb was configured with the following options: Build configuration: CC : $CC CFLAGS : $CFLAGS CPPFLAGS : $CPPFLAGS Extra flags : $PHP_MONGODB_STD_CFLAGS Developer flags (slow) : $PHP_MONGODB_DEV_CFLAGS Code Coverage flags (extra slow) : $PHP_MONGODB_COVERAGE_CFLAGS libmongoc : $PHP_MONGODB_BSON_VERSION_STRING libbson : $PHP_MONGODB_MONGOC_VERSION_STRING libmongocrypt : $PHP_MONGODB_MONGOCRYPT_VERSION_STRING LDFLAGS : $LDFLAGS EXTRA_LDFLAGS : $EXTRA_LDFLAGS MONGODB_SHARED_LIBADD : $MONGODB_SHARED_LIBADD Please submit bugreports at: https://jira.mongodb.org/browse/PHPC " fi ]) fi dnl: vim: et sw=2 mongodb-1.21.0/config.w320000644000175100001660000004623614760300421011753 0ustar // vim:ft=javascript function mongodb_generate_header(inpath, outpath, replacements) { STDOUT.WriteLine("Generating " + outpath); var infile = FSO.OpenTextFile(inpath, 1); var outdata = infile.ReadAll(); infile.Close(); for (var key in replacements) { var replacement = replacements[key]; if (typeof replacement === 'string') { replacement = replacement.replace(/"/g, '\\"'); } outdata = outdata.replace(new RegExp('@' + key + '@', 'g'), replacement); } var outfile = FSO.CreateTextFile(outpath, true); outfile.Write(outdata); outfile.Close(); } function mongodb_parse_libmongoc_version_file(prefix) { var infile = FSO.OpenTextFile(configure_module_dirname + "/src/LIBMONGOC_VERSION_CURRENT", 1); var version = infile.ReadLine(); infile.Close(); var xyz_pre = version.split("-"); var xyz = xyz_pre[0].split("."); var pre = xyz_pre.length > 1 ? xyz_pre[1] : ""; var replacements = {}; replacements[prefix + "VERSION_FULL"] = version; replacements[prefix + "VERSION_MAJOR"] = xyz[0]; replacements[prefix + "VERSION_MINOR"] = xyz[1]; replacements[prefix + "VERSION_PATCH"] = xyz[2]; replacements[prefix + "VERSION_PRERELEASE"] = pre; return replacements; } function mongodb_get_libmongocrypt_version() { var infile = FSO.OpenTextFile(configure_module_dirname + "/src/LIBMONGOCRYPT_VERSION_CURRENT", 1); var version = infile.ReadLine(); infile.Close(); return version; } function create_folder_recursive(path) { if (FSO.FolderExists(path)) { return; } create_folder_recursive(FSO.GetParentFolderName(path)); FSO.CreateFolder(path); } function MONGODB_ADD_SOURCES(dir, file_list) { // Ensure obj_dir and all parent directories exist create_folder_recursive(FSO.BuildPath(get_define('BUILD_DIR'), dir)); ADD_SOURCES(configure_module_dirname + dir, file_list, "mongodb", dir); } ARG_ENABLE("mongodb", "MongoDB support", "no"); ARG_WITH("mongodb-sasl", "MongoDB: Build against Cyrus-SASL", "yes"); ARG_WITH("mongodb-client-side-encryption", "MongoDB: Enable client-side encryption", "yes"); if (PHP_MONGODB != "no") { ADD_EXTENSION_DEP("mongodb", "date", false); ADD_EXTENSION_DEP("mongodb", "standard", false); ADD_EXTENSION_DEP("mongodb", "json", false); ADD_EXTENSION_DEP("mongodb", "spl", false); /* MongoDB does not actually depend on PHP's OpenSSL extension, but this is in * place to ensure that later SSL library checks succeed. This can be removed * once we support building with Secure Channel. */ ADD_EXTENSION_DEP("mongodb", "openssl", false); var PHP_MONGODB_CFLAGS="\ /D BSON_COMPILATION /D MONGOC_COMPILATION /D UTF8PROC_STATIC \ /I" + configure_module_dirname + " \ /I" + configure_module_dirname + "/src \ /I" + configure_module_dirname + "/src/BSON \ /I" + configure_module_dirname + "/src/MongoDB \ /I" + configure_module_dirname + "/src/MongoDB/Exception \ /I" + configure_module_dirname + "/src/MongoDB/Monitoring \ /I" + configure_module_dirname + "/src/contrib \ /I" + configure_module_dirname + "/src/libmongoc/src/common/src \ /I" + configure_module_dirname + "/src/libmongoc/src/uthash \ /I" + configure_module_dirname + "/src/libmongoc/src/libbson/src \ /I" + configure_module_dirname + "/src/libmongoc/src/libbson/src/jsonsl \ /I" + configure_module_dirname + "/src/libmongoc/src/libmongoc/src \ /I" + configure_module_dirname + "/src/libmongoc/src/libmongoc/src/mongoc \ /I" + configure_module_dirname + "/src/libmongoc/src/utf8proc-2.8.0 \ "; // Condense whitespace in CFLAGS PHP_MONGODB_CFLAGS = PHP_MONGODB_CFLAGS.replace(/\s+/g, ' '); // Sources below are updated by scripts/update-submodule-sources.php var PHP_MONGODB_COMMON_SOURCES="common-atomic.c common-b64.c common-json.c common-md5.c common-oid.c common-string.c common-thread.c" var PHP_MONGODB_KMS_MESSAGE_SOURCES="hexlify.c kms_azure_request.c kms_b64.c kms_caller_identity_request.c kms_crypto_apple.c kms_crypto_libcrypto.c kms_crypto_none.c kms_crypto_windows.c kms_decrypt_request.c kms_encrypt_request.c kms_gcp_request.c kms_kmip_reader_writer.c kms_kmip_request.c kms_kmip_response.c kms_kmip_response_parser.c kms_kv_list.c kms_message.c kms_port.c kms_request.c kms_request_opt.c kms_request_str.c kms_response.c kms_response_parser.c sort.c"; var PHP_MONGODB_BSON_SOURCES="bcon.c bson-atomic.c bson.c bson-clock.c bson-context.c bson-decimal128.c bson-error.c bson-iso8601.c bson-iter.c bson-json.c bson-keys.c bson-md5.c bson-memory.c bson-oid.c bson-reader.c bson-string.c bson-timegm.c bson-utf8.c bson-value.c bson-version-functions.c bson-writer.c"; var PHP_MONGODB_JSONSL_SOURCES="jsonsl.c"; var PHP_MONGODB_MONGOC_SOURCES="mcd-azure.c mcd-nsinfo.c mcd-rpc.c mongoc-aggregate.c mongoc-apm.c mongoc-array.c mongoc-async.c mongoc-async-cmd.c mongoc-buffer.c mongoc-bulk-operation.c mongoc-bulkwrite.c mongoc-change-stream.c mongoc-client.c mongoc-client-pool.c mongoc-client-session.c mongoc-client-side-encryption.c mongoc-cluster-aws.c mongoc-cluster.c mongoc-cluster-cyrus.c mongoc-cluster-sasl.c mongoc-cluster-sspi.c mongoc-cmd.c mongoc-collection.c mongoc-compression.c mongoc-counters.c mongoc-crypt.c mongoc-crypto.c mongoc-crypto-cng.c mongoc-crypto-common-crypto.c mongoc-crypto-openssl.c mongoc-cursor-array.c mongoc-cursor.c mongoc-cursor-change-stream.c mongoc-cursor-cmd.c mongoc-cursor-cmd-deprecated.c mongoc-cursor-find.c mongoc-cursor-find-cmd.c mongoc-cursor-find-opquery.c mongoc-cursor-legacy.c mongoc-cyrus.c mongoc-database.c mongoc-deprioritized-servers.c mongoc-error.c mongoc-find-and-modify.c mongoc-flags.c mongoc-generation-map.c mongoc-gridfs-bucket.c mongoc-gridfs-bucket-file.c mongoc-gridfs.c mongoc-gridfs-file.c mongoc-gridfs-file-list.c mongoc-gridfs-file-page.c mongoc-handshake.c mongoc-host-list.c mongoc-http.c mongoc-index.c mongoc-init.c mongoc-interrupt.c mongoc-libressl.c mongoc-linux-distro-scanner.c mongoc-list.c mongoc-log-and-monitor-private.c mongoc-log.c mongoc-matcher.c mongoc-matcher-op.c mongoc-memcmp.c mongoc-ocsp-cache.c mongoc-opcode.c mongoc-openssl.c mongoc-optional.c mongoc-opts.c mongoc-opts-helpers.c mongoc-queue.c mongoc-rand-cng.c mongoc-rand-common-crypto.c mongoc-rand-openssl.c mongoc-read-concern.c mongoc-read-prefs.c mongoc-rpc.c mongoc-sasl.c mongoc-scram.c mongoc-secure-channel.c mongoc-secure-transport.c mongoc-server-api.c mongoc-server-description.c mongoc-server-monitor.c mongoc-server-stream.c mongoc-set.c mongoc-shared.c mongoc-socket.c mongoc-ssl.c mongoc-sspi.c mongoc-stream-buffered.c mongoc-stream.c mongoc-stream-file.c mongoc-stream-gridfs.c mongoc-stream-gridfs-download.c mongoc-stream-gridfs-upload.c mongoc-stream-socket.c mongoc-stream-tls.c mongoc-stream-tls-libressl.c mongoc-stream-tls-openssl-bio.c mongoc-stream-tls-openssl.c mongoc-stream-tls-secure-channel.c mongoc-stream-tls-secure-transport.c mongoc-structured-log.c mongoc-timeout.c mongoc-topology-background-monitoring.c mongoc-topology.c mongoc-topology-description-apm.c mongoc-topology-description.c mongoc-topology-scanner.c mongoc-ts-pool.c mongoc-uri.c mongoc-util.c mongoc-version-functions.c mongoc-write-command.c mongoc-write-concern.c service-gcp.c"; var PHP_MONGODB_UTF8PROC_SOURCES="utf8proc.c"; EXTENSION("mongodb", "php_phongo.c", null, PHP_MONGODB_CFLAGS); MONGODB_ADD_SOURCES("/src", "phongo_apm.c phongo_atomic.c phongo_bson.c phongo_bson_encode.c phongo_client.c phongo_compat.c phongo_error.c phongo_execute.c phongo_ini.c phongo_log.c phongo_util.c"); MONGODB_ADD_SOURCES("/src/BSON", "Binary.c BinaryInterface.c Document.c Iterator.c DBPointer.c Decimal128.c Decimal128Interface.c Int64.c Javascript.c JavascriptInterface.c MaxKey.c MaxKeyInterface.c MinKey.c MinKeyInterface.c ObjectId.c ObjectIdInterface.c PackedArray.c Persistable.c Regex.c RegexInterface.c Serializable.c Symbol.c Timestamp.c TimestampInterface.c Type.c Undefined.c Unserializable.c UTCDateTime.c UTCDateTimeInterface.c functions.c"); MONGODB_ADD_SOURCES("/src/MongoDB", "BulkWrite.c ClientEncryption.c Command.c Cursor.c CursorId.c CursorInterface.c Manager.c Query.c ReadConcern.c ReadPreference.c Server.c ServerApi.c ServerDescription.c Session.c TopologyDescription.c WriteConcern.c WriteConcernError.c WriteError.c WriteResult.c"); MONGODB_ADD_SOURCES("/src/MongoDB/Exception", "AuthenticationException.c BulkWriteException.c CommandException.c ConnectionException.c ConnectionTimeoutException.c EncryptionException.c Exception.c ExecutionTimeoutException.c InvalidArgumentException.c LogicException.c RuntimeException.c ServerException.c SSLConnectionException.c UnexpectedValueException.c WriteException.c"); MONGODB_ADD_SOURCES("/src/MongoDB/Monitoring", "CommandFailedEvent.c CommandStartedEvent.c CommandSubscriber.c CommandSucceededEvent.c LogSubscriber.c SDAMSubscriber.c Subscriber.c ServerChangedEvent.c ServerClosedEvent.c ServerHeartbeatFailedEvent.c ServerHeartbeatStartedEvent.c ServerHeartbeatSucceededEvent.c ServerOpeningEvent.c TopologyChangedEvent.c TopologyClosedEvent.c TopologyOpeningEvent.c functions.c"); MONGODB_ADD_SOURCES("/src/libmongoc/src/common/src", PHP_MONGODB_COMMON_SOURCES); MONGODB_ADD_SOURCES("/src/libmongoc/src/libbson/src/bson", PHP_MONGODB_BSON_SOURCES); MONGODB_ADD_SOURCES("/src/libmongoc/src/libbson/src/jsonsl", PHP_MONGODB_JSONSL_SOURCES); MONGODB_ADD_SOURCES("/src/libmongoc/src/libmongoc/src/mongoc", PHP_MONGODB_MONGOC_SOURCES); MONGODB_ADD_SOURCES("/src/libmongoc/src/utf8proc-2.8.0", PHP_MONGODB_UTF8PROC_SOURCES); var bson_opts = { BSON_BYTE_ORDER: 1234, BSON_OS: 2, BSON_HAVE_STDBOOL_H: 0, BSON_HAVE_STRINGS_H: 0, BSON_HAVE_CLOCK_GETTIME: 0, BSON_HAVE_STRNLEN: 0, BSON_HAVE_SNPRINTF: 0, BSON_HAVE_STRLCPY: 0, BSON_HAVE_TIMESPEC: 0, BSON_EXTRA_ALIGN: 0, BSON_HAVE_GMTIME_R: 0, BSON_HAVE_RAND_R: 0, BSON_HAVE_ALIGNED_ALLOC: 0 }; mongodb_generate_header( configure_module_dirname + "/src/libmongoc/src/libbson/src/bson/bson-config.h.in", configure_module_dirname + "/src/libmongoc/src/libbson/src/bson/bson-config.h", bson_opts ); mongodb_generate_header( configure_module_dirname + "/src/libmongoc/src/libbson/src/bson/bson-version.h.in", configure_module_dirname + "/src/libmongoc/src/libbson/src/bson/bson-version.h", mongodb_parse_libmongoc_version_file("libbson_") ); var mongoc_opts = { // TODO: Support building with Secure Channel on Windows MONGOC_ENABLE_SSL_SECURE_CHANNEL: 0, MONGOC_ENABLE_CRYPTO_CNG: 0, MONGOC_HAVE_BCRYPT_PBKDF2: 0, // Secure Transport does not apply to Windows MONGOC_ENABLE_SSL_SECURE_TRANSPORT: 0, MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO: 0, MONGOC_ENABLE_SSL_LIBRESSL: 0, MONGOC_ENABLE_SSL_OPENSSL: 0, MONGOC_ENABLE_CRYPTO_LIBCRYPTO: 0, MONGOC_ENABLE_SSL: 0, MONGOC_ENABLE_CRYPTO: 0, MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE: 0, MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION: 0, MONGOC_ENABLE_COMPRESSION_SNAPPY: 0, MONGOC_ENABLE_COMPRESSION_ZLIB: 0, MONGOC_ENABLE_COMPRESSION_ZSTD: 0, MONGOC_ENABLE_COMPRESSION: 0, MONGOC_ENABLE_DEBUG_ASSERTIONS: 0, MONGOC_ENABLE_MONGODB_AWS_AUTH: 0, MONGOC_ENABLE_SASL: 0, MONGOC_ENABLE_SASL_CYRUS: 0, MONGOC_ENABLE_SASL_SSPI: 0, MONGOC_ENABLE_SRV: 0, MONGOC_ENABLE_RDTSCP: 0, MONGOC_ENABLE_SHM_COUNTERS: 0, MONGOC_HAVE_ASN1_STRING_GET0_DATA: 0, MONGOC_HAVE_SASL_CLIENT_DONE: 0, MONGOC_HAVE_SCHED_GETCPU: 0, MONGOC_HAVE_SOCKLEN: 1, MONGOC_NO_AUTOMATIC_GLOBALS: 1, MONGOC_SOCKET_ARG2: "struct sockaddr", MONGOC_SOCKET_ARG3: "socklen_t", MONGOC_TRACE: 1, MONGOC_HAVE_DNSAPI: 0, MONGOC_HAVE_RES_NSEARCH: 0, MONGOC_HAVE_RES_NDESTROY: 0, MONGOC_HAVE_RES_NCLOSE: 0, MONGOC_HAVE_RES_SEARCH: 0, MONGOC_HAVE_SS_FAMILY: 0, MONGOC_CC: "", MONGOC_USER_SET_CFLAGS: "", MONGOC_USER_SET_LDFLAGS: "" }; var mongoc_ssl_path_to_check = PHP_MONGODB; if (typeof PHP_OPENSSL === 'string') { mongoc_ssl_path_to_check += ";" + PHP_OPENSSL; } var mongoc_ssl_found = false; /* PHP 7.1.2 introduced SETUP_OPENSSL(), which supports OpenSSL 1.1.x. Earlier * versions will use the legacy check for OpenSSL 1.0.x and lower. */ if (typeof SETUP_OPENSSL === 'function') { openssl_type = SETUP_OPENSSL("mongodb", mongoc_ssl_path_to_check); mongoc_ssl_found = openssl_type > 0; if (openssl_type >= 2) { mongoc_opts.MONGOC_HAVE_ASN1_STRING_GET0_DATA = 1; } } else if (CHECK_LIB("ssleay32.lib", "mongodb", mongoc_ssl_path_to_check) && CHECK_LIB("libeay32.lib", "mongodb", mongoc_ssl_path_to_check) && CHECK_LIB("crypt32.lib", "mongodb", mongoc_ssl_path_to_check) && CHECK_HEADER_ADD_INCLUDE("openssl/ssl.h", "CFLAGS_MONGODB")) { mongoc_ssl_found = true; } if (mongoc_ssl_found) { mongoc_opts.MONGOC_ENABLE_SSL_OPENSSL = 1; mongoc_opts.MONGOC_ENABLE_CRYPTO_LIBCRYPTO = 1; mongoc_opts.MONGOC_ENABLE_SSL = 1; mongoc_opts.MONGOC_ENABLE_CRYPTO = 1; mongoc_opts.MONGOC_ENABLE_MONGODB_AWS_AUTH = 1; ADD_FLAG("CFLAGS_MONGODB", "/D KMS_MSG_STATIC=1 /D KMS_MESSAGE_ENABLE_CRYPTO=1 /D KMS_MESSAGE_ENABLE_CRYPTO_LIBCRYPTO=1"); } else { WARNING("mongodb libopenssl support not enabled, libs not found"); } // TODO: Support building with native GSSAPI (SSPI) on Windows if (PHP_MONGODB_SASL != "no" && CHECK_LIB("libsasl.lib", "mongodb", PHP_MONGODB) && CHECK_HEADER_ADD_INCLUDE("sasl/sasl.h", "CFLAGS_MONGODB")) { mongoc_opts.MONGOC_ENABLE_SASL = 1; mongoc_opts.MONGOC_ENABLE_SASL_CYRUS = 1; // Referenced by _mongoc_cyrus_verifyfile_cb in mongoc-cyrus.c on Windows ADD_FLAG("CFLAGS_MONGODB", "/D MONGOC_CYRUS_PLUGIN_PATH_PREFIX=NULL"); if (CHECK_FUNC_IN_HEADER("sasl/sasl.h", "sasl_client_done")) { mongoc_opts.MONGOC_HAVE_SASL_CLIENT_DONE = 1; } } else if (PHP_MONGODB_SASL != "no") { WARNING("mongodb libsasl support not enabled, libs not found"); } if (PHP_MONGODB_CLIENT_SIDE_ENCRYPTION != "no" && mongoc_ssl_found) { mongoc_opts.MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION = 1; ADD_FLAG("CFLAGS_MONGODB", "/D KMS_MESSAGE_LITTLE_ENDIAN=1 /D MONGOCRYPT_LITTLE_ENDIAN=1 /D MLIB_USER=1"); ADD_FLAG("CFLAGS_MONGODB", "/I" + configure_module_dirname + "/src/libmongocrypt/src"); ADD_FLAG("CFLAGS_MONGODB", "/I" + configure_module_dirname + "/src/libmongocrypt/kms-message/src"); ADD_FLAG("CFLAGS_MONGODB", "/I" + configure_module_dirname + "/src/libmongocrypt-compat"); var mongocrypt_opts = { MONGOCRYPT_ENABLE_TRACE: 1, MONGOCRYPT_ENABLE_CRYPTO: 1, MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO: 1, // TODO: Support building with Secure Channel on Windows MONGOCRYPT_ENABLE_CRYPTO_CNG: 0, // Secure Transport does not apply to Windows MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO: 0 }; // Sources below are updated by scripts/update-submodule-sources.php var PHP_MONGODB_MONGOCRYPT_SOURCES="mc-array.c mc-efc.c mc-fle2-encryption-placeholder.c mc-fle2-find-equality-payload.c mc-fle2-find-equality-payload-v2.c mc-fle2-find-range-payload.c mc-fle2-find-range-payload-v2.c mc-fle2-insert-update-payload.c mc-fle2-insert-update-payload-v2.c mc-fle2-payload-iev.c mc-fle2-payload-iev-v2.c mc-fle2-payload-uev.c mc-fle2-payload-uev-common.c mc-fle2-payload-uev-v2.c mc-fle2-rfds.c mc-fle2-tag-and-encrypted-metadata-block.c mc-range-edge-generation.c mc-range-encoding.c mc-range-mincover.c mc-rangeopts.c mc-reader.c mc-tokens.c mc-writer.c mongocrypt-binary.c mongocrypt-buffer.c mongocrypt.c mongocrypt-cache.c mongocrypt-cache-collinfo.c mongocrypt-cache-key.c mongocrypt-cache-oauth.c mongocrypt-ciphertext.c mongocrypt-crypto.c mongocrypt-ctx.c mongocrypt-ctx-datakey.c mongocrypt-ctx-decrypt.c mongocrypt-ctx-encrypt.c mongocrypt-ctx-rewrap-many-datakey.c mongocrypt-endpoint.c mongocrypt-kek.c mongocrypt-key-broker.c mongocrypt-key.c mongocrypt-kms-ctx.c mongocrypt-log.c mongocrypt-marking.c mongocrypt-opts.c mongocrypt-status.c mongocrypt-traverse-util.c mongocrypt-util.c"; var PHP_MONGODB_MONGOCRYPT_CRYPTO_SOURCES="cng.c commoncrypto.c libcrypto.c none.c"; var PHP_MONGODB_MONGOCRYPT_OS_POSIX_SOURCES="os_dll.c os_mutex.c"; var PHP_MONGODB_MONGOCRYPT_OS_WIN_SOURCES="os_dll.c os_mutex.c"; var PHP_MONGODB_MONGOCRYPT_KMS_MESSAGE_SOURCES="hexlify.c kms_azure_request.c kms_b64.c kms_caller_identity_request.c kms_crypto_apple.c kms_crypto_libcrypto.c kms_crypto_none.c kms_crypto_windows.c kms_decrypt_request.c kms_encrypt_request.c kms_gcp_request.c kms_kmip_reader_writer.c kms_kmip_request.c kms_kmip_response.c kms_kmip_response_parser.c kms_kv_list.c kms_message.c kms_port.c kms_request.c kms_request_opt.c kms_request_str.c kms_response.c kms_response_parser.c sort.c"; MONGODB_ADD_SOURCES("/src/libmongocrypt/src", PHP_MONGODB_MONGOCRYPT_SOURCES); MONGODB_ADD_SOURCES("/src/libmongocrypt/src/crypto", PHP_MONGODB_MONGOCRYPT_CRYPTO_SOURCES); MONGODB_ADD_SOURCES("/src/libmongocrypt/src/os_posix", PHP_MONGODB_MONGOCRYPT_OS_POSIX_SOURCES); MONGODB_ADD_SOURCES("/src/libmongocrypt/src/os_win", PHP_MONGODB_MONGOCRYPT_OS_WIN_SOURCES); MONGODB_ADD_SOURCES("/src/libmongocrypt/kms-message/src", PHP_MONGODB_MONGOCRYPT_KMS_MESSAGE_SOURCES); mongocrypt_opts.MONGOCRYPT_BUILD_VERSION = mongodb_get_libmongocrypt_version(); mongodb_generate_header( configure_module_dirname + "/src/libmongocrypt/src/mongocrypt-config.h.in", configure_module_dirname + "/src/libmongocrypt/src/mongocrypt-config.h", mongocrypt_opts ); } else if (PHP_MONGODB_CLIENT_SIDE_ENCRYPTION != "no") { // No SSL library found, we can't enable libmongocrypt WARNING("mongodb libmongocrypt support not enabled, crypto libs not found"); } if (PHP_MONGODB_CLIENT_SIDE_ENCRYPTION == "no" && mongoc_ssl_found) { // Add kms-message sources bundled with libmongoc MONGODB_ADD_SOURCES("/src/libmongoc/src/kms-message/src", PHP_MONGODB_KMS_MESSAGE_SOURCES); ADD_FLAG("CFLAGS_MONGODB", "/I" + configure_module_dirname + "/src/libmongoc/src/kms-message/src"); } if (CHECK_LIB("dnsapi.lib", "mongodb", PHP_MONGODB) && CHECK_HEADER_ADD_INCLUDE("windns.h", "CFLAGS_MONGODB")) { mongoc_opts.MONGOC_HAVE_DNSAPI = 1; mongoc_opts.MONGOC_ENABLE_SRV = 1; } if (typeof COMPILER_NAME === 'string') { mongoc_opts.MONGOC_CC = COMPILER_NAME; } else if (typeof VC_VERSIONS === 'array' && typeof VC_VERSIONS[VCVERS] === 'string') { mongoc_opts.MONGOC_CC = VC_VERSIONS[VCVERS]; } else if (typeof COMPILER_NAME_LONG === 'string') { mongoc_opts.MONGOC_CC = COMPILER_NAME_LONG; } /* MONGOC_USER_SET_CFLAGS and MONGOC_USER_SET_LDFLAGS can be left blank, as we * do not expect CFLAGS or LDFLAGS to be customized at build time. */ mongodb_generate_header( configure_module_dirname + "/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config.h.in", configure_module_dirname + "/src/libmongoc/src/libmongoc/src/mongoc/mongoc-config.h", mongoc_opts ); mongodb_generate_header( configure_module_dirname + "/src/libmongoc/src/common/src/common-config.h.in", configure_module_dirname + "/src/libmongoc/src/common/src/common-config.h", mongoc_opts ); mongodb_generate_header( configure_module_dirname + "/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version.h.in", configure_module_dirname + "/src/libmongoc/src/libmongoc/src/mongoc/mongoc-version.h", mongodb_parse_libmongoc_version_file("libmongoc_") ); } mongodb-1.21.0/phongo_version.h0000644000175100001660000000200614760300421013344 0ustar /* * Copyright 2014-present MongoDB, 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. */ #ifndef PHONGO_VERSION_H #define PHONGO_VERSION_H /* Note: this file should remain in the repository's root directory so that * PECL's release-upload.php script can verify the version information when * publishing a release. */ /* clang-format off */ #define PHP_MONGODB_VERSION "1.21.0" #define PHP_MONGODB_STABILITY "stable" #define PHP_MONGODB_VERSION_DESC 1,21,0,0 /* clang-format on */ #endif /* PHONGO_VERSION_H */ mongodb-1.21.0/php_phongo.c0000644000175100001660000005137614760300421012457 0ustar /* * Copyright 2014-present MongoDB, 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. */ #include "bson/bson.h" #include "mongoc/mongoc.h" #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION #include #endif #include #include #include "php_phongo.h" #include "src/phongo_atomic.h" #include "src/phongo_client.h" #include "src/phongo_error.h" #include "src/phongo_ini.h" #include "src/phongo_log.h" #include "src/functions_arginfo.h" ZEND_DECLARE_MODULE_GLOBALS(mongodb) #if defined(ZTS) && defined(COMPILE_DL_MONGODB) ZEND_TSRMLS_CACHE_DEFINE(); #endif /* Initialize a thread counter, which will be atomically incremented in GINIT. * In turn, GSHUTDOWN will decrement the counter and call mongoc_cleanup() when * it reaches zero (i.e. last thread is shutdown). This is necessary because * mongoc_cleanup() must be called after all persistent clients have been * destroyed. */ static int32_t phongo_num_threads = 0; /* Declare zend_class_entry dependencies, which are initialized in MINIT */ zend_class_entry* php_phongo_json_serializable_ce; /* {{{ phongo_std_object_handlers */ zend_object_handlers phongo_std_object_handlers; zend_object_handlers* phongo_get_std_object_handlers(void) { return &phongo_std_object_handlers; } /* }}} */ /* {{{ Memory allocation wrappers */ static void* php_phongo_malloc(size_t num_bytes) { return pemalloc(num_bytes, 1); } static void* php_phongo_calloc(size_t num_members, size_t num_bytes) { return pecalloc(num_members, num_bytes, 1); } static void* php_phongo_realloc(void* mem, size_t num_bytes) { return perealloc(mem, num_bytes, 1); } static void php_phongo_free(void* mem) { if (mem) { pefree(mem, 1); } } /* }}} */ PHP_RINIT_FUNCTION(mongodb) /* {{{ */ { /* Initialize HashTable for non-persistent clients, which is initialized to * NULL in GINIT and destroyed and reset to NULL in RSHUTDOWN. Although we * specify an element destructor here, all request clients should be freed * naturally via garbage collection (i.e. the HashTable should be empty at * the time it is destroyed in RSHUTDOWN). */ if (MONGODB_G(request_clients) == NULL) { ALLOC_HASHTABLE(MONGODB_G(request_clients)); zend_hash_init(MONGODB_G(request_clients), 0, NULL, php_phongo_pclient_destroy_ptr, 0); } /* Initialize HashTable for loggers, which is initialized to NULL in GINIT * and destroyed and reset to NULL in RSHUTDOWN. Since this HashTable will * store logger object zvals, we specify ZVAL_PTR_DTOR as its element * destructor so that any still-registered loggers can be freed in * RSHUTDOWN. */ if (MONGODB_G(loggers) == NULL) { ALLOC_HASHTABLE(MONGODB_G(loggers)); zend_hash_init(MONGODB_G(loggers), 0, NULL, ZVAL_PTR_DTOR, 0); } /* Initialize HashTable for APM subscribers, which is initialized to NULL in * GINIT and destroyed and reset to NULL in RSHUTDOWN. Since this HashTable * will store subscriber object zvals, we specify ZVAL_PTR_DTOR as its * element destructor so that any still-registered subscribers can be freed * in RSHUTDOWN. */ if (MONGODB_G(subscribers) == NULL) { ALLOC_HASHTABLE(MONGODB_G(subscribers)); zend_hash_init(MONGODB_G(subscribers), 0, NULL, ZVAL_PTR_DTOR, 0); } /* Initialize HashTable for registering Manager objects. This is initialized * to NULL in GINIT and destroyed and reset to NULL in RSHUTDOWN. Since this * HashTable stores pointers to existing php_phongo_manager_t objects (not * counted references), the element destructor is intentionally NULL. */ if (MONGODB_G(managers) == NULL) { ALLOC_HASHTABLE(MONGODB_G(managers)); zend_hash_init(MONGODB_G(managers), 0, NULL, NULL, 0); } return SUCCESS; } /* }}} */ PHP_GINIT_FUNCTION(mongodb) /* {{{ */ { #if defined(COMPILE_DL_MONGODB) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif /* Increment the thread counter. */ phongo_atomic_int32_fetch_add(&phongo_num_threads, 1, phongo_memory_order_seq_cst); /* Clear extension globals */ memset(mongodb_globals, 0, sizeof(zend_mongodb_globals)); /* Initialize HashTable for persistent clients, which will be destroyed in * GSHUTDOWN. We specify an element destructor so that persistent clients * can be destroyed along with the HashTable. The HashTable's struct is * nested within globals, so no allocation is needed (unlike the HashTables * allocated in RINIT). */ zend_hash_init(&mongodb_globals->persistent_clients, 0, NULL, php_phongo_pclient_destroy_ptr, 1); } /* }}} */ static zend_class_entry* php_phongo_fetch_internal_class(const char* class_name, size_t class_name_len) { zend_class_entry* pce; if ((pce = zend_hash_str_find_ptr(CG(class_table), class_name, class_name_len))) { return pce; } return NULL; } static HashTable* php_phongo_std_get_gc(zend_object* object, zval** table, int* n) { *table = NULL; *n = 0; return zend_std_get_properties(object); } PHP_MINIT_FUNCTION(mongodb) /* {{{ */ { bson_mem_vtable_t bson_mem_vtable = { php_phongo_malloc, php_phongo_calloc, php_phongo_realloc, php_phongo_free, }; (void) type; /* We don't care if we are loaded via dl() or extension= */ /* Start by disabling libmongoc's default log handler, which could write to * stdout/stderr. The PHP driver's log handler may be assigned below when * parsing INI options or at a later point during a request when registering * a logger. */ mongoc_log_set_handler(NULL, NULL); /* Disable trace logging. This will be enabled in phongo_log_sync_handlers() * if the "mongodb.debug" INI option is set. */ mongoc_log_trace_disable(); phongo_register_ini_entries(INIT_FUNC_ARGS_PASSTHRU); /* Assign our custom vtable to libbson, so all memory allocation in libbson * (and libmongoc) will use PHP's persistent memory API. After doing so, * initialize libmongoc. Later, we will shutdown libmongoc and restore * libbson's vtable in the final GSHUTDOWN. */ bson_mem_set_vtable(&bson_mem_vtable); mongoc_init(); /* Prep default object handlers to be used when we register the classes */ memcpy(&phongo_std_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); /* Disable cloning by default. Individual classes can opt in if they need to * support this (e.g. BSON objects). */ phongo_std_object_handlers.clone_obj = NULL; /* Ensure that get_gc delegates to zend_std_get_properties directly in case * our class defines a get_properties handler for debugging purposes. */ phongo_std_object_handlers.get_gc = php_phongo_std_get_gc; /* Initialize zend_class_entry dependencies. * * Although JsonSerializable was introduced in PHP 5.4.0, * php_json_serializable_ce is not exported in PHP versions before 5.4.26 * and 5.5.10. For later PHP versions, looking up the class manually also * helps with distros that disable LTDL_LAZY for dlopen() (e.g. Fedora). */ php_phongo_json_serializable_ce = php_phongo_fetch_internal_class(ZEND_STRL("jsonserializable")); if (php_phongo_json_serializable_ce == NULL) { zend_error(E_ERROR, "JsonSerializable class is not defined. Please ensure that the 'json' module is loaded before the 'mongodb' module."); return FAILURE; } /* Register base BSON classes first */ php_phongo_type_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serializable_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_unserializable_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_binary_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_decimal128_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_javascript_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_maxkey_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_minkey_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_objectid_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_regex_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_timestamp_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_utcdatetime_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_iterator_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_packedarray_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_document_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_binary_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_dbpointer_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_decimal128_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_int64_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_javascript_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_maxkey_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_minkey_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_objectid_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_persistable_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_regex_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_symbol_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_timestamp_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_undefined_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_utcdatetime_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_cursor_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_bulkwrite_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_clientencryption_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_command_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_cursor_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_cursorid_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_manager_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_query_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_readconcern_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_readpreference_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_server_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serverapi_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serverdescription_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_topologydescription_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_session_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_writeconcern_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_writeconcernerror_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_writeerror_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_writeresult_init_ce(INIT_FUNC_ARGS_PASSTHRU); /* Register base exception classes first */ php_phongo_exception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_runtimeexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serverexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_connectionexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_writeexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_authenticationexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_bulkwriteexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_commandexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_connectiontimeoutexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_encryptionexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_executiontimeoutexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_invalidargumentexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_logicexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_sslconnectionexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_unexpectedvalueexception_init_ce(INIT_FUNC_ARGS_PASSTHRU); /* Register base APM classes first */ php_phongo_subscriber_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_commandsubscriber_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_commandfailedevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_commandstartedevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_commandsucceededevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_logsubscriber_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_sdamsubscriber_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serverchangedevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serverclosedevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serverheartbeatfailedevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serverheartbeatstartedevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serverheartbeatsucceededevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_serveropeningevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_topologychangedevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_topologyclosedevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_topologyopeningevent_init_ce(INIT_FUNC_ARGS_PASSTHRU); REGISTER_STRING_CONSTANT("MONGODB_VERSION", (char*) PHP_MONGODB_VERSION, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("MONGODB_STABILITY", (char*) PHP_MONGODB_STABILITY, CONST_CS | CONST_PERSISTENT); return SUCCESS; } /* }}} */ PHP_MSHUTDOWN_FUNCTION(mongodb) /* {{{ */ { phongo_unregister_ini_entries(SHUTDOWN_FUNC_ARGS_PASSTHRU); return SUCCESS; } /* }}} */ PHP_RSHUTDOWN_FUNCTION(mongodb) /* {{{ */ { /* Destroy HashTable for loggers, which was initialized in RINIT. */ if (MONGODB_G(loggers)) { zend_hash_destroy(MONGODB_G(loggers)); FREE_HASHTABLE(MONGODB_G(loggers)); MONGODB_G(loggers) = NULL; } /* TODO: consider calling phongo_log_sync_handler here since logging may no * longer be enabled. */ /* Destroy HashTable for APM subscribers, which was initialized in RINIT. */ if (MONGODB_G(subscribers)) { zend_hash_destroy(MONGODB_G(subscribers)); FREE_HASHTABLE(MONGODB_G(subscribers)); MONGODB_G(subscribers) = NULL; } /* Destroy HashTable for non-persistent clients, which was initialized in * RINIT. This is intentionally done after the APM subscribers to allow any * non-persistent clients still referenced by a subscriber (not freed prior * to RSHUTDOWN) to be naturally garbage collected and freed by the Manager * free_object handler rather than the HashTable's element destructor. There * is no need to use zend_hash_graceful_reverse_destroy here like we do for * persistent clients; moreover, the HashTable should already be empty. */ if (MONGODB_G(request_clients)) { zend_hash_destroy(MONGODB_G(request_clients)); FREE_HASHTABLE(MONGODB_G(request_clients)); MONGODB_G(request_clients) = NULL; } /* Destroy HashTable for Managers, which was initialized in RINIT. */ if (MONGODB_G(managers)) { zend_hash_destroy(MONGODB_G(managers)); FREE_HASHTABLE(MONGODB_G(managers)); MONGODB_G(managers) = NULL; } return SUCCESS; } /* }}} */ PHP_GSHUTDOWN_FUNCTION(mongodb) /* {{{ */ { /* Destroy persistent client HashTable in reverse order. This is necessary * to prevent segmentation faults as clients may reference other clients in * encryption settings. */ zend_hash_graceful_reverse_destroy(&mongodb_globals->persistent_clients); /* TODO: Check that logging actually gets disabled. The logger HashTable * should be empty by this point. */ phongo_log_set_stream(NULL); /* Decrement the thread counter. If it reaches zero, we can infer that this * is the last thread, MSHUTDOWN has been called, persistent clients from * all threads have been destroyed, and it is now safe to shutdown libmongoc * and restore libbson's original vtable. */ if (phongo_atomic_int32_fetch_sub(&phongo_num_threads, 1, phongo_memory_order_seq_cst) - 1 == 0) { mongoc_cleanup(); bson_mem_restore_vtable(); } } /* }}} */ PHP_MINFO_FUNCTION(mongodb) /* {{{ */ { php_info_print_table_start(); php_info_print_table_header(2, "MongoDB support", "enabled"); php_info_print_table_row(2, "MongoDB extension version", PHP_MONGODB_VERSION); php_info_print_table_row(2, "MongoDB extension stability", PHP_MONGODB_STABILITY); #ifdef HAVE_SYSTEM_LIBBSON php_info_print_table_row(2, "libbson headers version", BSON_VERSION_S); php_info_print_table_row(2, "libbson library version", bson_get_version()); #else php_info_print_table_row(2, "libbson bundled version", BSON_VERSION_S); #endif #ifdef HAVE_SYSTEM_LIBMONGOC php_info_print_table_row(2, "libmongoc headers version", MONGOC_VERSION_S); php_info_print_table_row(2, "libmongoc library version", mongoc_get_version()); #else /* Bundled libraries, buildtime = runtime */ php_info_print_table_row(2, "libmongoc bundled version", MONGOC_VERSION_S); #endif #ifdef MONGOC_ENABLE_SSL php_info_print_table_row(2, "libmongoc SSL", "enabled"); #if defined(MONGOC_ENABLE_SSL_OPENSSL) php_info_print_table_row(2, "libmongoc SSL library", "OpenSSL"); #elif defined(MONGOC_ENABLE_SSL_LIBRESSL) php_info_print_table_row(2, "libmongoc SSL library", "LibreSSL"); #elif defined(MONGOC_ENABLE_SSL_SECURE_TRANSPORT) php_info_print_table_row(2, "libmongoc SSL library", "Secure Transport"); #elif defined(MONGOC_ENABLE_SSL_SECURE_CHANNEL) php_info_print_table_row(2, "libmongoc SSL library", "Secure Channel"); #else php_info_print_table_row(2, "libmongoc SSL library", "unknown"); #endif #else /* MONGOC_ENABLE_SSL */ php_info_print_table_row(2, "libmongoc SSL", "disabled"); #endif #ifdef MONGOC_ENABLE_CRYPTO php_info_print_table_row(2, "libmongoc crypto", "enabled"); #if defined(MONGOC_ENABLE_CRYPTO_LIBCRYPTO) php_info_print_table_row(2, "libmongoc crypto library", "libcrypto"); #elif defined(MONGOC_ENABLE_CRYPTO_COMMON_CRYPTO) php_info_print_table_row(2, "libmongoc crypto library", "Common Crypto"); #elif defined(MONGOC_ENABLE_CRYPTO_CNG) php_info_print_table_row(2, "libmongoc crypto library", "CNG"); #else php_info_print_table_row(2, "libmongoc crypto library", "unknown"); #endif #ifdef MONGOC_ENABLE_CRYPTO_SYSTEM_PROFILE php_info_print_table_row(2, "libmongoc crypto system profile", "enabled"); #else php_info_print_table_row(2, "libmongoc crypto system profile", "disabled"); #endif #else /* MONGOC_ENABLE_CRYPTO */ php_info_print_table_row(2, "libmongoc crypto", "disabled"); #endif #ifdef MONGOC_ENABLE_SASL php_info_print_table_row(2, "libmongoc SASL", "enabled"); #else php_info_print_table_row(2, "libmongoc SASL", "disabled"); #endif #ifdef MONGOC_ENABLE_SRV php_info_print_table_row(2, "libmongoc SRV", "enabled"); #else php_info_print_table_row(2, "libmongoc SRV", "disabled"); #endif #ifdef MONGOC_ENABLE_COMPRESSION php_info_print_table_row(2, "libmongoc compression", "enabled"); #ifdef MONGOC_ENABLE_COMPRESSION_SNAPPY php_info_print_table_row(2, "libmongoc compression snappy", "enabled"); #else php_info_print_table_row(2, "libmongoc compression snappy", "disabled"); #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZLIB php_info_print_table_row(2, "libmongoc compression zlib", "enabled"); #else php_info_print_table_row(2, "libmongoc compression zlib", "disabled"); #endif #ifdef MONGOC_ENABLE_COMPRESSION_ZSTD php_info_print_table_row(2, "libmongoc compression zstd", "enabled"); #else php_info_print_table_row(2, "libmongoc compression zstd", "disabled"); #endif #else /* MONGOC_ENABLE_COMPRESSION */ php_info_print_table_row(2, "libmongoc compression", "disabled"); #endif #ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION #ifdef HAVE_SYSTEM_LIBMONGOCRYPT php_info_print_table_row(2, "libmongocrypt headers version", MONGOCRYPT_VERSION); php_info_print_table_row(2, "libmongocrypt library version", mongocrypt_version(NULL)); #else php_info_print_table_row(2, "libmongocrypt bundled version", MONGOCRYPT_VERSION); #endif #ifdef MONGOCRYPT_ENABLE_CRYPTO php_info_print_table_row(2, "libmongocrypt crypto", "enabled"); #if defined(MONGOCRYPT_ENABLE_CRYPTO_LIBCRYPTO) php_info_print_table_row(2, "libmongocrypt crypto library", "libcrypto"); #elif defined(MONGOCRYPT_ENABLE_CRYPTO_COMMON_CRYPTO) php_info_print_table_row(2, "libmongocrypt crypto library", "Common Crypto"); #elif defined(MONGOCRYPT_ENABLE_CRYPTO_CNG) php_info_print_table_row(2, "libmongocrypt crypto library", "CNG"); #else php_info_print_table_row(2, "libmongocrypt crypto library", "unknown"); #endif #else /* MONGOCRYPT_ENABLE_CRYPTO */ php_info_print_table_row(2, "libmongocrypt crypto", "disabled"); #endif { const char* crypt_shared_version = php_phongo_crypt_shared_version(); if (crypt_shared_version) { php_info_print_table_row(2, "crypt_shared library version", crypt_shared_version); } else { php_info_print_table_row(2, "crypt_shared library version", "unknown"); } } #else /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */ php_info_print_table_row(2, "libmongocrypt", "disabled"); #endif php_info_print_table_end(); phongo_display_ini_entries(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU); } /* }}} */ /* {{{ Module dependencies and module entry */ static const zend_module_dep mongodb_deps[] = { /* clang-format off */ ZEND_MOD_REQUIRED("date") ZEND_MOD_REQUIRED("json") ZEND_MOD_REQUIRED("spl") ZEND_MOD_REQUIRED("standard") ZEND_MOD_END /* clang-format on */ }; zend_module_entry mongodb_module_entry = { STANDARD_MODULE_HEADER_EX, NULL, mongodb_deps, "mongodb", ext_functions, PHP_MINIT(mongodb), PHP_MSHUTDOWN(mongodb), PHP_RINIT(mongodb), PHP_RSHUTDOWN(mongodb), PHP_MINFO(mongodb), PHP_MONGODB_VERSION, PHP_MODULE_GLOBALS(mongodb), PHP_GINIT(mongodb), PHP_GSHUTDOWN(mongodb), NULL, STANDARD_MODULE_PROPERTIES_EX }; /* }}} */ #ifdef COMPILE_DL_MONGODB ZEND_GET_MODULE(mongodb) #endif mongodb-1.21.0/php_phongo.h0000644000175100001660000000713314760300421012454 0ustar /* * Copyright 2014-present MongoDB, 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. */ #ifndef PHONGO_H #define PHONGO_H #ifdef HAVE_CONFIG_H #include "config.h" #endif /* Include headers for getpid(), which is used by PHONGO_SET_CREATED_BY_PID. * This is based on PHP's ext/standard/pageinfo.c includes for getmypid. */ #if HAVE_UNISTD_H #include #endif #ifdef PHP_WIN32 #include #endif #include "phongo_version.h" #include "phongo_compat.h" #include "phongo_classes.h" #include "phongo_structs.h" /* Define a common logging domain for the extension. Individual files may * override the domain after including this header (e.g. phongo_bson.c). */ #undef MONGOC_LOG_DOMAIN #define MONGOC_LOG_DOMAIN "PHONGO" #define phpext_mongodb_ptr &mongodb_module_entry extern zend_module_entry mongodb_module_entry; ZEND_BEGIN_MODULE_GLOBALS(mongodb) char* debug; FILE* debug_fd; HashTable persistent_clients; HashTable* request_clients; HashTable* subscribers; HashTable* managers; HashTable* loggers; ZEND_END_MODULE_GLOBALS(mongodb) #define MONGODB_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(mongodb, v) #if defined(ZTS) && defined(COMPILE_DL_MONGODB) ZEND_TSRMLS_CACHE_EXTERN() #endif zend_object_handlers* phongo_get_std_object_handlers(void); #define PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_temp, intern, props, size) \ do { \ if (is_temp) { \ ALLOC_HASHTABLE(props); \ zend_hash_init((props), (size), NULL, ZVAL_PTR_DTOR, 0); \ } else if ((intern)->properties) { \ (props) = (intern)->properties; \ } else { \ ALLOC_HASHTABLE(props); \ zend_hash_init((props), (size), NULL, ZVAL_PTR_DTOR, 0); \ (intern)->properties = (props); \ } \ } while (0) #define PHONGO_GET_PROPERTY_HASH_FREE_PROPS(is_temp, props) \ do { \ if (is_temp) { \ zend_hash_destroy((props)); \ FREE_HASHTABLE(props); \ } \ } while (0) #define PHONGO_ZVAL_EXCEPTION_NAME(e) (ZSTR_VAL(e->ce->name)) #define PHONGO_SET_CREATED_BY_PID(intern) \ do { \ (intern)->created_by_pid = (int) getpid(); \ } while (0) #define PHONGO_DISABLED_CONSTRUCTOR(classname) \ static PHP_METHOD(classname, __construct) \ { \ PHONGO_PARSE_PARAMETERS_NONE(); \ phongo_throw_exception(PHONGO_ERROR_RUNTIME, "Accessing private constructor"); \ } #endif /* PHONGO_H */